nexys3正式开始练手-数码管时钟显示

来源:互联网 发布:淘宝五星好评怎么截图 编辑:程序博客网 时间:2024/05/16 11:42

下决心好好研究一番这个板子了,网上借鉴到一个不错的帖子首先来做一个数码管时钟显示。

数码管时钟我想对于很多学电子的同学来说都不陌生了,闲话不多说,先来说说这个原理。怎么点亮单个数码管我就不说了,无非分清共阴共阳,然后就是置高置低的问题。但是对于4个一起的数码管,要怎么控制他们看起来好像是在同时点亮的而且还能显示不同的内容就比较麻烦了。先上原理图:


显然要控制一个数码管需要两部分的端口--CA...DP和AN0...AN3,我一般叫左边的为段选,右边的为位选。从原理图上来看,位选端接在PNP管的B极,要先让C、E极导通,相应的位选端应该是低电平,比如AN3...AN0四位为1110,就是选择了最后一个数码管。而当数码管选中时(即相应的三极管导通),数码管公共端接的是高电平,显然这些数码管应该是共阳的,于是CA...DP端的编码就可以按共阳数码管的编码方式做了。转换成Verilog代码,可以是一下的常数定义:


parameter AN1 = 4'b1110,AN2 = 4'b1101,AN3 = 4'b1011,AN4 = 4'b0111;//数码管位选定义parameter zero = 8'b0000_0011,one = 8'b1001_1111,two = 8'b0010_0101,three = 8'b0000_1101,four = 8'b1001_1001,             five = 8'b0100_1001,six = 8'b0100_0001,seven = 8'b0001_1111,eigth = 8'b0000_0001,nine = 8'b0000_1001;//数码管段选定义
好了,现在搞清楚了第一个问题--怎么将0-9几个数显示出来,接下来的问题是怎么让4个数码管看起来是一起显示的,而且还能显示不同的内容。这个问题相信做过单片机数码管实验的同学马上就猜到了,没错,原理就是利用人眼视觉的暂留性(我是这么叫的,再专业点就不是我研究的问题了)--当两个数码管之间的变化小于100ms(貌似是这么长时间)时,我们的眼睛是看不到他们之间的闪烁的。于是,当我们要显示1234这4个数时,我们可以在1ms时显示1,25ms时显示2,50ms时显示3,75ms时显示4,然后循环,看起来就是一起显示1234这4个数了。当然,我们的硬件可以做的更快,这个时间间隔可以根据实际情况选择更短。把它翻译成Verilog语言就有下面的程序段了:

