|
按键扫描时 所有位输出置0 P46/P13/P15设为双向弱上拉并置1 把段输出设为0xFE,并检测P46/P13有没有拉低,有就是key3/key8被按下 |
|
程序写了一遍,水平有限,请指教 流程上往下,按键扫描从循环数码管输出中插入 bit key_service_Lock=0; //循环标志位,禁止连续扫描 uchar KeySec = 0; //按键编号 uchar KeyTimeCnt=0; //按键去抖动延时计数器 uchar key_service_tmp; while(1) { void Reuse_time_sharing() //复用驱动数码管 此函数通用定时器标位控制,1MS循环一次,每次约15MS { if(Reuse) { Reuse=~Reuse; Reuse_count++; switch(Reuse_count) { case 1 : //DS1_1 第一个数码管个位 P05=0; //关闭上一个输出位选 if(!key_service_Lock) //循环标志位0,进入扫描按键 key_select(); //扫描按键函数 P2=Digital_tube_Segment_program_123[Energy_TXD(Ion_B,1)]; //输出段选 P03=1; //打开位选 break; case 2 : //DS1_10 P03=0; if(!key_service_Lock) key_select(); P2=Digital_tube_Segment_program_123[Energy_TXD(Ion_B,1)]; P04=1; break; case 3 : //DS2_1 P04=0; if(!key_service_Lock) key_select(); P2=Digital_tube_Segment_program_123[Energy_TXD(Ion_B,1)]; P02=1; break; case 4 : //DS2_10 P02=0; if(!key_service_Lock) key_select(); P2=Digital_tube_Segment_program_123[Energy_TXD(Ion_B,10)]; P47=1; break; case 5 : //DS3_1 P47=0; if(!key_service_Lock) key_select(); P2=Digital_tube_Segment_program_123[Energy_TXD(Ion_A,1)]; P01=1; break; case 6 : //DS3_10 P01=0; if(!key_service_Lock) key_select(); P2=Digital_tube_Segment_program_123[Energy_TXD(Ion_A,10)]; P00=1; break; case 7 : //DS4_1 time P00=0; if(!key_service_Lock) key_select(); P2=Digital_tube_Segment_program_456[Energy_TXD(Time_MIN,1)]; P37=1; break; case 8: //DS4_10 time P37=0; if(!key_service_Lock) key_select(); P2=Digital_tube_Segment_program_456[Energy_TXD(Time_MIN,10)]; P41=1; break; case 9 : //DS5_1 P41=0; if(!key_service_Lock) key_select(); P2=Digital_tube_Segment_program_456[Energy_TXD(Heat_B,1)]; P36=1; break; case 10 : //DS5_10 P36=0; if(!key_service_Lock) key_select(); P2=Digital_tube_Segment_program_456[Energy_TXD(Heat_B,10)]; P43=1; break; case 11 : //DS6_1 P43=0; if(!key_service_Lock) key_select(); P2=Digital_tube_Segment_program_456[Energy_TXD(Heat_A,1)]; P45=1; break; case 12: //DS6_10 P45=0; if(!key_service_Lock) key_select(); P2=Digital_tube_Segment_program_456[Energy_TXD(Heat_A,10)]; P44=1; break; case 13 : //D1~D8 P44=0; if(!key_service_Lock) key_select(); if(Ion_mode==0) P2=0xfb; else if(Ion_mode==1) P2=0xfd; else P2=0xfe; P11=1; break; case 14 : //D19~D16 P11=0; if(!key_service_Lock) key_select(); if(start_Time) P2=0xf7; else P2=0xff; P42=1; break; case 15 : //D17~D21 P42=0; if(!key_service_Lock) key_select(); P05=1; break; default:break; } if(Reuse_count>=15) Reuse_count=0; } } } //大循环到止 void key_select() //按键扫描函数 { uchar i; Bidirectional_IO(); //P46,P13,P15 设用准双口 for(i=1;i<=8;i++) { switch(i) //按键服务状态切换 { case 1: P2=0x7f; //扫描按键 复用IO输出O _nop_(); //这里不加空操作,会读不到 _nop_(); if(P13==0) //判断IO是否拉低 {KeySec =7; key_service_Lock=~key_service_Lock;return;} //缓存对应按键 ,循环标志位取反,放开TO内部函数 else if(P46==0) //判断IO是否拉低 {KeySec =12; key_service_Lock=~key_service_Lock;return;} //缓存对应按键 ,循环标志位取反, break; case 2: P2=0xbf; if(P13==0) {KeySec =9; key_service_Lock=~key_service_Lock;return;} else if(P46==0) {KeySec =1;key_service_Lock=~key_service_Lock;return;} break; case 3: P2=0xdf; if(P13==0) {KeySec =8; key_service_Lock=~key_service_Lock;return;} else if(P46==0) {KeySec =3; key_service_Lock=~key_service_Lock;return;} break; case 4: P2=0xef; if(P13==0) {KeySec =5; key_service_Lock=~key_service_Lock;return;} else if(P15==0) {KeySec =18; key_service_Lock=~key_service_Lock;return;} else if(P46==0) {KeySec =14; key_service_Lock=~key_service_Lock;return;} break; case 5: P2=0xf7; if(P13==0) {KeySec =6; key_service_Lock=~key_service_Lock;return;} else if(P15==0) {KeySec =17; key_service_Lock=~key_service_Lock;return;} else if(P46==0) {KeySec =4; key_service_Lock=~key_service_Lock;return;} break; case 6: P2=0xfb; if(P15==0) {KeySec =15; key_service_Lock=~key_service_Lock;return;} else if(P46==0) {KeySec =2; key_service_Lock=~key_service_Lock;return;} break; case 7: P2=0xfd; if(P15==0) {KeySec =19; key_service_Lock=~key_service_Lock;return;} else if(P46==0) {KeySec =13; key_service_Lock=~key_service_Lock;return;} break; case 8: P2=0xfe; if(P15==0) {KeySec =16; key_service_Lock=~key_service_Lock;return;} else if(P46==0) {KeySec =11; key_service_Lock=~key_service_Lock;return;} break; default: break; } } High_IO(); //P46,P13,P15 设用高阻 } void TM0_Isr() interrupt 1 //定时器0中断 { if(!Reuse) Reuse=~Reuse; if(key_service_Lock) //循环标志位取反,进入中断 { KeyTimeCnt++; if(KeyTimeCnt>=20) //大于20Ms { P0&=0xc0; //拉低循环过程中位选 P11=0; //拉低循环过程中位选 P3&=0x1f; //拉低循环过程中位选 P4&=0x43; //拉低循环过程中位选 KeyTimeCnt=0; key_service_Lock=~key_service_Lock; ////循环标志位取反,防止进入中断,开放循环扫描 key_service_tmp=KeySec; //缓存上次扫描结果 key_select(); //再次扫描 if(key_service_tmp==KeySec) //对比扫描结果 { key_service(); //调用按键服务程序 } //else KeySec=0; P0|=0xc0; P11=1; P3|=0x1f; P4|=0x43; } } } 请问怎么优化,还有_nop_(); 那里原因,谢谢 |
happy2058 发表于 2022-4-12 10:30 这与短按和长按没有任何关系。如果以入门级水平写按键程序就另当别论了。 |
|
在扫描显示的“消隐”期间查键即可。 “消隐”:扫显时,在切换显示值之前,先关显示(让LED的COM失效即可),而后再切换显示内容,这时由于LED已关闭,所以不会产生乱显,之后再打开显示。这段时间就是“消隐”期。 |
wulin 发表于 2022-4-12 10:14 长按的时候???一直不亮 |
wulin 发表于 2022-4-12 10:14 那也是,谢谢了 |
happy2058 发表于 2022-4-12 09:34 检测按键的时候,如有键按下,IO口电平会被拉低,灯是要灭的。但这个过程只有几微秒,你能察觉出来? |
wulin 发表于 2022-4-12 06:59 我有点疑惑,检测的时候,IO电平会拉低,灯不是灭了吗? |
happy2058 发表于 2022-4-12 01:05 按你现有的条件可以做到用26个IO 复用驱动6个两位数码管,21个LDE ,18个按键。不过电路连接关系要改。把12个数码管看成96个LED,加上21个LDE共117,或看成15个数码管,有15个共用阳极,分别各接一个按键,另3个IO各接一个按键。
|
lkc8210 发表于 2022-4-11 23:52 2015的 15W408S 查了手册,IO可选4种态度 |
188610329 发表于 2022-4-11 23:38 嗯,感谢了, 按你的方法,循环时间快。不用单独判断 |
|
是2015年的产品还是15年前的产品? 用什么型号的单片机? 有高阻IO设定时吗? 如果有就好办了 显示的时候P46/P13/P15设为高阻 按键就不影响显示 按键扫描时 所有位输出置0 P46/P13/P15设为双向弱上拉并置1 把段输出设为0xFE,并检测P46/P13有没有拉低,有就是key3/key8被按下 把段输出设为0xFD,并检测P46/P13/P15有没有拉低,有就是key5/key14/key18被按下 ... 把各段都拉低后还原要显示的段输出,还原位输出,P46/P13/P15设为高阻 |
happy2058 发表于 2022-4-11 22:53 共阳的数码管 和 按键复用时 按键检测端的IO 内部寄存器置1,外部通过47K~100K 电阻下拉到地, IO模式设置为高阻或者开漏, 检测 外部电平, 高电平表示按键被按下,低电平表示按键没有被按下。 |
188610329 发表于 2022-4-11 22:26 我这是共阳的,按你的方法,按下去的时候不是要把 位选拉低吗?那不影响数码管显示吗?方便的话,提供一个图,谢谢 |
| 只要软件能做到“分时复用”,没有问题,IO复用多了去了。 |
|
按键复用 接数码管的 位, 不要接数码管的 段。 在点亮某个 位 的数码管时 顺便判断 和该位共用的 按键有没有 被按下即可。 |
Y_G_G 发表于 2022-4-11 21:48 写错了,是6个双位的数码管, |
Y_G_G 发表于 2022-4-11 21:48 15年的产品了,库存货想自己改掉。原理图是对着画的 |
|
一个数字的数码,com是短路的,接一个就行了,不用接两个引脚的 6个数码管只会用到8+6=14个引脚 不知道你是怎么用到26个IO的? 这么多的按键,为什么不用ADC 四多的STC8A8K有59个IO和上拉电阻,为什么不用? |