精华内容
下载资源
问答
  • 数码管动态扫描显示 象棋小子 1048272975 数码管由于发光亮度强,指示效果好,非常适合于电梯楼层等数值显示应用中。对于一位数码管,可以采用静态显示,但实际应用中都是需要显示多位数值,数码管模块也只能动态...

    51单片机开发系列三

    数码管动态扫描显示

    象棋小子    1048272975

    数码管由于发光亮度强,指示效果好,非常适合于电梯楼层等数值显示应用中。对于一位数码管,可以采用静态显示,但实际应用中都是需要显示多位数值,数码管模块也只能动态显示,因此笔者在这里简单分析一下数码管动态扫描驱动的实现。

    1. 数码管原理概述

    数码管由多个发光二极管封装在一起组成“8”字型的器件,引线已在内部连接完成,只引出它们的各个笔划,公共电极。数码管实际上是由七个发光管组成8字形构成的,加上小数点就是8个。这些段分别由字母a,b,c,d,e,f,g,dp来表示。数码管根据内部接法又可分成共阳极数码管和共阴极数码管。共阳数码管是指将所有发光二极管的阳极接到一起形成公共阳极(COM)的数码管(如下图SM*10501),共阴数码管是指将所有发光二极管的阴极接到一起形成公共阴极(COM)的数码管如下图(SM*20501)。以共阳数码管为例,要想显示数字2,需把A、B、G、E、D段点亮,即公共端接上正电源,ABGED段阴极拉低,其余段拉高即可显示数字2。


    2. 硬件设计

    笔者此处以四位一体共阳数码管显示为例讲解其大概的硬件设计。

    微控制器的IO口均不能流过过大的电流,LED点亮时有约10ms的电流,因此数码管的段码输出不要直接接单片机IO口,应先经过一个缓冲器74HC573。单片机IO口只需很小的电流控制74HC573即可间接的控制数码管段的显示,而74HC573输出也能负载约10ms的电流。设置数码管段的驱动电流为ID=15ma,这个电流点亮度好,并且有一定的裕度,即使电源输出电压偏高也不会烧毁LED,限流电阻值

    R = (VCC- VCE – VOL – VLED) / ID

    VCC为5v供电,VCE为三极管C、E间饱和电压,估为0.2v, VOL为74hc573输出低电平时电压,不同灌电流,此值不一样,估为0.2v,具体查看规格书,VLED为红光驱动电压,估为1.7v,根据上式可算出限流电阻为R = 200R。

    数码管需接收逐个扫描信号,扫描到相应数码管时,对应的段码数据有效,即显示这个数码管的数值。笔者采用三线八线译码器74HC138来产生对应的扫描线信号。

    当各个段码均点亮时,电流约15max8=90ma流过数码管公共端,74HC138无法直接驱动这个电流,需加三极管驱动,由于74HC138输出低电平有效,此处只有PNP三极管适合作为驱动。三极管基极电流设为2ma即可让三极管饱和,最大驱动电流远大于90ma。基极偏置电阻阻值

    Rb =(VCC - VEB – VOL) / IB

    VCC为5v供电,VEB为三极管E、B间的导通电压0.7v,VOL为74hc138输出低电平时电压,可根据规格书估为0.3v,故Rb = 2k即可。


    图2-1 四位一体数码管原理图

    3. 驱动实现

    数码管段码接P0口,位码接P2口第0~2位。对于LED显示器都是有一个刷新频率的,同样对于数码码动态扫描也需要一个扫描频率。扫描频率下限为50HZ,低于一定的扫描频率,显示会闪烁。频率过高,则亮度较差且占用cpu资源。一般整个数码管扫描一遍时间为约10ms较合适(即扫描频率100HZ),我们用的是四位数码管,每个数码管点亮时间为2ms,扫描一遍时间为8ms。为保证这个刷新频率,通过是通过定时器来周期性进行数码管刷新。笔者在此以四位一体数码管实现秒表计数显示为例来作代码开发。

    数码管动态显示功能实现模块文件DigitalTubeTable.c内容如下:

     

    #include "reg52.h"

    #include"DigitalTube.h"

     

    // 数值相对应的段码,共阳极

    static unsigned char codeDigitalTubeTable[12]= { // 共阳LED段码表

    0xc0, 0xf9, 0xa4, 0xb0, 0x99,0x92, 0x82, 0xf8, 0x80, 0x90, 0xff, 0xbf

    //"0"  "1"   "2"   "3"   "4"   "5"   "6"   "7"   "8"   "9" "不亮"  "-"

    };

     

    // 每个数码管需一个字节的内存保存对应数码管数据            

    static unsigned charFrameBuffer[DigitalTubeNumber];

     

    unsigned char*DigitalTube_GetBuffer()

    {

           return FrameBuffer;

    }

     

    void DigitalTube_Scan()

    {

           static unsigned char Select = 0; // 记录扫描的选择线

           unsigned char Code;

           // 从对应选择线中找到显存数据,并得到相应的段码

           Code = DigitalTubeTable[FrameBuffer[Select]];

           // 段码实际输出到数码管接口

           DigitalTube_Data(Code);

           // 位选实际输出到数码管接口

           DigitalTube_Select(Select);

           Select++; // 进入到下一位选扫描

           if (Select >= DigitalTubeNumber) {

                 Select = 0;    // 所有数码管已扫描,从第一个数码管再次开始扫描

           }

    }

     

    我们在数码管模块头文件DigitalTube.h中实现模块的接口访问宏实现,使之方便移植及修改接口配置。模块头文件同时也引出模块的接口函数,void DigitalTube_Scan(void)为数码管刷新函数,需周期性调用刷新数码管显示。unsigned char *DigitalTube_GetBuffer(void)用来获得数码管显存,从而更新数码管显存数据。其内容如下:

     

    #ifndef __DigitalTube_H__

    #define __DigitalTube_H__

     

    #ifdef __cplusplus

    extern "C" {

    #endif

     

    // 数码管模块中的个数,最大为8

    #define DigitalTubeNumber      4

     

    // 输出数码管位选

    #defineDigitalTube_Select(Select) {P2 = (P2&0xf8) + (Select);}

    // 输出数码管段码

    #define DigitalTube_Data(Dat)     {P0 =(Dat);}

     

    // 数码管刷新函数,必须保证以一定周期调用刷新

    void DigitalTube_Scan(void);

    // 获得数码管显存,以作显示的数据更新

    unsigned char*DigitalTube_GetBuffer(void);

     

    #ifdef __cplusplus

    }

    #endif

     

    #endif /*__DigitalTube_H__*/

     

    外部模块通过引入数码管的模块头文件DigitalTube.h来实现调用数码管驱动函数,简单测试调用(秒表数码管显示计数)实现如下:

     

    #include"reg52.h"

    #include"DigitalTube.h"

     

    // 以定时器时间为计时标准,记录时间间隔

    static volatile unsignedint SystemTick = 0;

     

    // 定时器2ms中断处理进行数码管刷新

    void T0_Interrupt()interrupt 1

    {

           TH0 = (65536-2000) / 256;

           TL0 = (65536-2000) % 256;

           SystemTick++; // 记录时间间隔

           DigitalTube_Scan();     //刷新数码管

    }

     

    void T0_Init()

    {

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

           // 2ms计时中断(12M)

           TH0 = (65536-2000) / 256;

           TL0 = (65536-2000) % 256;

           ET0 = 1; // 定时器T0中断允许

           EA = 1; // 总中断允许

    }

     

    void main()

    {

           unsigned char *pBuffer;

           unsigned char i;

           // 定时器初始化

           T0_Init();

           // 获得数码管显存,以作更新数据显示

           pBuffer = DigitalTube_GetBuffer();

           // 数据管显存初始化显示0

           for (i=0; i<DigitalTubeNumber; i++) {

                  pBuffer[i] = 0;

           }

           // 开启定时器进行计时以及数码管刷新

           TR0 = 1;

     

           while(1) {

                  // SystemTick读数到500时为1s间隔到

                  if (SystemTick > 500) {

                         SystemTick =0; // 重新计秒

                         // 更新数码管秒表计数显存     

                         for (i=0; i<DigitalTubeNumber; i++) {

                                pBuffer[DigitalTubeNumber-1-i]++;

                                if (pBuffer[DigitalTubeNumber-1-i] <10) {

                                       break; // 未到10,不用进位更新高位显存,退出

                                } else {

                                       // 到10,这一位清0,并继续循环更新高位显存

                                       pBuffer[DigitalTubeNumber-1-i] =0;

                                }

                         }                         

                  }                         

           }

    }

    附录:

    此章节的Keil工程,包含源码,Preteus仿真,包含仿真电路,可直接查看效果,DigitalTube.rar。

    http://pan.baidu.com/s/19wRr4

     

    展开全文
  • 动态扫描LED显示电路编程范例

    千次阅读 2008-01-17 16:07:00
    2006-05-11 09:32:16 51单片机编程范例(动态扫描LED显示电路编程范例) 上一节我们讲述了单只LED与单片机接口电路及编程实例,目的在于让初学者了解LED在单片机中应用原理,单只LED显示实际应用中并...
    2006-05-11 09:32:16

    字体变小字体变大
    51单片机编程范例(动态扫描LED显示电路编程范例)
    上一节我们讲述了单只LED与单片机的接口电路及编程实例,目的在于让初学者了解LED在单片机中的应用原理,单只LED显示在实际应用中并无多大用途,一般都是多位的LED显示。现在我们作进一步学习,我们要讲解的是8位LED的显示原理及实际的编程方法。这里我们没有采用多I/O口的8051系列单片机,而是采用了完全兼容C51指令系统的质优价廉的AT89C2051单片机,它的软件编程与C51完全一致。
    在多数的应用场合中,我们并不希望使用多I/O端口的单片机,原则上是使用尽量少引脚的器件。在没有富余端口的情况下,怎样通过扩展电路达到预期的目的呢?我们希望通过此例使设计人员在实际应用中了解一点电路扩展的原理,对实际的应用有所帮助。

    左图是显示电路,由于AT89C2051外部15个I/O引脚,即P1口和P3口,单P3口的P3.6是不引出的,15个I/O口要直接驱动8位LED显然是不够的,我们通过一片面74LS273对地址进行锁存,如果P1口仅用于显示驱动,而没有与其它外设进行数据交换,可省略这个锁存器,直接或通过其他驱动电路驱动连接LED。地址线我们通过一片74LS138三—八译码器对8位LED进行分时选通,这样在任一时刻,只有一位LED是点亮的,但只要扫描的频率足够高(一般大于25Hz),由于人眼的视觉暂留特性,直观上感觉却是连续点亮的,这就是我们常说的动态扫描电路。
    0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" height=250 alt="" hspace=5 src="http://data.willar.com/upload/article/2004105103427877.gif" width=370 vspace=5 border=0 dypop="8位LED显示电路">
    此电路中,74LS273用于驱动LED的8位段码,8位LED相应的"a"—"g"段连在一起,它们的公共端分别连至由74LS138(点击芯片型号可浏览其详细的技术手册)译码选通后经74LS04反相驱动的输出端。这样当选通某一位LED时,相应的地址线(74LS04输出端)输出的是高电平,所以我们的LED选用共阳LED数码管。
    动态扫描的频率有一定的要求,频率太低,LED将出现闪烁现象。如频率太高,由于每个LED点亮的时间太短,LED的亮度太低,肉眼无法看清,所以一般均取几个ms左右为宜,这就要求在编写程序时,选通某一位LED使其点亮并保持一定的时间,程序上常采用的是调用延时子程序。在C51指令中,延时子程序是相当简单的,并且延时时间也很容易更改,可参见程序清单中的DELAY延时子程序。
    为简单起见,我们只是编写了8位LED同步显示"00000000"—"11111111"直到"99999999"数字,并且反复循环。程序很简单,流程图略去。

    · 程序清单:
    0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" height=349 hspace=5 src="http://data.willar.com/upload/article/2004105103428142.gif" width=303 border=0>
    展开全文
  • 数码管动态扫描

    2017-12-10 11:34:35
    每位数码管的点亮时间为1~2ms,由于人的视觉暂留现象及发光二极管的余辉效应,尽管实际上各位数码管并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示数据,不会有闪烁感,动态显示的效果和静态...
  • 对于一位数码管,可以采用静态显示,但实际应用中都是需要显示多位数值,数码管模块也只能动态显示,因此笔者在这里简单分析一下数码管动态扫描驱动实现。 1. 数码管原理概述 数码管由多个发光二极管封装在一起...
  •  在单片机系统中动态扫描显示接口是单片机中应用最为广泛一种显示方式之一。其接口电路是把所有显示器8个笔划段a-h同名端连在一起,而每一个显示器公共极COM是各自独立地受I/O线控制。CPU向字段输出口送出...
  •  在单片机系统中动态扫描显示接口是单片机中应用为广泛一种显示方式之一。其接口电路是把所有显示器8个笔划段a-h同名端连在一起,而每一个显示器公共极COM是各自独立地受I/O线控制。CPU向字段输出口送出字形...
  • 它以其色彩鲜艳,动态范围广,亮度高,寿命长,工作稳定可靠等优点而成为众多显示媒体以及户外作业显示的理想选择。同时也可广泛应用到军事、车站、宾馆、体育、新闻、金融、证券、广告以及交通运输等许多行业。  ...
  • 它以其色彩鲜艳,动态范围广,亮度高,寿命长,工作稳定可靠等优点而成为众多显示媒体以及户外作业显示的理想选择。同时也可广泛应用到军事、车站、宾馆、体育、新闻、金融、证券、广告以及交通运输等许多行业。  ...
  • 它以其色彩鲜艳,动态范围广,亮度高,寿命长,工作稳定可靠等优点而成为众多显示媒体以及户外作业显示的理想选择。同时也可广泛应用到军事、车站、宾馆、体育、新闻、金融、证券、广告以及交通运输等许多行业。  ...
  • C51单片机数码管动态显示

    万次阅读 多人点赞 2018-08-27 21:49:25
    数码管作为最廉价的输出设备,在各种自动化设备中有很大的应用,最简单普通的显示方式为动态刷新显示,称为假动态显示,即通过分时扫描每一位,利于人眼的视觉停留现象,造成一种静态显示的效果,如下图所示: ...

    数码管作为最廉价的输出设备,在各种自动化设备中有很大的应用,最简单普通的显示方式为动态刷新显示,称为假动态显示,即通过分时扫描每一位,利于人眼的视觉停留现象,造成一种静态显示的效果,如下图所示:

    C51单片机由于运行速度很慢,在高刷新频率下,单片机的资源耗费很厉害,这样单片机就不可以再进行大量的计算工作,实际上,单片机在刷新时,只需要周期性的改变GPIO口的状态就可以了,剩下的时间其实都是在空转的状态下,我们能不能将这个空转的状态拿来用呢?当然是可以的啦,这里,我们利用单片机的定时器周期地产能中断,在中断内进行数码管的刷新工作,就可以将等待中断的这个CPU时间拿来做别的事情了。

    硬件电路:

    代码贴过来:

    主函数

    #include "shumaguan.h"
    #include "timer.h"
    
    
    sbit sw_jdq=P1^0;//定义一位继电器操作
    void main(void)
    {
      int cnt=0;//设定初值
      timer_init();//初始化定时器
      while(1)
      {
        value_now = cnt;//送初值到显示缓存
        delay(50);
        cnt++;
        sw_jdq=~sw_jdq;//切换继电器状态
        if(cnt>9999)//数值超出界线,回归最小
          cnt=-999;
      }
    }

    数码管驱动函数

    #include "shumaguan.h"
    
    #define DType	1			//define the Digital LED type, 1: VCC in common, 0: GND in common
    #if DType==1
    /*--------------------------------------------------------
    Set the digital LED display code 
    From left to right for
    0,1,2,3,4,5,6,7,8,9,a.b,c,d,e,f,dp,-, 
    --------------------------------------------------------*/
    uchar code DS_BUF[]={0xc0 , 0xf9 , 0xa4 , 0xb0 , 0x99 , 0x92 , 0x82 , 0xf8 , 0x80 , 0x90 , 0x88 , 
    0x83 , 0xc6 , 0xa1 , 0x86 , 0x8e , 0x7f , 0xbf , 0xff };
    #else
    uchar code DS_BUF[]={0x3f , 0x06 , 0x5b , 0x4f , 0x66 , 0x6b , 0x7d , 0x07 , 0x7f , 0x6f , 0x77 , 
    0x7c , 0x39 , 0x5e , 0x79 , 0x71 , 0x80 , 0x40 , 0x00 };
    #endif
    uchar xdata buf_sm[4];            //set display buffer
      
    uchar frash_cnt=0;//刷新计数器
    uchar wei_buf=0x10;//位输出计数器
     
    /*--------------------------
    Compute the number from Value
    value: something to display, range from -999 to 9999, suport float
    --------------------------*/
    void calc_sm(float value)
    {
    	uint tmp=0;
    	if(value>=0)//输入值为正数,不显示负号
    	{
    		if(value>9999)//输入值大于9999,显示----
    		{
    			buf_sm[0]=17;
    			buf_sm[1]=17;
    			buf_sm[2]=17;
    			buf_sm[3]=17;
    		}
    		else if(value>=1000)//输入值大于999,只显示整数
    		{
    			tmp=value;
    			buf_sm[0]=tmp/1000;
    			buf_sm[1]=tmp%1000/100;
    			buf_sm[2]=tmp%100/10;
    			buf_sm[3]=tmp%10;
    		}
    		else if(value>=100)//显示一位小数
    		{
    			tmp=value*10;
    			buf_sm[0]=tmp/1000;
    			buf_sm[1]=tmp%1000/100;
    			buf_sm[2]=(tmp%100/10)+20;
    			buf_sm[3]=tmp%10;
    		}
    		else if(value>=10)//显示两位小数
    		{
    			tmp=value*100;
    			buf_sm[0]=tmp/1000;
    			buf_sm[1]=(tmp%1000/100)+20;
    			buf_sm[2]=tmp%100/10;
    			buf_sm[3]=tmp%10;
    		}
    		else//显示三位小数
    		{
    			tmp=value*1000;
    			buf_sm[0]=(tmp/1000)+20;
    			buf_sm[1]=tmp%1000/100;
    			buf_sm[2]=tmp%100/10;
    			buf_sm[3]=tmp%10;
    		}
    	}
    	else//输入值小于0,显示负号,其余同上
    	{
    		if((value<0)&&(value>-10))
    		{
    			tmp=value*100;
    			tmp=abs(tmp);
    			buf_sm[0]=17;
    			buf_sm[1]=(tmp/100)+20;
    			buf_sm[2]=tmp%100/10;
    			buf_sm[3]=tmp%10;
    		}
    		else if((value<=-10)&&(value>-100))
    		{
    			tmp=value*10;
    			tmp=abs(tmp);
    			buf_sm[0]=17;
    			buf_sm[1]=(tmp/100);
    			buf_sm[2]=tmp%100/10+20;
    			buf_sm[3]=tmp%10;
    		}
    		else if((value<=-100)&&(value>-1000))
    		{
    			tmp=value;
    			tmp=abs(tmp);
    			buf_sm[0]=17;
    			buf_sm[1]=(tmp/100);
    			buf_sm[2]=tmp%100/10;
    			buf_sm[3]=tmp%10;
    		}
        
    	}
      
    }
    /*
    显示部分,每执行一次,显示的位左移一位,移到最左边时,重新回到最右边,开始下一次刷新。
    定义有小数点的位+20,每次送断码,检查大于20,段与0x7f添加小数点。
    */
    void display()
    {
      if(frash_cnt<=3)
      {
        wei |=0xf0;//数码管的消隐
        
        if(buf_sm[3-frash_cnt]>=20)
        {
          duan = (DS_BUF[(buf_sm[3-frash_cnt])-20]&0x7f);//显示小数点
        }
        else
          duan = DS_BUF[buf_sm[3-frash_cnt]];//不显示小数点
        
        wei = ~wei_buf;
        wei_buf <<=1;//显示位左移一位
        frash_cnt++;
      }
      else
      {
        wei |=0xf0;//数码管的消隐
        frash_cnt=0;
        wei_buf=0x10;//显示位回到最右边
      }
    }
    /*
    数码管自用延时
    */
    void delay(uint i)
    {
      uchar j;
      for(;i>0;i--)
      for(j=0;j<120;j++);
    
    }
    

    数码管头文件

    #ifndef _shumaguan_h_
    #define _shumaguan_h_
    #include "math.h"
    #include "reg52.h"
    #define duan P0
    #define wei P2
    
    #define uchar unsigned char
    #define uint unsigned int
      
    extern uchar frash_cnt;
    extern uchar wei_buf;
    
    void calc_sm(float value);
    void display();
    void delay(uint i);
    
    
    #endif
    

    定时器配置及中断服务函数

    #include "reg52.h"
    #include "timer.h"
    #include "shumaguan.h"
    
    
    float xdata value=0 , value_now = 0;
    
    void timer_init()
    {
      TMOD = 0x02;                    //set timer0 as mode1 (16-bit)
      TL0 = T1MS;                     //initial timer0 low byte
      TH0 = T1MS;                //initial timer0 high byte
      TR0 = 1;                        //timer0 start running
      ET0 = 1;                        //enable timer0 interrupt
      EA = 1;                         //open global interrupt switch
    }
    
    
    
    /* Timer0 interrupt routine */
    void tm0_isr() interrupt 1 using 1
    {
        if(value!=value_now)//检测显示值与当前值是否匹配
        {
          value=value_now;//刷新显示值
          calc_sm(value_now);//重新计算显示值的输出缓冲区
        }
        display();//刷新数码管显示
    
    }
    

    定时器头文件

    #ifndef _timer_h_
    #define _timer_h_
    #include "reg52.h"
    #define uchar unsigned char
    #define uint unsigned int
      
    //-----------------------------------------------
    
    /* define constants */
    //#define FOSC 11059200L
    #define FOSC 12000000L
    
    #define T1MS 0   //1ms timer calculation method in 12T mode
    
    
    //-----------------------------------------------
    
    extern float xdata value , value_now;
    
    
    void timer_init();
    
    
    #endif
    

     

    展开全文
  • 电子显示屏中LPC2131微控制器依据人视觉瞬时特性,以动态扫描数码管的显示方式降低显示功耗,满足了本质安全型电源远距离带载要求。该电子显示屏通过实际应用表明,能满足在复杂环境条件下各种数据信息就地显示...
  • 强大的扫描工具x-scan

    2009-11-13 23:17:02
    Q:为什么在一次扫描中我选择了“SYN”方式进行端口扫描,但X-Scan实际采用是“TCP”方式, 而且也没有被动识别出目标操作系统? A:端口扫描“SYN”方式在NT4或XP+SP2系统下无法使用,在windows 2000等...
  • 摘要:本文介绍了LED显示屏在交通上的应用,详细介绍了基于双CPU和双口RAMLED动态显示设计方法,显示屏三种颜色控制,以及扫描驱动电路实现,最后给出了VB6.0下提取汉字点阵方法。实际运行表明此方法非常...
  • 本文设计了一套16*64点阵数字时钟显示系统,该系统是一种基于AT89S52单片机为核心低成本、微型化数字显示系统,它根据人眼视觉暂留原理, 以DS12887为时钟芯片, 应用单片机技术和动态扫描技术来显示时间日期等信息...
  • 本文设计了一套16*64点阵数字时钟显示系统,该系统是一种基于AT89S52单片机为核心低成本、微型化数字显示系统,它根据人眼视觉暂留原理, 以DS12887为时钟芯片, 应用单片机技术和动态扫描技术来显示时间日期等信息...
  • 写在前面正文七段数码管原理七段数码管译码表单个七段数码管显示verilog设计多个数码管动态扫描显示参考资料交个朋友写在前面作为FPGA的基础知识教程怎么能少得了这个简单的实际应用七段数码管显示,本篇博文算得上...
    • 写在前面

    • 正文

      • 七段数码管原理

      • 七段数码管译码表

      • 单个七段数码管显示verilog设计

      • 多个数码管动态扫描显示

    • 参考资料

    • 交个朋友


    写在前面

    作为FPGA的基础知识教程怎么能少得了这个简单的实际应用七段数码管显示,本篇博文算得上是对以往这个话题的一个总结吧!注:数码管本身是七段,但是加上小数点之后就是八段了!


    正文

    七段数码管原理

    七段显示器是FPGA设计人员通常用来向用户显示信息的指示器。在VHDL和Verilog中可以轻松完成将二进制文件转换为兼容七段显示器的代码。有许多应用程序可能需要使用一个或多个八段显示器,例如:

    • 闹钟
    • 秒表
    • 按钮计数指示器
    • 电压测量(从模拟到数字转换器)

    等等!

    如下是七段数码管的示意图:我们将七段分别标记为A、B、C、D、E、F、G,还有一个小数点DP。

    0403107b8ac00462f0c979e70a6ad3a1.png
    七段数码管并带有小数点

    如果用reg型变量来存七段数码管的位值,定义reg型变量:

    reg [6:0] seg;

    其中G对应seg[6],F对应seg[5],一直到A对应seg[0],小数点用专门的dp来表示。

    七段数码管译码表

    那么要想显示0到F,对应的译码表为:

    parameter   NUM0     = 7'h3f,//40,
                NUM1     = 7'h06,//79,
                NUM2     = 7'h5b,//24,
                NUM3     = 7'h4f,//30,
                NUM4     = 7'h66,//19,
                NUM5     = 7'h6d,//12,
                NUM6     = 7'h7d,//02,
                NUM7     = 7'h07,//78,
                NUM8     = 7'h7f,//20,
                NUM9     = 7'h6f,//10,
                NUMA     = 7'h77,//08,
                NUMB     = 7'h7c,//03,
                NUMC     = 7'h39,//46,
                NUMD     = 7'h5e,//21,
                NUME     = 7'h79,//06,
                NUMF     = 7'h71,//0e;

    注意,前面部分为共阴极时的译码表,后面注释掉的为共阳极的译码表!所谓的共阳极,如下原理图所示:

    93585cfe3fcee27a160059ff43b57cfe.png
    共阳极数码管

    晶体管的集电极连接电源,片选低电平有效,片选选中时,晶体管导通,数码管公共端连接高电平,因此段选低电平,对应段发亮。

    单个七段数码管显示verilog设计

    以共阴极为例,对单个数码管显示的Verilog设计为:

    module Binary_To_7Segment 
      (
       input       i_Clk,
       input [3:0] i_Binary_Num,
       input     i_dp, //小数点输入
       output      o_Segment_A,
       output      o_Segment_B,
       output      o_Segment_C,
       output      o_Segment_D,
       output      o_Segment_E,
       output      o_Segment_F,
       output      o_Segment_G,
       output      o_dp
       );
     
      reg [6:0]    r_Hex_Encoding = 7'h00;
       
      // Purpose: Creates a case statement for all possible input binary numbers.
      // Drives r_Hex_Encoding appropriately for each input combination.
      always @(posedge i_Clk)
        begin
          case (i_Binary_Num)
            4'b0000 : r_Hex_Encoding <= 7'h3f;
            4'b0001 : r_Hex_Encoding <= 7'h06;
            4'b0010 : r_Hex_Encoding <= 7'h5b;
            4'b0011 : r_Hex_Encoding <= 7'h4f;
            4'b0100 : r_Hex_Encoding <= 7'h66;          
            4'b0101 : r_Hex_Encoding <= 7'h6d;
            4'b0110 : r_Hex_Encoding <= 7'h7d;
            4'b0111 : r_Hex_Encoding <= 7'h07;
            4'b1000 : r_Hex_Encoding <= 7'h7f;
            4'b1001 : r_Hex_Encoding <= 7'h6f;
            4'b1010 : r_Hex_Encoding <= 7'h77;
            4'b1011 : r_Hex_Encoding <= 7'h7c;
            4'b1100 : r_Hex_Encoding <= 7'h39;
            4'b1101 : r_Hex_Encoding <= 7'h5e;
            4'b1110 : r_Hex_Encoding <= 7'h79;
            4'b1111 : r_Hex_Encoding <= 7'h71;
          endcase
        end // always @ (posedge i_Clk)
     
      // r_Hex_Encoding[7] is unused
      assign o_Segment_A = r_Hex_Encoding[0];
      assign o_Segment_B = r_Hex_Encoding[1];
      assign o_Segment_C = r_Hex_Encoding[2];
      assign o_Segment_D = r_Hex_Encoding[3];
      assign o_Segment_E = r_Hex_Encoding[4];
      assign o_Segment_F = r_Hex_Encoding[5];
      assign o_Segment_G = r_Hex_Encoding[6];
      assign o_dp = i_dp;
     
    endmodule // Binary_To_7Segment

    多个数码管动态扫描显示

    用一句话来描述多个数码管动态扫描显示,那就是,只要你闪的够快,你就看不出我灭过!动态扫描显示就是如此,数码管的动态显示是对每个数码管采用分时复用的方式轮流点亮每个数码管,在同一时间只会点亮一个数码管。分时复用的扫描显示利用了人眼的视觉暂留特性,如果公共端的控制信号刷新速度足够快,人眼就不会区分出LED的闪烁,认为4个数码管是同时点亮。

    如下图是多个数码管连接的原理图:

    93585cfe3fcee27a160059ff43b57cfe.png
    数码管原理图

    片选控制信号的刷新速度必须足够快才能避免闪烁感,但也不能太快,以免影响数码管的开关切换,最佳的工作频率为1000Hz左右。如果FPGA的时钟为50MHz,那么至少跑5*10^4个周期,也即50000个周期刷新一次才行,我们知道2^16=65536,2^15=32768。我们选择计数器位宽为16试试!注:效果可以实际上板子测试决定,由于现在开发板不在手上,暂时并未验证怎么样!

    代码中采用的是18位2进制数,高2位控制片选,低16位计数满一次,进位一次,高两位的变化时00——01——10——11——00——...,分别选中数码管的其中之一,使用case语句即可完成这个功能。下面代码中的hex0、hex1、hex2、hex3是输入信号,用来控制数码管显示的数字,dp_in用来控制小数点的亮灭。

    `timescale 1ns / 1ps
    module scan_led_hex_disp(
        input clk,
        input reset,
        input [3:0] hex0, //第一个数码管显示的数字
        input [3:0] hex1,
        input [3:0] hex2,
        input [3:0] hex3,
        input [3:0] dp_in, //小数点控制
        output reg [3:0] an,   //片选
        output reg [7:0] sseg  //段选
        );
     
     localparam N = 18//使用低16位对50Mhz的时钟进行分频(50MHZ/2^16)
     reg [N-1:0] regN; //高两位作为控制信号,低16位为计数器,对时钟进行分频
     reg [3:0] hex_in; //段选控制信号
     reg dp; 
     
     always@(posedge clk, posedge reset)
     begin
      if(reset)
       regN <= 0;
      else
       regN <= regN + 1;
     end
     
     always@ *
     begin
      case(regN[N-1:N-2])
      2'b00:begin
       an = 4'b1110//选中第1个数码管
       hex_in = hex0; //数码管显示的数字由hex_in控制,显示hex0输入的数字;
       dp = dp_in[0]; //控制该数码管的小数点的亮灭
      end
      2'b01:begin
       an = 4'b1101//选中第二个数码管
       hex_in = hex1;
       dp = dp_in[1];
      end
      2'b10:begin
       an = 4'b1011;
       hex_in = hex2;
       dp = dp_in[2];
      end
      default:begin
       an = 4'b0111;
       hex_in = hex3;
       dp = dp_in[3];
      end
      
      endcase
     
     end
     always@ *
     begin
      case(hex_in)
       4'h0: sseg[6:0] = 7'b0000001//共阳极数码管
       4'h1: sseg[6:0] = 7'b1001111;
       4'h2: sseg[6:0] = 7'b0010010;
       4'h3: sseg[6:0] = 7'b0000110;
       4'h4: sseg[6:0] = 7'b1001100;
       4'h5: sseg[6:0] = 7'b0100100;
       4'h6: sseg[6:0] = 7'b0100000;
       4'h7: sseg[6:0] = 7'b0001111;
       4'h8: sseg[6:0] = 7'b0000010;
       4'h9: sseg[6:0] = 7'b0000100;
       4'ha: sseg[6:0] = 7'b0001000;
       4'hb: sseg[6:0] = 7'b1100000;
       4'hc: sseg[6:0] = 7'b0110001
       4'hd: sseg[6:0] = 7'b1000010;
       4'he: sseg[6:0] = 7'b0110000;
       default: sseg[6:0] = 7'b0111000;
      endcase
      sseg[7] = dp;
     end
    endmodule

    根据上一小节,单个数码管显示的Verilog设计,最后一段译码模块可以使用时序逻辑,也就是代码可以改为:

    `timescale 1ns / 1ps
    module scan_led_hex_disp(
        input clk,
        input reset,
        input [3:0] hex0, //第一个数码管显示的数字
        input [3:0] hex1,
        input [3:0] hex2,
        input [3:0] hex3,
        input [3:0] dp_in, //小数点控制
        output reg [3:0] an,   //片选
        output reg [7:0] sseg  //段选
        );
     
     localparam N = 18//使用低16位对50Mhz的时钟进行分频(50MHZ/2^16)
     reg [N-1:0] regN; //高两位作为控制信号,低16位为计数器,对时钟进行分频
     reg [3:0] hex_in; //段选控制信号
     reg dp; 
     
     always@(posedge clk, posedge reset)
     begin
      if(reset)
       regN <= 0;
      else
       regN <= regN + 1;
     end
     
     always@ *
     begin
      case(regN[N-1:N-2])
      2'b00:begin
       an = 4'b1110//选中第1个数码管
       hex_in = hex0; //数码管显示的数字由hex_in控制,显示hex0输入的数字;
       dp = dp_in[0]; //控制该数码管的小数点的亮灭
      end
      2'b01:begin
       an = 4'b1101//选中第二个数码管
       hex_in = hex1;
       dp = dp_in[1];
      end
      2'b10:begin
       an = 4'b1011;
       hex_in = hex2;
       dp = dp_in[2];
      end
      default:begin
       an = 4'b0111;
       hex_in = hex3;
       dp = dp_in[3];
      end
      
      endcase
     
     end
     always@(posedge clk)
     begin
      case(hex_in)
       4'h0: sseg[6:0] = 7'b0000001//共阳极数码管
       4'h1: sseg[6:0] = 7'b1001111;
       4'h2: sseg[6:0] = 7'b0010010;
       4'h3: sseg[6:0] = 7'b0000110;
       4'h4: sseg[6:0] = 7'b1001100;
       4'h5: sseg[6:0] = 7'b0100100;
       4'h6: sseg[6:0] = 7'b0100000;
       4'h7: sseg[6:0] = 7'b0001111;
       4'h8: sseg[6:0] = 7'b0000010;
       4'h9: sseg[6:0] = 7'b0000100;
       4'ha: sseg[6:0] = 7'b0001000;
       4'hb: sseg[6:0] = 7'b1100000;
       4'hc: sseg[6:0] = 7'b0110001
       4'hd: sseg[6:0] = 7'b1000010;
       4'he: sseg[6:0] = 7'b0110000;
       default: sseg[6:0] = 7'b0111000;
      endcase
      sseg[7] = dp;
     end
    endmodule

    注:由于代码都是根据过去的博客以及参考资料移植,导致命名方式没有统一,请注意;还有多个数码管显示时,数码管是共阳极的数码管,而单个数码管显示那一节,也就是上一节,使用的数码管是共阴极为例,因此,数码管译码部分数值不同,请注意!


    参考资料

    • 参考资料1[1]
    • 参考资料2[2]
    • 参考资料3[3]
    • 参考资料4[4]
    • 参考资料5[5]
    • 参考资料6[6]

    交个朋友

    • 个人微信公众号:FPGA LAB

    • 知乎:李锐博恩

    • FPGA/IC技术交流2020[7]

    参考资料

    [1]

    参考资料1: http://suo.im/6oLVv2

    [2]

    参考资料2: http://suo.im/5NQSgl

    [3]

    参考资料3: http://suo.im/6oLVq2

    [4]

    参考资料4: https://blog.csdn.net/Reborn_Lee

    [5]

    参考资料5: https://www.nandland.com/vhdl/modules/binary-to-7-segment.html

    [6]

    参考资料6: https://en.wikipedia.org/wiki/Seven-segment_display

    [7]

    FPGA/IC技术交流2020: https://blog.csdn.net/Reborn_Lee/article/details/105844330

    展开全文
  • 基本指针应用 4.1 指针到底有什么好处? 4.2 我想声明一个指针并为它分配一些空间,但却不行。这些代码有什么问题呢?char *p; *p =malloc(10); 4.3 *p++自增p还是p所指向变量? 指针操作 4.4 我用指针操作int...
  • x-scan3.3扫描工具

    2009-05-10 08:35:14
    Q:为什么在一次扫描中我选择了“SYN”方式进行端口扫描,但X-Scan实际采用是“TCP”方式,而且也没有被动识别出目标操作系统? A:端口扫描“SYN”方式在NT4或XP+SP2系统下无法使用,在windows 2000等系统...
  • 几何化 计算几何研究对象是几个图形。早期人们对于图像研究一般都是先建立坐标系,把图形转换成函数...其中剪取问题是计算机图形学一个基本问题,剪取关键是速度,尤其是在交互式动态显示和最新式扫描中。
  • 1.3 鼠标操作在实际的应用 实例015 隐藏和显示鼠标 实例016 鼠标双击窗体时模拟键盘tab键操作 实例017 使用鼠标拖放复制文本 实例018 利用鼠标绘图 实例019 模拟鼠标操作 实例020 实现鼠标穿透窗体 第2章 键盘操作...
  • 《Android开发权威指南》注重对实际动手能力指导,在遵循技术研发知识体系严密性同时,在容易产生错误、不易理解环节上配备了翔实开发情景截图;并将重要知识点和开发技巧以“多学一招”、“扩展学习”、...
  • 6.2 常见算法的实际应用 实例136 计算1+22+33+44+…+nn的值 实例137 计算10!的值 实例138 求最大公约数 实例139 求最小公倍数 实例140 判断素数的算法 实例141 按要求生成指定位数编号 实例142 身份证号从...
  • 6.2 常见算法的实际应用 实例136 计算1+22+33+44+…+nn的值 实例137 计算10!的值 实例138 求最大公约数 实例139 求最小公倍数 实例140 判断素数的算法 实例141 按要求生成指定位数编号 实例142 身份证号从...
  • 6.2 常见算法的实际应用 实例136 计算1+22+33+44+…+nn的值 实例137 计算10!的值 实例138 求最大公约数 实例139 求最小公倍数 实例140 判断素数的算法 实例141 按要求生成指定位数编号 实例142 身份证号从...
  • [Oracle.11g权威指南(第2版)].谷长勇.扫描版.pdf

    千次下载 热门讨论 2013-06-23 21:16:09
    《Oracle 11g权威指南(第2版)》从数据库的基础知识入手,全面系统地介绍了Oracle 11g 数据库管理系统的所有特性,并配以翔实的实际用例,论述严谨,深入探讨了这些特性的细节内容,同时具有很强的可操作性和实用性...
  • vc++ 应用源码包_1

    热门讨论 2012-09-15 14:22:12
    利用Delphi代码在VC中显示JPG图片,不使用动态连接库。 Mail_Report.zip 一个邮件报告程序。 SrcFirstProg.zip 解释了最基本MFC程序流程。 tabcontrol_demo.zip tabcontrol_src.zip 自定义标签控件对话框...
  • vc++ 应用源码包_2

    热门讨论 2012-09-15 14:27:40
    利用Delphi代码在VC中显示JPG图片,不使用动态连接库。 Mail_Report.zip 一个邮件报告程序。 SrcFirstProg.zip 解释了最基本MFC程序流程。 tabcontrol_demo.zip tabcontrol_src.zip 自定义标签控件对话框...
  • vc++ 应用源码包_6

    热门讨论 2012-09-15 14:59:46
    利用Delphi代码在VC中显示JPG图片,不使用动态连接库。 Mail_Report.zip 一个邮件报告程序。 SrcFirstProg.zip 解释了最基本MFC程序流程。 tabcontrol_demo.zip tabcontrol_src.zip 自定义标签控件对话框...
  • vc++ 应用源码包_5

    热门讨论 2012-09-15 14:45:16
    利用Delphi代码在VC中显示JPG图片,不使用动态连接库。 Mail_Report.zip 一个邮件报告程序。 SrcFirstProg.zip 解释了最基本MFC程序流程。 tabcontrol_demo.zip tabcontrol_src.zip 自定义标签控件对话框...
  • vc++ 应用源码包_4

    热门讨论 2012-09-15 14:38:35
    利用Delphi代码在VC中显示JPG图片,不使用动态连接库。 Mail_Report.zip 一个邮件报告程序。 SrcFirstProg.zip 解释了最基本MFC程序流程。 tabcontrol_demo.zip tabcontrol_src.zip 自定义标签控件对话框...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 155
精华内容 62
关键字:

动态扫描显示的实际应用