Jak na ukazatele ?

Ahoj

Ve svých pokusech jsem se dostal už tak daleko, že musím začít používat ukazatele, které jsem nikdy nechápal a tak jsem se teď o to pokusil :slight_smile:

1. Co se týče paměti SRAM

char retezec_SRAM]={“Tento text je umisten v pameti SRAM”};   // uložení řetězce do SRAM
char *SRAM_Pointer = & retezec_SRAM[0];   // ukazatel na řetězec retezec_SRAM (na jeho 0. prvek => na začátek) 
char *SRAM_Pointer2={“Tento text je umisten v pameti SRAM”}   // jiná možnost, jak uložit řetězec do SRAM rovnou jako řetězec

OK, tady mi to funguje a když jsem debugoval v AVR studiu (v5), tak jsem to v paměti SRAM skutečně viděl.

2. Paměť FLASH

flash char *FLASH_Pointer]={“Tento text je v pameti FLASH”};   // ukazatel na místo v paměti FLASH, kde je uložen řetězec FLASH_Pointer

Teď trochu neodborný popis: Zjistil jsem, že tady je možné (oproti SRAM) za chodu programu měnit obsah toho řetězce FLASH_Pointer např:

flash char *Empty_FLASH_string];

if (...){
   *Empty_FLASH_string = “ANO” ;}
else{
   *Empty_FLASH_string = “NE” ;};

tzn. Buď tam bude “ANO” nebo “NE” - jestli jsem to správně pochopil a v debugu správně viděl, tak ve skutečnosti jsou ve FLASH už dopředu uloženy řetězce “ANO” i “NE” a vlastně jen měním adresu, kam se ukazatel Empty_FLASH_string dívá (na který z těch dvou řetězců). Mám pravdu ?

3. paměť EEPROM
Tady jsem napsal:

eeprom char *EEPROM_pointer="Tento text je v EEPROM";

V debugu jsem ale v EEPROM tento řetězec nenašel. Takže teď jsem zmatený, protože jsem si myslel, že se řetězec EEPROM_pointer skutečně fyzicky uloží do EEPROM, tak nevím jestli to chápu špatně, nebo to třeba AVR studio neumí zobrazit ?

Jinak používám IDE CodeVision a debug již zmiňované AVR studio. Postupuji podle příručky “User Manual” a knihy “Mikrokontroléry ATMEL AVR programování v jazyce C” od Váňi, což je v podstatě překlad toho User Manualu k CodeVisionu.

Může mi prosím někdo osvětlit jak to tedy správně je?

Děkuji

Myslím si, že text “Tento text je v EEPROM” bude uložen ve FLASH paměti a do eeprom se uloží pouze ukazatel na tento řetězec (2 byty).
Druhá varianta je rozdíl v deklaracích :

flash char *FLASH_Pointer]={“Tento text je v pameti FLASH”}; eeprom char *EEPROM_pointer="Tento text je v EEPROM";
Možná díky tomu se vytvoří v EEPROM jenom místo pro pointer místo samotného textu.

Vyzkoušej následující :

eeprom char *EEPROM_pointer]={"Tento text je v EEPROM"}; // nová deklarace místo eeprom char *EEPROM_pointer="Tento text je v EEPROM" // této původní;

Balů:

eeprom char *EEPROM_pointer="Tento text je v EEPROM"

Ano vypadá to, že to funguje. Po kompilaci v CodeVision to píše, že je použita nějaká paměť EEPROM a ukazatel dostane i adresu. Když se ale na to dívám v debugu, tak stejně vidím samé FF FF FF … (prázdná EEPROM). Nemůžu se zbavit pocitu, že to AVR studio5 prostě neumí. Zítra zkusím verzi 6 co jí mám v práci, jestli půjde něco vidět.

