Arduino Nano: počítadlo otáček s děličkou

Diskuze a poradna o programátorech a programování různých obvodů

Moderátor: Moderátoři

Zpráva
Autor
Uživatelský avatar
Roman-W
Příspěvky: 51
Registrován: 29 kvě 2013, 00:00

Arduino Nano: počítadlo otáček s děličkou

#1 Příspěvek od Roman-W »

Zdravím sehnal jsem si na webu tento kod že ho upravím a nějak si nevím rady jak zakomponovat dělení vstupního signálu optozávory. na vřetenu mam kroužek s 8 výřezy viz příloha. Zapojení je defakto stejné jako na webu jen mam zapojený A0 (výstup z optozávory) a A2 (reset)

https://github.com/embeddedlab786/Count ... 219_Eeprom

Do budoucna plánuji dvě opto závory vedle sebe aby to poznalo směr otáčení. Abych mohl při přejetí požadovaného počtu zavitů odmotat na zpětný chod ale to bude další komplikace v programování
Přílohy
kolečka.jpg
kolečka.jpg
Uživatelský avatar
bum
Příspěvky: 290
Registrován: 04 zář 2011, 00:00
Kontaktovat uživatele:

#2 Příspěvek od bum »

Uvedený program co jste uvedl je ukázkový pro zápis hodnot do paměti zadaných tlačítky. Na čítání pulsů použijte vstup kde je možné načítat pulsy při přerušení použijte třeba vstup D2 což je přerušení 0, kde použijete vzorec co máte pro ten kotouč s osmi výřezy. Než takto upravovat tento program je lepší si napsat nový a místo uvedeného displeje použít obyčejný LCD displej ať 16-místný nebo 20-místný buď jednořádkový nebo s více řádky. Také jsem si kdysi stavěl navíječku s programem pro PC, schéma elektroniky, program s popisem je na webu tam se zadal počet závitů a po dosažení zadaného počtu se automaticky vypnul motorek.
To rozlišení směru otáček je možné řešit stejně jako se řeší u rotačního enkodéru. Pokud se mi namotal větší počet závitů tak jsem odmotání řešil přehozením směru otáčení a odpočtem závitů.
Uživatelský avatar
Celeron
Příspěvky: 20508
Registrován: 02 dub 2011, 00:00
Bydliště: Nový Bydžov

#3 Příspěvek od Celeron »

Moc složitý, na co je u počítadla navíječky potřeba EEPROM? Jako že to navíjení zastavíš a druhej den budeš pokračovat? Navíc to vypadá, že s každou změnou nahoru nebo dolů se zapisuje do EEPROM, která má technicky né moc velký počet zápisů a pak odejde.
No a upravit to na dělení osmi bude potřeba další počítadlo, do kterého se bude posílat těch 8 impulzů za otáčku a když přijde devátý, tak se přičte 1 v D1 a D0 vynuluje. On se totiž nezobrazuje obsah počítacího registru ale každý řád displeje má svý počítadlo 0-9 a když se napočítá na jednotkách víc než 9, tak se přičte 1 na desítkách a tak dále. Prostě to tupě kopíruje klasický mechanický počítadlo.

Tady to máš upravený, zkus to a dej vědět, jestli to chodí co otáčka, to přičtení 1 na řádu jednotek. Možná bude potřeba softwarový debounce (odrušení zákmitů) nebo detekce hrany místo stavu, kdyby to náhodně přičítalo blbě, dej vědět.

Kód: Vybrat vše

#include <EEPROM.h>

#define bt_up     A0
#define bt_reset  A2
#define buzzer    13

#define MAX7219_Clock        2
#define MAX7219_Chip_Select  3
#define MAX7219_Data_IN      4

long d1=0, d2=0, d3=0, d4=0, d5=0, d6=0, d7=0, d8=0;

int flag1=0, timer=0;
int pulseCounter = 0;  // Počet pulzů ze snímače (každých 8 = 1 otáčka)

