Rotačný enkodér: Rozdiel medzi revíziami
Zo stránky SensorWiki
| Riadok 35: | Riadok 35: | ||
| <tab name="AVR C-code"><source lang="c++" style="background: LightYellow;"> | <tab name="AVR C-code"><source lang="c++" style="background: LightYellow;"> | ||
| #include <avr/io.h> | #include <avr/io.h> | ||
| #include <avr/interrupt.h> | |||
| #include <util/delay.h> | |||
| #define clk_pin PB3 | |||
| #define data_pin PB4 | |||
| #define swt_pin PB5 | |||
| volatile int poutput; | |||
| volatile int counter = 0; | |||
| volatile bool buttonPressed = false; | |||
| enum MenuState { MENU_MAIN, MENU_VALUE }; | |||
| volatile MenuState menuState = MENU_MAIN; | |||
| void initLCD() | |||
| { | |||
|     DDRD |= (1 << PD0) | (1 << PD1) | (1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5); | |||
|     PORTD = 0x20; | |||
|     PORTD |= 0x04; | |||
|     PORTD &= ~0x04; | |||
|     sendLCDCommand(0x28); | |||
|     sendLCDCommand(0x0C); | |||
|     sendLCDCommand(0x01); | |||
|     DDRB &= ~(1 << clk_pin) & ~(1 << data_pin) & ~(1 << swt_pin); | |||
|     PORTB |= (1 << clk_pin) | (1 << data_pin) | (1 << swt_pin); | |||
|     // Čtení počátečního stavu enkodéru | |||
|     poutput = PINB & (1 << clk_pin); | |||
| } | |||
| // Odeslání příkazu na LCD | |||
| void sendLCDCommand(uint8_t command) | |||
| { | |||
|     PORTD = (command & 0xF0); | |||
|     PORTD &= ~(1 << PD4); | |||
|     PORTD |= (1 << PD5); | |||
|     _delay_us(1); | |||
|     PORTD &= ~(1 << PD5); | |||
|     PORTD = ((command << 4) & 0xF0); | |||
|     PORTD &= ~(1 << PD4); | |||
|     PORTD |= (1 << PD5); | |||
|     _delay_us(1); | |||
|     PORTD &= ~(1 << PD5); | |||
|     _delay_us(40); | |||
| } | |||
| // Odeslání dat na LCD | |||
| void sendLCDData(uint8_t data) | |||
| { | |||
|     PORTD = (data & 0xF0); | |||
|     PORTD |= (1 << PD4); | |||
|     PORTD |= (1 << PD5); | |||
|     _delay_us(1); | |||
|     PORTD &= ~(1 << PD5); | |||
|     PORTD = ((data << 4) & 0xF0); | |||
|     PORTD |= (1 << PD4); | |||
|     PORTD |= (1 << PD5); | |||
|     _delay_us(1); | |||
|     PORTD &= ~(1 << PD5); | |||
|     _delay_us(40); | |||
| } | |||
| void updateCounterDisplay() | |||
| { | |||
|     sendLCDCommand(0x80 | 0x40);   | |||
|     sendLCDData('P'); | |||
|     sendLCDData('o'); | |||
|     sendLCDData('s'); | |||
|     sendLCDData('i'); | |||
|     sendLCDData('t'); | |||
|     sendLCDData('i'); | |||
|     sendLCDData('o'); | |||
|     sendLCDData('n'); | |||
|     sendLCDData(':'); | |||
|     sendLCDCommand(0x80 | 0x40 | 0x09);   | |||
|     sendLCDData(' '); | |||
|     sendLCDData(' '); | |||
|     sendLCDData(' '); | |||
|     sendLCDData(' '); | |||
|     sendLCDData(' '); | |||
|     sendLCDData(' '); | |||
|     sendLCDData(' '); | |||
|     sendLCDData(' '); | |||
|     sendLCDCommand(0x80 | 0x40 | 0x09);   | |||
|     sendLCDData((counter / 100) + '0'); | |||
|     sendLCDData(((counter / 10) % 10) + '0'); | |||
|     sendLCDData((counter % 10) + '0'); | |||
| } | |||
| // Obsluha menu MENU_MAIN | |||
| void handleMainMenu() | |||
| { | |||
|     if ((PINB & (1 << clk_pin)) != poutput) | |||
|     { | |||
|         if ((PINB & (1 << data_pin)) != poutput) | |||
|         { | |||
|             counter++; | |||
|         } | |||
|         else | |||
|         { | |||
|             counter--; | |||
|         } | |||
|         updateCounterDisplay(); | |||
|     } | |||
|     poutput = PINB & (1 << clk_pin); | |||
|     if ((PINB & (1 << swt_pin)) == 0 && !buttonPressed) | |||
|     { | |||
|         buttonPressed = true; | |||
|         sendLCDCommand(0x01);   | |||
|         sendLCDData('P'); | |||
|         sendLCDData('r'); | |||
|         sendLCDData('e'); | |||
|         sendLCDData('s'); | |||
|         sendLCDData('s'); | |||
|         sendLCDData('e'); | |||
|         sendLCDData('d'); | |||
|         _delay_ms(500); | |||
|         sendLCDCommand(0x01);   | |||
|         menuState = MENU_VALUE; | |||
|         updateCounterDisplay(); | |||
|     } | |||
|     else if ((PINB & (1 << swt_pin)) != 0) | |||
|     { | |||
|         buttonPressed = false; | |||
|     } | |||
| } | |||
| // Obsluha menu MENU_VALUE | |||
| void handleValueMenu() | |||
| { | |||
|     if ((PINB & (1 << clk_pin)) != poutput) | |||
|     { | |||
|         if ((PINB & (1 << data_pin)) != poutput) | |||
|         { | |||
|             counter++; | |||
|         } | |||
|         else | |||
|         { | |||
|             counter--; | |||
|         } | |||
|         sendLCDCommand(0x80 | 0x40);   | |||
|         sendLCDData('P'); | |||
|         sendLCDData('o'); | |||
|         sendLCDData('s'); | |||
|         sendLCDData('i'); | |||
|         sendLCDData('t'); | |||
|         sendLCDData('i'); | |||
|         sendLCDData('o'); | |||
|         sendLCDData('n'); | |||
|         sendLCDData(':'); | |||
|         sendLCDCommand(0x80 | 0x40 | 0x09);   | |||
|         sendLCDData((counter / 100) + '0'); | |||
|         sendLCDData(((counter / 10) % 10) + '0'); | |||
|         sendLCDData((counter % 10) + '0'); | |||
|     } | |||
|     poutput = PINB & (1 << clk_pin); | |||
|     if ((PINB & (1 << swt_pin)) == 0 && !buttonPressed) | |||
|     { | |||
|         menuState = MENU_MAIN; | |||
|         sendLCDCommand(0x01);  // Vymazání displeje | |||
|         sendLCDData('V'); | |||
|         sendLCDData('a'); | |||
|         sendLCDData('l'); | |||
|         sendLCDData('u'); | |||
|         sendLCDData('e'); | |||
|         sendLCDData(' '); | |||
|         sendLCDData('e'); | |||
|         sendLCDData('n'); | |||
|         sendLCDData('t'); | |||
|         sendLCDData('e'); | |||
|         sendLCDData('r'); | |||
|         sendLCDData('e'); | |||
|         sendLCDData('d'); | |||
|         sendLCDCommand(0x80 | 0x40);   | |||
|         sendLCDData(' '); | |||
|         sendLCDData(' '); | |||
|         sendLCDData(' '); | |||
|         sendLCDData(' '); | |||
|         sendLCDData(' '); | |||
|         sendLCDData(' '); | |||
|         sendLCDData(' '); | |||
|         sendLCDData(' '); | |||
|         sendLCDCommand(0x01);   | |||
|         sendLCDData(' '); | |||
|         sendLCDData('R'); | |||
|         sendLCDData('o'); | |||
|         sendLCDData('t'); | |||
|         sendLCDData('a'); | |||
|         sendLCDData('r'); | |||
|         sendLCDData('y'); | |||
|         sendLCDData(' '); | |||
|         sendLCDData('E'); | |||
|         sendLCDData('n'); | |||
|         sendLCDData('c'); | |||
|         sendLCDData('o'); | |||
|         sendLCDData('d'); | |||
|         sendLCDData('e'); | |||
|         sendLCDData('r'); | |||
|         sendLCDData(' '); | |||
|         sendLCDData(' '); | |||
|         sendLCDData(' '); | |||
|         sendLCDData(' '); | |||
|         sendLCDData(' '); | |||
|         sendLCDData(' '); | |||
|         sendLCDData(' '); | |||
|         sendLCDData(' '); | |||
|         updateCounterDisplay(); | |||
|     } | |||
|     else if ((PINB & (1 << swt_pin)) != 0) | |||
|     { | |||
|         buttonPressed = false; | |||
|     } | |||
| } | |||
| int main(void) | int main(void) | ||
| { | { | ||
|     initLCD(); | |||
|     sei();   | |||
|     while (1) | |||
|     { | |||
|         switch (menuState) | |||
|         { | |||
|             case MENU_MAIN: | |||
|                 handleMainMenu(); | |||
|                 break; | |||
|             case MENU_VALUE: | |||
|                 handleValueMenu(); | |||
|                 break; | |||
|         } | |||
|      } | |||
| } | |||
|    return(0); |    return(0); | ||
| Riadok 61: | Riadok 311: | ||
| Zdrojový kód: [[Médiá:projektMenoPriezvisko.zip|zdrojaky.zip]] | Zdrojový kód: [[Médiá:projektMenoPriezvisko.zip|zdrojaky.zip]] | ||
| === Overenie === | === Overenie === | ||
Verzia z 15:47, 9. jún 2023
Záverečný projekt predmetu MIPS / LS2023 - Viktor Fos
Zadanie
Rotačný enkóder - vytvorime program pre zadávanie hodnoty nejakej veličiny na LCD displeji pomocou tohoto enkodéra. Jednoduché menu, výber hodnoty a zadávanie číselnej veličiny so zmenou nahor/nadol a potvrdenie stlačením.

Literatúra:
Analýza a opis riešenia
Najprv som podľa schémy zapojenia pripojil LCD displej a rotačný enkoder na dosku Arduino Uno.

Algoritmus a program
Algoritmus programu je....
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define clk_pin PB3
#define data_pin PB4
#define swt_pin PB5
volatile int poutput;
volatile int counter = 0;
volatile bool buttonPressed = false;
enum MenuState { MENU_MAIN, MENU_VALUE };
volatile MenuState menuState = MENU_MAIN;
void initLCD()
{
    
    DDRD |= (1 << PD0) | (1 << PD1) | (1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5);
    
    
    PORTD = 0x20;
    PORTD |= 0x04;
    PORTD &= ~0x04;
    
    
    sendLCDCommand(0x28);
    
    
    sendLCDCommand(0x0C);
    
   
    sendLCDCommand(0x01);
    
  
    DDRB &= ~(1 << clk_pin) & ~(1 << data_pin) & ~(1 << swt_pin);
    PORTB |= (1 << clk_pin) | (1 << data_pin) | (1 << swt_pin);
    
    // Čtení počátečního stavu enkodéru
    poutput = PINB & (1 << clk_pin);
}
// Odeslání příkazu na LCD
void sendLCDCommand(uint8_t command)
{
    PORTD = (command & 0xF0);
    PORTD &= ~(1 << PD4);
    PORTD |= (1 << PD5);
    _delay_us(1);
    PORTD &= ~(1 << PD5);
    
    PORTD = ((command << 4) & 0xF0);
    PORTD &= ~(1 << PD4);
    PORTD |= (1 << PD5);
    _delay_us(1);
    PORTD &= ~(1 << PD5);
    
    _delay_us(40);
}
// Odeslání dat na LCD
void sendLCDData(uint8_t data)
{
    PORTD = (data & 0xF0);
    PORTD |= (1 << PD4);
    PORTD |= (1 << PD5);
    _delay_us(1);
    PORTD &= ~(1 << PD5);
    
    PORTD = ((data << 4) & 0xF0);
    PORTD |= (1 << PD4);
    PORTD |= (1 << PD5);
    _delay_us(1);
    PORTD &= ~(1 << PD5);
    
    _delay_us(40);
}
void updateCounterDisplay()
{
    sendLCDCommand(0x80 | 0x40);  
    sendLCDData('P');
    sendLCDData('o');
    sendLCDData('s');
    sendLCDData('i');
    sendLCDData('t');
    sendLCDData('i');
    sendLCDData('o');
    sendLCDData('n');
    sendLCDData(':');
    
    sendLCDCommand(0x80 | 0x40 | 0x09);  
    sendLCDData(' ');
    sendLCDData(' ');
    sendLCDData(' ');
    sendLCDData(' ');
    sendLCDData(' ');
    sendLCDData(' ');
    sendLCDData(' ');
    sendLCDData(' ');
    
    sendLCDCommand(0x80 | 0x40 | 0x09);  
    sendLCDData((counter / 100) + '0');
    sendLCDData(((counter / 10) % 10) + '0');
    sendLCDData((counter % 10) + '0');
}
// Obsluha menu MENU_MAIN
void handleMainMenu()
{
    if ((PINB & (1 << clk_pin)) != poutput)
    {
        if ((PINB & (1 << data_pin)) != poutput)
        {
            counter++;
        }
        else
        {
            counter--;
        }
        updateCounterDisplay();
    }
    
    poutput = PINB & (1 << clk_pin);
    
    if ((PINB & (1 << swt_pin)) == 0 && !buttonPressed)
    {
        buttonPressed = true;
        sendLCDCommand(0x01);  
        sendLCDData('P');
        sendLCDData('r');
        sendLCDData('e');
        sendLCDData('s');
        sendLCDData('s');
        sendLCDData('e');
        sendLCDData('d');
        _delay_ms(500);
        sendLCDCommand(0x01);  
        menuState = MENU_VALUE;
        updateCounterDisplay();
    }
    else if ((PINB & (1 << swt_pin)) != 0)
    {
        buttonPressed = false;
    }
}
// Obsluha menu MENU_VALUE
void handleValueMenu()
{
    if ((PINB & (1 << clk_pin)) != poutput)
    {
        if ((PINB & (1 << data_pin)) != poutput)
        {
            counter++;
        }
        else
        {
            counter--;
        }
        sendLCDCommand(0x80 | 0x40);  
        sendLCDData('P');
        sendLCDData('o');
        sendLCDData('s');
        sendLCDData('i');
        sendLCDData('t');
        sendLCDData('i');
        sendLCDData('o');
        sendLCDData('n');
        sendLCDData(':');
        
        sendLCDCommand(0x80 | 0x40 | 0x09);  
        sendLCDData((counter / 100) + '0');
        sendLCDData(((counter / 10) % 10) + '0');
        sendLCDData((counter % 10) + '0');
    }
    
    poutput = PINB & (1 << clk_pin);
    
    if ((PINB & (1 << swt_pin)) == 0 && !buttonPressed)
    {
        menuState = MENU_MAIN;
        sendLCDCommand(0x01);  // Vymazání displeje
        sendLCDData('V');
        sendLCDData('a');
        sendLCDData('l');
        sendLCDData('u');
        sendLCDData('e');
        sendLCDData(' ');
        sendLCDData('e');
        sendLCDData('n');
        sendLCDData('t');
        sendLCDData('e');
        sendLCDData('r');
        sendLCDData('e');
        sendLCDData('d');
        sendLCDCommand(0x80 | 0x40);  
        sendLCDData(' ');
        sendLCDData(' ');
        sendLCDData(' ');
        sendLCDData(' ');
        sendLCDData(' ');
        sendLCDData(' ');
        sendLCDData(' ');
        sendLCDData(' ');
        sendLCDCommand(0x01);  
        sendLCDData(' ');
        sendLCDData('R');
        sendLCDData('o');
        sendLCDData('t');
        sendLCDData('a');
        sendLCDData('r');
        sendLCDData('y');
        sendLCDData(' ');
        sendLCDData('E');
        sendLCDData('n');
        sendLCDData('c');
        sendLCDData('o');
        sendLCDData('d');
        sendLCDData('e');
        sendLCDData('r');
        sendLCDData(' ');
        sendLCDData(' ');
        sendLCDData(' ');
        sendLCDData(' ');
        sendLCDData(' ');
        sendLCDData(' ');
        sendLCDData(' ');
        sendLCDData(' ');
        updateCounterDisplay();
    }
    else if ((PINB & (1 << swt_pin)) != 0)
    {
        buttonPressed = false;
    }
}
int main(void)
{
    initLCD();
    sei();  
    
    while (1)
    {
        switch (menuState)
        {
            case MENU_MAIN:
                handleMainMenu();
                break;
            case MENU_VALUE:
                handleValueMenu();
                break;
        }
    }
}
  return(0);
}
#include <avr/io.h>
void adc_init(void);                                   // A/D converter initialization
unsigned int adc_read(char a_pin);
Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x zdrojaky.zip:
Zdrojový kód: zdrojaky.zip
Overenie
Na používanie našej aplikácie stačia dve tlačítka a postup používania je opísaný v sekcii popis riešenia. Na konci uvádzame fotku záverečnej obrazovky pred resetom. Vypísaný je tu priemerný čas a najlepší čas.

Video:
Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte.