Formatovany tisk pro 8bit

Jan Waclawek konfera na efton.sk
Úterý Duben 23 09:05:39 CEST 2024


> protože v obou případech se používá pro řetězec const char* fa ne  __FlashStringHelper* f,což by umožnilo udělat přetížení.

Ja C++ nepouzivam (podla mna, rovnako ako malloc() a printf() (a float v
mcu bez HW podpory pre float), do mcu nepatri, resp. jeho pouzitie sa
riadi principom: najprv tresni klavesnicou po ruke, a az ked dostanes
vycerpavajucu analyzu jednoznacne dokazujucu prevahu vyhod nad nevyhodami,
tak sa ospravedln)), takze si v C++ pokojne urobte pretazenu verziu. Ale
ako pisem, nenachadzam dovod vobec mat ne-FLASH verziu.

> alloca() má proti  malloc()výhodu že se nemusí uvolňovat a uvolní se sama nebo ještě jinou?

alloca() alokuje miesto na zasobniku, akoby sa jednalo o lokalnu premennu,
t.j. vobec netreba mechanizmy okolo malloc() aj s ich sprievodnymi javmi.
Znova, neviem, ci v C++ je vobec k dispozicii, a treba si aj vysetrit, ake
to ma napr. nasledky na velkost kodu a dlzku vykonavania (v AVR som pouzil
raz, a to bolo asi pred 15 rokmi).

> Tu by som sa chcel spytat, preco vsetci robite konverziu od najmensej mocniny 10 a nie od najvacsej mocniny?

Ako vzdy, v mcu neexistuje "najlepsie" riesenie. Ano, ist od najvyssej
mocniny ma vyhodu v tom, ze netreba vobec ziadne miesto na
skladanie/otacanie retazca atd. "Nevyhoda" je, ze si treba bud ratat
"aktualnu" mocninu 10, alebo mat tabulku. A potom sa mozeme bavit aj o
variantach t.j. ci pouzit div/mod alebo opakovane odcitanie apod.

A potom u niektorych mcu je napriklad k dispozicii BCD aritmetika (resp.
desiatkova korekcia) a to otvara zase priestor pre nejake ine algoritmy.
Atd.

wek



----- Original Message ---------------
Ještě k té verzi ve flash. Chápu to dobře, že se to musí udělat tak, že 
to jsou dvě funkce, ale v té pro flash je

   i = strlen_P(f) + 1;  // these two functions do have the FLASH (_P)
variants
   strcpy_P(buf, f);
a ve volání
pr(0,  PSTR("Pokus1=###\n"));

protože v obou případech se používá pro řetězec const char* fa ne 
__FlashStringHelper* f,což by umožnilo udělat přetížení.

alloca()má proti  malloc()výhodu že se nemusí uvolňovat a uvolní se sama
nebo ještě jinou?

Martin Záruba

