ako naprogramovat

Daniel Valuch balu na k-net.fr
Pondělí Duben 15 10:04:29 CEST 2024


ano, nakoniec (uz v piatok) som to tak urobil. Je vytvorene FIFO s 
dlzkou spravy. Ked pride byte tak sa to cele posunie a novy znak zapise 
na koniec. Ak program na zaciatku najde "klucove slova" tak to extrahuje 
pozadovane 32 a 16 bitove cisla z paketu. A ano, neobtazoval som sa s 
pocitanim checksum.

Moj kod je taky drevorubacsky, funguje to, som si vedomy co sa stane v 
pripade prijmu zleho paketu. Cas sa pouziva len na zobrazenie na 
displeji, takze risk je akceptovatelny.

volatile byte tempArray1[24];         // temporary array for input data 
parsing from Serial1. It receives hex digits

// reception of character from uBlox serial link2 (binary timepulse)
void serialEvent1() {
   while (Serial1.available()) {
     // get the new byte:
     byte inByte = (byte)Serial1.read();
     for (byte i = 0; i < sizeof(tempArray1) - 1; i++) {
       tempArray1[i] = tempArray1[i + 1];
     }
     tempArray1[sizeof(tempArray1) - 1] = inByte;

     // 0-1 checksum
     // 2-18 data
     // 19-20 msglen
     // 21-24 header
     if (tempArray1[3] == 0x01 && tempArray1[2] == 0x0D && tempArray1[1] 
== 0x62 && tempArray1[0] == 0xB5) {
       towMS = *((long*)(&(tempArray1[6])));
       week = *((int*)(&(tempArray1[18])));
       doTimeCalculation = true;
       GPSlocked = true;
       GPSlockedTimestamp = millis();
     }
   }
} // end serialEvent1


