Arduino program

Odpovědět
remmi01
Příspěvky: 3
Registrován: 30 led 2022, 13:47
Reputation: 0

Arduino program

Příspěvek od remmi01 » 30 led 2022, 14:27

Zdravím,
ocitl jsem se ve složité situaci. Potřeboval jsem napsat program, který by hodnoty ze vstupu (1;2;3;4) vždy přepsal na výstup každého vstupu. (1->10; 2->11; 3->12; 4->13). Přepsal by je vždy však pouze po jednom, a pouze po přivedení řídícího impulzu na pin (5), časově závisle na tom jak byli hodnoty na vstup nahrány.
Příklad:
Na vstup bych tak nejprve přivedl impulz vysoké úrovně (například tlačítkem) na pin 2, ta by se zapsala do paměti a poté ještě třeba na pin 4, a 3 (které by se také zapsali do paměti). Kdybych poté přivedl impulz na řídící pin 5, nejprve by se objevil impuls vysoké úrovně na pinu 11 (výstup pinu 2), po dalším přivedení vysoké úrovně na pin 5 by se impuls převedl na pin 13, a po dalším řídícím impulzu na pin 12.
Společně se známým který v C programuje, jsme napsali kod, který ale nefunguje, a my nemůžeme najít chybu. Tento kód dělá s arduinem jen to, že poté co na pin 5 přivedu impulz vysoké úrovně, na pinu 10 se asi na dvě sekundy objeví vysoká úroveň. Žádná reakce na ostatní piny se neděje.
Prosím tedy někoho pro koho by to nebyl sebemenší problém o pomoc.

Kód: Vybrat vše

char pole[10];
int index = 0;
void vyplnPole() {
  for (int i = 0; i < 10; i++) {
  pole[i] = 0;
  }
  
 }
void serad() {
  for (int j = 0; j <= 8; j++)     {
  pole[j] = pole[j+1];
       
} 
pole[9] = 0;
}



void setup() {
  pinMode(1, INPUT);
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  pinMode(5, INPUT);   //řídící impulz
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  vyplnPole();
}




void loop() {
  if (digitalRead(1) == HIGH) {
     pole[index] = 1; 
     index++;
}
  else if (digitalRead(2) == HIGH)    {
       pole[index] = 2; 
       index++;
} 
  else if (digitalRead(3) == HIGH)    {
       pole[index] = 3; 
       index++;
} 

  else if (digitalRead(4) == HIGH)    {
       pole[index] = 4; 
       index++;
} 

if (digitalRead(5) == HIGH)    {
digitalWrite(pole[0]+9, HIGH);
delay(500);       //doba trvání impulzu na výstupu 0,5s
digitalWrite(pole[0]+9, LOW);
serad();
index--;
} 
}

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

Re: Arduino program

Příspěvek od peterple » 30 led 2022, 18:12

Nie že by sa mi to chcelo programovať. Ale aspoň poviem kde je zakopaný pes. Takže modelová situácia. Stisnem tlačítko na vstupe 1. Teda prvý if bude pravda. Čo sa bude diať.
  1. do poľa na pozíciu 0 sa da hodnota 1.
  2. index sa posunie na 1
  3. všetky ostatné vstupné if sa netestujú lebo je tam else if
  4. vstup 5 je nula takže nič
  5. loop sa ukončí.
  6. hlavná slučka arduina o jednu µs zavolá loop zase
  7. test dopadne zase true. teda sa zapiše1 do poľa na poziciu 1 index sa zase posunie
  8. toto sa opakuje bláznivou rýchlosťou asi milión zapisov sa sekundu.
  9. index sa nikde nekontroľuje na max hranicu poľa. takže sa zapisuje a zapisuje postupne celá pamäť.
  10. zaujímavé to nastane až sa dopracuje index na úroveň zásobníka. Vtedy náhodne prepíše návratovú adresu z funkcie loop. Program zablúdi niekam náhodne do pamäte programu a čo sa stane potom je vo hviezdach. Možno ako keby reset, a možno aj nie. Neviem čo sa stane keď to vbehne na začiatok bootloadera.
