第26节:在主函数while循环中驱动数码管的动态扫描程序

发布者:平和思绪最新更新时间:2016-03-14 来源: eefocus关键字:主函数  while循环  驱动数码管  动态扫描程序 手机看文章 扫描二维码
随时随地手机看文章
开场白:

上一节通过一个机械手自动控制程序展示了我在工控常用的编程框架,但是一直没涉及到人机界面,在大多数的实际项目中,人机界面是必不可少的,这一节开始讲最常用的人机界面------动态数码管的驱动。

这一节要教会大家两个知识点:

第一点:数码管的动态驱动原理。

第二点:如何通过编程,让数码管显示的内容转移到几个变量接口上,方便以后编写更上一层的窗口程序。

具体内容,请看源代码讲解。

(1)硬件平台:基于朱兆祺51单片机学习板。用两片74HC595动态驱动八位共阴数码管。

(2)实现功能:

开机后显示 8765.4321 的内容,注意,其中有一个小数点。

(3)源代码讲解如下:

#include "REG52.H"

void initial_myself();

void initial_peripheral();

void delay_short(unsigned int uiDelayShort);

void delay_long(unsigned int uiDelaylong);

//驱动数码管的74HC595

void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01);

void display_drive(); //显示数码管字模的驱动函数

//驱动LED的74HC595

void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01);

sbit beep_dr=P2^7; //蜂鸣器的驱动IO口

sbit led_dr=P3^5; //作为中途暂停指示灯 亮的时候表示中途暂停

sbit dig_hc595_sh_dr=P2^0; //数码管的74HC595程序

sbit dig_hc595_st_dr=P2^1;

sbit dig_hc595_ds_dr=P2^2;

sbit hc595_sh_dr=P2^3; //LED灯的74HC595程序

sbit hc595_st_dr=P2^4;

sbit hc595_ds_dr=P2^5;

unsigned char ucDigShow8; //第8位数码管要显示的内容

unsigned char ucDigShow7; //第7位数码管要显示的内容

unsigned char ucDigShow6; //第6位数码管要显示的内容

unsigned char ucDigShow5; //第5位数码管要显示的内容

unsigned char ucDigShow4; //第4位数码管要显示的内容

unsigned char ucDigShow3; //第3位数码管要显示的内容

unsigned char ucDigShow2; //第2位数码管要显示的内容

unsigned char ucDigShow1; //第1位数码管要显示的内容

unsigned char ucDigDot8; //数码管8的小数点是否显示的标志

unsigned char ucDigDot7; //数码管7的小数点是否显示的标志

unsigned char ucDigDot6; //数码管6的小数点是否显示的标志

unsigned char ucDigDot5; //数码管5的小数点是否显示的标志

unsigned char ucDigDot4; //数码管4的小数点是否显示的标志

unsigned char ucDigDot3; //数码管3的小数点是否显示的标志

unsigned char ucDigDot2; //数码管2的小数点是否显示的标志

unsigned char ucDigDot1; //数码管1的小数点是否显示的标志

unsigned char ucDigShowTemp=0; //临时中间变量

unsigned char ucDisplayDriveStep=1; //动态扫描数码管的步骤变量

unsigned char ucDisplayUpdate=1; //更新显示标志

//根据原理图得出的共阴数码管字模表

code unsigned char dig_table[]=

{

0x3f, //0 序号0

0x06, //1 序号1

0x5b, //2 序号2

0x4f, //3 序号3

0x66, //4 序号4

0x6d, //5 序号5

0x7d, //6 序号6

0x07, //7 序号7

0x7f, //8 序号8

0x6f, //9 序号9

0x00, //不显示 序号10

};

void main()

{

initial_myself();

delay_long(100);

initial_peripheral();

while(1)

{

display_drive(); //显示数码管字模的驱动函数

}

}

