Formatovany tisk pro 8bit

Pavel Hudeček edizon na seznam.cz
Neděle Duben 21 11:59:28 CEST 2024


Nepochybně ten nárůst kvůli knihovně nebude velký, ale sám jste psal, že 
to větší bylo:-)
V podstatě je tam několik věcí, které zvětšení způsobují (a třeba i 
nějaké další):
1. Separátně kompilovaná knihovna: Optimalizace překladu celku by třeba 
našla společné sekvence a tím ušetřila. Tohle ale nenastane.
2. Obecné vložení cizího kódu: Styl kódu je jiný, tak se snižuje 
pravděpodobnost, že kompilátor najde společné sekvence.

 >několikrát za sebou použije buf[i]

Nejsem si 100% jist, ale očekával bych, že tohle závisí na nastavení 
optimalizace a jak pak překladač uzná za vhodné. A že šance na registr 
se dá zvýšit slovem register v deklaraci.

PH

Dne 21.04.2024 v 10:12 Martin Záruba napsal(a):
>
> Myslím, že to s dobře napsanou knihovnou nebude tak hrozné. Všimněte 
> si, že když napíšete funkci, ale pak ji nepoužijete, zkontroluje se 
> sice na syntaktickou správnost, ale pak nezabírá žádný prostor v paměti.
>
> Stále váhám, zda pro 100byte buffer, který je v tiskové rutině, takže 
> asi nehrozí, že by bylo nutné, aby rutina byla reentrantní je vhodné 
> použít malloc. Ten problém, co píšete, se tam asi nemůže stát a rutina 
> se tím stane univerzální a bude vždy zabírat jen tak nejméně statické 
> paměti, jak je nutné. Ale zase bude mít delší kód.
>
> Nevíte zda jestliže se několikrát za sebou použije buf[i] bude se 
> index pokaždé počítat nebo si kompilátor uloží index do registru? A co 
> třeba proměnné cyklu? Jsou v paměti nebo v registrech?
>
> Vím, že to tu někdo psal, ale nemohu to najít, jak získat výpis 
> assembleru. Holt mých asi 10 různých assemblerů, které jsem se v 
> životě učil mi možná v těch vyšších jazycích chybí.
>
> Martin Záruba
> Dne 20.4.2024 v 23:27 Pavel Hudeček napsal(a):
>> Posledně jsem nějak zapomněl na poslední dva:-)
>> Teď jsem hledal jak se jmenuje to se stringem ve flash..
>>
>> > ultoa()
>> Jakmile chci do výsledku něčeho jinak celkem jednoduchého zasáhnout, 
>> je obvykle lepší to mít celé svoje. A když z univerzální knihovny 
>> použiju jen jednu funkci, často sežere o dost víc než když mám svoji.
>>
>> > pole buf pomocí malloc
>> To samozřejmě jde a může ušetřit prostředky, jen je nutná jistá míra 
>> opatrnosti. Malloc/free v rámci blokující funkce je obvykle 
>> bezproblémové.
>>
>> Je dobré se vyhnout situaci, kdy probíhají asynchronní malloc a free 
>> na více místech. Když alokuju jeden kus, pak druhý, pak vrátím první 
>> a pak třeba alokuju jinej kus, kterej může bejt větší a současně 
>> alokovaných kusů může bejt hodně. To vede k fragmentaci volného 
>> místa, až nakonec malloc vrátí NULL, protože požadovaná paměť není k 
>> dispozici v celku. Typický problém třeba u příjmu komunikačních 
>> paketů s pozdějším zpracováním v jiném pořadí. I s tím se žít dá, jen 
>> se prostě musí počítat se situací, že malloc paměť nedá (na PC mám 
>> vždy if, jestli se to povedlo) a potom adekvátně reagovat.
>>
>> PH
>>
>> Dne 20.04.2024 v 14:01 Martin Záruba napsal(a):
>>>
>>> Nojo, jenže pak s tím neuděláte tabulku. Je potřeba, aby například 
>>> pokud je hodnota 3753, napsalo to |3753mV| ale pokud je 53, napsalo 
>>> to |  53mV| a ne |53mV|. Tedy aby celý řetězec (včetně toho mV) byl 
>>> stále (například) 6 znaků.
>>>
>>> Zkusil jste, kolik to zabere paměti? Podle toho, co píšete to dělá 
>>> převod na float. To ale na osmibitu je hrůza. Já si hraju jen s 
>>> "grafikou". Číslo stále dělím deseti, to je i na osmibitu snadné. A 
>>> vypisuji zbytek po dělení. No a někam vrazím jakoukoli "výplň", 
>>> třeba tu tečku. Pak to vypadá jako desetinné číslo, které ale je v 
>>> celočíselném formátu uloženo třeba 10x 100x nebo jak se chce větší, 
>>> což je myslím ten nejefektivnější způsob, jak na malinkém procesoru 
>>> zobrazit desetinné číslo.
>>>
>>> Zkoušel jsem také použít ultoa(). Ale je to větší a stejně musíte 
>>> výsledek formátovat.
>>>
>>> Napadlo mě ještě nejprve první smyčkou zjistit délku masky a pak 
>>> nadefinovat pole buf pomocí malloc. A na konci ho uvolnit. Pak by 
>>> většinou bylo malinké. Co si myslíte o tomto nápadu?
>>>
>>> Martin Záruba
>>> Dne 20.4.2024 v 12:29 Pavel Hudeček napsal(a):
>>>> Ne, v mém příkladu je přeci stav uBat1=3753, tak uartSend("\1mV", 
>>>> adUbat1, 0); vypíše 3753mV
>>>> Pokud by adUbat bylo 53, vypíše 53mV
>>>> a pokud by bylo zadáno uartSend("\1mV", adUbat1, 3);
>>>> vyleze 3753,000mV
>>>> nebo třeba 3753,001, pokud float hodnota nevyšla přesně 3753,000
>>>>
>>>> Nějak tak to fungovalo, už je to dlouho.
>>>> Ale jak se tu o tom teď diskutuje a ještě jsme na kroužku došli k 
>>>> sériáku, tak si asi konečně udělám tu knihovnu, kde tohle bude 
>>>> jedno z přetížení.
>>>>
>>>> PH
>>>>
>>>> Dne 20.04.2024 v 11:27 Martin Záruba napsal(a):
>>>>>
>>>>> Jen dotaz: Co vypíše:
>>>>>
>>>>> uBat1 je 53
>>>>>
>>>>> uartSend("\1mV",adUbat1,0);
>>>>>
>>>>> nevypíše to
>>>>>
>>>>> 53mV      ?
>>>>>
>>>>> Martin Záruba
>>>>> Dne 20.4.2024 v 10:36 Pavel Hudeček napsal(a):
>>>>>> Tady asi došlo k mírnému nedorozumění:
>>>>>> Oba umíme zobrazit jen jednu hodnotu.
>>>>>> Oba umíme požadovaný počet des. míst.
>>>>>> Oba umíme text před ním i po něm.
>>>>>> Já nemám formátování tisíců, ale zas můžu ve výstupním textu 
>>>>>> použít #.
>>>>>> Zas to formátování s # se asi dá ohackovat, že zobrazí třeba 2 
>>>>>> čísla zakódovaný do jednoho longu?
>>>>>>
>>>>>> // adUin je 12,3456  uBat1 je 3753
>>>>>> // UART_sendDT je ','  UART_sendPosChr je '\1'
>>>>>> uartSend("Uin=\1 V\n", adUin, 2);
>>>>>> uartSend("\1mV", adUbat1, 0);
>>>>>> výsledek je:
>>>>>> Uin=12,34 V
>>>>>> 3753mV
>>>>>>
>>>>>> Ten uartSend byl trochu prasáckej, mist nakopíruje do globální 
>>>>>> uartSendMist a pak zavolá cislo((long)(v * m)), kde m je třeba 
>>>>>> 1000 pro mist=3. A cislo pak do požadovaného místa vnutí 
>>>>>> oddělovač a uartSendMist vynuluje. Tohle jsem už někde měl i na 
>>>>>> ty tisíce, jen se to nevypínalo samo.
>>>>>>
>>>>>> Chystám se že bych si z těhle věcí konečně udělal nějakou 
>>>>>> knihovnu, zatím to jen kopíruju mezi projekty a nejčastějc si 
>>>>>> vystačím s putchar2, text na poslání textu a cislo na poslání longu.
>>>>>> takže posledně to bylo ve stylu
>>>>>> text("Uin="); cislo(static_cast<long>(1000.0*adUin)); text(" 
>>>>>> mV\r\n");
>>>>>>
>>>>>> Buffer je na zásobníku, takže sám vznikne a sám zmizí.
>>>>>> Ale 100 B, to je 20 % RAMky na ATtiny816, což je hodně, případně 
>>>>>> 1,25 % na AVR64DD32, to už by bylo v pohodě.
>>>>>> Mě se to obecně nelíbí, protože rád používám děje na pozadí. 
>>>>>> Funkce cekej(uint32_t ms) je i víc než půlka programu a pokud 
>>>>>> možno všechno čekání volá aspoň cekej(0). No a když se těch 
>>>>>> čekání sejde více takových, kde mezitím vzniknul buffer..
>>>>>> Takže mám snahu takové buffery nedělat.
>>>>>> Další věc je, že mám snahu minimalizovat místa, kde je potřeba 
>>>>>> omezovat velikost stringu. Takže mě stačí buffer na 10B celej 
>>>>>> vstup může mít 254, výstup až 264 a ve verzi s txtPred + txtPo 
>>>>>> můžou klidně oba texty mít do 254.
>>>>>>
>>>>>> Ovšem to s F a PSTR je pro mě novinka, za to díky.
>>>>>>
>>>>>> Byl jsem zvyklý na codevision, tam se daly deklarovat proměnné do 
>>>>>> RAM, EEPROM i Flash, "text" byl ve flash a všechno fungovalo do 
>>>>>> velké míry samo, včetně toho, že v EEPROM je pointer do flash. 
>>>>>> Super věc, pokud se po kompilaci k binárce sprostě přikopírujou 
>>>>>> UTF8 texty ve 4 jazycích a za ně bitmapa fontů. Při prvním 
>>>>>> spuštění program ve flash najde "Tady>>>", pak dohledá začátky 
>>>>>> jazyků, hlášky v default jazyku a nakonec font. Pointery hodí do 
>>>>>> EEPROM a odteď se může na displeji 10 ms po zapnutí objevit třeba 
>>>>>> normální čeština.
>>>>>> A v případě GCC jsem si myslel, že nic už takhle elegantně nepůjde.
>>>>>> Vlastně opravdu nejde, protože si sice můžu nadeklarovat 
>>>>>> proměnnou v EEPROM, ale nemůžu jí přímo používat, jen přes funkce 
>>>>>> na čtení a zápis EEPROM, který maj navíc hrozně dlouhý názvy. 
>>>>>> "Super" do vzorce se 3 kalibračníma konstantama.
>>>>>> Tak aspoň snad zas můžu mít texty ve flash:-)
>>>>>>
>>>>>> PH
>>>>>>
>>>>>> Dne 19.04.2024 v 21:23 Martin Záruba napsal(a):
>>>>>>>
>>>>>>> Já to tak původně dělal, jenže byl to mnohem složitější a 
>>>>>>> vlastně můžete takto udělat jen část než narazíte na první 
>>>>>>> formátovací znak. Pak už je to stejně jen odeslání čísla. 
>>>>>>> protože nevíte, zda nebude následovat další formátovací znak po 
>>>>>>> libovolné počtu "výplní". Tvar text,val, míst se mi nelíbil, 
>>>>>>> protože s ním neuděláte třeba 10mV. Takto je text kdekoli, 
>>>>>>> dokonce je kdekoli i třeba \n, takže nemá smysl println. A 
>>>>>>> varinta txtPred, val, míst, txtPo to sice umí, ale jsou 4 
>>>>>>> parametry a stejně nejde udělat třeba odskočené tisíce. Taky se 
>>>>>>> mi líbí, že to sežere i float. Předpokládím, že buffer se 
>>>>>>> vytvoří na zásobníku a po opuštění funkce zmizí. Je to tak?
>>>>>>>
>>>>>>> Ještě to chci doplnit o možnost mít formátovací řetězec ve 
>>>>>>> flash. Není mi ale jasné, jaký je rozdíl mezi PSTR("V paměti 
>>>>>>> flash") a F("V paměti flash"). Asi se mi víc líbí F(" "), je to 
>>>>>>> kratší zápis a dovoluje přetížení funkce. Ale možná má nějakou 
>>>>>>> nevýhodu, na kterou jsem nepřišel.
>>>>>>>
>>>>>>> Martin Záruba
>>>>>>> Dne 19.4.2024 v 20:50 Pavel Hudeček napsal(a):
>>>>>>>> Moc pěkný.
>>>>>>>> Já bych teda akorát nekopíroval celý text do velkého bufferu a 
>>>>>>>> místo toho text před číslem rovnou odesílal v prvním do/while, 
>>>>>>>> pak převed a odeslal číslo a nakonec odeslal zbytek vstupního 
>>>>>>>> textu.
>>>>>>>>
>>>>>>>> Už jsem taky kdysi použil variantu, kdy se zadávají parametry 
>>>>>>>> (text, val, mist) a v textu je pak znak pro umístění čísla a 
>>>>>>>> des. míst se odešle podle hodnoty mist. Častějc mám ale 
>>>>>>>> (txtPred, val, mist, txtPo).
>>>>>>>>
>>>>>>>> Odesílání mám teda téměř vždy rovnou průběžně po znacích a 
>>>>>>>> odesílací funkce čeká jen na dokončení předchozího znaku, takže 
>>>>>>>> konverze na výstupní text probíhá paralelně s odesíláním.
>>>>>>>>
>>>>>>>> PH
>>>>>>>>
>>>>>>>> Dne 19.04.2024 v 19:23 Martin Záruba napsal(a):
>>>>>>>>> Už jsem se Vás dost natrápil na toto téma a měl jsem pocit, že 
>>>>>>>>> nic moc úsporného a jednoduše použitelného není. Jenže jsem 
>>>>>>>>> paličatý a zkusil jsem přece něco vymyslet. Požadavek byl:
>>>>>>>>>
>>>>>>>>> Výpis na požadovaný počet míst s možností textu před i za číslem.
>>>>>>>>>
>>>>>>>>> Potlačení nevýznamných nul.
>>>>>>>>>
>>>>>>>>> Co nejúspornější kód jak funkce, tak volání, vhodný pro 
>>>>>>>>> malinky procesor.
>>>>>>>>>
>>>>>>>>> Přímý tisk bez nutnosti psaní Serial.print();
>>>>>>>>>
>>>>>>>>> Vyrobil jsem toto, posuďte a navrhněte prosím co by ještě šlo 
>>>>>>>>> líp.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> void pr(int32_t h, const char* f) {
>>>>>>>>>   char buf[100];
>>>>>>>>>   uint8_t i = 0xFF;
>>>>>>>>>   int32_t x = abs(h);
>>>>>>>>>   do {
>>>>>>>>>     i++;
>>>>>>>>>     buf[i] = f[i];
>>>>>>>>>   } while (f[i] != 0);
>>>>>>>>>
>>>>>>>>>   do {
>>>>>>>>>     i--;
>>>>>>>>>     if (buf[i] == '#') {
>>>>>>>>>       if (x != 0) {
>>>>>>>>>         buf[i] = x % 10 + (uint8_t)'0';
>>>>>>>>>         if (h < 0 && x < 10) {
>>>>>>>>>           i--;
>>>>>>>>>           buf[i] = '-';
>>>>>>>>>         }
>>>>>>>>>       } else {
>>>>>>>>>         buf[i] = ' ';
>>>>>>>>>       }
>>>>>>>>>       x /= 10;
>>>>>>>>>     }
>>>>>>>>>   } while (i != 0);
>>>>>>>>>   Serial.print(buf);
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Funkce má jediný formátovací znak #
>>>>>>>>>
>>>>>>>>> Příklady:
>>>>>>>>>
>>>>>>>>> int32_t napetimV = 5432;
>>>>>>>>> pr(napetimV, "Pokus1=###.###V\n");
>>>>>>>>> pr(-21,      "Pokus2=### zaporne cislo\n");
>>>>>>>>> pr(9876543,  "Pokus3=# ### ### cislo s mezerami po 1000\n");
>>>>>>>>> float a = 54.3;
>>>>>>>>> pr(a*10,     "Pokus4=####.# vypis float na 1 desetinne misto\n");
>>>>>>>>>
>>>>>>>>> Výsledek vypadá takto:
>>>>>>>>>
>>>>>>>>> Pokus1=  5.432V
>>>>>>>>> Pokus2=-21 zaporne cislo
>>>>>>>>> Pokus3=9 876 543 cislo s mezerami po 1000
>>>>>>>>> Pokus4=   54.3 vypis float na 1 desetinne misto 
>>
>> _______________________________________________
>> HW-list mailing list  -  sponsored bywww.HW.cz
>> Hw-list na list.hw.cz
>> http://list.hw.cz/mailman/listinfo/hw-list
>
> _______________________________________________
> HW-list mailing list  -  sponsored bywww.HW.cz
> Hw-list na list.hw.cz
> http://list.hw.cz/mailman/listinfo/hw-list
------------- další část ---------------
HTML příloha byla odstraněna...
URL: <http://list.hw.cz/pipermail/hw-list/attachments/20240421/fcc7bcfe/attachment-0001.htm>


Další informace o konferenci Hw-list