I'm writing a program on attiny85 using interrupts. It is a simple program:
- when rising edge is detected on PCINT0, drive DEBUG_PIN
to HIGH
- when TIMER1 counts up to OCR1A, drive DEBUG_PIN to LOW
Problem is that when program detects rising edge on PCINT0, it starts Timer1 comparator A and then immediately calls ISR(TIMER1_COMPA_vect)
. As an effect, on DEBUG_PIN
there is only a little narrow spike instead of a nice square wave of length 50ms (checked it with oscilloscope).
Im using ARDUINO IDE. Here is the code:
/*
* Movement detection using interrupts instead of linear approach
*
* POS_TIMEOUT will be checked using COMPA on TIM0
* IMP_TIMEOUT will be checked using COMPB on TIM0
* LOOP_TIME will be chcecked using TIMER1 overflow
*
* INT0_PIN_IN (PB2) is the pin that receives the signal
* INT0_PIN_OUT (PB4) is the pin used for external interrupt debugging
* DEBUG_PIN (PB3) is the pin used for debugging
* STATUS_PIN (PB1) - high when awake, low when asleep
*/
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
//#include "timers_init.h"
//Watch out! do not use the reset pin (PB5)!
#define INT0_PIN_IN 0
#define INT0_PIN_OUT 4
#define STATUS_PIN 1
#define DEBUG_PIN 3
#define POS_TIMEOUT 50
#define PRE_1 0
#define PRE_2 1
#define PRE_4 2
#define PRE_8 3
#define PRE_16 4
#define PRE_32 5
#define PRE_64 6
#define PRE_128 7
#define PRE_256 8
#define PRE_512 9
#define PRE_1024 10
#define PRE_2048 11
#define PRE_4096 12
#define PRE_8192 13
#define PRE_16384 14
/*******MONITORING*VARIABLES*VOLATILES**************/
/* variable keeping last state of INT0 input */
volatile bool lastState = false;
/*************STATUS FLAGS**************************/
/* flags used for movement detection */
/* all flags are initiated as false */
volatile bool positiveFlag = false;
volatile bool fallingEdge = false;
volatile bool risingEdge = false;
volatile bool positiveTimeoutCheck = false;
volatile bool impulseTimeoutCheck = false;
/*************UTILS*********************************/
void timerOneCompADisable( void ){
bitClear(TIMSK, OCIE1A);
}
void timerOneCompAInit( uint8_t compValue ){
//set comparatorA value
OCR1A = compValue;
//enable compA interrupts
bitSet(TIMSK, OCIE1A);
}
/******************
* INTERRUPTS!!!
******************/
/*
* This interrupt is called every time PCINT0 input state changes
*/
ISR(PCINT0_vect){
bool readPin = digitalRead( INT0_PIN_IN );
//falling edge
if( lastState && lastState != readPin ){
fallingEdge = true;
lastState = false;
}
//rising edge
else if( !lastState && lastState != readPin ){
risingEdge = true;
lastState = true;
}
}
//TIMER 1 COMPARE match A
ISR(TIMER1_COMPA_vect){
positiveTimeoutCheck = false;
digitalWrite( DEBUG_PIN, LOW );
timerOneCompADisable();
}
/**********************
* MAIN CODE!!!!!!!
**********************/
void setup(){
/* Pin config */
pinMode( INT0_PIN_IN, INPUT );
pinMode( DEBUG_PIN, OUTPUT);
/* Pin initialization */
digitalWrite( DEBUG_PIN, LOW );
/* Timers configuration */
//prescaler is 8192 so one tick is ~1 ms
TCCR1 |= (1<<CS13)|(1<<CS12)|(1<<CS11)|(0<<CS10);
/* Interrupts initialization */
bitSet( GIMSK, PCIE );
bitSet( PCMSK, PCINT0 );
}
/* function resetting flags */
void resetFlags( void ){
positiveFlag = false;
fallingEdge = false;
risingEdge = false;
positiveTimeoutCheck = false;
}
int main(){
cli();
setup();
/* Variables initialization */
lastState = digitalRead( INT0_PIN_IN );
resetFlags();
sei();
while(1){
/* State machine */
//if nothing is going on and rising edge is detected
//reset everything and ignite positive flag
if( risingEdge ){
cli();
resetFlags();
positiveFlag = true;
sei();
} // if
//INT0 is high, initiate positive timeout check
else if( positiveFlag && !positiveTimeoutCheck ){
cli();
resetFlags();
timerOneCompAInit( POS_TIMEOUT );
positiveTimeoutCheck = true;
digitalWrite( DEBUG_PIN, HIGH );
TCNT1 = 0;
sei();
} //else if
} //while
return 0;
}