代码之家  ›  专栏  ›  技术社区  ›  messenger

关于在C语言中重新定义寄存器位字段的提示

  •  3
  • messenger  · 技术社区  · 14 年前

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

    例如,这就是其中一个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的变化无常的近选演员有点恼火。是否需要指定变量接近?

    2 回复  |  直到 14 年前
        1
  •  2
  •   Sparky    14 年前

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

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

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

    然后可以根据需要生成掩码,并分配、读取或测试值。您可以为宏选择更好的名称。

    希望这有帮助。

        2
  •  1
  •   Ernelli    14 年前

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

    union/struct声明位字段的排列方式,然后在声明指向此类结构的指针时指定寻址和访问限制。

    // 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;
      ...
    }
    

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