ATmega32, obsługa LCD - AVRStudio, Problem

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
hcmateusz
-
Posty: 4
Rejestracja: 11 mar 2008, 12:50
Lokalizacja: Inowrocław

ATmega32, obsługa LCD - AVRStudio, Problem

Post autor: hcmateusz » 11 mar 2008, 12:54

Witam. Mam problem, podejrzewam z opóźnieniami w inicjacji LCD. Mam do zrobienia komunikacje szeregową pomiedzy ZL10AVR z ATmega32 a komputerem PC. Program działa tak, że jak nacisnę przycisk 1 (S12) to na komputerze uruchamia sie program notatnik (to zrobilem w programie LabView - ale to nie wazne). Chodzi mi o to - jak nacisnę ten przycisk to na wyświetlaczu LCD (hd44780) ma mi wyswietlic napis (np. Uruchamiam notepad). I problem w tym, że jak umieszcze komendę wysyłającą znaki w pętli while, na LCD powstają zupełnie inne litery. Słyszałem, że mam nie odpowiednie opóźnienia. Nie jestem na wysokim poziomie programowania AVR więc nie mogę sobie poradzić. Proszę o pomoc. Niżej umieszczam kod programu:

Kod: Zaznacz cały

#include <avr/io.h> 
#include <avr/interrupt.h> 
#include <avr/signal.h> 
#include <avr/delay.h> 
#include <stdlib.h> 

#define CPU_Hz   8000000               // częstotliwość zegara w Hz 
#define OSC    8                  // częstotliwość zegara w MHz 
#define BAUD   9600               // prędkość transmisji po RS232 
#define MYUBRR  CPU_Hz/16/BAUD-1    

// **** fukcje dla RS232 **** 
void UART_init(unsigned int ubrr)       // inicjalizacja 
{ 
   UBRRH = (unsigned char) (ubrr>>8);   // ustawienie prędkości 
   UBRRL = (unsigned char) ubrr; 
   UCSRB = (1<<RXEN)|(1<<TXEN);         // transmisja dwukierunkowa, 
   UCSRC = (1<<URSEL)|(3<<UCSZ0);      // 8 bit danych i 1 bit stopu 
} 

void USART_out (unsigned char data)    // wysłanie znaku 
{ 
   while (!(UCSRA & (1<<UDRE))); 
   UDR = data; 
} 

unsigned char USART_in (void)    // odebranie znaku 
{ 
   while (!(UCSRA & (1<<RXC))); 
   return UDR; 
} 

// **** funkcja czasowa **** 
void waitms(unsigned char czas) 
{ 
   unsigned char a, b;                // zmnienne licznikowe 
   for( ; czas > 0; --czas)                // ta pętla zostanie wykonana x-razy 
      for(b = 10; b > 0; --b)          // a ta 10 razy 
         for(a = 25 * OSC; a > 0; --a)    // natomiast ta 100 razy 
            __asm("nop");             // instrukcja opóźniająca o 1 cykl 
} 

//Funkcja sterująca sygnałem E 
void lcd_e(unsigned char e){ 
    
   if(e!=0) 
      //jeżeli argument funkcji rózny 
      //od zera sygnał E zostaje ustawiony 
      PORTB=PORTB|(1<<2); 
   else 
      PORTB=PORTB&~(1<<2); 
} 

//Funkcja sterująca sygnałem RW 
void lcd_rw(unsigned char rw){ 
    
   if(rw!=0) 
      PORTB=PORTB|(1<<1); 
   else 
      PORTB=PORTB&~(1<<1); 
} 

//Funkcja sterująca sygnałem RS 
void lcd_rs(unsigned char rs){ 
    
   if(rs!=0) 
      PORTB=PORTB|1; 
   else 
      PORTB=PORTB&~1; 
} 

//Funkcja wysyłająca komendę 
//w trybie ośmio bitowym 
void lcd_send_cmd(unsigned char cmd){ 

   lcd_rs(0); 
   lcd_rw(0); 
   lcd_e(1); 
   PORTD=cmd; 
   lcd_e(0); 
} 

//Funkcja wysyłająca daną 
//w trybie ośmio bitowym 
void lcd_send_data(unsigned char data){ 

   lcd_rs(1); 
   lcd_rw(0); 
   lcd_e(1); 
   PORTD=data; 
   lcd_e(0); 
} 


