Dekódování, načtení obecných sériových dat

AstroMiK
Příspěvky: 592
Registrován: 08 pro 2017, 19:05
Reputation: 0

Re: Dekódování, načtení obecných sériových dat

Příspěvek od AstroMiK » 08 bře 2022, 17:58

Vlákno mne zaujalo, tak jsem si postavil simulátor toho čidla natočení.

Program simuláoru odesílá v půlsekundových intervalech tu sekvenci '1010', za kterou následuje binární kód úhlu '0000' až '1111'.

SIMULÁTOR:

Kód: Vybrat vše

#define vysilac          5

byte uhel;

//-----------------------------------------
void setup(void)
  {
    Serial.begin(9500);
    pinMode(vysilac,OUTPUT);  
  }


//-----------------------------------------
void loop(void)
  {
    for (uhel = 0; uhel < 16 ; uhel ++)
      {
        for (int bity = 7; bity >= 0 ; bity --)
          {
            jeden_impulz(bitRead(0b10100000 + uhel,bity));
          }
       delay(490);
       Serial.println(uhel);
      }
  
  }


//-----------------------------------------
void jeden_impulz(boolean stav)
  {
    if (stav == true)
      {
        digitalWrite(vysilac,HIGH);
        delayMicroseconds(1000);
        digitalWrite(vysilac,LOW);
        delayMicroseconds(500);
      }
    else
      {
        digitalWrite(vysilac,HIGH);
        delayMicroseconds(500);
        digitalWrite(vysilac,LOW);
        delayMicroseconds(1000);        
      }
  }
//-----------------------------------------


Výstup jednoho datového bloku ze simulátoru na osciloskopu (stav "10100010"):
10100010.gif


Na druhém Arduinu jsem spustil ten svůj včerejší program s použitím funkce pulseIn() a FUNGOVALO to!
Během dvou datových bloků se to sesynchronizovalo a začalo to sypat hodnoty.



Zkusil jsem na to jít ještě trochu jiným způsobem - bez měření šířky impulzů.
Jen se správným načasováním testování stavu pinu od první vzestupné hrany prvního impulzu.

První test proběhne po 700 mikrosekundách od první vzestupné hrany, dalších 7 testů potom s pravidelným odstupem 1500 mikrosekund.
Když se test trefí do stavu HIGH, nastaví se ve výsledku bit do '1', když se test trefí do LOW, zůstane příslušný bit v '0'

Odzkoušeno a také funguje.

Verze s časovanými testy stavu:

Kód: Vybrat vše


#define cteci_pin   5

unsigned long start_dat;

//============================
void setup(void)
  {
    Serial.begin(9600);
    pinMode(cteci_pin,INPUT_PULLUP);

    while (digitalRead(cteci_pin) == LOW) ;          // tady visi tak dlouho, nez dorazi prvni vzestupna hrana (je uplne jedno, jestli trefi nejaky prostredni impulz)
    delay(50);                                       // bezpecne preklene jakakoliv data az do mista, kde zadna data zarucene nejsou
    while (digitalRead(cteci_pin) == LOW) ;          // znova ceka na vzestupnou hranu. Ted je jistota, ze je to prvni impulz z datoveho bloku
    start_dat = micros();                            // casova znacka, kde zacinaji data

  
  }

//============================
void loop(void)
  {
    if (micros() - start_dat > 700)                  // prvnich 500 mikrosekund je nezajimavych (budou vzdycky HIGH). Zajimave je to, co nasleduje mezi 500 a 1000 mikrosekundami
      {                                              //                          Nad 1000 mikrosekund bude zase vzdycky stav LOW, takze taky neni zajimavy.
        byte vysledek = 0;
        for (int pulz = 7 ; pulz >= 0 ; pulz --)     // ocekava se 8 impulzu. Test stavu probiha vzdycky 700 mikrosekund po zacatku impulzu
          {
            if (digitalRead(cteci_pin) == HIGH) bitSet(vysledek,pulz);  // podle aktualniho stavu cteciho pinu se posklada vysledny bajt
            delayMicroseconds(1500);                 // kazdy impulz trva 1500 mikrosekund (nezavisle na tom, jestli signalizuje '1' nebo '0') 
          }


        //----------------------------------
        // tady se muze necelou pul sekundu vykonavat nejaka dalsi cinnost (muze se i testovat, jestli jsou data v poradku)
        if ((vysledek & 0b11110000) == 0b10100000)  Serial.println(vysledek,HEX);        // test hornich 4 bitu
        else                                        Serial.println("Chyba dat");
        delay(400);
        //----------------------------------
 
      
        while (digitalRead(cteci_pin) == LOW) ;      // ceka se dalsi vzestupnou hranu - to bude prvni impulz z dalsiho datoveho bloku
        start_dat = micros();                        // casova znacka, kde zacinaji data

      }

  }
