打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
51入门系列教程| 华丽的显示(数码管篇)

今天咱聊聊数码管,其实数码管这个器件,本身没有什么好讨论的。为什么这里作为单独一节拿出来讨论呢?个人认为,这个小东西虽然简单,实际使用过程中,其实包含了很多。单片机知识以外的内容,譬如一些简单的编程技巧、编程与实际现象的关联,非常值得入门者认真思考。因为在今后的电子之路上,遇到的情况会比这个复杂得多。所以建立一种分析问题解决问题的方法和思考,比掌握一种单片机或者一种外设要重要得多。

先来看看啥是数码管吧,其实数码管就是几个LED并联的产物,看下图的数码管:

这是一个常用的二位8段数码管,可以看到有7个段位和1个小数点,其实对于每一个段位,内部都有与之对应的一个LED。

上图中右上角给出了每个段位的称号,分别是abcdefg和dp,dp指的就是小数点。上图中的03621A和03621B说明的就是:这8个LED在内部的连接方式。值得注意的是,03621A中,所有LED的阳极都连接到了一起,称之为共阳极数码管。不难判断,abcdefg和dp需要给个低电平,才能使得LED导通发光。03621B中,所有LED的阴极都连接到了一起,称之为共阴极数码管。不难判断,abcdefg和dp需要给个高电平,才能使得LED导通发光;因为这是个两位的数码管,所以还设置了DIG1和DIG2来控制那位数码管进行显示。

举个栗子:在共阳极数码管中,阳极连接到电源。如果要显示数字“1”,那么就需要a和c这两个段位一个低电平,其它为高,使得这两段位的LED发光即可。So,a-g的编码就是0101111,以此类推,0-9均可以通过abcdefg的赋值来通过显示。小数则可以通过dp段的赋值来显示。好玩一点的话,整个16进制0-f都可以显示,特别值得一提的是。共阴极和共阳极的输入编码是不一样的在共阳极数码管中,如果要显示数字“1”,a-g分别输入0101111 。而在共阳阴极数码管中,如果要显示数字“1”,a-g分别输入1010000。

到这里,数码管的内部结构应该有了个大致的了解,来一起玩玩吧。上个洞洞板图

背部飞线,焊接功底比较差,请随性鄙视

上个原理图吧

三极管在这里不是用于信号放大,而是作为一个开关器件,完成对位的选通。其余每个段位都使用1k左右的电阻作为限流,这个限流电阻值的选取,需要考虑端口的灌电流能力。特别注意a-dp,完全使用P2的8个端口,加上P1.7,总共消耗9个IO口

上代码

#include

sbit smgbit1 = P1^7;

sbit smgbit2 = P1^6;

disp_cache[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xf8,0x80,0x90};

void delay_ms(unsigned int xms)

{

unsigned int i,j;

for(i=xms;i>0;i--)

{

for(j=124;j>0;j--);

}

}

void main()

{ unsigned char i;

smgbit1 = 1;

smgbit2 = 0;

while(1){

for(i = 0;i <= 9;i++)="">

P2 = disp_cache[i];

delay_ms(250);

}

}

}

这段代码里面有个数组disp_cache,第一个元素disp_cache[0]=0xC0,换做二进制便是1100 0000。

对照数码管的段位,dp至a的电平便是1100 0000,abcdef都亮,g和dp不亮,也就形成的数字“0”。以此类推,disp_cache[1]- disp_cache[9]则分别代表了数字“1”-“9”,所以,咱进行数码管显示的时候

只需要关注disp_cache[i]里面i这个变量就行了。方便不少,这种简单有效的编程技巧,会有助于代码更加简洁,主函数里面。将smgbit,也就是p1.7位置1。这个时候,DIG1端口的三极管导通。DIG1口相当于直接连接至Vcc,而DIG2则与Vcc断开。然后在for循环里面,每500ms对i从0-9自加操作。同时在P2口输出disp_cache[i],也就是数码管从0-9进行显示,看实际运行情况

