如果它们是相同内存映射端口寄存器的引脚,则可以一次读取它们。然后,您可以简单地创建一个新面具:
#define SWITCH_ALL (switch_green | switch_yellow | switch_blue | switch_red)
或者更难阅读,但在其他方面相同:
#define SWITCH_ALL 0x0F
然后,假设你可以摆脱看似多余的 pin_read 功能:
pin_read
uint8_t button_pressed (void) { return (uint8_t) (PORTX & SWITCH_ALL); }
哪里 PORTX 是端口数据寄存器的名称。
PORTX
除了速度更快之外,这还有一个优点,即所有引脚都可以同时读取。
然而 ,你自然需要在某处添加一些按钮去除,或者读取不可靠。
在函数内隐藏端口访问只是一种小而弱的抽象形式。您将面临嵌入式编程中的一般问题,即创建独特且明显反应的数据源的融合。一种方法是在语言层面创建过多的个人名称(在您的情况下,功能) - 这有一个自然的限制,直到维护和测试成为一场噩梦。当发端人离开时,这种系统往往会死亡,至少它们变得不受维护。
而是尝试在业务逻辑方面定义输入的性质 - 在您的情况下,特别是如果它们是级别或转换 - 并创建一种允许您使用运行时地址(某种形式的索引)而不是编译时地址(==函数名称)。当参数在编译时已知并仍然保持打开索引/编程方式时,您总是可以以一种优化等效快速代码的方式组织访问。然后在真实硬件和这些理想化输入之间编写映射,您可以处理诸如去抖动,反转逻辑电平等的事情。
用一个 struct 组织这些信息。
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 }