我指的是用于编写可重复使用的固件的文档,并且本书随附的代码使用指针数组来映射内存。
我对内存映射有点困惑
从此post开始,如果将8位内存映射到0X123,则可以使用以下命令
uint8_t volatile * p_reg = (uint8_t volatile *) 0x1234;
或
#define PORT 0X1234
uint8_t volatile * p_reg = (uint8_t volatile *) PORT;
或在指针数组的情况下
#define PORT 0X1234
uint8_t volatile * const portsout[NUM_PORTS] =
{
(uint8_t*)PORTB, ....,
};
我尝试了atmega168随书附带的代码,这是我映射内存所要做的
uint8_t volatile * const portsout[NUM_PORTS] =
{
(uint8_t*)&PORTB, (uint8_t*)&PORTC, (uint8_t*)&PORTD,
};
PORTB在头文件“ avr / io.h”中定义为此
#define PORTB _SFR_IO8 (0x05)
我不理解的是在指针数组中需要&吗?
使用lpc2148时出现编译错误时,我向作者发送了一封邮件,并在他的回复邮件中提到了
然后看起来您的指针数组实际上可能不是指针。 例如:
(uint32_t *)&IOPIN0,(uint32_t *)&IOPIN1
实际上可能是
(uint32_t *)IOPIN0,(uint32_t *)IOPIN1
取决于您对IOPIN0和IOPIN1的定义方式
lpc2148的IOPIN0宏是
#define IOPIN0 (*((volatile unsigned long *) 0xE0028000))
我在C语言方面没有太多经验。 我知道宏是否指向内存,那么在定义指针数组时不必使用&。 如何知道宏(例如:PORTB,IOPIN0)是引用地址还是值?
答案 0 :(得分:0)
defines for C是这样的:
#if __AVR_ARCH__ >= 100
# define __SFR_OFFSET 0x00
#else
# define __SFR_OFFSET 0x20
#endif
#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
#define PORTB _SFR_IO8(0x05)
这意味着PORTB
扩展为:
// presuming __AVR_ARCH__ >= 100
(*(volatile uint8_t *)(0x05 + 0x00))
已被取消引用,因此需要使用&号来获取地址,即,您将必须编写:
volatile uint8_t * p = &PORTB;
答案 1 :(得分:0)
编写寄存器映射时,通常使用一种使寄存器就像变量一样离开寄存器的方法:
#define REGISTER (*(volatile uint8_t*)0x1234)
其中左边的*
取消指向所指向的地址,这意味着您现在可以像使用任何普通变量一样使用REGISTER
。这就是为什么您必须编写&PORTB
的原因,它在宏扩展后最终显示为&*pointer
。 C(c17 6.5.3.2)保证与pointer
等效:
一元&运算符产生其操作数的地址。 /-/
如果操作数是一元*运算符的结果,则不会对该运算符和&运算符求值,并且结果好像都被省略了
至于是否需要&
,它确实取决于寄存器映射中寄存器的定义方式。无论系统如何,哪个都应作为您可以检查的头文件提供。
作为旁注,您的演员阵容可疑。不需要(uint8_t*)&PORTB
。这表明某些限定词与volatile
和const
不匹配。通常,从指针转到合格指针总是可以的,但反之则不行。
根据您使用IOPIN0
的示例,代码应如下所示:
volatile uint32_t*const portsout [NUM_PORTS] =
{
&IOPIN0, ...
};