Hi. I am using Arduino UNO R3 and I'm trying to write a program with a HW interrupt using INT0 (pin2) and a SW interrupt using timer0. They work fine separately, but the HW interrupt stopped working as soon as I enable the timer interrupt. I'm suspecting that the issue comes from setting the clock for timer0 that affects detecting the edge on the hardware pin.
Below is the snippet of code where the problem occurs.
#define startButton 2 // Yellow
#define emergencyButton 3 // Green
static unsigned long last_interrupt_time = 0;
void setup() {
timerConfig();
attachInterrupt(digitalPinToInterrupt(emergencyButton), emergencyStopISR, RISING); // setup emergency button interrupt pin, mode=RISING/FALLING (trigger at rising edge)
attachInterrupt(digitalPinToInterrupt(startButton), startupISR, RISING);
}
void loop() {
// main loop
}
// setup flag to signal stop sequence
void emergencyStopISR(){
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > 100) { // debouncing, ignore any triggers within 100ms
// set up stop flag
}
last_interrupt_time = interrupt_time;
}
// setup flag to enable functions
void startupISR(){
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > 100) { // debouncing, ignore any triggers within 100ms
// set up start flag
}
last_interrupt_time = interrupt_time;
}
void timerConfig() {
// disable all interrupts
cli();
// configure timer0 to the frequency for x-drive (100 Hz)
TCCR0A = 0; // reset registerA for timer0
TCCR0B = 0; // reset registerB for timer0
TCNT0 = 0; // reset timer0 counter to 0
OCR0A = 155; // set compare match register trigger value
TCCR0A |= (1 << WGM01); // turn on CTC mode
TCCR0B |= (1 << CS02) | (1 << CS00); // Set CS02, CS00 bits for 1024 prescaler
TIMSK0 |= (1 << OCIE0A); // enable timer compare interrupt
// enable all interrupts
sei();
}
unsigned int counterA = 0;
const unsigned int DIVIDER = 5; // divider of 100Hz --> 20Hz
// ISR for timer0 interrupt:
ISR(TIMER0_COMPA_vect){
counterA++;
if (counterA == DIVIDER){
// isr code
counterA = 0;
}
}
Always post ALL the code. The error is often in the code you did not post. Or post the minimum code that will compile, run and demonstrate the problem.
Timer0 has nothing to do with interrupt detection on the INT0 pin.
What led you to the conclusion about why it was failing to react to INT0? How do you have the switches wired?
You are re-configuring the millis() timer timer0 which you are also relying on in the ISRs. Maybe millis() no longer works. Also look at the volatile storage qualifier for global variables updated in an ISR.
Thank you for replying.
As per @jremington's request. Here's the full working version of the code.
I have tested with commenting out timerConfig() and it worked normally, but when I run that piece of configuration, it stopped reacting to the INT0 interrupt.
Responding to @6v6gt's comment, I've done a little research and noticed that millis() will be blocked in ISR. This should not matter because the ISR only takes the value from millis() once. However, I also noticed that millis() is using timer0, but since I'm using the compare register on Timer 0 and not altering its frequency, I don't think that will change millis() either.
*The part where I use millis() is for debouncing and I'm not sure if there's other simple ways to do it. It would be greatly appreciated if anyone can share some other interesting way to implement a debouncing on buttons!
Thank you!
Lastly, here's the full version of the code that I'm running.
#define startButton 2 // Yellow
#define emergencyButton 3 // Green
#define relay 4
// global flags
volatile int startFlag = 0;
volatile int stopFlag = 0;
enum state { STOP, NORMAL, IDLING };
volatile state currState = IDLING;
static unsigned long last_interrupt_time = 0;
void setup() {
Serial.begin(9600);
pinMode(relay, OUTPUT);
digitalWrite(relay, HIGH); // turn off relay
Serial.println(digitalRead(relay));
attachInterrupt(digitalPinToInterrupt(emergencyButton), emergencyStopISR, RISING); // setup emergency button interrupt pin, mode=RISING/FALLING (trigger at rising edge)
attachInterrupt(digitalPinToInterrupt(startButton), startupISR, RISING);
timerConfig();
}
void loop() {
switch (currState) {
case IDLING:
// state transition logic
if (stopFlag) {
currState = STOP;
} else if (startFlag) {
currState = NORMAL;
}
// main code
Serial.println("I");
break;
case NORMAL:
// state transition logic
if (stopFlag) {
currState = STOP;
}
// main code
Serial.println("N");
break;
case STOP:
// main code
Serial.println("S");
break;
}
}
// setup flag to signal stop sequence
void emergencyStopISR(){
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > 100) { // debouncing, ignore any triggers within 100ms
// code for ISR
stopFlag = 1;
}
last_interrupt_time = interrupt_time;
}
// setup flag to enable functions
void startupISR(){
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > 100) { // debouncing, ignore any triggers within 100ms
// code for ISR
if (currState == STOP) { // reset state
currState = IDLING;
startFlag = 0;
stopFlag = 0;
} else {
startFlag = 1;
}
}
last_interrupt_time = interrupt_time;
}
// setup timer interrupt for x, y drive
void timerConfig() {
// disable all interrupts
cli();
// configure timer0 to the frequency for x-drive (100 Hz)
TCCR0A = 0; // reset registerA for timer0
TCCR0B = 0; // reset registerB for timer0
TCNT0 = 0; // reset timer0 counter to 0
OCR0A = 155; // set compare match register trigger value, increment motor by 5
TCCR0A |= (1 << WGM01); // turn on CTC mode
TCCR0B |= (1 << CS02) | (1 << CS00); // Set CS02, CS00 bits for 1024 prescaler
TIMSK0 |= (1 << OCIE0A); // enable timer compare interrupt
// enable all interrupts
sei();
}
unsigned int counterA, counterB = 0;
const unsigned int DIVIDER = 5; // divider of 100Hz --> 20Hz
// ISR for timer0 interrupt: X-drive motor control -- too fast, will not allocate time to regular sequence
ISR(TIMER0_COMPA_vect){
counterA++;
if (counterA == DIVIDER){
Serial.println("triggered");
counterA = 0;
}
}