Problém s čtením dat z COM portu (sériová komunikace)

vasik006
Příspěvky: 7
Registrován: 30 bře 2022, 18:36
Reputation: 0

Problém s čtením dat z COM portu (sériová komunikace)

Příspěvek od vasik006 » 30 bře 2022, 18:44

Zdravím,
snažím se pomocí Arduina vytvořit ovladač pro simulátor a mám problém s čtením výstupu simulátoru. Můj první cíl je rozchodit kontrolku, kterou jsemv programu na získávání informací ze simulátoru definoval písmenem z, aby se mi při jejím rozsvícením v simulátoru rozsvítila na Arduinu. To se mi už povedlo, ale jakmile ji jednou rozsvítím, tak už ji nezshasnu. Z programu na získávání informací ze simulátoru mám přes COM port výstup z1, z0, z1, z0... Nevím, jak odlišit z0 od z1. Arduino mám pár dnů a žádný programátor nejsem, takže budu rád za každou pomoc. Díky! :)

Kód: Vybrat vše

[POSILEJ]

z = KontrolkaZaver

Kód: Vybrat vše

void setup() {
  Serial.begin(9600);
  pinMode(12, OUTPUT);
}
  
void loop() {
  if (Serial.read() == 'z') { 
    digitalWrite(12, HIGH);
  }
}

Uživatelský avatar
kiRRow
Příspěvky: 1151
Registrován: 07 kvě 2019, 07:03
Reputation: 0
Bydliště: Opava

Re: Problém s čtením dat z COM portu (sériová komunikace)

Příspěvek od kiRRow » 30 bře 2022, 20:11

Kód: Vybrat vše

void loop() {
  if (Serial.read() == 'z') { // čtu první znak
	if (Serial.read() == '1') { // hned za ním čtu druhý 
		digitalWrite(12, HIGH);
	} else { // a pokud ten znak není 1 předpokládám že je 0
		digitalWrite(12, LOW);	
	}
  }
}

vasik006
Příspěvky: 7
Registrován: 30 bře 2022, 18:36
Reputation: 0

Re: Problém s čtením dat z COM portu (sériová komunikace)

Příspěvek od vasik006 » 31 bře 2022, 16:44

Bohužel nefunguje, ani při tomhle se LEDka vůbec nerozsvítí.

Kód: Vybrat vše

void loop() {
  if (Serial.read() == 'z') {
    digitalWrite(12, HIGH);
  } else { 
    digitalWrite(12, LOW);  
  }
 }
 
Jinak tady je příklad výstupu z toho programu.
Přílohy
Snímek obrazovky 2022-03-31 164254.png

vasik006
Příspěvky: 7
Registrován: 30 bře 2022, 18:36
Reputation: 0

Re: Problém s čtením dat z COM portu (sériová komunikace)

Příspěvek od vasik006 » 31 bře 2022, 16:49

A tohle taky nic nedělá i kdyby mělo.

Kód: Vybrat vše

void loop() {
  if (Serial.read() == 'z') { 
  if (Serial.read() == '1') { 
    digitalWrite(12, HIGH); 
  }
 }
}

vasik006
Příspěvky: 7
Registrován: 30 bře 2022, 18:36
Reputation: 0

Re: Problém s čtením dat z COM portu (sériová komunikace)

Příspěvek od vasik006 » 31 bře 2022, 17:01

Člověk na anglickém fóru mi dal tenhle kód, který sice funguje jak má, ale je strašně složitý.

Kód: Vybrat vše

void setup() {
  Serial.begin(9600);
  pinMode(12, OUTPUT);
}
  
void loop() {
  static unsigned long serialInTimestamp = 0;
  static byte goodData = 0;
  if (goodData > 0) {
    if (millis() - serialInTimestamp >= 100UL) goodData = 0;
  }
  if (Serial.available()) {
    int c = Serial.read();
    if (goodData == 0) {
      if (c == 'z') {
        serialInTimestamp = millis();
        goodData = 1;
      }
      else goodData = 0;
    }
    else if (goodData == 1) {
      if ( c == '1') {
        digitalWrite(12, HIGH);
      }
      else if ( c == '0') {
        digitalWrite(12, LOW);
      }
      goodData = 0;
    }
  }
}

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

Re: Problém s čtením dat z COM portu (sériová komunikace)

Příspěvek od AstroMiK » 31 bře 2022, 17:50

Problém je v tom, že když první znak 'z' dorazí po sériové lince těsně před tím prvním Serial.read(), tak ho první Serial.read() sice bez problémů přečte, ale zároveň se tím vyprázdní přijímací buffer.
Když okamžitě po tom následuje další Serial.read(), bude se snažit přečíst druhý znak, který ještě do bufferu nedorazil.
A při pokusu o Serial.read() prázdného bufferu se vrací kód -1 (takže zhasne LED).

