野火征途Pro开发板FPGA数字时钟(秒表)设计学习心得(1)

hc595_ctl
shizhong

第一次写csdn,自学FPGA有一段时间了,七月中旬买的开发板,到现在一个多月终于稍微学懂点FPGA了。

这个分享的是野火FPGA开发指南数码管动态显示拓展训练的试题。野火征途Pro开发板FPGA数字时钟(秒表)设计学习心得(1)_第1张图片

 一开始一头雾水,野火教程只讲到动态扫描,自己在网上找秒表的教程,很少,并且野火的板子是使用74hc595驱动数码管,这点跟其他平台的板子不太一样。参考了明德扬一个教程里面的设计方法。

实验目标是生成一个时分秒时钟,设计思路是分别对时分秒的个位,十位进行设计,正好对应6段数码管。计时设计完成之后,直接用顶层模块调用shizhong模块和74hc595驱动模块,74hc595驱动原理野火有详细教程,话不多说直接上代码。

 时钟设计

module  shizhong
(
input   sys_clk,//50MHz
input   sys_rst_n,//复位信号
output  wire[7:0]   seg,//数码管段选信号,
output  wire[5:0]   sel//位选信号
);
parameter   CNT_MAX = 50_000;//动态扫描计时最大值
parameter   CNT_MAX_1S = 50_000_000;//1s计数器计时最大值
reg[15:0]   cnt_1ms;//动态扫描
reg[2:0]    cnt_6;//对动态扫描计时6次,方便位选
reg[5:0]    sel_reg;//位选信号中间变量
reg[25:0]   cnt_1s;//1s计数器
reg[3:0]    m_g;//秒个位
reg[2:0]    m_s;
reg[3:0]    f_g;
reg[3:0]    f_s;
reg[3:0]    s_g;
reg[3:0]    s_s;
reg[7:0]    seg_reg;//段选信号中间变量
reg[3:0]    x;//对时个位变量法计数最大值,因为时个位的跳转可能为9(9,19),也可能为3(23)
reg[3:0]    data;//很重要,将时分秒各数据赋值到数码管的中间变量



//设置动态扫描时间为1ms的计时器cnt_1ms
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n==0)
        cnt_1ms <= 0;
    else if(cnt_1ms==CNT_MAX-1)
        cnt_1ms <= 0;
    else  
        cnt_1ms <= cnt_1ms + 1;

