如何在arduino中断服务程序中使用函数指针来修改ISR?

时间:2016-10-18 12:15:25

标签: timer arduino interrupt interrupt-handling

我正在尝试设计一个简单的Arduino中断服务程序,该程序在其中使用函数指针,以便可以从main()函数有效地修改它。以下是我的代码。

#include <stdio.h>
#include <util/delay.h>
#include "gpio.h"        // "gpio.h" is my own library that contains the
                         // definitions of digital_write, digital_read,
                         // pin_mode, analog_write, etc.
                         // It also configures all the timer/counter
                         // circuits to operate in fast-PWM mode
                         // with an undivided input clock signal.
                         // This library has been tested.

/* Two interrupt service routines */

void INT_1(void);
void INT_2(void);

/* Function pointer to choose any one of the above defined ISRs */

void (* interrupt)(void) = NULL;

/* main */

int main(void) {

    pin_mode(3, OUTPUT);
    pin_mode(4, OUTPUT);

    cli();
    TIMSK0 |= _BV(TOIE0);     // Enable Timer0 overflow interrupt
    sei();

    while(1)
    {
        interrupt = INT_1;    // For 10 ms, INT_1 executes on interrupt
        _delay_ms(10);

        interrupt = INT_2;    // For next 10 ms, INT_2 executes on interrupt
        _delay_ms(10);
    }

    return 0;
}

ISR(TIMER0_OVF_vect) {        // Execute the function pointed to by
                              // "interrupt" on every overflow on timer 0
    if(interrupt != NULL)
    {
        interrupt();
    }
}

void INT_1(void) {

    digital_write(3, LOW);
    digital_write(4, HIGH);
}

void INT_2(void) {

    digital_write(3, HIGH);
    digital_write(4, LOW);
}

LED连接到引脚3和4.这些应交替亮起,每个10毫秒。但是,在将此程序闪存到Arduino上时,我发现每个LED亮起大约2秒钟。谁能告诉我为什么?

2 个答案:

答案 0 :(得分:1)

像往常一样,您必须对volatile和其他代码中使用的变量使用ISR修饰符。

void (* volatile interrupt)(void) = NULL;应该可以解决问题。

我的代码(在PlatformIO中编译)

#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdlib.h>

/* Two interrupt service routines */

void INT_1(void);
void INT_2(void);

/* Function pointer to choose any one of the above defined ISRs */

void (* volatile interrupt)(void) = NULL;

/* main */

int main(void) {
    DDRB = _BV(PB5);

    TCCR0B = _BV(CS00);      // enable timer, overflow every 256 clock cycles
    TIMSK0 = _BV(TOIE0);     // Enable Timer0 overflow interrupt
    sei();

    while(1)
    {
        cli();
        interrupt = INT_1;    // For 10 ms, INT_1 executes on interrupt
        sei();
        _delay_ms(10);

        cli();
        interrupt = INT_2;    // For next 10 ms, INT_2 executes on interrupt
        sei();
        _delay_ms(10);
    }
    return 0;
}

ISR(TIMER0_OVF_vect) {        // Execute the function pointed to by
                              // "interrupt" on every overflow on timer 0
    if(interrupt != NULL)
    {
        interrupt();
    }
}

void INT_1(void) {
    PORTB |= _BV(PB5);
}

void INT_2(void) {
    PORTB &= ~_BV(PB5);
}

命令:

[Fri Oct 21 19:29:40 2016] Processing uno (platform: atmelavr, board: uno)
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Collected 0 compatible libraries
Looking for dependencies...
Project does not have dependencies
avr-gcc -o .pioenvs/uno/src/main.o -c -std=gnu11 -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DPLATFORMIO=030100 -DARDUINO_ARCH_AVR -DARDUINO_AVR_UNO -Isrc src/main.c
avr-gcc -o .pioenvs/uno/firmware.elf -Os -mmcu=atmega328p -Wl,--gc-sections,--relax .pioenvs/uno/src/main.o -L.pioenvs/uno -Wl,--start-group -lm -Wl,--end-group
Checking program size .pioenvs/uno/firmware.elf
text       data     bss     dec     hex filename
296           0       2     298     12a .pioenvs/uno/firmware.elf
avr-objcopy -O ihex -R .eeprom .pioenvs/uno/firmware.elf .pioenvs/uno/firmware.hex

答案 1 :(得分:0)

我无法在代码中看到您的计时器值,它将默认为0,并在256个计数(8位)后溢出,然后将服务您的计时器ISR,具体取决于您的函数指针Interrupt的值跳转到相应的功能(INT0或INT1),可能每次都会跳转到相同的功能,您将无法获得预期的结果。

相关问题