I am working on a program for a RC mixer. It needs to measure incoming pulses and do some mixing. I have managed to get the whole program working on a PIC, but i now want to use a Arduino, and add a few more features.
The first feature i want to add is a failsafe. So if no pulse is received in 25ms then a failsafe value is used. So i have decided to use a Timer1 interrupt. So the code seems to work well, it measure the pulse and displays the value on the serial port. When i turn of the transmitter the timer1 overflow happens but seems to get stuck in the interrupt with the LED toggerling all the time. even when i turn the Transmitter back on it still stays in the interrupt loop.
I am guessing i have done something daft, but i cant see it.
Any clues??
Thanks for any help you may give!
#define ledPin 13
#define RxThro 3
int Time1 = 0;
int Time2 = 0;
int pulse1 = 0;
int failSafe = LOW;
int FST = 0;
boolean toggle = false;
void setup()
{
Serial.begin(115200);
pinMode(ledPin, OUTPUT);// initialize timer1
pinMode(RxThro, INPUT);
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = FST; // preload timer 65536-16MHz/256/2Hz
TCCR1B |= (1 << CS11); // 256 prescaler
TCCR1B |= (1 << CS10);
TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt
interrupts(); // enable all interrupts
}
void doCalcs()
{
if (failSafe == HIGH)
{
pulse1 = 900;
}
else
{
TCNT1 = FST; //reset the failsafe timer
pulse1 = Time2 - Time1;
}
}
void getInputs()
{
failSafe = LOW;
while ((digitalRead(RxThro) == LOW)|(failSafe == HIGH))
{
}
Time1 = micros();
while ((digitalRead(RxThro) == HIGH)|(failSafe == HIGH))
{
}
Time2 = micros();
}
ISR(TIMER1_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
Serial.print("+");
TCNT1 = FST; // preload timer with Fail Safe Time
failSafe = HIGH;
toggle = !toggle;
digitalWrite(ledPin, toggle);
}
void loop()
{
getInputs();
doCalcs();
Serial.print("\t");
Serial.println(pulse1);
}
Hi
Thanks for your very quick reply.
I have quickly changed the code to the following
ISR(TIMER1_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
TCNT1 = FST; // preload timer with Fail Safe Time
failSafe = HIGH;
}
Don't use int for storing micros() use unsigned long
Don't use | instead of || for or in your while
failSafe should be declared as volatile (and should be a Boolean with true or false and not an int with HIGH or LOW just for clarity and good memory usage)
Ok thanks for your replies. i have made adjustments but still have the same problem. maybe i have the wrong understanding of the logic? so if i could please explain how i think it is working then please tell me what i haven't understood?
while ((digitalRead(RxThro) == LOW)||(failSafe == HIGH))
So what i wanted to do was wait for the input pulse to go high. Or if the pulse doesn't go high then the interrupt will set the failsafe to true and the condition will be met? and the program continue?
With the timer in Normal Mode, it will overflow in 2^16 x 64 x .0625 us which works out to a little over 262ms. The led will be toggling quite quickly. What were you expecting?
TCCR1B |= (1 << CS12); // 256 prescaler
Will set the interrupt driven led toggle to more like one second.
You don't need interrupts for this 25ms is an eternity in nowadays microprocessors / microcontrollers.
unsigned long currentTime;
void loop()
{
// start time of failsafe check period
static unsigned long startTime = 0;
// flag to remember if failsafe is triggered
static bool fFailsafeActivated = false;
// get current time
currentTime = millis();
// if 25 ms lapsed
if(currentTime - startTime >=25000UL)
{
fFailsafeActivated = true;
}
// other code here
if(fFailsafeActivated == true || ....)
{
}
}
I leave it up to you to implement a means to reset the failsafe flag.
Cattledog, i tried a few different times and prescalers but it was clear the program wasn't working so its just been left as it untill i can work out why it sticks in the interrupt.
J-M-L, i believe i have done this... volatile boolean failSafe = false;
Sterretje, thanks for your idea, if i fail on the interrupt then i will change to what you have suggested, i started the program how you explained but decided that an interrupt would allow better resolution on the measured pulse?
Evening
I have set the interrupt time to 25ms and checked via a oscilloscope. the reading of the receiver pulse works well, and the interrupt works when a pulse is missing, but i still get stuck in the interrupt.
OK
Thanks for both of our comments.
cattledog you have solved one of the problems! the failsafe now resets when a pulse is received.
And When i can get my head around what Delta_G has said then i believe i will have what i need?
Currently i measure the pulse correctly, But when i turn of the transmitter the interrupt is called but nothing happens apart from a flashing LED. However when i turn the transmitter on again the interrupt is called and the serial displays the pulse again.
Should i have used something other than a while? i didn't want the loop to do anything other than wait for a pulse on RxThro OR a interrupt.
But when i turn of the transmitter the interrupt is called but nothing happens apart from a flashing LED
while ((digitalRead(RxThro) == LOW)||(failSafe == true))
{
}
while ((digitalRead(RxThro) == HIGH)||(failSafe == true))
{
}
You are going to get stuck in one or the other of the while loops. What is the state of the RxThro pin when the transmitter is turned off? I can change which while loop the code sticks in by changing pin 3 from INPUT to INPUT_PULLUP and not having any signal on that pin.
Your while loop can not be based on digitalRead(RxThro) but rather on waiting to see some change in RxThro.
Start the time when RxThro goes from HIGH to LOW or when failSafe is true. End the time when RxThro goes from LOW to HIGH or when failSafe is true.
You are not getting stuck in the interrupt. You are getting stuck in one or the other of the while loops because RxThro is not changing.
The interrupt is triggering independently of the while loop, and that's why you see the led flash.
Firstly thank you for persevering with me on this problem! I seem to have a knack of confusing people.
Delta_G:
From what I understand from what you said earlier, you want either RxThro going HIGH or failSafe going HIGH to get you OUT of the do nothing loop. So you want to stay in the whole loop while BOTH RxThro reads LOW AND failSafe is false. If you use && then either one of them changing gets you out of that do nothing loop.
I want to wait until i see a pulse OR (if no pulse comes) then move on to the next loop when the interrupt happens. then if i have seen no pulse in the first loop then i was thinking it would then skip the second loop due to the Failsafe True?
cattledog:
What is the state of the RxThro pin when the transmitter is turned off?
When the Transmitter is turned off the receiver gives out nothing. Hence the reason i want a failsafe!
Again thanks for all your help.. Your logic chart did the trick!
Its works just as it should and you are right i couldn't get my head around the OR and AND!
#define ledPin 13
#define RxThro 3
unsigned long Time1 = 0;
unsigned long Time2 = 0;
unsigned long pulse1 = 0;
volatile boolean failSafe = false;
int FST = 15000;
int B = 1;
boolean toggle = false;
void setup()
{
Serial.begin(115200);
pinMode(13, OUTPUT);
pinMode(ledPin, OUTPUT);// initialize timer1
pinMode(RxThro, INPUT);
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = FST; // preload timer 65536-16MHz/256/2Hz
TCCR1B |= (1 << CS11);
TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt
interrupts(); // enable all interrupts
}
void doCalcs()
{
if (failSafe == false)
{
TCNT1 = FST; //reset the failsafe timer
pulse1 = Time2 - Time1;
}
else
{
pulse1 = 900;
TCNT1 = FST;
}
}
void getInputs()
{
while ((digitalRead(RxThro) == LOW)&&(failSafe == false))
{
}
Time1 = micros();
while ((digitalRead(RxThro) == HIGH)&&(failSafe == false))
{
}
Time2 = micros();
}
ISR(TIMER1_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
TCNT1 = FST; // preload timer with Fail Safe Time
failSafe = true;
toggle = !toggle;
digitalWrite(13, toggle);
}
void loop()
{
failSafe = false;
getInputs();
doCalcs();
Serial.println(pulse1);
}