关于51单片机数码管消影

2018-06-18 04:02:10来源:未知 阅读 ()

新老客户大回馈,云服务器低至5折

自学单片机学到中断部分,用数码管动态显示刷新频率高的时候会有重影,为了消除重影我查找了网上很多资料,好多错的。

看看原理图:

 

百度百科:74HC573    数码管
-----------------------------------------------------------------------------------------------------------
74HC573是拥有八路输出的透明锁存器,输出为三态门,是一种高性能硅栅CMOS器件。
SL74HC573跟LS/AL573的管脚一样。器件的输入是和标准CMOS输出兼容的,加上拉电阻他们能和LS/ALSTTL输出兼容。
-----------------------------------------------------------------------------------------------------------
数码管动态显示接口是将所有数码管的8个显示笔划"a,b,c,d,e,f,g,dp"的同名端连在一起,另外为每个数码管的公共极COM增加位选通控制电路,位选通由各自独立的I/O线控制,当单片机输出字形码时,所有数码管都接收到相同的字形码,但究竟是哪个数码管会显示出字形,取决于单片机对位选通COM端电路的控制,所以我们只要将需要显示的数码管的选通控制打开,该位就显示出字形,没有选通的数码管就不会亮。通过分时轮流控制各个数码管的的COM端,就使各个数码管轮流受控显示,这就是动态驱动。在轮流显示过程中,每位数码管的点亮时间为1~2ms,由于人的视觉暂留现象及发光二极管的余辉效应,尽管实际上各位数码管并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示数据,不会有闪烁感,动态显示的效果和静态显示是一样的,能够节省大量的I/O端口,而且功耗更低。
------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------
由上面可以知道,数码管要显示得位码和段码都分别赋值(赋值前选通控制打开,赋值后选通关闭)才行,位码或段码赋值完成数值立即被锁存,只要不重新给位码或段码赋值则锁存的值不变。(注意,给锁存器赋值的是P0端口,只要不给P0重新赋值,则P0的值也不变)所以:

通常是  (1)清除位码 → (2)给锁存器赋下一位要显示的段码(字形码),开通段选,关闭段选 → (3)给锁存器赋下一位要显示的位码(位置码),开通位选,关闭位选

 1         P0   = 0xff;//消除重影,关闭所有位选
 2     wela = 1;
 3     wela = 0;
 4     P0   = digitron_table[shi];//调用八段数码管代码表
 5     dula = 1;
 6     dula = 0;
 7     P0   = 0xbf;
 8     wela = 1;
 9     wela = 0;
10     delay(1);
11     
12     P0   = 0xff;//消除重影
13     wela = 1;
14     wela = 0;
15     P0   = digitron_table[ge];//调用八段数码管代码表
16     dula = 1;
17     dula = 0;
18     P0   = 0x7f;
19     wela = 1;
20     wela = 0;
21     delay(1);
View Code

也可以  (1)清除段码 → (2)给锁存器赋下一位要显示的位码(位置码),开通位选,关闭位选 → (3)给锁存器赋下一位要显示的段码(字形码),开通段选,关闭段选

 1         P0   = 0x00;//消除重影,关闭段选
 2     dula = 1;
 3     dula = 0;
 4     P0   = 0xbf;
 5     wela = 1;
 6     wela = 0;
 7     P0   = digitron_table[shi];//调用八段数码管代码表
 8     dula = 1;
 9     dula = 0;
10     delay(1);
11     
12     P0   = 0x00;//消除重影
13     dula = 1;
14     dula = 0;
15     P0   = 0x7f;
16     wela = 1;
17     wela = 0;
18     P0   = digitron_table[ge];//调用八段数码管代码表
19     dula = 1;
20     dula = 0;
21     delay(1);
View Code

 

这样,不论多快的刷新频率都不会有重影。

--------------------------------------------------------------------------------------