//数码管刷新显示模块always@(posedge div1000hz)begin    if(rest)    begin        seg_count <= 0;        an <= 4'b0000;        seg <= 8'b0000_0000;    end    else    begin    case(seg_count)    0 : begin            case(sec1)            0 : seg <= zero;            1 : seg <= one;            2 : seg <= two;            3 : seg <= three;            4 : seg <= four;            5 : seg <= five;            6 : seg <= six;            7 : seg <= seven;            8 : seg <= eigth;            9 : seg <= nine;            endcase            an <= AN1;         end    1 : begin            case(sec2)            0 : seg <= zero;            1 : seg <= one;            2 : seg <= two;            3 : seg <= three;            4 : seg <= four;            5 : seg <= five;            6 : seg <= six;            7 : seg <= seven;            8 : seg <= eigth;            9 : seg <= nine;            endcase            an <= AN2;         end    2 : begin            case(min1)            0 : seg <= zero;            1 : seg <= one;            2 : seg <= two;            3 : seg <= three;            4 : seg <= four;            5 : seg <= five;            6 : seg <= six;            7 : seg <= seven;            8 : seg <= eigth;            9 : seg <= nine;            endcase            an <= AN3;         end    3 : begin            case(min2)            0 : seg <= zero;            1 : seg <= one;            2 : seg <= two;            3 : seg <= three;            4 : seg <= four;            5 : seg <= five;            6 : seg <= six;            7 : seg <= seven;            8 : seg <= eigth;            9 : seg <= nine;            endcase            an <= AN4;         end    endcase    seg_count <= seg_count + 1;    endend
//数码管刷新显示模块always@(posedge div1000hz)begin    if(rest)    begin        seg_count <= 0;        an <= 4'b0000;        seg <= 8'b0000_0000;    end    else    begin    case(seg_count)    0 : begin            case(sec1)            0 : seg <= zero;            1 : seg <= one;            2 : seg <= two;            3 : seg <= three;            4 : seg <= four;            5 : seg <= five;            6 : seg <= six;            7 : seg <= seven;            8 : seg <= eigth;            9 : seg <= nine;            endcase            an <= AN1;         end    1 : begin            case(sec2)            0 : seg <= zero;            1 : seg <= one;            2 : seg <= two;            3 : seg <= three;            4 : seg <= four;            5 : seg <= five;            6 : seg <= six;            7 : seg <= seven;            8 : seg <= eigth;            9 : seg <= nine;            endcase            an <= AN2;         end    2 : begin            case(min1)            0 : seg <= zero;            1 : seg <= one;            2 : seg <= two;            3 : seg <= three;            4 : seg <= four;            5 : seg <= five;            6 : seg <= six;            7 : seg <= seven;            8 : seg <= eigth;            9 : seg <= nine;            endcase            an <= AN3;         end    3 : begin            case(min2)            0 : seg <= zero;            1 : seg <= one;            2 : seg <= two;            3 : seg <= three;            4 : seg <= four;            5 : seg <= five;            6 : seg <= six;            7 : seg <= seven;            8 : seg <= eigth;            9 : seg <= nine;            endcase            an <= AN4;         end    endcase    seg_count <= seg_count + 1;    endend
好,现在剩最后一个问题了,那就是时钟控制部分。熟悉C的同学会说,那还不简单,分频计数,然后整除求余,将秒、分的十位各位分开不就可以了吗?没错,这是最简单的方式,但是,大家千万不要忽略了我们最后的代码是要变成硬件电路的。先不说Xilinx的IDE内嵌的XST综合器不支持对除号的综合,要实现除法必须要设计除法器(调用IP或自己设计),就算是设计出来了,一个除法器占用的硬件资源可能会比我们剩余部分电路占用的资源还多。从这方面出发考虑,我们要想想是不是有更好的方法实现它。其实只要我们稍微思考一下还是不难的,下面的代码就能很简洁的完成这部分的设计:

//时钟模块
always@(posedge div1hz)
begin
    if(rest)
    begin
        sec1 <= 0;
        sec2 <= 0;
        min1 <= 0;
        min2 <= 0;
    end
    else
    begin
    sec1 <= sec1 + 1;
    if(sec1 == 9)
    begin
        sec2 <= sec2 + 1;
        sec1 <= 0;
    end
    if(sec2 == 5 && sec1 == 9)
    begin
        min1 <= min1 + 1;
        sec2 <= 0;
    end
    if(min1 == 9)
    begin
        min2 <= min2 + 1;
        min1 <= 0;
    end
    if(min2 == 5 && min1 == 9)
    begin
        min2 <= 0;
    end
    end
end


下面是完整的程序:

`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// Company: // Engineer: // // Create Date:    09:59:26 10/09/2014 // Design Name: // Module Name:    sevenseg_demo // Project Name: // Target Devices: // Tool versions: // Description: //// Dependencies: //// Revision: // Revision 0.01 - File Created// Additional Comments: ////////////////////////////////////////////////////////////////////////////////////module segclk(    clk,//时钟输入,100M    rest,//时钟复位信号,BTNU,高电平时复位    seg,//数码管段选    an,//数码管位选      //led//8个LED     ); input clk,rest; output reg [7:0] seg; output reg [3:0] an; //output reg [7:0] led;  parameter AN1 = 4'b1110,AN2 = 4'b1101,AN3 = 4'b1011,AN4 = 4'b0111;//数码管位选定义  parameter zero = 8'b0000_0011,one = 8'b1001_1111,two = 8'b0010_0101,three = 8'b0000_1101,four = 8'b1001_1001,              five = 8'b0100_1001,six = 8'b0100_0001,seven = 8'b0001_1111,eigth = 8'b0000_0001,nine = 8'b0000_1001;//数码管段选定义 //parameter led_on = 8'b1111_1111,led_off = 8'b0000_0000;//LED亮灭定义              reg [25:0] div1hz_temp;//1秒分频计数 reg [12:0] div1000hz_temp;//数码管刷新时间分频计数 reg div1hz;//1Hz时钟 reg div1000hz;//数码管刷新时钟,频率为(100M/2^13)Hz//reg led_temp;//LED亮灭reg [3:0] sec1;//秒个位  reg [3:0] sec2;//秒十位  reg [3:0] min1;//分个位  reg [3:0] min2;//分十位    reg [1:0] seg_count;//数码管位选定位    //1秒分频模块  always@(posedge clk)  begin      div1hz_temp <= div1hz_temp + 1;      if(div1hz_temp == 50000000)      begin          div1hz_temp <= 0;          div1hz <= ~div1hz;      end  end    //数码管刷新时间分频模块  always@(posedge clk)  begin      div1000hz_temp <= div1000hz_temp + 1;      if(div1000hz_temp == 8191)      begin          div1000hz <= ~div1000hz;      end  end    //时钟模块  always@(posedge div1hz)  begin      if(rest)      begin          sec1 <= 0;          sec2 <= 0;          min1 <= 0;          min2 <= 0;      end     else      begin      sec1 <= sec1 + 1;      if(sec1 == 9)      begin          sec2 <= sec2 + 1;          sec1 <= 0;      end      if(sec2 == 5 && sec1 == 9)      begin          min1 <= min1 + 1;          sec2 <= 0;      end     if(min1 == 9)      begin          min2 <= min2 + 1;          min1 <= 0;     end     if(min2 == 5 && min1 == 9)     begin         min2 <= 0;     end     end end  //LED亮灭控制模块 //always@(posedge div1hz) //begin     //led_temp = ~led_temp;     //if(led_temp)     //    led <= led_on;     //else        // led <= led_off; //end  //数码管刷新显示模块 always@(posedge div1000hz) begin     if(rest)     begin         seg_count <= 0;        an <= 4'b0000;         seg <= 8'b0000_0000;     end     else     begin     case(seg_count)     0 : begin             case(sec1)             0 : seg <= zero;             1 : seg <= one;             2 : seg <= two;             3 : seg <= three;             4 : seg <= four;             5 : seg <= five;             6 : seg <= six;             7 : seg <= seven;             8 : seg <= eigth;             9 : seg <= nine;             endcase             an <= AN1;         end    1 : begin             case(sec2)             0 : seg <= zero;             1 : seg <= one;             2 : seg <= two;             3 : seg <= three;             4 : seg <= four;             5 : seg <= five;             6 : seg <= six;             7 : seg <= seven;             8 : seg <= eigth;             9 : seg <= nine;             endcase             an <= AN2;          end     2 : begin             case(min1)             0 : seg <= zero;             1 : seg <= one;             2 : seg <= two;             3 : seg <= three;             4 : seg <= four;             5 : seg <= five;             6 : seg <= six;             7 : seg <= seven;             8 : seg <= eigth;             9 : seg <= nine;             endcase             an <= AN3;          end     3 : begin             case(min2)             0 : seg <= zero;             1 : seg <= one;             2 : seg <= two;             3 : seg <= three;             4 : seg <= four;             5 : seg <= five;             6 : seg <= six;             7 : seg <= seven;             8 : seg <= eigth;             9 : seg <= nine;             endcase             an <= AN4;          end     endcase     seg_count <= seg_count + 1;     end end  endmodule



然后分配一下引脚,经测试程序在板子上运行正常,下一步要去研究下usb uart。


0 0
原创粉丝点击