// **** program główny **** 
int main(void)                        
{ 
   //inicjalizacja 
   //wszystkie sygnały sterujące zostają wyzerowane 
   lcd_rw(0); 
   lcd_rs(0); 
   lcd_e(0); 
   //wszystkie linie danych otrzymują stan niski 
   lcd_send_data(0); 
    
   //PORTD ustawiony jako wyjście - dane 
   DDRD=DDRD|0xff; 
    
   //PORTB ustawiony jako wyjście - sygnały sterujące 
   DDRB=DDRB|0x07; 
    
   _delay_ms(80); 
    
    
   //0x38= 
   //00111000b 
   //--1----- kod specyficzny komendy Function set (tabela 6 [6]) 
   //---1---- DL=1   - transmisja ośmio bitowa 
   //----1--- N=1   - wyświetlacz stanowi dwie linie 
   //-----0-- F=0   - wielkość czcionki 5 x 8 pikseli 
   lcd_send_cmd(0x38); 
   //żądane opóźnienie 
   _delay_us(38); 
    
   //0xf= 
   //00001111b 
   //----1--- kod specyficzny komendy Display on/off Control 
   //-----1-- D=1   - wyświetlacz załączony 
   //------1- C=1   - kursor załączony 
   //-------1 B=1   - migotanie znaku 
   lcd_send_cmd(0x0f); 
   _delay_us(38); 
    
   //0x06= 
   //00000110 
   //-----1-- kod specyficzny komendy Entry mode set 
   //------1- I/D=1   - inkrementacja położenia kursora 
   //-------0 S=0   - wyświetlany obraz pozostaje w spoczynku 
   lcd_send_cmd(0x06); 
   _delay_us(38); 
    
   //0x01= 
   //00000001 
   //-------1 kod specyficzny komendy Clear Display 
   //czyści ekran i ustawia adres DDRAM=0 
   lcd_send_cmd(0x01); 
   _delay_ms(1.52); 
    

    
    
    
       

//---------------------------------------------------------------------------------- 
DDRA=0x00; //klawa ustawiona jako wejscie 00000000 
PORTA=0xFF;//port ustawiony jako wyjscie 11111111 
//---------------------------------------------------------------------------------- 


       
   int i; int j; int x; int z; 
   char przycisk1; //inicjacja na przycisk 1 
   char przycisk2; //inicjacja na przycisk 2 
   char przycisk3; //inicjacja na przycisk 3 
   char przycisk4; //inicjacja na przycisk 4 


   przycisk1=49;   przycisk2=50;   przycisk3=51; 
przycisk4=52; 


          
         char znaki[]={"11\n11"}; 
         unsigned char q=0; 
    

   UART_init(MYUBRR);               // Inicjalizacja RS232 

while (1) { 
_delay_ms(250); 
_delay_ms(250); 
_delay_ms(250); 
_delay_ms(250); 



if (PINA==0xFE){ 
          
            USART_out(przycisk1); 

         while(znaki[q]!=0){                  //1 
         if(znaki[q]=='\n')                     //1 w wprzypadku nowej linii 
            lcd_send_cmd(0xc0);                  //1 adres DDRAM zostaje zmieniony na 0x40 
         else                              //1 
            lcd_send_data(znaki[q]);            //1 
         q++;                              //1 
         _delay_us(37);                        //1 
         }                

   //while(1){                                 //1 zatrzymanie na końcu kodu 
   //}; 
   }    
                   

           

if (PINA==0xFD){ 
       
      USART_out(przycisk2); 
       
          } 

if (PINA==0xFB){ 
       
      USART_out(przycisk3); 
       
          } 

if (PINA==0xF7){ 
       
      USART_out(przycisk4); 
          
          } 

}; 
} 

Z góry dziekuję za pomoc.
Serdecznie pozdrawiam.
hcmateusz.

Awatar użytkownika
gaweł
Użytkownik
Posty: 651
Rejestracja: 05 kwie 2004, 8:38
Lokalizacja: Białystok
Kontakt:

Post autor: gaweł » 11 mar 2008, 22:49

Na początek to polecam lekturę na temat samego wyświetlacza: https://elportal.pl/index.php?module=Co ... y&ceid=354 oraz użycia wyświetlacza LCD w programie: https://elportal.pl/index.php?module=Co ... y&ceid=356
Przyglądając się programowi można dostrzec następujące rzeczy:

Kod: Zaznacz cały

void lcd_send_data(unsigned char data){ 

   lcd_rs(1); 
   lcd_rw(0); 
   lcd_e(1); 
   PORTD=data; 
   lcd_e(0); 
} 
Zastanów się, ile czas będzie trwać impuls na wyprowadzeniu E i łatwo jest zauważyć, że jest za krótki. W poleconych wyżej artykułach jest (pomijając fragmenty kompilacji warunkowej):

Kod: Zaznacz cały

void LCDDelay ( void )
  {
    uint8_t Loop ;
    /*---------------------------------*/
    for ( Loop = 0 ; Loop < 16 ; Loop ++ )
      nop ( ) ;
  } /* LCDDelay */

void EPulse ( void )
  {
    lcd_E_port |= 1 << lcd_E_pin ;              // [E=1]
    LCDDelay ( ) ;
    lcd_E_port &= ~ ( 1 << lcd_E_pin ) ;        // [E=0]
  } /* EPulse */

void LCDOutD ( uint8_t Data )
  {
    SetOutputDataBus ( ) ;
    lcd_RS_port |= 1 << lcd_RS_pin ;            // [RS=1]
    lcd_RW_port &= ~ ( 1 << lcd_RW_pin ) ;      // [R/W=0]
    lcd_Data_port = Data ;
    EPulse ( ) ;
  } /* LCDOutD */ ;
Druga sugestia wiąże się z sygnałem zapisu RW. Skoro ten sygnał jest doprowadzony do procka (tak sądzę po zapisie):

Kod: Zaznacz cały

   lcd_rw(0); 
to dlaczego nie jest on używany do odczytu statusu z modułu LCD. Odczyt statusu powzoli ci na eliminację z programu odczekiwania określonych czasów w zależności od wykonywanego polecenia. Włączając zasilanie dla modułu należy pamiętać, że on wykonuje swoją procedurę startową, która zajmuje ileś czasu, więc po resecie procka warto dać mu szansę na skończenie jej. To może dawać taki efekt, że po włączeniu zasilania moduł żle działa, ale po naciśnięciu reset dla procka działa dobrze.

ODPOWIEDZ