我刚开始做一些 C(来自 Java)。我试图弄清楚该语言基于定义名称的条件方法是什么。
例如我有一个巨大的头文件,我不能(不应该)用很多定义来编辑它。
#define GPIO_OTYPER_OT_0 ((uint32_t)0x00000001)
#define GPIO_OTYPER_OT_1 ((uint32_t)0x00000002)
#define GPIO_OTYPER_OT_2 ((uint32_t)0x00000004)
#define GPIO_OTYPER_OT_3 ((uint32_t)0x00000008)
#define GPIO_OTYPER_OT_4 ((uint32_t)0x00000010)
#define GPIO_OTYPER_OT_5 ((uint32_t)0x00000020)
等等;
我想创建一个函数/声明(或解决方案的任何内容)来作用于定义的 _# 部分。
(伪代码)
void initialize(int X) {
GPIOA->MODER |= GPIO_MODER_MODER%X_5;
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_%X;
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR%X;
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR5;
GPIOA->ODR |= GPIO_ODR_ODR_%X;
}
其中 %X 是 int X
我能想到的就是每个 X 的 switch 语句,但 X 的范围很大,所以源文件会很大。
编辑: https://github.com/espruino/Espruino/blob/master/targetlibs/stm32f4/lib/stm32f411xe.h 是头文件。
最佳答案
使用ST的GPIO抽象层,可引用here .值得注意的是,参见 GPIO_InitTypeDef
这为您提供了上述操作的结构,并且 GPIO_Init
这实际上会做你想做的。初始化结构将引脚作为位掩码,所以正如@artless noise 在评论中建议的那样,你可以做 1<<X
创建你的面具。所有特定于 MCU 的行为和寄存器映射都隐藏在您的代码之外。
如果您正在尝试实现自己的驱动层作为练习,或者因为您认为 ST 库不是很好,那么我仍然会看看他们是如何实现的 GPIO_Init
在C file .他们使用移位,但您会注意到在处理寄存器时,它并不总是像 1<<X
那样容易。 (不过,请注意,对于它们的配置结构, 总是那么简单)。一些寄存器的每个引脚都有多个位(模式:2 位,拉取配置:2 位,替代功能:4 位,拆分为多个寄存器)。
编辑:我并不是建议添加更多您还没有的库。您在其中引用头文件的库/代码库已经包含 ST 的外设库,因此(对我而言)使用它很有意义。
关于基于#define 名称的条件语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38817767/