Gestione semaforo
- Una classe Timer4 con due registri
- Una classe LSS (Lanterna Semaforica Stradale)
- Controllo dei led attraverso shitf register (74595)
Work in Progress...
#include <SPI.h>
#define TIMER4_DEBUG
#include "Semafori.h"
#include "sr595.h"
const byte PIN_CS = 4;
const byte PIN_START = 7;
SR59516 sr16(PIN_CS);
uint16_t interval[] = { 3000 // tempo di permanenza verde
, 1000 // tempo di permanenza giallo
, 800 // tempo di permanenza rosso
};
// nota: mentre il semaforo A si evolve da verde al rosso, il semaforo B
// resta fermo sul rosso per il tempo 3000 + 1000 + 800 = 4800ms.
// Poi resta fermo A e si evolve B e così via per sempre.
// creare istanza di LSS richiede come argomenti:
// * Una istanza di classe SR59516 (vedi sr16)
// * 3 argomenti bit-verde, bit-giallo e bit-rosso
// Esempio: LSS lss2(
// sr16, // istanza di classe SR59516
// 10, // bit 10, pin sr2:Q2
// 11, // bit 11, pin sr2:Q3
// 12 // bit 12, pin sr2:Q4
// );
LSS lss5(sr16, 2, 3, 4);
LSS lss35(sr16, 5, 6, 7);
LSS lss2(sr16, 10, 11, 12);
LSS lss24(sr16, 13, 14, 15);
//const char *strColor[] = { "Verde", "Giallo", "Rosso" };
void setup() {
Serial.begin(115200);
pinMode(PIN_START, INPUT_PULLUP);
pinMode(PIN_CS, OUTPUT);
digitalWrite(PIN_CS, HIGH);
SPI.begin();
// ad ogni lanterna è possibile assegnare un ID 0÷255
lss2.setId(42);
lss24.setId(24);
lss5.setId(53);
lss35.setId(35);
Timer4 timer4(interval);
// prima di potere usare una istanza di classe LSS
// è necessario assegnargli un registro.
// Un registro è sostanzialmente una variabile uint8_t
// che assume un valore da 0÷2:
// 0 verde, 1 giallo, 2 rosso.
lss5.setRegister(timer4.getRegG());
lss2.setRegister(timer4.getRegR());
lss24.setRegister(timer4.getRegR());
lss35.setRegister(timer4.getRegG());
// avvia il timer
timer4.start();
while(true) {
// timer4.run() // restituisce true allo scadere dei
// seguenti tempi: uint16_t interval[] = { 3000, 1000, 800 };
bool event = timer4.run();
if (event) {
// aggiorna lo stato di tutte le lanterne
lss2.show();
lss5.show();
lss24.show();
lss35.show();
}
}
}
void loop() {
}
La classe LSS
Questa classe "è stupida", stupida nel senso che non cronometra i tempi, ma si limita
ad accendere/spegnere il led della lanterna in base al valore del registro m_register.
class LSS {
public:
LSS(SR59516 &sr, uint8_t pinG, uint8_t pinY, uint8_t pinR) :
m_srPtr(&sr), m_pinG(pinG), m_pinY(pinY), m_pinR(pinR)
{}
void setId(uint8_t id) {
m_id = id;
}
uint8_t id() const {
return m_id;
}
void setRegister(uint8_t *reg) {
m_register = reg;
}
uint8_t *getRegister() const {
return m_register;
}
void printReg() {
Serial.println(*m_register);
}
void show() {
if (m_register == nullptr)
return;
// piccola modifica: solo i primi 3 bit, gli altri 5 portano altre informazioni
switch(*m_register & 0x07) {
case 0: // VERDE
m_srPtr->set(m_pinR, false);
m_srPtr->set(m_pinG, true);
m_cColor = Color::GREEN;
break;
case 1: // GIALLO
m_srPtr->set(m_pinG, false);
m_srPtr->set(m_pinY, true);
m_cColor = Color::YELLOW;
break;
case 2: // ROSSO
m_srPtr->set(m_pinY, false);
m_srPtr->set(m_pinR, true);
m_cColor = Color::RED;
break;
}
m_srPtr->update();
}
Color color() const {
return m_cColor;
}
private:
SR59516 *m_srPtr;
Color m_cColor;
uint8_t m_id;
uint8_t *m_register = nullptr;
uint8_t m_pinG;
uint8_t m_pinY;
uint8_t m_pinR;
};
La classe Timer4
Questa classe è stata realizzata al solo scopo di testare il concetto di
registro condiviso come canale di comunicazione, per cui tutto è discutibile.
Il registro è però di proprietà di Timer4 (vedi m_reg[]) che potrebbe essere limitante.
Il puntatore m_t
deve puntare ad un array di 3 elementi (vedi nello sketch uint16_t interval[]
). I valori dei 3 tempi specificati dovrebbero essere modificabili a run-time
senza side effect, per realizzare ciò, Timer4 dovrebbe ad ogni ciclo copiarsi l'array dei tempi, in questo modo possiamo modificare interval[] ad ogni istante e le nuove tempistiche saranno eseguite nel prossimo ciclo semaforico.
class Timer4 {
public:
Timer4(uint16_t *t) : m_t(t)
{}
void start() {
m_timer = millis();
}
uint8_t *getRegG() {
return &m_reg[0];
}
uint8_t *getRegR() {
return &m_reg[1];
}
bool run() {
if (m_timeEvent) {
m_timeEvent = false;
return true;
}
bool t_event = false;
if (millis() - m_timer >= m_t[m_tIdx]) {
#ifdef TIMER4_DEBUG
Serial.print("reg[");
Serial.print(m_regIdx);
Serial.print("].");
Serial.print(m_t[m_tIdx]);
Serial.print(".");
Serial.println(m_reg[m_regIdx]);
//Serial.print("\t");
#endif
if (m_reg[m_regIdx] != Color::RED) {
m_reg[m_regIdx]++;
} else {
m_regIdx = !m_regIdx;
m_reg[m_regIdx]++;
m_reg[m_regIdx] = m_reg[m_regIdx] % 3;
}
m_tIdx++;
m_tIdx = m_tIdx % 3;
m_timer = millis();
t_event = true;
} else {
t_event = false;
}
return t_event;
}
private:
uint32_t m_timer; // per salvare il valore di millis()
bool m_timeEvent = true;
uint16_t *m_t = nullptr; // puntatore ad array di 3 tempi in ms
uint8_t m_tIdx; // indice di m_t
uint8_t m_reg[2] = { Color::GREEN, Color::RED }; // registro sincronizzato
uint8_t m_regIdx; // indice registro sincronizzato
};