版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第7章MCS-51系列单片机与键盘、显示 器、ADC和DAC的接口设计7.1MCS-51单片机系统的键盘设计7.2MCS-51单片机系统的显示器接口和编程控制7.3MCS-51单片机与ADC和DAC的接口习题七7.1.1非编码式键盘的接口设计和编程利用MCS-51单片机实现的最简单的键盘如图7-1所示。图中利用8051单片机的P1口构成F1(功能1键)、F2(功能2键)、F3(功能3键)、F4(功能4键)、▲(向上翻页)、▼(向下翻页)、ENT(确认)和ESC(取消)等8个按键。7.1MCS-51单片机系统的键盘设计图7-1利用P1口构成8个按键的电路图7-1中P1口的8个位作为按键使用时,它们都作为输入口,识别这些按键的软件非常简单,P1口的各个位状态代表各按键的状态。按照图7-1这样利用n位输入端口构成的n个键的原理称为“独立式”按键结构。识别按键的程序如下:#define
F1_Key
0x01
//定义常量表示键盘码#define
F2_Key
0x02#define
F3_Key
0x03#define
F4_Key
0x04#define
UP_Key
0x05
//向上翻页键的键值=5#define
DOWN_Key
0x06 //向下翻页键的键值=6#define
ENT_Key
0x07
//确认键的键值=7#define
ESC_Key
0x08
//取消键的键值=8unsignedcharGetKeyPadCode(void){
unsignedcharkey;
key=P1;
if(P1==0xFF)
//判断P1口的8个位是否全为“1”,如果全为“1”表示无按键
return0xF0;
//如果没有键按下,则返回0XF0
switch(key)
{
case0xFE:key=F1_Key;
break; //返回F1键的键值
case0xFD:key=F2_Key;
break; //返回F2键的键值
case0xFB:key=F3_Key;
break; //返回F3键的键值
case0xF7:key=F4_Key;
break; //返回F4键的键值
case0xEF:key=UP_Key;
break; //返回向上翻页键的键值
case0xDF:key=DOWN_Key;break; //返回向下翻页键的键值
case0xBF:key=ENT_Key;break;//返回确认键的键值
case0x7F:key=ESC_Key;break;//返回取消键的键值
default:key=0xF0;break;
}
return(key);}上面的程序根据P1口的8个位中低电平的位置识别被按下的键,然后返回相应的键码。程序比较简单,得到整个键码的执行过程大约需要几十微秒。但是,按键被按下是一个机械触点的接触(闭合)过程,按键被释放是一个机械触点的断开过程,在这两个机械触点动作过程中会出现机械触点抖动,触点的机械抖动期间会造成P1口相应的位出现电平抖动(即不稳定电平),如图7-2所示。另外,由于外界的振动也可能造成系统按键的触点误动作。由于触点的机械特性造成的电平抖动时间一般为5~10ms,如果在此期间连续快速扫描键码,容易使CPU错误响应按键。图7-2按键被按下和释放时的电平抖动示意图为了保证单片机能够正确处理和响应键盘,保证键稳定闭合一次,单片机只响应一次,系统对键盘的扫描过程必须有过滤电平抖动的处理程序。由于机械触点的抖动时间大约在10ms以内,简单的“去抖动”处理就是连续读键盘至少两次,每次间隔大于20ms。如果连续两次得到的键码是相同的,那么表示按键的状态(按下状态或释放状态)是稳定的,然后CPU就可以响应按键的动作。采用查询等待方式扫描键盘的程序如下:unsignedcharidataNowKeyCode=0;
//定义一个全局变量存储当前的按键unsignedcharScanKeyPad(void)
//扫描键盘程序,有键按下时返回1,否则返回0{
unsignedchark1,k2;
do{ //循环扫描键码,直至连续两次得到相同的键码
k1=GetKeyPadCode();
//调读键码的函数,将返回的键码暂存在变量k1中
if(k1==0xFF)
//判断是否有键按下
if(k1==0xFF)
//判断是否有键按下
return0;
//如果没有按键动作,返回0
Delay(200);
//延时20ms
k2=GetKeyPadCode();
//调读键码的函数,将返回的键码暂存在变量k2中
if(k2==0xFF)
//判断是否有键按下
return0;
//如果没有按键动作,返回0
}while(k1!=k2);
//如果连续两次得到的键码不相同,继续扫描键码
NowKeyCode=k1;
//保存当前被按下键的键码在变量NowKeyCode中
return1;
//有键被按下,返回1,键码保存在变量NowKeyCode中
}采用这种查询等待方式扫描键盘的程序在嵌入式实时控制系统中是非常不合理的,当有键被按下或释放时,系统CPU执行上面的ScanKeyPad()子程序至少需要20ms的时间,在此期间其他任务都被迫终止(除了中断服务程序外),造成嵌入式实时系统的实时性降低。为了不影响系统的实时性,CPU对键盘处理可以采用定时扫描方式,由MCS-51单片机内部的定时器产生定时中断,定时唤醒CPU扫描键盘。下面的程序是采用定时器0定时20ms,产生20ms定时中断,当定时器溢出时,主程序得到T0中断服务程序发来的Over20ms的消息,然后进入键盘扫描任务。unsignedcharidataOver20ms;
//全局变量,T0溢出标志unsignedcharidataNowKeyCode,OldKeyCode;
//KeyPadTask()必需的全局变量unsignedcharidataKeyPadWatCnt;
//KeyPadTask()必需的全局变量voidInit_8051(void){
EA=0;
//初始化T0之前关闭中断
TR0=0;
//T0定时器停止工作
TMOD=0x01;
//设置T0工作模式为定时器,工作方式为方式1
TL0=0xDF;
//fosc=12MHz,要求定时20ms
TH0=0xB1;
//装入T0定时器初始值
IE=0x82;
//允许T0和T1中断请求
Over20ms=0; //将“20ms定时时间到”的标志清零
TR0=1;
//启动T0开始定时
EA=1;
//中断总使能位置位
…
//其他初始化程序}interrupt[0x0B]voidT0_ISR(void) //T0中断服务程序{
TL0=0xDF;
//fosc=12MHz,要求定时20ms
TH0=0xB1;
//重新装入T0定时器初始值
Over20ms=1; //20ms定时时间到,向主程序发送标志}voidmain(void){
Init_8051();
//初始化程序
while(1)
{
//实时系统的任务之一是处理键盘任务
if(Over20ms)
//判断是否有T0中断的标志
{
//当收到T0中断的标志,处理键盘
Over20ms=0;
//将T0中断服务程序发送来的标志清零
KeyPadTask(); //处理键盘任务
}
//othertaskrunninghere //实时系统的其他任务的执行和响应
}}voidKeyPadTask(void)
//处理键盘任务{
unsignedcharnowk;
nowk=GetKeyPadCode();
if(nowk==0xF0)
//判断是否有按键
{
//当前没有任何键被按下时,将各变量还原
KeyPadWatCnt=0;
//键盘“去抖动”计数器清零
OldKeyCode=0;
//保存前一次键码的变量清零
NowKeyCode=0;
//存储“已经响应过的按键”变量清零
return;
//没有按键被按下,直接返回
}
if(OldKeyCode!=nowk)
//判断是否是新的按键
{
OldKeyCode=nowk; //保存新的键码在变量OldKeyCode中
KeyPadWatCnt=0; //键盘“去抖动”计数器清零
return;
//保存新的键码后直接返回
}
//本次得到的键码与前一次的键码相同,继续向下运行
if((KeyPadWatCnt++)>0x02)
//判断是否已经有连续两次相同的键码
{
if(NowKeyCode==OldKeyCode)
//判断当前的按键是否已经被响应
return;
//当前的按键已经被响应,就不能响应两次
NowKeyCode=OldKeyCode;
//有连续两次相同的键码,说明有键被稳定按下, 将被响应的按键保存在NowKeyCode变量中
//KeyPadProFun(); //处理、响应未响应的按键动作
}}按照上面程序的执行过程,MCS-51单片机每隔20ms执行一次键盘任务(执行一次KeyPadTask()子程序)。如果没有按键动作,执行过程仅需要几微秒时间;当有键被按下或释放时,不考虑键盘响应(执行KeyPadProFun()子程序)的时间,仅需要大约几十微秒的时间。这比前面以“查询等待方式”实现的程序的执行速度提高了1000倍左右,在实时性要求比较高的应用系统中,定时扫描方式实现处理键盘的程序更合理。利用MCS-51单片机的I/O端口扩展独立式按键在按键个数较少的系统中可以使用。如果系统需要按键的个数比较多,则这种方式需要占用系统大量的I/O端口,非常浪费系统的资源。当系统需要按键的个数比较多时采用行列式矩阵结构的键盘更合理,即利用MCS-51系列单片机的I/O端口相互交叉形成的行列式键盘,这种方法不仅节省I/O端口,而且键盘扫描和键盘识别的软件也比较简单。图7-3是采用行列式方法,利用8051的P1口构成16个按键的电路。这个4×4的行列式键盘的行线是P1.0~P1.3,列线是P1.4~P1.7,形成4×4=16个交叉点,每个交叉点连接一个按键。16个按键分别为:数字键“1”(P1.0与P1.7的交叉点)、数字键“2”(P1.0与P1.6的交叉点)、数字键“3”(P1.0与P1.5的交叉点)、功能键“Fn”(P1.0与P1.4的交叉点)、数字键“4”(P1.1与P1.7的交叉点)、数字键“5”(P1.1与P1.6的交叉点)、数字键“6”(P1.1与P1.5的交叉点)、向上翻页键“▲”(P1.1与P1.4的交叉点)、数字键“7”(P1.2与P1.7的交叉点)、数字键“8”(P1.2与P1.6的交叉点)、数字键“9”(P1.2与P1.5的交叉点)、向下翻页键“▼”(P1.2与P1.4的交叉点)、“CLR”(P1.3与P1.7的交叉点)、数字键“0”(P1.3与P1.6的交叉点)、“ESC”(P1.3与P1.5的交叉点)、“ENT”(P1.3与P1.4的交叉点)。当没有任何键按下时,所有的交叉点都是断开的,由于列线的上拉电阻作用,使其保持高电平。如果行线P1.0~P1.3被软件设置为低电平,当有任何按键被按下时,该键所在的行线和列线被按键短路,那么相应的列线就变为低电平。图7-3利用P1口构成16个按键的电路行列式结构键盘的键码识别过程如下:MCS-51单片机软件首先设置P1.0~P1.3(行线)都输出低电平,列线P1.4~P1.7为输入端口,读列线的状态并判断。如果列线都为高电平,说明没有任何交叉点闭合,即没有任何键被按下;如果有任何列线为低电平,说明有键被按下,并且根据低电平列线的位置可以确定被按下的键在哪一列。譬如数字键“0”被按下,低电平的列线是P1.6,软件根据P1.6为低电平这个条件可以准确地确定被按下的键肯定是数字键“2”、“5”、“8”和“0”4个键中的某一个,但是具体是哪一个键还不能确定,需要利用行线扫描查找键的准确位置。保存低电平列线的位置后,软件将行线全部设置为高电平,然后仅将第一行线P1.0置为低电平,判断P1.6(前面确定的低电平的列线位置)是否为低电平,由于P1.0和P1.6的交叉点并未闭合,因而此时P1.6为高电平,软件可以确定不是数字键“2”;需要继续查找,将行线P1.0置为高电平,并且将第二行线P1.1置为低电平,然后判断P1.6的电平状态,如此重复,直到对应行线为低电平时,列线P1.6也为低电平,它们的交叉点就是被按下的键的位置。当使用n个双向I/O端口构成行列式键盘时,键的个数可以利用下面的式子确定:
n为偶数n个双向I/O端口构成的按键个数=
n为奇数当n=8时,构成的按键个数为16个;当n=16时,构成的按键个数为64个。下面的程序是识别4×4的行列式键盘的程序:#define
Numeric0Key
0x0
//定义常数表示相应的键码#define
Numeric1Key
0x01#define
Numeric2Key
0x02#define
Numeric3Key
0x03#define
Numeric4Key
0x04#define
Numeric5Key
0x05#define
Numeric6Key
0x06#define
Numeric7Key
0x07#define
Numeric8Key
0x08#define
Numeric9Key
0x09#define
CLRKey
0x0A#define
FnKey
0x0B#define
PageUpKey
0x0C#define
PageDownKey
0x0D#define
ESCKey
0x0E#define
ENTKey
0x0F
//所有正常键码的高4位都为“0”codeunsignedcharKeyPadPositionTable[]={
0xB7,0x7E,0xBE,0xDE,0x7D,0xBD,0xDD,0x7B,0xBB,0xDB,
//数字键“0”~“9”
0x7E,0xEE,0xED,0xEB,0xD7,0xE7
//CLR、Fn、▲、▼、ESC、ENT键}unsignedcharGetKeyPadCode(void)
//识别4×4的行列式键盘的键码的子程序{
//如果无键,返回0xF0;否则返回键码
unsignedcharkey,column,line,i;
key=P1;
P1=key&0xF0;
//设置P1.0~P1.3(行线)为低电平
for(key=4;key>0;key--);
//延时4微秒,等待输出电平状态稳定
key=P1;
//读P1.4~P1.7(列线)的状态
if((key&0xF0)==0xF0)
//判断是否有列线为低电平
return(0xF0);
//如果所有列线都为高电平,即无任何键被按下,则返回
column=key&0xF0;
//保存列线的状态在变量column中
line=0xFE;
//首先置P1.0为低电平
for(i=0;i<4;i++)
//行线被逐个置低电平,确定键的位置
{
P1=line;
//将惟一的低电平信号写到P1口
for(key=2;key>0;key--);
//延时2微秒,等待输出电平状态稳定
key=P1;
if((key&0xF0)==column)
//比较低电平的列线
break;
//被按下的键位置被确定,终止循环
line<<=1;
//低电平的位置左移一位
}
P1=0xF0;
//重新将所有的行线置为低电平状态
if(i==4)
return(0xF0);
//查找按键的位置操作失败,认为没有按键,返回
key=line&column;
//合并行线和列线的状态,其中高低4位各有一个“0”
for(i=0;i<16;i++)
//根据行列交叉点在键盘位置表中快速查找位置
if(key==KeyPadPositionTable[i])
break;
//如果找到,终止查找
if(i!=16)
returni;
//已经找到键的位置和键码,返回键码
return(0xF0);
//在表中未找到响应的键位置,认为没有键
}比较独立式键盘的读取键码子程序GetKeyPadCode()和4×4的行列式键盘的读取键码子程序GetKeyPadCode(),MCS-51单片机执行两个子程序的时间有较大差异,后者大约是前者的5倍,后者估计需要0.1ms左右。显然,实现相同个数的按键时,独立式键盘的键码识别速度较快,但是需要占用较多的I/O端口;行列式键盘的键码识别速度相对较慢,但是能够有效地节省I/O端口的资源。图7-3中扩展的键盘允许应用程序以中断方式处理和响应键盘,所有的行线都保持低电平状态,一旦有任何按键被按下时,INT0引脚处会出现低电平的中断请求信号,在INT0中断服务程序中向主程序发送“有按键动作”的消息(标志)。当主程序收到该消息时,才运行键盘处理和响应的任务,CPU在没有按键的时间中可以处理和响应其他任务。这种方法比较适合嵌入式实时控制系统软件对行列式键盘的处理。7.1.2其他方式的键盘接口在上一节中利用MCS-51系列单片机的P1口扩展独立式键盘和行列式键盘是比较常用的非编码式键盘接口设计,但是,P1口是支持位操作的双向I/O端口,是MCS-51单片机的宝贵资源,往往更希望把它们作为扩展串行接口的器件的I/O线使用。为MCS-51单片机系统扩展键盘还有其他方法,如利用第六章中提到的“扩展的外部I/O通道”构成行列式开关矩阵,是利用外部扩展资源实现行列式键盘的方法之一。这种行列式键盘与前面讲到的行列式键盘的键码识别原理相同,无非是P1口和两个外部I/O通道(一个是只读的三态缓冲门,另一个是只写的锁存器)之间的访问方式不同而已。图7-4是利用MCS-51单片机扩展的I/O通道实现16个按键的电路,电路中扩展了一个8位的三态缓冲门(U2)74HC244和一个8位D型锁存器(U3)74HC374,其中三态缓冲门的低4位作为输入口使用,是4×4键盘的4根列线;锁存器的低4位作为输出口使用,是键盘的4根行线。这个电路的键码识别方法与前一节中的4×4行列式键盘相同。图7-4利用扩展的I/O通道构成16个按键的电路另外,也可以利用专用的键盘/显示器接口芯片——Intel公司的8279实现键盘的接口。它属于一种专用编码式键盘芯片,是Intel公司提供的通用键盘/显示器接口芯片。利用8279可以实现对键盘和动态扫描LED显示器的自动扫描,自动识别键盘的键码。在MCS-51系列单片机系统中扩展8279芯片实现键盘和LED显示器,不仅可以大大节省单片机对键盘和显示器的操作时间,从而减轻单片机执行程序的负荷,提高嵌入式实时系统的实时性,而且控制程序简单,显示稳定,不会出现误动作。
PDIP封装的8279芯片一共有40个引脚,其内部包括键盘输入控制逻辑块、I/O控制和数据缓冲块、扫描计数器、接口和译码控制逻辑、FIFORAM(FirstInFirstOutRAM)队列等。8279提供4根键盘和显示器的扫描输出线及8根键盘状态反馈线,利用它们可以直接构成4×8=32个键的行列式键盘。有关Intel8279的详细说明和接口设计、编程方法等请参考相关资料。随着CPLD和FPGA技术的迅速发展,以“单片机+CPLD/FPGA”为核心设计、实现的嵌入式控制系统越来越多,将传统的单片机外围器件(除了大容量存储器外)绝大多数都可以集成在一片CPLD/FPGA内部,即使是一个功能强大、复杂的单片机系统也都是“单片机+CPLD/FPGA”的2片结构,这种方法既能够发挥CPLD和FPGA的灵活性,而且开发的系统可以适用于多种目的,系统的结构比较简单,可靠性得以提高。8279作为一种传统的键盘和显示器专用接口芯片,其功能完全可以集成到CPLD/FPGA内部,而不需要专门扩展这些接口芯片。常用的编码式专用键盘接口扩展芯片还有74HC922和74HC923,它们是属于74系列的专用集成电路。74HC922提供行线X1~X4和列线Y1~Y4,并且都具有内部上拉电阻,利用行线和列线可以直接构成4×4=16个键的行列式键盘;74HC923具有4根行线和5根列线,可以构成4×5=20个键的行列式键盘。74HC922采用4位并行三态数据总线输出键码,可以与MC-51系列单片机的数据总线直接连接,并且具有“有按键和键码”的标志信号(或握手信号线)。74HC923则采用5位并行三态数据总线输出键码。
74HC922与74HC923的引脚排列(PDIP封装)和名称如图7-5所示。表7-1列出了74HC923的引脚名称和功能。图7-574HC922/3键盘编码器引脚排列和名称与其他专用的键盘编码器芯片相比,74HC922和74HC923都属于低成本的键盘接口扩展芯片,它们具有功能单一、接口简单、使用操作简单等优点。它们在MCS-51单片机系统使用时,器件的外部仅需要两个电容,一个是扫描时钟振荡器电容,另一个是键盘“去抖动”电容。器件的三态数据输出总线可以与MCS-51系列单片机的数据总线直接连接,仅占用单片机的一个I/O扩展地址资源,MCS-51单片机执行外部读操作就可以将键码读入CPU内部寄存器。74HC922和74HC923都带有DataValid信号输出,当有且仅有一个键被按下而且触点稳定闭合时,该信号输出一个有效的低电平脉冲,可以和MCS-51单片机的外部中断输入引脚INT0或INT1连接,实现中断方式处理和响应键盘。图7-6是利用74HC922扩展4×4结构的行列式键盘电路。图7-6利用74HC922扩展4×4结构行列式键盘电路程序使用INT0中断方式处理和响应键盘,当有键被按下时,DAV输出有效信号向8051单片机申请中断。在8051的INT0中断服务程序中,首先从74HC922中将键码读出存放在变量CurrentKeyCode中,并且在读键码的同时将中断请求信号复位,得到正确的键码后,INT0中断服务程序置HaveKeyActive标志有效,向主程序发送消息,键盘的响应和处理在主程序中完成。#include<io51.h>#define
KeyPortAdr*(unsignedchar*)(0x010000)
//74HC922的地址unsignedcharidataCurrentKeyCode,HaveKeyActive=0;interrupt[0x03]voidINT0_ISR(void){
CurrentKeyCode=KeyPortAdr;
//将键码读到变量CurrentKeyCode中
CurrentKeyCode&=0x0F;
//仅低4位有效,所以屏蔽高4位
HaveKeyActive=1; //有按键被按下,向主程序发送消息}…voidmain(void){
…
//初始化程序,包括中断INT0的初始化
while(1){
if(HaveKeyActive) //检查是否有中断INT0的消息
{
HaveKeyActive=0;
//标志被清除
//KeyPadProFun();
//处理、响应按键动作
}
…
//其他任务
}}7.2MCS-51单片机系统的显示器接口和编程控制在以MCS-51单片机为核心的嵌入式控制系统中常用的显示器包括段式LED(LightEmittingDiode,发光二极管)显示器、点阵LED显示器、段式LCD(LiquidCrystalDisplay,液晶显示器)、字符型LCD、图形点阵LCD、段式VFD(VacuumFluorescentDisplay,真空荧光显示器)、字符型VFD、图形点阵VFD等。所有的LED显示器都是将多个发光二极管组合而成。段式LED显示器应用最广泛,它是一种低成本、高可靠性、高稳定性的显示器,而且亮度也比较高,使用寿命长;点阵LED显示器作为户外文字广告和信息牌被广泛使用。LED显示器的缺点是消耗功率大,容易发热,体积相对较大。
LCD显示器具有功耗低、体积小等优点,它们被广泛使用于各种手持设备、智能终端设备,目前LCD显示器作为一种绿色平板显示器已经逐步成为PC的主流显示终端。段式LCD可以适用于各类数字型仪表;字符型LCD能够显示ASCII字符和简单的图形,在各种嵌入式系统中被广泛使用;图形点阵LCD能够显示各种图形、曲线和汉字,在高档仪器和嵌入式终端中被广泛使用。LCD显示器必须采用交流扫描信号,缺点是容易被干扰,而且使用寿命相对较短。
VFD显示器具有亮度高、稳定性高、寿命长等优点,但是所有的VFD器件都必须使用高压驱动电路,而且它们消耗的电流较大。VFD显示器应用最频繁的领域是家用电器。7.2.1LED显示器的接口所有的LED显示器件都是由若干LED组合而成的,当某一个LED导通时,该LED表示的点或段(笔画)被点亮,单片机控制多个不同的点或段的亮或灭,可以显示出不同的数码或字符。常用段式LED显示器包括“七段”结构LED显示器和“米字”结构LED显示器。它们都有共阴极和共阳极两种结构,其中共阴极LED显示器内部所有发光二极管的阴极连接在一起,而所有发光二极管的阳极各自独立;共阳极LED显示器内部发光二极管的阳极连接在一起,而所有发光二极管的阴极各自独立。图7-7是“七段”结构的段式LED显示器的内部结构和外型、引脚的示意图,其中“dp”段是小数点指示段。“米字”型结构的LED显示器的内部结构仅比“七段”结构的LED显示器多了5段,增加的5段从外型上看,是将原来的“g”段改成两段,并在“8”字中间增加“X”形状的4段,成为“米”字形状。图7-7“七段”结构的LED显示器的内部结构和外型、引脚示意图(a)共阴极结构;(b)共阳极结构;(c)外型和引脚排列按照图7-7中的“七段”结构LED显示器的外型和段的位置,“七段”LED显示器显示码与控制码的对照表如表7-2所示。段式LED显示器的控制方式分为静态显示控制和动态显示控制两种。所谓“静态显示控制”,就是当一个LED显示器显示某字符时,控制码控制相应的LED段处于恒定的导通状态,静态显示控制在电路上需要将控制码锁存在LED显示器的各段输入引脚,如果有多位LED显示器,每个位必需一个8位锁存器,MCS-51单片机仅在需要更改显示器的显示内容时,才重新将新的控制码锁存在8位锁存器中。静态显示控制的LED显示器的亮度与各段的导通电流大小有关,静态控制的显示是非常稳定的。所谓“动态显示控制”,就是多位显示器逐个扫描,任意时刻仅有某一个显示器是亮的,而其他各位都不亮,一个位亮一定时间后转向另一个位。这种动态逐个扫描多位LED显示器的方式会造成显示位“闪烁”,但是,适当地调整扫描速度,利用人的视觉暂留,使人的眼睛看起来“不闪烁”。动态扫描LED显示器方式比静态显示控制方式的电路更简单,将多位LED显示器的段引脚对应连接成“段”总线,仅需要一个8位锁存器和多个位选通控制线就可以达到控制多位LED显示器的目的。动态扫描LED显示器的亮度与各段的导通电流有关,另外,亮度还与扫描频率(一个位亮的时间和灭的时间称为一个扫描周期)有关。图7-8和图7-9是利用扩展的I/O通道分别实现静态LED显示器和动态LED显示器的电路。在图7-8中为实现3位LED显示器需要扩展3个8位的D型锁存器74HC273,每个锁存器的输出端经过限流电阻后与各位LED显示器的a~dp段对应连接。扩展的3个锁存器的地址分别为0DFFFH、0BFFFH和7FFFH,8051单片机将各位需要显示的字符对应的段控制码锁存在各锁存器中,即可实现显示器的控制。一旦段控制码锁存后,显示器一直保持显示的字符,直到8051单片机重新写新的段控制码到锁存器中。图7-83位LED显示器的静态控制接口电路在图7-9中,扩展了两个8位D型锁存器74HC273,U2作为段控制码锁存器使用,U3作为显示器位选通码使用,4位LED显示器的段引脚a~dp对应连接构成“段”总线与U2的输入连接。每一个位选通控制线都经过一个达林顿结构的驱动器(75452),当8051单片机通过写操作将段控制码锁存在段码锁存器中,然后控制位选通信号中的某一个位有效,此时该显示位显示段码锁存器中对应的字符。一个显示位亮一定时间后,8051单片机将所有的位选通信号都置为无效,然后重新将下一个显示位的字符的段控制码锁存在段码锁存器中,再将这个位选通信号置为有效,这样重复扫描4个LED显示器。图7-94位LED显示器的动态控制接口电路比较上面两个电路,如果需要显示器的位数相同,那么静态控制方式的电路需要扩展更多的锁存器。相比较而言,动态控制方式的电路就比较简单。下面是两种不同显示控制方式的控制程序。静态显示控制方式的程序:#include<io51.h>#define
StaticDisplayLED0Adr*(unsignedchar*)(0x01DFFF)
//BIT0地址#define
StaticDisplayLED1Adr*(unsignedchar*)(0x01BFFF)
//BIT1地址#define
StaticDisplayLED2Adr*(unsignedchar*)(0x017FFF)
//BIT2地址codeunsignedcharLEDSegmentCode[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71}unsignedcharidataDisplayBuffer[3];
//显示缓冲区…voidStaticLEDDisplayUpdate(void)
//刷新静态LED显示器的子程序{
unsignedcharct;
ct=DisplayBuffer[0]&0x0F;
//仅显示“0”~“F”
StaticDisplayLED0Adr=LEDSegmentCode[ct];
//将段码锁存在BIT0地址
ct=DisplayBuffer[1]&0x0F;
//仅显示“0”~“F”
StaticDisplayLED1Adr=LEDSegmentCode[ct];
//将段码锁存在BIT1地址
ct=DisplayBuffer[2]&0x0F;
//仅显示“0”~“F”
StaticDisplayLED2Adr=LEDSegmentCode[ct];
//将段码锁存在BIT2地址}在下面的动态显示方式控制程序中,利用Timer0定时20ms,作为LED显示器的扫描周期。源程序如下:#include<io51.h>#define
DynamicDispSegCodeAdr*(unsignedchar*)(0x01BFFF)
//段码锁存器地址#define
DynamicDispBitSelectAdr*(unsignedchar*)(0x017FFF)
//位选通码锁存器地址codeunsignedcharLEDSegmentCode[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};codeunsignedcharLEDBitSelectCode[]={0x01,0x02,0x04,0x08};unsignedcharidataDisplayBuffer[3];
//显示缓冲区unsignedcharidataOver20ms=0;
//20ms定时溢出标志unsignedcharidataCurrentLEDBitPt=0;//定时扫描LED的位指针interrupt[0x0B]voidTimer0_ISR(void){
TL0=0xDF;
//fosc=12MHz,要求定时20ms
TH0=0xB1;
//重新装入T0定时器初始值
Over20ms=1;
//20ms定时时间到,向主程序发送标志}voidmain(void)
//主程序{
unsignedncharcct;
…
//初始化程序
while(1)
//主程序无限循环开始
{
if(Over20ms) //从Timer0中断服务程序接收到消息
{
Over20ms=0;
//清除标志
DynamicDispBitSelectAdr=0x00;
//让所有的位选通线都无效
cct=DisplayBuffer[CurrentLEDBitPt]&0x0F;
//从显示缓冲区取显示数据
DynamicDispSegCodeAdr=LEDSegmentCode[cct];
//锁存段码
DynamicDispSegCodeAdr=LEDBitSelectCode [CurrentLEDBitPt];
//置指针指向的位的位选通码有效
CurrentLEDBitPt++;
//显示器位指针加1
if(CurrentLEDBitPt>4) //判断显示器位指针是否已经大于4
CurrentLEDBitPt=0;
//当大于4时,重新开始下一轮显示扫描
}
…
//执行系统的其他任务
}}动态扫描LED显示器时,为了防止“串亮”,在每次修改段码锁存器中的段控制码之前,必须首先让所有的位选通线都无效。比较上面两种控制程序可以看出,采用静态显示控制方式的LED显示器刷新程序比较简单,当主程序需要刷新显示的字符时才将新的段控制码锁存一次,平时不需要更改显示的字符时,静态控制方式的LED显示器能够自动保持显示的字符。而对动态显示控制方式的LED显示器来讲,无论主程序是否要更改显示的字符,程序必须周期性地扫描LED显示器,需要周期性占用CPU的时间去逐位刷新,否则动态控制方式的LED显示器将不能正常工作。
MCS-51系列单片机与LED显示器的接口方法还有很多种,如利用Intel公司的键盘和显示器专用接口芯片8279(参考前一节的有关内容)控制LED显示器,这是一种传统的扩展方法。在MCS-51单片机系统中扩展8279作为键盘和LED显示器接口电路,可以构成32个键的行列式键盘和8位LED显示器。7.2.2字符型LCD显示器的接口与LED显示器相比,LCD显示器是一种功耗极低的显示器件。液晶(LiquidCrystal)的特点是在一定的温度范围内既有液体的流动性和连续性,又有晶体的各向异性,它们的分子呈现长棒形状,长和宽的比例较大,分子不能弯曲,是一种刚性体。它们的中心一般有桥链,两头有极性。
LCD显示器件的内部结构原理如图7-10所示。由于液晶的“四壁效应”,在定向膜的作用下,液晶材料的分子在正、背玻璃板电极上呈水平排列,但排列方向互为正交,而玻璃电极之间的分子呈连续扭转过渡,这样的构造能使液晶对光产生旋光作用,使光的偏振方向旋转90°。所以说,LCD显示器属于非主动发光的光源,为了能够看到LCD显示器中的字符或图形,必须在光线充足的地方,或为LCD显示器提供外界主动发光的光源。为了在夜间能够使用LCD显示器,目前绝大多数LCD显示器都带有背光板,LCD显示器背光板必须能够为LCD显示器提供充足的背景光线。LCD显示器的背光板光源可以选择各种不同的颜色,可以得到不同的显示效果。图7-10LCD的基本构造示意图图7-11是LCD显示器的工作原理示意图。当外界主动发光源的光线通过上偏振片后形成偏振光,偏振方向呈垂直方向。然后,此偏振光通过液晶材料之后被旋转90°,此时光线的偏振方向呈水平,此方向与下偏振片的方向一致,因此此光线能够穿过下偏振片而到达反射板。最后,该光线的反射光线沿原路返回,从而使LCD显示器呈现透明状。当在液晶盒的上、下电极间加上一定电压后,电极部分的液晶分子转为垂直排列,从而失去旋光性。因此,从上偏振片入射的偏振光不被旋转,当此偏振光到达下偏振片时,被下偏振片吸收,无法到达反射板形成反射光,所以呈现黑色。这样控制电路可以根据显示的字符、图形的需要控制液晶盒上、下电极之间的电压,使得部分LCD显示器中的部分点呈透明状,而另一些点呈黑色,就可以在LCD显示器上显示各种字符或图形。图7-11LCD显示器工作原理示意图段式LCD显示器是将液晶盒各段的其中一个电极连在一起,另一个电极作为独立引脚,相应的控制电路直接控制液晶盒上、下电极之间的电压,使各段处于亮或灭的状态,从而组合出不同的字符。段式LCD液晶盒上、下电极之间的电压必须采用一定频率的交流信号,否则容易损坏LCD显示器。段式LCD显示器的驱动电路可以采用专用的段式LCD驱动芯片。当段式LCD显示位比较多时,其驱动电路也相应比较复杂,面积也会增加。字符型LCD显示器是一种通用的显示器件,常见的字符型LCD的型号大多数以其每行能够显示的字符个数和显示字符的行数来命名。如0802(2行,每行8个字符)、1601(1行,每行16个字符)、1602(2行,每行16个字符)、2004(4行,每行20个字符)等。所有字符型LCD显示器的接口都相同。图7-12是2行×16个字符(1602)的字符型LCD显示器的外型图和引脚排列。该显示器由32个字符点阵块组成,每个字符点阵块由5×7或5×10个点阵组成,可以显示ASCII码表中的所有可视的字符。其内部ROM中存储有ASCII码字符表,器件内部有若干个用户自编程字符存储区,允许用户编写ASCII码字符表之外的特殊字符或图形。器件内部还具有数据RAM存储器,用于保存显示数据。大多数字符型LCD显示器都以模块(Module)形状使用,LCD显示器模块(LCM)中有LCD驱动电路(点阵的行和列扫描电路)和接口控制器电路,有些字符型LCD显示器模块还带有背光板(BackLightingBoard)组件。LCM的接口控制器是连接主控制器的通道,目前常用的LCM接口控制器有Hitachi公司的HD44780和Samsung公司的SED1278等,它们的时序、接口电路互相兼容。图7-12字符型LCD显示器外型和引脚排列、名称标准的字符型LCD显示器模块的接口引脚名称和引脚功能如表7-3所示。字符型LCD显示器模块是一种智能器件,它的内部有两种寄存器:指令寄存器和数据寄存器。单片机等主控制系统对LCM的指令寄存器写操作,可以将“清屏”等控制指令发送给LCM;对指令寄存器读操作,得到的数据的最高位是LCM的状态(空闲状态或忙状态)标志位,低7位是地址计数器信息。对LCM的数据存储器写操作,可以修改当前地址中的显示字符;读操作可以得到当前显示地址中的显示数据。字符型LCD显示器模块的详细指令如表7-4所示。
LCM的显示数据存储器DDRAM与显示屏上的字符显示位置是一一对应的,表7-5给出了LCM2004(4行,每行20个字符)的DDRAM地址与字符显示位置的对应关系。当单片机等主控制器系统需要把字符显示在屏幕的某一位置时,首先将对应位置的DDRAM的地址写到地址计数器(指令寄存器)中,然后再将该字符的ASCII码写入DDRAM中,这样就可以完成一个字符的显示。字符型LCD显示器模块的接口读/写操作时序如图7-13和图7-14所示,其时序参数见表7-6。值得注意的是,LCM的读/写时序不兼容IntelBus时序,而MCS-51系列单片机的“三总线”时序兼容IntelBus时序,所以后面介绍的MCS-51单片机与LCM接口电路和接口控制程序都是按照图7-13和图7-14所示的读/写操作时序进行设计的。图7-13LCM接口读操作时序图7-14LCM接口写操作时序
MCS-51单片机与LCM接口的典型电路如图7-15所示。图中利用P2.7(AB15)和WR、RD逻辑组合后作为LCM1602的使能控制;P1.0和P1.1分别作为LCM的RS和R/W的控制信号。当MCS-51单片机对外部地址7FFFH单元进行读或写操作时,LCM1602的工作使能端有效,驱动程序通过设置P1.0和P1.1的电平状态以选择LCM1602的命令或数据寄存器及LCM1602的读或写操作。该电路的地址和I/O端口状态与LCM寄存器的对应关系见表7-7。图7-15MCS-51单片机与LCM1602的接口电路按照图7-15所示的接口电路,相应的接口控制程序如下:#include<io51.h>#include<string.h>#define
LCDRS
P1.0
//LCD的RS控制线#define
LCDRW
P1.1
//LCD的R/W控制线#define
ReadLCMCmdReg LCDRS=0;\
LCDRW=1
//设置LCM进入“读命令”操作#define
WriteLCMCmdReg
LCDRS=0;\
LCDRW=0
//设置LCM进入“写命令”操作#define
ReadLCMDataReg
LCDRS=1;\
LCDRW=1
//设置LCM进入“读数据”操作#define
WriteLCMDataReg
LCDRS=1;\
LCDRW=0
//设置LCM进入“写数据”操作#define
LCMPORTAdr*(unsignedchar*)(0x017FFF)
//LCM的地址codeTestScreen[][]={{“LCMInterface”},{“ZJUT2001/10”}};
//测试字符串unsignedcharReadBusyandACFromLCM(void)
//读忙标志和地址计数器{
unsignedcharresult;
ReadLCMCmdReg;
//置LCD-RS=0,LCD-RW=1
result=LCMPORTAdr;
//读LCM的忙标志和地址计数器
return(result);
//返回忙标志(MSB=Bsy)和地址计数器}voidWriteDataToLCM(unsignedchar_data)
//写数据操作{
WriteLCMDataReg;
//置LCD-RS=1,LCD-RW=0
LCMPORTAdr=_data; //写数据到LCM的数据寄存器
do{
_data=ReadBusyandACFromLCM();
}while((_data&0x80)==0x80); //等待LCM操作完毕}voidInit_LCM1602(void)
//初始化LCM操作{
Delay(100);
WriteCommandToLCM(0x38);
//连续执行3次,等待LCM上电自复位结束
Delay(80);
WriteCommandToLCM(0x38);
Delay(80);
WriteCommandToLCM(0x38);
//设置接口DB宽度(8位)和LCM显示行数(2行)
Delay(80);
WriteCommandToLCM(0x01); //执行清屏操作
Delay(50);
WriteCommandToLCM(0x06); //设置光标为加1模式
Delay(50);
WriteCommandToLCM(0x0C); //设置光标为移位模式
Delay(50);}voidGotoXYofLCMScreen(unsignedcharx,unsignedchary){
x&=0x01;
//显示行数仅可以为0或1,即第1或2行
y&=0x0F;
//显示的列位置仅可以为0~F
y|=(x==0)?0x40:0xC0;
//判断是第1或2行
WriteCommandToLCM(y);
//写到LCM的地址计数器
do{
y=ReadBusyandACFromLCM();
while((y&0x80)==0x80);
//等待LCM操作完毕}voidPutCharonLCMScreen(unsignedcharx,unsignedchary,
unsignedchar_char);
//显示一个字符在屏幕中指定的位置(x,y){
GotoXYofLCMScreen(x,y); //当前显示器地址转向(x,y)
WriteDataToLCM(_char); //将字符(_char)写到当前显示地址}voidPutStrToLCMScreen(unsignedcharx,unsignedchary,
unsignedchar*str,unsignedcharlen){ //从屏幕中指定的位置(x,y)开始显示字符串str
unsignedchari;
for(i=0;i<len;i++)
{
PutCharonLCMScreen(x,y++,str[i]);
//将一个字符写到当前显示地址
if(y>0x0F)
//显示自动换行调整操作
{
y=0;
//下一行的第1列
x++;
//下一行
}
}}voidmain(void) //主程序调用上面的子程序,显示两个字符串{
…
//8051初始化程序
Init_LCM1602();
//初始化LCM(2行,8位并行接口)
PutStrToLCMScreen(0,0,TestScreen[0][0],16);
//从(0,0)开始显示显示"_LCM_Interface__"
PutStrToLCMScreen(0,0,TestScreen[1][0],16);
//从(1,0)开始显示显示"__ZJUT_2002/10__"
...
//继续执行其他任务}7.2.3图形点阵LCD显示器的接口目前常用的图形点阵LCD显示器一般都采用模块结构(称为图形LCM)。MCS-51单片机与图形点阵LCD显示器接口电路取决于显示模块的接口控制器。目前常用的图形LCM的接口控制器有:Toshiba公司的T6963C、Hitachi公司的HD61830、Samsung公司的“KS0107+KS0108”(分别为行和列驱动)等。接口控制器不同,它们与单片机的接口电路、时序和接口控制软件也不完全相同。图7-16是G12864图形LCM的内部结构框图,它采用Samsung公司的图形LCD驱动控制器,其屏幕由64(行)×128(列)点阵组成,可以显示16点阵的4行×8列(32个)汉字或128×64全屏幕点阵图形。该模块的控制板上带有图形LCM必需的对比度调节负电压产生电路,设计接口电路时可以直接利用该LCM输出的负电压(VEE)。而且LCM的控制板中还具有背光板高压驱动电路,用户接口电路对背光板的控制采用兼容TTL逻辑电平。它采用单DC+5V供电,功耗极低,当背光板关闭时,消耗电流3mA;当背光板亮时,消耗电流小于50mA。它与MCS-51单片机等主控制系统采用8位并行接口及20引脚连接器,各引脚名称和功能如表7-8所示。图7-16G12864图形LCM的内部结构
G12864图形LCD显示器使用7种指令与单片机等主控制器之间通信,7种指令的详细格式和参数见表7-9。在表7-9中所谓的页地址就是DDRAM的行地址,8行为一页,LCMG12864共64行,即8页,A2~A0用于选择第0~7页。读/写数据对页地址没有影响,页地址为当前指令指定的位置或复位后位于第0页地址。页地址与DDRAM的对应关系如表7-10所示。
MCS-51单片机在执行指令“设y地址”时,将新的6位y地址写到y地址计数器中。当单片机对DDRAM中的数据进行读或写操作(读/写数据)时,y地址计数器会加1,指向下一个地址。图7-17是G12864显示模块与主控制系统的接口读/写操作时序,其时间参数见表7-11。图7-17G12864读/写操作时序(a)读操作时序;(b)写操作时序根据图7-17所示的操作时序,设计如图7-18所示的G12864与MCS-51单片机的接口电路。由于G12864接口时序的特殊性,采用MCS-51单片机的扩展I/O端口作为G12864的控制信号,扩展的I/O端口Bit.0和Bits.1分别作为两片列驱动器(KS0108A-1和KS0108A-2)的片选控制,这两个信号任何时刻仅允许一个输出高有效电平。选通其中的一片列驱动器,当Bit.0=1且Bit.1=0时,第1片列驱动器被选中;Bit.0=0且Bit.1=1时,第2片列驱动器被选中。Bit.2作为LCM的指令和数据寄存器选择控制信号,Bit.3作为LCM读/写选择控制信号。Bit.6控制LCM的复位和运行状态,Bit.6=0,复位LCM;正常运行状态时Bit.6=1。Bit.7作为G12864的背光板打开或关闭控制信号,Bit.7=1,背光板被打开;Bit.7=0,背光板被关闭。G12864的使能控制信号受P2.7(AB15)控制,当AB15=0时,8051执行读操作即读LCM的数据寄存器或指令寄存器;当AB15=1时,8051执行写操作即写LCM的指令寄存器或数据寄存器。扩展的8位锁存器的写锁存信号受P2.6(AB14)控制,当AB14=0时,8051可以将控制G12864状态字锁存到扩展的I/O输出端口处。图7-18MCS-51单片机与LCM12864的接口电路图形点阵LCD显示器可以直接显示汉字和图形、曲线,其原理是控制LCD点阵中的点的亮或暗,亮和暗的点阵按一定规律可以组成汉字,组成一幅、若干幅图形和曲线。而所有的LCM都带有显示缓存,单片机等主控制器只需要将点阵的亮和暗控制信息写到LCM的显示缓存中,LCM的行、列驱动器会自动扫描LCD点阵,保持用户期望的显示效果。所有的LCM显示缓存都采用字节方式读/写,对用户来讲,LCM屏幕上的点阵是按字节方式8个点一组来控制的。一个16点阵的汉字在LCM的屏幕上是采用16×16个点来表达的,即一个16点阵的汉字需要32个字节的编码数据,这些编码数据包含16×16点阵中亮和暗的控制信息。
G12864是一种全屏幕点阵图形显示器,可以在G12864的屏幕上仅显示一幅128×64点阵的图形或曲线。当用它来显示汉字或字符时,可以按照汉字或字符点阵的大小任意分割成多个小点阵块。如果用来显示16×16点阵的汉字,可以分割成32个16×16点阵块,能够显示32个汉字;如果用来显示32×32点阵汉字,能够显示8个32×32点阵汉字。下面就是在G12864显示器上显示16×16点阵汉字的程序:#include<io51.h>#include<string.h>#define
LCMCWAdr*(unsignedchar*)(0x01BFFF)
//LCM控制字锁存器端口地址#defineLCMPORTAdr*(unsignedchar*)(0x017FFF) //LCM读/写使能端口地址#define
_CS1
0x01
//指定各控制信号在锁存器中的位置(硬件有关)#define
_CS2 0x02#define
_DI
0x04#define
_RW
0x08#define
_RST
0x40#define
_ELON
0x80unsignedcharidataELState=0;
//是否允许背光板亮的状态寄存器codeunsignedcharTestHZDotCode[][]={
//将“机电一体化”5个汉字的编码保存在Code区{
0x00,0x0C,0x07,0x7F,0x61,0x03,0x42,0x30,
0x0F,0x00,0x00,0x00,0x7F,0x40,0x60,0x00,
0x00,0x30,0x10,0xFE,0x16,0x90,0x10,0x00,
0xFC,0x04,0x04,0x04,0xFC,0x00,0x00,0x00},
//汉字“机”的编码{
0x00,0x00,0x00,0x1F,0x04,0x04,0x04,0x7F,
0x44,0x44,0x44,0x44,0x47,0x60,0x20,0x00,
0x00,0x00,0x00,0xF0,0x90,0x90,0x90,0xFE,
0x90,0x90,0x90,0x90,0xF0,0x00,0x00,0x00},
//汉字“电”的编码{
0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 供热供气工程履约担保格式
- 2025版备货行业质量认证合同范本3篇
- 展览馆弱电系统改造合同模板
- 医疗服务票据管理策略与流程
- 2025年度绿色办公用品采购及回收利用合同3篇
- 纺织服装电力供应协议准则
- 城市滨水区改造房屋拆除工程协议
- 2025版电梯设备安装与维护合同范本3篇
- 船只租赁合同:水上建筑维修
- 2025版商用空调定期检查、保养与故障处理合同3篇
- 成都市农贸市场建设技术要求(2019年版)(完整版)
- 北京市海淀区2021-2022学年第一学期四年级期末考试语文试卷(含答案)
- 【MOOC】微型计算机原理与接口技术-南京邮电大学 中国大学慕课MOOC答案
- “小城镇建设”论文(六篇)
- 人人爱设计学习通超星期末考试答案章节答案2024年
- 福建省厦门市翔安区2023-2024学年八年级上学期期末语文试题
- DNA 亲子鉴定书 范本
- 膝关节骨性关节炎(膝痹病)病程模板
- 互联网+教育背景下智慧课堂教学模式设计研究
- 模块一:外贸业务操作技能试题
- 通用焊接工艺
评论
0/150
提交评论