Používáme sekvencer - semafor

Zápisník experimentátora

Oblíbeným projektem pro Arduino je řízení světelné křižovatky. V dnešním článku si takový semafor naprogramujeme. Nebudeme to dělat klasicky, ale využijeme sekvencer, pomocí kterého se tato úloha změní na velmi jednoduchou úlohu. Sekvencer jsme si programovali iv minulosti v článku o generování signálu SOS.

Nákup součástek

Na fotografiích je použito Arduino Pro Mini. To vás nelimituje, můžete použít v podstatě libovolné Arduino.

  • Arduino Pro Mini (link) - Použil jsem toto Arduino.
  • Breadboard (link) - Sem jsem zastrčil všechny součástky.
  • 2x zelená, žlutá a červená LED dioda - Barvy jsem vybral tak, aby se co nejvíce podobaly na světla na semaforu. Žlutá LED je jako náhrada za oranžovou barvu.
  • 6x rezistor 1k - Rezistor omezuje velikost proudu, který teče přes LED diodu. Protože používáme vysocesvítivé LED diody, stačí nám proud pár miliampérů.

Semafor

Náš příklad simuluje dva semafory. Na obou se nacházejí tři světla. Tři světla se starají o to, aby se auta na křižovatce nesrazily. Čili na jednom svítí zelené světlo a na druhém červené. V pravidelných intervalech se světla na semaforech vymění.

Typický semafor na Slovensku funguje následovně. Na semaforu svítí 10-20 sekund zelená barva. Ta se přepne na oranžovou a následně na červenou. Potom svítí červená barva 10-20 sekund. Současně s červenou barvou se zapne oranžová barva. Potom obě barvy zhasnou a zapne se zelená barva. Takto se to opakuje stále dokola. Na druhém semaforu jsou barvy posunuté. Vždy na jednom semaforu svítí červená barva a na druhém semaforu zelená.

Sekvencer

Sekvencery jsou velmi jednoduché nástroje. V pravidelných intervalech posílají na výstup požadovanou hodnotu. V našem případě vytvoříme sekvencer, který bude simulovat předchozí příklad. V intervalech 1 s zapne nebo vypne LED diody. Sekvencer má tu výhodu, že pokud by došlo ke změně požadavků na program, samotný program se nemusí změnit a změní se pouze sekvence.

Program

Napsal jsem tři programy. Dva slouží k otestování zapojení a třetím je samotná simulace semaforů.

sequencer_traffic_light_01

První program slouží k testování zapojení. Postupně zapne každou LED diodu. Pokud se všechny rozsvítí, máte to zapojeno správně. Zapojení jednotlivých LED diod najdete v zdrojovém textu programu.

int leds[] = {2, 3, 4, 5, 6, 7};
int step = 0;

void setup() {
  for (int i = 0; i < 6; i++)
    pinMode(leds[i], OUTPUT);
}

void loop() {
  for (int i = 0; i < 6; i++)
    digitalWrite(leds[i], i == step ? HIGH : LOW);
  step++;
  step %= 6;
  delay(1000);
}

sequencer_traffic_light_02

Druhý program slouží k testování zapojení a testování sekvenceru. Sekvencer je vytvořen ve třídě Sequencer. Má pouze dvě funkce. V konstruktoru si poznačit údaje o sekvenci a ve funkci next se pokaždé posuneme vpřed v sekvenci a podle toho nastavíme LED diodu na HIGH nebo LOW. Všimněte si, na které piny v Arduine jsou připojeny LED diody. Jsou to piny 2, 3, 4, 5, 6 a 7. Proč jsem si vybral právě tyto piny? Protože všechny tyto piny se nacházejí na portu D a mohu je ovládat jedním přiřazením hodnoty přímo na port

int leds[] = {2, 3, 4, 5, 6, 7};

//  222111xx
//  GYRGYR
const char PROGMEM sequence[] = {
  0b00000100,
  0b00001000,
  0b00010000,
  0b00100000,
  0b01000000,
  0b10000000,
};
const int sequence_length = sizeof(sequence) / sizeof(char);

class Sequencer {
    char *data;
    int len;
    int pos;

  public:
    Sequencer(char *_data, int _len)
      : data(_data), len(_len), pos(0)
    {}

    void next() {
      char b = pgm_read_byte(&data[pos]);
      PORTD = b;
      pos++;
      if (pos == len)
        pos = 0;
    }
};

Sequencer seq(sequence, sequence_length);

void setup() {
  for (int i = 0; i < 6; i++)
    pinMode(leds[i], OUTPUT);
}

void loop() {
  seq.next();
  delay(1000);
}

sequencer_traffic_light_03

Třetí program je samotná simulace světel na křižovatce. Předchozí příklad byl kvůli přehlednosti časovaný pomocí funkce delay. Nyní už můžeme náš program udělat maximálně efektivně a na časování využijeme timer1. Pomocí​ kalkulátora si nastavíme timer na frekvenci 1 Hz (každých 1000 ms) a funkci next z třídy Sequencer budeme volat z přerušení TIMER1_COMPA_vect.

int leds[] = {2, 3, 4, 5, 6, 7};

//  222111xx
//  GYRGYR
const char PROGMEM sequence[] = {
  0b10000100, // red, green
  0b10000100,
  0b10000100,
  0b10000100,
  0b10000100,
  0b10000100,
  0b10000100,
  0b10000100,
  0b10000100,
  0b10000100,
  0b01000100, // red, orange
  0b01000100,
  0b00100100, // red, red
  0b00101100, // red+orange, red
  0b00110000, // green, red
  0b00110000,
  0b00110000,
  0b00110000,
  0b00110000,
  0b00110000,
  0b00110000,
  0b00110000,
  0b00110000,
  0b00110000,
  0b00101000, // orange, red
  0b00101000,
  0b00100100, // red, red
  0b01100100, // red, red+orange
};
const int sequence_length = sizeof(sequence) / sizeof(char);

class Sequencer {
    char *data;
    int len;
    int pos;

  public:
    Sequencer(char *_data, int _len)
      : data(_data), len(_len), pos(0)
    {}

    void next() {
      char b = pgm_read_byte(&data[pos]);
      PORTD = b;
      pos++;
      if (pos == len)
        pos = 0;
    }
};

Sequencer seq(sequence, sequence_length);

void setupTimer1() {
  noInterrupts();
  // Clear registers
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;

  // 1 Hz (16000000/((15624+1)*1024))
  OCR1A = 15624;
  // CTC
  TCCR1B |= (1 << WGM12);
  // Prescaler 1024
  TCCR1B |= (1 << CS12) | (1 << CS10);
  // Output Compare Match A Interrupt Enable
  TIMSK1 |= (1 << OCIE1A);
  interrupts();
}

void setup() {
  for (int i = 0; i < 6; i++)
    pinMode(leds[i], OUTPUT);
  setupTimer1();
}

void loop() {
}

ISR(TIMER1_COMPA_vect) {
  seq.next();
}

Zdrojový kód

Zdrojový kód se nachází na serveru GitHub.


12.09.2017


Menu