在单片机教学中,我们往往会遇到8位数码管的动态显示电路。动态驱动是将所有数码管的8个段码a,b,c,d,e,f,g,dp”的同名端连在一起,公共端各自独立,还为每个数码管的公共极COM增加位选通控制电路,位选通由各自独立的I/O口线控制。通过分时轮流控制各个数码管的“位选端”(COM端),使各个数码管轮流受控显示。 原理图如图①所示。动态扫描程序的基本思路是: 本站家电维修网https://www.bjjdwx.com/是以家电维修技术交流为中心的技术论坛:①P0口输出第一个段码数据②P2口输出位码数据③延时④消隐位码——完成第一位数码显示;第二步:①P0口输出第二个段码数据②P2口输出位码数据③延时④消隐位码——完成第二位数码显示;……继续显示下一个数码,最后直至显示一组画面。在轮流显示过程中,每位数码管的点亮时间为1~2ms,由于人的视觉暂留现象及发光二极管的余辉效应,只要扫描的速度足够快(如扫描频率为50HZ,则扫描速度一般在20ms以内),给人的印象就是一组稳定的显示数据。 但在综合项目的实践中,会发现这种图①显示方式占用的单片机端口多,假如是8位数码管的话,共占用16个脚(8位段码和8个位选端)。假如选用138译码器,则需要3个引脚输出8位位码数据,占用了11个端口。能不能使单片机的多个外部设备共用单片机I/O线来实现“复用”的功能呢?我们对原有的显示电路进行改进:为了节约I/O接口采用了低8位地址与数据总线分时复用的方法。单片机首先由P2、P0口送出16位地址,然后通过P0口读写数据,在整个读写过程中,高8位地址是不变的。单片机在访问外部存储器的时候P0口首先是作为低8位的地址数据线输出地址信号,外接的锁存器74LS373将它锁存后,P0口再写入数据。这个就是P0口双向8位数据口和低8位地址输出口的复用,分时就是先地址后数据,从而达到节约端口的目的。 原理图如图②所示,占用I/O端口变少。单片机的外围可接2片74LS373进行数据锁存。我们分三步来理解这个程序: 首先是片选:单片机的P2.6和P2.7分别接两片74LS373的1脚 /OE(输出使能端),进行位码和段码的片选。只要P2.7为低电平,即可使得U3(74LS373位选锁存芯片)使能端有效;只要P2.6为低电平,可使U2(74LS373段选锁存芯片)使能端有效。 然后是锁存:单片机的/WR端接两片74LS373的控制端LE(11脚)。当LE=“1”时,74LS373输出端1Q—8Q与输入端1D—8D相同;当LE为下降沿时,将输入数据锁存。P0口输出数据稳定后,/WR写选通发出脉冲信号(低电平),P0 输出的段码或位码数据经由74LS373锁存。 最后是显示控制:定义总线,对外部数据进行赋值。P2口输出外部数据存储器其地址的高8位,P0口输出地址低8位,然后由P0口输出赋值数据,此时P2口在整个过程中信号不变(这是关键),整个对外部数据存储器的访问时序详见图③。在ALE信号下降沿时,P0口为低8位地址输出状态①;WR只在P0口输出数据稳定后发出有效脉冲信号(低电平)②。 当P2.6为低电平,选中U2(74LS373位选锁存芯片),P0口输出位码数据给U2锁存;当P2.7为低电平,选中U3(74LS373段选锁存芯片),P0口输出段码数据给U3锁存;然后延时显示、消隐,最后数码管完成动态扫描显示数据。 附1:动态显示八位数控制程序 #include<reg51.h> void delay() //延时程序 { unsigned char k; for(k=0;k<200;k++); } unsigned chartab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xd8,0x80,0x90};//设置共阳极0~9字型码 unsigned charval[]={2,0,1,8,1,1,0,8}; void main() {unsigned chari,j; while(1) {for(i=0,j=0x01;i<8;i++) //位选码初值为01H,显示8个位码 {P0=tab[val[i]]; //根据va1[i]值送段选码至P0段选码 P2=~j; //位选码:选中第一位数码管显示 delay(); //延时 P2=0xff; //位消隐 j=j<<1; //位选码左移一位,选中下一位LED }}} 附2:分时复用动态扫描显示八位数控制程序 #include <reg51.h> // 包含reg52.h头文件 unsigned char xdata DM _at_ 0x7fff; //定义总线外部地址段码:DM赋值时,P2赋值为0x7f,P0赋值为0xff unsigned char xdata PX _at_ 0xbfff; //定义总线外部地址位码:PX赋值时,P2赋值为0xbf,P0赋值为0xff unsigned charcode smg[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //共阳数码管0~9的段码 unsigned charcom[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};//位码 unsigned charshuju[]= {2,0,1,8,1,1,0,8}; //需要显示的数据 voiddelay() //延时程序 { unsigned chark; for(k=0;k<200;k++); } void display() { unsigned char i; //定义控制变量 for(i=0;i<8;i++) { PX=0xff; //P0口输出赋值数据,WR输出写时序脉冲,位码消隐 DM=smg[shuju[i]]; //P0口输出赋值数据,WR输出写时序脉冲,数据给段码 PX=com[i]; //数据给位码 delay(); //延时显示 } } void main() { while (1) { display(); //调用显示函数 } } 最后,我们用仿真器下载程序进行烧录,分时复用动态扫描实验现象和图①电路一致。减少端口的方法还有很多,比如选用138译码器,则需要3个引脚输出8位位码数据,占用了11个端口,也不失为一种好办法。 |
Powered by Discuz! X3.4
© 2001-2023 Discuz! Team.