51单片机教程:单片机键盘接口程序设计
- 格式:docx
- 大小:9.90 KB
- 文档页数:2
51单片机汇编语言教程:第25课-单片机键盘接口程序设计关S未被按下时,P1。
0输入为高电平,S闭合后,P1。
0输入为低电平。
由于按钮是机械触点,当机械触点断开、闭合时,会有抖动动,P1。
0输入端的波形如图2所示。
这种抖动对于人来说是感觉不到的,但对计算机来说,则是完全能感应到的,因为计算机处理的速度是在微秒级,而机械抖动的时间至少是毫秒级,对计算机而言,这已是一个“漫长”的时间了。
前面我们讲到中断时曾有个问题,就是说按钮有时灵,有时不灵,其实就是这个原因,你只按了一次按钮,可是计算机却已执行了多次中断的过程,如果执行的次数正好是奇数次,那么结果正如你所料,如果执行的次数是偶数次,那就不对了。
为使CPU能正确地读出P1口的状态,对每一次按钮只作一次响应,就必须考虑如何去除抖动,常用的去抖动的办法有两种:硬件办法和软件办法。
单片机中常用软件法,因此,对于硬件办法我们不介绍。
软件法其实很简单,就是在单片机获得P1。
0口为低的信息后,不是立即认定S1已被按下,而是延时10毫秒或更长一些时间后再次检测P1。
0口,如果仍为低,说明S1的确按下了,这实际上是避开了按钮按下时的抖动时间。
而在检测到按钮释放后(P1。
0为高)再延时5-10个毫秒,消除后沿的抖动,然后再对键值处理。
不过一般情况下,我们常常不对按钮释放的后沿进行处理,实践证明,也能满足一定的要求。
当然,实际应用中,对按钮的要求也是千差万别,要根据不一样的需要来编制处理程序,但以上是消除键抖动的原则。
键盘与单片机的连接<键盘连接>图3<单片机与键盘接口图>图41、通过1/0口连接。
将每个按钮的一端接到单片机的I/O 口,另一端接地,这是最简单的办法,如图3所示是实验板上按钮的接法,四个按钮分别接到P3.2、P3.3、P3.4和P3.5。
对于这种键各程序能采用持续查询的办法,功能就是:检测是否有键闭合,如有键闭合,则去除键抖动,判断键号并转入对应的键处理。
基于51单片机的USB键盘设计与实现
一、背景介绍
USB键盘是近些年来随着计算机科技发展而出现的一种新型输入设备。
它采用USB接口,是电脑设备接口标准由PS/2接口更换而来的,可以满
足现代电脑日益增长的输入需要。
现代联想主板,微星主板都采用了USB
接口出现,同时USB接口也可以有效投放鼠标、USB外置设备等。
是一种
非常有效的替代方案。
本文的主要目的是基于51单片机的USB键盘设计与实现,在此基础上,可以得出一个具有良好性能的USB键盘,它将成为计算机用户所不可
或缺的输入设备之一
二、功能要求
B键盘的硬件部分,采用51单片机作为核心,屏幕模块和按键
模块作为主要的输入设备。
2.支持USB1.1/2.0标准,能够兼容主流的主板及不同接口的设备,
实现多种输入功能并支持多种操作系统。
3.按键部分及其他硬件设计,需考虑到键盘的灵敏度、机械结构的耐
用性、按键的设计及密度等多方面因素,以提高使用者的操作方便性。
4.软件设计,在51单片机上实现USB键盘的驱动程序,在根据不同
接口的主板及设备对应的协议、功能及数据格式等配置相应的控制程序,
以保证其能够实现对应的输入功能。
三、硬件设计
1.主控:采用51单片机作为主控。
单片机按键程序设计单片机按键的基本原理其实并不复杂。
通常,按键就是一个简单的开关,当按键按下时,电路接通,对应的引脚电平发生变化;当按键松开时,电路断开,引脚电平恢复到初始状态。
在程序设计中,我们需要不断检测引脚的电平变化,从而判断按键是否被按下。
在实际的按键程序设计中,有多种方式可以实现按键检测。
其中一种常见的方法是查询法。
这种方法是通过不断地读取按键对应的引脚状态来判断按键是否被按下。
以下是一个简单的查询法示例代码:```cinclude <reg51h> //包含 51 单片机的头文件sbit key = P1^0; //定义按键连接的引脚void main(){while(1) //无限循环{if(key == 0) //如果按键按下,引脚为低电平{//执行按键按下的操作//比如点亮一个 LED 灯P2 = 0xfe;while(key == 0);//等待按键松开}}}```上述代码中,我们首先定义了按键连接的引脚`key`,然后在主函数的无限循环中不断检测按键引脚的状态。
当检测到按键按下时,执行相应的操作,并通过`while(key == 0)`等待按键松开。
除了查询法,还有中断法可以用于按键检测。
中断法的优点是能够及时响应按键动作,不会因为程序的其他操作而导致按键响应延迟。
```cinclude <reg51h> //包含 51 单片机的头文件sbit key = P1^0; //定义按键连接的引脚void int0_init()//中断初始化函数{IT0 = 1; //下降沿触发中断EX0 = 1; //使能外部中断 0EA = 1; //开总中断}void int0() interrupt 0 //外部中断 0 服务函数{//执行按键按下的操作//比如点亮一个 LED 灯P2 = 0xfe;}void main(){int0_init();//初始化中断while(1);//无限循环,保持程序运行}```在上述代码中,我们首先在`int0_init` 函数中对中断进行了初始化设置,然后在`int0` 函数中编写了按键按下时的处理代码。
用51单片机制作ps2接口的工业小键盘经过我的验证,是完全可行的。
#include <reg52.h>#include <intrins.h>#define uchar unsigned char#define SEM_FULL 1#define SEM_EMPTY 0uchar bdata ps2char;uchar bdata keystatus;uchar bdata parity_buf;uchar bdata s_buf,r_buf;uchar data last_s;sbit date=P3^0;sbit clock=P3^2;sbit key0=P2^0;sbit key1=P2^1;sbit key2=P2^2;sbit key3=P2^3;sbit key4=P2^4;sbit key5=P2^5;sbit key6=P2^6;sbit key7=P2^7;sbit s_buf0=s_buf^0;sbit r_buf7=r_buf^7;sbit parity_buf0=parity_buf^0;bit ps2_tx_sem=SEM_EMPTY;bit ps2_sendbyte(uchar c);void delayus(uchar us){while(--us);}void delayms(uchar ms){uchar i;while(ms--){for(i=0;i<120;i++);}}bit parity(){bit PARITY=1;uchar i;for(i=0;i<8;i++){PARITY^=parity_buf0;parity_buf=parity_buf>>1;}return PARITY;}void ps2_tx_sem_take(){ps2_tx_sem0:EA=0;if(ps2_tx_sem==SEM_FULL){EA=1;delayus(30);delayus(30);goto ps2_tx_sem0;}ps2_tx_sem=SEM_FULL;EA=1;return;}void ps2_tx_sem_give(){EA=0;ps2_tx_sem=SEM_EMPTY;EA=1;return;}void ps2_clk_check(){ps_tx_sem:EA=0;if(clock==0) // if PS2_CLK low, wait for 50us {EA=1;delayus(30);goto ps_tx_sem;}EA=1;return;}void ps2_send(uchar dat){ps2_tx_sem_take();ps2_clk_check();if(date==1)ps2_sendbyte(dat);ps2_tx_sem_give();}uchar ps2_recbyte() // Return receice data,Error return 0{uchar i;bit PARITY;r_buf=0;while(!clock); // Wait KBCLK Highdelayus(10);if(date) // KBDA TA shoud be low,mean received start bit{ps2_send(0xfe); // if KBDATA is High, return and send error status date(0xfe)return 0;}delayus(30);clock=0; // Device control the KBCLK signalfor(i=0;i<8;i++) // Rising edge of KBCLK, write data into r_buf7{delayus(30);clock=1;delayus(10);if(!clock) return 0; // if KBCLK pull down, mean Host cancelled this sendingr_buf7=date;if(i!=7)r_buf=r_buf>>1;delayus(10);clock=0;}delayus(30);clock=1;delayus(10);if(!clock) return 0; // if KBCLK pull down, mean Host cancelled this sendingPARITY=date; // Receive odd parity bitdelayus(10);clock=0;delayus(30);clock=1;delayus(10); // Receive Stop bit, should be highif(!date) // Otherwise,send error status date(0xfe){ps2_send(0xfe);return 0;}date=0; // Send ACK bit, mean have receive data done delayus(10);clock=0;delayus(30);clock=1; // Set KBCLK and KBDATA highdelayus(10);date=1;delayus(10);parity_buf=r_buf;if(PARITY==parity()) // Check Odd parity{return r_buf;}else{ps2_send(0xfe);return 0;}delayus(30);}bit ps2_sendbyte(uchar c) // Success return 1,Fail return 0{uchar i;bit PARITY;clock=1;if(!clock) // Host prevent Keyboard sending datareturn 0;parity_buf=c;PARITY=parity(); // Calculate value about sending data odd paritylast_s=c; // Save last sending datas_buf=c;if(!clock) // Host prevent Keyboard sending datareturn 0;if(!date) // Host prepared sending command data to keyboard return 0;date=0; // Falling edge of KBCLK send data, start bit 0 delayus(10);clock=0;for(i=0;i<8;i++) // First send LSB{delayus(10);clock=1;delayus(10);if(!clock) // if KBCLK is low,mean Hos prevent Keyboard sending datareturn 0;date=s_buf0;s_buf=s_buf>>1;delayus(10);clock=0;}delayus(10);clock=1;delayus(10);if(!clock) // if KBCLK is low,mean Hos prevent Keyboard sending datareturn 0;date=PARITY; // Sending odd parity bitdelayus(10);clock=0;delayus(10);clock=1;delayus(10);date=1; // Sending stop bitdelayus(10);clock=0;delayus(30);clock=1;delayus(30);delayus(10);return 1;}bit bat(){if(P2!=0xff)return 1;elsereturn 0;}void re_send ( ){ps2_send(last_s);}void reset(){date=1;while(!clock||!date); // Wait KBCLK and KBDATA highif(bat())ps2_send(0xfc); // Self-Check failedelseps2_send(0xaa); // Self-Check successed}bit Check_command ( ) // Keyboard receive host command,return 1 { clock=1;date=1;if(!clock&!date)return 1;elsereturn 0;}void receive_process(){uchar command;if(!Check_command()) return;command=ps2_recbyte();if(!command) return;switch(command){case 0xff: // reset commandps2_send(0xfa);reset();break;case 0xfe: // re-send commandps2_send(0xfa);re_send();break;case 0xf3: // Set Typematic Rate/Delayps2_send (0xfa);break;case 0xf2: // Read IDps2_send(0xfa);ps2_send(0xAB);ps2_send(0x83);break;case 0xee: // respond commandps2_send(0xee);case 0x00:ps2_send(0xfe);default:ps2_send(0xfa); // other command, just send a response of 0xFA break;}}void main(){P2=0xff;if(bat())ps2_send(0xfc);elseps2_send(0xaa);while(1){ if(Check_command())receive_process();key4=0;while(!key4){if(!key0){delayms(5);if(!key0){ps2_sendbyte(0x1C);delayms(5);ps2_sendbyte(0xF0);delayms(1);ps2_sendbyte(0X1C);while(!key0);}}else if(!key1){delayms(5);if(!key1){ps2_sendbyte(0x32);delayms(5);ps2_sendbyte(0xF0);delayms(1);ps2_sendbyte(0X32);while(!key1);}}else if(!key2){delayms(5);if(!key2){ps2_sendbyte(0x21);delayms(5);ps2_sendbyte(0xF0);delayms(1);ps2_sendbyte(0X21);while(!key2);}}else if(!key3){delayms(5);if(!key3){ps2_sendbyte(0x23);delayms(5);ps2_sendbyte(0xF0);delayms(1);ps2_sendbyte(0X23);while(!key3);}}else key4=1;}key5=0;while(!key5){if(!key0){delayms(5);if(!key0){ps2_sendbyte(0x24);delayms(5);ps2_sendbyte(0xF0);delayms(1);ps2_sendbyte(0X24);while(!key0);}}else if(!key1){delayms(5);if(!key1){ps2_sendbyte(0x2B);delayms(5);ps2_sendbyte(0xF0);delayms(1);ps2_sendbyte(0X2B);while(!key1);}}else if(!key2){delayms(5);if(!key2){ps2_sendbyte(0x34);delayms(5);ps2_sendbyte(0xF0);delayms(1);ps2_sendbyte(0X34);while(!key2);}}else if(!key3){delayms(5);if(!key3){ps2_sendbyte(0x33);delayms(5);ps2_sendbyte(0xF0);delayms(1);ps2_sendbyte(0X33);while(!key3);}}else key5=1;}key6=0;while(!key6){if(!key0){delayms(5);if(!key0){ps2_sendbyte(0x43);delayms(5);ps2_sendbyte(0xF0);delayms(1);ps2_sendbyte(0X43);while(!key0);}}else if(!key1){delayms(5);if(!key1){ps2_sendbyte(0x3B);delayms(5);ps2_sendbyte(0xF0);delayms(1);ps2_sendbyte(0X3B);while(!key1);}}else if(!key2){delayms(5);if(!key2){ps2_sendbyte(0x42);delayms(5);ps2_sendbyte(0xF0);delayms(1);ps2_sendbyte(0X42);while(!key2);}}else if(!key3){delayms(5);if(!key3){ps2_sendbyte(0x4B);delayms(5);ps2_sendbyte(0xF0);delayms(1);ps2_sendbyte(0X4B);while(!key3);}}else key6=1;}key7=0;while(!key7){if(!key0){delayms(5);if(!key0){ps2_sendbyte(0x3A);delayms(5);ps2_sendbyte(0xF0);delayms(1);ps2_sendbyte(0X3A);while(!key0);}}else if(!key1){delayms(5);if(!key1){ps2_sendbyte(0x31);delayms(5);ps2_sendbyte(0xF0);delayms(1);ps2_sendbyte(0X31);while(!key1);}}else if(!key2){delayms(5);if(!key2){ps2_sendbyte(0x44);delayms(5);ps2_sendbyte(0xF0);delayms(1);ps2_sendbyte(0X44);while(!key2);}}else if(!key3){delayms(5);if(!key3){ps2_sendbyte(0x4D);delayms(5);ps2_sendbyte(0xF0);delayms(1);ps2_sendbyte(0X4D);while(!key3);}}else key7=1;}}}。
在51单片机上使用PC机ps/2键盘(附源码)本人弄了几天,终于在今天晚上,也就是刚才实验成功,心情特佳,特写出来以享大家。
单片机上应用非编码键盘,各书上均有介绍。
作为实验用,我想到了用PC机的ps/2键盘。
PC机键盘内部有单片机电路来完成编码和去抖动,它按照ps/2协议来发送扫描码。
因此在应用中,我们需要做的只是将扫描码与字符对应起来,大部分事情都由键盘自己完成了。
首先介绍一下键盘的接口,典型的几种接口如下图:其中第一种用于老式键盘(我原来的键盘就是),第二种便是现在的PS/2键盘,第三个不用去管它。
我的实验是按照最常用的PS/2(即第二种)来做的。
再略微介绍一下PS/2协议的相关内容。
PS/2的一个数据帧为11位,时序如下:PS/2帧的第一位是起始位,为0,然后是8位数据位,发送键盘扫描码的一个字节(扫描码为1-4个字节),然后是奇偶校验位,最后是停止位,为1。
这些是在数据线(即1号引脚线)上发送的。
无键按下时,数据线和始终线都保持为1。
当有键按下时,时钟线CLOCK 送出脉冲,同时数据线送出数据。
主机(此处是89c51 MCU)在始终脉冲的下降沿对数据线采样获得数据。
键盘扫描码包括通码和断码,当键按下时发送通码,抬起时发送断码。
更详细的内容可参考所附的《PS/2技术参考》。
根据上述原理,我这样设计了实验:将键盘的脉冲线接至89c51的外部中断输入口(INT0或INT1),当键按下和抬起时有脉冲产生,此脉冲引发MCU中断。
将键盘的DATA线连至89c51的输入口(如P1.0)。
在中断处理程序中,从输入口读入数据,然后通过循环移位对读进的数据位进行处理,1(起始位)、10(奇偶校验)、11(停止位)可抛弃,如不嫌麻烦也可将奇偶校验位加以应用。
当一个数据帧收完后,将处理后剩下的2-9位(即扫描码)通过串口发至PC机,通过PC机的串口监视软件(如“串口调试助手”)来查看。
硬件连线和源码如下:源码:ORG 0000HAJMP MAIN;转入主程序ORG 0003H ;外部中断P3.2脚INT0入口地址AJMP INT ;转入外部中断服务子程序;以下为主程序进行CPU中断方式设置MAIN:MOV SCON,#50H;设置成串口1方式MOV TMOD,#20H;波特率发生器T1工作在模式2上MOV PCON,#80H;波特率翻倍为2400x2=4800BPSMOV TH1,#0F3H;预置初值(按照波特率2400BPS预置初值)MOV TL1,#0F3H;预置初值(按照波特率2400BPS预置初值)SETB EA ;打开CPU总中断请求SETB IT0 ;设定INT0的触发方式为脉冲负边沿触发SETB EX0 ;打开INT0中断请求SJMP $INT: CLR EA ;暂时关闭CPU的所有中断请求CJNE R0,#0,L1L3: INC R0SJMP L5L1: CJNE R0,#9,L2SJMP L3L2: CJNE R0,#10,L4SETB TR1;启动定时器T1MOV SBUF,AMOV R0,#0L5: SETB EA ;允许中断RETI ;退出子程序L4: MOV C,P1.0RRC ASJMP L3END搞定后,当按下和释放键时,会在PC机上显示其扫描码。
《单片机C51程序设计》课程标准一、课程性质课程名称:单片机C51程序设计课程代码:109025学时数:84其中课内实验学时数:34学分数:6适用专业:应用电子技术、电子信息工程技术二、课程教学目标1、课程知识目标掌握单片机基本原理,熟悉KEILL软件的使用,熟悉基于proteus软件的单片机的仿真方法,熟悉MCS-51的结构与应用设计方法,掌握C51结构与基本的程序设计方法,通过应用实例熟悉单片机C语言的在单片机应用设计中的用法。
2、课程技能目标通过本课程的教学,要求学生初步具有用C语言进行单片机系统设计的能力。
3、职业能力目标掌握电子产品设计的基本方法,能够以单片机作为核心进行电子产品的设计与开发。
三、课程内容本课程由理论教学模块、实验教学模块两大模块组成。
其中理论教学模块50学时、占60%,实践(含实验和实训)教学模块34学时,占40%。
各教学模块如下:1、理论教学模块2、实验教学模块四、学生学习指南模块一keil软件与proteus软件的使用Keil软件是目前最流行开发MCS-51系列单片机的软件,这从近年来各仿真机厂商纷纷宣布全面支持Keil即可看出。
Keil提供了包括C编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案,通过一个集成开发环境(uVision)将这些部份组合在一起。
掌握这一软件的使用对于使用51系列单片机的爱好者来说是十分必要的,如果你使用C语言编程,那么Keil几乎就是你的不二之选。
Proteus ISIS是一款Labcenter 出品的电路分析实物仿真系统,可仿真各种电路和IC,并支持单片机,元件库齐全,使用方便,是不可多得的专业的单片机软件仿真系统。
该软件的特点:①全部满足我们提出的单片机软件仿真系统的标准,并在同类产品中具有明显的优势。
②具有模拟电路仿真、数字电路仿真、单片机及其外围电路组成的系统的仿真、RS-232动态仿真、C调试器、SPI调试器、键盘和LCD系统仿真的功能;有各种虚拟仪器,如示波器、逻辑分析仪、信号发生器等。
实例制作的是用一个AT89C51单片机连接PS/2键盘接口和一个16x2的液晶显示屏,当敲击键盘时,字母可以显示在液晶显示屏上。
这个实例能启发你如何利用单片机来实现对PS/2接口的控制。
实例中提供的源代码修改后可以用到其他PS/2键盘制作项目中。
实例中提供的16x2字符型的液晶显示屏的驱动函数也可以其他项目。
电路原理主电路板中的AT89C51单片机(可以用AT89C52/S51/S52直接替换,如用AT89C2051/4051则需要改程序)组成了51最小化系统。
液晶显示屏于嗯了SMC1602A. 键盘通过PS/2六孔插座和主电路板。
PS/2设备的连接器使用mini-DIN连接器,正有6个引线,其中2个保留为用。
DATA和CLK是可双向通信的I/O线,也就是说通过这两根线,既可以把主机的数据发送到PS/2设备,有可以把设备的数据发向主机。
在无键按下是,DATA 和CLK一直处于高电平状态。
但有键按下时,键盘先检查CLK,看它是否处于高电平,如果是处在低电平,说明主机无空闲接收数据,这是键盘将会把数据放在自己的缓冲区(16Bytes).直到CLK重新被拉高。
键盘获得总线权,这是键盘产生始终信号在CLK上输出。
同时每一个时钟周期在DATA 线上输出一位数据。
第1位是起始位为0,第2-9位为一个八位二进制数据由地位到高位依次输出,第10位为奇偶校验位下面是电路原理图PS/2设备接口用于许多现代的鼠标和键盘,PS/2连接器上有四个管脚:电源地、+5V、数据和时钟。
Host(计算机)提供+5V并且键盘/鼠标的地连接到host的电源地上,数据和时钟都是集电极开路的这就意味着它们通常保持高电平而且很容易下拉到地(逻辑0)。
任何你连接到PS/2鼠标、键盘或host 的设备,在时钟和数据线上要有一个大的上拉电阻。
置“0”就把线拉低,置“1”就让线上浮成高。
从键盘/鼠标发送到主机的数据在时钟信号的下降沿(当时钟从高变到低的时候)被读取;从主机发送到键盘/鼠标的数据在上升沿(当时钟从低变到高的时候)被读取。
51单片机教程:单片机键盘接口程序设计
键盘是由若干按钮组成的开关矩阵,它是单片机系统中最常用的输入设备,用户能通过键盘向计算机输入指令、地址和数据。
一般单片机系统中采和非编码键盘,非编码键盘是由软件来识别键盘上的闭合键,它具有结构简单,使用灵活等特点,因此被广泛应用于单片机系统。
按钮开关的抖动问题
组成键盘的按钮有触点式和非触点式两种,单片机中应用的一般是由机械触点组成的。
在下图中,当开
键盘结构图
|图1
图2
关S未被按下时,P1。
0输入为高电平,S闭合后,P1。
0输入为低电平。
由于按钮是机械触点,当机械触点断开、闭合时,会有抖动动,P1。
0输入端的波形如图2所示。
这种抖动对于人来说是感觉不到的,但对计算机来说,则是完全能感应到的,因为计算机处理的速度是在微秒级,而机械抖动的时间至少是毫秒级,对计算机而言,这已是一个漫长的时间了。
前面我们讲到中断时曾有个问题,就是说按钮有时灵,有时不灵,其实就是这个原因,你只按了一次按钮,可是计算机却已执行了多次中断的过程,如果执行的次数正好是奇数次,那么结果正如你所料,如果执行的次数是偶数次,那就不对了。
为使CPU能正确地读出P1口的状态,对每一次按钮只作一次响应,就必须考虑如何去除抖动,常用的去抖动的办法有两种:硬件办法和软件办法。
单片机中常用软件法,因此,对于硬件办法我们不介绍。
软件法其实很简单,就是在单片机获得P1。
0口为低的信息后,不是立即认定S1已被按下,而是延时。