Jinak dotaz:
Jak si tak hraju s ukazateli a paměťmi…
Píšu si prográmek, který načte řetězec z EEPROM, uloží jej do SRAM jako nový řetězec. Je možné jej pak překopírovat “za chodu programu” do FLASH, nebo je FLASH zapisovatelná pouze při nahrávání .hex do MCU ?

Myslím si, že FLASH je za běhu programu už pevně daná a mohu pracovat pouze následujícími způsoby:

  1. kopírování z FLASH do SRAM (přes funkce z knihovny string.h)
  2. kopírování z SRAM do EEPROM (popsáno v datasheetu a dokonce to i hezky funguje :slight_smile:
  3. kopírování z EEPROM do SRAM (jako případ 2 - viz. datasheet)

P.S. Pracuji s Atmely MEGA (32 a 64)

Zapisovat do Flash za běhu procesoru za určitých okolností lze. Například bootloadery - to jsou programy, které Flash paměť přepisují za běhu MCU. Není to však tak triviální. Buď si musíš paměť , kam chceš zapisovat, zarovnat tak, aby odpovídala sránce/stránkám flash nebo musíš stránku vyčíst a do té části, kde je program zapsat to, co bylo přečteno a změnit jenom tu část, která je součástí řetězce, protože vždy mažeš+zapisuješ po stránkách a ne po bytech. Navíc musí být povolen pojistkami zápis do flash paměti MCU. Kromě toho počet zápisů do Flash je 10000 cyklů, EEPROM je 100000 cyklů.

Nemusíš, většina projektů pro malé mikroprocesory nepotřebuje žádné ukazatele.

AB:
Vlastně máš pravdu - už jsem udělal 1wire, LCD, USART, A/D převodník, EEPROM, RTC pomocí vlastních funkcí aniž bych se ukazatelů dotkl.
Problém nastal, když jsem začal používat knihovní funkce CodeVisia nebo různé stažené kódy z netu, kde autoři dost často (a nakonec si myslím že i správně) ukazatele používají.

Ono ty ukazatele naonec nejsou tak těžké, ale nikde jsem nenašel “příručku pro blbce” - kdy by to bylo po lopatě pro Amtely AVR + konkrétní příklady, kde se to trochu komplikuje těmi 3 typy pamětí . Něco už mám napsané a nahraju to na ulozto.cz - snad to pak někomu pomůže :slight_smile:

Tak jsem ještě zkoušel debug v AVR studiu 6.2 a tady je výsledek:

Když v CodeVision napíšeme:

eeprom char string1] = "Tento retezec je v EEPROM";

tak po kompilaci CodeVision píše, že bylo použito 0,0% EEPROM a v debugu, pokud se podíváme do EEPROM, tak tam nic nevidíme

Pokud ale napíšeme:

eeprom char *string2] = {"Tento retezec je v EEPROM"};

tak po kompilaci CodeVision píše, použito 2,7% EEPROM. Ale v debugu (stejně jako v AVR studiu 5), pokud si otevřeme paměť EEPROM opět nic nevidíme.

Ještě to zkusíme fyzicky přímo na MCU a pak budu zpětně načítat jenom EEPROM. Docela mě to zajímá, jestli je to skutečně neschopnost moje něco nastavit, nebo AVR studia pracovat s EEPROM.

Pokud použiješ inicializovanou EEPROM, tak AVR Studio 4.19, které používám, mi napíše, že v EEPROM jsou inicializovaná data a jestli je chci do EEPROM (simulátoru) nahrát. Při překladu pak vytvoří soubory xxx.HEX s programem a xxx.EEP s obsahem EEPROM, kterou musíš do EEPROMky při programování nahrát. Při inicializaci MCU, kterou provádí kompilátor před funkcí main inicializuje pouze proměnné v SRAM (samozřejmě z hodnot uložených ve FLASH - někde je vzít musí). Osobně to dělám tak, že v EEPROM si vyhradím místo na data a hodnoty do EEPROM (pokud existují defaultní hodnoty) nahrávám programem v main. Zkontroluju obsah EEPROM a pokud EEPROM obsahuje z hlediska vyžadovaných hodnot nesmysly (0xFF = smazaná EEPROM nebo hodnoty mimo požadovaný rozsah), tak do EEPROM zapíšu defaultní hodnoty. Výhodou je, že pak máš k dispozici možnost přechodu do “továrního” nastavení.

