基于51与adc0808的无冲键盘设计福建农林大学机电工程学院陈延联在一次瑞萨的研讨会中得知未来的按键趋势为与ADC结合,仔细想想很有道理也十分有趣,苦于没有时间实现。本来打算使用stm32来实现,因为arm有着出色的计算能力,和丰富的片上ADC资源,节约很多设计时间。出于对时间成本的考虑,使用PROTEUS7.8进行设计,proteus暂时没有cortex_m3系列的VSM模型,因此只好使用51加上常用的ADC0808,来实现设计。设计思路如下,利用电阻与按键串联,三路并联后再串联一个基准电阻,按键按下,哪几个按键按下都会对基准电阻上的电压产生影响,利用ADC采集基准电阻上的电压,再用mcu进行计算判断,来确定哪些按键按下,实现无冲。如当按键1与按键2按下时,并联阻值为3.3k,基准电压为5*(10/13.3)=3.759v.ADC得到电压值,反向计算得到按键信息。阻值设计得当,可以并联更多按键。将源代码贴在最后,供参考。兴趣作品,因此设计有许多不完善的地方,如adc选通通道全部接地。有疑问或需要技术文档的可联系作者Petereisenhower@hotmail.com源代码#includereg52.h//---------------------------------------------------------------------/*基于五一单片机与ADC0808的键盘设计福建农林大学机电工程学院13电气陈延联petereisen可以方便的对键盘进行扫描,对于带ADC的单片机如STM32,很容易的设计出简单的大规模键盘,而且能实现无冲。地址:petereisenhower@hotmail.comPS;设计实际电路时建议使用内部计时器产生PWM给0808clock,且建议不要把通道选择开关直接接地,只要依样画葫芦,就能轻松的扩展到3*8个无冲键*///------------------------------------------------------------------------------sbitSTART=P3^0;//转换启动信号sbitOE=P3^1;//输出允许信号sbitEOC=P3^2;//转换结束状态信号sbitRS=P3^5;sbitRW=P3^6;sbitENABLE_LCD=P3^7;unsignedcharget_data;//ADC0808转换后的数值unsignedchartemp;//用于存储ADC0808转换后处理过程中的临时数值unsignedchardisplay[3];//存储十进制的数值unsignedcharkey1,key2,key3;//------------------------------------------------------------------------------//ADC0808的启动和转换的初始化函数voidADC0808_init(void);voidlcd_init(void);//lcd初始化程序voiddelay(unsignedintx);//微秒延时voidwrite_com(unsignedcharcom);//写lcd指令voidwrite_data(unsignedchardat);//写LCD数据voidkey_value_dis(void);//键值显示voidkey_value_fig(void);//由ADC值归算键值voidADC_value_dis(void);//ADC值显示/////////////////////////////////////////////////////////////voidmain(void){lcd_init();ADC0808_init();//初始化0808,lcdwhile(1){ADC_value_dis();//每个周期从ADC取值并归算,显示键值key_value_fig();key_value_dis();delay(0xff);}}voidADC0808_init(void){START=0;//START信号上升沿,将所有内部寄存器清0START=1;START=0;//START信号下降沿,开始A/D转换,在转换过程中START保持为低电平while(EOC==0);//等待转换结束OE=1;//允许器件输出转换的结果get_data=P1;//P口接ADC0808temp=get_data;//暂存转换结果OE=0;}voiddelay(unsignedintx)//微微秒延时{unsignedinta,b;for(a=x;a0;a--)for(b=10;b0;b--);}voidwrite_com(unsignedcharcom)//些命令,RS=0{P0=com;WR=0;RS=0;ENABLE_LCD=0;delay(10);ENABLE_LCD=1;delay(10);ENABLE_LCD=0;}voidwrite_data(unsignedchardat)//写数据,RS=1{P0=dat;WR=0;RS=1;ENABLE_LCD=0;delay(10);ENABLE_LCD=1;delay(10);ENABLE_LCD=0;}voidADC_value_dis(void)//将ADC的值显示在液晶屏幕上{unsignedchard1,d2,d3;ADC0808_init();write_com(0x80);d1=temp/100;d2=(temp%100)/10;d3=(temp%100)%10;write_data(d1+0x30);delay(5);write_data(d2+0x30);delay(5);write_data(d3+0x30);delay(300);}voidlcd_init(void){write_com(0x38);//显示模式设置:10*2delay(20);write_com(0x0c);//显示模式设置,关闭光标delay(20);write_com(0x06);//显示模式设置:光标右移,字符不移delay(20);write_com(0x01);//清屏幕指令,将以前的显示内容清除delay(20);}voidkey_value_dis(void)//对于键值的显示,按下显示#,放开清空{write_com(0x42|0x80);write_data('K');write_data('1');if(key1)write_data(0x23);elsewrite_data(0x20);write_com(0x47|0x80);write_data('K');write_data('2');if(key2)write_data(0x23);elsewrite_data(0x20);write_com(0x4C|0x80);write_data('K');write_data('3');if(key3)write_data(0x23);elsewrite_data(0x20);}voidkey_value_fig()//由ADC值到键值的归算,主要通过对电阻的计算得到{unsignedintkey_value,key_point;//键值flag,没有键被按下时keypoint=0,清理屏幕key_value=temp;key_point=0;if((temp80)&&(temp90))//模糊判断,有一定冗余,有实际使用价值{delay(50);if((temp80)&&(temp90))//为了实际使用,加入消抖,根据不同的按键,可微调delay(x){key1=0;key2=0;key3=1;key_point=1;}}if((temp120)&&(temp135)){delay(50);if((temp120)&&(temp135)){key1=0;key2=1;key3=0;key_point=1;}}if((temp160)&&(temp180)){delay(50);if((temp160)&&(temp180)){key1=1;key2=0;key3=0;key_point=1;}}if((temp145)&&(temp160)){delay(50);if((temp145)&&(temp160)){key1=0;key2=1;key3=1;key_point=1;}}if((temp190)&&(temp195)){delay(50);if((temp190)&&(temp195)){key1=1;key2=1;key3=0;key_point=1;}}if((temp195)&&(temp205)){delay(50);if((temp195)&&(temp205)){key1=1;key2=1;key3=1;key_point=1;}}if((temp180)&&(temp190)){delay(50);if((temp180)&&(temp190)){key1=1;key2=0;key3=1;key_point=1;}}if(!key_point){key1=0;key2=0;key3=0;}}