在为 ATmega328 编译 avr-gcc 4.6.2 中的以下代码时,我得到了意外的全局变量读取结果:
#include <avr/io.h>
#include <util/delay.h>
#define LED_PORT PORTD
#define LED_BIT 7
#define LED_DDR DDRD
uint8_t latchingFlag;
int main() {
LED_DDR = 0xFF;
for (;;) {
latchingFlag=1;
if (latchingFlag==0) {
LED_PORT ^= 1<<LED_BIT; // Toggle the LED
_delay_ms(100); // Delay
latchingFlag = 1;
}
}
}
这是整个代码。我希望 LED 切换永远不会执行,因为latchingFlag
设置为1
,但是 LED 会持续闪烁。如果latchingFlag
声明为本地main()
程序按预期执行:LED 永远不会闪烁。
反汇编的代码没有显示我可以看到的任何陷阱,这是使用全局变量对版本的主循环进行反汇编(延迟例程调用被注释掉;相同的行为)
59 .L4:
27:main.cpp **** for (;;) {
60 .loc 1 27 0
61 0026 0000 nop
62 .L3:
28:main.cpp **** latchingFlag=1;
63 .loc 1 28 0
64 0028 81E0 ldi r24,lo8(1)
65 002a 8093 0000 sts latchingFlag,r24
29:main.cpp **** if (latchingFlag==0) {
66 .loc 1 29 0
67 002e 8091 0000 lds r24,latchingFlag
68 0032 8823 tst r24
69 0034 01F4 brne .L4
30:main.cpp **** LED_PORT ^= 1<<LED_BIT; // Toggle the LED
70 .loc 1 30 0
71 0036 8BE2 ldi r24,lo8(43)
72 0038 90E0 ldi r25,hi8(43)
73 003a 2BE2 ldi r18,lo8(43)
74 003c 30E0 ldi r19,hi8(43)
75 003e F901 movw r30,r18
76 0040 3081 ld r19,Z
77 0042 20E8 ldi r18,lo8(-128)
78 0044 2327 eor r18,r19
79 0046 FC01 movw r30,r24
80 0048 2083 st Z,r18
31:main.cpp **** latchingFlag = 1;
81 .loc 1 31 0
82 004a 81E0 ldi r24,lo8(1)
83 004c 8093 0000 sts latchingFlag,r24
27:main.cpp **** for (;;) {
84 .loc 1 27 0
85 0050 00C0 rjmp .L4
第 71-80 行负责端口访问:根据数据表,PORTD
地址0x2B
为十进制43
(参见第 71-74 行)。
变量的局部/全局声明之间的唯一区别latchingFlag
是如何latchingFlag
访问:全局变量版本使用sts
(直接存储到数据空间)和lds
(直接从数据空间加载)访问latchingFlag
,而局部变量版本使用ldd
(从数据间接加载) Space to Register)和std
(Store Indirect From Register to Data Space)使用寄存器Y
作为地址寄存器(可以用作堆栈指针,通过avr-gcc AFAIK)。以下是反汇编的相关行:
63 002c 8983 std Y+1,r24
65 002e 8981 ldd r24,Y+1
81 004a 8983 std Y+1,r24
全球版本也有latchingFlag
.bss 部分。我真的不是将不同的全局变量和局部变量行为归因于什么。这是 avr-gcc 命令行(注意-O0
):
/usr/local/avr/bin/avr-gcc \
-I. -g -mmcu=atmega328p -O0 \
-fpack-struct \
-fshort-enums \
-funsigned-bitfields \
-funsigned-char \
-D CLOCK_SRC=8000000UL \
-D CLOCK_PRESCALE=8UL \
-D F_CPU="(CLOCK_SRC/CLOCK_PRESCALE)" \
-Wall \
-ffunction-sections \
-fdata-sections \
-fno-exceptions \
-Wa,-ahlms=obj/main.lst \
-Wno-uninitialized \
-c main.cpp -o obj/main.o
使用编译器标志,循环从反汇编中消失,但如果声明了,-Os
则可以强制再次出现,在这种情况下,意外对我来说仍然存在。latchingFlag
volatile