用于ISR点注册的指针

时间:2014-01-09 21:22:25

标签: c++ c pointers gcc atmega

我有一个非常简单的程序让我很头疼。

一些背景: 我正在atmelstudio 6中编写一个arduino Uno“Atmega328P”。我在调试线模式下使用JTAGICE mkII进行编程和调试。 我还使用this method来使用arduino库来简化操作。

我编写了一个简单的程序来计算其中一个外部中断引脚的转换。在我的情况下我使用INT0_vect。我指向的值,只是每次转换的增量。

问题是在ISR中使用全局指针。您可能认为我忘记添加volatile关键字,但您错了。

每次转换都会为ISR提供服务,但不会更改该值。我无法弄清楚为什么所以我逐步完成程序,发现我的指针指向R00,一个工作寄存器。这应该没问题但是在ISR被服务之前R00被推到堆栈R00递增并且先前的值被恢复。

我不知道为什么会这样。正如我所说,我使用的是“volatile uint8_t*”,它应该是指向易失性uint8_t的指针。

这就是代码的样子:

#include "Arduino.h"
void setup();
void loop();
void update();

volatile uint8_t* Count;
void setup()
{
    *Count = 0;
    attachInterrupt(0,update, CHANGE);  // makes ISR call update
}
void loop()
{
//  delay(1000);
}
 void update()
{
    (*Count)++;
}

主循环调用设置一次然后重复循环 attach interrupt是一个设置中断然后有效创建的宏:

`ISR(INT0_vect){update();}`

其他一些信息:

  • 我正在为c ++和c编译器使用-Os。
  • avr-gcc完整选项: -funsigned-char -funsigned-bitfields -DF_CPU = 16000000UL -I“../../../../ arduino-1.0.5 / hardware / arduino / cores / arduino”-I“../../../../ arduino-1.0.5 / hardware / arduino / variants / standard“-Os -fdata-sections -ffunction-sections -fpack-struct -fshort-enums -Wall -c -std = gnu99 -fno-exceptions -MD -MP -MF”$(@:% .o =%。d)“ - MT”$(@:%。o =%。d)“ - MT”$(@:%。o =%。o)“ - mmcu = atmega328p
  • avr-g ++完整选项:-funsigned-char -funsigned-bitfields -DF_CPU = 16000000UL -I“../../../../ arduino-1.0.5 / hardware / arduino / cores / arduino” -I“../../../../ arduino-1.0.5 / hardware / arduino / variants / standard”-Os -fdata-sections -ffunction-sections -fpack-struct -fshort-enums -Wall - c -fno-exceptions -MD -MP -MF“$(@:%。o =%。d)” - MT“$(@:%。o =%。d)” - MT“$(@:%。 o =%。o)“ - mmcu = atmega328p
  • avr-g ++链接器选项:-Wl,-Map =“$(OutputFileName).map”-Wl, - start-group -Wl,-lm -Wl,-lcore -Wl, - end-group - Wl,-L“../../../ ArduinoCore”-Wl, - gc-sections -mmcu = atmega328p

2 个答案:

答案 0 :(得分:0)

在嵌入式应用程序中,访问寄存器的流行习惯是使用指针并为其分配地址:

uint32_t volatile * const uart_rx = 0xFFFFD000;

volatile限定符告诉编译器指向的内容在程序不知情的情况下会发生变化。

从UART接收寄存器读取如下所示: uint32_t register_value = * uart_rx;

如果硬件项为8位,则应使用uint8_t类型。

事实是编译器生成的汇编语言。

如果这不能解决您的问题,请修改您的帖子并添加更多详细信息。

答案 1 :(得分:0)

由于Count指针是未显式初始化的全局变量,因此它被设置为0x0,这恰好是Atmega328P将寄存器R00映射到的地址。 / p>

标有ISR()宏的函数向编译器指示它是C ISR处理程序。为了让编译器安排C代码执行ISR而不破坏ISR触发时可能运行的任何状态,它必须添加一些序言代码以保存一些CPU的寄存器状态(以及相应的结尾来恢复)当ISR函数返回时的状态),以便中断的执行路径不被破坏。因此,ISR()指定会导致编译器在堆栈上保存和恢复寄存器R00(以及其他寄存器)。

这两种情况的结合是为什么R00被保存在堆栈上,然后你的ISR递增它,然后从堆栈中恢复R00

如果您不希望发生这种情况,可以使用ISR_NAKED属性告诉编译器不要生成序言或结尾代码。但是,如果您的ISR句柄没有正确保存和恢复寄存器状态,那么在前台运行的任何内容都可能表现不佳。

因此,将Count设置为指向您为计数器分配的某个位置。或者,将Count设为一个简单变量而不是指针,并直接在ISR中处理它。

可以在此处找到有关avr-gcc中断处理支持的精彩概述:http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html