Formatovany tisk pro 8bit

Martin Záruba swz na volny.cz
Neděle Duben 21 10:12:10 CEST 2024


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
------------- další část ---------------
HTML příloha byla odstraněna...
URL: <http://list.hw.cz/pipermail/hw-list/attachments/20240421/5770dc68/attachment-0001.htm>


Další informace o konferenci Hw-list