//////////////////////////////////////////////////////////////////////
// Revers Drive Driver
// 11.08.2023
// V1.1
//////////////////////////////////////////////////////////////////////
// global variable definition & preprocessor def
// enum type for Finite State Machine
typedef enum {
FSM_ASM_STOP,
FSM_SIG_EDGE_DETECTION,
FSM_ASM_RUN_LEFT,
FSM_ASM_RUN_RIGHT,
} asm_fsm_t;
// debug level 0 - no debug, 1 - normal level, 2 - high level
#define DEBUG_LEVEL 2
// time grain for main loop, default time is 10ms
#define MAIN_LOOP_TIME_GRAIN_MS 10
// time interval between movement in left and right, default time is 2000ms
#define STAND_OFF_TIME 2000
// ADPU type: 0 means 1.0v, 1 means 1.5v
#define ADPU_TYPE 1
// debounce time to check edge, default time is 10ms
#define DEBOUNCE_INTERVAL 20
// pinout definition for Arduino nano
int ASM_Left = A5;
int ASM_Right = A0;
//int ACF_ADPU10_230V = 6;
//int ACF_ADPU15_12V = 4;
int ACF_230V_12V = 4;
// global variables
bool current_signal_level = 0, last_signal_level = 0;
bool rising_edge_flag = 0, falling_edge_flag = 0, aux_flag = 0;
bool edge_detected = 0, rising_edge_detected = 0, falling_edge_detected = 0;
unsigned long previous_millis_Debounce = 0;
unsigned long previous_millis_StandOff = 0;
unsigned long previous_millis_Main_Loop = 0;
asm_fsm_t state = FSM_ASM_RUN_RIGHT;
//////////////////////////////////////////////////////////////////////
// setup definition
void setup() {
Serial.begin(9600);
pinMode(ASM_Left, OUTPUT);
pinMode(ASM_Right, OUTPUT);
//pinMode(ACF_ADPU10_230V, INPUT_PULLUP);
//pinMode(ACF_ADPU15_12V, INPUT_PULLUP);
pinMode(ACF_230V_12V, INPUT_PULLUP);
//safety: set drive stop during startup
digitalWrite(ASM_Left, LOW);
digitalWrite(ASM_Right, LOW);
// Log after restart
Serial.println("Arduino Nano restart ...");
}
//////////////////////////////////////////////////////////////////////
// function to detect input signal edge
static void Edge_Detection(void)
{
// reading current level of input signal
//#if ADPU_TYPE == 0
// current_signal_level = digitalRead(ACF_ADPU10_230V);
//#else
// current_signal_level = digitalRead(ACF_ADPU15_12V);
//#endif
current_signal_level = digitalRead(ACF_230V_12V);
// po restarcie przy zalaczonym przelaczniku na stan wysoki generuje sygnal
// rising edge detection
if ((current_signal_level == HIGH) && (last_signal_level == LOW)) {
rising_edge_flag = 1;
falling_edge_flag = 0;
last_signal_level = current_signal_level;
previous_millis_Debounce = millis();
#if DEBUG_LEVEL > 1
Serial.println("RISING edge flag set");
#endif
}
// falling edge detection
if ((current_signal_level == LOW) && (last_signal_level == HIGH)) {
rising_edge_flag = 0;
falling_edge_flag = 1;
last_signal_level = current_signal_level;
previous_millis_Debounce = millis();
#if DEBUG_LEVEL > 1
Serial.println("FALLING edge flag set");
#endif
}
// debounce time to check HIGH level is stable
if (rising_edge_flag == HIGH) {
if (millis() - previous_millis_Debounce > DEBOUNCE_INTERVAL) {
if (current_signal_level == HIGH) {
edge_detected = 1;
rising_edge_detected = 1;
falling_edge_detected = 0;
rising_edge_flag = 0;
#if DEBUG_LEVEL > 1
Serial.println("RISING edge detected");
#endif
}
}
}
// debounce time to check LOW level is stable
if (falling_edge_flag == HIGH) {
if (millis() - previous_millis_Debounce > DEBOUNCE_INTERVAL) {
if (current_signal_level == LOW) {
edge_detected = 1;
rising_edge_detected = 0;
falling_edge_detected = 1;
falling_edge_flag = 0;
#if DEBUG_LEVEL > 1
Serial.println("FALLING edge detected");
#endif
}
}
}
}
//////////////////////////////////////////////////////////////////////
// function to stop ASM drive
static void Drive_Stop(void)
{
digitalWrite(ASM_Left, LOW);
digitalWrite(ASM_Right, LOW);
#if DEBUG_LEVEL > 1
Serial.println("Drive STOP");
#endif
}
//////////////////////////////////////////////////////////////////////
// function to set ASM rotaton left
static void Drive_Left(void)
{
digitalWrite(ASM_Left, HIGH);
digitalWrite(ASM_Right, LOW);
#if DEBUG_LEVEL > 1
Serial.println("Drive LEFT");
#endif
}
//////////////////////////////////////////////////////////////////////
// function to set ASM rotation right
static void Drive_Right(void)
{
digitalWrite(ASM_Left, LOW);
digitalWrite(ASM_Right, HIGH);
#if DEBUG_LEVEL > 1
Serial.println("Drive RIGHT");
#endif
}
//////////////////////////////////////////////////////////////////////
// ASynchronous Motor Finite State Machine definition
static void ASM_FSM(void)
{
switch (state)
{
case FSM_ASM_STOP:
#if DEBUG_LEVEL > 0
Serial.println("State: ASM STOP");
#endif
Drive_Stop();
state = FSM_SIG_EDGE_DETECTION;
aux_flag = 1;
previous_millis_StandOff = millis();
break;
case FSM_SIG_EDGE_DETECTION:
//state FSM_SIG_EDGE_DETECTION
#if (DEBUG_LEVEL > 0)
if (aux_flag) Serial.println("State: SIGNAL EDGE DETECTION");
#endif
if (millis() - previous_millis_StandOff > STAND_OFF_TIME)
{
if (rising_edge_detected == HIGH) {
state = FSM_ASM_RUN_LEFT; aux_flag = 1; rising_edge_detected = 0;
}
if (falling_edge_detected == HIGH) {
state = FSM_ASM_RUN_RIGHT; aux_flag = 1; falling_edge_detected = 0;
}
}
else {
if (aux_flag) Serial.println("Waiting..."); aux_flag = 0;
}
break;
case FSM_ASM_RUN_LEFT:
//state FSM_ASM_RUN_LEFT
#if (DEBUG_LEVEL > 0)
if (aux_flag) Serial.println("State: ASM RUN LEFT");
#endif
if (aux_flag) Drive_Left(); aux_flag = 0;
break;
case FSM_ASM_RUN_RIGHT:
//state FSM_ASM_RUN_RIGHT
#if (DEBUG_LEVEL > 0)
if(aux_flag) Serial.println("State: ASM RUN RIGHT");
#endif
if (aux_flag) Drive_Right(); aux_flag = 0;
break;
default:
//IN CASE OF ERROR
#if (DEBUG_LEVEL > 0)
if(aux_flag) Serial.println("State: DEFAULT in case of error");
#endif
if(aux_flag) Drive_Stop(); aux_flag = 0;
break;
}
}
//////////////////////////////////////////////////////////////////////
// Main program here
void loop()
{
// call ASM_FSM state machine every TIME_GRAIN
if (millis() - previous_millis_Main_Loop > MAIN_LOOP_TIME_GRAIN_MS)
{
// run edge detection
Edge_Detection();
//check result
if(edge_detected == HIGH)
{
state = FSM_ASM_STOP;
edge_detected = 0;
}
// call state machine
ASM_FSM();
// set current time as previous
previous_millis_Main_Loop = millis();
}
}