单片机按键扫描编程
- 格式:doc
- 大小:30.00 KB
- 文档页数:3
8051单片机的反转法扫描键盘键盘扫描采用反转法读键:先从P2口的高4位输出零电平,从P2口的低4位读取键盘状态;再从P2口的低4位输出零电平,从P2口的高4位读取键盘状态,将两次读取的结果组合起来就可以得到当前按键的特征码(见程序中TABLE表)。
有了这张表就可以编程,将它们转换成顺序码。
用当前读得的特征码来顺序查表,用一单元记录查找次数。
当在表中查到有该特征码时,它的位置(即查找次数)就是对应的顺序码。
对应的键盘查键程序如下:KEY: MOV P2,#0FH ;用反转法查键MOV A,P2ANL A,#0FHMOV B,AMOV P2,#0F0HMOV A,P2ANL A,#0F0HORL A,BCJNE A,#0FFH,KEY1RET ;无键按下KEY1: MOV B,A ;有键按下,存键码MOV DPTR,#TABLEMOV R3,#0FFH ;存顺序码单元初始化KEY2: INC R3MOV A,R3MOVC A,@A+DPTRCJNE A,B,KEY3 ;判键码,求顺序码MOV A,R3 ;若找到键码,存顺序码RETKEY3: CJNE A,#0FFH,KEY2;判是否查完RET ;已查完,键码未找到,以无按键处理TABLE: DB 77H,7BH,0BBH ;按键特征码表DB 0DBH,7DH,0BDHDB 0DDH,7EH,0BEHDB 0DEH,0B7H,0D7HDB 0EEH,0EDH,0EBHDB 0E7H,0C7H,0FFH用C语言的写法#include#includeCC.h#define uchar unsigned char#define uint unsigned intkeysCAN(){uchar i,h=0xfe;for(i=4,P1=h;i0;i) //扫描{if((P10xf0)!=0xf0) //有键按下? {uchar a;for(a=255;a0;a) //延时{}if((P10xf0)!=0xf0) //有键按下{uchar key,p;p=P1;for(key=0;key16;key++) //查表。
4.3.2 按键扫描处理程序流程图(1)按键扫描处理代码/* 功能实现参数,参数mode为Key_Menu按键选择的功能模块*/void Displa y(unsign ed char mode){switch (mode)//显示模式,0为显示实时温度,1为显示温度上限,2为显示温度下限{case 0: if (temper ature < 0)//温度小于0{temper ature = -temper ature;//换为正温度Displa ySeg(0x40, temper ature % 1000); //0x40为负号}else Displa ySeg(codeSe g[temper ature% 10000/ 1000], temper ature % 1000);break;case 1: Displa ySeg(0x76, alarm_temp_H * 10); break;//显示温度上限,0x76为H字符case 2: Displa ySeg(0x38, alarm_temp_L * 10); break;//显示温度下限,0x38为L字符defaul t:break;}}/* 按键扫描和处理函数*/void KeyScan(void){if (Key_Menu == 0)//判断按键是否被按下{DelayM s(10);//延时10毫秒,去抖动干扰if (Key_Menu == 0)//再次确认按键是否被按下{while(Key_Menu == 0)Displa y(menu);//等待按键释放,器件扫描数码管menu++;//功能键,功能切换if (menu == 3)menu = 0;//三个功能切换完}}if (Key_Ad d == 0){DelayM s(10);if (Key_Ad d == 0){while(Key_Ad d == 0)Displa y(menu);switch (menu){case 1: if (alarm_temp_H < 50)alarm_temp_H++;break;//加温度上限case 2: if (alarm_temp_L< 27)alarm_temp_L++;break;//加温度下限defaul t:break;}}}if (Key_De c == 0){DelayM s(10);if (Key_De c == 0){while(Key_De c == 0)Displa y(menu);switch (menu){case 1: if (alarm_temp_H > 30)alarm_temp_H--;break;//减温度上限case 2: if (alarm_temp_L > 7)alarm_temp_L--;break;//减温度下限defaul t:break;}}。
单片机矩阵键盘扫描的两种方式单片机矩阵键盘扫描的两种方式矩阵键盘扫描方式:第一种:逐行扫描法,就是一行一行的扫描。
实现代码如下(键盘连接P2口):#define NO_KEY 0XFF#define KEY_LO() P2 &= 0XF0#define KEY_HI() P2 |= 0X0F#define KEY_L(i) P2 &= ~(1<<i)#define KEY_RD() ((P2>>4) & 0x0f)UINT8 OnceKey(void){UINT8 line = 0;UINT8 key = NO_KEY;//key valueKEY_LO();if (KEY_RD() == 0X0F){KEY_HI();return NO_KEY;}for (line=0; line<4; line ++){KEY_HI();KEY_L(line);key = KEY_RD();switch (key){case ROW_FIRST:key = 4*line + 0;break;case ROW_SECOND:key = 4*line + 1;break;case ROW_THIRD:key = 4*line + 2;break;case ROW_FOURTH:key = 4*line +3;break;default :key = 0x0f;break;}if (key < 0x10){return key;}}return NO_KEY;}第二种,线性反转法。
就是行和列分别读出。
实现代码如下:#define CVT(i) ((i)==(~1)&0x0f)? 0: ((i)==(~2)&0x0f)? 1: ((i)==(~4)&0x0f)? 2: ((i)==(~8)&0x0f)? 3: 4;#define KEY0_3HI() P2 |= 0X0F#define KEY0_3LO() P2 &= 0XF0#define KEY4_7HI() P2 |= 0XF0#define KEY4_7LO() P2 &= 0X0F#define KEY0_3RD() (P2 & 0X0F)#define KEY4_7RF() ((P2>>4) & 0X0F)UINT8 OnceKey(void){UINT8 line = NO_KEY;UINT8 row = NO_KEY;UINT8 key;KEY0_3HI();KEY4_7LO();line = KEY0_3RD();//读入行的值if (0x0f == line){key = NO_KEY;}else{KEY0_3LO();KEY4_7HI();row = KEY4_7RD();//读入列的值if (0x0f == row){key = NO_KEY;}else{key = CVT(line)*4 + CVT(row);}}KEY0_3HI();KEY4_7HI();return key; }。
汇编形式的4x4键盘扫描接口顺续:从上到下:IOA0—IOA3从左到右:IOA4—IOA7返回键值:从左到右,从上到下依次为0,1,2 (15)没有按键按下时返回值为16有按键按下时按键弹起的时候才跳出函数,否则一直循环,直到按键弹//=========================================================================////4X4键盘扫描程序//键值从左到右,从上到下键值依次为0,1,2,,15没有按下时键值为16,不是很占用cpu 时间//初始化IOA口//在IOA口中IOA0~IOA3为输出口,IOA4~IOA7为输入口//*P_IOA_Attrib = 0x000f;//*P_IOA_Dir = 0x000f;//*P_IOA_Data = 0x00f0;//.define P_IOA_Data 0x7000.define P_IOA_Buffer 0x7001.define P_IOA_Dir 0x7002.define P_IOA_Attrib 0x7003.define P_IOB_Data 0x7005.define P_IOB_Buffer 0x7006.define P_IOB_Dir 0x7007.define P_IOB_Attrib 0x7008.DEFINE P_IO_Data P_IOA_Data.DEFINE P_IO_Buffer P_IOA_Buffer.DEFINE P_IO_Dir P_IOA_Dir.DEFINE P_IO_Attrib P_IOA_Attrib.DEFINE M_Line_Mask 0x00f0 //列扫描.DEFINE M_Com_Mask 0x000f //行扫描.DEFINE M_Com_Scan 0x0008 //行扫描起始数据.DEFINE M_Com_Num 4 //行数.CODE//========================================================// 语法格式:void F_Key4X4_Initial(void)// 实现功能:4X4键盘初始化子程序// 参数:无// 返回值:无// 破坏寄存器:无//========================================================.PUBLIC _F_Key4X4_Initial.PUBLIC F_Key4X4_Initial_F_Key4X4_Initial:F_Key4X4_Initial:push r1 to [sp]r1 = [P_IO_Dir]r1 = r1|M_Com_Maskr1 = r1&(~M_Line_Mask)[P_IO_Dir] = r1r1 = [P_IO_Attrib]r1 = r1|M_Com_Maskr1 = r1&(~M_Line_Mask)[P_IO_Attrib] = r1r1 = [P_IO_Buffer]r1 = r1&(~M_Com_Mask)[P_IO_Data] = r1pop r1 from [sp]retf//=============================================================// // 函数名称: F_Key4X4_Scan()// 功能描述: 4X4键盘扫描程序// 语法格式: unsigned int F_Key4X4_Scan(void)// 入口参数: 无// 出口参数: 键值// 注意事项: 仅为用户模型//=============================================================// .PUBLIC _F_Key4X4_Scan_F_Key4X4_Scan:push r2,r5 to [sp]Key4X4_Scan_0:r3 = 0x0001[0x7012] = r3r1 = [P_IO_Buffer]r1 = r1&(~M_Com_Mask)[P_IO_Data] = r1nopr1 = [P_IO_Data]r1 &= M_Line_Maskr1^=M_Line_Maskjnz Key4X4_Scan_1jmp Key4X4_nokey///Key4X4_Scan_1:// call F_Delay15 //进入十五毫秒延时消除抖动r1 = [P_IO_Buffer]//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\r1 = r1&(~M_Com_Mask)[P_IO_Data] = r1nopr1 = [P_IO_Data]r1 &= M_Line_Maskr1^=M_Line_Maskjnz Key4X4_Scan_2jmp Key4X4_nokey///Key4X4_Scan_2: //进入扫描r2 = ~M_Com_Scanr3 = 4Key4X4_Scan_3:r1 = [P_IO_Buffer]r1 &= ~M_Com_Maskr1 = r1|r2[P_IO_Data] = r1nopr1 = [P_IO_Data]r1 &= M_Line_Maskr1^=M_Line_Maskjnz Key4X4_Scan_4r2 = r2 lsr 1r3 -= 1jnz Key4X4_Scan_3jmp Key4X4_Scan_Exit///Key4X4_Scan_4: //以下是计算键值.......r2 = r3-1r1 = r1 lsr 4push r1 to [sp]r1 = 4MR = r2*r1r2 = r3pop r1 from [sp]r3=0Key4X4_Scan_4_loop:r3 += 1r1 = r1 lsr 1jnz Key4X4_Scan_4_loopr3=r3-1r1 = r3r1 = r1+r2 //end.......jmp Key4X4_Scan_ExitKey4X4_nokey:r1=0x0010Key4X4_Scan_Exit:r3 = 0x0001[0x7012] = r3r2 = [P_IO_Buffer]r2 = r2&(~M_Com_Mask)[P_IO_Data] = r2nopr2 = [P_IO_Data]r2 &= M_Line_Maskr2^=M_Line_Maskjnz Key4X4_Scan_Exit //等待按下的键释放pop r2,r5 from [sp]retf//======================================================== // 语法格式:F_Delay15// 实现功能:延时子程序// 参数:无// 返回值:无//======================================================== .public _F_Delay15_F_Delay15:push r1,r5 to [sp]r1=0x6eff//0xDCDBDely_L:r3 = 0x0001[0x7012] = r3r1-=1jnz Dely_Lpop r1,r5 from [sp]retf。
实验4 键盘实验一、实验目的:1.掌握8255A编程原理。
2.了解键盘电路的工作原理。
3.掌握键盘接口电路的编程方法。
二、实验设备:CPU挂箱、8031CPU模块三、实验原理:1.识别键的闭合,通常采用行扫描法和行反转法。
行扫描法是使键盘上某一行线为低电平,而其余行接高电平,然后读取列值,如所读列值中某位为低电平,表明有键按下,否则扫描下一行,直到扫完所有行。
本实验例程采用的是行反转法。
行反转法识别键闭合时,要将行线接一并行口,先让它工作于输出方式,将列线也接到一个并行口,先让它工作于输入方式,程序使CPU通过输出端口往各行线上全部送低电平,然后读入列线值,如此时有某键被按下,则必定会使某一列线值为0。
然后,程序对两个并行端口进行方式设置,使行线工作于输入方式,列线工作于输出方式,并将刚才读得的列线值从列线所接的并行端口输出,再读取行线上的输入值,那么,在闭合键所在的行线上的值必定为0。
这样,当一个键被按下时,必定可以读得一对唯一的行线值和列线值。
2.程序设计时,要学会灵活地对8255A的各端口进行方式设置。
3.程序设计时,可将各键对应的键值(行线值、列线值)放在一个表中,将要显示的0~F字符放在另一个表中,通过查表来确定按下的是哪一个键并正确显示出来。
实验题目利用实验箱上的8255A可编程并行接口芯片和矩阵键盘,编写程序,做到在键盘上每按一个数字键(0~F),用发光二极管将该代码显示出来。
四、实验步骤:将键盘RL10~RL17接8255A的PB0~PB7;KA10~KA12接8255A的PA0~PA2;PC0~PC7接发光二极管的L1~L8;8255A芯片的片选信号8255CS接CS0。
五、实验电路:六、程序框图7.程序清单八、附:8251/8255扩展模块该模块由8251可编程串行口电路和8255可编程并行口电路两部分组成,其电源、数据总线、地址总线和片选信号均由接口挂箱上的接口插座提供。
一、8251可编程串行口电路(1)8251可编程串行接口芯片引脚及功能8251A是通用同步/异步收发器USART,适合作异步起止式数据格式和同步面向字符数据格式的接口,其功能很强。
//3*3键盘扫描程序,键盘为3个行上拉电阻,扫描函数完全自主知识产权//数码管扫描函数据说是华为的程序员编写的,本人稍加改动#include <pic.h>#define uchar unsigned char#define uint unsigned int__CONFIG(PWRTDIS&HS&WDTDIS&LVPDIS&BORDIS);const uchar table[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};//共阴极数码管段表const uchar keycode[9][2]={{0x1E,1},{0x2E,2},{0x36,3},{0x1D,4}, {0x2D,5},{0x35,6},{0x1B,7},{0x2B,8},{0x33,9}};//矩阵键盘键值码void delayms(uint delay){uint i;for(;delay>0;delay--)for(i=0;i<453;i++);}void init(){ADCON1=0x8E;TRISD=0x00;TRISA&=0xE1;PORTD=0x00;PORTA=0x00;}uchar scankey(){uchar key3H,key3L,scancode;TRISB=0x38;//高3位置为输入,低3位为输出PORTB=0x00;//低3位输出低电平key3H=PORTB;//读取D口状态key3H=PORTB&0x38;if(key3H!=0x38){key3H=PORTB;delayms(5);if(key3H!=0x38){TRISB=0x07;//低3位输入,高3位输出PORTB=0x00;//高3位输出低电平key3L=PORTB;key3L=PORTB&0x07;if(key3L!=0x07){scancode=key3H|key3L;while(PORTB!=0x07);//等待按键松开return(scancode);}}}elsereturn(0xFF);}uchar getvalue(){uchar myvalue=0,i=0;myvalue=scankey();if(myvalue!=0xFF){while(myvalue!=keycode[i][0])i++;return(keycode[i][1]);}elsereturn(0xFF);}void display(uchar data){uchar i,j,k,num[5]={0,0,0,0,0};num[1]=data/1000;//千位num[2]=(data%1000)/100;//百位num[3]=data%100/10;//十位num[4]=data%10;//十位for(i=0;i<10;i++){PORTA=~(0x02);k=0x02;for(j=1;j<=4;j++){PORTA=~k;PORTD=table[num[j]];delayms(2);k=k<<1;}}}void main(){uchar mynum=0,i=0;init();//初始化while(1){i=getvalue();if(i!=0xFF)mynum=i;display(mynum);}}。
《单片机原理及应用》实验报告实验名称:键盘扫描一、实验目的:1、掌握键盘和显示器的接口方法和编程方法。
2、掌握键盘扫描和LED八段码显示器的工作原理。
二、实验内容:利用实验系统提供的键盘扫描电路和显示电路,做一个扫描键盘和数码显示实验,把按键输入的键码在六位数码管上显示出来。
1、按原来的源程序进行运行调试,要成功。
2、初始显示为自己学号的低6位3、将左边开始第3位数码管的显示跟随按键输入变化而变化。
4、在3的基础上让显示值和键码值相等。
5、若只用键盘中的列扫描,而不使用行扫描,会有什么结果产生?三、程序框图及电路连接图四、源程序清单(注释部分请手写)1、显示自己学号的低6位,显示值为680127,键码值分别为082H,080H,0C0H,0F9H,0A4H,0F8H。
OUTBIT equ 0ffddhOUTSEG equ 0ffdchIN equ 0ffdehLedBuf equ 60horg 0Start:mov sp,#40hmov LedBuf+0,#082hmov LedBuf+1,#080hmov LedBuf+2,#0c0hmov LedBuf+3,#0f9hmov LedBuf+4,#0a4hmov LedBuf+5,#0f8hMLoop:call DisplayLEDcall ScanKeyjb acc.5,MLoopjb acc.4,MLoopanl a,#00001111bmov dptr, #keytable (2)movc a, @a+dptrmov dptr,#LedMapmovc a,@a+dptrmov LedBuf+5,a (1)sjmp MLoopDelay:mov r7,#0DelayLoop:djnz r7,DelayLoopdjnz r6,DelayLoopretDisplayLED:mov r0,#LedBufmov r1,#6mov r2,#20hLoop:mov dptr,#OUTBITmov a,#0movx @dptr,amov a,@r0mov dptr,#OUTSEGmovx @dptr,amov dptr,#OUTBITmov a,r2movx @dptr,amov r6,#1call Delaymov a,r2rr amov r2,ainc r0djnz r1,LoopretScanKey:setb RS1mov r2,#0fehmov r3,#08hmov r0,#00hLoopS: mov r1,#Low(OUTBIT)mov a,r2movx @r1,arl amov r2,ainc r1movx a,@r1cpl aanl a,#0fhjnz Scan (3)inc r0djnz r3,LoopSReTKey3:mov a,#20hTKey3: mov r2,aclr amov r1,#Low(OUTBIT)movx @r1,amov a,r2clr RS1retScan1: mov a, r0sjmp TKey3Scan:cpl ajb acc.0,TKey0mov a,#00hsjmp EndLoopTKey0: jb acc.1,TKey1mov a,#08hsjmp EndLoopTKey1: jb acc.2,TKey2mov a,#10hsjmp EndLoopTKey2: jb acc.3,ReTKey3mov a,#18hEndLoop:add a,r0sjmp TKey3LedMap:db 0c0h,0f9h,0a4h,0b0h,099h,092h,082h,0f8hdb 080h,090h,088h,083h,0c6h,0a1h,086h,08eh KeyTable:db 07h,04h,08h,05h,09h,06h,0ah,0bhdb 01h,00h,02h,0fh,03h,0eh,0ch,0dhend2、在原有的程序上修改:把(1)处的mov LedBuf+5,a改为mov LedBuf+2,a3、在2的基础上让显示值和键码值相等:把(2)处的mov dptr, #keytable改为mov dptr, # LedMap 然后把后两行删除4、只用键盘中的列扫描,而不使用行扫描把(3)处的jnz Scan改为jnz Scan1。
51单片机的矩阵按键扫描的设计C语言程序以下为一个基于51单片机的矩阵按键扫描的设计C语言程序:```c#include <reg51.h>//定义端口连接到矩阵键盘sbit col1 = P2^0;sbit col2 = P2^1;sbit col3 = P2^2;sbit row1 = P2^3;sbit row2 = P2^4;sbit row3 = P2^5;sbit row4 = P2^6;//声明按键函数char read_keypad(;void maiwhile (1)char key = read_keypad(; // 读取按键值//根据按键值进行相应操作switch(key)case '1'://第一行第一列按键逻辑//在此处添加相应的代码break;case '2'://第一行第二列按键逻辑//在此处添加相应的代码break;//继续处理其他按键//...default://未识别到按键break;}}//按键扫描函数char read_keypacol1 = 0; col2 = 1; col3 = 1; // 激活第一列if (row1 == 0) { // 第一行第一列按键被按下while (row1 == 0); //等待按键释放return '1'; // 返回按键值}if (row2 == 0) { // 第二行第一列按键被按下while (row2 == 0); //等待按键释放return '4'; // 返回按键值}if (row3 == 0) { // 第三行第一列按键被按下while (row3 == 0); //等待按键释放return '7'; // 返回按键值}if (row4 == 0) { // 第四行第一列按键被按下while (row4 == 0); //等待按键释放return '*'; // 返回按键值}col1 = 1; col2 = 0; col3 = 1; // 激活第二列//处理第二列的按键逻辑//...col1 = 1; col2 = 1; col3 = 0; // 激活第三列//处理第三列的按键逻辑//...return '\0'; // 返回空字符表示未检测到按键```以上代码中,我们使用51单片机的P2端口连接到矩阵键盘的列和行,通过扫描不同的列和检测行的状态来判断按键是否被按下。
实验四单片机按键扫描编程
一、实验目的
1、掌握单片机按键扫描的工作方式;
2、掌握单片机按键扫描的编程方法。
二、实验内容
1、学习单片机按键扫描的工作方式;
2、扫描按键,控制LED灯实现闪烁和停止闪烁两种状态的切换。
基本要求:
用按键Key1控制,按一下Key1,控制LED灯闪烁和停止闪烁的切换。
三、实验设备
1、STC单片机开发板;
2、PC机以及串口线。
四、实验分析及关键代码
#include<reg51.h>
#include <intrins.h>
#define uchar unsigned char
uchar counter=0;
sbit KEY1=P2^6; //按下,值为0
sbit LEDG=P2^5;
void delay_10ms(void) //10ms延时函数
{
unsigned char i,j;
for(j=0;j<10;j++)
{for (i=0;i<250;i++)
_nop_();
}
}
void timer()interrupt 1 using 1 //定时器1方式1,采用中断方式{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256; //重置初值
counter++;
if(counter==10)
{
LEDG=!LEDG; //LEDG取反改变灯的状态
counter=0;
}
}
void main()
{
TMOD=0X21;
EA=1;
ET0=1;
TR0=1; //启动T/C0开始定时
while(1)
{
if(!KEY1)
{ delay_10ms();
if(!KEY1)
{
while(!KEY1);
delay_10ms();
TR0=!TR0; //执行按键任务}
}
}
五、实验总结。