/* 注释一:

* 动态驱动数码管的原理是,在八位数码管中,在任何一个瞬间,每次只显示其中一位数码管,另外的七个数码管

* 通过设置其公共位com为高电平来关闭显示,只要切换画面的速度足够快,人的视觉就分辨不出来,感觉八个数码管

* 是同时亮的。以下dig_hc595_drive(xx,yy)函数,其中第一个形参xx是驱动数码管段seg的引脚,第二个形参yy是驱动

* 数码管公共位com的引脚。

*/

void display_drive()

{

//以下程序,如果加一些数组和移位的元素,还可以压缩容量。但是鸿哥追求的不是容量,而是清晰的讲解思路

switch(ucDisplayDriveStep)

{

case 1: //显示第1位

ucDigShowTemp=dig_table[ucDigShow1];

if(ucDigDot1==1)

{

ucDigShowTemp=ucDigShowTemp|0x80; //显示小数点

}

dig_hc595_drive(ucDigShowTemp,0xfe);

break;

case 2: //显示第2位

ucDigShowTemp=dig_table[ucDigShow2];

if(ucDigDot2==1)

{

ucDigShowTemp=ucDigShowTemp|0x80; //显示小数点

}

dig_hc595_drive(ucDigShowTemp,0xfd);

break;

case 3: //显示第3位

ucDigShowTemp=dig_table[ucDigShow3];

if(ucDigDot3==1)

{

ucDigShowTemp=ucDigShowTemp|0x80; //显示小数点

}

dig_hc595_drive(ucDigShowTemp,0xfb);

break;

case 4: //显示第4位

ucDigShowTemp=dig_table[ucDigShow4];

if(ucDigDot4==1)

{

ucDigShowTemp=ucDigShowTemp|0x80; //显示小数点

}

dig_hc595_drive(ucDigShowTemp,0xf7);

break;

case 5: //显示第5位

ucDigShowTemp=dig_table[ucDigShow5];

if(ucDigDot5==1)

{

ucDigShowTemp=ucDigShowTemp|0x80; //显示小数点

}

dig_hc595_drive(ucDigShowTemp,0xef);

break;

case 6: //显示第6位

ucDigShowTemp=dig_table[ucDigShow6];

if(ucDigDot6==1)

{

ucDigShowTemp=ucDigShowTemp|0x80; //显示小数点

}

dig_hc595_drive(ucDigShowTemp,0xdf);

break;

case 7: //显示第7位

ucDigShowTemp=dig_table[ucDigShow7];

if(ucDigDot7==1)

{

ucDigShowTemp=ucDigShowTemp|0x80; //显示小数点

}

dig_hc595_drive(ucDigShowTemp,0xbf);

break;

case 8: //显示第8位

ucDigShowTemp=dig_table[ucDigShow8];

if(ucDigDot8==1)

{

ucDigShowTemp=ucDigShowTemp|0x80; //显示小数点

}

dig_hc595_drive(ucDigShowTemp,0x7f);

break;

}

ucDisplayDriveStep++;

if(ucDisplayDriveStep>8) //扫描完8个数码管后,重新从第一个开始扫描

{

ucDisplayDriveStep=1;

}

/* 注释二:

* 如果直接是单片机的IO口引脚驱动的数码管,由于驱动的速度太快,此处应该适当增加一点delay延时或者

* 用计数延时的方式来延时,目的是在八位数码管中切换到每位数码管显示的时候,都能停留一会再切换到其它

* 位的数码管界面,这样可以增加显示的效果。但是,由于朱兆祺51学习板是间接经过74HC595驱动数码管的,

* 在单片机驱动74HC595的时候,dig_hc595_drive函数本身内部需要执行很多指令,已经相当于delay延时了,

* 因此这里不再需要加delay延时函数或者计数延时。

*/

}

//数码管的74HC595驱动函数

void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01)

