• 关于51单片机数码管消影


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

    看看原理图:

    百度百科: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/

  • 相关阅读:
    G级别的文本文件分割器FileSpliter
    zabbix5.2.6性能优化001、数据库的优化
    Zabbix 6.0 使用Elasticsearch作为 后端数据库
    zabbix 5.2.6 升级到 6.0.1
    Linux 系统常用命令
    zabbix获取历史告警问题
    Kubernetes1.20.1 下 部署Prometheus+nodeexporter+Grafana+AlertManager 监控系统
    第一天
    zabbix 5.2.6不定时重启, 日志报错 failed to open log file: [24] Too many open files
    CentOS 7.6 部署 elasticsearch kibana 7.9.1
  • 原文地址:https://www.cnblogs.com/yllinux/p/6935590.html
Copyright © 2020-2023  润新知