AVR I/O 宏定义如何工作以允许访问寄存器?

Ale*_*Crb 2 c atmega cpu-registers avr-gcc atmel

我正在查看 ATmega2560 寄存器映射 ( iom2560.h) 的标头,其中包含寄存器的所有定义。例如:

#define PINA    _SFR_IO8(0X00)
//Macro definition:
#define _SFR_IO8(io_addr) ((io_addr) + 0X20)
Run Code Online (Sandbox Code Playgroud)

所以PINA是一个8位的十六进制值,对应于8位单片机寄存器的地址。当我编写代码时,我只需输入以下代码即可更改寄存器内的值:

PINA |= (1 << 3); // Setting the third bit.
Run Code Online (Sandbox Code Playgroud)

问题是:为什么我可以_SFR_IO8(0X00)通过将值赋给PINA来写入寄存器值(“由他的地址指向”)?这不是指向的寄存器的地址吗?编译器如何工作?

预先非常感谢

Kur*_*ier 5

简短的回答 - 隐藏在 Atmel 包含的标头中的是创建指向寄存器位置的指针的宏集合。以下是该过程的简要概述:

您的 Makefile 定义要使用的设备,然后将定义传递给编译器。

DEVICE = atmega2560
...
-D__$(DEVICE)__
Run Code Online (Sandbox Code Playgroud)

然后,您包含 io.h,它会根据您的设备自动包含必要的标头:

// In main source file
#include <io.h>    

// In io.h
#include <avr/sfr_defs.h>
// ...
#elif defined (__AVR_ATmega2560__)
    #  include <avr/iom2560.h>

// In sfr_defs.h
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
#define __SFR_OFFSET 0x20
#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)

// In iom2560.h
#include <avr/iomxx0_1.h>
// Other device specific definitions

// Om iomxx0_1.h
#define PINA    _SFR_IO8(0X00)
// Other device family shared definitions
Run Code Online (Sandbox Code Playgroud)

因此,如果您展开所有这些,您将得到一个指向寄存器地址的易失性指针。当您在代码中使用 PINA 时,预编译器会将其替换为所有扩展宏:

PINA
_SFR_IO8(0X00)
_MMIO_BYTE((0X00) + __SFR_OFFSET)
(*(volatile uint8_t *)((0X00) + 0x20))
Run Code Online (Sandbox Code Playgroud)

其中指定 PINA 是指向易失性 8 位内存地址 0x20 的指针。然后,无论何时访问该地址,内部芯片架构都会将该地址映射到适当的外设寄存器。