void setup() {
  pinMode(bt_up,    INPUT_PULLUP);
  pinMode(bt_reset, INPUT_PULLUP);
  pinMode(buzzer,   OUTPUT);

  pinMode(MAX7219_Data_IN, OUTPUT);
  pinMode(MAX7219_Chip_Select, OUTPUT);
  pinMode(MAX7219_Clock, OUTPUT);
  digitalWrite(MAX7219_Clock, HIGH);

  delay(200);

  // Nastavení MAX7219
  shift(0x0f, 0x00); // test mode off
  shift(0x0c, 0x01); // normal operation
  shift(0x0b, 0x07); // scan limit 0–7
  shift(0x0a, 0x0f); // brightness max
  shift(0x09, 0xff); // decode B mode for all digits

  if (EEPROM.read(0) != 0) {
    WriteEeprom();
    EEPROM.write(0, 0);
  }

  ReadEeprom();
}

void loop() {
  // Zpracování pulzů z čidla (8 pulzů = 1 otáčka)
  if (digitalRead(bt_up) == LOW) {
    if (flag1 == 0) {
      flag1 = 1;
      pulseCounter++;
      if (pulseCounter >= 8) {
        pulseCounter = 0;

        d1++;
        if (d1 > 9) { d1 = 0; d2++; }
        if (d2 > 9) { d2 = 0; d3++; }
        if (d3 > 9) { d3 = 0; d4++; }
        if (d4 > 9) { d4 = 0; d5++; }
        if (d5 > 9) { d5 = 0; d6++; }
        if (d6 > 9) { d6 = 0; d7++; }
        if (d7 > 9) { d7 = 0; d8++; }
        if (d8 > 9) { d8 = 0; }

        WriteEeprom();
      }
    }
  } else {
    flag1 = 0;
  }

  // RESET
  if (digitalRead(bt_reset) == LOW) {
    digitalWrite(buzzer, HIGH);
    if (timer < 200) timer++;
    if (timer == 200) {
      d1 = d2 = d3 = d4 = d5 = d6 = d7 = d8 = 0;
      pulseCounter = 0;
      WriteEeprom();
    }
  } else {
    digitalWrite(buzzer, LOW);
    timer = 0;
  }

  // Zobrazení na displeji
  shift(0x01, d1);  // nejnižší řád (vpravo)
  shift(0x02, d2);
  shift(0x03, d3);
  shift(0x04, d4);
  shift(0x05, d5);
  shift(0x06, d6);
  shift(0x07, d7);
  shift(0x08, d8);  // nejvyšší řád (vlevo)
  delay(10);
}

void ReadEeprom() {
  d1 = EEPROM.read(1);
  d2 = EEPROM.read(2);
  d3 = EEPROM.read(3);
  d4 = EEPROM.read(4);
  d5 = EEPROM.read(5);
  d6 = EEPROM.read(6);
  d7 = EEPROM.read(7);
  d8 = EEPROM.read(8);
}

void WriteEeprom() {
  EEPROM.write(1, d1);
  EEPROM.write(2, d2);
  EEPROM.write(3, d3);
  EEPROM.write(4, d4);
  EEPROM.write(5, d5);
  EEPROM.write(6, d6);
  EEPROM.write(7, d7);
  EEPROM.write(8, d8);
}

void shift(byte send_to_address, byte send_this_data) {
  digitalWrite(MAX7219_Chip_Select, LOW);
  shiftOut(MAX7219_Data_IN, MAX7219_Clock, MSBFIRST, send_to_address);
  shiftOut(MAX7219_Data_IN, MAX7219_Clock, MSBFIRST, send_this_data);
  digitalWrite(MAX7219_Chip_Select, HIGH);
}
Na ten směr se dvěma snímačema můžeš použít již hotový knihovny pro n-codéry.
Jirka

Proč mi nemůže všechno chodit hned ?!!
Uživatelský avatar
samec
Příspěvky: 6670
Registrován: 19 pro 2017, 00:00

#4 Příspěvek od samec »

Čo za obludnosť? Autor toho kódu by mal radše sadiť zemiaky, lebo programovaniu nerozumie. Niečo tak primitívne sa dá inteligentne napísať na desať riadkov.