Riešenie problému:
  1. naštudovať ako je to s mainloop v arduine
  2. popozerať ako sa rieši snímanie tlačíkok. Sú na to príklady v samotnom prostredí. Tlačítka generujú zákmity.
  3. logovať si na serial kade sa program pohybuje a čo obsahujú premenné.
Happy coding

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

Re: Arduino program

Příspěvek od AstroMiK » 30 led 2022, 20:26

Nedodržel jsem číslování pinů a logiku spínání tlačítek, ale to už by neměl být problém upravit.

Mám to tak, že tlačítka jsou proti GND. Takže aktivní dává signál LOW.
Logika signálu se kopíruje na LED, takže aby LED svítila při LOW, musí být připojena proti Vcc.

Program si pamatuje sekvenci 20 stisků pro 4 tlačítka.
Změna velikosti bufferu je možná přes úpravu konstanty "MAX_BUFFER".
Pro čtení tlačítek využívám vnitřní registr PIND, který zjistí stav všech 4 vstupů najednou.

Odrušení zákmitů provádím přes delay(50).

V krátkosti princip:
Program v hlavní smyčce testuje změny stavu tlačítek.
Když k nějaké změně dojde (a není to uvolnění), zapíše se aktuální stav tlačítek jako bajt do pole pamet[] na pozici, na kterou ukazuje ukazatel.
Při zápisu se zvětší ukazatel do toho pole o 1.

Když se pole zaplní, zahlásí se do sériové linky "PREPLNENI BUFFERU!"

V druhé části programu se testuje stisk vyčítacího tlačítka.
Když se zjistí, že je stisknuté, vezme se nejstarší záznam z pole (index 0) a jeho jednotlivé bity se převedou na výstupní piny.
Hned potom se celý buffer (celé pole) přesype o jeden index níž (z indexu 1 se stane index 0, z indexu 2 se stane index 1 ..... až do indexu 20).
Ukazatel do pole se sníží o 1.
Když ukazatel doběhne do 0, zahlásí se "BUFFER PRAZDNY".

Dokud je vyčítací tlačítko stisknuté, program čeká ve smyčce.
Po uvolnění tlačítka se běh programu vrací do hlavní smyčky na další testování vstupních tlačítek.



Tady je video:
https://youtu.be/TfgsgVNLhCw


kód:

Kód: Vybrat vše


// Vstupy     2,  3,  4,  5   (Tlacitka proti GND. V rozepnutem stavu jsou v HIGH)
// Vystupy    9, 10, 11, 12   (LED proti Vcc. Aktivni LED jsou v '0')
// Cteci pin  6               (Tlacitko proti GND. V rozepnutem stavu je v HIGH)

#define MAX_BUFFER   20      // maximalni pocet  zapamatovatelnych stavu

byte pamet[MAX_BUFFER];      // buffer, kam se bude ukladat postupny stav vstupu
byte ukazatel;               // ukazatel do bufferu, kam se bude ukladat posledni stav

byte posledni_stav_vstupu;   // slouzi ke zjistovani zmen na vstupech 
 
//------------------------------------------
void setup(void)
  {

    pinMode(2, INPUT_PULLUP);
    pinMode(3, INPUT_PULLUP);
    pinMode(4, INPUT_PULLUP);
    pinMode(5, INPUT_PULLUP);

    pinMode(9, OUTPUT);
    pinMode(10, OUTPUT);
    pinMode(11, OUTPUT);
    pinMode(12, OUTPUT);

    pinMode(6, INPUT_PULLUP);

    Serial.begin(9600);      // Seriovy vystup jen pro debugovani


    for (byte i = 0; i < MAX_BUFFER; i++)    // vynulovani pameti (vsechny vystupy do neaktivniho HIGH)
      {
        pamet[i] = 0b11111111; 
      }

   
  }



//------------------------------------------
void loop(void)
  {
    testuj_zmeny();          // testovani, jestli doslo k nejake zmene na vstupech a pripadny zapis do bufferu
    testuj_vycitani();       // testovani, jestli prichazi impulzy na ctecim pinu a pripadne cteni bufferu a ovladani vystupu
  }


