/*
Scope of the game
start in the state Ready and come back to the state ready with the minimal number of clicks
No push the RESET
no read the code
The true scope of this code are
General purpose FSM code
kickoff condition (READY to START)
two debouncing solutions
three input
five output (2 led – 3 relay)
two hardware interrupts
RTC simulation / time tic / time display
Timer1 management with 3 ISR
Multipin set
OLED i2c display management
Easy game
1) STAR the game and come back to the “READY” state with the minimal number of clicks
• without pushing the RESET
• without reading the code
Double effect
2) Go from state 2 to 5 and Go from state 5 to 2, note you some differences?
3) Repeat from 2 to … 6
Now change the code as you like
Note
wokwi
1) permit to supply external devices using +5V PIN
it is not possible in real cases
2) don't permit the use resistor partitores
3) see https://docs.wokwi.com/parts/board-ssd1306
4) ...... see all wokwi advices and instructions .....
This program was written in the simplest possible way in order to prevent
a not excellent knowledge of programming language. It is possible use it
HOW IT IS only on the wokwi simulator
For no reason the publication of this code
it makes the authors responsible and even less obliges them to
provide support and / or any explanation or clarification
However, if possible, we will try to answer
to any questions, without any obligation and / or commitment and / or
responsibility
These phrases will always reported in complete form included this following
This software can be used for any purpose under own total, complete
and exclusive responsibility.
Anyone can modify it and adapt it to own needs,always reporting the
present in its entirety phrases, even after importnt changes.
by https://www.facebook.com/groups/883620498953478
Thank you
Max Korrad Team
*/
#include <stdio.h>
#include <Wire.h> // protocollo i2c per settare ad esempio la velocità
#include <Adafruit_GFX.h> // font
#include <Adafruit_SSD1306.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 first_time -3
#define reset_interrup -2
#define wait_interrupt -1
#define button_st 4
#define button_up 3
#define button_dw 2
boolean button_dw_state;
boolean tmpbutton_dw_state;
int debounceDelay = 20;
int counter=0;
volatile int new_state=-1;
volatile int state=0;
volatile int led;
volatile bool up=false, dw=false;
int old_state=0;
void call_up() {
// call interrupt
detachInterrupt(digitalPinToInterrupt(button_up));
up=true;
new_state=state+1;
}
void call_dw() {
// call interrupt
detachInterrupt(digitalPinToInterrupt(button_dw));
dw=true;
new_state=state-1;
}
//long int blink_duration = 300;
int start_h=00, start_m=00, clk=53;
char outstr[30];
void reset_watch (void) {
// RTC setup simulation
start_h=00;
start_m=00;
clk=53;
}
void clock(void) {
// clear
display.setTextSize(2); // 2:1 pixel scale
display.setCursor(25, 0);
display.setTextColor(SSD1306_BLACK);
sprintf(outstr,"%02d:%02d:%02d",start_h,start_m,clk);
display.print(outstr);
// tic RTC simulation
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++;
// print
display.setCursor(25, 0);
display.setTextColor(SSD1306_WHITE);
sprintf(outstr,"%02d:%02d:%02d",start_h,start_m,clk);
display.print(outstr);
display.display();
}
ISR(TIMER1_COMPB_vect) {
digitalWrite(led,HIGH);
}
ISR(TIMER1_COMPA_vect) {
digitalWrite(led,LOW);
}
ISR(TIMER1_OVF_vect) {
digitalWrite(led,HIGH);
/* with TCNT1 > 0 timer1 will start from this value e not zero*/
//TCNT1=15000;
}
void setup() {
Serial.begin(9600); // initialize the serial port:
//cli(); // Nointerrupt
TCCR1A = 0;
TCCR1B = 0;
TCCR1B |= (1 << CS11); //(1 << CS11)|(1 << CS10);(1 << CS12)|
TCCR1B |= (1 << WGM10);
//TCCR1B |= (1 << WGM12); //CTC : with CTC led1 don't work
OCR1A = 37000;
OCR1B = 26000;
//TIMSK1 |= (1 << OCIE1B);
//TIMSK1 |= (1 << OCIE1A);
TCNT1=0;
//TIMSK1 |= (1 << TOIE1); //overflow
// Display setup
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.clearDisplay(); // no logo
pinMode(button_st,INPUT_PULLUP);
pinMode(button_up,INPUT_PULLUP);
pinMode(button_dw,INPUT_PULLUP);
pinMode( 8,OUTPUT);
pinMode( 9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(11,OUTPUT);
pinMode(12,OUTPUT);
pinMode(13,OUTPUT);
PORTB|=B00100000;
PORTB&=B11100000;
int new_state=-2; // numero trasmesso
int state=0;
bool up=false, dw=false;
int old_state=0;
led=9;
sei(); // ok interrupt
}
void loop() {
bool start_flag=false;
static unsigned long now,last=0L; // clock
static int i,k=0; // tic clock x funzione reset_watch di debug
// CTR simulation (each one can choice if introduce the CTR or not)
now=millis();
if( (now-last) > 1000)
{
clock();
last=now;
// only for debug
k++;
if(k==600)
{ // reset abaut each 30 minutes
k=1;
reset_watch();
} }
if(counter < debounceDelay)
{
if(counter==0)
{
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("READY");
display.display();
tmpbutton_dw_state = digitalRead(button_st);
new_state=first_time;
}
counter++;
delay(1);
button_dw_state = digitalRead(button_st);
if( (button_dw_state != tmpbutton_dw_state) || button_dw_state)
{ // l’ingresso è cambiato, ricomincio da zero
counter = 1;
tmpbutton_dw_state = button_dw_state;
} }
else switch(new_state)
{ case first_time:
attachInterrupt(digitalPinToInterrupt(button_up),call_up,FALLING);
attachInterrupt(digitalPinToInterrupt(button_dw),call_dw,FALLING);
led=9;
TIMSK1 |= (1 << OCIE1B);
TIMSK1 |= (1 << OCIE1A);
state=0;
old_state=0;
display.setTextSize(2);
display.setTextColor(SSD1306_BLACK); // Draw white text
display.setCursor(36, 22); // top-left corner
display.write("READY");
display.setTextSize(4);
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(56, 20); // top-left corner
display.write("0");
display.display();
break;
case reset_interrup:
if(state!=old_state)
{ digitalWrite(13, HIGH);
// during LED13 .....
display.setTextSize(4); // 2:1 pixel scale
display.setTextColor(SSD1306_BLACK); // Draw white text
display.setCursor(56, 20); // top-left corner
display.write(old_state+48);
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(56, 20); // top-left corner
display.write(state+48);
display.display();
old_state=state;
}
//debouncing
if( (PIND&B00001000) && (PIND&B00000100)) delay(200);
//reset
if( (PIND&B00001000) && (PIND&B00000100))
{
if (up && state<6)
{ attachInterrupt(digitalPinToInterrupt(button_up),call_up,FALLING);
up=false;
}
{ attachInterrupt(digitalPinToInterrupt(button_dw),call_dw,FALLING);
if (dw && state>0)
dw=false;
}
new_state=wait_interrupt;
digitalWrite(13, LOW);
}
break;
case wait_interrupt:
// wait state
// aspetto un click
break;
case 0:
if(old_state==1)
{ digitalWrite(9, LOW);
TIMSK1 &= !(1 << OCIE1B);
TIMSK1 &= !(1 << OCIE1A);
}
new_state=reset_interrup;
old_state=state;
state=0;
break;
case 1:
led=8;
digitalWrite(9, LOW);
new_state=reset_interrup;
old_state=state;state=1;
break;
case 2:
TIMSK1 &= !(1 << OCIE1B);
TIMSK1 &= !(1 << OCIE1A);
digitalWrite(8, LOW);
digitalWrite(9, LOW);
digitalWrite(10, HIGH); // relay N.1
new_state=reset_interrup;
old_state=state;state=2;
break;
case 3:
digitalWrite(10, LOW); // relay N.1
digitalWrite(11, HIGH); // relay N.2
new_state=reset_interrup;
old_state=state;state=3;
break;
case 4:
digitalWrite(11, LOW); // relay N.2
digitalWrite(12, HIGH); // relay N.3
new_state=reset_interrup;
old_state=state;state=4;
break;
case 5:
digitalWrite(12, LOW); // relay N.1
new_state=reset_interrup;
old_state=state;
state=5;
break;
case 6:
counter=0;
detachInterrupt(digitalPinToInterrupt(button_up));
up=true;
detachInterrupt(digitalPinToInterrupt(button_dw));
dw=true;
display.setTextSize(4);
display.setTextColor(SSD1306_BLACK); // Draw white text
display.setCursor(56, 20); // top-left corner
display.write("5");
display.display();
state=0;
old_state=state;
break;
default:
new_state=reset_interrup;
break;
}
}
// Max KORRAD Team
// FB: Elettronica Hobby Arduino https://www.facebook.com/groups/883620498953478
// https://pastebin.com/APZTbXAZ