{

unsigned char i;

unsigned char ucTempData;

dig_hc595_sh_dr=0;

dig_hc595_st_dr=0;

ucTempData=ucDigStatusTemp16_09; //先送高8位

for(i=0;i<8;i++)

{

if(ucTempData>=0x80)dig_hc595_ds_dr=1;

else dig_hc595_ds_dr=0;

/* 注释三:

* 注意,此处的延时delay_short必须尽可能小,否则动态扫描数码管的速度就不够。

*/

dig_hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器

delay_short(1);

dig_hc595_sh_dr=1;

delay_short(1);

ucTempData=ucTempData<<1;

}

ucTempData=ucDigStatusTemp08_01; //再先送低8位

for(i=0;i<8;i++)

{

if(ucTempData>=0x80)dig_hc595_ds_dr=1;

else dig_hc595_ds_dr=0;

dig_hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器

delay_short(1);

dig_hc595_sh_dr=1;

delay_short(1);

ucTempData=ucTempData<<1;

}

dig_hc595_st_dr=0; //ST引脚把两个寄存器的数据更新输出到74HC595的输出引脚上并且锁存起来

delay_short(1);

dig_hc595_st_dr=1;

delay_short(1);

dig_hc595_sh_dr=0; //拉低,抗干扰就增强

dig_hc595_st_dr=0;

dig_hc595_ds_dr=0;

}

//LED灯的74HC595驱动函数

void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01)

{

unsigned char i;

unsigned char ucTempData;

hc595_sh_dr=0;

hc595_st_dr=0;

ucTempData=ucLedStatusTemp16_09; //先送高8位

for(i=0;i<8;i++)

{

if(ucTempData>=0x80)hc595_ds_dr=1;

else hc595_ds_dr=0;

hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器

delay_short(1);

hc595_sh_dr=1;

delay_short(1);

ucTempData=ucTempData<<1;

}

ucTempData=ucLedStatusTemp08_01; //再先送低8位

for(i=0;i<8;i++)

{

if(ucTempData>=0x80)hc595_ds_dr=1;

else hc595_ds_dr=0;

hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器

delay_short(1);

hc595_sh_dr=1;

delay_short(1);

ucTempData=ucTempData<<1;

}

hc595_st_dr=0; //ST引脚把两个寄存器的数据更新输出到74HC595的输出引脚上并且锁存起来

delay_short(1);

hc595_st_dr=1;

delay_short(1);

hc595_sh_dr=0; //拉低,抗干扰就增强

hc595_st_dr=0;

hc595_ds_dr=0;

}

void delay_short(unsigned int uiDelayShort)