完整代码:

  1 //使用定时器1中断让8个LED循环右移,间隔500ms,同时使用定时器0中断方式让数码管前2位间隔1000ms从0显示到60,
  2 //如果有外部中断产生则停止数码管走数(外部中断0低电平触发方式)
  3  
  4 #include <reg52.h>
  5 #include <intrins.h>
  6  
  7 //宏定义,方便书写
  8 #define uchar unsigned char
  9 #define uint unsigned int
 10 
 11 sbit dula = P2^6;
 12 sbit wela = P2^7;
 13 uchar counter_s;
 14 
 15 //子函数声明
 16 void interrupt_timer_init();
 17 void display(uchar i);
 18 void delay(uint z);
 19 
 20 //八段数码管代码表
 21 uchar code digitron_table[] = {//LED单元 dp g f e  d c b a 
 22     0x3F,  //"0"  0011 1111
 23     0x06,  //"1"  0000 0110
 24     0x5B,  //"2"  0101 1011    * * * *  a  * * * *
 25     0x4F,  //"3"  0100 1111    *                 *
 26     0x66,  //"4"  0110 0110    *                 *
 27     0x6D,  //"5"  0110 1101    *                 *
 28     0x7D,  //"6"  0111 1101    f                 b
 29     0x07,  //"7"  0000 0111    *                 *
 30     0x7F,  //"8"  0111 1111    *                 *
 31     0x6F,  //"9"  0110 1111    *                 *
 32     0x77,  //"A"  0111 0111    * * * *  g  * * * *
 33     0x7C,  //"B"  0111 1100    *                 *
 34     0x39,  //"C"  0011 1001    *                 *
 35     0x5E,  //"D"  0101 1110    *                 *
 36     0x79,  //"E"  0111 1001    e                 c
 37     0x71,  //"F"  0111 0001    *                 *
 38     0x76,  //"H"  0111 0110    *                 *
 39     0x38,  //"L"  0011 1000    *                 *
 40     0x37,  //"n"  0011 0111    * * * *  d  * * * * * dp * *
 41     0x3E,  //"u"  0011 1110
 42     0x73,  //"P"  0111 0011
 43     0x5C,  //"o"  0101 1100
 44     0x40,  //"-"  0100 0000
 45     0x00,  //熄灭 0000 0000
 46     0x00   //自定义
 47 };
 48 
 49 //主函数部分
 50 void main()
 51 {
 52     interrupt_timer_init();
 53     while (1) {
 54         display(counter_s);
 55 }
 56 }
 57  
 58 //中断服务特殊功能寄存器配置和定时器初始化
 59 void interrupt_timer_init()
 60 {
 61     TMOD = 0x11;//定时方式工作模式0和1,工作模式寄存器TMOD的地址是0x89,不能被8整除,只能对字节操作,不能位操作
 62     TH1  = 0x4c;//公式:定时时间t = (2^16 - T1初值) * 振荡周期 * 12         (振荡周期 * 12 即机器周期)
 63     TH0  = 0x4c;
 64     TL1  = 0x00;//T1 = 2^16 - t * 11059200 / 12         (此定时时间为 50ms, T1 = 19456 = 0x4c00)
 65     TL0  = 0x00;
 66     TR1  = 1;    //定时器运行控制位置1,TCON的地址是0x88,可以对位操作
 67     TR0  = 1;
 68     ET1  = 1; //定时器/计数器T1的溢出中断允许位置1,允许T1中断, 中断允许寄存器IE(A8H)
 69     ET0  = 1;
 70     EX0  = 1;
 71     IT0   = 0;
 72     EA   = 1; //中断允许总控制位置1,CPU开放中断, 中断允许寄存器IE(A8H)
 73     P1 = 0x7f;
 74 } 
 75 
 76 //
 77 void interrupt_program_INT0() interrupt 0 //(1)中断函数无返回值,会破坏栈 (2)不能向ISR传递参数,会破坏栈 (3)ISR应该尽可能的短小精悍 (4)中断函数不能被调用,硬件决定
 78 {
 79     TR0 = 0;
 80 }
 81 
 82 //T1中断服务程序
 83 void interrupt_program_T1() interrupt 3
 84 {
 85     uchar counter;
 86     counter++;
 87     TH1  = 0x4c;
 88     TL1  = 0x00;
 89     if (counter == 10) {    
 90         P1 = _cror_(P1, 1);
 91         counter = 0;
 92     }    
 93 }
 94 
 95 //T0中断服务程序
 96 void interrupt_program_T0() interrupt 1
 97 {
 98     uchar counter_ms;
 99     counter_ms++;
100     TH1  = 0x4c;
101     TL1  = 0x00;
102     if (counter_ms == 20) {        
103         counter_ms = 0;
104         counter_s++;
105         if (counter_s == 60) {
106             counter_s = 0;
107         }
108     }    
109 }
110 
111 //延时函数
112 void delay(uint z)
113 {
114     uint x, y;
115     for (x = 0; x < z; x++)
116         for (y = 0; y < 114; y++);
117 }
118 
119 //数码管显示函数
120 void display(uchar i)
121 {
122      uchar shi,ge;
123     shi = i / 10;//求模
124     ge = i % 10;//求余
125 //实际产品中,(1)关所有位选→(2)输出下一位要显示的段码→(3)开通下一位要显示的位选
126 //其实也可以,(1)关所有段码→(2)开通下一位要显示的位选→(3)输出下一位要显示的段码
127     P0   = 0x00;//消除重影,关闭段选
128     dula = 1;
129     dula = 0;
130     P0   = 0xbf;
131     wela = 1;
132     wela = 0;
133     P0   = digitron_table[shi];//调用八段数码管代码表
134     dula = 1;
135     dula = 0;
136     delay(1);
137     
138     P0   = 0x00;//消除重影
139     dula = 1;
140     dula = 0;
141     P0   = 0x7f;
142     wela = 1;
143     wela = 0;
144     P0   = digitron_table[ge];//调用八段数码管代码表
145     dula = 1;
146     dula = 0;
147     delay(1);
148     
149 /*
150   P0   = 0xff;//消除重影,关闭所有位选
151     wela = 1;
152     wela = 0;
153     P0   = digitron_table[shi];//调用八段数码管代码表
154     dula = 1;
155     dula = 0;
156     P0   = 0xbf;
157     wela = 1;
158     wela = 0;
159     delay(1);
160     
161     P0   = 0xff;//消除重影
162     wela = 1;
163     wela = 0;
164     P0   = digitron_table[ge];//调用八段数码管代码表
165     dula = 1;
166     dula = 0;
167     P0   = 0x7f;
168     wela = 1;
169     wela = 0;
170     delay(1);
171 */
172 }
View Code

 

 

如有错误还请指出,如有侵权还请告知,如需转载请注明出处!                                              

本人博客:http://www.cnblogs.com/yllinux/

 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:死锁和活锁

下一篇:P1290 欧几里德的游戏