数码管动态显示程序全是8,有延时,不知道是不是电路出了问题,请看出问题的朋友解答一下

数码管显示有残影,困扰几天了还没有解决|我爱单片机 - 数码之家
查看完整版本: [--
赞助商链接
数码管显示有残影,困扰几天了还没有解决单独把显示部分独立出来还是这样[attachment=4514447]再发个视频硬件电路结构[attachment=4514448]测试程序#include &REG52.H&#include &intrins.h&#define&&&&&&&&uint unsigned int#define&&&&&&&&uchar unsigned char#define&&NOP&&_nop_&&&&&&&&()&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& #define&&NOP3&&_nop_(); _nop_(); _nop_()#define&&Duan P2sfr T2MOD&&= 0xC9;sfr&&P4&&= 0xe8;uchar code Num[]={ 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,};//uchar code Num[]={1,2,4,8,16,32,64,128,};uchar a,b,c,d;char Hour,Schar Min=10;bit Shan1,Shan2;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//闪烁标志&&&&&&&& 1Hz/2Hzsbit SMG1= P1^6;&&&&&&&&&&&&&&&&&&//时十位sbit SMG2= P1^7;&&&&&&&&&&&&&&&&&&//时个位sbit SMG3= P3^6;&&&&&&&&&&&&&&&&&&//分十位sbit SMG4= P3^7;&&&&&&&&&&&&&&&&&&//分个位sbit DP&&= P4^0;&&&&&&&&&&&&&&&&&&//小数点sbit Maohao=P1^2;&&&&&&&&&&&&&&&&&&//冒号void Delay(uint x)&&//延时子函数&&&&&&&&&& 50us{&&&&&&uint i,j;&&&&&&for(i=x;i&0;i--)&&&& //yanshi x10us&&&&&& for(j=15;j&0;j--);&&}void Xianshi()&&&&&&&&&& /*显示扫描*/{&&&&&&&&&&&&&&&&&&&&&&&&Duan=Num[Sec/10];&&&&&&&&&&&&&&&& //段码&&&&&&&&&&&&&&&&&&&&&&&& SMG1=1;&&&&&&&&&&&&&&&&&&&&&&&&&&//位开&&&&&&&&&&&&&&&&&&&&&&&&Delay(12);&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&SMG1=0;&&&&&&&&&&&&&&&&&&&&&&&&&&//位关&&&&&&&&&&&&&&&&&&&&&&&&Duan=0;&&&&&&&&&&&&&&&&&&&&&&&&Delay(20);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Duan=Num[Sec%10];&&&&&&&&&&&&&&&&&&&&&&&&SMG2=1;&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&DP=Shan1;&&&&&&&&&&&&&&&&&&&&&&&&Delay(12);&&&&&&&&&&&&&&&&&&&&&&&&SMG2=0;&&&&&&&&&&&&&&&&&&&&&&&&Duan=0;&&&&&&&&&&&&&&&&&&&&&&&&DP=0;&&&&&&&&&&&&&&&&&&&&&&&&Delay(20);&&&&&&&&&&&&&&&&&&&&&&&&Duan=Num[Min/10];&&&&&&&&&&&&&&&&&&&&&&&& SMG3=1;&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&Delay(12);&&&&&&&&&&&&&&&&&&&&&&&&SMG3=0;&&&&&&&&&&&&&&&&&&&&&&&&Duan=0;&&&&&&&&&&&&&&&&&&&&&&&&Delay(20);&&&&&&&&&&&&&&&&&&&&&&&&Duan=Num[Min%10];&&&&&&&&&&&&&&&&&&&&&&&&SMG4=1;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Delay(12);&&&&&&&&&&&&&&&&&&&&&&&&SMG4=0;&&&&&&&&&&&&&&&&&&&&&&&&Duan=0;&&&&&&&&&&&&&&&&&&&&&&&&Delay(20);}void main(){&&&&&&&&TMOD = 0x01;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//设置定时器0模式1&&&&&&&&TH0=0xE0;&&&&&&&&TL0=0x00;&&&&&&&&&&&&&&&&//设置定时0初值&&&&&&&&2ms@24.576M/6T&&&&&&&&TR0=1;&&&&&&&&&&&&&&&&ET0=1;&&&&&&&&&&&&&&&&&&&&&&&&//定时器0开始计时&&&&&&&&EA=1; &&&&&&&&SMG1=SMG2=SMG3=SMG4=DP=0;&&&&&&&&while(1)&&&&&&&&{&&&&&&&&&&&&&&&&Xianshi();&&&&&&&&}}void Tim0(void) interrupt 1 using 3&&&&&&&&//定时器中0{&&&&&&&&TH0=0xf5; TL0=0x95;&&&&&&&&&&&&&&&&//2ms@16M&&&&&&&&a++;&&&&&&&&if(a&124)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //0.25s&&&&&&&&{&&&&&&&&&& b++; &&&&&&&&&&&&&&&&Shan2=!Shan2; &&&&&&&&&&&&&&&&a=0; &&&&&&&&&&&&&&&&if(b&1)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//0.5s&&&&&&&&&&&&&&&&{ &&&&&&&&&&&&&&&&&&c++;&&&&&&&&&&&&&&&&&&b=0; &&&&&&&&&&&&&&&&&&Shan1=!Shan1; &&&&&&&&&&&&&&&&&&if(c&1)&&&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&&&& Sec++;&&&&&&&&&&&&&&&&&&&&&&&&c=0;&&&&&&&&&&&&&&&&&&&&&&&&if(Sec&59)&&&&&&&&&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Min++;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Sec=0;&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&}&&&&&&&&}}复制代码
赞助商链接
先关段,延时20,再关位,应该会好的。应为延时太短,三极管和数码管会有电流存在,还来不及放完
赞助商链接
我提2点1、不知道LED数码管型号,12V驱动而限流电阻221是否太小了,LED太亮导致残影2、个人非常反对在主循环体内使用delay函数,因为在显示子程序内是靠delay延时来显示内容,而这时候很可能产生中断使显示数据改变,从而造成残影。
数码管是3寸的,内部是6串结构中断不会影响程序数据的,调用中断程序、子程序前都要把当前程序压入堆栈的
降低电压试试看,前些天我就遇到这种问题了,把电压降低后解决问题
把限流电阻换大一点应该能解决,不过太大了就会变暗了
8050去掉上拉或改成下拉。8550加12V上拉。
只用驱动,不接控制,直接检测给信号来判断下。修板子时有遇到过换驱动集成块后显示残影的问题,集成块不合格造成,换个厂做的就好了。
:8050去掉上拉或改成下拉。8550加12V上拉。 ( 00:17) Q2\Q3\Q4的基极没有上拉电阻,关断的时候由于载流子存储还会导通一段时间。加适当的上拉电阻吧。
:数码管是3寸的,内部是6串结构中断不会影响程序数据的,调用中断程序、子程序前都要把当前程序压入堆栈的 ( 00:01) 1、可能我没表述清楚,我坚持认为是代码问题,你延时函数是多少时间?整个主循环就只有1个显示函数,那么循环1次用时多少?在循环的过程中产生中断的话,中断里面又刚好秒进位。2、整个代码非常低劣(恕我直言),大量delay不说,在主循环里对duan数据有2次除法2次取模,单片机本身数学运算就弱还耗费大量的周期来处理这些运算,效率会很低,实时性变差。我写LED显示的思路是开辟几个字节RAM当做显示缓存,显示子程序只负责直接把显示数据送到LED,并不做任何运算,而在每次秒进位时才运算一次显示数据送进缓存,这样效率提高很多。本人也属初学,请指正
:1、可能我没表述清楚,我坚持认为是代码问题,你延时函数是多少时间?整个主循环就只有1个显示函数,那么循环1次用时多少?在循环的过程中产生中断的话,中断里面又刚好秒进位。2、整个代码非常低劣(恕我直言),大量delay不说,在主循环里对duan数据有2次除法2次取模,单片机 .. ( 00:47) 1.在扫描过程中中断触发会引发显示错乱,比如当前时间是11分59秒,当显示59秒之后产生中断,那么这一次实际显示的数字就是12 59,不过因为一次扫描的时间相当短暂,有一次错乱不会有什么人类可察觉的问题。2.程序确实写得不够精简,只在中断时计算显示数据可以大大减少开销。我不是很熟悉51,看注释两次中断之间有2ms,足够完成所有计算了,不会出现这次没算完下次中断又来的情况。一次除法用时也不会太长,印象中也就几个周期,短于delay(1)。不过算起来delay(1)大概是几十个周期,显示函数执行一次不超过1k个周期,中断我不是很了解先忽略,那么扫描频率会在1k-2kHz之间,相当高了。我之前做过一个扫描数码管驱动电路,驱动频率仅200Hz左右,但三极管不加上拉电阻时用示波器可以观察到LED上的电压已经不是方波而是锯齿波了。
6楼是正解!!!!!!!!!!!该死的字数
:降低电压试试看,前些天我就遇到这种问题了,把电压降低后解决问题 ( 00:12) 与电压无关。电压只是影响亮度,降电压是治标不治本
:8050去掉上拉或改成下拉。8550加12V上拉。 ( 00:17) 8050必须有上拉,下拉则无需,因为单片机输出是弱上拉的开漏结构,高电平驱动能力很弱。8550加上拉倒可以试试
:1、可能我没表述清楚,我坚持认为是代码问题,你延时函数是多少时间?整个主循环就只有1个显示函数,那么循环1次用时多少?在循环的过程中产生中断的话,中断里面又刚好秒进位。2、整个代码非常低劣(恕我直言),大量delay不说,在主循环里对duan数据有2次除法2次取模,单片机本身数学运算就弱还耗费大量的周期来处理这些运算,效率会很低,实时性变差。我写LED显示的思路是开辟几个字节RAM当做显示缓存,显示子程序只负责直接把显示数据送到LED,并不做任何运算,而在每次秒进位时才运算一次显示数据送进缓存,这样效率提高很多。本人也属初学,请指正....... 1,单片机是单任务运行的,一次只能处理一条指令,就算再循环过程产生中断改变数据也不会产生残影。相应中断程序前单片机要先执行完当前指令,然后把当前执行的函数压入堆栈保护起来,然后再调用中断函数。2,/10运算反汇编后仅3条指令,微不足道,这只是个测试程序,实际上用的是RTC时钟芯片,要是每次进位运算要做大量的if判断,还不如直接运算。
1,中断中数据改变不会影响当时执行程序的数据,直到下一个循环才会改变。2,也没必要一味追求高效,单片机资源够用就行,实际上是过剩状态,提高执行效率也没有多大意义
1,中断中数据改变不会影响当时执行程序的数据,直到下一个循环才会改变。2,也没必要一味追求高效,单片机资源够用就行,实际上是过剩状态,提高执行效率也没有多大意义
显示模块现在为什么不用一个TM1637呢?我们公司现在都很多在用了~
可能还是程序上的问题void Xianshi()&&&&&&&&&& /*显示扫描*/{&&&&&&&&&&&&&&&&&&&&&&&&Duan=Num[Sec/10];&&&&&&&&&&&&&&&& //段码&&&&&&&&&&&&&&&&&&&&&&&& SMG1=1;&&&&&&&&&&&&&&&&&&&&&&&&&&//位开&&&&&&&&&&&&&&&&&&&&&&&&Delay(20);&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&SMG1=0;&&&&&&&&&&&&&&&&&&&&&&&&&&//位关&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Duan=Num[Sec%10];&&&&&&&&&&&&&&&&&&&&&&&&SMG2=1;&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&DP=Shan1;&&&&&&&&&&&&&&&&&&&&&&&&Delay(20);&&&&&&&&&&&&&&&&&&&&&&&&SMG2=0;&&&&&&&&&&&&&&&&&&&&&&&&Duan=Num[Min/10];&&&&&&&&&&&&&&&&&&&&&&&&SMG3=1;&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&Delay(20);&&&&&&&&&&&&&&&&&&&&&&&&SMG3=0;&&&&&&&&&&&&&&&&&&&&&&&&Duan=Num[Min%10];&&&&&&&&&&&&&&&&&&&&&&&&SMG4=0;&&&&&&&&&&&&&&&&&&&&&&&&Delay(20);&&&&&&&&&&&&&&&&&&&&&&&&SMG4=0;}后面没有必要加多个 Delay(20);的呢从显示来看出是位没有完全关闭,下一个数有上一个的残影,但Duan=0;都加上了问题……
2个不同延时是为了调整亮度,为何有问题实在是搞不懂
:2个不同延时是为了调整亮度,为何有问题实在是搞不懂 ( 09:20) 用示波器看看相关电路的波形吧。
1、2、3、4总共4个灯。显示2之前先把1关了,再开2.
已经是这样做了
整个扫描过程延时量超过定时器2ms中断,造成在扫描过程中会被定时器中断干扰,形成乱码或者残影。最好的LED动态扫描是放在定时器中断里,定时刷新显示端口,整个过程无需延时函数,比如你有4个显示位,那么利用2ms的中断,循环一次只要8ms,甚至还可以加一个消隐,就是5*2==10ms,整个扫描过程还是100HZ,眼睛看不到闪烁的,这样做的好处是开可以调整显示占空比,调节亮度。例如&&uchar t0_void Tim0(void) interrupt 1 using 3&&&&&&&&//定时器中0{&&TH0=0xf5; TL0=0x95;&&&&&&&&&&&&&&&&//2ms@16M //LED动态扫描&&t0_cnt++;if(t0_cnt&4)t0_cnt=0;//将4增大可以降低LED亮度,但是太大后会降低扫描频率,除非提高定时器时间switch(t0_cnt)&&{&&csse 0:SMG4=0;&&&&&&&& Duan=Num[Sec/10];&&&&&&&&&&&&&&&& //段码&&&&&&&& SMG1=1;&&&&&&&&&&&&&&&&&&&&&&&&&&//位开&&&&&&&&&&case 1:SMG1=0;&&&&&&&& Duan=Num[Sec%10]+0x80*//假设你的数码管DP接在P2.7上,当做秒点&&&&&&&& SMG2=1; &&&&&&&&&&&&&&case 2:SMG2=0;&&&&&&&& Duan=Num[Min/10];&&&&&&&& SMG3=1;&&&&&&&&&&&& &&case 3:SMG3=0;&&&&&&&& Duan=Num[Min%10];&&&&&&&& SMG4=1;&&&&&&&&&& &&csse 4:SMG4=0;&&&&&&&& &&default:&&}&&&&&&&&&&&&&& && //这里写你其他的定时函数}
呵呵,不要乱说,定时器并不影响扫描,
我补充了例程,你先试试再说
呵呵,没法调整亮度的,扫描空闲一位也是浪费,我的亮度范围非常大,夜间才可见的最暗的微亮,到白天能正常看的亮度,相差几十倍,这种思路是行不通的
别着急嘛,慢慢来,我以前也为这个问题困扰过,支持你。
试一下这个电路, [attachment=4517792]
虽然还搞不清问题出在哪里,不过可以肯定与主程序扫描还是定时器扫描无关,两者只是方式不同。
扫描显示还是用定时中断,用延时占用单片机资源。参考代码://-------------------------------------------------------------------//Timer1Int:定时中断子程序,2ms//-------------------------------------------------------------------void Timer1Int(void) interrupt 3{&&&&&&&&TH1=0xE3;&&&&&&&&&&&&&&&&&&&&&& //延时时间2ms&&&&TL1=0x32;&&&&Snum++;&&&&if(Snum==1)&&&&&&&&&&&&&&&&&&&&&&&&//输出个位数字&&&& {&&&&&&&&COM2=1;&&&&&&&&COM3=1;&&&&&&&&P2=LED[Show[2]];&&&&&&&&COM1=0;&&&&&& }&&&&if(Snum==2)&&&&&&&&&&&&&&&&&&&&&&&&//输出十位数字&&&& {&&&&&&&&COM1=1;&&&&&&&&COM3=1;&&&&&&&&P2=LED[Show[1]];&&&&&&&&&&&&&&&&COM2=0;&&&&}&&&&if(Snum&2)&&&&&&&&&&&&&&&&&&&&&&&&//输出百位数字&&&& {&&&&&&&&Snum=0;&&&&&&&&&&&&&&&&&&&&&&&&//超时清零&&&&&&&&COM1=1;&&&&&&&&COM2=1;&&&&&&&&P2=LED[Show[0]];&&&&&&&&//显示温度符号&&&&&&&&COM3=0;&&&&}}共阳,位低电平有效,先关,显示段,再开位显示。
数码管显示不都是需要有消隐的吗?我以前的残影是通过在送下次数据前关前一次位选搞定的。没有细看程序。。只是一些自己的经历说下。。。
楼上的显示函数很好。。楼主可以借鉴。。我现在写的程序里超过1ms的延时都是用定时实现的。。delay只在初始化有用过。。。
:虽然还搞不清问题出在哪里,不过可以肯定与主程序扫描还是定时器扫描无关,两者只是方式不同。 ( 19:45) 我敢说绝对有关系,不要太固执己见,上面用朋友都给出了例子,照这思路改下程序就个把钟头的事。今天我仔细思考过这问题的,但是要画个流程图才好解释清楚
:呵呵,不要乱说,定时器并不影响扫描, 我玩计算机电子电路仿真的,很多时候要把自己的大脑模拟成CPU来考虑问题,而人觉得没问题的地方往往就是出错的地方,我画了张图来表述[attachment=4518668]你的主循环其实也就是一个显示扫描循环,就用图片左边的黑箭头表示你把自己当做CPU来走流程当SMG1显示完成时,刚好发生中断导致sec变量加1,那么这时候显示是不是就出问题了???
:我玩计算机电子电路仿真的,很多时候要把自己的大脑模拟成CPU来考虑问题,而人觉得没问题的地方往往就是出错的地方,我画了张图来表述[图片]你的主循环其实也就是一个显示扫描循环,就用图片左边的黑箭头表示....... ( 22:21) 这确实是个问题,但是该现象出现的周期为1秒,人眼基本不会观察到。从楼主的照片和视频可以看到,拖影是一直存在,而不是1秒出现一次。并且可以观察到小数点也有拖影现象。所以中断使变量前后不一致不是导致拖影的根本原因。
:我玩计算机电子电路仿真的,很多时候要把自己的大脑模拟成CPU来考虑问题,而人觉得没问题的地方往往就是出错的地方,我画了张图来表述[图片]你的主循环其实也就是一个显示扫描循环,就用图片左边的黑箭头表示....... ( 22:21) 绝对没有这个问题,1/100秒一闪而过人眼是觉察不到的
:我玩计算机电子电路仿真的,很多时候要把自己的大脑模拟成CPU来考虑问题,而人觉得没问题的地方往往就是出错的地方,我画了张图来表述[图片]你的主循环其实也就是一个显示扫描循环,就用图片左边的黑箭头表示....... ( 22:21) 补充一点,图片和视频都是RTC芯片获得的时间而不是中的产生的
:绝对没有这个问题,1/100秒一闪而过人眼是觉察不到的 ( 22:59) 你也觉得不是软件问题,那你有尝试更改硬件电路了吗?
我想问下benli,你程序中是先关位,再关段。有没有照我说的先关段,再关位,之后的效果怎样?
又想了下,这样也不会致使鬼影,数据变成40了,这一位会直接显示0。这和正常的数据变化的过程是看上去一样的,扫描一遍也就是1/100s的时间,人眼根本觉察不到,看起来就和39变为40一样,不会产生鬼影,
改过。应当不是软件的问题。已经从硬件上进行处理了,在每个段对地加了个电阻,现在已经基本上看不到鬼影了,只剩下小数点没处理好
刚用4位数码管做测试,定时器中断方式驱动,25HZ闪得很厉害,30HZ明显好转,35HZ基本看不到闪,40HZ完全看不到闪,100HZ再快,残影越来越明显,原因是写段数据时不关位驱动。不知道楼主的是不是写段时没有关位驱动,并且扫描速度较快。
没消隐发送下一个内容之前,把数码管全部关闭。数码管扫描显示都得这样啊,就像按键消抖,写按键扫描必须消抖…
试一下全亮 然后 全灭 看看没问题的话 就是代码问题目测是延迟
查看完整版本: [--
Powered by
Time 0.099336 second(s),query:5 Gzip enabled查看: 53724|回复: 230
帮助新手学习单片机数码管电子钟:原理,c程序详解
这个帖子意在帮助有兴趣的初学者理解单片机驱动最基本的LED数码管电子钟的硬件原理,以及如何用c编程实现。图和代码是实打实的东西。这些内容对于仔细学过单片机的和会搞的人就不必浪费时间了。为了保持连续性,请勿跟帖。
实物图:重点是显示效果如下:
clock.jpg (18.64 KB, 下载次数: 73)
11:46 上传
硬件主要部分电路:
FIG.JPG (44.58 KB, 下载次数: 121)
11:46 上传
从以下几个部分解析:
1,8段led数码管的原理
2,单片机如何动态驱动多个数码管
3,单片机怎样构成电子钟
4,怎样用c语言编程
5,程序代码详解
1:8段led数码管的原理:再复习一下
& & LED::发光二极管大家都用过吧?直流电源,串上限流电阻,再串上LED就成了一个小电灯,
& &8段数码管就是把8个LED按数字“8”的笔画安排,使各个LED按要求发光就形成数字或其他符号了。见下图:
txt1.JPG (31.8 KB, 下载次数: 90)
11:46 上传
这个8字数码管由7个LED构成笔画,另一个LED为小圆点。这8个笔段通常以a b c d e f g h 表示,这个位置是固定的。
用电路图表示在右边。注意,数码管都是由笔段电极和公共电极构成的,而按制造时的内部接法不同分为共阳极和共阴极两种,看图就明白。老式单片机,吸收电流能力较强而吐出电流较弱,用共阳极接法多些。 新式单片机两种都可以用。
对于共阳极接法,单片机的口线通过限流电阻和LED的笔段电极--阴极连接,正好一个8位口对应一个数码管的各段,公共阳极因电流较大,超出单片机的驱动能力所以另外用一个晶体管控制,这个晶体管的基极则另外用一个口线控制:显然只有这点为0才能使得数码管发光。设a b c d e f g 均为低,h为高,则显示不带点的8字。
共阴极数码管则相反,只有笔端电极-阳极为高,公共电极:阴极为低时才能显示。显然这个制作用的是共阴极数码管。下面,列出共阴极管显示各个数字时笔段电位高低的关系,也就是让单片机的一个8位口设为P0口,如原理图,和笔段对应时的驱动二进制数据对应的16进数和显示的字形:举例说显示2,要让P0口输出十六进数0X5B
P0.7& & P0.6& & P0.5& & P0.4& & P0.3& & P0.2& & P0.1& &P0.0
h& && && &g& && && & f& && && &e& && && &d& && && &c& && && &b& && && &a
0& && && &0& && && &1& && && &1& && && &1& && && &1& && && &1& && && &1& && && &==0X3F&&显示“0“
0& && && &0& && && &0& && && &0& && && &0& && && &1& && && &1& && && &0& && && &==0X06& && && &&&1
0& && && &1& && && &0& && && &1& && && &1& && && &0& && && &1& && && &1& && && &==0X5B& && && &&&2
0& && && &1& && && &0& && && &0& && && &1& && && &1& && && &1& && && &1& && && &==0X4F& && && &&&3
0& && && &1& && && &1& && && &0& && && &0& && && &1& && && &1& && && &0& && && &==0X66& && && &&&4
0& && && &1& && && &1& && && &0& && && &1& && && &1& && && &0& && && &1& && && &==0X6D& && && &&&5
0& && && &1& && && &1& && && &1& && && &1& && && &1& && && &0& && && &1& && && &==0X7D& && && &&&6
0& && && &0& && && &0& && && &0& && && &0& && && &1& && && &1& && && &1& && && &==0X07& && && && &7
0& && && &1& && && &1& && && &1& && && &1& && && &1& && && &1& && && &1& && && &==0X7F& && && && &8
0& && && &1& && && &1& && && &0& && && &1& && && &1& && && &1& && && &1& && && &==0X6F& && && && &9
0& && && &1& && && &0& && && &0& && && &0& && && &0& && && &0& && && &0& && && &==0X40& && && &&&—
此外还可以显示A b&&c&&d& &E& & F& & G& & H& & L& & P等,就不列举了。
另一点,上面小点h始终不显示 ,怎样显示它呢?以后用到再说,一般用它较少。好了休息一下。
<p id="rate_09" onmouseover="showTip(this)" tip="赞一个!&经验 + 10 点
" class="mtn mbn">
<p id="rate_86" onmouseover="showTip(this)" tip="&经验 + 10 点
" class="mtn mbn">
<p id="rate_98" onmouseover="showTip(this)" tip="精品文章&经验 + 10 点
" class="mtn mbn">
用C语言编程
有关C语言的书籍很多,其实也用不着我来多嘴,不过是想救自己自学C的一些体会来说道说道,对老鸟毫无意义,对新手可能有所帮助,要深入钻下去,还是看书吧,我这里是尽量用通俗理解说清楚一点,即使一下还不会用C编程,如果能看明白C的代码也好啊。事情总是一步一步,首先别怕,人家都能做出来,做出来就是给人用的,只要花力气,一定能学会。
1,为什么要用C。原因很多,既然大家都用,自然有好处,最大的好处就是它的基本语法对于不同的单片机都能用,只是具体细节不一样,而汇编对于不同的单片机完全没有通用性,其他就不多说了。
2。快速了解C语言
2。1.构成C语言的主要基本零件:
数据:数据类型,常量和变量
运算符,表达式:用他们来操作数据
函数:通过运算符、表达式和数据一起来完成所需要的功能。注意C语言只有函数,没有子程序。
2.。2 C语言的基本框架
下面逐一说明。
C语言的数据,计算机语言处理的就是数据,C语言也一样。
在程序中不变的数据是常量,在程序中可改变的数据是变量
为了限定常量和变量的取值范围,我们要用数据类型来说明。在51的C,简称51C,数据类型有:
字符型:char& &:长度1字节(8位二进数)分为
有符号字符型&&signed char&&取值范围-128~+127
和无符号字符型 unsigned char 取值范围 0~255
默认为有符号型(不用加signed)
使用最多的是无符号型,必须加以unsigned 说明。例如 unsugned sec:这里sec就是一个变量,它是无符号字符型的,取值最大只能到255,如果写出sec=500;意思是给sec赋以数目500,那就错了。对于更大的数,我们使用
整型:int& &:长度2字节(16位二进数)和字符型类似也有
有符号整型 (默认)取值范围-3
无符号整型&&unsigned int& & 取值范围 0~65535& & 例如unsigned int&&sou=7850;正确,变量sou既然是无符号整型,它可以达到7850没问题。再大的数据就要用
长整型 :long& &:长度4字节 (32位二进数,赶上电脑了)也有有符号和无符号两种
有符号长整型&&(默认) 取值-~
无符号长整型&&unsigned long&&取值 0~ 为了表示小数,还有
浮点型&&float&&:长度4字节,可表示7位有效十进数。运算中还有
指针型 *&&长度1~3,它还具有上述类型。 51C还有一些独有的:
位标量 bit 只能取值0或1 ,例如 bit&&yn 只可以 yn=0;或 yn=1,别看它简单,程序中这个很方便
可寻址位 sbit 用它来访问可寻址位,如sbit&&P11=P1^1;用P11来访问P1口的P1.1,这个也用得多。
此外还有特殊故功能寄存器的sfr 和sfr16使用较少就不说了,使用最多的还是
unsigned char 和 unsigned int
常量:分为
整型:例如 123& &&&-8& &0xf9&&0b
都是程序总就是以数字出现
浮点型& &例如& & 123.45& &75e3
字符型& &例如‘A'& & 'a'& & 有单引号,注意C的大小写有区别,不可随意
字串型&&例如&About U &&&&V& 用双引号,V加了双引号尽管只有一个字符也是字串型的
变量类型上面都说了,在程序中,我们可以自己定义一个变量,然后使用它进行运算。
例如&&先定义unsigend min ;unsigned sec
然后使用:min=sec-60等等。决不可未加定义就直接来一个sta=7..
完整地说,要定义一个变量,得给他戴上3顶帽子:
存储种类&&数据类型&&存储器类型&&变量名
例如&&static&&unsigend char&&data&&num, 变量num是静态的,无符号字节 内部数据存储器
一般不用这多,存储种类就默认为auto不用写,unsigned char必不可少,存储器也不用指定。除非用到外部存储器等等,就不多说了
虽然说,用一个或一些字母就可以表示变量名,但是也不可任意为之,因为有些字是专用的,例如不能用数据类型int做变量名,类似的还有一些程序语句里的关键字,都不能做变量名,变量名除了大家常用的例如i 、 j& &还可以用具有意义的便于记住,或者用汉语拼音也行,还要注意,变量名可以以字母打头,也可以用下划线打头,但是不可以数字打头。例如
unsigned&&& &&&unsigned _23都可以,unsigned 5d就不行。
下面说C里面的运算符,表达式和语句,用他们来操作变量、常量,得到我们所需的结果。
[ 本帖最后由 wey05 于
17:23 编辑 ]
市面上买到的数码管,除了尺寸不同(驱动电流不同)以外,有单个的,双联体的,四联体的。单个的就是8个段电极和1个公共电极了,联体的,各个数码管的对应笔段内部已经连接好,也只有8个脚引出,各位数码管的公共电极则分别引出,例如4联的,一共有12根引脚。那又有什么区别呢?
单个的数码管,可以用于静态显示,也可用于动态显示。
多联的数码管只能用于动态显示。
所谓静态显示,就是数码管段电极接到一个硬件锁存器上,单片机控制口如P0,顺序输出各个数码管对应的驱动码,驱动码被分别锁存起来,再推动数码管。只要锁存器不变,数码管显示就不变。如有8个数码管,就有8个锁存器,它们同时可以显示8位不同的数字。这样的显示,明亮而稳定。但缺点就是硬件电路复杂了。但如果采用 串入并出的锁存器,可以减少单片机所需的口线,对于口线紧张的情况(如使用2051)有时还是要采用的。下面说说
2。单片机如何动态驱动多个数码管
所谓动态显示,是让几个数码管轮流显示,每一时刻只有一个管子点亮,其余都必须熄灭。方法是首先把所有数码管的公共电极电路都断开,这时大家都不显示,然后单片机输出字段数据,(例子是P0口),然后开通需要显示的数码管公共电极,这个管子就亮了。其他管子尽管也加上了相同的字段数据,但是他们的公共电极都还关着,当然也不会亮。拿这个例子来说,如果在P0口输出数据0X4F,也就是,然后P2口输出0X01也就是也就是P2口只有P2.0为高,其余都是低,那么Q8导通,最右一个(最低位)数码管就点亮:最低位或个位就显示“3”。
接下来P2口输出0,这个管子就熄灭了。大家一片黑。P0口输出0X5B。(数字“2”的笔段码),然后P2口输出0X02,也就是,P2.1为高。.于是Q7导通,十位就显示数字“2”。
就这样一位位地显示下去,直到最高位,然后又从最低位开始。周而复始。只要每个管子点亮的时间较短,整个显示过程很快,那么由于人眼跟不上数码管亮灭的快速的变化,就可以显示出完整的数字了
一般,每个数码管只要点亮4毫秒,8个管子从头到尾依次亮灭一遍需要32毫秒多,1秒钟能刷新30多次,这样虽然也还有少许闪烁感,但显示已经很清晰了。
在动态显示的情况,数码管愈多则在完整的显示周期中一个管子分得的时间就越少,而使平均亮度降低为了显示清晰,管子的限流电阻就要减小,驱动电流就要增加。所以显示位数也不能够增加太多。一般8位是没有问题的。
上上面举例是从右往左依次显示,反过来行不行呢?当然可以。不过还要结合具体的应用条件决定,这个等到编程时再说。
<p id="rate_56" onmouseover="showTip(this)" tip="好文!&经验 + 10 点
" class="mtn mbn">
我想搞个控制13个LED管的,,,不知道什么搞?
我想搞个控制13个LED管的,,,不知道什么搞?
好了,现在如果用8个数码管显示电子钟,各个数码管承担的任务就可以按照我们的要求安排了。以本实例说,从右至左依次是:秒个位,秒十位,分个位,分十位,横线,小时个位,小时十位,空白备用。比如说要显示45秒,那并不是说在P0口输出数据45然后依次开通秒个位和十位,而是:先把数字45分解为两个单独的数字4和数字5,然后找到他们所对应的共阴极数码管显示码:4对应的是16进数0X66(2进数),5对应的是0X6D(2进数),然后在P0口输出数字5的显示吗0X6D,P2口输出0X01,晶体管Q8开通于是最低位数码管显示“5”。持续一小会例如4毫秒,P0口输出0X00,不显示了,乘机P2口输出0X02(2进数)开通Q7,再给P0口输出数字4的显示码0X66,此位显示4了,再持续4毫秒。。。于是时分秒就动态显示出来了。
然而我们做的是电子钟,时分秒要随时间按规律变化,因此下面就说说
时间信号源
单片机电子钟一般可以使用专用实时钟电路作为时钟源例如最常用的DS1302,优点是走时精准,加上后备电源(小电池或法拉电容)在单片机停电时依然正确走时,还有日历功能。不过它牵涉到对电路编程,这次就不说了。以后如果大家有兴趣专门再讲。再一个方法就是利用单片机自身的资源,通过软硬件结合,产生秒信号。有了秒信号,分和时就好办了。正好这个52单片机内部有3个定时-计数电路:定时计数器T0,T1,T2。作为定时器使用的情况下,它按照单片机的工作节奏:机器周期计数,而机器周期是依赖于精准的石英振荡器产生的振荡周期的,传统的AT89S51单片机,用12兆晶体时,机器周期是1微秒。STC89C52RD,用12兆晶体时则可以使用1微秒或0.5微秒两种。不过由于STC单片机为了保证串口编程速率没有误差,使用的是11.0592兆赫的晶体,这样机器周期就要长一点。这个必须须记住的。
3.单片机怎样构成电子钟
任何一个钟,手表也好,大本钟也好,有三个部分:心脏=走时机构,脸面=显示装置,再加上调节装置:对表。
以上所说,是数码管的基本显示原理。下面再仔细说说具体到这个电子钟的显示安排。
由图可知,8个数码管从右到左,分别是秒个位,秒十位;分个位,分十位;横杠;小时个位,小时十位。还剩下最左一位备用。
按现在的动态显示方式,是从左到右一个个轮流点亮、熄灭数码管,周而复始。对于具体的一个时间值例如10时35分24秒,在显示前先要把时分秒分别拆开为十位数和个位数,要显示哪个数,除了开通对应数码管的公共阴极,还要给字段电极加上这个数字的显示码。对照原理图,过程可以是这样的:
首先P2口为0,当然P2.0到P2.7都是0,数码管全部关断,漆黑一片,准备显示。
P2口为0x01,这时仅仅P2.0为1,Q8开通。然后P0口输出0X66——数字4的显示码,最低位立即显示4。维持数毫秒,然后P0口输出0,管子灭了。趁机把P2口输出0X02,仅仅P2.1为1,Q8关闭,Q7开通,然后P0口输出数字2的显示码0X5B,秒十位显示2了。就这样,轮流把P2口的各位输出1,然后P0口加上显示代码并维持一会儿,最后就动态地显示出完整的时间数值了。注意,在转到下一个显示位置前,先关掉显示代码。下面说说怎样用单片机的定时器取得时间源。
继续~~~~~~~~~~~~
怎样使用定时/计数器:16位定时器
51单片机有2个16位定时计数器C/T0和C/T1,52机还多一个C/T2有控制串口的作用先不管他,C/T0 和CT1既是计数器又是定时器,怎么说?它的工作方式可以人为改变的,如果它输入的是P3.4引脚上的脉冲,那么就对这些脉冲计数计数值送到16位(二进位)寄存器TH0(高8位)TL0(低8位)中,如果它输入的是单片机的机器周期振荡脉冲tm那就成了定时器。下面用一个简化图表示它是如何工作的
timer.JPG (28.41 KB, 下载次数: 73)
00:50 上传
外部脉冲计数器这次用不上,用的是定时器,图中画的是C/T0,C/T1也是一样,但是C/T0和C/T1的工作都是受特殊功能寄存器TCON和TMOD控制,这个只有一套,然而计数器则各是各的图上画的是TH0和TL0,对于C/T1则它有TH1和TL1。
我们知道,机器周期是石英晶体振荡器分频而来,这个东西是比较精准的,频率误差一般在5-20ppm甚至更低,51是晶振12分频,STC机也可选6分频,甚至有单周期(不分频)的高速型,以12分频为例,假设晶振是12兆的,那分频后的机器周期tm就是1微秒,如果计数4000次就是4毫秒,用它来控制前面说的数码管显示倒是不错,而且计数40000次就是40毫秒,经过250个40毫秒是多少呢?1秒!干嘛是40毫秒呢,一次连续计数1000000,不就是1秒吗?不行!因为16位计数器最大才能计数65536,计数40000还在其范围内,要计数1百万那相差太远了。
要是定时计数器CT0(CT1也一样)工作起来,就要正确设定控制它的特殊寄存器TMOD 和TCON,还要给TH1、TH0正确的预置值,最后再使它工作。先看TMODE和TCON:如上图所示,TMOD的高4位控制C/T1,低4位控制C/T0.就以C/T0说事,
最低位M1M0是工作方式选择,这两位00:方式0,13位计数,01:方式1:16位计数。10,方式3,自动加载8位计数,11,方式4;两个8位计数器,现在我们使用16为计数器,所以M1为0,M0为1.
C/T为0时机器周期脉冲可以进来计数,那好,把它置0.
GATE位为0时允许计数开关闭合。所以置它为0。现在只要把TCON寄存器的TR0置位1,计数通路开关就闭合上机器周期脉冲就能够进入计数TL0-TH0。.可见设定好这两个寄存器的相关位,定时器就可以跑起来。但是定时时间长短,就要给TH0]TL0正确的预置值。
假如预置值是0,那么显然定时时间是65.536毫秒(12兆晶振)预置值是65534那么一个脉冲就把它装满再来一个脉冲就溢出中断了,两个脉冲之间的时间就是1微秒。一般来说,可以用以下公式计算预置值:
TH0=(65536-tx*f/6
TL0=(65536-tx*f/6,
上式中,tx是定时时间,微秒;f是晶振频率,赫兹,特别是STC使用的晶振为了满足串口下载0误差,通常是的。
顶,终于快到程序部份了..
使用定时器的要点
如上所说。使用定时器就是1:设置相关寄存器,2:设定预置值。例如,使用T0作为16位定时器,定时时间40毫秒,T1作为16位定时器,定时时间4毫秒。
TMOD:它的各位应该是:
D7—-T1的GATE:0
D6— T1的C/T:0
D5— T1的M1 :0
D4— T1的M0 :1(16位计数M1:0 M0:1)
D3—-T0的GATE:0
D2— T0的C/T:0
D1— T0的M1 :0
D0— T0的M0 :1(16位计数M1:0 M0:1)
综合起来,TMOD的设置值是进数就是0X11。
TCON:只有TR1控制T1的启动计时,TR0控制T0的启动计时,什么时候需要启动计时器,就把这两位分别置1即可,要停止计时,就把这两位分别置0。.
定时器的中断:当定时器使用方式1、方式2的时候,一旦TH1、TL1或TH0、TL0装满,再加一个计时脉冲就会“溢出”,TH1 TL1或TH0 TL0会被清除掉,先前放进去的预置值也没有了,这时定时器会使得TCON的TF1或TF0置位为1,通常我们都是把定时器设为中断工作方式,这时会引发定时器中断,单片机会暂停其他程序的处理转而处理中断程序,一般中断程序是很小的,编写时主要是重新充填预置值,以及发出检测信号等,随即结束中断程序还原先前运行的程序。
为了使用定时器中断,还必须在启动定时器(置位TR1或TR0)之前,设置好中断控制寄存器IE。在IE中,只需设置ET0位:T0中断、ET1位:T1中断和EA位:总中断即可。
寄存器设置就这么多,下面按要求,T0定时40毫秒,使用11.0592晶振,按以上算式:
TH0=(*02=0X70;
T1定时4毫秒,晶振相同则
TH1=(*01=0XF1
TL1=(*04=0X9A
实际上编程时这样的常数计算可交由编译器去完成,所以只要列出式子便可。
最后,再说说调校按键的原理:
从原理图上看P1口的P1.2和PI.4分别接有按键K1、K2用来调整小时和分钟,为简单计省去了调秒的按键。
它的工作是:首先PI口输出高电平,按后检查P1.2和P1.4的引脚:如果为高,没有按键,如果为低,有键按下。通常的按键处理,是延时10毫秒再检测电位,目的是避开由于按键未达到稳定状态会因弹跳发生的多次短暂通断。这个例子就是利用数码管扫描的时间来达到延时目的:亮一个数码管后检测按键,如发现按下就计数一次,下一个数码管再捡测,辱国检测5次都是按下则确认为按下,转去把小时或分钟加1。至此,数字钟的基本原理就说完了,下次就看看怎样通过C语言编程把这些功能都组织起来让它有规律地工作,首先我们需要了解程序流程。
好!一个老师!
程序流程是我们编程的依据,按照流程可以理解单片机的工作循环,否则上来就是一堆代码,要看清楚不是很容易的。单片机都是循环工作。主要理解他是怎么循环的,看下图:
bloc.jpg (46.22 KB, 下载次数: 98)
18:06 上传
左边就是主要的工作循环。开机后,首先初始化,给各个变量赋值,其中还有一个自检过程。以及设置定时器并加以启动。
然后进入程序循环。在循环中,单片机要顺序查询显示时间4ms到了没有,到了就要移入下一位数码管显示,移位后再检查40ms定时。否则直接检查40ms定时。如果定时已到,就处理时间累加以及时分秒递增。然后查询按键K1、K2就这样周而复始。而两个定时器在初始化启动后,就进行定时,时间一到就触发定时中断,设置定时标志以供主循环查询,同时还要恢复预置值并进入下一轮定时。
按键检测,先看电平高低,高:无键,低:有键。这里不另设延时,而按照显示移位循环5次后还为低,就是确有按键,转入按键处理。整个流程还是比较简单的,
插个队。顶你一下讲得如此详细。
TH0=(65536-tx*f/6
TL0=(65536-tx*f/6,
a lot simpler than that:
#define F_XTAL ul //xtal for a 12-state 8051
#define MSB(word_t) ((word_t) && 8) //msb of a word
#define LSB(word_t) ((word_t) & 0x00ff) //lsb of&&a word
period=(F_XTAL / ) * //period for the timer
TH0 = MSB(-period);&&//load the msb for a count-up timer
TL0 = LSB(-period);&&//load the lsb for a count-up timer
you will also find that 1) you can improve long-term timing accuracy by a) using auto-reloading (mode 2); or b) using the Roman Black approach - 2) you need to implement a way to correct for xtal inaccuracy.
hope it helps.
怎么不用51单片机的T2定时器?16位自动重载方式定时的误差为0.
Powered by

我要回帖

更多关于 数码管动态显示电路 的文章

 

随机推荐