Balů: Lepší by možná bylo kontrolovat checksum těch eeprom dat…

Což to je jen další způsob, jak zjistit, jestli data v EEPROM jsou. A co, když ne ? Pokud nejsou default hodnoty uloženy v programové paměti, tak se musí do EEPROM dostat nějak jinak. Buď nové nastavení nebo nové naprogramování. Je to pořád o tom, že pokud nemáš data v programu, tak je v případě potřeby do EEPROMky nenasypeš, ať je mechanizmus jejich kontroly v EEPROMce jakýkoliv.

Ten "další " způsob odhalí i data poškozená, dokonce i jen trochu. Samozřejmě že to neřeší mechanizmus obnovy/nastavení, to je na každém soudruhovi zvolit co bude pak. Já mám default v programu vždy, obvykle to provází i nějaké ty kecy pro uživatele aby věděl co se děje.

Ahojte, celkom ma zaujala tato tema. Najprv by ma zaujimala uvaha autora v prvom prispevku. Cize ak chcem ulozit premenu v SRAM ulozim to napr. takto?

unsigned char premenna; //ulozena v SRAM?

vo flash takto?

flash unsigned char premenna;  //ulozena vo Flash?

Este jedna otazka: spravil som si s atmega8 ‘‘anglicky prekladovy slovnik’’ cize v pamati mam ulozene anglicke slovicka aj slovensky preklad.
To si viem listovat na lcd bud v sk alebo v en. Problem je ze po ulozeni cca 47 anglickych slov a 47 slovenskych mi v AVR studiu vypisuje Data: 1014 bytes (99.0% Full) a Program:3952 bytes (48.2% Full) s toho som usudil ze pamat sram je plna nejde doplnit dalsie slovicka. Je mozne ich dopisat do flash pamate?

Este jedna otazka tie slovicka si listujem na lcd pomocou case. Je to dobry sposob alebo je sposob ako to spravit elegantnejsie?

ad 1) Ty slovíčka ve Flash paměti stejně máš, jen se při startu MCU překopírujou z Flash do SRAM. Nadefinuj je jako PROGMEM a nezabírej s nima zbytečně SRAM paměť. Pak je vypisuj přímo z Flash paměti programu.

Takto definované texty jsou uloženy v SRAM. Jenže aby se tam dostaly, jsou i ve Flash paměti mcu…

char const Texty][17]={ "Text 1", "Text 2", "Text 3", "Text 4", . . . . "Text n-1", "Text n", };

Vzhledem k tomu, že jsou to konstanty, lze je nadefinovat takto :

char const PROGMEM Texty][17]={ "Text 1", "Text 2", "Text 3", "Text 4", . . . . "Text n-1", "Text n", };

Tak zůstávají trvale pouze v paměti Flash a nezabírají vůbec žádné místo v SRAM.
Jediný rozdíl je v tom, že je musíš z paměti dostávat pomocí pgm_read_byte();

Tudíž číslo 4 z textu “Text 4” dostanu :

  1. takto : Znak = Texty[3][5];
  2. takto : Znak = pgm_read_byte(Texty[3][5]);

ad 2) Použití case je dobrý způsob.

Doteď je mi záhadou proč “zprasili” používání const. Ten modifikátor PROGMEM by člověk ještě zkousnul, ale to čtení…

Tak ta pgm funkcia bola nova pre mna. Trochu som si o tom precital je to presne to co potrebujem. Presiel som si nejake example kody na internete. Kedze mi to nedalo hned som si aj nejaky programik vyskusal text sa mi na lcd menil podla toho ako som si menil premennu.

[code]#include <avr/pgmspace.h>