always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n==0)
        cnt_6 <= 0;
    else if((cnt_1ms==CNT_MAX-1)&&(cnt_6 > 3'd4))  
        cnt_6 <= 0;
    else if(cnt_1ms==CNT_MAX-1)
        cnt_6 <= cnt_6 + 1;    
    else
        cnt_6 <= cnt_6;
//位选信号sel_reg 赋值
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n==0)
        sel_reg <= 6'b000_001;
    /*  else if(cnt_6==0) 
        sel_reg <= 6'b000_001;
     else if(cnt_6==1) 
        sel_reg <= 6'b000_010;
     else if(cnt_6==2) 
        sel_reg <= 6'b000_100;
     else if(cnt_6==3) 
        sel_reg <= 6'b001_000;
     else if(cnt_6==4) 
        sel_reg <= 6'b010_000;
     else  
        sel_reg <= 6'b100_000; */
    else case(cnt_6)    
        3'd0:sel_reg <= 6'b000_001;
        3'd1:sel_reg <= 6'b000_010;
        3'd2:sel_reg <= 6'b000_100;
        3'd3:sel_reg <= 6'b001_000;
        3'd4:sel_reg <= 6'b010_000;
        3'd5:sel_reg <= 6'b100_000;
        default:sel_reg <= 6'b000_001;
        
        endcase
//秒设计
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n==0)
        cnt_1s <= 0;
    else if(cnt_1s==CNT_MAX_1S-1)
        cnt_1s <= 0;
    else
        cnt_1s <= cnt_1s + 1;
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n==0)
        m_g <= 0;
    else if((cnt_1s==CNT_MAX_1S-1)&&(m_g==4'd9))
        m_g <= 0;
    else if(cnt_1s==CNT_MAX_1S-1) 
        m_g <= m_g +1;
   
    else 
        m_g <= m_g;  
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n==0)
        m_s <= 0;
    else if((cnt_1s==CNT_MAX_1S-1)&&(m_s==4'd5)&&(m_g==4'd9))
        m_s <= 0;    
    else if((cnt_1s==CNT_MAX_1S-1)&&(m_g==4'd9)) 
        m_s <= m_s +1;
    
    else 
        m_s <= m_s;
//分设计        
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n==0)
        f_g <= 0;
    else if((cnt_1s==CNT_MAX_1S-1)&&(f_g==4'd9)&&(m_s==4'd5)&&(m_g==4'd9))
        f_g <= 0;    
    else if((cnt_1s==CNT_MAX_1S-1)&&(m_s==4'd5)&&(m_g==4'd9)) 
        f_g <= f_g +1;
    
    else 
        f_g <= f_g;  
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n==0)
        f_s <= 0;
    else if((cnt_1s==CNT_MAX_1S-1)&&(f_s==4'd5)&&(f_g==4'd9)&&(m_s==4'd5)&&(m_g==4'd9))
        f_s <= 0;    
    else if((cnt_1s==CNT_MAX_1S-1)&&(f_g==4'd9)&&(m_s==4'd5)&&(m_g==4'd9)) 
        f_s <= f_s +1;
    
    else 
        f_s <= f_s;        
//时设计
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n==0)
        s_g <= 0;
    else if((cnt_1s==CNT_MAX_1S-1)&&(s_g==x-1)&&(f_s==4'd9)&&(f_g==4'd9)&&(m_s==4'd5)&&(m_g==4'd9))
        s_g <= 0;    
    else if((cnt_1s==CNT_MAX_1S-1)&&(f_s==4'd9)&&(f_g==4'd9)&&(m_s==4'd5)&&(m_g==4'd9)) 
        s_g <= s_g +1;
    
    else 
        s_g <= s_g;  
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n==0)
        s_s <= 0;
    else if((cnt_1s==CNT_MAX_1S-1)&&(s_s==4'd2)&&(s_g==x-1)&&(f_g==4'd9)&&(m_s==4'd5)&&(m_g==4'd9))
        s_s <= 0;    
    else if((cnt_1s==CNT_MAX_1S-1)&&(s_g==x-1)&&(f_g==4'd9)&&(m_s==4'd5)&&(m_g==4'd9))
        s_s <= s_s +1;
    
    else 
        s_s <= s_s;
always@(*) begin
        if(s_s==4'd2)
            x = 4'd4;
        else    
            x = 4'd10;
        end  
     
//段选seg_reg
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n==0)
        seg_reg <= 8'hc0;
    else case(data)
    4'd0:seg_reg <= 8'hc0;
    4'd1:seg_reg <= 8'hf9;
    4'd2:seg_reg <= 8'ha4;
    4'd3:seg_reg <= 8'hb0;
    4'd4:seg_reg <= 8'h99;
    4'd5:seg_reg <= 8'h92;
    4'd6:seg_reg <= 8'h82;
    4'd7:seg_reg <= 8'hf8;
    4'd8:seg_reg <= 8'h80;
    4'd9:seg_reg <= 8'h90;
    default:seg_reg <= 8'hc0;
    endcase
always@(*) begin
    case(cnt_6)
    0:data = m_g;
    1:data = m_s;
    2:data = f_g;
    3:data = f_s;
    4:data = s_g;
    5:data = s_s;
    default:data = m_g;
    endcase
end
  assign sel = sel_reg;
  assign seg = seg_reg;
        
        
endmodule

74HC595模块 

module  hc595_ctl
(
    input   wire            clk     ,   //系统时钟,频率50MHz
    input   wire            rst_n   ,   //复位信号,低有效
    input   wire    [5:0]   smg_sel         ,   //数码管位选信号
    input   wire    [7:0]   smg_dig         ,   //数码管段选信号
    
    output  reg             stcp        ,   //数据存储器时钟
    output  reg             shcp        ,   //移位寄存器时钟
    output  reg             ds          ,   //串行数据输入
    output  wire            oe              //使能信号,低有效
);


reg     [1:0]   cnt_4   ;   //分频计数器
reg     [3:0]   cnt_bit ;   //传输位数计数器

//wire  define
wire    [13:0]  data    ;   //数码管信号寄存

//将数码管信号寄存
assign  data = {smg_dig[0],smg_dig[1],smg_dig[2],smg_dig[3],smg_dig[4],smg_dig[5],smg_dig[6],smg_dig[7],smg_sel};

//将复位取反后赋值给其即可
assign oe = ~rst_n;

//分频计数器:0~3循环计数
always@(posedge clk or  negedge rst_n)
    if(rst_n == 1'b0)
        cnt_4 <=  2'd0;
    else    if(cnt_4 == 2'd3)
        cnt_4 <=  2'd0;
    else
        cnt_4 <=  cnt_4 +   1'b1;

//cnt_bit:每输入一位数据加一
always@(posedge clk or  negedge rst_n)
    if(rst_n == 1'b0)
        cnt_bit   <=  4'd0;
    else    if(cnt_4 == 2'd3 && cnt_bit == 4'd13)
        cnt_bit   <=  4'd0;
    else    if(cnt_4  ==  2'd3)
        cnt_bit   <=  cnt_bit   +   1'b1;
    else
        cnt_bit   <=  cnt_bit;

//stcp:14个信号传输完成之后产生一个上升沿
always@(posedge clk or  negedge rst_n)
    if(rst_n == 1'b0)
        stcp    <=  1'b0;
    else    if(cnt_bit == 4'd13 && cnt_4 == 2'd3)
        stcp    <=  1'b1;
    else
        stcp    <=  1'b0;

//shcp:产生四分频移位时钟
always@(posedge clk or  negedge rst_n)
    if(rst_n == 1'b0)
        shcp    <=  1'b0;
    else    if(cnt_4 >= 4'd2)
        shcp    <=  1'b1;
    else
        shcp    <=  1'b0;

//ds:将寄存器里存储的数码管信号输入即
always@(posedge clk or  negedge rst_n)
    if(rst_n == 1'b0)
        ds  <=  1'b0;
    else    if(cnt_4 == 2'd0)
        ds  <=  data[cnt_bit];
    else
        ds  <=  ds;

endmodule

总结:从三月份开始学数电,四五月份开始断断续续学Verilog,现在自己能上手操作一些东西了,对于我这个零基础转行的人来说有莫大的欣慰。时钟设计对我来说真的是不小的挑战,通过这一周的找资料设计,对调用模块,写仿真代码,跑波形,管教绑定学习有非常大的帮助。总之FPGA的学习是一个操作性很强的过程,在不断的试错找bug,调试,再试错的过程中学习是最快的。多上手,遇到问题就解决,相信一定能入行。

你可能感兴趣的:(fpga开发)