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

[ATtiny 2313][C] LCD - problem

Darektbg 09 Lis 2008 13:18 2416 8
  • #1 5718204
    Darektbg
    Poziom 21  
    
    $regfile = "attiny2313.dat"
    $crystal = 11000000
    Config Portb = &B11111111 : Portb = &B11111111
    Config Portd = &B11111111 : Portd = &B11111111
    
    
    Config Lcdpin = Pin , Db4 = Portb.4 , Db5 = Portb.5 , Db6 = Portb.6 , Db7 = Portb.7 , E = Portb.1 , Rs = Portb.2
    Config Lcd = 16 * 2
    Cls
    Cursor Off Noblink
    
    
    Lcd " HELLO WORLD!!!"
    Lowerline
    Lcd " by GIVER 2008"
    
    Do
    
    Loop
    End
    

    Kod się kompiluje bez problemu, programowanie również przebiega bez problemu, efekt w postaci napisu na wyświetlaczu.

    
    //////////////////////////////////////////////////////////////////////////////////////////////////
    // LCD_simple.c - plik pokazujący prostą obsługę wyświetlacza alfanumerycznego LCD
    // 
    // Autor: Radosław Koppel          Kompilator: WinAVR 20050214
    //////////////////////////////////////////////////////////////////////////////////////////////////
    // Komentarz dodatkowy:
    //  Pierwsza wersja. Założenie, że wyprowadzenia portu podpięto "po koleji"
    //  Brak wygodnych komend, wszystko realizowane na dość niskim poziomie. 
    //////////////////////////////////////////////////////////////////////////////////////////////////
    #include <avr\io.h>
    #include <inttypes.h>
    
    // Makra upraszczające dostęp do portów
    // *** Port
    #define PORT(x) XPORT(x)
    #define XPORT(x) (PORT##x)
    // *** Pin
    #define PIN(x) XPIN(x)
    #define XPIN(x) (PIN##x)
    // *** DDR
    #define DDR(x) XDDR(x)
    #define XDDR(x) (DDR##x)
    
    // Definicje wyprowadzeń
    #define LCD_RS 2
    #define LCD_RSPORT B
    #define LCD_E 1
    #define LCD_EPORT B
    // Port danych: zakładam, że wyprowadzenia są połączone kolejno. 
    // Definiowane jest jedynie przesunięcie oznaczające na którym wyprowadzeniu jest D4
    #define LCD_DPORT B
    #define LCD_D4 4 // D5, D6, D7 - połączone kolejno
    
    // Komendy sterujące wyświetlaczem
    #define LCDC_CLS		0x01
    #define LCDC_HOME		0x02
    #define LCDC_MODE		0x04
    	#define LCDC_MODER		0x02
    	#define LCDC_MODEL		0
    	#define LCDC_MODEMOVE	0x01
    #define LCDC_ON 		0x08
    	#define LCDC_ONDISPLAY	0x04
    	#define LCDC_ONCURSOR	0x02
    	#define LCDC_ONBLINK	0x01
    #define LCDC_SHIFT		0x10
    	#define LCDC_SHIFTDISP	0x08
    	#define LCDC_SHIFTR		0x04
    	#define LCDC_SHIFTL		0
    #define LCDC_FUNC		0x20
    	#define LCDC_FUNC8b		0x10
    	#define LCDC_FUNC4b		0
    	#define LCDC_FUNC2L		0x08
    	#define LCDC_FUNC1L		0
    	#define LCDC_FUNC5x10	0x4
    	#define LCDC_FUNC5x7	0
    #define LCDC_CGA		0x40
    #define LCDC_DDA		0x80
    
    //--------------------------------------------------
    // Generowanie opóźnień
    #define delay250ns() {asm volatile("nop"::);}
    
    #define delayus8(t)\
    	{asm volatile( \
    		"delayus8_loop%=: \n\t"\
    			"nop \n\t"\
    			"dec %[ticks] \n\t"\
    			"brne delayus8_loop%= \n\t"\
    	: :[ticks]"r"(t) );}
    	// DEC - 1 cykl, BRNE 2 cykle, + 1xnop. Zegar 4MHz
    
    void delay100us8(uint8_t t)
    {
    	while(t>0)
    	{
    		delayus8(100); 
    		--t; 
    	}
    }
    // Koniec opóźnień
    //--------------------------------------------------
    
    //--------------------------------------------------
    // Obsługa wyświetlacza
    // Funkcje niskiego poziomu
    #define LCD_EPULSE() \
    	{PORT(LCD_EPORT) |= 1<<LCD_E; \
    	delay250ns(); \
    	PORT(LCD_EPORT) &= ~(1<<LCD_E);}
    
    void LCDsendHalf(uint8_t data)
    {
    	data = (data & 0x0F) << LCD_D4; 
    	//data |= 0xF0;
    	//data &= 0x0F;
    	//data <<= LCD_D4; 
    	PORT(LCD_DPORT) = 
    		(PORT(LCD_DPORT) & ~(0x0F<<LCD_D4)) | data;
    	//PORT(LCD_DPORT) &= ~(0x0F<<LCD_D4); 
    	//PORT(LCD_DPORT) |= data; 
    	LCD_EPULSE();
    }
    
    void LCDsend(uint8_t data)
    {
    	// Starsza część
    	LCDsendHalf(data>>4);
    	// Młodsza część
    	LCDsendHalf(data);
    	delayus8(120);
    }
    
    // Funkcje interfejsu
    void LCDcommand(uint8_t command)
    {
    	PORT(LCD_RSPORT) &= ~(1<<LCD_RS);
    	LCDsend(command);
    }
    
    void LCDdata(uint8_t data)
    {
    	PORT(LCD_RSPORT) |= 1<<LCD_RS;
    	LCDsend(data);
    }
    
    void LCDcls(void)
    {
    	LCDcommand(LCDC_CLS);
    	delay100us8(48);
    }
    
    void LCDhome(void)
    {
    	LCDcommand(LCDC_HOME);
    	delay100us8(48);
    }
    
    void LCDinit(void)
    {
    	delay100us8(150);
    	PORT(LCD_RSPORT) &= ~(1<<LCD_RS);
    	LCDsendHalf(LCDC_FUNC|LCDC_FUNC8b); 
    	delay100us8(41);
    	LCDsendHalf(LCDC_FUNC|LCDC_FUNC8b);
    	delay100us8(2);
    	LCDsendHalf(LCDC_FUNC|LCDC_FUNC4b);
    	delay100us8(2);
    	// Teraz jest już 4b. Koniec korzystania z sendHalf
    	LCDcommand(LCDC_FUNC|LCDC_FUNC4b|LCDC_FUNC2L|LCDC_FUNC5x7);
    	LCDcommand(LCDC_ON);
    	LCDcls();
    	LCDcommand(LCDC_MODE|LCDC_MODER);
    	LCDcommand(LCDC_ON|LCDC_ONDISPLAY|LCDC_ONCURSOR);
    }
    
    // Koniec obsługi wyświetlacza
    //--------------------------------------------------
    
    // START
    int main(void)
    {
    	//----------------------------------------------
    	// Inicjacja - uwaga: uproszczona, może wymagać 
    	// zmian przy zmianie przyporządkowania portów
    	DDR(LCD_DPORT) = 1<<LCD_E | 1<<LCD_RS | 
    		0x0F<<LCD_D4;
    	
    	LCDinit();
    	// Koniec inicjacji
    	//----------------------------------------------
    	
    	// \/ Bez tego, czasami zerowanie z poziomu programatora
    	// \/ powoduje śmieci na wyświetlaczu. 
    	LCDcls(); 
    	
    	LCDdata('H');
    	LCDdata('E');
    	LCDdata('L');
    	LCDdata('L');
    	LCDdata('O');
    	LCDdata(' ');
    	LCDdata(':');
    	LCDdata('-');
    	LCDdata(')');
    	return 0;
    }
    

    Kod się kompiluje, programator procesor zaprogramował, a na wyświetlaczu nic ...
    Podałem pierwszy kod w bascomie, po to, aby pokazać, że mimo takiego samego przyporządkowania wyprowadzeń, kod napisany w bascomie działa a w C już nie.
    Korzystam z kompilatora AVR-GCC 20080610, na innych przykładach kodu, działa bez problemu, więc to nie wina środowiska.
    Połączenie jest również prawidłowe, skoro pierwszy program działa.

    E-B1
    RS-B2
    D4-B4
    D5-B5
    D6-B6
    D7-B7
  • Pomocny post
    #2 5718264
    Samuraj
    Poziom 35  
    Sprawdź opóźnienia to jest bardzo istotne.
    W baskomie masz zadeklarowaną prędkość 11MHz a w C nic takiego nie widzą.
    W komentarzach jest coś o 4MHz ale nie wgryzałem się dokładnie w kod.
  • #3 5718344
    Darektbg
    Poziom 21  
    Zminiłem kwarc na 16 MHz jak i również kod:
    
    #include <avr/io.h>
    //
    #define LCD  PORTB
    #define E  1
    #define RS  2
    //
    #define SET_E   LCD |= _BV(E)
    #define CLR_E   LCD &= ~_BV(E)
    //
    #define SET_RS  LCD |= _BV(RS)
    #define CLR_RS  LCD &= ~_BV(RS)
    
    #define OSC 16
    // definicja funkcji opóźniającej
    void waitms(unsigned char x)
    {
    unsigned char a, b; // zmnienne licznikowe
    for( ; x > 0; --x) // 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"); // dodatkowa instrukcja opóźniająca o 1 cykl
    // razem to da opóźnienie ok. x * 1ms
    // x od 0 do 255
    // gdy x = 0 to opóźnienie = 256ms 
    }
    
    // pcodedura zapisu bajtu do wyświetlacza LCD
    // bez rozróżnienia instrukcja/dana
    void write_to_lcd(char x)
    {
    SET_E; // ustaw na E stan wysoki
    LCD = ((LCD & 0x0F) | (x & 0xF0)); // zapis pierwszej połówki bajtu
    CLR_E; // opadające zbocze na E -> zapis do wyświetlacza
    SET_E; // ustaw na E stan wysoki
    LCD = ((LCD & 0x0F) | ((x & 0x0F) << 4)); // zapis drugiej połowki bajtu
    CLR_E; // opadające zbocze na E -> zapis do wyświetlacza
    waitms(1); // czekaj 1ms
    }
    
    // procedura zapisu instrukcji do wyświetlacza LCD
    void write_command(char x)
    {
    CLR_RS; // niski stan na RS -> zapis instrukcji
    write_to_lcd(x); // zapis do LCD
    }
    
    // procedura zapisu danej do wyświetlacza LCD
    void write_char(char x)
    {
    SET_RS; // wysoki stan na RS -> zapis danej
    write_to_lcd(x); // zapis do LCD
    }
    
    // procedura zapisu tekstu do wyświetlacza LCD
    void write_text(char * s)
    {
    while(*s) // do napotkania 0
      {
      write_char(*s); // zapisz znak wskazywany przez s na LCD
      s++; // zwiększ s (przygotuj nastepny znak)
      }
    }
    
    // procedura inicjalizacji wyświetlacza LCD
    void lcd_init(void)
    {
    waitms(15); // czekaj 15ms na ustabilizowanie się napięcia zasilającego
    CLR_E; // E = 0
    CLR_RS; // RS = 0
    char i; // zmianna licznikowa
    for(i = 0; i < 3; i++) // trzykrotne powtórzenie bloku instrukcji
      {
      SET_E; // E = 1
      LCD &= 0x3F; //
      CLR_E; // E = 0
      waitms(5); // czekaj 5ms
      }
    SET_E; // E = 1
    LCD &= 0x2E; //
    CLR_E; // E = 0
    waitms(1); // czekaj 1ms
    write_command(0x28); // interfejs 4-bity, 2-linie, znak 5x7
    write_command(0x08); // wyłącz LCD, kursor i miganie
    write_command(0x01); // czyść LCD
    write_command(0x06); // bez przesuwania w prawo
    write_command(0x0C); // włącz LCD, bez kursora i mrugania
    }
    
    // program główny
    int main(void)
    {
    // konfiguracja portów we/wy
    DDRB = 0xFF;
    DDRD = 0xFC;
    PORTB = 0xFF;
    PORTD = 0xF7;
    // inicjalizacja LCD
    lcd_init();
    // zapisz na LCD przykładowy tekst
    write_text("Ala ma kota :D");
    // petla nieskończona
    while(1);
    return 0;
    }
    

    Dla ciekawość sprawdziłem bascom, co się okazuje: jaką bym nie zadeklarował wartość kwarca w zmiennej $crystal, wyświetlacz i tak pracuje poprawnie(np. $crystal - 4000000 a kwarc włożony jest 16MHz)
  • Pomocny post
    #4 5720319
    dawid512
    Poziom 32  
    Kwarc zmieniłeś, a fuse bity?
  • #5 5720434
    Darektbg
    Poziom 21  
    oprócz kwarcu nic nie ruszałem. Gdzie i co należy zmienić?
  • Pomocny post
    #6 5720441
    dawid512
    Poziom 32  
    To zmień #define OSC 16 na 1 i nic nie musisz ruszać.
  • #7 5720501
    Darektbg
    Poziom 21  
    Działa! Dzięki za pomoc.
    Mam teraz pytanie:dlaczego po zmianie zmiennej na 1(co odpowiada kwarcowi 1 MHz), program zaczął działać poprawnie, skoro kwarc jest włożony 16 MHz?
  • Pomocny post
    #8 5720784
    dawid512
    Poziom 32  
    Dzieje się tak bo domyślnie procek jest ustawiony na wew. generator 1MHz. To że miałeś podłączony 16MHz nic nie zmienia bo procek go "nie widzi". Żeby przełączyć się na zew. kwarc trzeba zmienić fuse bity.
  • #9 5721090
    Darektbg
    Poziom 21  
    Ok, teraz już rozumie.
    Jeszcze raz dziękuję.
REKLAMA