Řešení je několik, ale asi nejjednodušší je před ten druhý Serial.read() dát nějakou krátkou pauzu, která zajistí, že bude dost času na příjem druhého znaku.
Při rychlosti 9600 to vychází asi na milisekundu - pro sichr jsem tam dal radši 2 milisekundy.



(v kódu jsem upravil zarovnávání závorek - jsem tak zvyklý a program se mi zdá čitelnější)

Kód: Vybrat vše

void setup(void)
  {
    Serial.begin(9600);
    pinMode(12,OUTPUT);
  }

void loop(void)
  {
    if (Serial.read() == 'z')
      {
        delay(2);
        if(Serial.read() == '1')   digitalWrite(12, HIGH);        
        else                       digitalWrite(12, LOW);  
      }
  }

Jiné řešení by bylo využívat Serial.available(). A čtení dat provádět až v případě, když je v bufferu předpokládaný počet znaků.

vasik006
Příspěvky: 7
Registrován: 30 bře 2022, 18:36
Reputation: 0

Re: Problém s čtením dat z COM portu (sériová komunikace)

Příspěvek od vasik006 » 31 bře 2022, 18:52

Děkuji, to je přesně to, co jsem potřeboval. :) Jen mám otázku trochu mimo, proč jste napsal u void.setup a void.loop do závorky znovu void?

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

Re: Problém s čtením dat z COM portu (sériová komunikace)

Příspěvek od AstroMiK » 31 bře 2022, 19:12

... někde mě to naučili a tak to tak píšu furt. Význam to ale nemá.
Znamená to, že funkce setup a loop nemají žádné parametry.
Obvykle se ten druhý void nepíše.


Mimochodem ten příklad, který jsem uváděl, by bylo dost obtížné rozšiřovat o další funkce (další znaky - třeba 'x', 'y').
Lepší by bylo si uchovat ten první znak do proměnné a pak ho vyhodnotit buď pomocí několika podmínek if, nebo pomocí příkazu switch.

Kód: Vybrat vše

void setup()
  {
    Serial.begin(9600);
    pinMode(10,OUTPUT);
    pinMode(11,OUTPUT);
    pinMode(12,OUTPUT);
  }

void loop()
  {
    if (Serial.available() > 0)
      {
        char funkce = Serial.read();                                 // prvni znak udava funkci ('x', 'y', nebo 'z')
        delay(2);

        if (funkce == 'x')
          {
            int parametr = Serial.parseInt();                        // za 'x' nasleduje nejake cislo (-32768 az 32767)
            if(parametr > 5000)        digitalWrite(10, HIGH);       // pro vetsi cislo nez 5000 se LED 10 rozsviti
            else                       digitalWrite(10, LOW);        // pro mensi cislo LED zhasne
          }
        
        if (funkce == 'y')
          {
            float parametr = Serial.parseFloat();                    // za 'y' nasleduje nejake desetinne cislo
            if(parametr > 1.5)         digitalWrite(11, HIGH);       // pro vetsi cislo nez 1.5 se LED rozsviti
            else                       digitalWrite(11, LOW);        // pro mensi cislo LED zhasne
          }

        if (funkce == 'z')
          {
            char parametr = Serial.read();                           // druhy znak je parametr '1' nebo jakykoliv jiny znak
            if(parametr == '1')        digitalWrite(12, HIGH);       // "z1" rozsviti LED
            else                       digitalWrite(12, LOW);        // "z0" zhasne LED
          }
        
      }
  }

vasik006
Příspěvky: 7
Registrován: 30 bře 2022, 18:36
Reputation: 0

Re: Problém s čtením dat z COM portu (sériová komunikace)

Příspěvek od vasik006 » 31 bře 2022, 19:31

Děkuji moc, to se bude velmi hodit, protože budu přidávat další kontrolky.
Teď ještě zjistit, jak do programu informace posílat. Zkoušle jsem Serial.print("x1") například, ale takhle to nejspíš nepůjde. Samozřejmě posílané proměnné z Arduina mám taky v programu pro komunikaci s simulátorem definované akorát v bloku "PRIJIMEJ" a ne "POSILEJ". Např. tlačítko, též se stavy 0 a 1 jsem označil písmenem x.

Pokus o kód zde:

Kód: Vybrat vše

const int buttonPin = 2;   
const int ledPin =  13;      

int buttonState = 0;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
}
  
void loop() {
  buttonState = digitalRead(buttonPin);

  if (buttonState == HIGH){ 
    Serial.print("p1");
  }      
}
Definice proměnné:

Kód: Vybrat vše

[PRIJIMEJ]

x = TlacitkoPistala

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

Re: Problém s čtením dat z COM portu (sériová komunikace)

Příspěvek od AstroMiK » 31 bře 2022, 19:45

Serial.print určitě půjde, ale s tím tlačítkem je to na delší diskusi a na to teď nemám.
Musí se řešit odrušení zakmitávání a detekovat hrany. Příkaz se pak do sériové linky odešle jen při hraně.

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Google [Bot] a 15 hostů