返回主页 单片机教程XL2000开发板 单片机学习 自制编程器 单片机资料 软件下载 电子技术产品介绍如何购买 进入论坛

单片机教程第1课  教学资料单片机教程第18课  算术指令
单片机教程第2课  好书推荐单片机教程第19课  逻辑指令
单片机教程第3课  单片机不易掌握的概念单片机教程第20课  逻辑指令
单片机教程第4课  实战一:流水灯单片机教程第21课  转移指令
单片机教程第5课  实战二:唱歌单片机教程第22课  位操作
单片机教程第6课  测试一单片机教程第23课  计数定时器
单片机教程第7课  新教程前言单片机教程第24课  计数定时器
单片机教程第8课  总体规划单片机教程第25课  中断系统
单片机教程第9课  概述单片机教程第26课  中断练习
单片机教程第10课  单片机结构单片机教程第27课  定时计数实验2
单片机教程第11课  基本概念单片机教程第28课  串行口
单片机教程第12课  延时程序分析单片机教程第29课  串口实例
单片机教程第13课  延时程序分析单片机教程第30课  数码管编程
单片机教程第14课  并口结构单片机教程第31课  动态数码管编程
单片机教程第15课  结构分析单片机教程第32课  键盘接口编程
单片机教程第16课  寻址方式单片机教程第33课  键盘扫描编程
单片机教程第17课  上机练习 单片机教程第34课  指令介绍        平凡的单片机教程

动态扫描显示接口

动态扫描显示接口是单片机中应用最为广泛的一种显示方式之一。其接口电路是把所有显示器的8个笔划段a-h同名端连在一起,而每一个显示器的公共极COM是各自独立地受I/O线控制。CPU向字段输出口送出字形码时,所有显示器接收到相同的字形码,但究竟是那个显示器亮,则取决于COM端,而这一端是由I/O控制的,所以我们就可以自行决定何时显示哪一位了。而所谓动态扫描就是指我们采用分时的方法,轮流控制各个显示器的COM端,使各个显示器轮流点亮。

在轮流点亮扫描过程中,每位显示器的点亮时间是极为短暂的(约1ms),但由于人的视觉暂留现象及发光二极管的余辉效应,尽管实际上各位显示器并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示数据,不会有闪烁感。

下图所示就是我们的实验板上的动态扫描接口。由89C51P0口能灌入较大的电流,所以我们采用共阳的数码管,并且不用限流电阻,而只是用两只1N4004进行降压后给数码管供电,这里仅用了两只,实际上还可以扩充。它们的公共端则由PNP型三极管8550控制,显然,如果8550导通,则相应的数码管就可以亮,而如果8550截止,则对应的数码管就不可能亮,8550是由P2.7P2.6控制的。这样我们就可以通过控制P27P26达到控制某个数码管亮或灭的目的。

下面的这个程序,就是用实验板上的数码管显示01

FIRST           EQU       P2.7       ;第一位数码管的位控制

SECOND      EQU       P2.6       ;第二位数码管的位控制

DISPBUFF    EQU       5AH ;显示缓冲区为5AH5BH

       ORG       0000H

       AJMP     START

       ORG       30H

START:

       MOV       SP,#5FH              ;设置堆栈

       MOV       P1,#0FFH

       MOV       P0,#0FFH

       MOV       P2,#0FFH     ;初始化,所显示器,LED

       MOV       DISPBUFF,#0      ;第一位显示0

       MOV       DISPBUFF+1,#1  ;第二握显示1

LOOP:

       LCALL    DISP             ;调用显示程序

       AJMP     LOOP

;主程序到此结束

DISP:

       PUSH     ACC        ;ACC入栈

       PUSH     PSW             ;PSW入栈

       MOV       A,DISPBUFF ;取第一个待显示数

       MOV       DPTR,#DISPTAB ;字形表首地址

       MOVC    A,@A+DPTR ;取字形码

       MOV       P0,A              ;将字形码送P0位(段口)

       CLR       FIRST           ;开第一位显示器位口

       LCALL    DELAY          ;延时1毫秒

       SETB     FIRST           ;关闭第一位显示器(开始准备第二位的数据)

       MOV       A,DISPBUFF+1    ;取显示缓冲区的第二位

       MOV       DPTR,#DISPTAB

       MOVC    A,@A+DPTR

       MOV       P0,A              ;将第二个字形码送P0

       CLR       SECOND              ;开第二位显示器

       LCALL    DELAY          ;延时

       SETB     SECOND              ;关第二位显示

       POP       PSW

       POP       ACC

       RET

DELAY:                ;延时1毫秒

       PUSH     PSW

       SETB     RS0

       MOV       R7,#50

D1:  MOV       R6,#10

