版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第五部分基本单片机C程序分析1、任务:点亮LED灯在Keil软件编辑窗口输入以下程序:#include<reg51.h>sbitP3_0=P3^0;voidmain(void){while(1){P3_0=0;}}第五部分基本单片机C程序分析1、任务:点亮LED灯在Kei2、任务:闪烁灯#include<reg51.h>voiddelay02s(void){unsignedchari,j,k;for(i=20;i>0;i--)for(j=20;j>0;j--)for(k=248;k>0;k--);}voidmain(void){while(1){P3_0=0;delay02s();P3_0=1;delay02s();}}要求:前面例子是让LED灯亮,现在实现LED灯的闪烁。2、任务:闪烁灯#include<reg51.h>要求:3、任务:按键识别要求:通过按下一次按键INT0,使小灯D1亮灭交替变换。实验原理:只要判断P3.2的电平就可以知道按键是否被按下;而在按键按下的过程中,由于机械抖动,将产生干扰,电平高低变化。可以采用软件滤波的方法去除这些干扰信号,在程序设计时,一旦发现P3.2为低电平,进入按键判断状态,软件延时10-20ms,从而避开了干扰信号区域,再重新检测P3.2状态,看按键是否真的已经按下。3、任务:按键识别要求:通过按下一次按键INT0,使小灯D1参考程序(传统的延时消抖按键程序)include<AT89X52.H>sbitINT_0=P3^2;//定义按键的输入端sbitD1=P3^0;
//D1小灯定义voiddelay10ms(void)//延时程序{
unsignedchari,j;
for(i=20;i>0;i--)
for(j=248;j>0;j--);}key(
)
//按键判断程序{ if(INT_0==0)//判断是否按下键盘 { delay10ms(
);//延时,软件去干扰 if(INT_0==0)//确认按键按下 {
D1=!D1;//D1亮灭交替变化 }
while(INT_0==0);//按键锁定,每按一次D1只变化一次 }参考程序(传统的延时消抖按键程序)续前页:}main(){while(1)
//永远循环,扫描判断按键是否按下 { key();
//对于此处CPU只按键判断一直扫描; }}
课后请实践:1.用两个按键来控制D1的亮灭;2.使用一个按键,控制小灯亮的顺序D1→D2→D3→D4→┅→D8→D7→→┅D0亮重复循环;续前页:课后请实践:4、任务:数码管静态显示要求:用数码管LED的个位,静态显示数字“4”字样;注意:因采用共阴数码显示管,故此图P0口还应接1K或10K的排阻作为上拉电阻。4、任务:数码管静态显示要求:用数码管LED的个位,静态显参考程序:#include<AT89X52.H>sbitGE=P1^3;codeunsignedcharseg7code[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
//显示段码main(){ unsignedchardisplay_date=4;//定义并赋值要显示的数据 while(1) { P0=seg7code[display_date];
//查表,输出 GE=0;//P1^3为低电平,相当于把数码管的4H端接地 }}课后请实践:1.让显示的数据动起来,比如做一个0到9的秒表(用软件延时);2.和按键判断程序结合,用按键控制数字变化;参考程序:课后请实践:5、任务:数码管动态显示要求:用数码管LED的显示四位数据,比如显示数字“1234”;参考程序:#include<AT89X52.H>sbitqian=P1^0;sbitbai=P1^1;sbitshi=P1^2;sbitge=P1^3;codeunsignedcharseg7code[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//显示段码voidDelay(unsignedinttc)//延时程序{ while(tc!=0) //如果tc为0则终止延时 { unsignedinti; //局部正整数变量i for(i=0;i<100;i++); //执行400次将耗时1毫秒 tc--; //tc计数减一 }}5、任务:数码管动态显示要求:用数码管LED的显示四位数据续前页:voidLed(intdate)//显示函数{ qian=0;//P1.0输出低电平,选通千位数 P0=seg7code[date/1000];//取出千位数,查表,输出。 Delay(10);//延时 qian=1;//销隐 bai=0;//P1.1输出低电平,选通百位数 P0=seg7code[date%1000/100];//取出百位数,查表,输出。 Delay(10);//延时 bai=1;//销隐 shi=0;//P1.2输出低电平,选通十位数 P0=seg7code[date%100/10];//取出十位数,查表,输出。 Delay(10);//延时 shi=1;//销隐 ge=0; //P1.3输出低电平,选通十位数 P0=seg7code[date%10];//取出个位数,查表,输出。 Delay(10); ge=1;}
续前页:续前页:main(){intdisplay_date=1234;//定义并赋值要显示的数据while(1){Led(display_date);//调用显示函数显示数据display_date}}
续前页:上述数码管动态显示程序的另一种写法参考程序:#include<AT89X51.H>unsignedchardatebit[]={0xfe,0xfd,0xfb,0xf7};//存储数码管的位选值unsignedchartvdate[]={0x3f,0x06,0x5b,0x4f,0x66, 0x6d,0x7d,0x07,0x7f,0x6f,};unsignedintdisdata;//定义要显示的数据unsignedchardisdat[4];//存储要显示的四位数据voiddelay(time){unsignedchari,j;for(j=0;j<time;j++)for(i=0;i<250;i++);}display(void){ unsignedchark; disdata=1234;//显示1234
上述数码管动态显示程序的另一种写法参考程序:续前页:
disdat[0]=disdat/1000; //取出千位 disdat[1]=disdat%1000/100;
//取出百位 disdat[2]=disdat%100/10; //取出十位 disdat[3]=disdat%10; //取出个位 for(k=0;k<4;k++)
//显示四位数据 { P0=tvdate[disdat[k]];
//送出要显示数据的段码 P1=datebit[k]; //P2位选 delay(10); //延时 }}main(){while(1){display();}}
这种写法比上一种复杂,占用空间要多一些.但是使用方便,可以在此基础上方便的加上比如显示小数点,指定某位数码管闪烁等。课后思考:如何用软件延时来做一个0到60秒的计数器吗?续前页:这种写法比上一种复杂,占用空间要多一些.但是使6、任务:4X4矩阵键盘识别要求:用AT89S51的并行口P2接4×4矩阵键盘,以P3.0-P3.3作输入线,以P3.4-P3.7作输出线;在每一个数码管上显示每个按键的“0-F”序号。[实验原理]每个按键有它的行值和列值,行值和列值的组合就是识别这个按键的编码。矩阵的行线和列线分别通过两并行接口和CPU通信。键盘处理程序的任务是:确定有无键按下,判断哪一个键按下,键的功能是什么;还要消除按键在闭合或断开时的抖动。两个并行口中,一个输出扫描码,使按键逐行动态接地,另一个并行口输入按键状态,由行扫描值和回馈信号共同形成键编码而识别按键,通过软件查表,查出该键的功能。6、任务:4X4矩阵键盘识别要求:用AT89S51的并行口键盘识别的两种方法逐行扫描法:(1)首先判断有无键按下:令矩阵行线输出全0信号,检测列线状态,若有一列电平为低,则有键按下。(2)确定闭合键位置:依次将各行线置为低电平,逐行检测各列线的电平状态,若某列为低,则该行线和列线交叉处按键就是闭合键。线反转法:(1)令矩阵键盘列线输出全0信号,行线作为输入接口接收信号,可判断按键处于哪一行。(2)令矩阵键盘行线输出全0信号,列线作为输入接口接收信号,可判断按键处于哪一列。(3)将输入信号相或后形成键盘的唯一键码。键盘识别的两种方法逐行扫描法:程序:(线反转法)#include<reg52.h>unsignedcharcodeseg7code[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};unsignedchark;voiddelay10ms(void)//延时程序{ unsignedchari,j; for(i=20;i>0;i--) for(j=248;j>0;j--);}voidGetch(){ unsignedcharX,Y,Z;
P2=0xff;
P2=0x0f;
//先对P2置数行扫描 if(P2!=0x0f)//判断是否有键按下 {
delay10ms();//延时,软件去干扰
if(P2!=0x0f)
//确认按键按下X=P2;
{
程序:(线反转法)续前页:
X=P2;//保存行扫描时有键按下时状态 P2=0xf0;//列扫描 Y=P2;//保存列扫描时有键按下时状态 Z=X|Y;//取出键值 switch(Z)//判断键值(那一个键按下) { case0x77:k=0;break;//对键值赋值 case0x7b:k=1;break; case0x7d:k=2;break; case0x7e:k=3;break; case0xb7:k=4;break; case0xbb:k=5;break; case0xbd:k=6;break; case0xbe:k=7;break; case0xd7:k=8;break; case0xdb:k=9;break; case0xdd:k=10;break; case0xde:k=11;break; case0xe7:k=12;break; case0xeb:k=13;break; 续前页:续前页:
case0xed:k=14;break;
case0xee:
k=15;break; } } }}voidmain(void){while(1){P2=0xff;Getch(
);P0=seg7code[k];//查表LED输出P1=0xf0;//输出相同的四位数据。}}
续前页:该程序的缺陷:1、虽然线反转法识别键盘的思路正确,但本程序按键扫描中消除按键抖动采用了传统的延时方法,这种办法会使CPU陷入无谓的等待,在延时的过程中CPU无法并行处理其它事件。采用定时扫描法(比如采用定时中断每隔100ms扫描1次键盘),可以解决这一问题;2、如果要求实现“短促”按键和“长按”按键的区分,使程序能应用在功能要求更为复杂的场合,继续编制该程序则有繁琐和可读性变差的缺点。因此有必要采用更为便捷和高效的键值识别算法以实现本程序的功能。
该程序的缺陷:新型键盘识别程序基本思想:unsignedcharTrg;unsignedcharCont;voidKeyRead(void){unsignedcharReadData=P3^0xff;//1
Trg=ReadData&(ReadData^Cont);//2
Cont=ReadData;//3
}分析:(1)没有按键的时候ReadData=0x00;Trg=0x00;Cont=0x00;(2)第一次按下按键的情况
(假设按键接在P3.0上面)ReadData=0x01;Trg=0x01;Cont=0x01;(3)按键按着不松(长按键)的情况ReadData=0x01;Trg=0x00;Cont=0x01;
(4)按键松开的情况ReadData=0x00;Trg=0x00;Cont=0x00;
Trg表示的就是触发的意思,也就是跳变,只要有按键按下,Trg在对应按键的位上面会置1;最关键的地方,Trg的值每次按下只会出现一次,然后立刻被清除,完全不需要人工去干预。所以按键功能处理程序不会重复执行,省下了一大堆的条件判断,所谓精粹即此!!Cont代表的是长按键,如果按键按着不放,那么Cont的值就为0x01。新型键盘识别程序基本思想:Trg表示的就是触发的意思,也就应用一:一次触发的按键处理——假设为蜂鸣器按键,按一下,蜂鸣器beep的响一声
#defineKEY_BEEP0x01voidKeyProc(void){if(Trg&KEY_BEEP)//如果按下的是KEY_BEEP
{Beep();//执行蜂鸣器处理函数
}}应用一:一次触发的按键处理——假设为蜂鸣器按键,按一下,蜂鸣应用二:长按键的处理
#defineKEY_MODE0x01//此模式按键也
#defineKEY_PLUS0x02//此加键也
voidKeyProc(void){if(Trg&KEY_MODE)//若KEY_MODE键按之,虽常按亦无益
{//无执行再,必先松再按可矣
Mode++;//模式寄存器加1
}if(Cont&KEY_PLUS)//若“加”键按之不放
{cnt_plus++;//则计时
if(cnt_plus>100)//20ms*100=2S若计时到
{Func();//则执行所需执行之功能程序也
}}}应用二:长按键的处理#defineKEY_MODE0x延时消抖问题?真正的单片机入门,是从学会处理多任务开始的。
加入延时消抖程序的架构如下:volatileunsignedcharIntrcnt;voidInterruptHandle()//中断服务程序
{Intrcnt++;}//1ms中断1次,可变
voidmain(void){SysInit();while(1)//每20ms执行一次大循环
{KeyRead();//将每个子程序都扫描一遍
KeyProc();Func1();Funt2();……while(1){if(Intrcnt>20)//一直在等,直到20ms时间到
{Intrcnt="0";break;}//返回主循环
}}}延时消抖问题?真正的单片机入门,是从学会处理多任务开始的。怎么判断按键释放?再增加一个按键释放检测功能,程序如下:
volatileunsignedcharTrg;volatileunsignedcharCont;volatileunsignedcharRelease;//再增加新功能!
voidKeyRead(void){unsignedcharReadData=PINB^0xff;//1读键值
Trg=ReadData&(ReadData^Cont);//2得到按下触发值
Release=(ReadData^Trg^Cont);//3得到释放触发值
Cont=ReadData;//4得到所有未释放的键值
}怎么判断按键释放?再增加一个按键释放检测功能,程序如下:v7、任务:按键中断识别要求:采用中断技术,每按一下按键,计数器加1,并用LED显示出来,注意只显示2位十进制数。原理:以上的两个旧式按键识别的实验的程序都是采用扫描的方式来实现的,CPU的利用率比较低;按键判断还可以用中断方式来判断。中断方式可以满足快速响应的要求。7、任务:按键中断识别要求:采用中断技术,每按一下按键,计数程序:#include<AT89X51.H>unsignedcharcodetable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};unsignedchardispcount=0;//计数sbitgewei=P1^3;//个位选通定义sbitshiwei=P1^2;//十位选通定义voidDelay(unsignedinttc)//延时程序{while(tc!=0){unsignedinti;for(i=0;i<100;i++);tc--;}}voidExtInt0()interrupt0//中断服务程序{程序:续前页:dispcount++;//每按一次中断按键,计数加一if(dispcount==100)//计数范围0-99{dispcount=0;}}voidLED()//LED显示函数{if(dispcount>=10)//显示两位数{shiwei=0;P0=table[dispcount/10];Delay(8);shiwei=1;gewei=0;P0=table[dispcount%10];Delay(5);gewei=1;}else//显示一位数{
续前页:续前页:shiwei=1;gewei=0;P0=table[dispcount];Delay(8);}}
voidmain(){TCON=0x01;
//下降沿触发
IE=0x81;
//开总中断和允许外部中断
while(1)
//循环执行{LED(
);}
//调用显示函数}/*******************************************************************课后思考:在程序在硬件运行过程中,有时候按一下键会加几个数,是因为没有去除按键干扰请您想一想怎么消除抖动./***************************************************************************************/
续前页:8、任务:数模转换器ADC0804的应用(扩展)要求:从ADC0804的通道IN+输入0-5V之间的模拟量,通过ADC0804转换成数字量在数码管上以十进制形成显示出来。8、任务:数模转换器ADC0804的应用(扩展)要求:从AD程序:#include<reg52.h>codeunsignedcharseg7code[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//显示段码sbitint1=P3^3;//定义管脚功能sbitcs=P3^2;sbitwr=P3^6;sbitrd=P3^7;voidDelay(unsignedinttc)//显示延时程序{while(tc!=0){unsignedinti;for(i=0;i<100;i++);tc--;}}unsignedcharadc0804(void)//读AD0804子程序{unsignedcharaddata,i;rd=1;wr=1;int1=1;//读ADC0804前准备P1=0xff;//P1全部置一准备cs=0;wr=0;wr=1;//启动ADC0804开始测电压while(int1==1);//查询等待A/D转换完毕产生的INT(低电平有效)信号rd=0;//开始读转换后数据程序:续前页:i=i;i=i;//无意义语句,用于延时等待ADC0804读数完毕addata=P1;//读出的数据赋与addatard=1;cs=1;//读数完毕return(addata);//返回最后读出的数据}unsignedintdatpro(void)
//ADC0804读出的数据处理{unsignedcharx;unsignedintdianyah,dianyal;
//用于存储读出数据的高字节和低字节unsignedintdianya=0;
//存储最后处理完的结果注意数据类型for(x=0;x<10;x++)
//将10次测得的结果存储在dianya中{dianya=adc0804()+dianya;}dianya=dianya/10;
//求平均值dianyah=dianya&0xf0;
//屏蔽低四位dianyah=dianyah>>4;
//右移四位取出高四位dianyal=dianya&0x0f;
//屏蔽高四位取出低四位dianya=dianyal*20+dianyah*320;
//最后的结果是一个四位数,便于显示return(dianya);//返回最后处理结果}换为dianya*=196;续前页:换为dianya*=196;续前页:voidLed(){unsignedintdate;date=datpro();//调用数据处理最后结果P2=P2&0xef;P0=seg7code[date/1000]|0x80;//输出个位数和小数点Delay(8);P2=P2|0xf0;P2=P2&0xdf;P0=seg7code[date%1000/100];//输出小数点后第一位Delay(8);P2=P2|0xf0;P2=P2&0xbf;P0=seg7code[date%100/10];//输出小数点后第二位Delay(8);P2=P2|0xf0;P2=P2&0x7f;P0=seg7code[date%10];//输出小数点后第三位Delay(8);P2=P2|0xf0;}main(){while(1){Led();//只需调用显示函数}}续前页:第五部分基本单片机C程序分析1、任务:点亮LED灯在Keil软件编辑窗口输入以下程序:#include<reg51.h>sbitP3_0=P3^0;voidmain(void){while(1){P3_0=0;}}第五部分基本单片机C程序分析1、任务:点亮LED灯在Kei2、任务:闪烁灯#include<reg51.h>voiddelay02s(void){unsignedchari,j,k;for(i=20;i>0;i--)for(j=20;j>0;j--)for(k=248;k>0;k--);}voidmain(void){while(1){P3_0=0;delay02s();P3_0=1;delay02s();}}要求:前面例子是让LED灯亮,现在实现LED灯的闪烁。2、任务:闪烁灯#include<reg51.h>要求:3、任务:按键识别要求:通过按下一次按键INT0,使小灯D1亮灭交替变换。实验原理:只要判断P3.2的电平就可以知道按键是否被按下;而在按键按下的过程中,由于机械抖动,将产生干扰,电平高低变化。可以采用软件滤波的方法去除这些干扰信号,在程序设计时,一旦发现P3.2为低电平,进入按键判断状态,软件延时10-20ms,从而避开了干扰信号区域,再重新检测P3.2状态,看按键是否真的已经按下。3、任务:按键识别要求:通过按下一次按键INT0,使小灯D1参考程序(传统的延时消抖按键程序)include<AT89X52.H>sbitINT_0=P3^2;//定义按键的输入端sbitD1=P3^0;
//D1小灯定义voiddelay10ms(void)//延时程序{
unsignedchari,j;
for(i=20;i>0;i--)
for(j=248;j>0;j--);}key(
)
//按键判断程序{ if(INT_0==0)//判断是否按下键盘 { delay10ms(
);//延时,软件去干扰 if(INT_0==0)//确认按键按下 {
D1=!D1;//D1亮灭交替变化 }
while(INT_0==0);//按键锁定,每按一次D1只变化一次 }参考程序(传统的延时消抖按键程序)续前页:}main(){while(1)
//永远循环,扫描判断按键是否按下 { key();
//对于此处CPU只按键判断一直扫描; }}
课后请实践:1.用两个按键来控制D1的亮灭;2.使用一个按键,控制小灯亮的顺序D1→D2→D3→D4→┅→D8→D7→→┅D0亮重复循环;续前页:课后请实践:4、任务:数码管静态显示要求:用数码管LED的个位,静态显示数字“4”字样;注意:因采用共阴数码显示管,故此图P0口还应接1K或10K的排阻作为上拉电阻。4、任务:数码管静态显示要求:用数码管LED的个位,静态显参考程序:#include<AT89X52.H>sbitGE=P1^3;codeunsignedcharseg7code[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
//显示段码main(){ unsignedchardisplay_date=4;//定义并赋值要显示的数据 while(1) { P0=seg7code[display_date];
//查表,输出 GE=0;//P1^3为低电平,相当于把数码管的4H端接地 }}课后请实践:1.让显示的数据动起来,比如做一个0到9的秒表(用软件延时);2.和按键判断程序结合,用按键控制数字变化;参考程序:课后请实践:5、任务:数码管动态显示要求:用数码管LED的显示四位数据,比如显示数字“1234”;参考程序:#include<AT89X52.H>sbitqian=P1^0;sbitbai=P1^1;sbitshi=P1^2;sbitge=P1^3;codeunsignedcharseg7code[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//显示段码voidDelay(unsignedinttc)//延时程序{ while(tc!=0) //如果tc为0则终止延时 { unsignedinti; //局部正整数变量i for(i=0;i<100;i++); //执行400次将耗时1毫秒 tc--; //tc计数减一 }}5、任务:数码管动态显示要求:用数码管LED的显示四位数据续前页:voidLed(intdate)//显示函数{ qian=0;//P1.0输出低电平,选通千位数 P0=seg7code[date/1000];//取出千位数,查表,输出。 Delay(10);//延时 qian=1;//销隐 bai=0;//P1.1输出低电平,选通百位数 P0=seg7code[date%1000/100];//取出百位数,查表,输出。 Delay(10);//延时 bai=1;//销隐 shi=0;//P1.2输出低电平,选通十位数 P0=seg7code[date%100/10];//取出十位数,查表,输出。 Delay(10);//延时 shi=1;//销隐 ge=0; //P1.3输出低电平,选通十位数 P0=seg7code[date%10];//取出个位数,查表,输出。 Delay(10); ge=1;}
续前页:续前页:main(){intdisplay_date=1234;//定义并赋值要显示的数据while(1){Led(display_date);//调用显示函数显示数据display_date}}
续前页:上述数码管动态显示程序的另一种写法参考程序:#include<AT89X51.H>unsignedchardatebit[]={0xfe,0xfd,0xfb,0xf7};//存储数码管的位选值unsignedchartvdate[]={0x3f,0x06,0x5b,0x4f,0x66, 0x6d,0x7d,0x07,0x7f,0x6f,};unsignedintdisdata;//定义要显示的数据unsignedchardisdat[4];//存储要显示的四位数据voiddelay(time){unsignedchari,j;for(j=0;j<time;j++)for(i=0;i<250;i++);}display(void){ unsignedchark; disdata=1234;//显示1234
上述数码管动态显示程序的另一种写法参考程序:续前页:
disdat[0]=disdat/1000; //取出千位 disdat[1]=disdat%1000/100;
//取出百位 disdat[2]=disdat%100/10; //取出十位 disdat[3]=disdat%10; //取出个位 for(k=0;k<4;k++)
//显示四位数据 { P0=tvdate[disdat[k]];
//送出要显示数据的段码 P1=datebit[k]; //P2位选 delay(10); //延时 }}main(){while(1){display();}}
这种写法比上一种复杂,占用空间要多一些.但是使用方便,可以在此基础上方便的加上比如显示小数点,指定某位数码管闪烁等。课后思考:如何用软件延时来做一个0到60秒的计数器吗?续前页:这种写法比上一种复杂,占用空间要多一些.但是使6、任务:4X4矩阵键盘识别要求:用AT89S51的并行口P2接4×4矩阵键盘,以P3.0-P3.3作输入线,以P3.4-P3.7作输出线;在每一个数码管上显示每个按键的“0-F”序号。[实验原理]每个按键有它的行值和列值,行值和列值的组合就是识别这个按键的编码。矩阵的行线和列线分别通过两并行接口和CPU通信。键盘处理程序的任务是:确定有无键按下,判断哪一个键按下,键的功能是什么;还要消除按键在闭合或断开时的抖动。两个并行口中,一个输出扫描码,使按键逐行动态接地,另一个并行口输入按键状态,由行扫描值和回馈信号共同形成键编码而识别按键,通过软件查表,查出该键的功能。6、任务:4X4矩阵键盘识别要求:用AT89S51的并行口键盘识别的两种方法逐行扫描法:(1)首先判断有无键按下:令矩阵行线输出全0信号,检测列线状态,若有一列电平为低,则有键按下。(2)确定闭合键位置:依次将各行线置为低电平,逐行检测各列线的电平状态,若某列为低,则该行线和列线交叉处按键就是闭合键。线反转法:(1)令矩阵键盘列线输出全0信号,行线作为输入接口接收信号,可判断按键处于哪一行。(2)令矩阵键盘行线输出全0信号,列线作为输入接口接收信号,可判断按键处于哪一列。(3)将输入信号相或后形成键盘的唯一键码。键盘识别的两种方法逐行扫描法:程序:(线反转法)#include<reg52.h>unsignedcharcodeseg7code[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};unsignedchark;voiddelay10ms(void)//延时程序{ unsignedchari,j; for(i=20;i>0;i--) for(j=248;j>0;j--);}voidGetch(){ unsignedcharX,Y,Z;
P2=0xff;
P2=0x0f;
//先对P2置数行扫描 if(P2!=0x0f)//判断是否有键按下 {
delay10ms();//延时,软件去干扰
if(P2!=0x0f)
//确认按键按下X=P2;
{
程序:(线反转法)续前页:
X=P2;//保存行扫描时有键按下时状态 P2=0xf0;//列扫描 Y=P2;//保存列扫描时有键按下时状态 Z=X|Y;//取出键值 switch(Z)//判断键值(那一个键按下) { case0x77:k=0;break;//对键值赋值 case0x7b:k=1;break; case0x7d:k=2;break; case0x7e:k=3;break; case0xb7:k=4;break; case0xbb:k=5;break; case0xbd:k=6;break; case0xbe:k=7;break; case0xd7:k=8;break; case0xdb:k=9;break; case0xdd:k=10;break; case0xde:k=11;break; case0xe7:k=12;break; case0xeb:k=13;break; 续前页:续前页:
case0xed:k=14;break;
case0xee:
k=15;break; } } }}voidmain(void){while(1){P2=0xff;Getch(
);P0=seg7code[k];//查表LED输出P1=0xf0;//输出相同的四位数据。}}
续前页:该程序的缺陷:1、虽然线反转法识别键盘的思路正确,但本程序按键扫描中消除按键抖动采用了传统的延时方法,这种办法会使CPU陷入无谓的等待,在延时的过程中CPU无法并行处理其它事件。采用定时扫描法(比如采用定时中断每隔100ms扫描1次键盘),可以解决这一问题;2、如果要求实现“短促”按键和“长按”按键的区分,使程序能应用在功能要求更为复杂的场合,继续编制该程序则有繁琐和可读性变差的缺点。因此有必要采用更为便捷和高效的键值识别算法以实现本程序的功能。
该程序的缺陷:新型键盘识别程序基本思想:unsignedcharTrg;unsignedcharCont;voidKeyRead(void){unsignedcharReadData=P3^0xff;//1
Trg=ReadData&(ReadData^Cont);//2
Cont=ReadData;//3
}分析:(1)没有按键的时候ReadData=0x00;Trg=0x00;Cont=0x00;(2)第一次按下按键的情况
(假设按键接在P3.0上面)ReadData=0x01;Trg=0x01;Cont=0x01;(3)按键按着不松(长按键)的情况ReadData=0x01;Trg=0x00;Cont=0x01;
(4)按键松开的情况ReadData=0x00;Trg=0x00;Cont=0x00;
Trg表示的就是触发的意思,也就是跳变,只要有按键按下,Trg在对应按键的位上面会置1;最关键的地方,Trg的值每次按下只会出现一次,然后立刻被清除,完全不需要人工去干预。所以按键功能处理程序不会重复执行,省下了一大堆的条件判断,所谓精粹即此!!Cont代表的是长按键,如果按键按着不放,那么Cont的值就为0x01。新型键盘识别程序基本思想:Trg表示的就是触发的意思,也就应用一:一次触发的按键处理——假设为蜂鸣器按键,按一下,蜂鸣器beep的响一声
#defineKEY_BEEP0x01voidKeyProc(void){if(Trg&KEY_BEEP)//如果按下的是KEY_BEEP
{Beep();//执行蜂鸣器处理函数
}}应用一:一次触发的按键处理——假设为蜂鸣器按键,按一下,蜂鸣应用二:长按键的处理
#defineKEY_MODE0x01//此模式按键也
#defineKEY_PLUS0x02//此加键也
voidKeyProc(void){if(Trg&KEY_MODE)//若KEY_MODE键按之,虽常按亦无益
{//无执行再,必先松再按可矣
Mode++;//模式寄存器加1
}if(Cont&KEY_PLUS)//若“加”键按之不放
{cnt_plus++;//则计时
if(cnt_plus>100)//20ms*100=2S若计时到
{Func();//则执行所需执行之功能程序也
}}}应用二:长按键的处理#defineKEY_MODE0x延时消抖问题?真正的单片机入门,是从学会处理多任务开始的。
加入延时消抖程序的架构如下:volatileunsignedcharIntrcnt;voidInterruptHandle()//中断服务程序
{Intrcnt++;}//1ms中断1次,可变
voidmain(void){SysInit();while(1)//每20ms执行一次大循环
{KeyRead();//将每个子程序都扫描一遍
KeyProc();Func1();Funt2();……while(1){if(Intrcnt>20)//一直在等,直到20ms时间到
{Intrcnt="0";break;}//返回主循环
}}}延时消抖问题?真正的单片机入门,是从学会处理多任务开始的。怎么判断按键释放?再增加一个按键释放检测功能,程序如下:
volatileunsignedcharTrg;volatileunsignedcharCont;volatileunsignedcharRelease;//再增加新功能!
voidKeyRead(void){unsignedcharReadData=PINB^0xff;//1读键值
Trg=ReadData&(ReadData^Cont);//2得到按下触发值
Release=(ReadData^Trg^Cont);//3得到释放触发值
Cont=ReadData;//4得到所有未释放的键值
}怎么判断按键释放?再增加一个按键释放检测功能,程序如下:v7、任务:按键中断识别要求:采用中断技术,每按一下按键,计数器加1,并用LED显示出来,注意只显示2位十进制数。原理:以上的两个旧式按键识别的实验的程序都是采用扫描的方式来实现的,CPU的利用率比较低;按键判断还可以用中断方式来判断。中断方式可以满足快速响应的要求。7、任务:按键中断识别要求:采用中断技术,每按一下按键,计数程序:#include<AT89X51.H>unsignedcharcodetable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};unsignedchardispcount=0;//计数sbitgewei=P1^3;//个位选通定义sbitshiwei=P1^2;//十位选通定义voidDelay(unsignedinttc)//延时程序{while(tc!=0){unsignedinti;for(i=0;i<100;i++);tc--;}}voidExtInt0()interrupt0//中断服务程序{程序:续前页:dispcount++;//每按一次中断按键,计数加一if(dispcount==100)//计数范围0-99{dispcount=0;}}voidLED()//LED显示函数{if(dispcount>=10)//显示两位数{shiwei=0;P0=table[dispcount/10];Delay(8);shiwei=1;gewei=0;P0=table[dispcount%10];Delay(5);gewei=1;}else//显示一位数{
续前页:续前页:shiwei=1;gewei=0;P0=table[dispcount];Delay(8);}}
voidmain(){TCON=0x01;
//下降沿触发
IE=0x81;
//开总中断和允许外部中断
while(1)
//循环执行{LED(
);}
//调用显示函数}/*******************************************************************课后思考:在程序在硬件运行过程中,有时候按一下键会加几个数,是因为没有去除按键干扰
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 国际贸易合同范本
- 2026年电子书版权转让协议
- 2025国考宁夏税务局行测言语理解与表达模拟题及答案
- 2026年牙齿隐形矫正服务合同
- 昆明市官渡区云南大学附属中学星耀学校2026年校园招聘备考题库及答案详解1套
- 2025年湖北银行武汉财富管理人员社会招聘备考题库及参考答案详解
- 2025国考国家税务总局新泰市税务局面试题库及答案
- 2025年明水辅警招聘真题及答案
- 2024年北京通州区教委所属事业单位招聘考试真题
- 黑龙江公安警官职业学院《管理学原理》2025 学年第二学期期末试卷
- 灯笼安装施工合同协议
- 洗煤厂环保培训教案
- 雨课堂在线学堂《文献管理与信息分析》课后作业单元考核答案
- 河南省2025年普通高中学业水平合格性考试思想政治试题及答案
- 2025年解剖生理学考试题及答案
- 2025全国交管12123学法减分必考题库和答案(完整版)
- 银行保卫安全培训课件
- 智慧网联算力中心建设项目节能评估报告
- 员工自行缴纳社保协议书
- 妊娠期高血压试题含答案
- DB12∕T 1332.8-2024 市域(郊)铁路施工质量验收规范 第8部分:通信工程
评论
0/150
提交评论