Lepšia simulácia svätojánskej mušky

Zápisník experimentátora

Hierarchy: Svätojánska muška v pohári

V druhom pokračovaní simulátora som urobil niekoľko zmien. Rozšíril som počet LED diód na 16 a spomalil som blikanie mušiek. Sprehľadnil som kód, zmenil som štruktúru na triedu a vylepšil vypisovanie ladiacich informácií, ktoré teraz možno zapnúť alebo vypnúť.

Hardvér

Budeme potrebovať nasledovné súčiastky:

  • Arduino UNO - Ja vo videu používam Arduino Pro Mini a programované je v IDE 1.6.7.
  • 2x 74HC595 - Posuvný register. Používam vo videu moju dosku, ktorá je určená do skúšobného poľa.
  • Sadu 16x LED s príslušným rezistorom minimálne 330R - Používam moju dosku, ktorá je určená do skúšobného poľa.

16 LED diód

Oproti predchádzajúcej verzii programu som zvýšil počet LED na dvojnásobok. Dvojnásobné množstvo mušiek spôsobuje, že ich naraz bliká viac. Vyzerá to lepšie. Dvojnásobné množstvo diód si vyžiadalo pridanie ďalšieho posuvného registra 74HC595. Tie sa dajú pohodlne reťaziť do takých dĺžok, ako práve potrebujeme.

V samotnom programe si to preto vyžiadalo iba drobné úpravy. Stačí nastavovať iba premennú numRegisters na ten počet posuvných registrov, ktorý používame. Použitie const modifikátorov umožňuje, aby kompilátor urobil všetky výpočty a nebolo ich potrebné robiť počas behu programu. Vďaka tomu je možné použiť definíciu poľa mušiek v tvare firefly f[ffCount];. Konštanta ffCount je vypočítaná počas kompilácie a nám stačí upraviť všetky miesta v programe, ktoré pracujú s počtom LED diód na túto konštatntnú hodnotu.

const int numRegisters = 2;
const int ffCount = numRegisters*8;

firefly f[ffCount];

void loop() {
  mil=millis();
  for(int i=0;i<ffCount;i++)
  {
  ...
  }

Spomalenie blikania

Spomalenie blikania na polovicu robí to isté ako spomalenie videa. Máte viac času na pozretie animácie.

Prečo trieda

V predchádzajúcej verzii programu bola firefly definovaná ako struct. Teraz je definovaná ako class. Aký to má zmysel? Umožnilo mi to presunúť inicializáciu každého objektu do konštruktora. Preto sa skrátila deklarácia poľa objektov firefly v hlavnom programe na minimum. A keby bolo potrebné, v konštruktore môžeme porobiť ďalšie výpočty. Tiež teraz môžeme podľa potreby zapúzdrovať členské premenné a funkcie triedy do public:, private: alebo protected:, aj keď v tomto konkrétnom prípade je všetko nastavené ako public:.

class firefly
{
public:  
  ffstate state;
  const unsigned char *pattern;
  int pos;
  int length;
  long tired;
  int repeat;

  firefly() :
    state(ffIdle), pattern(NULL), pos(0), length(0),
    tired(0), repeat(0)
    {}
};

Vypisovanie ladiacich informácií

Pretože v IDE Arduina nemôžeme ladiť program v debuggeri, ostáva nám na bežné ladenie iba sériový port. Tam si môžeme vypisovať informácie, aké nás zaujímajú. Platíme za to ale veľkosťou programu. A keď je program hotový, obvykle už tieto informácie nebudeme potrebovať. Ako sa s týmto problémom vysporiadať? Jedno z možných riešení je použité v tomto programe.

Všetky ladiace výpisy sú presunuté do súboru debug.h. Jeho obsah v skrátenej podobe vyzerá takto. Použitie príkazov preprocesora #ifdef, #else a #endif nám umožnilo vytvoriť dva bloky v kóde, ktoré možno medzi sebou zamieňať na základe definície makra DEBUG_PRINT. Ak je definované, ladiace informácie sa odosielajú na sériový port. Ak nie je definované, neodosiela sa nič. Je to vďaka tomu, že v druhom bloku sú telá funkcií nahradené iba formálne správnymi definíciami makier, ktoré nič nerobia. Čiže kompilátor nebude protestovať, lebo formálne je z hľadiska hlavného programu všetko rovnaké v oboch prípadoch.

C++ kompilátor je natoľko inteligentný, aby z kódu vyhodil všetko nepotrebné a výsledkom čoho by boli aj tak len nič nerobiace inštrukcie.

#ifdef DEBUG_PRINT

void initDebug()
{
Serial.begin(9600);
}

void printActive(int i, int r, long mil)
{
...
}

void printTired(int i)
{
...
}

void printIdle(int i, long mil)
{
...
}

#else

#define initDebug()
#define printActive(i, r, mil)
#define printTired(i)
#define printIdle(i, mil)

#endif

Hlavný program potom formálne nevidí rozdiel a v prípade definície makra DEBUG_PRINT pridá ladiace výpisy a v opačnom prípade všetko nepotrebné ignoruje. Za zmienku ešte stojí obalenie príkazu ShiftPWM.PrintInterruptLoad();.Je to tam preto, lebo pri pohľade na jej zdrojový kód uvidíte aj v tej funkcii vypisovanie na sériový port.

#define DEBUG_PRINT
#include "debug.h"

void setup() {
  // debug output
  initDebug();

  // ShiftPWM
  ...
  #ifdef DEBUG_PRINT
  ShiftPWM.PrintInterruptLoad();
  #endif

...
}

void loop() {
...

printActive(i,r,mil);
...
}

Vďaka týmto úprvám vieme trochu skrátiť výsledný program a tak ho dostať napríklad aj do mikrokontroléra s menšou pamäťou. Konkrétne v tomto prípade sme získali niekoľko kb voľného miesta navyše.

Video

Vo videu je vidno ako bliká 16 LED.

Čo ďalej

Teraz už len treba navrhnúť výslednú dosku, dať ju vyrobiť a nainštalovať do skleného pohára, aby sa z experimentu stalo umelecké dielo.



Download
  • 74HC595 - Datasheet 74HC595 - 8-bit shift registers with 3-state output registers
  • Firefly Sketch v. 2 - Better Firefly Simulator

01.02.2016


Menu