D2:  DJNZ     R6,$

       DJNZ     R7,D1

       POP       PSW

       RET

DISPTAB:DB28H,7EH,0a4H,64H,72H,61H,21H,7CH,20H,60H

       END

从上面的例子中可以看出,动态扫描显示必须由CPU不断地调用显示程序,才能保证持续不断的显示。

上面的这个程序可以实现数字的显示,但不太实用,为什么呢?这里仅是显示两个数字,并没有做其他的工作,因此,两个数码管轮流显示1毫秒,没有问题,实际的工作中,当然不可能只显示两个数字,还是要做其他的事情的,这样在二次调用显示程序之间的时间间隔就不一不定了,如果时间间隔比较长,就会使显示不连续。而实际工作中是很难保证所有工作都能在很短时间内完成的。况且这个显示程序也有点浪费,每个数码管显示都要占用1个毫秒的时间,这在很多合是不允许的,怎么办呢?我们可以借助于定时器,定时时间一到,产生中断,点亮一个数码管,然后马上返回,这个数码管就会一直亮到下一次定时时间到,而不用调用延时程序了,这段时间可以留给主程序干其他的事。到下一次定时时间到则显示下一个数码管,这样就很少浪费了。

Counter         EQU       59H ;计数器,显示程序通过它得知现正显示哪个数码管

FIRST           EQU       P2.7       ;第一位数码管的位控制

SECOND      EQU       P2.6       ;第二位数码管的位控制

DISPBUFF    EQU       5AH ;显示缓冲区为5AH5BH

       ORG       0000H

       AJMP     START

       ORG       000BH          ;定时器T0的入口

       AJMP     DISP             ;显示程序

       ORG       30H

START:

       MOV       SP,#5FH              ;设置堆栈

       MOV       P1,#0FFH

       MOV       P0,#0FFH

       MOV       P2,#0FFH     ;初始化,所显示器,LED

       MOV       TMOD,#00000001B    ;定时器T0工作于模式116位定时/计数模式)

       MOV       TH0,#HIGH(65536-2000)

       MOV       TL0,#LOW(65536-2000)

       SETB     TR0

       SETB     EA

       SETB     ET0

       MOV       Counter,#0    ;计数器初始化

       MOV       DISPBUFF,#0      ;第一位始终显示0

       MOV       A,#0

LOOP:   

       MOV       DISPBUFF+1,A    ;第二位轮流显示0-9

       INC A

       LCALL    DELAY

       CJNE     A,#10,LOOP

       MOV       A,#0

       AJMP     LOOP     ;在此中间可以按排任意程序,这里仅作示范。

;主程序到此结束

DISP:            ;定时器T0的中断响应程序

       PUSH     ACC        ;ACC入栈

       PUSH     PSW             ;PSW入栈

       MOV       TH0,#HIGH(65536-2000)   ;定时时间为2000个周期,约2170微秒(11.0592M

       MOV       TL0,#LOW(65536-2000)

       SETB     FIRST

       SETB     SECOND              ;关显示

       MOV       A,#DISPBUFF      ;显示缓冲区首地址

       ADD       A,Counter     

       MOV       R0,A

       MOV       A,@R0          ;根据计数器的值取相应的显示缓冲区的值

       MOV       DPTR,#DISPTAB ;字形表首地址

       MOVC    A,@A+DPTR ;取字形码

       MOV       P0,A              ;将字形码送P0位(段口)

       MOV       A,Counter      ;取计数器的值

       JZ   DISPFIRST   ;如果是0则显示第一位

       CLR       SECOND              ;否则显示第二位

       AJMP     DISPNEXT

DISPFIRST:

       CLR       FIRST           ;显示第一位         

DISPNEXT:

       INC Counter         ;计数器加1

       MOV       A,Counter     

       DEC       A            ;如果计数器计到2,则让它回0

       DEC       A           

       JZ   RSTCOUNT  

       AJMP     DISPEXIT

RSTCOUNT:

       MOV       Counter,#0    ;计数器的值只能是01

DISPEXIT:

       POP       PSW

       POP       ACC

       RETI

DELAY:                ;延时130毫秒

       PUSH     PSW

       SETB     RS0

       MOV       R7,#255

D1:  MOV       R6,#255

D2:  NOP

       NOP

       NOP

       NOP

       DJNZ     R6,D2

       DJNZ     R7,D1

       POP       PSW

       RET

DISPTAB:DB 28H,7EH,0a4H,64H,72H,61H,21H,7CH,20H,60H      

       END

从上面的程序可以看出,和静态显示相比,动态扫描的程序稍有点复杂,不过,这是值得的。这个程序有一定的通用性,只要改变端口的值及计数器的值就可以显示更多位数了。下面给出显示程序的流程图。

程序一程序一之代码程序二 程序二之代码