我有一个非常简单的程序让我很头疼。
一些背景: 我正在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();}`
其他一些信息:
答案 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