c++ - ISR 中使用的指针指向寄存器

标签 c++ c pointers gcc atmega

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

一些背景: 我正在 atmelstudio 6 中对 arduino Uno“Atmega328P”进行编程。我在 debugwire 模式下使用 JTAGICE mkII 进行编程和调试。 我也用过this method使用 arduino 库使事情变得更容易。

我写了一个简单的程序来计算一个外部中断引脚上的转换。在我的例子中,我使用的是 INT0_vect。我指向的值,每次转换都会递增。

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

ISR 为每次转换提供服务,但不会更改值。我不明白为什么,所以我单步执行程序,发现我的指针指向工作寄存器之一 R00。这应该没问题,但在服务 ISR 之前,R00 被插入堆栈 R00 递增并恢复先前的值。

我不知道为什么会这样。正如我所说,我正在使用“volatile uint8_t*”,它应该是一个指向 volatile 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/硬件/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

最佳答案

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

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

关于c++ - ISR 中使用的指针指向寄存器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21031428/

相关文章:

c++ - 了解 cout.operator<<() 的行为

c++ - C++ `for`在应为多个的情况下仅循环迭代一次。

c++ - 将参数传递给 Makefile 以更改编译后的代码

c++ - 如何从包含字符和整数的行中解析出整数

c - 理解指向结构的指针是指访问它时c中的指针成员

delphi - 如何在Delphi中将对象方法作为参数传递,然后调用它?

c++ - 确定 Visual Studio 2015 调试器中每个帧的堆栈大小

c - 语义宏 - 将前一个宏分配给另一个宏

c - 交换双链表中的节点

c - 尝试通过链表读取数组时得到错误的整数