我正在从事一个嵌入式系统项目,正在读取多个开关,然后根据结果进行操作。我试图保持这种模块化和抽象性,所以我的每个功能都看不到任何低级别的引脚号或引脚读取功能。
一次可能有多个开关关闭,所以我使用位或|
存储数字,然后使用位进行比较。我目前只是冗余地将读取的引脚转换为可以与按位运算符进行比较的开关值。
是更有效或更有效的方法吗?
// 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..
答案 0 :(得分:2)
如果它们是同一内存映射端口寄存器的引脚,则可以一次性读取它们。然后,您可以简单地创建一个新的蒙版:
#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
是端口数据寄存器的名称。
除了速度更快之外,它还具有所有引脚将同时同步读取的优点。
但是,您自然需要在某个位置添加一些按钮的反跳操作,否则读取将不可靠。
答案 1 :(得分:-1)
使用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
}
答案 2 :(得分:-1)
隐藏函数内部的端口访问只是一种小而弱的抽象形式。您将面对嵌入式编程中的一般问题,即创建不同且反应明显的数据源的融合。一种方法是在语言级别上创建过多的单个名称(在您的情况下为函数)-在维护和测试成为噩梦之前,这是一个自然的限制。当发起者离开它们时,此类系统趋向于死亡,至少它们变得不可维护。
相反,请尝试在业务逻辑方面定义输入的性质(在您的情况下,尤其是在进行级别转换时),并创建一种允许您使用运行时地址(某种形式的索引)访问它们的方式)而不是编译时地址(==函数名称)。当参数在编译时已知时,您始终可以以一种优化为等效快速代码的方式来组织访问,并且仍然保持索引/编程方式的开放性。然后在您的实际硬件和这些理想化的输入之间编写一个映射,在其中您可以处理诸如反跳,逻辑电平倒置等问题。