Zahoď ten kód a napíš si vlastný.
Alebo ak nevieš napísať vlastný program, tak zahoď aj arduino a kúp si hotový čítač.
https://vi.aliexpress.com/item/1005005883201203.html
Uživatelský avatar
Michal22
Příspěvky: 8229
Registrován: 28 bře 2012, 00:00
Bydliště: Brno

#5 Příspěvek od Michal22 »

Samče, nějak jsem si vzpomněl, že už po několikáté uvádíš, že někdo dělá něco špatně, a že ty to umíš podstatně líp.
Tak byl bys tě dobroty a předvedl nám někdy svoje dovednosti v reálu?
Diky
Civilizace založená na oboustranné lepící pásce nemůže dobře skončit...
I kdyby se z tebe jednou stal král, neodsuzuj lidi, kteří ti nebudou provolávat slávu- raději se zeptej sám sebe, proč tomu tak není...
Uživatelský avatar
samec
Příspěvky: 6670
Registrován: 19 pro 2017, 00:00

#6 Příspěvek od samec »

Ak nevidíš, koľko chýb je v použití toho kódu a v tom kóde samotnom, tak si najprv naštuduj základy programovania a potom sa vyjadruj.

Až bude zadanie dodefinované, že na čom sa má počítadlo zobrazovať, či sa má ukladať do EPROM, prípadne ako sú optočleny rozmiestnené, tak možno program rozvinúť...

Kód: Vybrat vše

#define vstup1 A0 //vstup z 1. optozavory

static char pocet_pulsu = 0;
int pocet_otacek = 0;

void setup() {
 pinMode(vtup1, INPUT_PULLUP);
 attachInterrupt(digitalPinToInterrupt(vstup1), nahoru, RISING);
}

void loop() {
 if(pocet_pulsu >= 8) {
  pocet_pulsu -= 8;
  pocet_otacek++;
 }

 //todo: zobraz pocet otacek ...
}

void nahoru() {  //interrupt
 pocet_pulsu++;
}
Mimochodom, na obojsmerné počítanie by boli vhodnejšie kotúčiky s medzerami rovnako širokými, ako má plná časť medzi nimi.
Uživatelský avatar
lesana87
Příspěvky: 4395
Registrován: 20 zář 2014, 00:00

#7 Příspěvek od lesana87 »

Snímat stav pomalého vstupu přes přerušení je cesta k chytání kdejakého rušení a zákmitů, zvláště po doplnění snímače na kvadraturní kodér. Myslím si, že čistější je vstup(y) samplovat vhodnou frekvencí od časovače.
Jinak samče, když jseš u toho správnýho programování, určitě jsi slyšel o race condition, jseš si jistej, že pocet_pulsu -= 8; je atomická operace?
Uživatelský avatar
samec
Příspěvky: 6670
Registrován: 19 pro 2017, 00:00

#8 Příspěvek od samec »

lesana87 píše:Snímat stav pomalého vstupu přes přerušení je cesta k chytání kdejakého rušení a zákmitů, zvláště po doplnění snímače na kvadraturní kodér. Myslím si, že čistější je vstup(y) samplovat vhodnou frekvencí od časovače.
Jak pomalý je podĺa teba pomalý vstup? Koľko sekúnd bude trvať jeden ten výsek na kotúčiku pri rýchlosti otáčania napríklad 1200 rpm?
lesana87 píše:Jinak samče, když jseš u toho správnýho programování, určitě jsi slyšel o race condition, jseš si jistej, že pocet_pulsu -= 8; je atomická operace?
Máš pravdu.

Kód: Vybrat vše

#define vstup1 A0 //vstup z 1. optozavory

static long pocet_pulsu = 0;
long pocet_otacek = 0;

void setup() {
 pinMode(vtup1, INPUT_PULLUP);
 attachInterrupt(digitalPinToInterrupt(vstup1), nahoru, RISING);
}

void loop() {
 pocet_otacek = pocet_pulsu / 8;

 //todo: zobraz pocet otacek ...
}

void nahoru() {  //interrupt
 pocet_pulsu++;
}
Uživatelský avatar
nostalcomp
Příspěvky: 169
Registrován: 09 lis 2022, 00:00

#9 Příspěvek od nostalcomp »