//============================


rteppp
Příspěvky: 5
Registrován: 07 bře 2022, 18:01
Reputation: 0

Re: Dekódování, načtení obecných sériových dat

Příspěvek od rteppp » 09 bře 2022, 13:26

To: AstroMik
Krásná práce!
Děkuji!

Zítra budu mít více času, tak odpoledne otestuji v reálu.

Mezitím si dovolím mít dva dotazy:
- bylo by možno, prosím, startovat zpracování příjmu datového paketu přes přerušení?
Já zatím zvládl přerušení na úrovni počítání rychlosti otáčení anemometru na měření rychlosti větru :-))
Tím bych nemusel myslet na čtení při běhu hlavního programu, který ještě kromě zobrazení natočení pres matici 8x8 led s IO MAX7219, hlídá dvě tlačítka a ovládá dvě relé, což jsou časově nenáročné fce, ale...

- na jakém HW běží funkční generátor pro simulaci? vypadá to dobře a občas by se mi něco takového sešlo?

AstroMiK
Příspěvky: 592
Registrován: 08 pro 2017, 19:05
Reputation: 0

Re: Dekódování, načtení obecných sériových dat

Příspěvek od AstroMiK » 09 bře 2022, 15:50

bylo by možno, prosím, startovat zpracování příjmu datového paketu přes přerušení?
- Asi ano, ale přenechám raději zkušenějším.
na jakém HW běží funkční generátor pro simulaci?
- Dělal jsem to na Arduino NANO, ale když se vyhodí ten zbytečný Serial.print() a upraví číslo výstupního pinu, tak se to s rezervou vejde třeba i do ATtiny13.

peterple
Příspěvky: 156
Registrován: 22 zář 2021, 20:20
Reputation: 0

Re: Dekódování, načtení obecných sériových dat

Příspěvek od peterple » 09 bře 2022, 18:13

Jedna z možností ako to urobiť pomocou prerušení a čítača. Naschvál som nepoužil k tomu žiadnu knižnicu aby bolo vidno že je to pomerne jednoduché. Samozrejme za predpokladu že človek vie čo má ten chrobák za periférie a ako fungujú.
Ešte dodám že tento čítač má aj tzv Capture input mode pomocou ktorého sa to odchytávanie stavu čítača dá nechať na hw toho čítača. Nevýhoda je že sa nedá nastaviť odchytávanie na obe hrany (nábežnú aj dobežnú) ale len na jednu. To dovoľuje krásne merať periódu signálu pripojeného na ICP1 vstup v podstate s nulovou réžiou procesora. Skvelé na meranie otáčok.
V tomto prípade ale perióda je stále rovnaká a treba merať čas aj od nábežnej a dobežnej hrany. Tak som to urobil pomocou prerušovaceho vstupu INT0. Tam sa dá nastaviť aby prerušenie nastalo pri oboch typov hrán.

Celé toto sw riešenie je možné nasadiť na také úlohy ako je už spomínané meranie otáčok, periódy, dekódovanie signálov z IR DO, alebo DCF.

Kód: Vybrat vše

#include <util/atomic.h>

#define NEW_EDGE 0
volatile uint8_t flags;
volatile uint16_t duration;
uint16_t lastEdgeTime;
uint16_t actualEdgeTime;

