c - 将 32 位寄存器拆分为可变大小字节

标签 c embedded bit

我想将一个通用寄存器拆分为三个独立的寄存器; 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/

相关文章:

c - 使用递归的基本转换

c++ - 当工件是库且标志影响 C 或 C++ header 时,功能标志/切换

c++ - 修复了带引用的内存布局同步变量

c - 如何在嵌入式应用中使用环形缓冲区并保证完整性

c - 缓冲区中帧的所有权 - C 编程

linux - Ubuntu 64 位还是 32 位?

c - 两个 8 位数字相乘

c - 在多线程程序中访问文件指针时出错

c - Xcode 中 rand() 的奇怪行为

java - Java中BitSet的Set操作的时间复杂度是多少?