
刚写了一个关于stm32单片机的按键识别的程序。目的,同时识别多个按键,并且不浪费cpu的时间。 关于去抖动,以前以为是在按键的时候,手会抖动。通过程序验证,这个确实是误解。这个应该是防止意外干扰。以我的手按键的速度,单次持续时间小于0.2秒钟。 前提:引脚低电平为按键按下。为每个按键设置3个变量,分别是识别过程的计数器keycnt、识别的结果keystat、可以判定的结果keymod(比如按下、释放、单击、双击、长按等)。 本例 只有单击一种判断,keymod暂时不用。另外考虑,按键判定后,直到松开,不重复判定。具体模式和规则,可根据需要修改。另外要考虑,按键后,要执行的其他动作,是瞬间动作还是长时间动作,比如让灯闪烁,本例没有涉及该步骤。 思路:定时周期内:扫描每个按键的引脚电平,根据预定规则改变对应的计数器;依据计数状态,给出按键结果。 对于具体应用,应进一步人性化。 部分头文件:
相关功能: uint8_t keypress=15; // 去抖动参数,用于计数器参考判定按键单击。定时器间隔为0.01秒。+ G/ }8 a6 k/ P4 j0 g; F& E 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) { uint8_t m;, u2 z3 L, e( ~ RCC->APB2ENR|=0x08; //enable PORTB clock9 y" J3 `6 y9 I# V GPIOB->CRH&=0x0000FFFF; //clean PB12,PB13,PB14,PB15¡£Per 4 bits for one Port¡£- [# g* R2 o9 Y) p& P+ } GPIOB->CRH|=0x88880000; //set PB12,PB13,PB14,PB15" r b8 \+ T: M# u GPIOB->CRL&=0xFFF00000; //clean PB0,PB1¡£PB2,PB3 error¡£ GPIOB->CRL|=0x00008888; //set PB0,PB1¡£PB2,PB3 error¡£ GPIOB->ODR&=0x0FF0;! V% H5 x1 H$ m& I! \ GPIOB->ODR|=0xF00F;( F5 ~8 h- I1 v B # {2 o' m. _' ^. D+ G, `1 w for(m=0;m<keynum;m++){ keycnt[m]=0;& g) V) K3 e+ T$ s# L" A keystat[m]=0;; Y e* r; M7 X" Z# f keymod[m]=0x10;) O' ~3 h; h3 ~8 N2 D4 e1 Q }( z* ^1 I1 I- I2 b4 B } //循环扫描,在定时中执行! M% r0 X' j( S7 z, N9 ^$ m/ A8 b void keyscan(void): x2 F! b- S, k {* u1 n1 e k @0 k uint8_t k; for(k=0;k<keynum;k++){ keyone(k);7 ^2 @% o. g" V; R3 i7 A% ] }! ]) f" b2 h j) Z } //识别规则 void keyone(uint8_t nkey) {+ C) a0 M( Z3 ^0 }+ c q" ? switch(nkey){6 R; t6 V7 o; q7 z case 0: if(KEY0==KEYON){. y: u& V$ `+ t B if(keycnt[nkey]==keypress){ // keycnt[nkey]=0;//长按视为反复触发按键。 keystat[nkey]=0x02; j9 g' Q( {! c4 i1 W+ _0 \ }else{* Q5 E; v% l6 |+ J9 C9 [; s' [2 a keycnt[nkey]++;) s, E' Y4 e/ ]4 Q. } f! Z } }else{ keycnt[nkey]=0;$ j, A- z2 v+ k: n/ i5 I5 g } break; ………… } //后续动作,在定时中执行 void keydo(void) {- D, X! M. A! H: y+ N if(keystat[0]==0x02){& }; e5 M7 B6 E) w3 S+ N keystat[0]=0; //reset key after done7 D; I" t$ a5 h% d* l kset0(); //要执行的动作6 s: A- g2 u% y7 d/ y) h }" l* X, x! x* k1 {8 [1 C …………………… if(keystat[5]==0x02){ keystat[5]=0; //reset key begin done1 g" ^! ^% J0 j H$ k led_flush(2); led_flush(3); } } |