Dne 22.4.2024 v 0:27 Jan Waclawek napsal(a):
> Pekne.
>
> Ma to vsak tu istu chybu na ktoru som uz upozornoval predtym: odstranujete
> prilis vela nul.
> Skuste
> pr(0,  "Pokus1=###\n");
> pr(23, "Pokus2=###.###\n");
> Dalsia, suvisiaca chyba je, ze minus moze prepisat desatinnu bodku:
> pr(-123, "Pokus3=###.###\n");
>
> Obe chyby sa daju odstranit bud trikom, ktory mi napisal Andy Jancura mimo
> konfery, kde sa tie nuly, ktore netreba odstranovat, doplnia vopred, tu
> priamo do toho formatovacieho retazca - napr. ten retazec bude teda
> vyzerat takto
> pr(0,  "Pokus1=##0\n");
> pr(-123, "Pokus3=##0.000\n");
> a funkcia bude v duchu
>
> void pr(int32_t h, const char* f) {
>    char buf[100];
>    uint8_t i;
>    uint32_t uh;
>    _Bool isNegative;  // C++ : bool
>
>    i = strlen(f) + 1;  // these two functions do have the FLASH (_P) variants
>    strcpy(buf, f);
>
>    if (h < 0) {
>      uh = -h;
>      isNegative = 1;
>    } else {
>      uh = h;
>      isNegative = 0;
>    }
>
>    do {
>      i--;
>      if ((buf[i] == '#') || (buf[i] == '0')) {
>        if (uh != 0) {
>          buf[i] = uh % 10 + (uint8_t)'0';
>          uh /= 10;
>        } else if (buf[i] == '#') {  // don't touch the zeros in formatting
> string
>          if (isNegative) {
>            buf[i] = '-';
>            isNegative = 0;
>          } else {
>            buf[i] = ' ';
>          }
>        } // (*)
>      }
>    } while (i > 0);
>    Serial.print(buf);
> }
>
> Nevyhoda je, ze sa v texte nemoze vyskytnut okrem # ani nula.
>
> Pouzil som funkcie strlen() a strcpy(), jednak preto, lebo su napisane
> optimalne v asm, a druhak preto, lebo maju aj _P verziu. Ak sa nepouziju
> ale sa kopiruje po znakoch ako v povodnej verzii, treba vo FLASH verzii
> funkcie pouzivat pgm_read_byte(),
> https://www.nongnu.org/avr-libc/user-manual/pgmspace.html  , co je otravne.
> V C je moznost pouzit namiesto prostriedkov z <avr/pgmspace.h> named
> address space __flash
> https://gcc.gnu.org/onlinedocs/gcc/Named-Address-Spaces.html#AVR-Named-Address-Spaces
> , ale v C++ nie.
>
> Da sa ta funkcia rozbit na dve polovice, kde prva len kopiruje do toho
> docasneho bufra, a tym padom sa da verzia pre FLASH a RAM napisat tak, ze
> ma rozdielny len ten zaciatok s kopirovanim a potom sa vola jeden spolocny
> koniec. Ale aj tak asi verziu pre RAM nikdy nepouzijete, takze nad tym
> zase netreba tolko spekulovat.
>
> Tiez som pre "odomielanie" pouzil neznamienkovu premennu (uh), mam nicim
> neodovodneny pocit, ze neznamienkove % bude efektivnejsie. gcc za urcitych
> okolnosti vie pouzit jednu funkciu z internej kniznice pre obe operacie
> div mod, namiesto separatneho delenia a modula, treba si ustrazit, aby
> bola pouzita (nepamatam si presne tie okolnosti, to avr-gcc uz aktivne
> nepouzivam zo 10 rokov).
>
> Ak vadi to, ze sa nuly nedaju pouzit v texte, da sa pouzit nejaka ina
> znacka, ktora sa v mieste oznacenom (*) prepise na nuly.
>
> Ak sa Vam nepacia formatovacie stringy s nulami alebo nahradnou znackou,
> tak je tu algoritmicka moznost, ze sa napocita pocet potrebnych nul pri
> tom prechode "dopredu" (rovna sa pocet # za desatinnou bodkou plus jedna,
> ak nie je desatinna bodka tak jedna); a pri "tlaceni" v smere dozadu sa
> pri kazdom "vytlacenom" znaku odcita z tohoto poctu nul, a ak je uh
> nulove, tlacia sa nuly az kym ten pocet nevynuluje. Je to viac programu a
> podla mna sa tym nic take vyznamne neziska.
>
> Tych pausalnych 100 byte zo stacku sa mi tiez nepaci. A malloc() v mcu si
> vyzaduje velmi dobre odovodnenie (vo vacsine pripadov to odovodnene nie je
> a malloc() sa jednoducho nema pouzivat uplne rovnako ako ten printf()).
> Jedna z moznosti je buf = alloca(i);
> https://www.nongnu.org/avr-libc/user-manual/group__alloca.html, ale treba
> mysliet na to, ze takto moze zasobnik pretiect; v mcu musi clovek mat
> vsetky pamate pod plnou kontrolou (t.j. musi ten zasobnik mat vypocitany).
> V konecnom dosledku, ak si ten zasobnik skutocne vypocitate, zistite, ze
> aj tak musite vediet, aky najdlhsi string budete tlacit, takze tam ten
> konstantny buffer moze byt a moze to byt najefektivnejsie riesenie.
>
> Narocnejsia moznost, ktora setri pamat/zasobnik za cenu dlhsieho programu,
> je to spominane rozbitie na text a cislo: text pred cislom je jednoduchy,
> ide sa az po prvu znacku a moze sa tlacit znak po znaku t.j. netreba
> ziadnu extra pamat; text za cislom  je vlastne tiez jednoduchy, ide sa od
> konca po prvu (t.j. poslednu) znacku a zapamata sa, kde ta znacka je,
> nakopiruje sa len kus medzi prvou a poslednou znackou, urobi sa konverzia,
> vytlaci sa; a potom sa vytlaci znak po znaku aj ten text za poslednou
> znackou. Cislo nebude vacsie ako cojaviem 10 cislic 2 mezery a jedna
> desatinna bodka a jedno minus, to je 14, to sa da.
>
> Ale samozrejme, ako vzdy, detaily zavisia od poziadaviek. V mcu nikdy
> neexistuje jedno "najlepsie" riesenie.
>
> wek
>
> PS. Disasm je avr-objdump -d -S program.elf >program.lss
> Myslim, ze som tu pred par mesiacmi o tom pisal, nechce sa mi to hladat. Tu
> https://sourceware.org/binutils/docs-2.42/binutils/objdump.html  je
> dokumentacia k objdump; on sam vypise vacsinu pouzitelnych prepinacov pri
> pouziti --help.
>
>
>
> ----- Original Message ---------------
>
> Subject: Formatovany tisk pro 8bit
>     From: Martin Záruba<swz na volny.cz>
>     Date: Fri, 19 Apr 2024 19:23:12 +0200
>       To: Martin Zaruba<hw-list na list.hw.cz>
>
> 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


Další informace o konferenci Hw-list