//------------------------------------------
void testuj_zmeny(void)
  {
    byte stav_vstupu = (PIND & 0b00111100);        // precteni vsech 4 vstupu najednou D2 az D5 (odpovida to bitum 2 az 5 v registru PIND)
    
    if (stav_vstupu == 0b00111100)                 // zadne tlacitko neni stisknute
      {
        posledni_stav_vstupu = stav_vstupu;        // v tomto podprogramu se nic dit nebude a normalne se vypadne
      }

    if (stav_vstupu == posledni_stav_vstupu)       // od minule nenastala zadne zmena, nebo jsou vsechna vstupni tlacitka rozepnuta
      {
        delay(50);                                 // odruseni zakmitu pred vypadnutim z podprogramu
        return;
      }


    posledni_stav_vstupu = stav_vstupu;            // zapamatovat si posledni stisknute tlacitko (aby se v dalsi smycce tento stav ignoroval)

    pamet[ukazatel] = stav_vstupu;
    ukazatel ++;
    if (ukazatel > 20)
      {
        Serial.println("PREPLNENI BUFFERU!");
        ukazatel = 20;
      }   
    delay(50);                                     // odruseni zakmitu pri uvolnovani vstupnich tlacitek
  }





//------------------------------------------
void testuj_vycitani(void)
  {
    if (digitalRead(6) == LOW)                  // vycitaci tlacitko sepnuto
      {
        digitalWrite( 9,bitRead(pamet[0],2));   // D2 se prepisuje na D9 
        digitalWrite(10,bitRead(pamet[0],3));   // D3 se prepisuje na D10
        digitalWrite(11,bitRead(pamet[0],4));   // D4 se prepisuje na D11
        digitalWrite(12,bitRead(pamet[0],5));   // D5 se prepisuje na D12


        for (byte i = 1 ; i < MAX_BUFFER ; i++)  // posunuti celeho bufferu o jednu polozku dolu
          {
            pamet[i-1] = pamet[i];
          }

        if (ukazatel > 0)    ukazatel --;        // ukazatel do pameti se o 1 snizi (nesmi ale podlezt pod 0)
        else                 Serial.println("BUFFER PRAZDNY");
      }

    while (digitalRead(6) == LOW)                  // dokud je vycitaci tlacitko stisknute
      {
        delay(10);                                 // program stoji v teto smycce
      }
    delay(50);                                     // pripadne odruseni zakmitu

    digitalWrite( 9,HIGH);          // vsechny LED zhasnout
    digitalWrite(10,HIGH);
    digitalWrite(11,HIGH);
    digitalWrite(12,HIGH);

  
  }


remmi01
Příspěvky: 3
Registrován: 30 led 2022, 13:47
Reputation: 0

Re: Arduino program

Příspěvek od remmi01 » 02 úno 2022, 19:57