这样就完成了一个基础的数码管显示,但是回头想想.咱这可是2位的数码管哟!如果按照这种显示方式,同时显示2位的话,需要占用8+1+8+1=18个IO口.单片机硬件资源消耗情况实在太夸张了.

如何解决?

一是采用ASIC来驱动数码管,这种方式一来会增加硬件成本,二来要研究ASIC复杂的协议.另外一种就是扫描的显示方式了,所谓扫描显示,就是利用人眼的视觉暂留原理'.这个原理在现实生活中用的非常广泛,譬如电源、摇摇棒等等!每次只显示一位数码管,在ms的时间内进行切换.譬如要显示”13”,那就先显示1,再切换显示3.切换时间不超过十多ms的话,人眼会认为是同时显示的.这种方式可以较少IO口的使用,同时降低功耗

上个代码

#include

sbit smgbit1 = P1^7;

sbit smgbit2 = P1^6;

smgdisp_cache[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xf8,0x80,0x90};

unsigned int count,timer_count;

void init()

{

smgbit1 = 0;

smgbit2 = 1;

TMOD=0x01;//设置定时器0为工作方式1

TH0=0xfc;

TL0=0X66;

EA=1;//开总中断

ET0=1;//开定时器0中断

TR0=1;//启动定时器0

}

void SMG_Dis()

{

if(smgbit1){

P2 = smgdisp_cache[count%10];//求余,取个位数显示

}

if(smgbit2){

P2 = smgdisp_cache[count/10];//求商,取十位数显示

}

}

void time0() interrupt 1

{

timer_count++;

if(timer_count == 100)

{count++;

timer_count = 0;

}

smgbit1 = ~smgbit1;

smgbit2 = ~smgbit2;

if(count>99){count = 0;}

SMG_Dis();

TF0 = 0;

TH0 = 0xfc;

TL0 = 0x66;

}

void main()

{ init();

while(1){

}

}

在这段代码中,Init()用于初始化定时器,1ms中断,同时两位数码管只有其中一位可以显示.SMG_Dis()用于进行扫描显示,如果smgbit1和smgbit2.哪个选通,哪个就进行显示,中断服务函数中,处理定时器事宜,每100ms进行一次自加.并且每次中断都将smgbit1和smgbit2取反,保证每次只显示其中一位.看看运行效果

上面的动图中,基本计数显示的功能是达到了,但是,似乎个位的走动会影响到十位的显示.其实就是数码管在刷新下一个数据时,上次的数据会留有余晖导致的.也就是传说中的数码管鬼影.鬼影的消除,无非就是两种,加延时和数据清零.这里使用数据清零的办法,把中断函数做个简单处理

void time0() interrupt 1

{ P2 = 0xff; //消除鬼影

timer_count++;

if(timer_count == 100)

{count++;

timer_count = 0;

}

smgbit1 = ~smgbit1;

smgbit2 = ~smgbit2;

if(count>99){count = 0;}

SMG_Dis();

TF0 = 0;

TH0 = 0xfc;

TL0 = 0x66;

}

增加一句P2 = 0xff;及时对数码管的显示数据进行清零.用来对暂态数据进行清除

看效果

可以看出来,基本上残影都被消除掉了.其实鬼影的出现,并非是代码思路有问题.而是一些外部器件的特性使然.今后碰到的器件,很可能会有类似的情况.养成遇山开路、遇水搭桥的思维习惯,才是学习单片机的捷径.

Ok,今天就讨论到这里.

了解更多51系列教程,请关注“云汉电子社区”官方微信公众号,关注后回复'活动'可免费参与社区最新活动,有机会获得电子类图书以及京东购物卡!


本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
应广单片机系列
Micropython实例之TPYBoardv102位数码管显示实验
INT0中断
拍马屁的段位
四位七段数码管引脚图
Hbase 统计表行数的3种方式总结
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服