void setup() {
  Serial.begin(9600);
  Serial.println("Start");
  pinMode(2, INPUT_PULLUP);

  TCCR1A = 0;         //normalny mod citac 1 pocita od 0 do 65365 potom pretecie na 0
  TCCR1B = (1<<CS12); //preddelic 256 - citac pocita FOSC/256
                      //to je 16Mhz/256 = 62.5kHz
                      //citac 1 ma rozsah 16bitov takze dokaze zmerat interval max 1.048576 sekundy
                      //rozlisenie je 16µs
  EICRA = (1<<ISC00); //kazda hrana prerusuje
  EIMSK = (1<<INT0);
}

ISR(INT0_vect)
{
  actualEdgeTime = TCNT1;
  duration = actualEdgeTime-lastEdgeTime;
  lastEdgeTime=actualEdgeTime;
  flags |= (1<<NEW_EDGE);
}
void loop() {
  uint16_t duration_local;
  if (flags & (1<<NEW_EDGE)){
    flags &=~(1<<NEW_EDGE);
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE){
      duration_local=duration;    
    }
    Serial.println(duration_local);
  }
}
Tu je výstup na signál z toho simulátora predrečníka. Dúfam že dekódovanie signálu je už na základe toho hračka. A samozrejme že najlepšie je ho napísať do ISR.

Kód: Vybrat vše

18:35:53.284 -> 30648
18:35:53.284 -> 63
18:35:53.284 -> 33
18:35:53.284 -> 31
18:35:53.284 -> 64
18:35:53.331 -> 63
18:35:53.331 -> 31
18:35:53.331 -> 32
18:35:53.331 -> 63
18:35:53.331 -> 32
18:35:53.331 -> 63
18:35:53.331 -> 63
18:35:53.331 -> 32
18:35:53.331 -> 63
18:35:53.331 -> 31
18:35:53.331 -> 32
18:35:53.800 -> 30680
18:35:53.800 -> 63
18:35:53.800 -> 33
18:35:53.800 -> 31
18:35:53.800 -> 63
18:35:53.800 -> 63
18:35:53.800 -> 32
18:35:53.800 -> 32
18:35:53.847 -> 63
18:35:53.847 -> 32
18:35:53.847 -> 63
18:35:53.847 -> 63
18:35:53.847 -> 31
18:35:53.847 -> 63
18:35:53.847 -> 32
18:35:53.847 -> 63

rteppp
Příspěvky: 5
Registrován: 07 bře 2022, 18:01
Reputation: 0

Re: Dekódování, načtení obecných sériových dat

Příspěvek od rteppp » 09 bře 2022, 22:30

Tak se mi podařilo ukořistit záložní snímač a vyzkoušet všechny navržené příklady.
Všechny tři fungují!

To AstroMiK
Verze s časovanými testy stavu je přesnější, dává stabilní výsledky.

To peterple
Poté co jsem asi tak 200 vzorků natáhnul do Calcu (OpenOffice) tak jsem byl překvapen stabilitou výsledků. Nasbírané čsy se liší max o +/- 1 číslici.

Zkusím postupně všechny vizulaizovat na matixi 8x8 a uvidím jak to bude stabilní ještě s dalšími věcmi, které by to mělo dělat :-)
Zatím vám oběma děkuji, ale kdyby měl ještě někdo další nápad, tak sem s ním :-)

peterple
Příspěvky: 156
Registrován: 22 zář 2021, 20:20
Reputation: 0

Re: Dekódování, načtení obecných sériových dat

Příspěvek od peterple » 10 bře 2022, 19:10

Pre mňa to tak prekvapivé nie je. Keď máš presné hodinky vieš aj presne zmerať čas. MCU presné hodinky má. Ak to nezabiješ nejakými dlhými obsluhami prerušení, tak to aj tak zostane. Latencia na INT0 je pri 16MHz určite pod jednu µs. Pri rozlíšení 16µs sa tam teda môže uplatňovať iba chyba +- jeden digit. Ak to bude ukazovať menej alebo viac tak môžeš skôr veriť tomu čo meria procesor ako tomu snímaču. Už sa mi také raz stalo, pri meraní rýchlosti mali podozrenie že to zle meria ale keď sa to prekontrolovalo osciloskopom tak sa ukázalo že v meraní problém nebol.

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 5 hostů