Zdravím, dnes jsem se konečně dostal zpět k Arduinu, a to mě přivádí opět k sem na fórum. Mockrát Vám děkuji za zaslaný program, který jsem si dovolil ještě trochu poupravit. Koupil jsem si k arduinu totiž ještě lcd displej (konkrétně tento: https://dratek.cz/arduino/1570-iic-i2c- ... modry.html ) a snažil jsem se program dopsat tak, aby se na displej vždy zapsal zápis vstupní hodnoty do paměti, a po přivedení řídícího impulzu (6) se vždy aktuálně přehraný impulz na výstup z displeje vymazal. To se mi však povedlo pouze u jednoho vstupu (5). Ostatní vstupy na displej vždy zapíší pouze první impulz a ostatní poté ignorují, a to i přes to že jsou napsány úplně stejně. Nemůžu přijít na to kde jsem udělal chybu, ve Vašem kódu jsem se snažil "hrabat" co nejméně, k tomu co jsem tam ale změnil, nebo přidal jsem vždy napsal komentář.

Kód: Vybrat vše

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

// Vstupy     2,  3,  4,  5   (Tlacitka proti GND. V rozepnutem stavu jsou v HIGH)
// Vystupy    9, 10, 11, 12   (LED proti Vcc. Aktivni LED jsou v '0')
// Cteci pin  6               (Tlacitko proti GND. V rozepnutem stavu je v HIGH)

#define MAX_BUFFER   20      // maximalni pocet  zapamatovatelnych stavu


byte pamet[MAX_BUFFER];      // buffer, kam se bude ukladat postupny stav vstupu
byte ukazatel;               // ukazatel do bufferu, kam se bude ukladat posledni stav

byte posledni_stav_vstupu;   // slouzi ke zjistovani zmen na vstupech 

 
//------------------------------------------
void setup(void)
  {

    pinMode(2, INPUT_PULLUP);
    pinMode(3, INPUT_PULLUP);
    pinMode(4, INPUT_PULLUP);
    pinMode(5, INPUT_PULLUP);

    pinMode(9, OUTPUT);
    pinMode(10, OUTPUT);
    pinMode(11, OUTPUT);
    pinMode(12, OUTPUT);

    pinMode(6, INPUT_PULLUP);

    pinMode(13, INPUT);     //jen pro smazání hodnot lcd displeje, slouží jako podmínka 
    
    Serial.begin(9600);      // Seriovy vystup jen pro debugovani

     lcd.init();
        lcd.backlight();
        lcd.setCursor(0, 0);
        lcd.print("-ZADEJ HODNOTY-");

       

    for (byte i = 0; i < MAX_BUFFER; i++)    // vynulovani pameti (vsechny vystupy do neaktivniho HIGH)
      {
        pamet[i] = 0b11111111; 
      }

  }



//------------------------------------------
void loop(void)
  {
    testuj_zmeny();          // testovani, jestli doslo k nejake zmene na vstupech a pripadny zapis do bufferu
    testuj_vycitani();       // testovani, jestli prichazi impulzy na ctecim pinu a pripadne cteni bufferu a ovladani vystupu


      
  }


//------------------------------------------
void testuj_zmeny(void)
  {
    byte stav_vstupu = (PIND & 0b00111100);        // precteni vsech 4 vstupu najednou D2 az D5 (odpovida to bitum 2 az 5 v registru PIND)
    
    if (stav_vstupu == 0b00111100)                 // zadne tlacitko neni stisknute
      {
        posledni_stav_vstupu = stav_vstupu;        // v tomto podprogramu se nic dit nebude a normalne se vypadne
      }

    if (stav_vstupu == posledni_stav_vstupu)       // od minule nenastala zadne zmena, nebo jsou vsechna vstupni tlacitka rozepnuta
      {
        delay(50);                                 // odruseni zakmitu pred vypadnutim z podprogramu
        return;
      }


    posledni_stav_vstupu = stav_vstupu;            // zapamatovat si posledni stisknute tlacitko (aby se v dalsi smycce tento stav ignoroval)

    pamet[ukazatel] = stav_vstupu;
    ukazatel ++;
    if (ukazatel > 20)                                // tady jsem pouze prepsal aby se zprava o preplneni nezobrazovala v konzoli ale na displeji
      {
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("-max 20 hodnot-");
        lcd.setCursor(0, 1);
        lcd.print("reset nebo start");
        ukazatel = 20;
      }   
    delay(50);                                     // odruseni zakmitu pri uvolnovani vstupnich tlacitek
     
   if (digitalRead(2) == LOW ||          // toto if pouze z displeje smaze " -ZADEJ HODNOTY- " po zadání první hodnoty na nektery ze vstupu
       digitalRead(3) == LOW || 
       digitalRead(4) == LOW || 
       digitalRead(5) == LOW &&
       digitalRead(13) == LOW) {
    digitalWrite(13, HIGH);
    lcd.clear();
     }

      
    if (digitalRead(2) == LOW){       // na displej se zapise pouze jednou, pote uz displej na dalsi zapisovani nereaguje, to stejne na vstupech 3,4 
                                                   // tady je ten problem
    lcd.print("2!");
    
    }

     if (digitalRead(3) == LOW){
    lcd.print("3!");

    }

     if (digitalRead(4) == LOW){            
    lcd.print("4!");

    }

     if (digitalRead(5) == LOW){             // toto je jedine if ze seznamu ktere mi funguje jak ma, zapisuje všechny impulzy na displej
    lcd.print("5!");

    }
  

    
  }





//------------------------------------------
void testuj_vycitani(void)
  {
    if (digitalRead(6) == LOW)                  // vycitaci tlacitko sepnuto
      {
        digitalWrite( 9,bitRead(pamet[0],2));   // D2 se prepisuje na D9 
        digitalWrite(10,bitRead(pamet[0],3));   // D3 se prepisuje na D10
        digitalWrite(11,bitRead(pamet[0],4));   // D4 se prepisuje na D11
        digitalWrite(12,bitRead(pamet[0],5));   // D5 se prepisuje na D12
        lcd.scrollDisplayLeft();                         // posune hodnoty na displeji o jedno doleva, tim padem se aktualne prehrany impulz z displeje vymaze


        for (byte i = 1 ; i < MAX_BUFFER ; i++)  // posunuti celeho bufferu o jednu polozku dolu
          {
            pamet[i-1] = pamet[i];
          }

        if (ukazatel > 0)    ukazatel --;        // ukazatel do pameti se o 1 snizi (nesmi ale podlezt pod 0)
        else                 
                 Serial.println("BUFFER PRAZDNY");
      }

    while (digitalRead(6) == LOW)                  // dokud je vycitaci tlacitko stisknute
      {
        delay(10);                                 // program stoji v teto smycce
      }
    delay(50);                                     // pripadne odruseni zakmitu

    digitalWrite( 9,HIGH);          // vsechny LED zhasnout
    digitalWrite(10,HIGH);
    digitalWrite(11,HIGH);
    digitalWrite(12,HIGH);


  }

  //------------------------------------------


   

      
  
  

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

Re: Arduino program

Příspěvek od kiRRow » 02 úno 2022, 20:45

Chybka je v tom, že pracuješ s digitalRead o 50milivteřin později, než dojde k jeho přečtení tady

Kód: Vybrat vše

byte stav_vstupu = (PIND & 0b00111100);        // precteni vsech 4 vstupu najednou D2 az D5 (odpovida to bitum 2 az 5 v registru PIND)

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

Re: Arduino program

Příspěvek od AstroMiK » 02 úno 2022, 20:48

Chyba je v tý velký mazací podmínce. Je třeba tam dodělat závorky.
Pak taky pozor na pin D13. Na některých Arduinech je tam připojená vnitřní LED, která udržuje stav na LOW.
Já jsem to pro testování musel předělat na A0 - protože na D13 mi to nefungovalo ani pro ten vstup D5.
Přílohy
podminka.gif

remmi01
Příspěvky: 3
Registrován: 30 led 2022, 13:47
Reputation: 0

Re: Arduino program

Příspěvek od remmi01 » 02 úno 2022, 21:08

Mockrát děkuju chlape. Funguje jak má. Pošli mi prosím číslo účtu, za takovýhle informace se platí!

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

Re: Arduino program

Příspěvek od kiRRow » 02 úno 2022, 21:17

AstroMiK píše:
02 úno 2022, 20:48
Chyba je v tý velký mazací podmínce.
WOW tak toho jsem si absolutně nevšimnul

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

Re: Arduino program

Příspěvek od AstroMiK » 02 úno 2022, 21:25

remmi01 píše:
02 úno 2022, 21:08
... za takovýhle informace se platí!
Tohle byla jen rozcvička. Nic za to nechci ...

Koukám, že tam mám možná ještě chybu s velikostí toho bufferu.
Když je nastavený na velikost 20, tak mají jeho položky indexy 0 až 19. Takže by se nikdy nemělo stát, že bude mít 'ukazatel' hodnotu 20.
Tím už by se četlo nebo zapisovalo někam mimo.

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

Re: Arduino program

Příspěvek od AstroMiK » 02 úno 2022, 21:31

kiRRow píše:
02 úno 2022, 21:17
WOW tak toho jsem si absolutně nevšimnul
... ale jinak máš pravdu v tom, že číst jednotlivé vstupy 50ms po tom, co byly přečtené a uložené do proměnné je trochu zbytečné.
Já už jsem to nechtěl nějak komplikovat, tak jsem to nechal v tom stavu, jak to vymyslel "remmi01".

Odpovědět

Kdo je online

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