I have an Arduino program that operates turn signals for a motorcycle based on a PY503 gyro with its 4x pin connected to Arduino pin A2 and the left turn button connected to pin 9 and the right turn button connected to pin 10.
Here is how it functions:
- Press left button < 333ms and the left blinker blinks 4 times (lane change)
- Press the left button > 333ms and < 2000 ms and it blinks until either is true:
a. A button is pressed and released (cancel)
b. The gyro turns left, then right, then stops turning (What a motorcycle does in a left turn) - Press the left button > 2000ms and both the left and right directional lights blink until cancelled with a subsequent press of either button..
- The same is true for the right button except the gyro turn requirements are reversed.
Both 1 and 2 above are working just fine but #3 (emergency flashers) has a problem.
Line 108 has Serial.println("Ready to Cancel"); and the emergency flashers work if that line is not commented out. If I comment out that line, the system goes through the motions but the flashers do not blink.
(By goes through the motions I mean after holding a button for > 2000ms, nothing flashes, and the first subsequent brief button press doesn’t “appear” to change anything but the second brief press puts it into lane change mode. That means it exited the Emergency mode with the first press and then cancelled with the second.
This is 100% repeatable, #3 works when the Serial.print is functioning and no blinks occur if I comment it out.
I have spent several hours trying to resolve this. I do not print while inside an interrupt routine. The code has been shuffled around to change the order of things in the main loop.
This seems bazaar to me. Anyone have some ideas on what is happening?
Here is the code:
#include <elapsedMillis.h>
#include<Wire.h>
#include "TimerOne.h"
#include <MsTimer2.h>
#define variance 75
#define pressed 0
int g = 0;
int gyroLeft;
int gyroRight;
boolean BlinkLeft = false;
boolean BlinkRight = false;
boolean BlinkBoth = false;
typedef struct data_type
{
int leftButton;
int rightButton;
int len;
boolean turn;
boolean change;
boolean cancel;
} data_t;
data_t d;
elapsedMillis timer0;
void setup() {
Serial.begin(115200);
pinMode(9, INPUT_PULLUP); // Left directional Switch
pinMode(10, INPUT_PULLUP); // Right directional Switch
pinMode(11, OUTPUT); // Left directional output
pinMode(12, OUTPUT); // Right directional output
pinMode(13, OUTPUT); // LED circuit board indicator
Timer1.initialize(500000); // initialize timer1, and set a 1/2 second period
Timer1.attachInterrupt(Timer1Int); // attaches interruptk() as a timer overflow interrupt
MsTimer2::set(4000, Timer2Int); // 4 second period
MsTimer2::stop(); // timer off
BlinkOff();
g = ReadGyro();
gyroLeft = g + variance;
gyroRight = g - variance;
}
void Timer1Int() // Comes here every .5 seconds for blinking
{
if (BlinkLeft)
{
digitalWrite(11, digitalRead(11) ^ 1); // Left
digitalWrite(13, digitalRead(13) ^ 1); // LED
}
else if (BlinkRight)
{ digitalWrite(12, digitalRead(12) ^ 1); // Right
digitalWrite(13, digitalRead(13) ^ 1); // LED
}
else if (BlinkBoth)
{
digitalWrite(11, digitalRead(11) ^ 1); // Left
digitalWrite(12, digitalRead(12) ^ 1); // Right
digitalWrite(13, digitalRead(13) ^ 1); // LED
}
else
BlinkOff();
}
void Timer2Int() // lane change ends after 5 seconds
{
BlinkLeft = false;
BlinkRight = false;
MsTimer2::stop();
}
void loop()
{
String dir;
int l, r;
d.len = 0;
ReadButtons(true); // blocked read
if (d.len > 0) // is it valid?
{
// Serial.println("Start");
if (d.len <= 333) // lane change
{
d.change = true;
d.turn = false;
d.cancel = false;
if (d.leftButton == pressed)
BlinkLeft = true;
if (d.rightButton == pressed)
BlinkRight = true;
MsTimer2::start();
}
if (d.len > 333 and d.len <= 2000) // Turn
{
d.change = false;
d.turn = true;
d.cancel = false;
if (d.leftButton == pressed)
BlinkLeft = true;
if (d.rightButton == pressed)
BlinkRight = true;
}
if (d.len > 2000) // Emergency flashers
{
BlinkBoth = true;
BlinkLeft = false;
BlinkRight = false;
delay(100);
Serial.println("Ready to Cancel");
while (ReadButtons(false) == false); // Wait for button press (Cancel);
delay(100);
while (ReadButtons(false) == true); // Wait for button release
BlinkBoth = false;
}
}
if (d.turn)
Turn();
}
void Turn() // blink until turn completed or cancelled
{
int g, i;
g = ReadGyro();
while (d.turn)
{
if (BlinkLeft)
{
if (WaitForLeft())
d.turn = false;
if (d.turn)
if (WaitForRight())
break;
if (d.turn)
WaitForStraight();
Reset(false);
d.turn = false;
}
else if (BlinkRight)
{
//watch(d.turn, d.change, BlinkLeft, BlinkRight, d.leftButton, d.rightButton, g);
if (WaitForRight())
d.turn = false;
if (d.turn)
if (WaitForLeft())
d.turn = false;
if (d.turn)
WaitForStraight();
Reset(false);
d.turn = false;
}
}
}
void BlinkOff()
{
digitalWrite(11, LOW);
digitalWrite(12, LOW);
digitalWrite(13, LOW);
BlinkLeft = false;
BlinkRight = false;
BlinkBoth = false;
}
int ReadGyro()
{
int i;
g = 0;
for (i = 0; i < 20; i++)
g += analogRead(10);
return (g / 20);
}
void ShowGyro(int a)
{
if (a < gyroRight)
Serial.println("right");
else if (a > gyroLeft)
Serial.println("left");
}
boolean ReadButtons(bool blocking)
{
boolean result = false;
int l, r;
d.leftButton = digitalRead(9);
d.rightButton = digitalRead(10);
if (d.leftButton == pressed | d.rightButton == pressed)
{
result = true;
}
if (blocking)
{
timer0 = 0;
d.len = 0;
l = d.leftButton;
r = d.rightButton;
while (l == pressed | r == pressed)
{
l = digitalRead(9);
r = digitalRead(10);
}
if (timer0 > 10)
d.len = timer0;
}
return result;
}
boolean WaitForLeft()
{
g = ReadGyro();
while (g < gyroLeft) // wait for left turn
{
g = ReadGyro();
if (CheckCancel())
return true;
}
return false;
}
boolean WaitForRight()
{
g = ReadGyro();
while (g > gyroRight) // wait for right turn
{
g = ReadGyro();
if (CheckCancel())
return true;
}
return false;
}
boolean WaitForStraight()
{
int i;
g = ReadGyro();
while (g < gyroRight | g > gyroLeft)
{
g = ReadGyro();
if (CheckCancel())
return true;
}
return false;
}
void Reset(boolean prt)
{
d.change = false;
d.turn = false;
d.cancel = true;
d.leftButton = 1;
d.rightButton = 1;
d.len = 0;
BlinkLeft = false;
BlinkRight = false;
BlinkOff();
if (prt)
Serial.println("Canceled");
}
boolean CheckCancel()
{
int but = ReadButtons(false); // cancel if button pressed
if (but)
{
while (ReadButtons(false)); // Wait for button release
Reset(true);
return true;
}
return false;
}