尝试在使用按位运算符保持模块性的同时压缩代码
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了尝试在使用按位运算符保持模块性的同时压缩代码相关的知识,希望对你有一定的参考价值。
我正在开发一个嵌入式系统项目,正在读取多个开关,然后根据结果做事。我试图保持这种模块化和抽象化,因此我的每个功能都没有看到任何低级引脚号或引脚读取功能。
一次可能有多个开关,所以我使用按位或|
存储数字,然后使用按位进行比较。我目前只是将读取的引脚冗余转换为可以与按位运算符进行比较的开关值。
这是一种更有效或更好的方法吗?
// physical pins on microcontroller
#define pin_sw_green 5
#define pin_sw_yellow 6
#define pin_sw_blue 7
#define pin_sw_red 8
// switch numbers, allowing bitwise operators to work
#define switch_green 0x01
#define switch_yellow 0x02
#define switch_blue 0x04
#define switch_red 0x08
// store switch press to val
uint8_t button_pressed()
{
uint8_t data;
if (pin_read(pin_sw_red))
data |= switch_red;
//...
if (pin_read(pin_sw_green))
data |= switch_green;
return data;
}
//...
uint8_t button_data = button_pressed();
if (button_data & switch_red)
{
// do things..
如果它们是相同内存映射端口寄存器的引脚,则可以一次读取它们。然后,您可以简单地创建一个新面具:
#define SWITCH_ALL (switch_green | switch_yellow | switch_blue | switch_red)
或者更难阅读,但在其他方面相同:
#define SWITCH_ALL 0x0F
然后,假设你可以摆脱看似多余的pin_read
功能:
uint8_t button_pressed (void)
{
return (uint8_t) (PORTX & SWITCH_ALL);
}
其中PORTX
是端口数据寄存器的名称。
除了速度更快之外,这还有一个优点,即所有引脚都可以同时读取。
但是,您自然需要在某处添加一些按钮去除,否则读取将不可靠。
在函数内隐藏端口访问只是一种小而弱的抽象形式。您将面临嵌入式编程中的一般问题,即创建独特且明显反应的数据源的融合。一种方法是在语言层面创建过多的个人名称(在您的情况下,功能) - 这有一个自然的限制,直到维护和测试成为一场噩梦。当发端人离开时,这种系统往往会死亡,至少它们变得不受维护。
而是尝试在业务逻辑方面定义输入的性质 - 在您的情况下,特别是如果它们是级别或转换 - 并创建一种允许您使用运行时地址(某种形式的索引)而不是编译时地址(==函数名称)。当参数在编译时已知并仍然保持打开索引/编程方式时,您总是可以以一种优化等效快速代码的方式组织访问。然后在真实硬件和这些理想化输入之间编写映射,您可以处理诸如去抖动,反转逻辑电平等的事情。
使用struct
来组织此信息。
typedef struct{
uint8_t green:1;
uint8_t yellow:1;
uint8_t blue:1;
uint8_t red:1;
uint8_t :4; //unused
}switch_t;
switch_t s = {0};
// store switch press to val
void button_pressed(switch_t * s)
{
s->red = pin_read(pin_sw_red);
//...
s->green = pin_read(pin_sw_green);
}
button_pressed(&s);
if(s.red){
//do stuff
}
//...
if(s.green){
//do stuff
}
以上是关于尝试在使用按位运算符保持模块性的同时压缩代码的主要内容,如果未能解决你的问题,请参考以下文章