logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[AVR][C] Wysterowanie LCD na ATMEGA8. Wyświetlacz WH2004A 4x20.

mrrudzin 19 Mar 2009 12:45 2616 8
REKLAMA
  • #1 6302720
    mrrudzin
    Poziom 39  
    Mam problem z wysterowaniem wyświetlacza LCD na ATMEGA8.
    Podejrzewam że gdzieś zrobiłem jakiegoś byka i świeże spojrzenie na problem może pomóc.
    Wyświetlacz (WH2004A 4x20) podłączam pod portC Atmegi. Piny PC0-PC3 podłączyłem pod DB4-DB7 LCD, pin PC4 to RS w LCD, PC5 to sygnał E.
    Wejścia R/W, DB0-DB3 podpięte do masy.

    I żadnej reakcji ze strony wyświetlacza :(

    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    //#include <util/delay.h>
    #include <stdio.h>
    #include <avr/pgmspace.h>
    // Definicje dotyczace LCD 
    #define LCD PORTC           			//port z LCD
    #define RS 4                     		// wybor rejestru
    #define E 5                      		// sygnal zezwalajacy (enable)
    
    #define SET_RS sbi(PORTC,PC4) 
    #define CLR_RS cbi(PORTC,PC4)
    
    #define SET_E sbi(PORTC,PC5) 
    #define CLR_E cbi(PORTC,PC5)
     
    //Definicje i markodeklaracje
    
    //Definicje do delay-a 
    
    #define F_CPU 8000000 // 8MHz zegar procesora
    #define CYCLES_PER_US ((F_CPU+500000)/1000000) // cpu cycles per microsecond
    
    #define LEDP1ON sbi(PORTD,PD0) 
    #define LEDP2ON sbi(PORTD,PD1)
    
    #define LEDP1OFF cbi(PORTD,PD0)
    #define LEDP2OFF cbi(PORTD,PD1)
    
    #define LEDP1 PD0 
    #define LEDP2 PD1
    
    
    //F-cje odpowiedzialne za delay
    	void delayp(unsigned int us)
    		{
    	do{asm("nop");}while(--us);
    	}
    	
    	void delay_ms(unsigned int ms)
    	{
    	unsigned int i;
    	for (i=0;i<ms;i++)
    	 {
    	delayp(999);
    	asm volatile (
    	"WDR"::);
    	}
    	
    	}
    
    void write_to_lcd(char x)
    //void write_to_lcd(unsigned int x)
    {
    //Zapisujemy najpierw starsza czesc bajtu, nastepnie mlodsza
    //po ustawieniu bajtow na wejsciach LCD wystawiamy sygnal E
    CLR_E;
    delay_ms(1);
    LCD=(LCD & 0x0F)|(x>>4);//starsza czesc bajtu
    SET_E;
    delay_ms(5);
    CLR_E;
    delay_ms(1);
    LCD=(LCD & 0x0F)|(x&0x0f);//mlodsza czesc bajtu
    SET_E;
    delay_ms(5);
    CLR_E;
    }
    
    //***************** procedura zapisu instrukcji do wyświetlacza LCD
    void LCD_write_command(char x)
    {
    CLR_RS; 								// niski stan na RS -> zapis instrukcji
    delay_ms(1);
    write_to_lcd(x); 						// zapis do LCD
    }
    //***************** procedura zapisu danej do wyświetlacza LCD
    void LCD_write_char(char x)
    {
       SET_RS; 								// wysoki stan na RS -> zapis danej
       delay_ms(1);
       write_to_lcd(x); 					// zapis do LCD
    }
    //***************** procedura zapisu tekstu do wyświetlacza LCD
    void LCD_write(char * s)
    {
    while(*s) 								// do napotkania 0
      {
      LCD_write_char(*s); 						// zapisz znak wskazywany przez s na LCD
      s++; 									// zwiększ s (przygotuj nastepny znak)
      }
    }
    
    void LCD_write_P(const char *s)
    {
    	register char c;
    	while((c = pgm_read_byte(s))) 		// do napotkania 0
    	{
    	LCD_write_char(c); 						// zapisz znak wskazywany przez s na LCD
    	s++; 								// zwiększ s (przygotuj nastepny znak)
    	}
    }
    //***************** procedura inicjalizacji wyświetlacza LCD
    void LCD_init(void)
    {
    
    delay_ms(15); 							
    CLR_E; 									// E = 0
    CLR_RS; 								// RS = 0
    char i; 								// zmienna licznikowa
    for(i = 0; i < 3; i++) 				// trzykrotne powtórzenie bloku instrukcji
      {
      SET_E; 				// E = 1
     // LCD &= 0x30; 			//
      CLR_E; 				// E = 0
      delay_ms(5); 		// czekaj 5ms
      }
    SET_E; 					// E = 1
    //LCD &= 0x2E; 			//
    CLR_E; 					// E = 0
    
    delay_ms(1); 			// czekaj 1ms
    LCD_write_command(0x28); 	// interfejs 4-bity, 2-linie, znak 5x7
    LCD_write_command(0x08); 	// wyłącz LCD, kursor i miganie
    LCD_write_command(0x01); 	// czyść LCD
    LCD_write_command(0x06); 	// bez przesuwania w prawo
    LCD_write_command(0x0C); 	// włącz LCD, bez kursora i mrugania*/
    LCD_write_command(0x03);
    LCD_write_command(0x01);
    //LCD_write_command(0x0F);//wlacz LCD, kursor i miganie
    }
    
    //***************** procedura ustawiania pozycji kursora
    void LCD_xy(unsigned char w, unsigned char k)
    {
       LCD_write_command((w*0x40+k) | 0x80);
    }
    //***************** czysci wyswietlacz LCD
    void LCD_clear(void)
    {
       LCD_write_command(0x01);
    }
    
    main()
    {
    DDRC|=_BV(PC0)|_BV(PC1)|_BV(PC2)|_BV(PC3)|_BV(PC4)|_BV(PC5);
    //Diody statusu
    DDRD |= _BV(LEDP1)|_BV(LEDP2);
    
    const char pea[]="HELLO"; //stala dla wyswietlacza
    
    do
    {
    LCD_init();
    delay_ms(1000);
    LCD_clear();
    const char s="f";
    LCD_write_char(s);
    LCD_write_P(pea);
    delay_ms(1000);
    }
    while(1);
    
    }
    
  • REKLAMA
  • #2 6302777
    Freddie Chopin
    Specjalista - Mikrokontrolery
    LCD=(LCD & 0x0F)|(x>>4)

    Chyba chodziło ci o

    LCD=(LCD & (~0x0F))|(x>>4)

    czyli:

    LCD=(LCD & 0xF0)|(x>>4)

    bo AND z 0xF raczej na pewno nie wyczyści poprzednich wartości na młodszych bitach, tylko wyzeruje wszystkie starsze. (podobny błąd w kilku innych miejscach też jest)

    Dalej:

    
    for(i = 0; i < 3; i++)             // trzykrotne powtórzenie bloku instrukcji 
      { 
      SET_E;             // E = 1 
     // LCD &= 0x30;          // 
      CLR_E;             // E = 0 
      delay_ms(5);       // czekaj 5ms 
      } 
    SET_E;                // E = 1 
    //LCD &= 0x2E;          // 
    CLR_E;                // E = 0
    


    Raczej trzykrotne wielkie nic, bo kod jest zakomentowany. Pomijam już to, że zakomentowane fragmenty mają ten sam błąd co na początku posta.

    Pozatym pewnie masz blad w czasach, nie chce mi sie nad tym myslec, ale twoje funkcje opozniajace nie wygladaja na super dokladne. Wygladaja wrecz na super-niedokladne.

    4\/3!!
  • #3 6304436
    mrrudzin
    Poziom 39  
    Racja - był błąd z operatorami.
    Kawałek kodu zakomentowałem przy którejś z prób znalezienia błędu.
    Co do opóźnień - myśle że wprzypadku LCD nie powinno to mieć większego znaczenia.

    Niestety dalej nie działa :( Ktoś widzi coś jeszcze?
  • REKLAMA
  • #4 6304515
    Freddie Chopin
    Specjalista - Mikrokontrolery
    mrrudzin napisał:

    Co do opóźnień - myśle że wprzypadku LCD nie powinno to mieć większego znaczenia.

    przy takim podejsciu nigdy go nie uruchomiesz. po to sa gotowe funkcje z naglowka delay.h (ktory zreszta dolaczasz, a nie uzywasz), zeby je wykorzystac i nie zastanawiac sie nad tym, czy opoznienie bedzie dokladne czy nie.

    skoro poprawiles kod, to moze wrzuc poprawiony?

    4\/3!!
  • REKLAMA
  • #5 6304792
    mrrudzin
    Poziom 39  
    Nagłówek delay.h rzeczywiście dołączałem, ale nie miałem zainstalowanego AVR-LIBC, więc nie chciało działać. Problem rozwiązany.

    Kod po poprawkach:

    
    #define F_CPU 8000000 // 8MHz zegar procesora
    #define CYCLES_PER_US ((F_CPU+500000)/1000000) // cpu cycles per microsecond
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    #include <utils/delay.h>
    #include <stdio.h>
    #include <avr/pgmspace.h>
    
    #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 
    #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
    
    // Definicje dotyczace LCD 
    #define LCD PORTC           			//port z LCD
    #define RS 4                     		// wybor rejestru
    #define E 5                      		// sygnal zezwalajacy (enable)
    
    #define SET_RS sbi(PORTC,PC4) 
    #define CLR_RS cbi(PORTC,PC4)
    
    #define SET_E sbi(PORTC,PC5) 
    #define CLR_E cbi(PORTC,PC5)
     
    //Definicje i markodeklaracje
    
    #define LEDP1ON sbi(PORTD,PD0) 
    #define LEDP2ON sbi(PORTD,PD1)
    
    #define LEDP1OFF cbi(PORTD,PD0)
    #define LEDP2OFF cbi(PORTD,PD1)
    
    #define LEDP1 PD0 
    #define LEDP2 PD1
    
    
    void write_to_lcd(char x)
    //void write_to_lcd(unsigned int x)
    {
    	//Zapisujemy najpierw starsza czesc bajtu, nastepnie mlodsza
    	//po ustawieniu bajtow na wejsciach LCD wystawiamy sygnal E
    	CLR_E;
    	_delay_ms(5);
    	LCD=(LCD & 0xF0)|(x>>4);//starsza czesc bajtu
    	SET_E;
    	_delay_ms(2);
    	CLR_E;
    	_delay_ms(5);
    	LCD=(LCD & 0xF0)|(x&0x0F);//mlodsza czesc bajtu
    	SET_E;
    	_delay_ms(2);
    	CLR_E;
    }
    
    //procedura zapisu instrukcji do wyświetlacza LCD
    void LCD_write_command(char x)
    {
    	CLR_RS; 								// niski stan na RS -> zapis instrukcji
    	_delay_ms(1);
    	write_to_lcd(x); 						// zapis do LCD
    }
    //procedura zapisu danej do wyświetlacza LCD
    void LCD_write_char(char x)
    {
    	SET_RS; 								// wysoki stan na RS -> zapis danej
    	_delay_ms(1);
    	write_to_lcd(x); 					// zapis do LCD
    }
    //procedura zapisu tekstu do wyświetlacza LCD
    void LCD_write(char * s)
    {
    	while(*s) 								// do napotkania 0
    	  {
    	  LCD_write_char(*s); 						// zapisz znak wskazywany przez s na LCD
    	  s++; 									// zwiększ s (przygotuj nastepny znak)
    	  }
    }
    
    void LCD_write_P(const char *s)
    {
    	register char c;
    	while((c = pgm_read_byte(s))) 		// do napotkania 0
    	{
    	LCD_write_char(c); 						// zapisz znak wskazywany przez s na LCD
    	s++; 								// zwiększ s (przygotuj nastepny znak)
    	}
    }
    //procedura inicjalizacji wyświetlacza LCD
    void LCD_init(void)
    {
    	_delay_ms(15); 			// czekaj 15ms
    	LCD_write_command(0x28);// interfejs 4-bity, 2-linie, znak 5x7
    	LCD_write_command(0x28);
    	LCD_write_command(0x28);
    	LCD_write_command(0x0C);// włącz LCD, bez kursora i mrugania
    	LCD_write_command(0x06);// bez przesuwania w prawo
    	LCD_write_command(0x01);// czyść LCD
    }
    
    //procedura ustawiania pozycji kursora
    void LCD_xy(unsigned char w, unsigned char k)
    {
       LCD_write_command((w*0x40+k) | 0x80);
    }
    //czysci wyswietlacz LCD
    void LCD_clear(void)
    {
       LCD_write_command(0x01);
    }
    
    main()
    {
    DDRC|=_BV(PC0)|_BV(PC1)|_BV(PC2)|_BV(PC3)|_BV(PC4)|_BV(PC5);
    //Diody statusu
    DDRD |= _BV(LEDP1)|_BV(LEDP2);
    
    const unsigned char Wea[]="HELLO"; //stala dla wyswietlacza
    char s="A";
    	do
    	{
    	LEDP1ON;
    	_delay_ms(20);
    	LCD_init();
    	LCD_clear();
    	LEDP1OFF;
    	LCD_write_char(s);
    	LCD_write(Wea);
    	_delay_ms(1000);
    	}
    	while(1);
    }
    
  • REKLAMA
  • #7 6305100
    mrrudzin
    Poziom 39  
    Zmieniłem f-cję wysyłającą bajt do LCD zgodnie z Twymi sugestiami, doinstalowałem AVR-LIBC, teraz delay korzysta z biblioteki. Zmieniłem f-cję inicjalizującą.

    Generalnie narazie błąd musi być w którejś z tych f-cji, bo na wyświetlaczu (4x20) mam dwie linie świecących kwadratów, więc inicjalizacja nie przebiega poprawnie.
  • #8 6305378
    Freddie Chopin
    Specjalista - Mikrokontrolery
    w twoim kodzie nie widze nigdzie procedury resetu wyswietlacza (podanie mu nastepujacych polbajtow: 3, 3, 3, 2), wiec definitywnie inicjalizacja nie dziala. procedura ta jest wlasnie (mniej wiecej, bo z lekkimi bledami) tymi zakomentowanymi kawalkami w twoim pierwszym kodzie, ktory nagle zniknal

    4\/3!!
  • #9 6328064
    mrrudzin
    Poziom 39  
    Problem był w inicjalizacji.
    Powinno być:
    
    LCD_write_command(0x30);
    	LCD_write_command(0x30);
    	LCD_write_command(0x30);
    	LCD_write_command(0x02);
    	LCD_write_command(0x28);// interfejs 4-bity, 2-linie, znak 5x7
    	LCD_write_command(0x08);
    	LCD_write_command(0x06);// bez przesuwania w prawo
    	LCD_write_command(0x0C);// włącz LCD, bez kursora i mrugania
    	LCD_write_command(0x03);
    


    wyświetlacz działa poprawnie :)
REKLAMA