假设我在内存中映射了两个地址:
#define MY_REGISTER_1 (*(volatile uint8_t *)(0x1B))
#define MY_REGISTER_2 (*(volatile uint8_t *)(0x18))
我想创建一个在一个寄存器中设置位的函数,如下所示:
set_bit_low(MY_REGISTER_1, 3);
如下声明我的函数是否正确?
void set_bit_low(uint8_t, uint8_t);
假设我在内存中映射了两个地址:
#define MY_REGISTER_1 (*(volatile uint8_t *)(0x1B))
#define MY_REGISTER_2 (*(volatile uint8_t *)(0x18))
我想创建一个在一个寄存器中设置位的函数,如下所示:
set_bit_low(MY_REGISTER_1, 3);
如下声明我的函数是否正确?
void set_bit_low(uint8_t, uint8_t);
让我们从您的定义开始:
#define MY_REGISTER_1 (*(volatile uint8_t *)(0x1B))
取消引用 address 处的八位字节0x1b
,因此它表示内存映射寄存器的内容,而不是它的位置。最好有一个带有寄存器位置的宏:
#define REGISTER_1 ((volatile uint8_t *) (0x1B)) /* Substitute _1 for some meaningful name */
然后您可以随意取消引用,您可以按如下方式声明您的函数:
void set_bit_low(volatile uint8_t *register, uint8_t bitpos);
/* Use like this: */
set_bit_low(REGISTER_1, 3);
以下应该是声明函数的正确方法:
void set_bit_low(uint8_t *, uint8_t);
不,您想更改内存位置的内容。因此,您必须将其作为指针传递。
函数头应该喜欢
void set_bit_low(uint8_t *, uint8_t);
该功能应该喜欢
void set_bit_low(uint8_t *my_reg, uint8_t bit_location)
{
// do your bit manupulation here by assigning to *my_reg.
}
这个:
#define MY_REGISTER_1 (*(volatile uint8_t *)(0x1B))
产生(内存映射)寄存器中值的副本。所以这:
set_bit_low(MY_REGISTER_1, 3);
将该副本传递给set_bit_low()
. 然后,您可以设置副本中的位(这将是函数的本地)。如果要在寄存器中设置值的位,则必须传递地址本身:
#define MY_REGISTER_1_ADDR 0x1b
说得通?
许多答案已经提到将MY_REGISTER_1
您定义它的方式传递给函数将导致发送它的副本。但是,微控制器中经常使用的实际解决方案与其他答案所暗示的不同。
通常,寄存器是按照您定义它们的方式定义的,即
#define MY_REGISTER_1 (*(volatile uint8_t *)(0x1B))
#define MY_REGISTER_2 (*(volatile uint8_t *)(0x18))
没关系。但是,如果您希望它们被该函数更改,则应注意不要将它们传递给该函数。对此类寄存器执行位操作的最简洁方法是通过宏。例如:
#define SET_BIT_LOW(reg, n) (reg) &= (uint8_t)~(1 << (n))
#define SET_BIT_HIGH(reg, n) (reg) |= (uint8_t)(1 << (n))
这不仅正确地操作了实际的寄存器,而且还具有避免函数调用的额外好处。如果这些是函数,n
则将是未知的,因此必须以任何一种方式以及(相对)昂贵的函数调用来完成 shift 和 not 操作。使用宏,编译器已经可以计算出右边的表达式 ifn
是一个常数,并用 1 或 2 条指令替换该行。