No, to už je lepší. Ta konstrukce s tím IFem se ti opravdu hodně nepovedla. Já bych obě verze napsal asi takto:

Kód: Vybrat vše

// pulsy = BYTE
// otacky = WORD

void nahoru1 ()
{
pulsy++;
otacky += (pulsy == 8);
pulsy *=  (pulsy < 8);
}

//nebo:

// pulsy = UNSIGNED LONG
// otacky = WORD

void nahoru2 ()
{
pulsy++;
otacky = pulsy >> 3;
}

Uživatelský avatar
lesana87
Příspěvky: 4395
Registrován: 20 zář 2014, 00:00

#10 Příspěvek od lesana87 »

samec píše:Jak pomalý je podĺa teba pomalý vstup? Koľko sekúnd bude trvať jeden ten výsek na kotúčiku pri rýchlosti otáčania napríklad 1200 rpm?
To je 160 Hz, to je pomalý vstup.
Přijde mi zbytečné, dělat na navíječce 8 zubů na otáčku, k čemu je dobrá osmina závitu? Já mám na soustruhu 2 zuby na otáčku snímané kvadraturně dvojicí optočlenů a je to dostatečné i pro měření ot/min. Do 3000 ot/min stačí samplovat 1kHz, to jsou také pomalé vstupy. Zároveň tím časovačem multiplexuju LED displej.
Uživatelský avatar
samec
Příspěvky: 6670
Registrován: 19 pro 2017, 00:00

#11 Příspěvek od samec »

1/160 sú vzdialenosti medzi pulzami. Samotné pulzy (medzery v disku) sú 6x kratšie. Takže pulz má dlžku cca 1ms. Pri dvojnásobnej rýchlosti 500µs. Ak to navzorkuješ cez časovač, aj tak potrebuješ prerušenie. Problém s atomárnymi inštrukciami zostáva, rušenie tiež. A čo ak sa kotúčik zastaví presne hranou v optozávore? To ti ani neuronka nepomôže, pokiaľ to nebude odolné už na úrovni senzora.

Mal som radšej ostať pri konštatovaní, že ten pôvodný nalinkovaný softvér je blbosť a viac sa k tomu nevyjadrovať.

Jeden pulz na otočku je málo, lebo to by znamenalo chybu jedného závitu v závislosti od počiatočnej polohy kotúčika voči polohe začiatku vinutia a zrejme približnej polohe začiatku a konca navíjania.
Uživatelský avatar
HF_Tech
Příspěvky: 2365
Registrován: 25 dub 2022, 00:00

#12 Příspěvek od HF_Tech »

Proto je lepší použít ten kvadraturní enkodér. U něj si naprogramuješ zámek, že se vyhodnotí pouze první hrana a pak se čeká až na změnu na druhém vstupu. Když se ještě dodělá obsluha od všech vstupů a hran, tak stačí na snímání úplně primitivní půlkolečko 8-)
Uživatelský avatar
Celeron
Příspěvky: 20508
Registrován: 02 dub 2011, 00:00
Bydliště: Nový Bydžov

#13 Příspěvek od Celeron »

Hodně tady mudrujte, tazatel chtěl upravit původní program aby jen dělil osmi.
Samo že se to dá napsat elegantněji, jeden kotouček 8 výřezů, dva fototrandy.
To načítání pulzů mám v počítadle odzkoušený s magnetickým n-codérem 100 pulzů na otáčku. U magneťáku se nemusí vůbec řešit zákmity co mají fototranzistory.
U tohodle je jen 8 zářezů co generují kvadraturní signál (A, B, 90° fázový posun). Rozklad registru counter na řády jsem nikdy nezkoušel ale našel jsem to na netu. Zapojení stejný jako původní. Bez záruky, nemám moc času se v tom rejpat. Asi by bylo lepší přepojit to na využití přerušení a došlechtit tam ochranu proti zákmitům.

Kód: Vybrat vše

#include <Arduino.h>

#define SIG_A A0
#define SIG_B A1
#define RESET_BTN A2
#define BUZZER 13

#define MAX7219_DIN   4
#define MAX7219_CLK   2
#define MAX7219_CS    3

