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

Wyświetlanie napisów. Dlaczego wypisuje krzaczki?

aceman 29 Lis 2006 01:01 1977 16
REKLAMA
  • #1 3274579
    aceman
    Poziom 12  
    Posty: 37
    Pomógł: 1
    Witam!

    Mam problem z odczytaniem napisów. W programie napisy wpisałem w taki sposób:
    prog_char PM_UST_ZEG[]	= "Ustaw zegar: ";
    prog_char PM_UST_CZAS[]	= "<    Ustaw czas    >";
    prog_char PM_UST_DATE[]	= "<    Ustaw datę    >";
    
    const prog_char* info[] PROGMEM =
    {
      PM_UST_ZEG,	
      PM_UST_CZAS,	
      PM_UST_DATE
    }

    Jeżeli wywołuję napisy jak poniżej, to jest wszystko OK,
    pisz_tekst(info[1]);

    lecz jeżeli robię to w ten sposób to wypisuje krzaki na LCD.
    unsigned char m = 1;
    pisz_tekst(info[m]);

    Czy może mi ktoś wytłumaczyć dlaczego tak jest i jak wywoływać odpowiedni napis zmienną??
    Pozdrawiam
  • REKLAMA
  • Pomocny post
    #2 3274939
    jam_es
    Poziom 24  
    Posty: 491
    Pomógł: 75
    Ocena: 93
    Witam

    Możliwe, że ma to związek z deklaracją m.
    Ustaliłeś jako unsigned char. Spróbuj jako integer.

    Pozdrawiam
  • REKLAMA
  • #3 3275075
    aceman
    Poziom 12  
    Posty: 37
    Pomógł: 1
    Niestety powyższa propozycja również nie działa.
    Deklarowałem zmienną "m" na wiele różnych sposobów i wciąż krzaki.
  • #4 3275100
    JacekCz
    Poziom 42  
    Posty: 8670
    Pomógł: 760
    Ocena: 1460
    jam_es napisał:
    Witam

    Możliwe, że ma to związek z deklaracją m.
    Ustaliłeś jako unsigned char. Spróbuj jako integer.

    Pozdrawiam


    unsigned char jest legalny choć zaskakujący.
    Możesz mieć jakies efekty uboczne, cos zamazuje coś innego itd, ale nie dajesz źródel. Wrożka ze szklaną kulą ma wolne.
  • #5 3275109
    aceman
    Poziom 12  
    Posty: 37
    Pomógł: 1
    To co byś zaproponował Jacku??
    Próbowałem deklarować zmienną również jako int i to samo.
  • REKLAMA
  • #6 3275137
    JacekCz
    Poziom 42  
    Posty: 8670
    Pomógł: 760
    Ocena: 1460
    aceman napisał:
    To co byś zaproponował Jacku??
    Próbowałem deklarować zmienną również jako int i to samo.


    Błąd jest gdzie indziej.
    Wynika mi to z metody Kaszpirowskiego.
  • #7 3275425
    aceman
    Poziom 12  
    Posty: 37
    Pomógł: 1
    Trochę cienka ta metoda, skoro nie wiesz w czym problem ;P
  • Pomocny post
    #8 3275446
    Bigfoot
    Poziom 25  
    Posty: 982
    Pomógł: 74
    Ocena: 13
    Ja Kaszpirowskim nie jestem ale na 99% problem lezy w tym, ze do Twojej funkcji, ktorej prawdopodobnie argumentem powinien byc const Ty "wkladasz" zmienna, ktora nie jest const. Jesli sie myle to niech mnie ktos poprawi.

    Pokaz definicje funkcji pisz_tekst, powiedz tez w jakim srodowisku piszesz.

    BF
  • #9 3275474
    aceman
    Poziom 12  
    Posty: 37
    Pomógł: 1
    W końcu jakieś konkrety!
    Funkcja pisz_tekst() wygląda następująco, a piszę w C pod WinAVR.
    void pisz_tekst(prog_char* tekst) 
    {
    	char zn;
    	
    	while(0 != (zn = pgm_read_byte(tekst++)))
    	{
    			if(zn == CR) // czy znak nowej linii
    			{
    			wiersz==1?wiersz=0:++wiersz;
    			kolumna = 0;
    			lcd_xy(wiersz,kolumna);	
    			}	
    			else
    			{	
    			pisz_dlcd(zn);				}
    	}
    }

    Spróbuję bez const.

    Dodano po 8 [minuty]:

    Niestety bez operatora const efekt jest taki sam :((
  • Pomocny post
    #10 3275778
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    Dlaczego upierasz się , by wepchać wskaźniki do pamięci programu :?:
    Mówisz kompilatorowi - umieść wskaźnik do pamięci programu , w pamięci programu ...
    const prog_char* info[] PROGMEM = ...

    ... , a powinieneś powiedzieć - umieść wskaźnik do pamięci programu , w pamięci data(RAM)
    const char* info[] = { PM_UST_ZEG,   PM_UST_CZAS,  PM_UST_DATE};
    To samo masz tu ...
    void pisz_tekst(prog_char* tekst)
    ... , więc zmień na ...
    void pisz_tekst(const char* tekst)
    ... i po bulu :D
    const char* można zastąpić PGM_P

    Piotrek
  • REKLAMA
  • #11 3275989
    aceman
    Poziom 12  
    Posty: 37
    Pomógł: 1
    Witaj Piotrze!

    Twoje rozwiązanie w końcu zaczęło działać.
    Należało poprawić jeszcze:
    char PM_UST_ZEG[]   = "Ustaw zegar: "; 
    char PM_UST_CZAS[]   = "<    Ustaw czas    >";   // itd

    zamiast:
    prog_char PM_UST_ZEG[]   = "Ustaw zegar: "; 
    prog_char PM_UST_CZAS[]   = "<    Ustaw czas    >";


    I już się ucieszyłem, lecz stworzył się kolejny problem!!
    Ponieważ napisów jest ok 40-50, to po powyższej zmianie zajęty obszar pamięci data(RAM) nie wynosi już 31,3%, lecz 93,4%.

    I CO Z TYM DALEJ ROBIĆ:cry::?:

    Pozdrawiam, Artur

    Dodano po 1 [godziny] 22 [minuty]:

    To może podejdźmy do problemu inaczej:
    Jak rozpisać tabelę z wyświetlanymi napisami, żeby w prosty sposób można było je wyświetlać poprzez poniższą funkcję. Napisy chcę zapisać w osobnym pliku napisy.h oraz żeby dane napisy były umieszczone ekonomicznie w pamięci.
    void pisz_tekst(prog_char* tekst) 		// pisz tekst na LCD wskazywany przez *tekst
    {
    	char zn;
    	
    	while(0 != (zn = pgm_read_byte(tekst++)))
    	{
    			if(zn == CR)					// czy znak nowej linii
    			{
    			wiersz==1?wiersz=0:++wiersz;	// przejdz do nowej linni
    			kolumna = 0;
    			lcd_xy(wiersz,kolumna);			// ustaw obowiazujace po zmianie wspolrzedne LCD
    			}	
    			else
    			{	
    			pisz_dlcd(zn);	// umiesc pojedynczy znak tekstu na LCD
    			}
    	}
    }
  • Pomocny post
    #12 3276322
    JacekCz
    Poziom 42  
    Posty: 8670
    Pomógł: 760
    Ocena: 1460
    Może kombinuję (nie czuje intuicyjnie tych słów kluczowych)

    const prog_char* info[] PROGMEM = ...

    prog_long /*prog_void */ const prog_char* info[] PROGMEM = ...

    warto sprawdzić odwrocenia kolejności słów, ma to inny sens.

    Manipulując również kolejnością słow ... musi być rozwiązanie lepsze niż wszystko w RAM

    2.
    Takie coś:
    char *LINE1 = PSTR("Pierwsza linia na LCD");

    3.
    I jeszcze: jeśli już literki będą w xxxROM, wskazniki bolą nas że są nie takie albo kosztują RAM ... może ich nie trzmać ? w ciągłym obszarze literek, ile ich, 1k, 2k ? szukam szybką pętlą stringu nr N i używam.
    Być może szybkośc nie jest krytyczna.


    .... tab[]=
    "Tekst 1szy\0Tekst 2gi\0"
    "Tekst 3ci\0tekst 4ty\0"
    ....
    ;

    (sklejenia stringów każdy ludzki kompilator akceptuje)

    4. Sugeruję, że użycie operatora pytajnika? jak w twojej pętli jest przesadą i nic pozytywnego nie daje. To powinien byc normalny if.

    5.
    while(0 != ....
    też jest hakerstwem kogoś kto nie czuje się pewnie z C. Albo to w kilku konstrukcjach jak ma byc estetycznie,
    albo bez tego 0 != jak ma być hakersko
    [/code]
  • Pomocny post
    #13 3276495
    adamusx
    Poziom 27  
    Posty: 977
    Pomógł: 94
    Ocena: 28
    Zmien const char* na PGM_P jak kolega Zumek napisal i po kłopocie. Wtedy przezucisz te zmienne z RAMu do Flasha.
  • Pomocny post
    #14 3276701
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    aceman napisał:
    ...I już się ucieszyłem, lecz stworzył się kolejny problem!!
    Ponieważ napisów jest ok 40-50, to po powyższej zmianie zajęty obszar pamięci data(RAM) nie wynosi już 31,3%, lecz 93,4%.

    I CO Z TYM DALEJ ROBIĆ:cry::?:

    Chyba się nie zrozumieliśmy :(
    Dane możesz umieścić w pamięci programu ...
    
    prog_char PM_UST_ZEG[]  = "Ustaw zegar: ";
    prog_char PM_UST_CZAS[] = "<    Ustaw czas    >";
    prog_char PM_UST_DATE[] = "<    Ustaw datę    >";
    

    ... , ale wskaźniki na te tablice , kompilator umieści w RAM-ie(bo gdzież by indziej) ...
    
    const char* info[] = { PM_UST_ZEG,   PM_UST_CZAS,  PM_UST_DATE};
    

    ... więc Twój fragment powinien wyglądać tak:
    
    prog_char PM_UST_ZEG[]   = "Ustaw zegar: ";
    prog_char PM_UST_CZAS[]   = "<    Ustaw czas    >";
    prog_char PM_UST_DATE[]   = "<    Ustaw datę    >";
    
    const prog_char* info[] PROGMEM ={  PM_UST_ZEG,  PM_UST_CZAS,PM_UST_DATE}
    
    //...
    
    void pisz_tekst(const char* tekst)
    {
       char zn;
       
       while(0 != (zn = pgm_read_byte(tekst++)))
       {
             if(zn == CR) // czy znak nowej linii
             {
             wiersz==1?wiersz=0:++wiersz;
             kolumna = 0;
             lcd_xy(wiersz,kolumna);   
             }   
             else
             {   
             pisz_dlcd(zn);            }
       }
    }
    

    Każdy wskaźnik zajmuje 2 bajty RAM-u , więc dla 50 tablic umieszczonych w ROM-ie , "zużyjesz" 100B RAM-u , to chyba niewiele :?:
    Jeśli już żałujesz tego RAM-u , to zastosuj np.switch]
    
    const char * romptr;
    //....
    		switch (m)
    		{
    		case  1: romptr=PM_UST_CZAS; break; //pośrednio
    		case  2: pisz_tekst(PM_UST_ZEG); break; //bezpośrednio i 
                                                             //niepotrzebna tablica wskaźników
    		//itd.
    		}
                    //....
    		pisz_tekst(romptr);
    //...
    

    Wybierz najlepsze dla Ciebie rozwiązanie , bo nie ma powodu "rozdzierać szat" :D

    Piotrek
  • #15 3277027
    aceman
    Poziom 12  
    Posty: 37
    Pomógł: 1
    Dziękuję za pomoc.
    Wszystko już chodzi jak należy. Pewnie temat dla was jest banalny, ale ja jeszcze nie czaję pewnych spraw.
    Błędy, które popełniałem to:
    Po zmianie na (const char* tekst) w funkcji pisz_tekst() pisałem;
    while(0 != *tekst++)

    zamiast:
    while(0 != (zn = pgm_read_byte(tekst++)))

    No i równie pomocna okazała się zmiana const char* na PGM_P;

    Pozdrawiam gorąco.
    Artur
  • #16 3277487
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    Tak mnie zaciekawił temat danych w pamięci programu , że z chęci zaoszczędzenia RAM-u (zawsze go mało) , spłodziłem takie coś :D
    
    #include <avr/io.h>
    #include <avr/pgmspace.h>
    
    //tablice z danymi w ROM
    prog_char ROM1[]  = "AAAAAAAAAA";
    prog_char ROM2[]  = "BBBBBBBBBB";
    prog_char ROM3[]  = "CCCCCCCCCC";
    
    //tablica w ROM , z adresami tablic w ROM ;-) 
    const prog_char*  rom_tab_adr[] PROGMEM = { ROM1,ROM2,ROM3};
    
    char buf[22]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};//dla symultora
    
    void copy_to_buf(const char* rom_data)
    {
       char chr,i=0;
       while(0 != (chr = pgm_read_byte(rom_data++)))
       	{ 
    		buf[(int)i++]=chr;//lub do LCD,UART , czy gdzie dusza zapragnie ;) 
       	}
    }
    
    int main(void)
    {
    unsigned char i;
    
    while(1)
    	{
    	for(i=0;i<3;i++)
    		{
    		copy_to_buf((const char*)pgm_read_word(&rom_tab_adr[i]));
    		}
    	}
    return 0;
    }
    
    

    Piotrek
  • #17 3277573
    aceman
    Poziom 12  
    Posty: 37
    Pomógł: 1
    He he
    Temat wydaje się banalny, lecz byle nowicjusz nie napisze tego ot tak sobie.
    W końcu praktyka czyni mistrza :D.

Podsumowanie tematu

✨ Problem dotyczył wyświetlania napisów zapisanych w pamięci programu (PROGMEM) na wyświetlaczu LCD w środowisku WinAVR przy użyciu języka C. Użytkownik definiował napisy jako tablice typu prog_char w pamięci programu oraz tworzył tablicę wskaźników do tych napisów również w PROGMEM. Wywołanie funkcji pisz_tekst() z indeksem stałym działało poprawnie, natomiast z użyciem zmiennej indeksującej powodowało wyświetlanie "krzaczków". Przyczyną problemu było nieprawidłowe zarządzanie wskaźnikami do napisów w pamięci programu oraz błędne typy argumentów funkcji pisz_tekst(). Poprawne rozwiązanie polegało na:
- deklarowaniu wskaźników do napisów w RAM (const char* info[]), a samych napisów w PROGMEM (prog_char[]),
- zmianie typu argumentu funkcji pisz_tekst() na const char* lub PGM_P,
- odczytywaniu znaków z pamięci programu za pomocą pgm_read_byte(), a nie bezpośrednio przez dereferencję wskaźnika,
- unikaniu umieszczania wskaźników w PROGMEM, gdyż kompilator umieszcza je w RAM, co powodowało błędy.
Dzięki tym zmianom napisy wyświetlały się poprawnie, a pamięć RAM była oszczędzana. Dyskusja zawierała także przykłady efektywnego zarządzania napisami w pamięci programu AVR oraz wskazówki dotyczące optymalizacji pamięci RAM i Flash w mikrokontrolerach AVR.
Wygenerowane przez model językowy.
REKLAMA