/**************************************************************************
Trafic light
state list
1) yellow night
2) green
3) yellow
4) red
5) call
6) warning red
**************************************************************************/
#include <Wire.h> // protocollo i2c per settare ad esempio la velocità
#include <Adafruit_GFX.h> // font
#include <Adafruit_SSD1306.h>
#include <stdio.h>
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define Yellow_night 1
#define TLgreen 2
#define TLyellow 3
#define TLred 4
#define Call 5
#define Wred 6
#define led1 12 // led 1 green
#define led2 11 // led 2 yellow
#define led3 10 // led 3 red
#define ledp 8 // light person si può collegare direttamente al pin 10,
// ma manca il preallarme a rosso
#define button 3 // call
#define slide 4 // day/night
volatile bool day_night_state=true; // true=day; false=night
static bool call_state=false;
volatile int old_state,state=TLred;
volatile unsigned long last_event=0L;
long int green_duration = 4000; // millisecondi
long int yellow_duration = 2000;
long int red_duration = 4000;
long int blink_duration = 300;
int start_h=15, start_m=04, clk=53;
char outstr[30];
char state_str[7][6]={"NULL_","NIGHT","GREEN","YELLW","_RED_","CALL ","W_RED"};
void call_falling() {
// call interrupt
detachInterrupt(digitalPinToInterrupt(button)); //,call_falling);
last_event=millis();
call_state=true;
}
void reset_watch (void) {
// simula inizializzazione del RTC
start_h=17;
start_m=59;
clk=53;
}
void clock(void) {
// cancella vecchio orario
display.setCursor(80, 0);
display.setTextColor(SSD1306_BLACK);
sprintf(outstr,"%02d:%02d:%02d",start_h,start_m,clk);
display.print(outstr);
// simula RTC
if(clk==59) {
if(start_m==59) {
if(start_h==23) start_h=0;
else start_h++;
start_m=-1;
}
start_m++;
clk=-1;
}
clk++;
// stampa orario aggiornato
display.setCursor(80, 0);
display.setTextColor(SSD1306_WHITE);
sprintf(outstr,"%02d:%02d:%02d",start_h,start_m,clk);
display.print(outstr);
display.display();
}
void setup() {
//Serial.begin(9600);
// Display setup
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
// cancella il logo iniziale di Adafruit
display.clearDisplay();
// settaggio delle porte
pinMode(led1,OUTPUT);
pinMode(led2,OUTPUT);
pinMode(led3,OUTPUT);
pinMode(ledp,OUTPUT);
pinMode(button,INPUT_PULLUP);
pinMode(slide, INPUT_PULLUP);
// START
digitalWrite(led1, HIGH);
digitalWrite(led2, HIGH);
digitalWrite(led3, HIGH);
display.setTextSize(2); // 2:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(36, 22); // top-left corner
display.cp437(true); // Use full 256 char 'Code Page 437' font
display.write("START");
display.display();
delay(300);
digitalWrite(led1, LOW);
digitalWrite(led2, LOW);
digitalWrite(led3, LOW);
digitalWrite(ledp, HIGH);
display.clearDisplay();
cli(); // Nointerrupt
// READY
display.setTextSize(1); // Normal 1:1 pixel scale
display.setCursor(2,0);
display.print("Trafic Light");
//display.setCursor(80, 24);
//display.setTextColor(SSD1306_WHITE);
reset_watch();
digitalWrite(led1,LOW);
digitalWrite(led2,LOW);
if(digitalRead(slide)) // read Day/Night slide 1 time for second
{ day_night_state=true; // day
state=TLred; // il semaforo parte con rosso all'accensione ed al passaggio da notte a giorno
last_event=millis();
digitalWrite(led3,HIGH);
digitalWrite(ledp,LOW);
}
else
{ day_night_state=false; // night
state=Yellow_night;
digitalWrite(ledp,HIGH);
}
sei(); // ok interrupt
attachInterrupt(digitalPinToInterrupt(button),call_falling,FALLING);
display.setCursor(2,56);
display.setTextColor(SSD1306_BLACK);
display.print(" ");
display.setCursor(2,56);
display.setTextColor(SSD1306_WHITE);
sprintf(outstr,"state=%s",state_str[state]);
display.print(outstr);
display.display();
old_state=state;
}
void loop() {
static unsigned long now,last=0L; // orologio
static int k=0; // tic clock x funzione reset_watch di debug
// aggiorna orario sul display ogni 1000ms
// simula CTR
now=millis();
if( (now-last) > 1000)
{
clock();
last=now;
// funzione di debug
k++;
if(k==60)
{ // circa ogni 3 minuti resetta l'orologio
k=0;
reset_watch();
} }
// stampa dello stato corrente
// al cambio di stato
if(state!=old_state){
display.setCursor(2,56);
display.setTextColor(SSD1306_BLACK);
sprintf(outstr,"state=%s",state_str[old_state]);
display.print(outstr);
display.setCursor(2,56);
display.setTextColor(SSD1306_WHITE);
sprintf(outstr,"state=%s",state_str[state]);
display.print(outstr);
display.display();
old_state=state;
}
// verifica slide Night/Day
if(digitalRead(slide)) day_night_state=true; // day
else day_night_state=false; // night
// trafic light finite state machine
switch (state) {
case(Yellow_night) :
if(call_state || (day_night_state) )
{ last_event=now;
now=millis();
digitalWrite(led2,HIGH);
state=TLyellow;
}
if ((now-last_event)>blink_duration){
digitalWrite(led2,!(PINB & B00001000)); // devi aggiornare il pin se cambi led
//Serial.print();
last_event=now;
}
break;
case(TLgreen) :
if (!day_night_state)
{ digitalWrite(led1,LOW);
digitalWrite(led2,HIGH);
digitalWrite(led3,LOW);
digitalWrite(ledp,HIGH);
state=Yellow_night;
}
if ((now-last_event)>green_duration){
digitalWrite(led1,HIGH);
digitalWrite(led2,HIGH);
digitalWrite(led3,LOW);
digitalWrite(ledp,HIGH);
last_event=now;
now=millis();
state=TLyellow;
}
if(call_state)
{ last_event=now;
digitalWrite(led1,LOW);
digitalWrite(led2,HIGH);
digitalWrite(led3,LOW);
digitalWrite(ledp,HIGH);
state=TLyellow;
}
break;
case(TLyellow) :
if ((now-last_event)>yellow_duration){
digitalWrite(led1,LOW);
digitalWrite(led2,LOW);
digitalWrite(led3,HIGH);
digitalWrite(ledp,LOW);
state=TLred;
last_event=now;
now=millis();
}
break;
case(TLred) :
if(call_state){ // una sola volta durante il rosso
last_event=now;
call_state=false;
}
if ((now-last_event)>red_duration/2){
detachInterrupt(digitalPinToInterrupt(button)); //,call_falling);
state=Wred;
delay(100); // si può anche far passante
}
if ((now-last_event)>red_duration){
if(!day_night_state) state=Yellow_night;
else
{ state=TLgreen;
digitalWrite(led1,HIGH);
digitalWrite(led2,LOW);
}
digitalWrite(led3,LOW);
digitalWrite(ledp,HIGH);
attachInterrupt(digitalPinToInterrupt(button),call_falling,FALLING);
last_event=now;
now=millis();
}
break;
case(Call) :
attachInterrupt(digitalPinToInterrupt(button),call_falling,FALLING);
call_state=true;
last_event=now;
now=millis();
state=TLyellow; // il semaforo parte con rosso all'accensione ed al passaggio da notte a giorno
digitalWrite(led1,LOW);
digitalWrite(led2,HIGH);
digitalWrite(led3,LOW);
digitalWrite(ledp,HIGH);
break;
case(Wred) :
if(call_state){ // una sola volta durante il rosso
last_event=now;
call_state=false;
}
digitalWrite(ledp,!(PINB & B00000001));
delay(100); // si può anche far passante
if ((now-last_event)>red_duration){
if(!day_night_state) state=Yellow_night;
else
{ state=TLgreen;
digitalWrite(led1,HIGH);
digitalWrite(led2,LOW);
}
digitalWrite(led3,LOW);
digitalWrite(ledp,HIGH);
attachInterrupt(digitalPinToInterrupt(button),call_falling,FALLING);
last_event=now;
now=millis();
}
break;
default :
break;
}
}