long counter = 0;
bool lastA = 1;
bool lastB = 1;
int resetTimer = 0;

void setup() {
  pinMode(SIG_A, INPUT_PULLUP);
  pinMode(SIG_B, INPUT_PULLUP);
  pinMode(RESET_BTN, INPUT_PULLUP);
  pinMode(BUZZER, OUTPUT);

  pinMode(MAX7219_DIN, OUTPUT);
  pinMode(MAX7219_CLK, OUTPUT);
  pinMode(MAX7219_CS, OUTPUT);

  digitalWrite(MAX7219_CLK, HIGH);
  delay(100);

  initMAX7219();
}

void loop() {
  // Čtení signálu A a B
  bool A = digitalRead(SIG_A);
  bool B = digitalRead(SIG_B);

  if (A != lastA) {
    if (A == LOW) {
      if (B == HIGH) counter++;  // směr 1
      else counter--;            // směr 2
    }
    lastA = A;
  }

  // RESET držení
  if (digitalRead(RESET_BTN) == LOW) {
    digitalWrite(BUZZER, HIGH);
    if (++resetTimer > 200) {
      counter = 0;
    }
  } else {
    digitalWrite(BUZZER, LOW);
    resetTimer = 0;
  }

  displayNumber(counter/8);
  delay(5); // stabilizace
}
// inic Maxe
void initMAX7219() {
  sendToMAX7219(0x0F, 0x00); // Test off
  sendToMAX7219(0x0C, 0x01); // Shutdown = normal
  sendToMAX7219(0x0B, 0x07); // Scan limit = 8 digits
  sendToMAX7219(0x0A, 0x0F); // Brightness max
  sendToMAX7219(0x09, 0xFF); // Decode all digits
}
// plnění Maxe
void sendToMAX7219(byte address, byte data) {
  digitalWrite(MAX7219_CS, LOW);
  shiftOut(MAX7219_DIN, MAX7219_CLK, MSBFIRST, address);
  shiftOut(MAX7219_DIN, MAX7219_CLK, MSBFIRST, data);
  digitalWrite(MAX7219_CS, HIGH);
}
// rozklad pro Maxe
void displayNumber(long value) {
  unsigned long absVal = abs(value);
  for (int i = 1; i <= 8; i++) {
    byte digit = absVal % 10;
    sendToMAX7219(i, digit);
    absVal /= 10;
  }
}
Jirka

Proč mi nemůže všechno chodit hned ?!!
Uživatelský avatar
lesana87
Příspěvky: 4395
Registrován: 20 zář 2014, 00:00

#14 Příspěvek od lesana87 »

samec píše:Ak to navzorkuješ cez časovač, aj tak potrebuješ prerušenie. Problém s atomárnymi inštrukciami zostáva, rušenie tiež. A čo ak sa kotúčik zastaví presne hranou v optozávore? To ti ani neuronka nepomôže, pokiaľ to nebude odolné už na úrovni senzora.
S tím si právě ten samplovaný kvadraturní kodér poradí s prstem v nose, klidně se to může třepat na hraně, jak chce a generovat to třeba 100ns pulsy, to přes přerušení od hrany nepochytáš ani náhodou. A dva zuby na otáčku jsou 8 impulsů na otáčku, stejně jako tady.
Uživatelský avatar
samec
Příspěvky: 6670
Registrován: 19 pro 2017, 00:00

#15 Příspěvek od samec »

Celeron píše:Rozklad registru counter na řády jsem nikdy nezkoušel ale našel jsem to na netu.

Kód: Vybrat vše

...
// rozklad pro Maxe
void displayNumber(long value) {
  unsigned long absVal = abs(value);
  for (int i = 1; i <= 8; i++) {
    byte digit = absVal % 10;
    sendToMAX7219(i, digit);
    absVal /= 10;
  }
}
Ja by som to nehľadal. Rovno by som napísal

Kód: Vybrat vše

char dekadicky[8];

sprintf(dekadicky,"%d",value");
for(char i=0; i <=8; i++) sendToMAX7219(i, dekadicky[i] - '0');  // ;-)
Odpovědět

Zpět na „Programování PIC, ATMEL, EEPROM a dalších obvodů“