Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[ATmega32][C] Kurs progamowania w C z EdW Lekcja 9

mgiro 23 Dec 2010 07:43 5125 18
  • #1
    mgiro
    Level 22  
    Witam,

    Jestem w trakcie przerabiania kursu z EdW
    [ATmega32][C] Kurs progamowania w C z EdW Lekcja 9

    Pracuje na zestawie startowym ZL3AVR [ATmega32 + kwarc 16MHz]

    Podczas pisania kursu była biblioteka avrlib 1.4, teraz pracuję na 1.6. Mam problem z kompilacją programu. Powstają następujące błędy:

    [ATmega32][C] Kurs progamowania w C z EdW Lekcja 9

    Zamieszczam kod programu:
    
    /////////////////////////////////////////////////////////////////////////////////////////////
    // main.c - testowanie zaawansowanej obsługi alfanumerycznego wyświetlacza LCD
    //		Program dla płytki testowej AVT3505
    //
    // Autor: Radosław Koppel	Kompilator: WinAVR 20060125
    /////////////////////////////////////////////////////////////////////////////////////////////
    #include <avr/io.h>
    #include <inttypes.h>
    #include <stdio.h>
    #include <avr/pgmspace.h>
    #include <util/delay.h>
    
    #include "makra.h"
    #include "harddef.h"
    #include "lcd.h"
    #include "local.h"
    
    // Opóźnienie o 10ms x t
    void delay_10ms8(uint8_t t)
    {
    	do
    	{
    		_delay_ms(10); // dla 8MHz możemy opóźnić o max 32ms
    	} while(t--!=0);
    }
    
    int main(void)
    {
    	// Inicjacja wyprowadzeń
    	DDR(LCD_CTRLPORT) = (1<<LCD_E | 1<<LCD_RW | 1<<LCD_RS | 1<<LCD_LED); 
    	PORT(LCD_CTRLPORT) = ~(1<<LCD_E | 1<<LCD_LED); 
    	// Test biblioteki wyświetlacza
    	lcd_Init();
    	
    	lcd_SetStatus(LCD_STATUS_DISP|LCD_STATUS_CURSOR);
    	// Wypisanie przywitania
    	fputs_P(str_Hello, lcd_GetFile());
    	lcd_Update();
    	delay_10ms8(200);
    	// Przewijanie 
    	uint8_t start=0;
    	for(;;)
    	{
    		lcd_Cls();
    		fputs_P(str_all+start, lcd_GetFile());
    		lcd_Update();
    		
    		if(++start >= strlen_P(str_all))
    			start = 0;
    			
    		delay_10ms8(100);
    	}
    	return 0;
    }
    
    

    
    /////////////////////////////////////////////////////////////////////////////////////////////
    // lcd.c - plik źródłowy do obsługi alfanumerycznego wyświetlacza LCD.
    //			! Dynamiczne przydzielanie znaków specjalnych !
    //
    // Autor: Radosław Koppel	Kompilator: WinAVR 20060125
    /////////////////////////////////////////////////////////////////////////////////////////////
    #include <avr/io.h>
    #include <inttypes.h>
    #include <util/delay.h>
    #include <string.h>
    #include <avr/pgmspace.h>
    
    #include "makra.h"
    #include "harddef.h"
    #include "lcd.h"
    #include "local.h"
    
    //__________________________________________________________________________________________
    // Definicje stałych
    // 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
    
    //__________________________________________________________________________________________
    // Deklaracje funkcji które muszą być tutaj zdeklarowane
    static int lcd_put(char c, FILE* f);
    
    //__________________________________________________________________________________________
    // Zmienne
    // Korzystamy z nowej możliwości avrlibc 1.4
    static FILE lcd_fLCD_temp = FDEV_SETUP_STREAM(lcd_put, NULL, _FDEV_SETUP_WRITE);
    #define lcd_fLCD (&lcd_fLCD_temp)
    
    // Uwaga - wyświetlacz niewykorzystuje kodów 0x80-0x9f. To 32 kody które zostaną wykorzystane dla znaków specjalnych
    static char lcd_buffer[LCD_SX*LCD_SY];
    // Aktualne pozycja kursora (dotyczy bufora i jest aktualizwana przy odświerzaniu napisu)
    static uint8_t lcd_curpos;
    // Informacja o tym jakie znaki specjalne zostały zapisane do wyświetlacza
    static uint8_t lcd_spec[8];
    // Zmienna przechowująca flagi na temat włączenia wyświetlacza (wyświetlacz, kursor, migający kursor)
    static uint8_t lcd_status;
    
    //__________________________________________________________________________________________
    // Obsługa LCD - funkcje niskiego poziomu
    
    // Impuls ENABLE - przede wszystkim dla zapisu
    // Odczyt wymaga trochę bardziej skomplikowanej sekwencji
    #define lcd_epulse() \
    	{PORT(LCD_CTRLPORT) |= 1<<LCD_E; \
    	_delay_us(0.25); \
    	PORT(LCD_CTRLPORT) &= ~(1<<LCD_E);}
    
    // Odbiór danej - funkcja wewnętrzna
    static inline uint8_t lcd_Get(void)
    {
    	uint8_t dana; 
    	// Ustawienie portu lcd jako wejścia
    	DDR(LCD_DATAPORT) = 0x00; 
    	// Aktywacja odczytu
    	PORT(LCD_CTRLPORT) |= 1<<LCD_E; 
    	// \/ Uwaga - sprawdziłem eksperymentalnie, 
    	// \/ że 0.5us to czasami za mało
    	// \/ przy podłączonym programatorze wyświetlacz
    	// \/ wciąż gubił dane
    	_delay_us(1);
    	// Skopiowanie danych z wyjścia modułu
    	dana = PIN(LCD_DATAPORT); 
    	// Deaktywacja wyjścia ENABLE
    	PORT(LCD_CTRLPORT) &= ~(1<<LCD_E); 
    	return dana; 
    }
    
    uint8_t lcd_GetBF(void)
    {
    	// Wysterowanie wyprowadzeń do odczytu statusu
    	PORT(LCD_CTRLPORT) |= 1<<LCD_RW; 
    	PORT(LCD_CTRLPORT) &= ~(1<<LCD_RS);
    	// Odczekanie wymaganego przez sterownik czasu
    	_delay_us(0.25);
    	// Odczyt danej
    	return lcd_Get(); 
    }
    
    // Sprawdza flagę zajętości i czeka na jej wyzerowanie
    void lcd_WaitBF(void)
    {
    	// Bit zajętości to bit najstarszy
    	while(0 != (0x80 & lcd_GetBF())) {}; 
    }
    
    // Wysłanie danej - funkcja wewnętrzna
    static void lcd_Send(uint8_t dana)
    {
    	// Ustawienie portu lcd jako wyjścia
    	DDR(LCD_DATAPORT) = 0xFF; 
    	// Presłanie na port danej
    	PORT(LCD_DATAPORT) = dana; 
    	// Przesłanie do lcd
    	lcd_epulse(); 
    }
    
    // Wysłanie danej do pamięci DDRAM lub CGRAM
    // Zależnie od ustawionego adresu
    void lcd_SendData(uint8_t dana)
    {
    	lcd_WaitBF();
    	// Wysterowanie wyprowadzeń dla zapisu danej
    	PORT(LCD_CTRLPORT) &= ~(1<<LCD_RW); 
    	PORT(LCD_CTRLPORT) |= 1<<LCD_RS; 
    	// Odczekanie oraz wysłanie
    	_delay_us(0.25); 
    	lcd_Send(dana); 
    }
    
    // Wysłanie instrukcji sterującej
    void lcd_SendInstr(uint8_t dana)
    {
    	lcd_WaitBF();
    	// Wysterowanie wyprowadzeń dla zapisu instrukcji
    	PORT(LCD_CTRLPORT) &= ~(1<<LCD_RW | 1<<LCD_RS);
    	// Odczekanie oraz wysłanie
    	_delay_us(0.25); 
    	lcd_Send(dana); 
    }
    
    //__________________________________________________________________________________________
    // Funkcje obsługujące wejście wyjście strumienia
    static int lcd_put(char c, FILE* f)
    {
    	// Zabezpieczenie przed przepełnieniem
    	if(lcd_curpos >= ELEMS(lcd_buffer))
    		lcd_curpos = 0;
    	// Zapis do bufora
    	lcd_buffer[lcd_curpos++] = c;
    	return 0;
    }
    
    //__________________________________________________________________________________________
    // Funkcje interfejsu
    
    // inicjacja LCD (uwaga - nie włączam wyświetlacza ani kursora)
    void lcd_Init(void)
    {
    	lcd_Cls();
    	PORT(LCD_CTRLPORT) &= ~(1<<LCD_RW | 1<<LCD_RS); 
    	_delay_us(0.25); 
    	lcd_Send(LCDC_FUNC | LCDC_FUNC8b); 
    	_delay_ms(4.3); 
    	lcd_Send(LCDC_FUNC | LCDC_FUNC8b); 
    	_delay_us(200); 
    	lcd_Send(LCDC_FUNC | LCDC_FUNC8b); 
    	// Już można sprawdzać BF
    #if LCD_SY == 1
    	lcd_SendInstr(LCDC_FUNC | LCDC_FUNC8b | LCDC_FUNC1L); 
    #else
    	lcd_SendInstr(LCDC_FUNC | LCDC_FUNC8b | LCDC_FUNC2L); 
    #endif
    	lcd_SendInstr(LCDC_ON);
    	lcd_SendInstr(LCDC_CLS);
    	lcd_SendInstr(LCDC_MODE | LCDC_MODER); 
    	lcd_WaitBF();
    	// Koniec inicjacji. Wyjątkowo czekam na zakończenie. Normalnie BF jest sprawdzana przed wykonaniem indtrukcji 
    	// - daje to większą oszczędność czasu. Podczas inicjacji nie ma to wielkiego znaczenia. 
    }
    
    // Zerowanie bufora wyświetlacza
    void lcd_Cls(void)
    {
    	lcd_curpos = 0;
    	memset(lcd_buffer, ' ', sizeof(lcd_buffer));
    }
    
    // kontrola włączenia wyświetlacza, kursora, migającego kursora
    void lcd_SetStatus(uint8_t status)
    {
    	lcd_status = status;
    }
    
    // Odswierzenie statusu
    inline void lcd_UpdateStatus(void)
    {
    	lcd_SendInstr(LCDC_ON | lcd_status);
    }
    
    // Funkcja wewnętrzna podająca początek danej linii
    static uint8_t lcd_LineStart(uint8_t line)
    {
    #if LCD_SY == 1
    	return LCD_LINE1;
    #elif LCD_SY == 2
    	if(line == 0)
    		return LCD_LINE1;
    	else
    		return LCD_LINE2;
    #elif LCD_SY == 4
    	if(line == 0)
    		return LCD_LINE1;
    	else if(linenum == 1)
    		return LCD_LINE2;
    	else if(linenum == 2)
    		return LCD_LINE3;
    	else
    		return LCD_LINE4;
    #else
    #error Unknown display type!
    #endif
    }
    
    // Ustawienie kursora
    inline void lcd_GoToAdr(uint8_t adr)
    {
    	lcd_curpos = adr;
    }
    
    // Odswierzenie pozycji kursora
    void lcd_UpdateCurPos(void)
    {
    	// Obliczenie adresu w wyświetlaczu
    	uint8_t adres = 
    		lcd_LineStart(lcd_curpos / LCD_SX) + (lcd_curpos % LCD_SX);
    	// Wysłanie instrkucji ustawiającej kursor
    	lcd_SendInstr(LCDC_DDA | adres);
    }
    
    // Wewnętrzna pomocnicza funkcja sprawdzająca czy dany znak jest znakiem specjalnym
    static uint8_t lcd_IsSpec(char c)
    {
    	// Przydział znaków specjalnych na obszar którego LCD nie wykorzystuje
    	return (c >= 0x80) && (c <= 0x9f);
    }
    
    // Zamiana znaku specjalnego na odpowiedni numer w tablicy symboli
    static inline uint8_t lcd_Spec2Index(char c)
    {
    	return c-0x80;
    }
    
    // Funkcja sprawdzajaca czy w tablicy jest podany znak
    // Zwraca: indeks w tablicy gdzie znajduje sie dany znak
    //  lub kod znaku alternatywnego (zawsze >= 0x20)
    static uint8_t lcd_GetSpec(uint8_t s_index)
    {
    	uint8_t a; 
    	for(a=0; a<ELEMS(lcd_spec); a++)
    	{
    		// 0xff oznacza, że nie ma już dalej wpisów
    		if(lcd_spec[a] == 0xff)
    			break; 
    		// Jeśli znaleziono...
    		else if(lcd_spec[a] == s_index)
    			return a; 
    	}
    	// Nic nie znaleziono
    	return pgm_read_byte(&(local_lcdspec[s_index].cAlt));
    }
    
    // Makro pomocnicze
    #define LCD_SPECNF(spec) (spec > 7)
    
    // Funkcja przydzielająca znaki specjalne
    // Zwraca ilość różnych znaków jaką znaleziono. Jeśli > 8 części znaków nie udało się przydzielić
    uint8_t lcd_PrepareSpec(void)
    {
    	// Analizuję cały łańcuch danych i zapisuję kolejno znalezione znaki
    	char* pbuffer = lcd_buffer;
    	uint8_t n;
    	uint8_t cnt=0;
    	char znak;
    	// Na początku "zerowanie" tablicy znaków specjalnych
    	memset(lcd_spec, 0xff, sizeof(lcd_spec));
    	// dodawanie wpisów
    	for(n=0; n<ELEMS(lcd_buffer); n++)
    	{
    		znak = *pbuffer++;
    		// Jeśli znaleziony znak jest specjalny
    		if(lcd_IsSpec(znak))
    		{
    			// Przeszukanie tablicy
    			znak = lcd_Spec2Index(znak);
    			// Jeśli nie znaleziono - dodawanie
    			if(LCD_SPECNF(lcd_GetSpec(znak)))
    			{
    				// dodaj do tablicy tylko jeśli 
    				// nie wystąpiło przepełnienie
    				if(cnt < ELEMS(lcd_spec))
    					lcd_spec[cnt] = znak;
    				// Licznik zwiększany zawsze
    				// dla statystyki
    				++cnt;
    			}
    		}
    	}
    	return cnt;
    }
    
    // Funkcja zapisująca definicje znaków do pamięci CGRAM wyświetlacza
    void lcd_UpdateCGRAM(void)
    {
    	// Ustawiam adres w module na początek definicji znaków: 
    	lcd_SendInstr(LCDC_CGA); 
    	// Przesyłanie bloków - tylko do czasu aż mam 0xff w tablicy - koniec danych
    	uint8_t a; 
    	for(a=0; a<ELEMS(lcd_spec); a++)
    	{
    		// 0xff oznacza koniec danych
    		if(lcd_spec[a] == 0xff) break;
    		// Wskaźnik na początek danych wyglądu znaku
    		uint8_t* pdata = local_lcdspec[lcd_spec[a]].matrix;
    		// Wysyłam kolejny indeks
    		uint8_t bait;
    		for(bait=0; bait<8; bait++)
    		{
    			lcd_SendData(pgm_read_byte(pdata++)); 
    		}
    	}
    }
    
    // Funckcja odświerzająca dane w pamięci DDRAM wyświetlacza
    // Aby wyświetlanie przebiegło prawidłowo pamięć CGRAM musi być już ustawiona
    void lcd_UpdateText(void)
    {
    	uint8_t x, y;
    	
    	char *pbuffer = lcd_buffer;
    	// Przetwarzanie każdej linii oddzielnie
    	for(y=0; y<LCD_SY; y++)
    	{
    		lcd_SendInstr(LCDC_DDA | lcd_LineStart(y));
    		// Wysłanie wszystkich znaków z danej linii
    		for(x=0; x<LCD_SX; x++)
    		{
    			uint8_t znak = *pbuffer++;
    			if(lcd_IsSpec(znak))
    				znak = lcd_GetSpec(lcd_Spec2Index(znak));
    			// Znak gotowy do wysłania
    			lcd_SendData(znak);
    		}
    	}
    }
    
    // Odświerzenie wszystkich danych wyświetlacza
    void lcd_Update(void)
    {
    	lcd_PrepareSpec();
    	lcd_UpdateCGRAM();
    	// Wyłączenie kursora na czas odświerzania
    	lcd_SendInstr(LCDC_ON | (lcd_status & LCD_STATUS_DISP));
    	lcd_UpdateText();
    	lcd_UpdateCurPos();
    	// Ponowne włączenie kursora (jeśli był włączony)
    	lcd_UpdateStatus();
    }
    
    //__________________________________________________________________________________________
    // Funkcja podająca uchwyt do strumienia
    inline FILE* lcd_GetFile(void)
    {
    	return lcd_fLCD;
    }
    


    
    /////////////////////////////////////////////////////////////////////////////////////////////
    // local.c - wszystkie dane lokalizowalne
    //
    // Autor: Radosław Koppel	Kompilator: WinAVR 20060125
    /////////////////////////////////////////////////////////////////////////////////////////////
    #include <avr/pgmspace.h>
    
    #include "lcd.h" // potrzebuję tego nagłówka ze względu na definicję tablicy znaków specjalnych
    
    // Definicja znaków narodowych
    // (Polski ma ich 18)
    LCD_LOCAL_PGM local_lcdspec[18] = 
    {
    	// Znaczki - poprawiłem pod względem wyglądu znaczki z EdW 1/98, dodałem brakujące
    	{{0, 0, 14, 1, 15, 17, 15, 2}, 'a'},    //ą - kod 0x80
    	{{2, 4, 14, 16, 16, 17, 14, 0}, 'c'},   //ć - kod 0x81
    	{{0, 0, 14, 17, 31, 16, 14, 2}, 'e'},   //ę - kod 0x82
    	{{12, 4, 6, 4, 12, 4, 14, 0}, 'l'},     //ł - kod 0x83
    	{{2, 4, 22, 25, 17, 17, 17, 0}, 'n'},   //ń - kod 0x84
    	{{2, 4, 14, 17, 17, 17, 14, 0}, 'o'},   //ó - kod 0x85
    	{{2, 4, 14, 16, 14, 1, 30, 0}, 's'},    //ś - kod 0x86
    	{{2, 4, 31, 2, 4, 8, 31, 0}, 'z'},      //ź - kod 0x87
    	{{4, 0, 31, 2, 4, 8, 31, 0}, 'z'},      //ż - kod 0x88
    	{{14, 17, 17, 31, 17, 17, 17, 2}, 'A'}, //Ą - kod 0x89
    	{{2, 14, 21, 16, 16, 16, 17, 14}, 'C'}, //Ć - kod 0x8a
    	{{31, 16, 16, 30, 16, 16, 31, 2}, 'E'}, //Ę - kod 0x8b
    	{{16, 16, 20, 24, 16, 16, 31, 0}, 'L'}, //Ł - kod 0x8c
    	{{2, 21, 17, 25, 21, 19, 17, 17}, 'N'}, //Ń - kod 0x8d
    	{{2, 14, 21, 17, 17, 17, 17, 14}, 'O'}, //Ó - kod 0x8e
    	{{2, 15, 20, 16, 14, 1, 1, 30}, 'S'},   //Ś - kod 0x8f
    	{{2, 31, 5, 2, 4, 8, 16, 31}, 'Z'},     //Ź - kod 0x90
    	{{4, 31, 1, 2, 4, 8, 16, 31}, 'Z'},     //Ż - kod 0x91
    }; 
    
    // Napisy
    prog_char str_Hello[] = "Cze\x86\x81";
    //prog_char str_Hello[] = "fl\x80dra";
    //prog_char str_Hello[] = "fl\x80""dra";
    prog_char str_all[] = "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91";
    
    


    
    /////////////////////////////////////////////////////////////////////////////////////////////
    // lcd.h - plik nagłówkowy do obsługi alfanumerycznego wyświetlacza LCD.
    //			! Dynamiczne przydzielanie znaków specjalnych !
    //
    // Autor: Radosław Koppel	Kompilator: WinAVR 20060125
    /////////////////////////////////////////////////////////////////////////////////////////////
    #ifndef LCD_H_INCLUDED
    #define LCD_H_INCLUDED
    
    #include <avr/pgmspace.h>
    #include <stdio.h>
    
    // Struktura definiująca wygląd znaku specjalnego
    typedef struct LCD_LOCAL
    {
    	uint8_t matrix[8]; // Matryca znaku
    	char cAlt; // Znak alternatywny
    }LCD_LOCAL_PGM PROGMEM; 
    
    // Definicje funkcji interfejsu
    void lcd_Init(void);
    void lcd_Cls(void);
    void lcd_SetStatus(uint8_t status);
    	#define LCD_STATUS_BLINK 0x01
    	#define LCD_STATUS_CURSOR 0x02
    	#define LCD_STATUS_DISP 0x04
    inline void lcd_UpdateStatus(void);
    inline void lcd_GoToAdr(uint8_t adr);
    	#define lcd_GoTo(x, y) lcd_GoToAdr(y*LCD_SX+x);
    void lcd_UpdateCurPos(void);
    uint8_t lcd_PrepareSpec(void);
    void lcd_UpdateCGRAM(void);
    void lcd_UpdateText(void);
    void lcd_Update(void);
    
    inline FILE* lcd_GetFile(void);
    
    #endif // LCD_H_INCLUDED
    


    
    /////////////////////////////////////////////////////////////////////////////////////////////
    // local.h - plik nagłówkowy do wszystkich danych które muszą zostać zlokalizowane
    //		teksty oraz znaki narodowe (specjalne)
    // Dołącz ten plik wszędzie tam gdzie chcesz korzystać ze zmiennych zawartych w local.c
    //
    // Autor: Radosław Koppel	Kompilator: WinAVR 20060125
    /////////////////////////////////////////////////////////////////////////////////////////////
    #ifndef LOCAL_H_INCLUDED
    #define LOCAL_H_INCLUDED
    extern LCD_LOCAL_PGM local_lcdspec[];
    extern prog_char str_Hello[];
    extern prog_char str_all[];
    
    #endif // LOCAL_H_INCLUDED
    


    
    /////////////////////////////////////////////////////////////////////////////////////////////
    // harddef.h - definicja sprzętu dla programu zaawansowanej obsługi alfanumerycznego wyśw. LCD
    //
    // Autor: Radosław Koppel	Kompilator: WinAVR 20060125
    /////////////////////////////////////////////////////////////////////////////////////////////
    #ifndef HARDDEF_H_INCLUDED
    #define HARDDEF_H_INCLUDED
    
    //__________________________________________________
    // Definicje wyświetlacza LCD
    // Informacje o typie wyświetlacza
    #define LCD_SX 16
    #define LCD_SY 2
    #define LCD_LINE1 0
    #define LCD_LINE2 64
    // Podłączenie
    #define LCD_DATAPORT B
    #define LCD_CTRLPORT D
    #define LCD_E 4
    #define LCD_RW 3
    #define LCD_RS 2
    #define LCD_LEDPORT D
    #define LCD_LED 5
    
    
    #endif // HARDDEF_H_INCLUDED
    
    


    
    //////////////////////////////////////////////////////////////////////////////////////////////////
    // makra.h - makra pomocnicze 
    // 
    // Autor: Radosław Koppel          Kompilator: WinAVR 20050214
    //////////////////////////////////////////////////////////////////////////////////////////////////
    #ifndef MAKRA_H_INCLUDED
    #define MAKRA_H_INCLUDED
    
    // 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)
    
    // NOPek
    #define NOP() {asm volatile("nop"::);}
    
    // Ilość elementów tablicy
    #define ELEMS(p) (sizeof(p)/sizeof(p[0]))
    
    
    #endif //MAKRA_H_INCLUDED
    


    Poniżej zamieszczam pdf z opisem lekcji:
    http://www.sendspace.com/file/h3hl3m

    Szukałem informacji w plikach biblioteki avrlib, ale nie udało się mi usunąć tych błędów. Miał ktoś również kłopot z tą lekcją kursu??
  • #2
    maly_elektronik
    Level 23  
    Dodałeś do pliku makefile plik lcd.c :?:
    Jeżeli tak to spróbuj dodać includa pliku ze zmiennymi globalnymi na samej górze pliku main.c (pod standardowymi includami)
  • #3
    User removed account
    User removed account  
  • #4
    mgiro
    Level 22  
    Ale w AVR Studio nie tworzy sie pliku makefile.

    Problem moim zdaniem jest z "fputs_P(str_Hello, lcd_GetFile()); " a dokladnie z funkcja lcd_GetFile().

    To jest połączone z:
    
    inline FILE* lcd_GetFile(void)
    {
       return lcd_fLCD;
    } 
    

    W avrlib 1.6 inaczej deklaruje się FILE*, a gdzieś znalazłem, że można się go w ogole pozbyć. Tylko nie wiem, jak to zrobić.
  • Helpful post
    #5
    Andrzej__S
    Level 28  
    W pliku 'lcd.h':

    #1 Usuń wszystkie 'inline'.

    #2 Zamiast:
    
    typedef struct LCD_LOCAL 
    { 
       uint8_t matrix[8]; // Matryca znaku 
       char cAlt; // Znak alternatywny 
    }LCD_LOCAL_PGM PROGMEM;
    

    napisz:
    
    typedef struct
    { 
       uint8_t matrix[8]; // Matryca znaku 
       char cAlt; // Znak alternatywny 
    }LCD_LOCAL_PGM;
    


    W pliku 'local.h':

    Zmień:
    
    extern LCD_LOCAL_PGM local_lcdspec[]; 
    

    na:
    
    extern LCD_LOCAL_PGM local_lcdspec[] PROGMEM;
    


    Podobnie w pliku 'local.c' linijkę:
    
    LCD_LOCAL_PGM local_lcdspec[18] =
    

    zmień na:
    
    LCD_LOCAL_PGM local_lcdspec[18] PROGMEM =
    


    Powinno się skompilować. Czy będzie działać, to już musisz przetestować sam.

    P.S. No i powinieneś przed #include <util/delay.h> zdefiniować częstotliwość taktowania procesora, czyli F_CPU, bo opóźnienia mogą być nieprawidłowe.
  • #6
    mgiro
    Level 22  
    Dzięki Andrzej__S, działa.

    Powiedz mi jeszcze, dlaczego trzeba zrobić takie zmiany. Mógłbyś to krótko wytłumaczyć??
  • #7
    LordBlick
    VIP Meritorious for electroda.pl
    Andrzej__S wrote:
    P.S. No i powinieneś przed #include <util/delay.h> zdefiniować częstotliwość taktowania procesora, czyli F_CPU, bo opóźnienia mogą być nieprawidłowe.
    Takie rzeczy to tylko w Makefile się robi, podobnie jak deklaracja procesora... ;)
    Drobny przykład :
    PROJECT = ATmega8515_test
    MCU = atmega8515
    CC = avr-gcc
    F_CPU=11059200
    ## Options common to compile, link and assembly rules
    COMMON = -mmcu=${MCU}
    [...]
    CFLAGS = ${COMMON}
    CFLAGS += -Wall -gdwarf-2 -std=gnu99 -DF_CPU=${F_CPU}UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
    CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d 
    
  • #8
    szelus
    Level 34  
    mgiro wrote:
    Powiedz mi jeszcze, dlaczego trzeba zrobić takie zmiany. Mógłbyś to krótko wytłumaczyć??

    Bo atrybuty, w rodzaju PROGMEM, czyli przypisanie do konkretnej sekcji pamięci, mogą mieć tylko zmienne, a nie typy danych.
    Natomiast atrybut inline ma sens tylko wtedy, jeżeli kompilator w momencie użycia funkcji zna jej definicję, a nie tylko deklarację. W praktyce oznacza to, że w nagłówku musi znaleźć się kompletna definicja funkcji, a nie tylko prototyp. I, oczywiście, funkcje inline definiowane w nagłówkach nie mogą się odwoływać do zmiennych static, bo będą się odwoływały do różnych zmiennych, mimo tej samej nazwy.
  • #9
    Andrzej__S
    Level 28  
    Light-I wrote:

    Andrzej__S wrote:

    P.S. No i powinieneś przed #include <util/delay.h> zdefiniować częstotliwość taktowania procesora, czyli F_CPU, bo opóźnienia mogą być nieprawidłowe.

    Takie rzeczy to tylko w Makefile się robi, podobnie jak deklaracja procesora...

    Na pewno masz rację, tylko że wcześniej:
    mgiro wrote:

    Ale w AVR Studio nie tworzy sie pliku makefile.

    W AVR Studio należałoby w menu "Project/Configuration Options" zaznaczyć opcję "Use External Makefile" i edytować plik Makefile ręcznie, co dla początkującego programisty może stanowić problem. #define F_CPU 11059200UL przed #include <util/delay.h> też zadziała :)
  • #10
    landy13
    Level 31  
    Andrzej__S wrote:

    mgiro wrote:

    Ale w AVR Studio nie tworzy sie pliku makefile.

    W AVR Studio należałoby w menu "Project/Configuration Options" zaznaczyć opcję "Use External Makefile" i edytować plik Makefile ręcznie, co dla początkującego programisty może stanowić problem. #define F_CPU 11059200UL przed #include <util/delay.h> też zadziała :)


    W AVR Studio nie tworzy się pliku Makefile, bo AVR Studio "samo" tworzy plik Makefile.
    W menu "Project/Configuration Options" jest okienko "Frequency" jak też "Device" i in. Zmiany tam wprowadzone skutkują zmianami w automatycznie tworzonym pliku Makefile.
  • #11
    dondu
    Moderator on vacation ...
    landy13 wrote:
    W AVR Studio nie tworzy się pliku Makefile, bo AVR Studio "samo" tworzy plik Makefile.

    W specyficznych przypadkach (sam się ostatnio przekonałem przy projekcie V-USB) użycie w AVR Studio zewnętrznego pliku Makefile (autora V-USB) jest konieczne i robi się to tak jak pisze Andrzej.
  • #12
    landy13
    Level 31  
    dondu wrote:
    W specyficznych przypadkach (sam się ostatnio przekonałem przy projekcie V-USB) użycie w AVR Studio zewnętrznego pliku Makefile (autora V-USB) jest konieczne i robi się to tak jak pisze Andrzej.
    Może masz rację, choć zamiast słowa "konieczne" użyłbym "pożądane".
    W mojej krótkiej znajomości z AVR Studio nie miałem tak "specyficznych przypadków", a omawiany w tym temacie też chyba do nich nie należy.
  • #13
    Andrzej__S
    Level 28  
    landy13 wrote:

    Może masz rację, choć zamiast słowa "konieczne" użyłbym "pożądane".

    Być może wyraziłem swoje myśli mało precyzyjnie. Oczywiście, że można w "Configuration Options" ustawić częstotliwość taktowania procesora, co skutkuje zmianami w pliku Makefile. Niemniej przykład Light-I podany był w formie tekstowej, a żeby wpisanie tego (lub odpowiednio zmodyfikowanego) fragmentu tekstu do pliku Makefile odniosło skutek, trzeba zaznaczyć opcję "Use External Makefile", bo inaczej AVR Studio i tak będzie używało własnego pliku Makefile (nawet, jeśli edytujemy właśnie ten przez niego utworzony). Właśnie dlatego użyłem słowa "konieczne".

    Poza tym sami autorzy (czy też jeden z autorów) avr-libc podają w komentarzach pliku "delay.h" dwie alternatywne metody:
    Quote:

    
    ...............
        \code
        #define F_CPU 1000000UL  // 1 MHz
        //#define F_CPU 14.7456E6
        #include <util/delay.h>
        \endcode
    
        \note As an alternative method, it is possible to pass the
        F_CPU macro down to the compiler from the Makefile.
        Obviously, in that case, no \c \#define statement should be
        used.
    .................
    


    więc chyba użycie #define F_CPU 1000000UL jest dopuszczalne, przynajmniej w tym konkretnym przypadku.
    Oczywiście zgadzam się, że zdefiniowanie F_CPU w pliku Makefile dla większych projektów jest na pewno wygodniejsze.

    To chyba na tyle, bo zdaje mi się, że odbiegamy od tematu :)
  • #14
    mgiro
    Level 22  
    szelus, mógłbyś wytłumaczyć te zmiany troszeczkę obszerniej, bo nie bardzo rozumiem.
  • #15
    mgiro
    Level 22  
    Przystąpiłem do lekcji 10. Zrobiłem analogiczne poprawki, jak w lekcji 9, ale niestety również nie mogę skompilować kodu. Poświęciłem praktycznie cały dzień na szukaniu przyczyny.

    Pojawiają się takie błędy przy kompilacji:

    [ATmega32][C] Kurs progamowania w C z EdW Lekcja 9

    Tutaj zamieszczam kod programu po moich poprawkach:

    
    /////////////////////////////////////////////////////////////////////////////////////////////
    // main.c - testowanie możliwości zmiany języka
    //
    // Autor: Radosław Koppel	Kompilator: WinAVR 20060125
    /////////////////////////////////////////////////////////////////////////////////////////////
    #include <avr/io.h>
    #include <stdio.h>
    #include <util/delay.h>
    #include "makra.h"
    #include "harddef.h"
    //#include "makra.h"
    #include "lcd.h"
    #include "langsys.h"
    
    void uint8_t sw_wait(void)
    {
    	for(;;)
    	{
    		// Oczekiwanie na naciśnięcie przycisku
    		if(!(PIN(SW_PORT) & 1<<SW1))
    		{
    			_delay_ms(30);
    			if(!(PIN(SW_PORT) & 1<<SW1))
    				return 1;
    		}
    		if(!(PIN(SW_PORT) & 1<<SW2))
    		{
    			_delay_ms(30);
    			if(!(PIN(SW_PORT) & 1<<SW2))
    				return 2;
    		}
    	}
    }
    
    int main(void)
    {
    	// Inicjacja wyprowadzeń
    	DDR(LCD_CTRLPORT) = (1<<LCD_E | 1<<LCD_RW | 1<<LCD_RS | 1<<LCD_LED); 
    	PORT(LCD_CTRLPORT) = ~(1<<LCD_E | 1<<LCD_LED); 
    	PORT(SW_PORT) = 1<<SW1 | 1<<SW2;
    	// Inicjacja wyświetlacza
    	lcd_Init();
    	lcd_SetStatus(LCD_STATUS_DISP);
    	
    	// Wyświetlenie zapytania o język
    	fputs_P(PSTR("S1 - "), lcd_GetFile());
    	fputs_P(langsys_GetLangName(0), lcd_GetFile());
    	lcd_GoTo(0, 1);
    	fputs_P(PSTR("S2 - "), lcd_GetFile());
    	fputs_P(langsys_GetLangName(1), lcd_GetFile());
    	lcd_Update();
    	
    	// Oczekiwanie na przycisk i wybranie odpowiedniego języka
    	langsys_Select(sw_wait()-1);
    	
    	// Wyświetlenie przywitania w wybranym języku
    	lcd_Cls();
    	fputs_P(langsys_GetText(IDS_Start), lcd_GetFile());
    	lcd_Update();
    	
    	return 0;
    }
    
    

    
    /////////////////////////////////////////////////////////////////////////////////////////////
    // lcd.c - plik źródłowy do obsługi alfanumerycznego wyświetlacza LCD.
    //			! Dynamiczne przydzielanie znaków specjalnych !
    //
    // Autor: Radosław Koppel	Kompilator: WinAVR 20060125
    /////////////////////////////////////////////////////////////////////////////////////////////
    #include <avr/io.h>
    #include <inttypes.h>
    #include <util/delay.h>
    #include <string.h>
    #include <avr/pgmspace.h>
    
    #include "makra.h"
    #include "harddef.h"
    #include "lcd.h"
    #include "langsys.h"
    
    //__________________________________________________________________________________________
    // Definicje stałych
    // 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
    
    //__________________________________________________________________________________________
    // Deklaracje funkcji które muszą być tutaj zdeklarowane
    static int lcd_put(char c, FILE* f);
    
    //__________________________________________________________________________________________
    // Zmienne
    // Korzystamy z nowej możliwości avrlibc 1.4
    static FILE lcd_fLCD_temp = FDEV_SETUP_STREAM(lcd_put, NULL, _FDEV_SETUP_WRITE);
    #define lcd_fLCD (&lcd_fLCD_temp)
    
    // Uwaga - wyświetlacz niewykorzystuje kodów 0x80-0x9f. To 32 kody które zostaną wykorzystane dla znaków specjalnych
    static char lcd_buffer[LCD_SX*LCD_SY];
    // Aktualne pozycja kursora (dotyczy bufora i jest aktualizwana przy odświerzaniu napisu)
    static uint8_t lcd_curpos;
    // Informacja o tym jakie znaki specjalne zostały zapisane do wyświetlacza
    static uint8_t lcd_spec[8];
    // Zmienna przechowująca flagi na temat włączenia wyświetlacza (wyświetlacz, kursor, migający kursor)
    static uint8_t lcd_status;
    
    //__________________________________________________________________________________________
    // Obsługa LCD - funkcje niskiego poziomu
    
    // Impuls ENABLE - przede wszystkim dla zapisu
    // Odczyt wymaga trochę bardziej skomplikowanej sekwencji
    #define lcd_epulse() \
    	{PORT(LCD_CTRLPORT) |= 1<<LCD_E; \
    	_delay_us(0.25); \
    	PORT(LCD_CTRLPORT) &= ~(1<<LCD_E);}
    
    // Odbiór danej - funkcja wewnętrzna
    static inline uint8_t lcd_Get(void)
    {
    	uint8_t dana; 
    	// Ustawienie portu lcd jako wejścia
    	DDR(LCD_DATAPORT) = 0x00; 
    	// Aktywacja odczytu
    	PORT(LCD_CTRLPORT) |= 1<<LCD_E; 
    	// \/ Uwaga - sprawdziłem eksperymentalnie, 
    	// \/ że 0.5us to czasami za mało
    	// \/ przy podłączonym programatorze wyświetlacz
    	// \/ wciąż gubił dane
    	_delay_us(1);
    	// Skopiowanie danych z wyjścia modułu
    	dana = PIN(LCD_DATAPORT); 
    	// Deaktywacja wyjścia ENABLE
    	PORT(LCD_CTRLPORT) &= ~(1<<LCD_E); 
    	return dana; 
    }
    
    uint8_t lcd_GetBF(void)
    {
    	// Wysterowanie wyprowadzeń do odczytu statusu
    	PORT(LCD_CTRLPORT) |= 1<<LCD_RW; 
    	PORT(LCD_CTRLPORT) &= ~(1<<LCD_RS);
    	// Odczekanie wymaganego przez sterownik czasu
    	_delay_us(0.25);
    	// Odczyt danej
    	return lcd_Get(); 
    }
    
    // Sprawdza flagę zajętości i czeka na jej wyzerowanie
    void lcd_WaitBF(void)
    {
    	// Bit zajętości to bit najstarszy
    	while(0 != (0x80 & lcd_GetBF())) {}; 
    }
    
    // Wysłanie danej - funkcja wewnętrzna
    static void lcd_Send(uint8_t dana)
    {
    	// Ustawienie portu lcd jako wyjścia
    	DDR(LCD_DATAPORT) = 0xFF; 
    	// Presłanie na port danej
    	PORT(LCD_DATAPORT) = dana; 
    	// Przesłanie do lcd
    	lcd_epulse(); 
    }
    
    // Wysłanie danej do pamięci DDRAM lub CGRAM
    // Zależnie od ustawionego adresu
    void lcd_SendData(uint8_t dana)
    {
    	lcd_WaitBF();
    	// Wysterowanie wyprowadzeń dla zapisu danej
    	PORT(LCD_CTRLPORT) &= ~(1<<LCD_RW); 
    	PORT(LCD_CTRLPORT) |= 1<<LCD_RS; 
    	// Odczekanie oraz wysłanie
    	_delay_us(0.25); 
    	lcd_Send(dana); 
    }
    
    // Wysłanie instrukcji sterującej
    void lcd_SendInstr(uint8_t dana)
    {
    	lcd_WaitBF();
    	// Wysterowanie wyprowadzeń dla zapisu instrukcji
    	PORT(LCD_CTRLPORT) &= ~(1<<LCD_RW | 1<<LCD_RS);
    	// Odczekanie oraz wysłanie
    	_delay_us(0.25); 
    	lcd_Send(dana); 
    }
    
    //__________________________________________________________________________________________
    // Funkcje obsługujące wejście wyjście strumienia
    static int lcd_put(char c, FILE* f)
    {
    	// Zabezpieczenie przed przepełnieniem
    	if(lcd_curpos >= ELEMS(lcd_buffer))
    		lcd_curpos = 0;
    	// Zapis do bufora
    	lcd_buffer[lcd_curpos++] = c;
    	return 0;
    }
    
    //__________________________________________________________________________________________
    // Funkcje interfejsu
    
    // inicjacja LCD (uwaga - nie włączam wyświetlacza ani kursora)
    void lcd_Init(void)
    {
    	lcd_Cls();
    	PORT(LCD_CTRLPORT) &= ~(1<<LCD_RW | 1<<LCD_RS); 
    	_delay_us(0.25); 
    	lcd_Send(LCDC_FUNC | LCDC_FUNC8b); 
    	_delay_ms(4.3); 
    	lcd_Send(LCDC_FUNC | LCDC_FUNC8b); 
    	_delay_us(200); 
    	lcd_Send(LCDC_FUNC | LCDC_FUNC8b); 
    	// Już można sprawdzać BF
    #if LCD_SY == 1
    	lcd_SendInstr(LCDC_FUNC | LCDC_FUNC8b | LCDC_FUNC1L); 
    #else
    	lcd_SendInstr(LCDC_FUNC | LCDC_FUNC8b | LCDC_FUNC2L); 
    #endif
    	lcd_SendInstr(LCDC_ON);
    	lcd_SendInstr(LCDC_CLS);
    	lcd_SendInstr(LCDC_MODE | LCDC_MODER); 
    	lcd_WaitBF();
    	// Koniec inicjacji. Wyjątkowo czekam na zakończenie. Normalnie BF jest sprawdzana przed wykonaniem indtrukcji 
    	// - daje to większą oszczędność czasu. Podczas inicjacji nie ma to wielkiego znaczenia. 
    }
    
    // Zerowanie bufora wyświetlacza
    void lcd_Cls(void)
    {
    	lcd_curpos = 0;
    	memset(lcd_buffer, ' ', sizeof(lcd_buffer));
    }
    
    // kontrola włączenia wyświetlacza, kursora, migającego kursora
    void lcd_SetStatus(uint8_t status)
    {
    	lcd_status = status;
    }
    
    // Odswierzenie statusu
    inline void lcd_UpdateStatus(void)
    {
    	lcd_SendInstr(LCDC_ON | lcd_status);
    }
    
    // Funkcja wewnętrzna podająca początek danej linii
    static uint8_t lcd_LineStart(uint8_t line)
    {
    #if LCD_SY == 1
    	return LCD_LINE1;
    #elif LCD_SY == 2
    	if(line == 0)
    		return LCD_LINE1;
    	else
    		return LCD_LINE2;
    #elif LCD_SY == 4
    	if(line == 0)
    		return LCD_LINE1;
    	else if(linenum == 1)
    		return LCD_LINE2;
    	else if(linenum == 2)
    		return LCD_LINE3;
    	else
    		return LCD_LINE4;
    #else
    #error Unknown display type!
    #endif
    }
    
    // Ustawienie kursora
    inline void lcd_GoToAdr(uint8_t adr)
    {
    	lcd_curpos = adr;
    }
    
    // Odswierzenie pozycji kursora
    void lcd_UpdateCurPos(void)
    {
    	// Obliczenie adresu w wyświetlaczu
    	uint8_t adres = 
    		lcd_LineStart(lcd_curpos / LCD_SX) + (lcd_curpos % LCD_SX);
    	// Wysłanie instrkucji ustawiającej kursor
    	lcd_SendInstr(LCDC_DDA | adres);
    }
    
    // Wewnętrzna pomocnicza funkcja sprawdzająca czy dany znak jest znakiem specjalnym
    static uint8_t lcd_IsSpec(char c)
    {
    	// Przydział znaków specjalnych na obszar którego LCD nie wykorzystuje
    	return (c >= 0x80) && (c <= 0x9f);
    }
    
    // Zamiana znaku specjalnego na odpowiedni numer w tablicy symboli
    static inline uint8_t lcd_Spec2Index(char c)
    {
    	return c-0x80;
    }
    
    // Funkcja sprawdzajaca czy w tablicy jest podany znak
    // Zwraca: indeks w tablicy gdzie znajduje sie dany znak
    //  lub kod znaku alternatywnego (zawsze >= 0x20)
    static uint8_t lcd_GetSpec(uint8_t s_index)
    {
    	// Zabezpieczenie
    	if(langsys_GetSpec() == NULL)
    		return 0x20;
    	uint8_t a; 
    	for(a=0; a<ELEMS(lcd_spec); a++)
    	{
    		// 0xff oznacza, że nie ma już dalej wpisów
    		if(lcd_spec[a] == 0xff)
    			break; 
    		// Jeśli znaleziono...
    		else if(lcd_spec[a] == s_index)
    			return a; 
    	}
    	// Nic nie znaleziono
    	return pgm_read_byte(&(langsys_GetSpec()[s_index].cAlt));
    }
    
    // Makro pomocnicze
    #define LCD_SPECNF(spec) (spec > 7)
    
    // Funkcja przydzielająca znaki specjalne
    // Zwraca ilość różnych znaków jaką znaleziono. Jeśli > 8 części znaków nie udało się przydzielić
    uint8_t lcd_PrepareSpec(void)
    {
    	// Analizuję cały łańcuch danych i zapisuję kolejno znalezione znaki
    	char* pbuffer = lcd_buffer;
    	uint8_t n;
    	uint8_t cnt=0;
    	char znak;
    	// Na początku "zerowanie" tablicy znaków specjalnych
    	memset(lcd_spec, 0xff, sizeof(lcd_spec));
    	// dodawanie wpisów
    	for(n=0; n<ELEMS(lcd_buffer); n++)
    	{
    		znak = *pbuffer++;
    		// Jeśli znaleziony znak jest specjalny
    		if(lcd_IsSpec(znak))
    		{
    			// Przeszukanie tablicy
    			znak = lcd_Spec2Index(znak);
    			// Jeśli nie znaleziono - dodawanie
    			if(LCD_SPECNF(lcd_GetSpec(znak)))
    			{
    				// dodaj do tablicy tylko jeśli 
    				// nie wystąpiło przepełnienie
    				if(cnt < ELEMS(lcd_spec))
    					lcd_spec[cnt] = znak;
    				// Licznik zwiększany zawsze
    				// dla statystyki
    				++cnt;
    			}
    		}
    	}
    	return cnt;
    }
    
    // Funkcja zapisująca definicje znaków do pamięci CGRAM wyświetlacza
    void lcd_UpdateCGRAM(void)
    {
    	// Zabezpieczenie
    	if(langsys_GetSpec() == NULL)
    		return;
    	// Ustawiam adres w module na początek definicji znaków: 
    	lcd_SendInstr(LCDC_CGA); 
    	// Przesyłanie bloków - tylko do czasu aż mam 0xff w tablicy - koniec danych
    	uint8_t a; 
    	for(a=0; a<ELEMS(lcd_spec); a++)
    	{
    		// 0xff oznacza koniec danych
    		if(lcd_spec[a] == 0xff) break;
    		// Wskaźnik na początek danych wyglądu znaku
    		uint8_t* pdata = langsys_GetSpec()[lcd_spec[a]].matrix;
    		// Wysyłam kolejny indeks
    		uint8_t bait;
    		for(bait=0; bait<8; bait++)
    		{
    			lcd_SendData(pgm_read_byte(pdata++)); 
    		}
    	}
    }
    
    // Funckcja odświerzająca dane w pamięci DDRAM wyświetlacza
    // Aby wyświetlanie przebiegło prawidłowo pamięć CGRAM musi być już ustawiona
    void lcd_UpdateText(void)
    {
    	uint8_t x, y;
    	
    	char *pbuffer = lcd_buffer;
    	// Przetwarzanie każdej linii oddzielnie
    	for(y=0; y<LCD_SY; y++)
    	{
    		lcd_SendInstr(LCDC_DDA | lcd_LineStart(y));
    		// Wysłanie wszystkich znaków z danej linii
    		for(x=0; x<LCD_SX; x++)
    		{
    			uint8_t znak = *pbuffer++;
    			if(lcd_IsSpec(znak))
    				znak = lcd_GetSpec(lcd_Spec2Index(znak));
    			// Znak gotowy do wysłania
    			lcd_SendData(znak);
    		}
    	}
    }
    
    // Odświerzenie wszystkich danych wyświetlacza
    void lcd_Update(void)
    {
    	lcd_PrepareSpec();
    	lcd_UpdateCGRAM();
    	// Wyłączenie kursora na czas odświerzania
    	lcd_SendInstr(LCDC_ON | (lcd_status & LCD_STATUS_DISP));
    	lcd_UpdateText();
    	lcd_UpdateCurPos();
    	// Ponowne włączenie kursora (jeśli był włączony)
    	lcd_UpdateStatus();
    }
    
    //__________________________________________________________________________________________
    // Funkcja podająca uchwyt do strumienia
    inline FILE* lcd_GetFile(void)
    {
    	return lcd_fLCD;
    }
    
    

    /////////////////////////////////////////////////////////////////////////////////////////////
    // langsys.c - moduł zarządzający językiem interfejsu
    //
    // Autor: Radosław Koppel	Kompilator: WinAVR 20060125
    /////////////////////////////////////////////////////////////////////////////////////////////
    #include <inttypes.h>
    #include <avr/pgmspace.h>
    
    #include "makra.h"
    #include "lcd.h" // Potrzebujemy stąd zmiennej opisującej wygląd znaku specjalnego
    #include "langsys.h"
    // Tutaj dodać wszystkie nagłówki języków
    #include "english.h"
    #include "polski.h"
    
    //______________________________________________________________________________________________
    // Zmienne
    static uint8_t langsys_sel = 0; // wybrany język
    
    // Definicja informacji o znakach specjalnych
    const LCD_LOCAL_PGM* langsys_lcdspec[] PROGMEM /*w EdW brak PROGMEM - to błąd!*/= 
    {
    	NULL,
    	PL_lcdspec
    };
    
    // Tablica wszystkich posiadanych napisów
    //   [język][tekst] - na odwrót nie trzebaby pilnować rozmiaru 
    //   (pierwszy wymiar może być obliczany przez kompilator), jednka inicjacja była by mniej wygodna
    //      +---tablica wskaźników na tablice w pamięci programu
    //      |                                        +--umieść tą tablicę w pamięci programu
    const prog_char* langsys_strTable[2][IDS_END] PROGMEM = 
    {
    	{
    		EN_strDisplay,
    		EN_strStart
    	},
    	{
    		PL_strDisplay,
    		PL_strStart
    	}
    };
    
    //______________________________________________________________________________________________
    // Funkcje dostępu
    
    // Ilość "zainstalowanych" języków
    uint8_t langsys_GetNumOfLangs(void)
    {
    	return ELEMS(langsys_strTable);
    }
    
    // Wybór języka
    void langsys_Select(uint8_t index)
    {
    	langsys_sel = index;
    }
    
    // Pobranie informacji o wybranym języku
    uint8_t langsys_GetSelected(void)
    {
    	return langsys_sel;
    }
    
    // Pobranie nazwy języka o podanym indeksie
    prog_char* langsys_GetLangName(uint8_t index)
    {
    	if(index > ELEMS(langsys_strTable))
    		return NULL;
    	return (prog_char*)pgm_read_word_near(&langsys_strTable[index][IDS_LANGNAME]);
    }
    
    // Pobieranie wskaźnika na informację o znakach specjalnych
    LCD_LOCAL_PGM* langsys_GetSpec(void)
    {
    	return (LCD_LOCAL_PGM*)pgm_read_word_near(&langsys_lcdspec[langsys_sel]);
    }
    
    // Pobieranie wybranego napisu
    prog_char* langsys_GetText(uint8_t index)
    {
    	return (prog_char*)pgm_read_word_near(&langsys_strTable[langsys_sel][index]);
    }
    

    /////////////////////////////////////////////////////////////////////////////////////////////
    // langsys.h - plik nagłówkowy modułu zarządzającego danymi języka
    //   Tutaj znajdują się oznaczenia syboliczne wszystkich łańcuchów
    //
    // Autor: Radosław Koppel	Kompilator: WinAVR 20060125
    /////////////////////////////////////////////////////////////////////////////////////////////
    #ifndef LANGSYS_H_INCLUDED
    #define LANGSYS_H_INCLUDED
    
    //__________________________________________________________________________________________
    // Funkcje interfejsu
    uint8_t langsys_GetNumOfLangs(void);
    void langsys_Select(uint8_t index);
    uint8_t langsys_GetSelected(void);
    prog_char* langsys_GetLangName(uint8_t index);
    LCD_LOCAL_PGM* langsys_GetSpec(void);
    prog_char* langsys_GetText(uint8_t index);
    
    //__________________________________________________________________________________________
    // Indeksy dla poszczególnych napisów
    // Dużymi literami specjalne, reszta tak jak odpowiednie zmienne
    enum
    {
    	IDS_LANGNAME,
    	IDS_Start,
    	
    	// Nie umieszczać żadnych identyfikatorów za poniższym!
    	IDS_END
    };
    
    #endif //LANGSYS_H_INCLUDED
    

    /////////////////////////////////////////////////////////////////////////////////////////////
    // lcd.h - plik nagłówkowy do obsługi alfanumerycznego wyświetlacza LCD.
    //			! Dynamiczne przydzielanie znaków specjalnych !
    //
    // Autor: Radosław Koppel	Kompilator: WinAVR 20060125
    /////////////////////////////////////////////////////////////////////////////////////////////
    #ifndef LCD_H_INCLUDED
    #define LCD_H_INCLUDED
    
    #include <avr/pgmspace.h>
    #include <stdio.h>
    
    // Struktura definiująca wygląd znaku specjalnego
    typedef struct
    {
    	uint8_t matrix[8]; // Matryca znaku
    	char cAlt; // Znak alternatywny
    }LCD_LOCAL_PGM; 
    
    // Definicje funkcji interfejsu
    void lcd_Init(void);
    void lcd_Cls(void);
    void lcd_SetStatus(uint8_t status);
    	#define LCD_STATUS_BLINK 0x01
    	#define LCD_STATUS_CURSOR 0x02
    	#define LCD_STATUS_DISP 0x04
    void lcd_UpdateStatus(void);
    void lcd_GoToAdr(uint8_t adr);
    	#define lcd_GoTo(x, y) lcd_GoToAdr(y*LCD_SX+x);
    void lcd_UpdateCurPos(void);
    uint8_t lcd_PrepareSpec(void);
    void lcd_UpdateCGRAM(void);
    void lcd_UpdateText(void);
    void lcd_Update(void);
    
    FILE* lcd_GetFile(void);
    
    #endif // LCD_H_INCLUDED
    

    /////////////////////////////////////////////////////////////////////////////////////////////
    // harddef.h - definicja sprzętu dla programu zaawansowanej obsługi alfanumerycznego wyśw. LCD
    //
    // Autor: Radosław Koppel	Kompilator: WinAVR 20060125
    /////////////////////////////////////////////////////////////////////////////////////////////
    #ifndef HARDDEF_H_INCLUDED
    #define HARDDEF_H_INCLUDED
    
    //__________________________________________________
    // Definicje wyświetlacza LCD
    // Informacje o typie wyświetlacza
    #define LCD_SX 16
    #define LCD_SY 2
    #define LCD_LINE1 0
    #define LCD_LINE2 64
    // Podłączenie
    #define LCD_DATAPORT B
    #define LCD_CTRLPORT D
    #define LCD_E 4
    #define LCD_RW 3
    #define LCD_RS 2
    #define LCD_LEDPORT D
    #define LCD_LED 5
    
    //___________________________________________________
    // Definicja przycisków
    #define SW_PORT E
    #define SW1 0
    #define SW2 2
    
    
    #endif // HARDDEF_H_INCLUDED
    

    //////////////////////////////////////////////////////////////////////////////////////////////////
    // makra.h - makra pomocnicze 
    // 
    // Autor: Radosław Koppel          Kompilator: WinAVR 20050214
    //////////////////////////////////////////////////////////////////////////////////////////////////
    #ifndef MAKRA_H_INCLUDED
    #define MAKRA_H_INCLUDED
    
    // 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)
    
    // NOPek
    #define NOP() {asm volatile("nop"::);}
    
    // Ilość elementów tablicy
    #define ELEMS(p) (sizeof(p)/sizeof(p[0]))
    
    
    #endif //MAKRA_H_INCLUDED
    

    /////////////////////////////////////////////////////////////////////////////////////////////
    // english.h - dane dla języka angielskiego.
    //
    // Uwaga: Ten plik definiuje zmienne. Wolno go dołączyć tylko raz i robimy do w langsys.c
    //
    // Autor: Radosław Koppel	Kompilator: WinAVR 20060125
    /////////////////////////////////////////////////////////////////////////////////////////////
    
    // Język angielski nie potrzebuje definicji znaków specjalnych
    
    // Teksty
    prog_char EN_strDisplay[] = "English";
    prog_char EN_strStart[] = "   Welcome in   English Version";
    

    /////////////////////////////////////////////////////////////////////////////////////////////
    // polski.h - dane dla języka polskiego.
    //
    // Uwaga: Ten plik definiuje zmienne. Wolno go dołączyć tylko raz i robimy do w langsys.c
    //
    // Autor: Radosław Koppel	Kompilator: WinAVR 20060125
    /////////////////////////////////////////////////////////////////////////////////////////////
    
    // Definicja znaków narodowych
    // (Polski ma ich 18)
    LCD_LOCAL_PGM PL_lcdspec[18] PROGMEM = 
    {
    	// Znaczki - poprawiłem pod względem wyglądu znaczki z EdW 1/98, dodałem brakujące
    	{{0, 0, 14, 1, 15, 17, 15, 2}, 'a'},    //ą - kod 0x80
    	{{2, 4, 14, 16, 16, 17, 14, 0}, 'c'},   //ć - kod 0x81
    	{{0, 0, 14, 17, 31, 16, 14, 2}, 'e'},   //ę - kod 0x82
    	{{12, 4, 6, 4, 12, 4, 14, 0}, 'l'},     //ł - kod 0x83
    	{{2, 4, 22, 25, 17, 17, 17, 0}, 'n'},   //ń - kod 0x84
    	{{2, 4, 14, 17, 17, 17, 14, 0}, 'o'},   //ó - kod 0x85
    	{{2, 4, 14, 16, 14, 1, 30, 0}, 's'},    //ś - kod 0x86
    	{{2, 4, 31, 2, 4, 8, 31, 0}, 'z'},      //ź - kod 0x87
    	{{4, 0, 31, 2, 4, 8, 31, 0}, 'z'},      //ż - kod 0x88
    	{{14, 17, 17, 31, 17, 17, 17, 2}, 'A'}, //Ą - kod 0x89
    	{{2, 14, 21, 16, 16, 16, 17, 14}, 'C'}, //Ć - kod 0x8a
    	{{31, 16, 16, 30, 16, 16, 31, 2}, 'E'}, //Ę - kod 0x8b
    	{{16, 16, 20, 24, 16, 16, 31, 0}, 'L'}, //Ł - kod 0x8c
    	{{2, 21, 17, 25, 21, 19, 17, 17}, 'N'}, //Ń - kod 0x8d
    	{{2, 14, 21, 17, 17, 17, 17, 14}, 'O'}, //Ó - kod 0x8e
    	{{2, 15, 20, 16, 14, 1, 1, 30}, 'S'},   //Ś - kod 0x8f
    	{{2, 31, 5, 2, 4, 8, 16, 31}, 'Z'},     //Ź - kod 0x90
    	{{4, 31, 1, 2, 4, 8, 16, 31}, 'Z'},     //Ż - kod 0x91
    }; 
    
    // Teksty
    prog_char PL_strDisplay[] = "Polski";
    prog_char PL_strStart[] = " Witaj w wersji     Polskiej\x80";
    


    Tutaj kod orginalny:
    http://www.sendspace.com/file/slcc8q

    Co należy jeszcze poprawić, aby była możliwość kompilacji??
  • #16
    User removed account
    Level 1  
  • #17
    mgiro
    Level 22  
    U mnie lekcja 11 chyba działała. Sprawdzę i dam znać ;D
  • #18
    hexen2k
    Level 16  
    Sprawdzał któryś z kolegów czy udało się uruchomić przykłady z lekcji 9,10,11 ? Jeśli tak to co trzeba było zmienić aby to ruszyć...

    Jest możliwość aby nie wykorzystywać strumienia danych w przykładzie z lekcji 10 ? Wolałbym używać swoich prostych funkcji do wyświetlania stringów na wyświetlaczu ;)

    http://elportal.pl/n0017/c_materialy/_do_cz10.rar
  • #19
    User removed account
    Level 1