访问结构和联合中的元素

Access element in struct and union

我正在为微控制器编写自己的库(头文件)。我想访问下面示例中的元素。我怎样才能做到这一点?

myLibrary.h:

#include <stdint.h>

struct PWR_CR_tag {
    union {
        uint32_t R;
        struct {
            uint32_t VOS:1;
            uint32_t FPDS:1;
            uint32_t DBP:1;
            uint32_t PLS:3;
            uint32_t PVDE:1;
            uint32_t CSBF:1;
            uint32_t CWUF:1;
            uint32_t PDDS:1;
            uint32_t LPDS:1;
        } B;
    } PWR_CR;
};

#define PWR_CR (*(volatile struct PWR_CR_tag *) 0x40007004)

然后在 main.c 中(给出 ERROR):

#include <stdio.h>
#include <myLibrary.h>

int main() {
    PWR_CR test; // this gives ERROR expected ‘;’ before ‘test’

    test.R = // write to address 0x40007004
    test.B.VOS = // write to address 0x40007004 with offset 0xE (=0x40007012)

    return 0;
}

我怎样才能做到 PWR_CR test; 不会失败,并且我将能够访问像 test.Rtest.B.VOS、...

这样的寄存器

所以,我正在努力实现这样的目标:

// led struct
GPIO_InitTypeDef GPIO_LedInitStructure;

// configure led
GPIO_LedInitStructure.GPIO_Pin = ...; 
GPIO_LedInitStructure.GPIO_Mode = ...;
GPIO_LedInitStructure.GPIO_Speed = ...; // for example GPIO_Speed_2Mhz
GPIO_LedInitStructure.GPIO_OType = ...;
GPIO_LedInitStructure.GPIO_PuPd = ...;

这取决于您的控制器架构。 16 位机器上的地址:

#include <stdint.h>

struct PWR_CR_tag {
    union {
        uint32_t R;                 //Addr. 0x40007004
        struct {
            uint32_t VOS;           //Addr. 0x40007014
            uint32_t FPDS;          //Addr. 0x40007012
            uint32_t DBP;           //Addr. 0x40007010
            uint32_t PLS;           //Addr. 0x4000700E
            uint32_t PVDE;          //Addr. 0x4000700C
            uint32_t CSBF;          //Addr. 0x4000700A
            uint32_t CWUF;          //Addr. 0x40007008
            uint32_t PDDS;          //Addr. 0x40007006
            uint32_t LPDS;          //Addr. 0x40007004
        } B;
    } PWR_CR;
};

#define PWR_CR (*(volatile struct PWR_CR_tag *) 0x40007004)

不确定你想用 define 实现什么(注意,它与你试图在 main 中声明的变量类型同名(难怪它不能编译) 因为它扩展为:

//PWR_CR test;
//expanded to:
(*(volatile struct PWR_CR_tag *) 0x40007004) test;

但是如果你改变define的名称,你可以使用它作为:

#define PWR_test (*(volatile struct PWR_CR_tag *) 0x40007004)

//no need to declare a variable 

PWR_test.PWR_CR.R = 2;
PWR_test.PWR_CR.B.VOS = 1;

希望这就是你想要的..

首先,您声明了一个名为 PWR_CR 的联合和一个名为 PWR_CR 的宏,这会发生冲突。不要那样做。
我们可以通过删除结构 PWR_CR_tag 并将其声明为联合 PWR_CR_tag 来修复您的一些代码,从而从 PWR_CR_tag 结构中删除 PWR_CR 成员。
我们也可以将变量声明移动到宏并使用 variable.R = smth; 与您当前的代码:

union PWR_CR_tag {
        uint32_t R;
        struct {
            uint32_t VOS:1;
            uint32_t FPDS:1;
            uint32_t DBP:1;
            uint32_t PLS:3;
            uint32_t PVDE:1;
            uint32_t CSBF:1;
            uint32_t CWUF:1;
            uint32_t PDDS:1;
            uint32_t LPDS:1;
        } B;
};

#define test (*(volatile union PWR_CR_tag *)0x40007004)

int main() {
    test.R = 0x00; // write to address 0x40007004
    test.B.VOS = 0x01 // write to address 0x40007004 with offset (at least) 0xE (=0x40007012)    (or offset WORD_SIZE-(at least) 0xE depending on machine endianess and padding bytes)
    return 0;
}

就好像它是一个全局变量一样。但是我肯定会删除宏并声明一个全局 const 指针变量到 volatile object 以获得更清晰的代码并通知程序员他正在取消引用指针:

static volatile union PWR_CR_tag * const PWR_CR = (void*)0x40007004;

int main() {
    PWR_CR->R = 0; // write to address 0x40007004
    PWR_CR->B.VOS = 1; // write to address 0x40007004 with offset 0xE (=0x40007012)
    return 0;
}

PS。但是你提到了 GPIO_InitTypeDef,它是在 stm32 hal 库中声明的类型。你好像知道STM32和hal headers,为什么不像hal那样用PWR->CR,比如here?您将减少错误,您将轻松地将您的程序移动到另一条 stm32 线路,从而加快编程速度?

#include "stm32l0xx.h"
int main() {
    PWR->CR = 0x00;
    MODIFY_REG(PWR->CR, PWR_CR_VOS, 0b10);
    // or better:
    LL_PWR_SetRegulVoltageScaling(0b10);
    return 0;
}

说到错误,我猜 VOS 是 2 位而不是一位(至少在 stm32l1 和 l0 上),如果是 stm32,我认为你的结构需要从结构的开头开始填充位,希望你知道字节顺序您的目标平台并考虑到这一点,编译器可能会在位域之间插入任意数量的填充字节,因此您只能希望它不会,声明具有 uint32_t 类型的位域不符合标准,除非 uint32_t 是您平台上的 "implementation-defined type for bitfields",我希望您在该结构上使用带有 gcc 编译器的 __attribute__((__packed__))