Stránka 1 z 3

Problém se znakovým LCD, ATmega32

Napsal: 04 črc 2012, 18:58
od 1N4148
Zkouším ovládat znakový LCD displej 16x2 pomocí ATmegy32, na internetu jsem našel tento tutoriál http://extremeelectronics.co.in/avr-tutorials/using-lcd-module-with-avrs/ ale bohužel mi nefunguje vše jak by mělo. Zdrojový kód je obsažen v odkazovaném článku (Sample program), připojené knihovny taky (lcdlibv20.zip).
Můj problém je, že v úvodním for-cyklu se mi zobrazuje část textu "Hello world", který by se měl zobrazit až později, a ještě před tím znak "°", který by tam vůbec být neměl, viz foto:
Obrázek
Přijde mi to divné, další text by se neměl vypisovat, dokud for-cyklus neskončí. Přidání prodlevy mezi příkazy ani snížení taktu procesoru nepomohlo. V čem je chyba?

Napsal: 04 črc 2012, 20:32
od gmike
Je to divné, ale zkus příkaz LCDWriteStringXY(12,1,"%");
nahradit tímhle LCDWriteStringXY(12,1,"% ");.
Jenom za znak procenta přídáš tři mezery, tím si jednoduše to co nechceš přepíšeš.
edit: nechce mi to vzít tři mezery, ale jsou tam :)

Napsal: 04 črc 2012, 20:38
od 1N4148
Jasný, to mě taky napadlo. Ale mě jde spíš o to, najít kde je chyba, abych ty knihovny mohl v budoucnu používat a nemusel řešit kolik tam dát mezer. :D

Napsal: 04 črc 2012, 20:48
od Andrea
V té knihovně je chyba ve funkci void LCDWriteString(const char *msg).
Konkrétně v tomhle

Kód: Vybrat vše

      else
      {
         LCDData('%');
         LCDData(*msg);
      }

Napsal: 04 črc 2012, 21:19
od 1N4148
Autor knihovny zvolil asi trochu nešťastně znak "%" pro uvozování uživatelsky definovaného symbolu (což by vysvětlovalo, proč se ve výpisu objevil znak "°"), změnil jsem to na "_" a je to ok. Zatím ale nechápu, proč se vypisoval i řetězec "Hello world" :?

Napsal: 04 črc 2012, 21:21
od Andrea
No kvůli té chybě, tou změnou jsi ji neodstranil.

Napsal: 04 črc 2012, 21:26
od 1N4148
Přiznám se, že se v tom zas tak neorientuju, mohla bys mi prosím sdělit, v čem přesně je ta chyba a jak ji odstranit? Díky.

Napsal: 04 črc 2012, 21:30
od Andrea
Lámej si trochu hlavu, jen opisováním se nic nenaučíš. Řetězce jsou v C zakončené 0, tzv. ASCIIZ, tak se zamysli nad tím, co ta funkce udělá, když poslední znak v řetězci je ten "speciální" a za ním je už jen ta nula.

Napsal: 04 črc 2012, 21:54
od 1N4148
No bude si myslet, že chci vypsat uživatelsky definovaný znak. Podívá se, jaké číslo následuje za %, což je 0. Takže vypíše znak č. 0, což je °. While cyklus skončí a do větve else program nedojde.

Napsal: 04 črc 2012, 22:03
od Andrea
1N4148 píše:No bude si myslet, že chci vypsat uživatelsky definovaný znak. Podívá se, jaké číslo následuje za %, což je 0.

Pleteš si ASCII znak '0' s číslem 0.

1N4148 píše:While cyklus skončí a do větve else program nedojde.

To jseš na omylu, while cyklus neskončí, nemá proč by se ukončil.

Napsal: 04 črc 2012, 22:40
od 1N4148
No dobře, tak funkce narazí na znak %, pokusí se příkazem msg++ přejít na další znak, ale žádný tam není, na tom místě bude nejspíš v paměti uložený ukazatel na string Hello world, program přejde do větve else, vypíše se znak % a string Hello world. Tak a teď zas nevím, kde se vezme znak ° :twisted:

Napsal: 04 črc 2012, 22:41
od Andrea
:roll:
Tak si to odkrokuj v nějakým simulátoru, když to z toho papíru nedokážeš pochopit.

Napsal: 05 črc 2012, 00:53
od WLAB
Ten kod je zmatlanej, po (287) msg++; se uz nekontroluje konec retezce (chyba je spis tady nez v te else casti), ktery by to vubec chtelo testovat na jednom jedinem miste - a do tela while pak napsat stavovy automat, ktery udela parsing user retezcu (tady by byl hodne jednoduchy). Ten symbol stupen je puvodni zakoncovaci nula, kterou tam nasype (296) LCDData(*msg);

Napsal: 05 črc 2012, 05:32
od AB1
Chyba se projeví, když poslední znak ve stringu je '%'.
Pointer msg se ve smyčce while() dvakrát inkrementuje a tím pádem se přeskočí test koncové nuly.

Pomohlo by třeba

Kód: Vybrat vše

       //Custom Char Support
      if(*msg=='%')           
      {                         
         msg++;                 
         if(*msg == '\0') {LCDData('%'); return;}  ////// přidáno
     
         int8_t cc = *msg-'0';
         if(cc>=0 && cc<=7)
...
...       

Napsal: 05 črc 2012, 07:50
od Andrea
Stačí v té else části místo LCDData(*msg); dát msg--;