Stránka 1 z 1

Arduino program

Napsal: 30 led 2022, 14:27
od remmi01
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--;
} 
}

Re: Arduino program

Napsal: 30 led 2022, 18:12
od peterple
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

Re: Arduino program

Napsal: 30 led 2022, 20:26
od AstroMiK
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);

  
  }


Re: Arduino program

Napsal: 02 úno 2022, 19:57
od remmi01
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);


  }

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


   

      
  
  

Re: Arduino program

Napsal: 02 úno 2022, 20:45
od kiRRow
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)

Re: Arduino program

Napsal: 02 úno 2022, 20:48
od AstroMiK
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.

Re: Arduino program

Napsal: 02 úno 2022, 21:08
od remmi01
Mockrát děkuju chlape. Funguje jak má. Pošli mi prosím číslo účtu, za takovýhle informace se platí!

Re: Arduino program

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

Re: Arduino program

Napsal: 02 úno 2022, 21:25
od AstroMiK
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.

Re: Arduino program

Napsal: 02 úno 2022, 21:31
od AstroMiK
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".