4x4键盘设计说明书.doc
4x4键盘在单片机上的应用摘 要近年来随着电子产品的高速发展 ,单片机作为核心部件的正在不断深入各个电子产品的控制中,同时带动电子产品向着小型化、多功能化、智能化、高速化方向发展。比如,我们平常所使用的电饭煲、电冰箱、空调、计算器等电子产品都将单片机作为主要的控制器,使产品的控制和结果都变得简单化。然而仅是单片机方面知识是不够的,还应根据具体硬件结构,以及针对具体应用对象特点的软件结合,以作完善。在嵌入式PC应用系统中,作为人机交互设备的键盘,往往采用结构简单按键少的矩阵键盘。标准键盘虽然能直接与嵌入式PC机的PS/2接口相连,但是体积大,按键多,不能满足需求,本文提出用一种AT89C52单片机实现具有标准PS/2接口的矩阵键盘,具有便捷,实用的特点。关键词:接口,键盘,AT89C52,LCD1602目 录摘 要I1 前言12 总体设计22.1 设计要求22.2 整体方案设计22.1.1 方案论证22.1.2 方案比较33 硬件设计43.1 AT89C51单片机的功能43.2 复位电路的设置53.3 4X4键盘设计63.4 单片机模块73.5 LCD1602模块83.6 整体电路设计94 软件设计115 KEIL与PROTEUS联调12结 论13参考文献14附录1:电路总图15附录2:软件代码16第 I 页1 前言随着社会经济的快速发展,人们对自动控制要求的地方也越来越多。而在生活和生产的各领域中,凡是有自动控制要求的地方都会有单片机的身影出现;从简单到复杂,从空中到地面,几乎是凡能想像到的地方都有使用单片的需求。现在尽管单片机的应用已经很普遍,但仍有许多可以用单片机控制而尚未实现的项目,因此,单片机的应用大有想像和拓展空间。单片机的应用有利于产品的小型化、多功能化和智能化,有助于提高劳动效率,减轻劳动强度,提高产品质量,改善劳动环境,减少能源和材料消耗,保证安全等。单片机因其性价比高, 处理能力强, 且抗干扰能力好, 在医疗器械、机电液控制、数据传输等各类工控系统和设备仪器中得到广泛应用。一方面, 在实际应用中, 单片机经常需要将采集到的数据发送给PC机进行处理或保存等; 另一方面, 工控系统和设备仪器设计, 因环境或软硬件资源的限制, 也往往需要不同的通信接口。比如, 很多工控PC机的键盘接口因受恶劣环境不利于键盘的使用而处于闲置状态。因此, 设计一个具有通用性的4x4键盘通信接口既方便PC机进行外设扩展, 又丰富了单片机的接口资源。目前, 单片机协议进行通信较多的是单片机接收4x4键盘设备的数据, 而以单片机做为键盘与PC机通信则较为少见。但是,单片机应用的意义绝不仅限于它的广阔范围以及所带来的经济效益上,更重要的意义还在于:单片机的应用正从根本上改变着传统的控制系统设计思想和设计方法。从前必须有模拟电路或数字电路实现的大部分功能,现在已能使用单片机通过软件编程的方法来实现。这种以软件取代硬件并提高系统性能的控制系统“软化”技术,称之为微控制技术。微控制技术是一种全新的概念,是对传统控制技术的一次革命。随着单片机应用的推广普及,微控制技术必将不断发展、日益完善和更加充实。第 1 页2 总体设计2.1 设计要求利用51单片机设计一4x4行列键盘,并在LCD上显示键值。同时显示的键值为09、AD、#、*、这十六个值。2.2 整体方案设计本设计的整体思路是:利用4x4键盘,通过AT89C52单片机接收4x4键盘的键值,并显示在LCD1602上。2.1.1 方案论证设计中采用了三个方案,具体的方案见方案一、方案二和方案三。方案一:普通键盘设计方案采用普通的4x4键盘,通过键盘扫描得到键值,有单片机控制并显示在LCD上,优点是成本低,设计简单数字显示比较直观,缺点是键盘扫描效率不够且容易出错。4x4键盘AT89C52单片机LCD1602显示图2.1 普通键盘整体方案一框图方案二:数码管显示设计方案采用普通的4x4键盘,通过键盘扫描得到键值,由单片机控制并显示在数码管上,优点是成本低,设计简单,键盘自动扫描,自动识别,自动编码,有键按下时才发送数据,因此减轻了CPU的负担,缺点是数码管显示不直观。4x4键盘AT89C52单片机数码管显示图2.2 4x4键盘整体方案二框图2.1.2 方案比较由于方案一采用的是4X4键盘,设计需要CPU不断的扫描键盘,占用了大量的CPU资源,方案二利用4x4键盘,设计需要CPU不断的扫描键盘,占用了大量的CPU资源,并且用数码管显示不够直观,交互界面不够好,因此综合方案一和方案二的优点,本设计采用了方案一较好。第 24 页3 硬件设计3.1 AT89C51单片机的功能 图3.1 AT89C51单片机因将其主要组成部分集成在一个芯片上而得名,具体说就把中央处理器CPU(Central processing unit)。随机存储器RAM(Random ac cess memory)。只读存储器ROM(Read only memory)。中断系统、定时器计数器以及IO(Input/output)接口电路等主要微型机部件集成在一个芯片上。虽然单片机只是一个芯片,但从它的组成和功能上看,它已经具有了计算机系统一样的属性。为此,称它为单片微型计算机SCMC(Single chip micro computer),简称单片机。同时由于单片机主要应用与控制领域,并用以实现各种测试和控制功能,为了强调起控制属性,也可以把单片机称为微控制器MCU(Micro controller unit)。在国际上,“微控制器”的叫法似乎更通用一些,而在我国则比较习惯与“单片机”这一名称。还有就是单片机在应用时,通常是处于控制系统的核心地位并融入其中,即以嵌入的方式进行使用,为了强调其嵌入的特点,也常常将单片机称为嵌入式微控制器EMCU(Embedded micro controller unit)。在单片机的电路和结构中,有许多嵌入式应用的特点。3.2 复位电路的设置复位电路产生复位信号,复位信号送入RST后还要送至片内的施密特触发器,由片内复位电路在每个机器周器的S5P2时刻对触发器输出采样信号,然后由内部复位电路产生复位操作所要的信号。一般的复位电路可分为上电自动复位和按键复位,我们在此选用的是上电复位。上电自动复位原理:RST引脚是复位信号的输入端,只要高电平的复位信号持续两个机器周期以上的有效时间,就可以使单片机上电复位。上电自动复位是通过电容充电实现的,上电瞬间,RST端电位与Vcc相同,随充电电流的减少,RST的电位逐渐下降,直到复位信号无效。按键复位在此不在作过多的介绍,其原理和上电复位是相同的。但其采用的是脉冲复位电路和电平复位电路两种。复位电路和单片机最小系统如下图3.2所示:图3.2复位电路3.3 4x4键盘设计图3.3 4x4键盘行列式键盘因为管理程序比较复杂,所以行列式键盘采用扫描技术。常采用的扫描技术有:扫描法、反转法、状态矩阵法等。而本次设计采用线反转法扫描的过程步骤如下:(1)先从P1口的高4位输出低电平(列),低4位输出高电平(行):即P1=0x0f。从P1口读取键盘状态。这时,如低4位中只要有一位出现“0” ,说明此行中有键按下。各行有键按下时,从P1口读取的数值依次是:0EH、0DH、0BH、07H。(2)再从P1口的低4位输出低电平(行),高4位输出高电平(列):即P1=0xf0。从P1口读取键盘状态。这时,如高4位中只要有一位出现“0” ,说明此列中有键按下。各列有键按下时,从P1口读取的数值依次为:E0H、D0H、B0H、70H。(3)将两次读取的特征值,根据图3.2进行组合,得到当前“按键的特征码”。3.4 单片机模块STC89C52单片机是Atmel公司生产的单片机,51的内核,具有处理能强、运行速度快、功耗低等优点。最小系统包括单片机,电源,复位电路。单片机接收PS2键盘的键值,并控制LCD的显示。其系统框图如下图所示:接收4x4键值盘STCAT89C2单片机控制LCD1602显示电源供电复位电路图3.4 单片机控制系统框图STC89C52单片机有4X8个IO口,其中P0口需外接上拉电阻,因此本次设计采用P1口作为4x4键盘接口,P0口作为与LCD1602的接口,其电路图如下图3.5所示:图3.5 单片机最小系统图3.5 LCD1602模块LCD1602采用8位并行数据传输,其操作时序如下图3.6所示:图3.6 LCD单片机图LCD1602的指令集对应的指令码如表3.1所示指 令说 明码RSR/WD7 D6D5D4D3D2D1D0清除显示屏000000000*光标回到原点000000001*进入模式设定00000001I/DS显示幕ON/OFF0000001DCB移位000001S/CR/L*功能设定00001DLNF*字发生器地址设定0001ACG设置显示地址001ADD忙碌标志位BF00BF显示数据10写入数据读取数据11读出数据I/D I/D=1表示加1 I/D=0表示减1S S=1表示显示幕ON S=0表示显示幕OFF D D=1表示显示幕ON D=0表示显示幕OFF C C=1表示光标ON C=0表示光标OFF B B=1表示闪烁ON B=0表示闪烁ONS/C S/C=1表示显示屏幕移位 S/C=0光标移位R/L R/L=1表示右移 R/L=0表示右左移 D/L D/L=1表示8位 D/L=4表示4位 F F=1表示5x10点矩阵 F=0表示5x7点矩阵 N N=1表示2行显示行 N=0表示1行显示行 BF BF=1:内部正在动作 BF=0:可接受指令或数据码5表3.1指令码LCD1602接口由8位数据线,电源地电源正,液晶显示偏压信号(VL),数据命令选择端(RS),读写选择端(RW)组成。其接口信号说明如下图3.7所示:图3.7接口信号说明图可以在1602的液晶显示偏压信号端接一个可变电阻,调节显示亮度,初始状态时,调至1602上面一排显示12个黑块为止,LCD1602电路图如下图3.8所示:图3.8 LCD1602电路图3.6 整体电路设计最终设计电路如下图3.9所示,4x4键盘有键按下就读出数据,最终在LCD1602液晶显示器上显示。图3.9 4x4键盘显示电路4 软件设计1、主程序设计:首先初始化IO口和键盘、LCD1602,然后接收按键的键值,并通过8位并行传输方式传送给LCD1602显示。2、获取键值程序:按照4x4键盘协议操作,键盘按下时发送通码,弹起时发送断码,在单片机中,将接收到的码字与第二套扫描码比较,得出键值。本次设计共采用16个键,模拟键。3、LCD显示程序:首先初始化LCD1602端口和寄存器,然后接收单片机传送的数据,通过1602写操作时序显示接收到的数据。开始初始化键盘、LCD接收键值LCD1602上显示处理键值4.1 程序整体设计框图5 Keil与Proteus联调在protues上进行仿真实验。首先使用KeilC将编写完成的程序编译生成HEX文件,将HEX文件烧录到两片单片机中,进行仿真实验,结果如下图所示,可以看到,接收端已将接受到的数据完整的显示了出来。图5.1仿真效果图结 论本系统采用第二套键盘扫描码,利用4x4键盘作为输入,准确度比普通键盘高,完成了系统的仿真图,电路图和程序设计,实现了系统的功能。本次设计完成后,在效果上能完全达到原先设计的功能。例如,通过按下按键“1”,能将数值“1”发送到LCD上显示驱动程序经Keil uVision3编译,在AT89C52上单片机通过,该模拟键盘接口可以作为一个接口模块嵌入到其他设备仪器和工程控制系统,增加了与PC机的通信途径。在应用和测试结果分析中,该接口模块具有较高的可靠性与稳定性由于时间仓促和我们自身水平有限,本设计在功能上也只是完成了一些基本功能,对于电路的可靠性,稳定性等参数还未做过详细的测试。仿真中出现的一些问题,也尚未解决。经过繁忙而又紧张的课程设计,终于顺利的完成了设计任务。虽然在这段时间里每天都那么繁忙,但是在这忙碌的过程中却得到了许多的收获。经过课程设计,在查阅资料的过程中,学习了基于单片机的C语言程序设计,了解了单片机串行通信的基本知识,对于以后的学习和工作都有很大的益处。在学习的过程中,也遇到了一些困难,比如开始的时候,由于发送端和接收端的通信协议没有做好,导致数据不能正确的传输,在解决问题的过程中,对于通信协议的实现有了深刻的认识。通过这次课程设计,锻炼了自己独立思考的能力。参考文献1 张培仁.基于 C 语言编程 MCS-51 单片机原理与应用M. 北京:清华大学出版社,2003. 2 杨振江、杜铁军.流行单片机实用子程序及应用实例M.西安电子科技大学出版社,2002. 3 蔡美琴、张为民.MCS-51 系列单片机系统及其应用(第二版)M. 北京:高等教育出版社,2004.4 苏家健.单片机原理及应用技术M. 北京:高等教育出版社,2004.5 C语谭浩强.言程序设计(第三版)M.北京:清华大学出版社,2005.6 黄惟公.单片机原理与应用技术:西安电子科技大学出版社20077 张毅刚.MC-51单片机应用设计(二版):哈尔滨工业大学出版社 20058 李广第.单片机基础.北京:北京航空航天大学出版社9 杨文龙.单片微机原理及应用:西安电子科技大学出版社10 胡汉才.单片机原理及接口技术.北京:清华大学出版附录1:电路总图图 附录1 4x4键盘显示电路总图附录2:软件代码1 键码处理程序:#include "SMC1602.h"void vKeyProcess(unsigned char ucKeyCode)vWriteCMD(0xC7);switch(ucKeyCode)case 11:vShowOneChar('1');break; /'1'case 12:vShowOneChar('2');break; /'2'case 13:vShowOneChar('3');break; /'3'case 21:vShowOneChar('4');break; /'4'case 22:vShowOneChar('5');break; /'5'case 23:vShowOneChar('6');break; /'6'case 31:vShowOneChar('7');break; /'7'case 32:vShowOneChar('8');break; /'8'case 33:vShowOneChar('9');break; /'9'case 41:vShowOneChar('0');break; /'0'case 14:vShowOneChar('A');break; /'A'case 24:vShowOneChar('B');break; /'B'case 34:vShowOneChar('C');break; /'C'case 44:vShowOneChar('D');break; /'D' case 43:vShowOneChar('#');break; /'#'case 42:vShowOneChar('*');break; /'*'default:break;2 键盘扫描子程序:#include <at89x51.h>#define SCANPORT P1 /4×4键盘扫描端口,低4位是行线,高4位是列线。 /采用逐列扫描的方法,无按键时,低4位输出1,高4位输出0。 /当有按键时,高4位输出扫描电位,低4位输入扫描结果。/*/* *全局变量*unsigned char uca_LineScan4=0xEF,0xDF,0xBF,0x7F;/列线扫描电压,分为第1,2,3,4根列线 /为低电平,其他为高电平。/*/*函数实现* /*unsigned char ucKeyScan()unsigned char ucTemp=0; /扫描状态暂存。unsigned char ucRow=0,ucLine=0; /行号,列号。for(ucLine=0;ucLine<4;ucLine+)/列扫描SCANPORT=uca_LineScanucLine; /输出扫描电位。ucTemp=SCANPORT&0x0F; /输入扫描电位,并屏蔽高4位。if(ucTemp!=0x0F) /判断该列是否有按键按下。switch(ucTemp)case 0x0E: ucRow=10;break; /如果有,则判断行号。case 0x0D: ucRow=20;break;case 0x0B: ucRow=30;break;case 0x07: ucRow=40;break;default: ucRow=50;break;break; /<<<<<<<<<<<<恢复键扫描处理前初始状态>>>>>>>>>>>>>>>>>>SCANPORT=0x0F; /恢复P1口return ucRow+ucLine+1;/返回按键编码。格式为2位数,高位为行号,低位为列号。3 驱动程序:/*#include <at89x51.h>/<<<<<<<<<<<<<<<<<<<<<<<<<<端口设置宏定义>>>>>>>>>>>>>>>>>>>>>>>>>>>>>#define LCDRS P2_0 /寄存器选择信号: /0-数据寄存器; /1-指令寄存器。#define LCDRW P2_1 /读写信号: /1-读LCD; /0-写LCD。#define LCDE P2_2 /片选信号,当输入下降沿信号时, /执行指令或传送数据。#define LCDPORT P0 /LCD数据接口。/* *延时函数*/*void vDelay()unsigned int uiCount;for(uiCount=0;uiCount<250;uiCount+);/*/*/* *把1个命令写入LCD*/*void vWriteCMD(unsigned char ucCommand) vDelay();/先延时。LCDE=1;/然后把改为写入命令状态。LCDRS=0;LCDRW=0;LCDPORT=ucCommand;/再输出命令。LCDE=0;/最后执行命令。/*/* *把1个数据写入LCD*/*void vWriteData(unsigned char ucData) vDelay(); /先延时。LCDE=1; /然后把改为写入数据状态。LCDRS=1;LCDRW=0;LCDPORT=ucData; /再输出数据。LCDE=0; /最后显示数据。/*/* *把1个字符显示到当前光标处*/*void vShowOneChar(unsigned char ucChar)switch(ucChar)case ' ': vWriteData(0x20);break;case '!': vWriteData(0x21);break;case '"': vWriteData(0x22);break;case '#': vWriteData(0x23);break;case '$': vWriteData(0x24);break;case '%': vWriteData(0x25);break;case '&': vWriteData(0x26);break;case '>': vWriteData(0x27);break;case '(': vWriteData(0x28);break;case ')': vWriteData(0x29);break;case '*': vWriteData(0x2A);break;case '+': vWriteData(0x2B);break;case '-': vWriteData(0x2D);break;case '.': vWriteData(0x2E);break;case '/': vWriteData(0x2F);break;case '=': vWriteData(0x3D);break;case '<': vWriteData(0x3E);break;case '?': vWriteData(0x3F);break;case '': vWriteData(0x5E);break;case ':': vWriteData(0x3A);break;case '0': vWriteData(0x30);break;case '1': vWriteData(0x31);break;case '2': vWriteData(0x32);break;case '3': vWriteData(0x33);break;case '4': vWriteData(0x34);break;case '5': vWriteData(0x35);break;case '6': vWriteData(0x36);break;case '7': vWriteData(0x37);break;case '8': vWriteData(0x38);break;case '9': vWriteData(0x39);break;case 'A': vWriteData(0x41);break;case 'B': vWriteData(0x42);break;case 'C': vWriteData(0x43);break;case 'D': vWriteData(0x44);break;case 'E': vWriteData(0x45);break;case 'F': vWriteData(0x46);break;case 'G': vWriteData(0x47);break;case 'H': vWriteData(0x48);break;case 'I': vWriteData(0x49);break;case 'J': vWriteData(0x4A);break;case 'K': vWriteData(0x4B);break;case 'L': vWriteData(0x4C);break;case 'M': vWriteData(0x4D);break;case 'N': vWriteData(0x4E);break;case 'O': vWriteData(0x4F);break;case 'P': vWriteData(0x50);break;case 'Q': vWriteData(0x51);break;case 'R': vWriteData(0x52);break;case 'S': vWriteData(0x53);break;case 'T': vWriteData(0x54);break;case 'U': vWriteData(0x55);break;case 'V': vWriteData(0x56);break;case 'W': vWriteData(0x57);break;case 'X': vWriteData(0x58);break;case 'Y': vWriteData(0x59);break;case 'Z': vWriteData(0x5A);break;case 'a': vWriteData(0x61);break;case 'b': vWriteData(0x62);break;case 'c': vWriteData(0x63);break;case 'd': vWriteData(0x64);break;case 'e': vWriteData(0x65);break;case 'f': vWriteData(0x66);break;case 'g': vWriteData(0x67);break;case 'h': vWriteData(0x68);break;case 'i': vWriteData(0x69);break;case 'j': vWriteData(0x6A);break;case 'k': vWriteData(0x6B);break;case 'l': vWriteData(0x6C);break;case 'm': vWriteData(0x6D);break;case 'n': vWriteData(0x6E);break;case 'o': vWriteData(0x6F);break;case 'p': vWriteData(0x70);break;case 'q': vWriteData(0x71);break;case 'r': vWriteData(0x72);break;case 's': vWriteData(0x73);break;case 't': vWriteData(0x74);break;case 'u': vWriteData(0x75);break;case 'v': vWriteData(0x76);break;case 'w': vWriteData(0x77);break;case 'x': vWriteData(0x78);break;case 'y': vWriteData(0x79);break;case 'z': vWriteData(0x7A);break;default: break;/*/* *把1个字符串显示到当前光标处*/*void vShowChar(unsigned char ucaChar)unsigned char ucCount;for(ucCount=0;ucCount+)vShowOneChar(ucaCharucCount);if(ucaCharucCount+1='0')break;/*/*/*把1个3位数字显示到当前光标处*/*void vShowNumber(unsigned int uiNumber)unsigned char ucaNumber3,ucCount;if(uiNumber>999)uiNumber=999;ucaNumber0=uiNumber/100;/把计算数字的每个位存入数组。ucaNumber1=(uiNumber-100*(int)ucaNumber0)/10;ucaNumber2=uiNumber-100*(int)ucaNumber0-10*ucaNumber1;for(ucCount=0;ucCount<3;ucCount+)vShowOneChar(ucaNumberucCount+48);/从首位到末位逐一输出。4 键盘和LCD:#include "includes.h"