I am using the timer to time the duration of states in a state machine, so basically it should be acting as a one-shot timer. Once it initially starts however, it never stops running.
The state machine does progress through its states and finish, but the states last for too long and for random times. I will try to cut out most of the trash that accumulated while debugging and unrelated stuff. Apologies in advance if this too disjointed.
Timer.c
#include "Timer.h"
void Timer_Init()
{
// CTC Mode
TCCR1B |= (1 << WGM12);
// Output compare interrupt A enabled.
TIMSK1 |= (1 << OCIE1A);
// Set compare match.
//OCR1A = 0x3d09; // 15625
Timer_Frequency(1);
// Enable interrupts.
sei();
}
void Timer_Start(Timer *t)
{
//check if timer is already running!
if(t->timer_running)
return;
t->timer_expired = 0;
t->timer_running = 1;
// 64 prescaler.
TCCR1B |= (1 << CS11) | (1 << CS10);
}
void Timer_Frequency(uint8_t f)
{
// OCRnA = F_CPU / frequency * 2 * N - 1
OCR1A = (1000000ul / (f * 2 * 64) - 1);
}
The timer is only used in this function.
#include "EscapeBehavior.h"
//#include "Serial.h"
uint8_t currentState = 0;
void Escape(int id, uint8_t *ready, int8_t *r, int8_t *l, Timer *t)
{
//USART_Transmit(currentState);
switch(currentState)
{
case IDLE:
{
if(ready[id] == 1)
currentState = BACK;
break;
}
case BACK:
{
r[id] = -1;
l[id] = -1;
if(t->timer_running == 0) // if timer is not running, start it.
Timer_Start(t);
if(t->timer_expired != 1) // if timer has not reached its end.
break;
currentState = TURN;
break;
}
case TURN:
{
r[id] = -1;
l[id] = 1;
if(t->timer_running == 0) // if timer is not running, start it.
Timer_Start(t);
if(t->timer_expired != 1) // if timer has not reached its end.
break;
currentState = FOREWARD;
break;
}
case FOREWARD:
{
r[id] = 1;
l[id] = 1;
if(t->timer_running == 0) // if timer is not running, start it.
Timer_Start(t);
if(t->timer_expired != 1) // if timer has not reached its end.
break;
currentState = IDLE;
ready[id] = 0;
break;
}
//default:
//currentState = IDLE;
}
}
the timer is supposed to be stopped in the ISR, and maybe that is where I am missing something.
// Timer interrupt.
ISR(TIMER1_COMPA_vect)
{
// Timer ran its course.
timer.timer_expired = 1;
// Turn off timer.
TCCR1B &= (~(1 << CS11) | ~(1 << CS10) | ~(1 << CS12));
timer.timer_running = 0;
USART_Transmit(times);
times++;
}
Yes, I know using the USART in an interrupt is a bad idea, but it is only for debugging and how I know the timer never stops.
main is simple.
uint8_t behavior_ready[NUM_BEHAVIORS]; // Set when behavior is active.
int8_t right_motor_speed[NUM_BEHAVIORS];// Speed of right motor.
int8_t left_motor_speed[NUM_BEHAVIORS]; // Speed of left motor.
int main(void)
{
Timer_Init();
Motor_Init();
USART_Init(MYUBRR);
// Set up pins.
// IR Sensor
DDRB &= ~(1 << PINB0);
// Set up pcint8.
// Set pin change mask
PCMSK1 |= (1 << PCINT8);
// enable pin change interrupts
PCICR |= (1 << PCIE1);
// enable interrupts.
sei();
while (1)
{
CruiseBehavior(CRUISE_ID);
Escape(ESCAPE_ID, behavior_ready, right_motor_speed, left_motor_speed, &timer);
speed = arbitrate();
Motor_Speed(speed.right, speed.left);
}
}
This supposed to be simple code and only lights LEDs based the direction each motor should be running. As I said, it does do that, just not at the correct times. Once started, the timer never stops and as near as I can tell never misses a beat regardless how often or when Escape() gets re-enabled. My last thought was that I somehow could not clear the register to stop the timer in the interrupt, but putting it in the while loop of main did not make a difference. The variables; timer_running and timer_expired must be getting changed, or the state machine would get stuck once it left idle.
Any thoughts on why the timer continuously runs would be appreciated.