{

unsigned int i;

for(i=0;i

{

; //一个分号相当于执行一条空语句

}

}

void delay_long(unsigned int uiDelayLong)

{

unsigned int i;

unsigned int j;

for(i=0;i

{

for(j=0;j<500;j++) //内嵌循环的空指令数量

{

; //一个分号相当于执行一条空语句

}

}

}

void initial_myself() //第一区 初始化单片机

{

led_dr=0; //关闭独立LED灯

beep_dr=1; //用PNP三极管控制蜂鸣器,输出高电平时不叫。

hc595_drive(0x00,0x00); //关闭所有经过另外两个74HC595驱动的LED灯

}

void initial_peripheral() //第二区 初始化外围

{

/* 注释四:

* 让数码管显示的内容转移到以下几个变量接口上,方便以后编写更上一层的窗口程序。

* 只要更改以下对应变量的内容,就可以显示你想显示的数字。初学者应该仔细看看display_drive等函数,

* 了解来龙去脉,就可以知道本驱动程序的框架原理了。

*/

ucDigShow8=8; //第8位数码管要显示的内容

ucDigShow7=7; //第7位数码管要显示的内容

ucDigShow6=6; //第6位数码管要显示的内容

ucDigShow5=5; //第5位数码管要显示的内容

ucDigShow4=4; //第4位数码管要显示的内容

ucDigShow3=3; //第3位数码管要显示的内容

ucDigShow2=2; //第2位数码管要显示的内容

ucDigShow1=1; //第1位数码管要显示的内容

ucDigDot8=0;

ucDigDot7=0;

ucDigDot6=0;

ucDigDot5=1; //显示第5位的小数点

ucDigDot4=0;

ucDigDot3=0;

ucDigDot2=0;

ucDigDot1=0;

}

总结陈词:

把本程序下载到朱兆祺51学习板上,发现显示的效果还是挺不错的。但是,本程序也有一个弱点,在一些项目中 ,主函数循环中的任务越多,就意味着在某一瞬间,每显示一位数码管停留的时间就会越久,一旦超过某个值,会严重影响显示的效果,有没有办法改善它?当然有。欲知详情,请听下回分解-----在定时中断里动态扫描数码管的程序。

关键字:主函数  while循环  驱动数码管  动态扫描程序 引用地址:第26节:在主函数while循环中驱动数码管的动态扫描程序

上一篇:第25节:用LED灯和按键来模拟工业自动化设备的运动控制
下一篇:第27节:在定时中断里动态扫描数码管的程序

推荐阅读最新更新时间:2024-03-16 14:47

8051单片机实战分析(以STC89C52RC为例) | 06 - 动态数码管驱动
1 动态扫描 那什么是动态扫描呢? 举个例子:有 2 个数码管,我们要显示“12”这个数字,可以先让高位的位选三极管导通,然后控制段选让其显示“1”,延时一定时间后再让低位的位选三极管导通,然后控制段选让其显示“2”。把这个流程以一定的速度循环运行就可以让数码管显示出“12”,由于交替速度非常快,人眼识别到的就是“12”这两位数字同时亮了。 在多个数码管显示数字的时候,我们可以轮流点亮数码管(一个时刻内只有一个数码管是亮的),利用人眼的视觉暂留现象(也叫余辉效应),就可以做到看起来是所有数码管都同时亮了,这就是动态显示,也叫做动态扫描。 那么一个数码管需要点亮多长时间呢?也就是说要多长时间完成一次全部数码管的扫描呢(很
[单片机]
8051单片机实战分析(以STC89C52RC为例) | 06 - <font color='red'>动态</font><font color='red'>数码管</font><font color='red'>驱动</font>
TM1637四位数码管模块驱动(TM1637.h头文件)51单片机C语言
TM1637四位数码管模块是一个带时钟点的4位共阳数码管(0.36英寸)的显示模块,驱动芯片为TM1637,驱动方式为IIC,因此只需2根信号线即可使单片机控制4位8段数码管(数码管8级灰度可调)。 控制接口:共4个引脚(GND、VCC、DIO、CLK),GND为地,VCC为供电电源,DIO为数据输入输出脚,CLK为时钟信号脚。 TM1637.h单片机源程序如下: sbit CLK= P3^4; //定义模拟IIC总线的时钟线 sbit DIO = P3^5; //定义模拟IIC总线的数据线 code unsigned char tab = { 0x3F,/*0*/ 0x06,/*1*/
[单片机]
TM1637四位<font color='red'>数码管</font>模块<font color='red'>驱动</font>(TM1637.h头文件)51单片机C语言
自制单片机之三----数码管电路的制做与驱动
数码管的使用方法与发光二极管没什么区别,只是把七或八只发光二极管组合在一个模件上组成了个8字和小数点,用以显示数字。为了减少管脚,把各个发光管的其中同一个极接在一起作为共用点,因此就产生了共阳极和共阴极数码之说。共阳管就是把各个发光管的正极接在一起,而共阴管就刚好相反。见下图: iframe id="iframe_0.3267470763530582" src="data:text/html;charset=utf8,%3Cimg%20id=%22img%22%20src=%22http://hiphotos.baidu.com/txz01/pic/item/3f24f244448bca8bb3b7dca7.jpg?_=3264
[单片机]
自制单片机之三----<font color='red'>数码管</font>电路的制做与<font color='red'>驱动</font>
CEPARK AVR单片机 之HC595驱动数码管显示
这里我用的CEPARK 的M64 AVR开发板,这一课的重点是学会如何使用74HC595来驱动数码管。 74HC595是具有8位移位寄存器和一个存储器,三态输出功能。移位寄存器和存储器是分别的时钟。数据在SHcp的上升沿输入,在STcp的上升沿进入的存储寄存器中去。如果两个时钟连在一起,则移位寄存器总是比存储寄存器早一个脉冲。移位寄存器有一个串行移位输入(Ds),和一个串行输出(Q7 ),和一个异步的低电平复位,存储寄存器有一个并行8位的,具备三态的总线输出,当使能 OE时(为低电平),存储寄存器的数据输出到总线。 引脚说明: QA--QH: 八位并行输出端,可以直接控制数码管的8个段。 QH': 级联输出端。我将它接下
[单片机]
基于AVR C++写的4位数码管驱动程序
我在这里用C++向大家展示一个实用的程序,如果你会C,相信C++对你来说不会很难。而且在我们平时的编程中,又要兼顾PCB,又要记住接线方法,是否会让你感到很棘手呢?经过我多年的编程经验,我把这个程序和大家分享,让大家领略到一些编程的技巧。这个程序需要将数码管的脚全部连接到MCU的IO上,可以任意连接. 首先我们需要定义一个mydef.h保存在你的工作目录下,输入以下内容,当然是由您自己的喜欢而定义,但是请记住需要对号入座。 #define seLED_QW() (clPB0()) #define seLED_BW() (clPB0()) #define seLED_SW() (clPB0()) #define seLED
[单片机]
51单片机教程:数码管动态显示(0~99999999)74hc138驱动
数码管动态显示0~99999999 一、共阴极8位数码管原理 首先了解一些必要知识 1、多位数码管是扫描显示,也就是同一时刻只有一个数码管显示 2、视觉暂留效果:第一个数码管显示完,第二个数码管接着显示,接着后面数码管一次显示,当显示(扫描)足够快的时候,人眼是看不到闪烁的,就认为多个数码管是同时显示的 3、多位数码管只能同时显示多个一样的数字,要显示不同数字需要扫描显示 比如说要显示12345678,你看起来8个数码管是同时亮的,其实同一时刻只有一个数码管是亮的 我们把时间放慢,看看数码管都发生了什么变化: 1、第1毫秒 2、第二毫秒 3、第三毫秒 4、第四毫秒 5、第五毫秒 6、第六毫秒
[单片机]
51单片机教程:<font color='red'>数码管</font><font color='red'>动态</font>显示(0~99999999)74hc138<font color='red'>驱动</font>
8位LED动态扫描时钟演示程序
//使用12MHz晶振,P0口输出段码,P2口作列扫描,用共阳LED数码管 // #include reg51.h code char dis_7 ={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff}; /* 共阳LED段码表 0 1 2 3 4 5 6 7 8 9 不亮 */ code char sCAN_con ={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; // 列扫描控制字 data char disdata ={0x00,0x00,0x00,0x00,0x00,0x00};
[单片机]
51单片机【三】静态与动态驱动数码管
数码管结构及分类 数码管是发光器件之一,内部由七个条形发光二极管(a,b,c,d,e,f,g)和一个小圆点发光二极管(dp)构成,51单片机开发板上为八段数码管,如下图所示,根据各段的组合不同,显示的字符也就不同。 按八个数码管的公共端接线不同,数码管又可分类为共阴极数码管和共阳极数码管两种。共阴极数码管的公共端接地,而共阳极数码管的公共端接电源,接线如下图所示(左为共阴极,右为共阳极)。当连接的单片机接口为高电平时共阴极数码管亮;反之,连接的接口为低电平时则共阳极数码管亮。 void DigDisplay(void) { unsigned char i = 0; // 首先确定位码,选中最左侧数码管,注意查3
[单片机]
51单片机【三】静态与<font color='red'>动态</font><font color='red'>驱动</font><font color='red'>数码管</font>
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved