
刚写了一个关于stm32单片机的按键识别的程序。目的,同时识别多个按键,并且不浪费cpu的时间。 关于去抖动,以前以为是在按键的时候,手会抖动。通过程序验证,这个确实是误解。这个应该是防止意外干扰。以我的手按键的速度,单次持续时间小于0.2秒钟。 前提:引脚低电平为按键按下。为每个按键设置3个变量,分别是识别过程的计数器keycnt、识别的结果keystat、可以判定的结果keymod(比如按下、释放、单击、双击、长按等)。 本例 只有单击一种判断,keymod暂时不用。另外考虑,按键判定后,直到松开,不重复判定。具体模式和规则,可根据需要修改。另外要考虑,按键后,要执行的其他动作,是瞬间动作还是长时间动作,比如让灯闪烁,本例没有涉及该步骤。 思路:定时周期内:扫描每个按键的引脚电平,根据预定规则改变对应的计数器;依据计数状态,给出按键结果。 对于具体应用,应进一步人性化。 部分头文件:
相关功能: uint8_t keypress=15; // 去抖动参数,用于计数器参考判定按键单击。定时器间隔为0.01秒。 uint8_t keycnt[keynum]; //计数器 uint8_t keystat[keynum]; //0x00/release;0x01/down; 0x02/press;0x04/up; 0x10 /click; 0x20 /double; 0x40 /keep; uint8_t keymod[keynum]; //定义同keystat,对应bit位置1,则为启动相应功能。 // KEY ![]() void key_init(void) {$ J# O) f' p, b7 ? uint8_t m; p3 Y1 |* ~1 o8 L RCC->APB2ENR|=0x08; //enable PORTB clock! ^9 g# ~# ?, @8 p- I% U/ I" B4 T GPIOB->CRH&=0x0000FFFF; //clean PB12,PB13,PB14,PB15¡£Per 4 bits for one Port¡£ GPIOB->CRH|=0x88880000; //set PB12,PB13,PB14,PB15 GPIOB->CRL&=0xFFF00000; //clean PB0,PB1¡£PB2,PB3 error¡£* i9 b9 }- F. F0 d0 b7 L! i& Z2 r2 m GPIOB->CRL|=0x00008888; //set PB0,PB1¡£PB2,PB3 error¡£ GPIOB->ODR&=0x0FF0; GPIOB->ODR|=0xF00F; for(m=0;m<keynum;m++){ keycnt[m]=0;, t" ^7 C$ F$ P; n keystat[m]=0;. K1 o3 _ r' M. N keymod[m]=0x10;8 E( {' r3 n4 f }/ E" ~- F% v/ B1 m } //循环扫描,在定时中执行- T9 A1 V# L/ [ P2 N8 f: I$ }) o void keyscan(void) {# B' A& Y# G) E3 B, ?$ R: [9 I* n uint8_t k;" J* p, ? S" p# ] for(k=0;k<keynum;k++){ keyone(k);% D' \3 s' \% n) I- E3 G* A } } //识别规则 void keyone(uint8_t nkey)2 \" C0 e+ } `) h2 S: T5 g {$ E B5 o% u, z* ^( J switch(nkey){/ M& }/ R9 z) i9 F* T1 I8 E case 0: if(KEY0==KEYON){# H4 z& {' ~! M8 k+ Z! l4 x if(keycnt[nkey]==keypress){ // keycnt[nkey]=0;//长按视为反复触发按键。 keystat[nkey]=0x02;( y: C- F" ]' F: F ] }else{ keycnt[nkey]++;7 T* g, ^' K8 g/ e# d } }else{3 i+ |2 I" Q, k; ~/ r keycnt[nkey]=0;( S! b; Q; U1 i, v [9 H) n9 | }. I4 Q3 O) E) ?& i4 }3 {5 @2 p& ^- c: D break; ………… } //后续动作,在定时中执行- X+ ~2 P3 c/ ?- O I, ` void keydo(void)* l+ W' I2 h3 }; L/ I" n {, `$ a6 A" a7 Z' _% V8 g if(keystat[0]==0x02){ keystat[0]=0; //reset key after done kset0(); //要执行的动作. D8 U" ?5 E/ |' W& C; B } ……………………* _; m. R( i% f if(keystat[5]==0x02){ keystat[5]=0; //reset key begin done led_flush(2); led_flush(3);2 x/ U' v, `- }/ ]; h+ ? }$ t: l( o" u9 o4 N } |