在 C 中重新定义寄存器位域的技巧

发布于 2024-08-28 05:25:09 字数 1065 浏览 12 评论 0原文

我正在努力想出一种干净的方法来重新定义一些寄存器位字段,以便在我正在使用的芯片上使用。

例如,CAN 配置寄存器之一的定义如下:

extern volatile near unsigned char       BRGCON1;
extern volatile near struct {
  unsigned BRP0:1;
  unsigned BRP1:1;
  unsigned BRP2:1;
  unsigned BRP3:1;
  unsigned BRP4:1;
  unsigned BRP5:1;
  unsigned SJW0:1;
  unsigned SJW1:1;
} BRGCON1bits;

这些定义都没有多大帮助,因为我需要如下所示分配 BRP 和 SJW:

struct
{
    unsigned BRP:6;
    unsigned SJW:2;
} GoodBRGbits;

以下是我所做的两次尝试:

尝试 #1 :

union
{
    byte Value;
    struct
    {
        unsigned Prescaler:6;
        unsigned SynchronizedJumpWidth:2;
    };    
} BaudRateConfig1 = {NULL};
BaudRateConfig1.Prescaler = 5;
BRGCON1 = BaudRateConfig1.Value;

尝试#2:

static volatile near struct
{
    unsigned Prescaler:6;
    unsigned SynchronizedJumpWidth:2;
} *BaudRateConfig1 = (volatile near void*)&BRGCON1;
BaudRateConfig1->Prescaler = 5;

是否有任何“更干净”的方法来完成我想做的事情?另外,我对尝试 #2 中铸造附近的不稳定感到有点恼火。是否有必要指定一个变量是near?

I am struggling trying to come up with a clean way to redefine some register bitfields to be usable on a chip I am working with.

For example, this is what one of the CAN configuration registers is defined as:

extern volatile near unsigned char       BRGCON1;
extern volatile near struct {
  unsigned BRP0:1;
  unsigned BRP1:1;
  unsigned BRP2:1;
  unsigned BRP3:1;
  unsigned BRP4:1;
  unsigned BRP5:1;
  unsigned SJW0:1;
  unsigned SJW1:1;
} BRGCON1bits;

Neither of these definitions is all that helpful, as I need to assign the BRP and SJW like the following:

struct
{
    unsigned BRP:6;
    unsigned SJW:2;
} GoodBRGbits;

Here are two attempts that I have made:

Attempt #1:

union
{
    byte Value;
    struct
    {
        unsigned Prescaler:6;
        unsigned SynchronizedJumpWidth:2;
    };    
} BaudRateConfig1 = {NULL};
BaudRateConfig1.Prescaler = 5;
BRGCON1 = BaudRateConfig1.Value;

Attempt #2:

static volatile near struct
{
    unsigned Prescaler:6;
    unsigned SynchronizedJumpWidth:2;
} *BaudRateConfig1 = (volatile near void*)&BRGCON1;
BaudRateConfig1->Prescaler = 5;

Are there any "cleaner" ways to accomplish what I am trying to do? Also I am slightly annoyed about the volatile near casting in Attempt #2. Is it necessary to specify a variable is near?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

涫野音 2024-09-04 05:25:09

就我个人而言,出于可移植性的原因,我尽量避免使用位字段。相反,我倾向于使用位掩码,以便我可以明确控制使用哪些位。

例如(假设位顺序正确)...

#define BRP0  0x80
#define BRP1  0x40
#define BRP2  0x20
#define BRP3  0x10
#define BRP4  0x08
#define BRP5  0x04
#define SJW0  0x02
#define SJW1  0x01

然后可以适当地生成掩码并分配或读取或测试值。您可以为宏选择更好的名称。

希望这有帮助。

Personally, I try to avoid using using bit fields for portability reasons. Instead, I tend to use bit masks so that I can explicitly control which bits are used.

For example (assuming the bit order is correct) ...

#define BRP0  0x80
#define BRP1  0x40
#define BRP2  0x20
#define BRP3  0x10
#define BRP4  0x08
#define BRP5  0x04
#define SJW0  0x02
#define SJW1  0x01

Masks can then be generated as appropriate and values assigned or read or tested. Better names for the macros can be picked by you.

Hope this helps.

樱花坊 2024-09-04 05:25:09

我建议您不要将位域声明与硬件寄存器的寻址混淆。

您的联合/结构声明了位域的排列方式,然后在声明指向此类结构的指针时指定寻址和访问限制。

// foo.h
// Declare struct, declare pointer to hw reg

struct com_setup_t {
  unsigned BRP:6;
  unsigned SJW:2;
};

extern volatile near struct com_setup_t *BaudRateConfig1;

// foo.c
// Initialise pointer

volatile near struct com_setup_t *BaudRateConfig1 = 
(volatile near struct com_setup_t *)0xfff...;

// access hw reg
foo() {
  ...
  BaudRateConfig1->BRP = 3;
  ...
}

关于近/远,我假设默认值为近,除非指定远,除非您可以使用编译器开关将默认指针大小设置为远。

I suggest that you dont mix up the bitfield declaration with the adressing of the hardware register.

Your union/struct declares how the bitfields are arranged, then you specify addressing and access restrictions when declaring a pointer to such a structure.

// foo.h
// Declare struct, declare pointer to hw reg

struct com_setup_t {
  unsigned BRP:6;
  unsigned SJW:2;
};

extern volatile near struct com_setup_t *BaudRateConfig1;

// foo.c
// Initialise pointer

volatile near struct com_setup_t *BaudRateConfig1 = 
(volatile near struct com_setup_t *)0xfff...;

// access hw reg
foo() {
  ...
  BaudRateConfig1->BRP = 3;
  ...
}

Regarding near/far I assume that the default is near unless far is specified, unless you can set the default pointer size to far using compiler switches.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文