char const PROGMEM sk][17]={
“jeden”,
“dva”,
“tri”,
“styri”,
};

lcd_gotoxy(0,0);
lcd_puts(&sk[premenna][0]); [/code]

Este by som potreboval doriesit aby po stlaceni tlacitka slovo trebars jeden ktore je aktualne zobrazene na lcd preplo na one. Je treba definovat dalsie pole a to s anglickymi slovami?

Toto mi nejako nefungovalo Znak ma byt definovany ako pole?

Znak je definován jako char nebo unsigned char.

Jinak si myslím, že lcd_puts(&sk[premenna][0]); by asi šlo zapsat jen jako lcd_puts(sk[premenna]);.

Jinak samozřejmě, že musíš nadefinovat 2 pole. Jedno slovensky a jedno anglicky tak, aby pořadí slov vzájemně korespondovalo.
Druhá varianta je nadefinovat pole tak, že bude slovenský výraz a další řetězec bude jeho anglický překlad.

Text[0]] SK1
Text[1]] EN1
Text[2]] SK2
Text[3]] EN2
.
.
.

Jinak ještě doplním, abys tu šířku pole [17] upravil tak, aby odpovídala nejdelšímu uloženému slovu v daném poli (a nezapomeň, že ukončovací 0x00 se do počtu bytů potřebných pro řetězec také počítá…), protože každý ten řetězec je 17 znaků dlouhý, takže pokud nejdelší slovo v poli je dlouhé 7 znaků, pak je 10 znaků v každém řetězci definováno zbytečně. A doporučuju zvolit pro každou položku pole (každý řetězec) sudý počet bytů (včetně ukončovací nuly) kvůli organizaci Flash paměti (po wordech -> 2 bytech).

V GCC 4.9.2 (prý už od 4.7.0) je modifikátor __flash kterej eliminuje nutnost používaní pgm_read_xx(). Zdá se, že to chodí. Problém je, že mi nechodí avr studio 4.18 (716) s touto verzí gcc. Respektive spadne simulátor. Chodí to někomu ?

Super funguje aj tento zapis :slight_smile:

lcd_puts(sk[premenna]);

Rozhodol som sa pre druhu variantu cize za radom budem mat sk a hned za nim en slovo atd.

[code]static const char slovnik][14]PROGMEM ={
“sk0”,
“en0”,
“sk1”,
“en1”,
“sk2”,
“en2”, };

lcd_gotoxy(0,0);
lcd_puts(slovnik[premena]);[/code]

Musel som este pridat static lebo mi vypisovalo warning:‘progmem’ attribute ignored
Ale po doplneni static mi zas nekorektne zobrazuje lcd. Podla avr studia vsetko uklada do flash ale zle mi to zobrazuje.

Toto som nepochopil aky ukoncovaci 0x00?

C-čko ukládá řetězec následujícím způsobem :
AHOJ vypadá v paměti následovně : 0x41 0x48 0x4F 0x4A 0x00

Řetězec je dlouhý 4 znaky - strlen vrátí 4, ale v paměti zabírá 5 bytů …

Ve Tvém případě, když máš délku řetězce [14], tak musíš počítat s tím, že můžeš mít slovo dlouhé maximálně 13 znaků + ukončovací 0x00.

Radius : C-čko moc nepoužívám, většinu píšu v assembleru, ale vím, že mi tohle AVR Toolchain dělal taky, takže jsem používal na debugování WinAVR. Ale před nějakým časem mi začal chodit i toolchain, jenže netuším, čím se to změnilo. Zjistil jsem to náhodou, když jsem si tady v klidu krokoval program, pak jsem měnil kmitočet hodin a všimnul jsem si, že to chodí i s toolchainem. Určitě jsem něco musel v počítači měnit, ale opravdu nevím co …

Mám AVR Studio 4.19 Build 716 a pokud souhlasí verze, tak AVR Toolchain 3.4.5.1522