#define PORTA _SFR_IO8(0x1B)
接着在sfr_defs.h中定义了_SFR_IO8()如下:
#if _SFR_ASM_COMPAT ...... #define _SFR_IO8(io_addr) ((io_addr) + __SFR_OFFSET) #define _SFR_IO16(io_addr) ((io_addr) + __SFR_OFFSET) ...... #else /* !_SFR_ASM_COMPAT */ ...... #define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET) #define _SFR_IO16(io_addr) _MMIO_WORD((io_addr) + __SFR_OFFSET) ...... #endif /* !_SFR_ASM_COMPAT */这个定义表示:
此时、__SFR_OFFSET是IO寄存器的基地址,其值等于0x00,所以PORTA展开如下:
#define PORTA _SFR_IO8(0x1B) = ((io_addr) + __SFR_OFFSET) = ((0x1B) + 0x00) = 0x1B在汇编中操作 PORTA时,就是直接操作 PORTA的地址:
#define PORTA _SFR_IO8(0x1B) = _MMIO_BYTE((io_addr) + __SFR_OFFSET)_MMIO_BYTE()的定义如下:
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))这就是用指针的方式去操作一个内存地址,此时 __SFR_OFFSET等于 0x20。
#define PORTA _SFR_IO8(0x1B) = _MMIO_BYTE((io_addr) + __SFR_OFFSET) = (*(volatile uint8_t *)((io_addr) + __SFR_OFFSET)) = (*(volatile uint8_t *)((0x1B) + __SFR_OFFSET)) = (*(volatile uint8_t *)(0x3B))
__SFR_OFFSET是IO寄存器的基地址,0x1B是PORTA在寄存器文件中的偏移量,加在一起就是PORTA的真实的物理地址(端口地址)。
所以我们对PORTA赋值的时候,就是将数值写入上面这个地址处的寄存器中。
参考avr-libc的介绍:http://www.nongnu.org/avr-libc/user-manual/group__avr__sfr__notes.html
-------------------------------------------------------------------------------------------------------------------------------------
因此、我们可以将PORTA重命名如下:
uint8_t *LED = (uint8_t *)(&PORTA);然后就可以直接对 LED进行操作,来点亮 LED:
*LED = 0x55;如果以后更换了 LED的 IO口,只需要修改 LED这个变量的定义即可。
#define LED (*(volatile uint8_t *)(&PORTA))
最后、如果可以不用#define的定义来隐藏指针操作符就更好了,因为#define定义的部分阅读起来不方便
<还在继续...>