精华内容
下载资源
问答
  • 数码管动态扫描显示 象棋小子 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

     

    展开全文
  • 6.用4位LED数码管实现计数值的显示,要求必须采用动态扫描驱动电路,要求该电路只用一个译码显示芯片(7448)能同时驱动,4位数码管无闪烁的显示对应数码。 7.功能扩展(自选)。 急需!急需!急需!最好今天就有...
  • I/O输出——实例3:数码管动态扫描显示

    万次阅读 多人点赞 2018-04-14 10:21:07
    I/O输出——实例3:数码管动态扫描显示一、实例目的 通过本实例,我们应: 1. 了解多位数码管的结构及引脚; 2. 了解多位数码管驱动电路; 3.掌握数码管动态扫描程序设计。 本例重点介绍多位数码管的驱动电路...
     I/O输出——实例3:数码管动态扫描显示

    一、实例目的
          通过本实例,我们应:
          1. 了解多位数码管的结构及引脚;
          2. 了解多位数码管驱动电路;
          3.掌握数码管动态扫描程序设计。
          本例重点介绍多位数码管的驱动电路和程序设计,关于单个数码管的结构和驱动原理,请参见《I/O输出——实例2:数码管静态驱动》。
    二、多位数码管结构及引脚
          多位数码管用于显示更多的数值信息,其由多个数码管组成,这些数码管的段(a~h)一一对应连接在一起,公共极独立。4位数码管外观如图1所示。
               
                        图1   4位数码管
        注:图1来源自Wikipedia,原文链接:https://en.wikipedia.org/wiki/Seven-segment_display
       
     四位数码管引脚见表1。
       表1 四位数码管引脚

    引脚
    功能
    a~h
    多位数码管的段控制端,输入,决定数码管的显示内容
    com0~com3
    数码管的公共端,即共阴极或共阳极,又称位选

    二、多位数码管驱动原理
            因为多位数码管的a~h段在内部连接在一起,为了让数码管显示不同的内容,只能采用动态扫描方式,即按照一定方向(例如从左到右)逐一选中数码管,单片机输出相应的显示数据,并保持一定的时间,如此循环。由于人眼的视觉暂留效应,我们看到多位显示内容是同时显示的,这与动画由一幅幅图片动态快速切换的原理是类似的。 根据经验,当帧率为15fps以上,则动画是连贯的(一帧就是一幅图像)。帧率越高动画越流畅,一般动画要求帧数在24帧以上。对于四位数码管,显示四位数字为一帧,按25fps计算,则每位数字的显示时间为10ms左右(1s/25/4)(帧率取25fps,4为数码管的位数)。但是,经过实测,每位数字显示10ms,明显看到辉光闪烁,刷新频率不够,改为5ms则稳定显示。 
            8位数码管的驱动电路如图2所示。一个74HC573锁存器用于提供数码管驱动电流,一个74LS138译码器用于片选8位数码管,任意时刻仅有一个数码管是选中的。
            
                                                               图2 8位数码管动态扫描驱动电路
           下面简单介绍74HC573和74LS138芯片的功能和引脚。
           74HC573是8位锁存器(时序电路,输出不仅仅取决于输入,还与电路之前的状态有关,具有记忆(存储)功能),用于锁存8位数据,其引脚见表2。
                                                           表2 74HC573引脚
    引脚
    功能
    D0~D7
    输入,8位待锁存的数据
    Q0~Q7
    输出,三态,内部8位锁存器的输出
    提示:三态指高电平、低电平和高阻态。高阻态相当于与其它电路断开。通常总线(地址线、数据线都是三态的)
    输入,输出使能,低电平有效
    输入高电平时,Q0~Q7呈高阻态;输入低电平时,Q0~Q7为内部8位锁存器输出
    提示:如果管脚带帽(名称上有一个横线),表示该引脚低电平有效,否则为高电平有效。
    LE
    输入,锁存使能端,高电平有效。
    LE = 1时,D0~D7能够进入到内部的8位锁存器
    LE = 0时,内部的8位锁存器保持,即D0~D7无法进入到锁存器内部
    74LS138是38译码器(组合电路,输出由输入决定,无记忆(存储)功能),其引脚见表3,功能表见表4。
    表3 74LS138引脚
    引脚
    功能
    C,B,A
    输入,译码输入,C为最高位,A为最低位,共8种状态
    Y0~Y7
    输出,38译码器输出,低电平有效
    提示:如果管脚后有一个圆圈。,表示该引脚有效时,输出低电平。
    E1
    输入,使能端,高电平有效
    E2、E3
    输入,使能端,低电平有效
    提示:如果管脚前有一个圆圈。且引脚名称未带帽(—),表示该引脚低电平有效,否则为高电平有效。
    表4  74LS138引脚功能表
    注:  G2=E2+E3, G1=E1                                           

    三、多位数码管动态扫描程序设计
           下面以使用4位数码管显示“2016”为例进行介绍。
     动态扫描程序主流程图如图3所示。

             图3   4位数码管动态扫描显示流程图

           采用结构式编程,将数码管动态扫描相关的函数写在一个7seg.h头文件里,便于移植和嵌入。当工程用到数码管动态扫描时,仅需引用7seg.h和修改相关的硬件接口定义即可。
    1. 新建一个工程LEDDynamic。
    2. 新建两个文件,一个main.c,一个7seg.h,添加到本工程。文件内容如下:
        
    //main.c
    #include"7seg.h"
    //显示数据存在一个数组里
    unsigned char num[] = {2,0,1,6};
    /****************************
    *函数:delayMS
    *功能:ms级延时函数@12MHz主频
    *参数:ms:unsinged int,延时时间,单位:ms
    *返回值:无
    *****************************/
    void delayMS(unsigned int ms)
    {
       unsigned int i,j;
       for(i=0;i<ms;i++)
        for(j=0;j<150;j++);
    }
    //main是主程序
    void main()
    {
       unsigned char i;
       while(1)
       {
          for(i=0;i<4;i++)  //4位数码管,逐个扫描,共四次
             {
               led_display(i,num[i]); //显示2016
               delayMS(10);
             }

       }

    //7seg.h
    #include"reg51.h"
    #define led_seg P0 //段控制a~h
    #define led_com P2 //P2.2~P2.0控制74LS138译码的输入(C,B,A)
    //共阴极段码表code table for 0-9,A-F, and off
    unsigned char LED_CODE[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,
                              0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x00};

    /****************************
    *函数:led_display
    *功能:片选某位数码管,显示指定数字
    *参数:com:unsigned char,数码管位选;number:unsigned char,显示的数字
    *返回值:无
    *****************************/
    void led_display(unsigned char com, unsigned char number)
    {
             led_com  = com;
            led_seg = LED_CODE[number];    
    }

           7seg.h的led_display函数即为动态扫描的函数,选中某位数码管,显示指定内容。要显示多少位,则调用多少次。注意,每位数码管显示间隔时间不能太大也不能太小,太大则显示结果出现逐位显示现象,太小可能导致每位数码管显示时间过短,亮度不够。原则上,N位数码管,每位数码管显示时间T=1s/(25*N)。

    3.编译并生成.hex。
    4.在Proteus进行仿真。
    仿真结果如下:
    图4 数码管动态扫描显示2016(每位数码管保持10ms)

    图5 数码管动态扫描显示2016(每位数码管保持16ms,约15fps)

           可见,当扫描间隔超过16ms时,明显看出显示不连贯。 
           但是,经过实测,每位数字显示10ms,明显看到辉光闪烁,刷新频率不够,改为5ms则稳定显示。

         至此,数码管动态扫描驱动电路和程序已经学完。上面例子是在main函数里进行数码管动态扫描显示,如果存在其他延时(如按键延时,呼吸灯延时),则这些延时过程中,数码管只能显示最后一个扫描的数码管的内容,这是很糟糕的。有没有好的解决办法呢?当然有,改为使用定时器中断周期地去刷新显示内容。 

    展开全文
  • 实验的功能很简单,就是让4个数码管每隔1s递增显示,使用动态扫描的方式来实现。 从这个功能的描述可以看出,我们首先要写一个计数器模块,来让计数值每隔1s增加1,暂时实现的是16进制的东西,从0到f,之后10到1f...

     

    实验的功能很简单,就是让4个数码管每隔1s递增显示,使用动态扫描的方式来实现。

    从这个功能的描述可以看出,我们首先要写一个计数器模块,来让计数值每隔1s增加1,暂时实现的是16进制的东西,从0到f,之后10到1f等等。

    我们的实验平台的系统时钟是25MHz,不是25MHz的实验平台,可以通过PLL来分频或倍频得到25MHz的时钟。

    其次,写一个模块来控制数码管的位选和段选。

    实验平台的数码管是共阴极的,也就是片选端低电平有效。

    还需要注意的一个问题是:

    片选控制信号的刷新速度必须足够快才能避免闪烁感,但也不能太快,以免影响数码管的开关切换,最佳的工作频率为1000Hz左右。如果FPGA的时钟为50MHz,那么至少跑5*10^4个周期,也即50000个周期刷新一次才行,我们知道2^16=65536,2^15=32768。

    当然,这里的时钟是25Mhz,所以我们需要计数大概25000个周期才能刷新一次。

    上面的最佳工作频率是1000hz的说法是否权威呢?我不知道,但是实验证明能用。

    先给出计数模块的Verilog描述:

    /
    //工程硬件平台: Xilinx Spartan 6 FPGA
    /
    module counter(
    			input clk,		//时钟信号,25MHz
    			input rst_n,	//复位信号,低电平有效
    			output reg[15:0] display_num	//数码管显示数据,[15:12]--数码管千位,[11:8]--数码管百位,[7:4]--数码管十位,[3:0]--数码管个位
    		);
    
    //-------------------------------------------------
    //1s定时产生逻辑
    reg[24:0] timer_cnt;	//1s计数器,0-24999999
    
    	//1s定时计数
    always @(posedge clk or negedge rst_n)
    	if(!rst_n) timer_cnt <= 25'd0;
    	else if(timer_cnt < 25'd24_999_999) timer_cnt <= timer_cnt+1'b1;
    	else timer_cnt <= 25'd0;
    
    wire timer_1s_flag = (timer_cnt == 25'd24_999_999);		//1s定时到标志位,高有效一个时钟周期
    
    //-------------------------------------------------
    //递增数据产生逻辑
    
    	//显示数据每秒递增
    always @(posedge clk or negedge rst_n)
    	if(!rst_n) display_num <= 16'd0;
    	else if(timer_1s_flag) display_num <= display_num+1'b1;
    	
    endmodule
    
    

     

    再给出片选和段选控制的Verilog描述:

    /
    //工程硬件平台: Xilinx Spartan 6 FPGA
    /
    module seg7(
    			input clk,		//时钟信号,25MHz
    			input rst_n,	//复位信号,低电平有效
    			input[15:0] display_num,	//数码管显示数据,[15:12]--数码管千位,[11:8]--数码管百位,[7:4]--数码管十位,[3:0]--数码管个位
    			output reg[3:0] dtube_cs_n,	//7段数码管位选信号
    			output reg[7:0] dtube_data	//7段数码管段选信号(包括小数点为8段)
    		);
    
    //-------------------------------------------------
    //参数定义
    
    //数码管显示 0~F 对应段选输出
    parameter 	NUM0 	= 8'h3f,//c0,
    			NUM1 	= 8'h06,//f9,
    			NUM2 	= 8'h5b,//a4,
    			NUM3 	= 8'h4f,//b0,
    			NUM4 	= 8'h66,//99,
    			NUM5 	= 8'h6d,//92,
    			NUM6 	= 8'h7d,//82,
    			NUM7 	= 8'h07,//F8,
    			NUM8 	= 8'h7f,//80,
    			NUM9 	= 8'h6f,//90,
    			NUMA 	= 8'h77,//88,
    			NUMB 	= 8'h7c,//83,
    			NUMC 	= 8'h39,//c6,
    			NUMD 	= 8'h5e,//a1,
    			NUME 	= 8'h79,//86,
    			NUMF 	= 8'h71,//8e;
    			NDOT	= 8'h80;	//小数点显示
    
    //数码管位选 0~3 对应输出
    parameter	CSN		= 4'b1111,
    			CS0		= 4'b1110,
    			CS1		= 4'b1101,
    			CS2		= 4'b1011,
    			CS3		= 4'b0111;
    
    parameter N = 17;//高两位控制片选,其他位用于分频
    //-------------------------------------------------
    //分时显示数据控制单元
    reg[3:0] current_display_num;	//当前显示数据
    reg[N-1:0] div_cnt;	//分时计数器
    
    	//分时计数器
    always @(posedge clk or negedge rst_n)
    	if(!rst_n) div_cnt <= 0;
    	else div_cnt <= div_cnt+1'b1;
    
    	//显示数据
    always @(posedge clk or negedge rst_n)
    	if(!rst_n) current_display_num <= 4'h0;
    	else begin
    		case(div_cnt[N-1:N-2])
    			2'b00: current_display_num <= display_num[3:0];
    			2'b01: current_display_num <= display_num[7:4];
    			2'b10: current_display_num <= display_num[11:8];
    			2'b11: current_display_num <= display_num[15:12];
    			default: ;
    		endcase
    	end
    		
    	//段选数据译码
    always @(posedge clk or negedge rst_n)
    	if(!rst_n) dtube_data <= NUM0;
    	else begin
    		case(current_display_num) 
    			4'h0: dtube_data <= NUM0;
    			4'h1: dtube_data <= NUM1;
    			4'h2: dtube_data <= NUM2;
    			4'h3: dtube_data <= NUM3;
    			4'h4: dtube_data <= NUM4;
    			4'h5: dtube_data <= NUM5;
    			4'h6: dtube_data <= NUM6;
    			4'h7: dtube_data <= NUM7;
    			4'h8: dtube_data <= NUM8;
    			4'h9: dtube_data <= NUM9;
    			4'ha: dtube_data <= NUMA;
    			4'hb: dtube_data <= NUMB;
    			4'hc: dtube_data <= NUMC;
    			4'hd: dtube_data <= NUMD;
    			4'he: dtube_data <= NUME;
    			4'hf: dtube_data <= NUMF;
    			default: ;
    		endcase
    	end
    
    	//位选译码
    always @(posedge clk or negedge rst_n)
    	if(!rst_n) dtube_cs_n <= CSN;
    	else begin
    		case(div_cnt[N-1:N-2])
    			2'b00: dtube_cs_n <= CS0;
    			2'b01: dtube_cs_n <= CS1;
    			2'b10: dtube_cs_n <= CS2;
    			2'b11: dtube_cs_n <= CS3;
    			default:  dtube_cs_n <= CSN;
    		endcase
    	end
    	
    
    endmodule
    
    

    最后给出主模块,调用上述两个模块:

    /
    //工程硬件平台: Xilinx Spartan 6 FPGA
    ///产生一个每秒递增的16bit数据以16进制方式显示在4位数码管上
    module sp6(
    			input ext_clk_25m,	//外部输入25MHz时钟信号
    			input ext_rst_n,	//外部输入复位信号,低电平有效
    			output[3:0] dtube_cs_n,	//7段数码管位选信号
    			output[7:0] dtube_data	//7段数码管段选信号(包括小数点为8段)
    		);													
    
    //-------------------------------------
    //PLL例化
    wire clk_12m5;	//PLL输出12.5MHz时钟
    wire clk_25m;	//PLL输出25MHz时钟
    wire clk_50m;	//PLL输出50MHz时钟
    wire clk_100m;	//PLL输出100MHz时钟
    wire sys_rst_n;	//PLL输出的locked信号,作为FPGA内部的复位信号,低电平复位,高电平正常工作
    
      pll_controller uut_pll_controller
       (// Clock in ports
        .CLK_IN1(ext_clk_25m),      // IN
        // Clock out ports
        .CLK_OUT1(clk_12m5),     // OUT
        .CLK_OUT2(clk_25m),     // OUT
        .CLK_OUT3(clk_50m),     // OUT
        .CLK_OUT4(clk_100m),     // OUT
        // Status and control signals
        .RESET(~ext_rst_n),// IN
        .LOCKED(sys_rst_n));      // OUT		
    		
    
    //-------------------------------------
    //25MHz时钟进行分频,产生每秒递增的16位数据
    wire[15:0] display_num;	//数码管显示数据,[15:12]--数码管千位,[11:8]--数码管百位,[7:4]--数码管十位,[3:0]--数码管个位
    
    counter		uut_counter(
    				.clk(clk_25m),		//时钟信号
    				.rst_n(sys_rst_n),	//复位信号,低电平有效
    				.display_num(display_num)		//LED指示灯接口	
    			);
    		
    //-------------------------------------
    //4位数码管显示驱动															
    
    seg7		uut_seg7(
    				.clk(clk_25m),		//时钟信号
    				.rst_n(sys_rst_n),	//复位信号,低电平有效
    				.display_num(display_num),		//LED指示灯接口	
    				.dtube_cs_n(dtube_cs_n),	//7段数码管位选信号
    				.dtube_data(dtube_data)		//7段数码管段选信号(包括小数点为8段)
    		);
    
    endmodule
    
    

    里面用到了一个PLL的IP核,这里只是一个示例,由于本设计的实验平台的时钟频率本身就是25MHz,所以不用也行。

     

    实验结果证明,很完美。

    关于数码管,以前也写过两篇博文:

    数码管显示实验(一)(初步明白片选、段选)

    四位16进制的数码管动态显示设计

    8段数码管译码表

     

     

     

     

    展开全文
  • //按键扫描函数 } } void Timer0() interrupt 1 { static uint count_ms; static uint count_s; static uint count_min; TH0 = 0xEE; TL0 = 0x00; count_ms++; count_s++; count_min++; ...

    实验课题

    今天微机原理实验老师布置了一道课后作业,就是利用51单片机做一个秒表,本来单片机是有P0,P1,P2,P3共计32个I/O口可以用的,但是因为实验箱内单片机做了外部扩展,所以端口不够用,改成利用C51单片机外扩8255实现数字秒表。

    思考

    因为外部做了扩展,所以在做仿真的时候思考了很久,为了和实验箱布局一致,我在proteus上还原实验箱的布局。首先是从P0做的扩展,因此要对应8255的输入端口。

    很多人对8255的使用不太了解,这里我就补充一下8255的知识。

    8255引脚部分及原理

    • 和外设相连的 

    PA7~PA0:A口数据信号线,双向,三态引脚; 

    PB7~PB0:B口数据信号线,双向,三态引脚; 

    PC7~PC0:C口数据信号线,双向,三态引脚;  

    • 面向系统总线和CPU相连的 

    RESET:复位信号,高电平有效。当RESET信号来到时,所有内部寄存器都被清除,同时3个数据端口被自动置 为输入端口。 

    D7~D0:它们是8255A的数据线,和系统总线相连,用来传送数据和控制字。 

    片选信号,低电平有效。即当端为低电平时,8255A被选中。只有当有效时,CPU才能对8255A进行读写操作。 

    • /WR读信号,低电平有效。当有效时,CPU可以从8255A中读取数据。 
    • /RD~写信号,低电平有效。当有效时,CPU可以往8255A中写入控制字或数据。 

    A1、A0:端口选择信号。8255A内部有3个数据端口(I/O端口)和1个控制端口,共4个端口。通过地址线A0A1寻 址。规定当A1、A0为00时,选中A端口;为01时,选中B端口; 为10时,选中C端口;为11时,选中控制口。(这里外扩74LS373实现)

    • 电源和地

    Vcc :+5V电源 

    GND:地线

    控制字及工作方式

    工作方式我们只讲方式0(基本的输入和输出),读者只需了解这一个即可。

    方式0为基本的输入/输出方式,传送数据时不需要联络信号。A口、B口和C口(或C高4位口及C低4位口)均可独立设置成方式0输入口或方式0输出口。

    实验设计要求:

    1. 按下按钮S1,秒表暂停计时;
    2. 按下按钮S2,秒表开始计时;
    3. 按下按钮S3,秒表清零;
    4. 计时精确到0.5s

    实验实现代码

    #include <reg51.h>
    #define uint unsigned int	
    #define uchar unsigned char
    sbit k1=P1^0;
    sbit k2=P1^1;
    sbit k3=P1^2;
    uchar ms = 0;//毫秒
    uchar s = 0;//秒
    uchar min = 0;//分  
    unsigned char xdata *p=0xc000;
    unsigned char xdata *pa=0xc000;//段选
    unsigned char xdata *pb=0xc002;//位选
    uchar code led_data[] = {0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6};
    uchar code dp[] = {0xfd,0x61,0xdb,0xf3,0x67,0xb7,0xbf,0xe1,0xff,0xf7};
    
    //延时函数
    void delay(uint t)
    {
    	uint i,j;
    	for(i=0;i<t;i++)
    	{
    		for(j=0;j<120;j++);	
    	}
    }
    
    void Timer0Init()
    {
    	TMOD = 0x01; 		//选择T0定时/计数器,工作在方式1,16位计数器		
    	TH0 = 0xEE;			s
    	TL0 = 0x00;		
    	ET0 = 1;			//定时/计数器0中断允许位
    	EA = 1;				//总中断
    }
    
    void S3()
    {
    	ms = 0;
    	s = 0;				
    	min = 0;			
    	TR0 = 0;			
    }
    
    void Key()
    {
    	uchar K;		   
    	K = P1&0x07;	   
    	if(K!=0x07)	   
    	{
    		delay(10);	 	//消抖10ms
    		K = P1&0x07;	 
    		if(K!=0x07)	 
    		{
    			switch(K)
    			{
    				case 0x05:				  
    							TR0 = 1;	  
    							break;
    				case 0x06:				  //S2(P1^1)被按下
    							TR0 = 0;	  //定时器0运行控制位为0,关闭定时器0
    							break;
    				case 0x03:				  
    							S3();
    							break;
    			}
    		}
    		while(K!=0x07)		//松手检测
    		{
    			K = P1&0x07;
    		}
    	}
    }
    
    
    void digital(uchar ms,uchar s,uchar min)
    {
     
    	*pb = 0x7f;
    	*pa = led_data[ms%10];		  
    	delay(1);
    
     	*pb = 0xbf;
    	*pa = led_data[ms/10];		  
    	delay(1);
    
    	*pb = 0xdf;
    	*pa = dp[s%10];		  
    	delay(1);
    
    	*pb = 0xef;
    	*pa = led_data[s/10];		  
    	delay(1);
    
     	*pb = 0xff;				   
       	*pa = dp[min%10];		  
    	delay(1);
    				  
    	*pb = 0xf7;				   
       	*pa = dp[min%10];		  
    	delay(1);
    
    	*pb = 0xfb;
    	*pa = led_data[min/10];		  
    	delay(1);
    
    	*pa = 0x00;					
    }
    
    
    void main(void)
    {
    	p[3]=0x80;		//普通IO
    	(*pa) = 0x00;	//读端口前写0
    	P1 = 0xFF;		//读端口前写1
    	Timer0Init();	//定时器中断初始化函数
    	while(1)
    	{
     
    		digital(ms,s,min);	//数码管显示函数
    		Key();			   //按键扫描函数
    	}
    }
    
    void Timer0() interrupt 1
    {
    	static uint count_ms;
    	static uint count_s;	
    	static uint count_min;		
    	TH0 = 0xEE;				
    	TL0 = 0x00;
    	count_ms++;
    	count_s++;				
    	count_min++;			
    
    	if(count_ms==2)			 
    	{
    		count_ms = 0;		 
    		ms++;			 
    		if(ms>59)		 
    		{
    			ms = 0;
    		}
    	}
    
    	if(count_s==200)			 
    	{
    		count_s = 0;		 
    		s++;			 
    		if(s>59)		 
    		{
    			s = 0;
    		}
    	}
    	if(count_min==12000)		  
    	{
    		count_min = 0;		      
    		min++;				  
    		if(min>59)			  
    		{
    			min = 0;
    		}
    	}
    }
    
    
    

    展示

    展开全文
  • 8位数码管动态扫描显示变化数据

    千次阅读 2017-02-08 18:29:23
    #include //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义 #define DataPort P0 //定义数据端口 程序中遇到DataPort 则用P0 替换 sbit LATCH1=P2^2;//定义锁存使能端口 段锁存 sbit LATCH2=P2^3...
  • //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义#define DataPort P0 //定义数据端口 程序中遇到DataPort 则用P0 替换sbit LATCH1=P2^2;//定义锁存使能端口 段锁存sbit LATCH2=P2^3;// 位锁存...
  • 实现扫描按键显示功能

    千次阅读 2011-03-10 13:50:00
    ;**********************************************************************...本程序实现扫描按键显示功能. * ;分别按16个键盘显示分别显示数字123A456B789C*0#D *;键盘口P1,数码管显示第一位p21, 数码管段位p0口 
  • FPGA动态扫描数码管

    千次阅读 2018-10-28 17:56:20
    由于数码管的段选段是连在一起的,要想两个数码管显示不一样的值,就必须动态扫描数码管。因为人眼地时间分辨率是20ms,只要扫描数码管地的周期小于20ms,就可以使用残影让数码管显示数值,给人的感觉就是数码管...
  • STM32之---数码管动态扫描

    万次阅读 2019-02-28 23:26:37
    如果按照惯例,第一个实验一般是LED流水灯,但是我相信大家的胃口绝不仅仅满足于区区一个流水灯,因此给出了一个稍微复杂一点的实验,这个实验就是通过动态扫描的方式让这8个数码管分别显示0~7这8个数字。...
  • Verilog HDL数码管动态扫描

    千次阅读 2019-04-13 11:06:44
    数码管动态扫描 1.概述 本程序实现的是以个递增的数码管显示模块,可供其他模块使用。 每隔0.5秒数码管显示的数值加1 2.模块设计说明 本实验由5个模块构成,由顶层模块(top)调用其它四个模块实现。 1....
  • 让6位数码管显示“123456”(动态扫描) 实验平台 小精灵开发板 QuartusII 11.0 原理分析 我们上一讲讲了数码管的静态显示,如果只有一位,那么我们需要控制8个段选,1个位选,总共9个引脚。如果我们要控制...
  • 数码管的动态扫描实现

    千次阅读 2020-08-12 18:02:27
    实现FPGA驱动数码管动态显示,板级调试时通过in system sources and probes(ISSP)输入想要显示的数据。 八段数码管的驱动原理: 八段数码管的结构如下图所示,七段数码管就是少了h那个点。 数码管分别共阳极和共阴极...
  • STA模式 - wifi随时扫描功能

    千次阅读 2016-03-10 17:42:06
    随时扫描功能:在wifi关闭的时候,底层并没有真正意义上的关闭,而是继续扫描,只是不再列表上显示罢了。现在分析随时扫描功能开启后wifi打开、关闭、显示扫描结果的流程。在这里需要关注两个状态机:WifiController...
  • 使用合适的描述方式编程实现规定功能的数码管扫描显示模块。 课前任务:在Xilinx ISE上完成创建工程、编辑程序源代码、编程、综合、仿真、验证,确保逻辑正确性。 实验室任务:配置管脚,生成*.bit文件,完成板级...
  • 之前在网上看了很多数字七段管的相关代码,发现都...实现功能: 在八位七段数码管上显示固定数字,具体数字可修改q后面的数字实现。 管脚分配: q(0~6) 分配数码管A到G。 s(0~7)分配数码管八个使能端。
  • 数码管显示分静态扫描和动态扫描,动态扫描显示一般分两种方式 1、选用一个数码管位,写断码显示,延时一定的时间,关闭显示,选择下一位,依次类推,完成数码管的多位扫描显示,这种方式比较耗CPU资源。 2、...
  • Android App扫描二维码功能的实现

    万次阅读 热门讨论 2018-03-09 20:28:25
    转载:http://blog.csdn.net/yuzhiqiang_1993/article/details/782920041.基本的扫一扫扫描二维码从图片可以看到,我扫的二维码还是挺复杂...闪光灯(如果设备支持闪光的话,显示闪光灯按钮,否则不会显示)3.解析二...
  • 动态数码管显示实验

    千次阅读 多人点赞 2019-04-19 19:20:24
    本实验采用了普中科技的51单片机开发板 本实验以静态数码管显示实验为基础 通过动态扫描方式静态显示八个数据
  • library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; ...--功能:利用4位共阴极动态...--原理:动态扫描电路,时钟分频,段选位选 entity led is port ( clkin:in std_logic;...
  • 51单片机开发系列四 LED点阵扫描显示 ...笔者此处就LED点阵屏动态扫描显示作一个简单的介绍。 1. LED点阵屏显示原理概述 图1-1为一种8x8的LED点阵单色行共阳模块的内部等效电路图,对于红光LED其工作正向电压约
  • 扫描二维码显示汉字也是比较通用的一项功能,在使用中琅标签打印软件制作二维码时,需要先根据实际纸张尺寸设置一下纸张尺寸及布局,下面我们就可以直接来看一下制作二维码且扫描显示汉字的效果: 一、...
  • 实验9、键盘扫描及数码管显示实验

    千次阅读 2019-11-26 13:14:24
    1、编写程序,实现如下功能:初始时数码管无显示;第一次按下键盘时,在最右侧数码管对应的十六进制数字;以后每次按下键盘,则将当前显示的数字全部向左移动一位(最左侧的数字移出数码管),并将刚刚键入的数字...
  • 上一节讲了在主函数循环中动态扫描数码管的程序,但是该程序有一个隐患,在一些项目中 ,主函数循环中的任务越多,就意味着在某一瞬间,每显示一位数码管停留的时间就会越久,一旦超过某个值,会严重影响显示的效果...
  • AR应用程序脱离扫描功能实现

    千次阅读 2016-03-04 08:45:23
    下面咱们说说怎么实现脱离扫描托仍然让模型在屏幕的最中显示 首先你需要判断什么情况下是脱离扫描图的状态,高通为此提供了一个方法 在这个代码里面,自己写一个bool判断, 这样你就可以通过监听imesh来判断是否...
  • 了解二维码这个东西还是从微信中,当时微信推出二维码扫描功能,自己感觉挺新颖的,从一张图片中扫一下竟然能直接加好友,不可思议啊,那时候还不了解二维码,呵呵,然后做项目的时候,老板说要加上二维码扫描功能,...
  • 基于MUI框架的使用HTML5+实现的二维码扫描功能

    万次阅读 多人点赞 2017-02-09 09:24:17
    Barcode的一个实现案例 ... Barcode模块管理条码扫描,提供常见的条码(二维码及一维码)的扫描识别功能,可调用设备的摄像头对条码图片扫描进行数据输入。通过plus.barcode可获取条码码管理对象。博客有更新,修...
  • 现在手上有个需求,就是webview加载的js端想调用原生的摄像头进行扫码功能,查找了挺多资料 方法是1、通过拦截webview页面ulr的方法进行监听页面操作 2、监听到我们想要的操作后,原生端进行打开摄像头并进行扫码 3...
  • 今天介绍一下,实现二维码扫描的webView 可以实现二维码扫描的在度娘上有很多,今天这个呢其实和网上的差不多,只是我们的webView是一直在使用的,如果用网上的话,会改动很大,影响很多代码,所以我就在网上的基础...
  • 相信每一个玩过电脑的人都...),每当我们的电脑出现卡顿或者中毒等情况的的时候,我们往往会进行一个全盘的文件扫描,对每个文件进行处理,包括校验该文件的各种属性,来确定该文件是否是垃圾文件或者是不安全文件,

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 220,428
精华内容 88,171
关键字:

动态扫描显示功能