我想将一个通用寄存器拆分为三个独立的寄存器; 2 个 8 位寄存器和 1 个 16 位寄存器。这是我正在使用的方法,但我认为它可能是错误的。
typedef struct {
volatile uint8_t reg_0;
volatile uint8_t reg_1;
volatile uint16_t reg_2;
} reg_split;
#define REG_BASE (0xA040000C)
#define REG ((reg_split *)REG_BASE)
这就是我访问寄存器的方式:
REG->reg_0 = 0xFF;
这是错误的方法还是他们的解决方案更干净?
最佳答案
对于像这样的各种内存映射来说,最重要的是验证 C 代码是否产生了预期的结果。您必须考虑填充和对齐。
您的示例中存在一些小问题:
- 始终确保代码中的所有十六进制文字都具有有意义的类型。在您的情况下,
0xA040000C
是有符号类型,很可能是unsigned int
。但是,如果您使用像0x5040000C
这样的文字,它将是(有符号)int
类型。在大多数系统上,拥有签名地址是没有意义的。 “马虎类型”可能会导致各种微妙的错误,特别是与各种形式的整数提升结合使用时。 - 将 volatile 限定符移出结构体。如果可能,请避免在结构内部使用类型限定符 - 它们通常会导致大量类型兼容性问题。
- 硬件寄存器的指针表示法有点特殊。最常见的风格是将寄存器视为声明的变量。
考虑到上述评论,您的代码可以重写为:
typedef struct {
uint8_t reg_0;
uint8_t reg_1;
uint16_t reg_2;
} reg_split;
#define REG_BASE (0xA040000Cu)
#define REG (*(volatile reg_split *)REG_BASE)
_Static_assert(sizeof(reg_split) == 4, "Unwanted padding detected");
...
REG.reg_0 = 0xFF;
关于c - 将 32 位寄存器拆分为可变大小字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39388419/