对于嵌入式C应用程序,我一直使用以下约定来定义GPIO引脚掩码:
‘传统’示例:32位CPU与32位GPIO端口
在GPIO输出寄存器中断言bit5以打开led。
#define BIT5 (1u << 5) //or maybe even just hardcode as 0x20
...
#define PIN_LED_CTRL (BIT5) //LED_CTRL is Pin #5
...
void gpio_set(uint16_t pin_mask) {
GPIO_OUT |= pin_mask;
}
...
//turn the led on
gpio_set(PIN_LED_CTRL);在最近的一个多开发人员嵌入式项目中,一个开发人员选择了以下语法
的替代示例:32位CPU和32位GPIO端口
#define PIN(x) (1u << (x##_PIN_NUM))
...
#define LED_CTRL_PIN_NUM (5)
...
void gpio_set(uint16_t pin_mask) {
GPIO_OUT |= pin_mask;
}
...
//turn the led on
gpio_set(PIN(LED_CTRL));没有真正清楚地解释为什么选择这一办法。与所有文档化的代码一样,它看起来很神秘,以至于“cleary”可以保证它的实现。当然,开发人员知道一些我不知道的事情。在这种情况下,这家伙是一个聪明的饼干来自CPU驱动世界。
反对
我一点也不喜欢“alt”的方法。它看起来太可爱了,为了自己的利益。但我能提出的唯一理由是:
但在我看来,这似乎是一种抱怨;所有这些都不是反对使用“alt”方法的真正理由。
问题
为什么有人会使用'alt‘方法呢?这可能是桌面驱动程序中注册表使用中的一种方式吗?
是否有任何常见的嵌入式MCU库、替代目标或编程语言使用这种“alt”方法?
谢谢!
*在一天结束时,我可能会坚持“它看起来很奇怪”:)。
发布于 2014-02-23 10:01:59
这两种方法几乎是一样的,只是风格不同,但问题是相同的。
通常,引脚不是由位数定义的,您还需要知道端口。
因此,在更改端口时,不仅需要修改定义,还需要修改代码。
#define PIN_LED_CTRL (BIT5) //LED_CTRL is Pin #5
...
void gpio_set_port2(uint16_t pin_mask) {
GPIO2_OUT |= pin_mask;
}
...
//turn the led on
gpio_set_port2(PIN_LED_CTRL);我只需要定义一次引脚,所有不同的依赖项都是由宏或函数构建的。
#define HW_SPI_CLOCK 2,5 // uses port2,bit5
#define HW_RESET_EXT 4,3 // uses port4,bit3然后,我使用一些宏来定义获取端口方向、pushPull和其他寄存器。
这些宏几乎不依赖于平台和工具链。
/**
* Generic GH-Macros
*/
#define PASTE2(a,b) a##b
#define PASTE3(a,b,c) a##b##c
#define __PASTE3(a,b,c) PASTE3(a,b,c)
#define PASTE4(a,b,c,d) a##b##c##d
#define PASTE6(a,b,c,d,e,f) a##b##c##d##e##f
#define __PASTE6(a,b,c,d,e,f) PASTE6(a,b,c,d,e,f)
#define GH_PORT(port,pin) port
#define GH_PIN(port,pin) pin
#define GPIO_PIN(gh) __PASTE6(FIO,GH_PORT(gh),PIN_bit.P,GH_PORT(gh),_,GH_PIN(gh))
#define GPIO_DIR(gh) __PASTE6(FIO,GH_PORT(gh),DIR_bit.P,GH_PORT(gh),_,GH_PIN(gh))发布于 2014-02-23 06:02:08
假设"Alternative“示例中有一个错误(在最后一行中,您指定了"LED_CTRL",它没有定义).我假设您的意思是"LED_CTRL_PIN_NUM"),那么我相信这两个示例将产生相同的机器代码。所以,在这两种选择之间。这只是一个风格偏好的问题。(第二个示例中的##只是一个嵌入的注释。)
就我个人而言,我会使用一种完全不同的方法。我会使用内置的位字段构造来修改一个按位排列的字段,这样编译器就可以决定什么是最有效的方法。例子如下:
struct {
unsigned int :4, LED_CTRL:1, :27;
} GPIO_OUT;
...
GPIO_OUT.LED_CTRL = 1;注意,":4“和":27”指的是寄存器中的其他位.您可能希望映射整个I/O寄存器,而不仅仅是其中的一部分。
发布于 2014-02-23 08:12:50
Bitfield: SGeorgiades在上面给出了一个有风险的问题的答案*
如果您正在使用C Bitfield来定义您的引脚,请非常小心。
对于GCC/C11,我将使用以下位域语法(如果我使用它)
struct gpio_out {
int b0 : 1;
int led_ctrl : 1;
....
int b30 : 1;
int b31 : 1;
} __attribute__((packed));Notes
*如果我弄错了,请纠正我。
https://stackoverflow.com/questions/21964192
复制相似问题