访问结构和联合中的元素
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.R
、test.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__))
。
我正在为微控制器编写自己的库(头文件)。我想访问下面示例中的元素。我怎样才能做到这一点?
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.R
、test.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__))
。