On 14/04/2024 23:34, David Obdrzalek wrote:
> Já bych ještě s dovolením podotknul, že používat String v situaci, kdy se do něj
> inkrementálně neco strká, je dost neefektivní jak paměťově, tak výkonově, protože
> tempString += inChar; znamená, že se v zásadě udělá nová alokace na velikost součtu
> délek (v tomhle přípaně jen o 1 větší) a okopíruje se tam všechno plus ten nový
> znak. A tak pořád dokola.
> Plus je potřeba připočítat management okolo vlastní existence instance String.
>
> Pokud vím, jak je zpráva dlouhá, tak je šetrnější deklarovat rovnou buffer potřebné
> délky a do něj to postupně ukládat. Nebo zprávu dokonce zpracovávat za letu tak jak
> přicházejí jednotlivé znaky a nepotřebuju ani buffer na celou zprávu.
>
> Ono sice né že by to byl ve spojení se seriovou linkou nějaký výkonnostní problém
> (seriová komunikace je obvykle výrazně pomalejší, než jak běží mikrokontroler, takže
> se mezitím ta realokace v pohodě stihne). Také obvykle string bude krátký, takže
> nejspíš ani nějaké potíže, že by se to do paměti nevešlo dvakrát nebo došlo k nějaké
> fatální vnitřní fragmentaci paměti, asi taky nenastanou. Ale myslím, že ani tehdy se
> prostě nemá plýtvat :-)
>
> Na druhou stranu souhlasím, že pokud se jedná o nějakou jednorázovku nebo něco fakt
> triviálního, kde i těch 32 kB programové paměti Arduino Uno je řádově víc, než
> potřebuju, a 16MHz hodiny to ženou tak rychle, že se to stejně vlastně pořád jen
> točí dokola v loop, aniž by to dělalo něco rozumného, a navíc ani nepotřebuju nijak
> šetřit energií, tak se zohledněním ceny času programátora může být prostě
> efektivnější se s tím nebabrat a namastit to tam víceméně jakkoli... (ovšem když se
> to namastí ne plýtvavě, tak to asi vadit nebude, žejo)
>
> D.O.
>
>
>
>
> PS: Pro srovnání:
> A)
> volatile String retezec;
> void loop() {
>    while(Serial.available())
>    {
>      char novyZnak;
>      novyZnak = Serial.read();
>      retezec += novyZnak;
>    }
> }
>
> B)
> const unsigned maxDelka=100;
> volatile char retezec[maxDelka];
> uint8_t delka;
> void loop() {
>    while(Serial.available())
>    {
>      char novyZnak;
>      novyZnak = Serial.read();
>      if(delka<maxDelka-1) {
>        retezec[delka++] = novyZnak;
>        retezec[delka] = 0;
>      }
>    }
> }
> (volatile je v obou případech jen aby se to fakt uložilo, jinak by to přinejmenším v
> tom druhém případě teď bez dalšího použití pole retezec překladač vyoptimalizoval)
>
> Na mé instalaci se pro Arduino Uno A) přeloží do 2826 B programové paměti + 202 B
> gbálních proměnných, B) do 1388 B + 285 B. V B) jsem dal 100 jen tak od oka, neznaje
> max délku té věty v ASCII, tam by samozřejmě mělo být něco rozumnějšího. A) má proti
> B) větší program o cca kilo a půl. Na proměnných to je sice na první pohled naopak,
> B) teď potřebuje o 83 B víc místa pro globální proměnné, ale za běhu už pak nebude
> potřebovat téměř žádné lokální nebo dynamické alokování, zatímco varianta A)
> potřebuje vždy naalokovat dvakrát tolik místa, než je délka věty, kterou přijímá.
> Protože jak globální, tak lokální a dynamicky naalokované proměnné jsou ale ve
> stejné paměti, je potřeba porovnávat součet, takže B) bude proti A) úspornější i z
> tohoto pohledu.
> (běhovou analýzu, jak přesně moc ten heap roste dělat nebudu)
>   
>
> Detailnější pohled na přidání 1 písmene do Stringu: V případě A) se to retezec +=
> novyZnak; přeloží zavoláním metody retezce concat, která uvnitř vytvoří z toho
> jednoho znaku céčkový řetězec a zavolá concat stávajícího Stringu s ním:
> unsigned char String::concat(char c)
> {
> 	char buf[2];
> 	buf[0] = c;
> 	buf[1] = 0;
> 	return concat(s.buffer, s.len);
> }
>
> Tehnle druhý concat si vyžádá rezervaci délky bufferu na požadovanou novou délku a
> strcpy pak na konec původního přikopíruje nový:
> unsigned char String::concat(const char *cstr, unsigned int length)
> {
> 	unsigned int newlen = len + length;
> 	if (!cstr) return 0;
> 	if (length == 0) return 1;
> 	if (!reserve(newlen)) return 0;
> 	strcpy(buffer + len, cstr);
> 	len = newlen;
> 	return 1;
> }
>
> Metoda reserve zavolá v případě zvětšování metodu changeBuffer:
> unsigned char String::reserve(unsigned int size)
> {
> 	if (buffer && capacity >= size) return 1;
> 	if (changeBuffer(size)) {
> 		if (len == 0) buffer[0] = 0;
> 		return 1;
> 	}
> 	return 0;
> }
>
> Metoda changeBuffer zavolá realloc:
> unsigned char String::changeBuffer(unsigned int maxStrLen)
> {
> 	char *newbuffer = (char *)realloc(buffer, maxStrLen + 1);
> 	if (newbuffer) {
> 		buffer = newbuffer;
> 		capacity = maxStrLen;
> 		return 1;
> 	}
> 	return 0;
> }
> Tady připouštím, že je možné, že realloc uvnitř zjistí, že za tím řetězcem je ještě
> volno, takže není potřeba přesouvat. To nevím, jak je pro avr implementované, ale i
> kdyby, tak za tím řetězcem volno principiálně být nemusí a tak to čert bude nutit
> přesouvat pořád znovu a znovu.
>
> On 12 Apr 2024 at 18:19, Daniel Valuch wrote:
>
>> zdravim osadenstvo,
>>
>> programovat viem len velmi zakladne, preto by som mal na piatok
>> algoritmicku... Dokoncujem ziskavanie presneho casu z GNSS modulu o
>> ktorych sme tu uz nejaky cas rozpravali.
>>
>> Ten generuje dva typy vystupu po seriovej linke. Klasicky ascii, ktory
>> je ukonceny \n znakom a parsovanie tohoto stringu je trivialne (robim v
>> arduino ide). Prijimaju sa data, tie sa pridavaju do stringu a ked pride
>> \n tak sa to rozobere a urobi co treba
>>
>> void serialEvent() {
>>     while (Serial.available()) {
>>       // get the new byte:
>>       char inChar = (char)Serial.read();
>>       if (inChar == '\n') {
>>           // sprava/retazec je hotovy, rozparsuj a urob co treba
>>         tempString = "";
>>       }
>>       // keep receiving until \n arrives
>>       else {
>>         // add it to the inputString and keep receiving:
>>         tempString += inChar;
>>       }
>>
>> Druhy vystup je ale binarny, prichadzaju pakety, ktore maju strukturu
>> definovanu, ale paket zacina opacne.
>>
>> 0000  B5 62 06 8A 18 00 00 05 00 00 01 00 76 10 01 05
>> 0010  00 53 10 01 7E 01 91 20 00 7F 01 91 20 01 00 B6
>>
>> Prve dva bajty na zaciatku B5 62 vzdy oznacuju zaciatok paketu
>>
>> dalsie dva 06 8A oznacuju o aky paket ide
>>
>> nasledujuce dva 18 00 dlzku kolko byteov spravy nasleduje (v tomto
>> pripade 24)
>>
>> potom je samotna sprava
>>
>> a na konci 00 B6 su dva bajty checksum
>>
>> a s tymto si neviem poradit, ako to zapisat aby to pocuvalo kedy pride
>> B5 62, pockalo ako dlha bude sprava a potom zapisalo do nejakeho stringu
>> data.
>>
>> Ako na to?
>>
>> dakujem,
>>
>> b.
>>
>>
>
>
> _______________________________________________
> HW-list mailing list  -  sponsored by www.HW.cz
> Hw-list na list.hw.cz
> http://list.hw.cz/mailman/listinfo/hw-list
>



Další informace o konferenci Hw-list