| |
代码分析:
`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
module seg7(
clk,rst_n,
ds_stcp,ds_shcp,ds_data
);
input clk; //
input rst_n; //复位信号输入,低有效
output ds_stcp; //74HC595的并行时钟输入,上升沿将当前串行输入数据并行输出
output ds_shcp; //74HC595的串行时钟输入,上升沿锁存当前串行输入数据
output ds_data; //74HC595的串行数据输入
//数码管显示 0~F 对应段选输出
parameter SEG_NUM0
= 8'h
SEG_NUM1 = 8'h06,//f9,
SEG_NUM2 = 8'h5b,//a4,
SEG_NUM3
= 8'h
SEG_NUM4 = 8'h66,//99,
SEG_NUM5 = 8'h6d,//92,
SEG_NUM6 = 8'h7d,//82,
SEG_NUM7 = 8'h07,//F8,
SEG_NUM8
= 8'h
SEG_NUM9
= 8'h
SEG_NUMA = 8'h77,//88,
SEG_NUMB
= 8'h
SEG_NUMC = 8'h39,//c6,
SEG_NUMD = 8'h5e,//a1,
SEG_NUME = 8'h79,//86,
SEG_NUMF = 8'h71;//8e;
//数码管位选 0~3 对应输出
parameter SEG_WE0 = 4'b1110,
SEG_WE1 = 4'b1101,
SEG_WE2 = 4'b1011,
SEG_WE3 = 4'b0111;
//递增数据产生单元
reg[24:0] cnt_1s; //1s计数器,0-24999999(时钟频率25MHz)
reg[15:0] dis_data; //数码管显示数据,16位
//1s定时计数
always @(posedge clk or negedge rst_n)
if(!rst_n) cnt_1s <= 25'd0;
else if(cnt_1s == 25'd24_999_999) cnt_1s <= 25'd0;
else cnt_1s <= cnt_1s+1'b1;
wire done_1s = (cnt_1s == 25'd24_999_999); //1s定时到标志位,高有效一个时钟周期
//显示数据每秒递增
always @(posedge clk or negedge rst_n)
if(!rst_n) dis_data <= 16'd0;
else if(done_1s) dis_data <= dis_data+1'b1;
//-------------------------------------------------
//分时显示数据控制单元
reg[7:0] seg_num; //当前显示数据
reg[7:0] seg_duan; //7段数码管段选信号(包括小数点为8段)
reg[3:0] seg_wei; //7段数码管位选信号
reg[7:0] cnt_4; //分时计数器,每个clk自加“
always @(posedge clk or negedge rst_n)
if(!rst_n) cnt_4 <= 8'd0;
else cnt_4 <= cnt_4+1'b1;
//显示数据,1s内seg_num不变,直到dis_data变化此信号才发生变化
always @(posedge clk or negedge rst_n)
if(!rst_n) seg_num <= 8'h00;
else
case(cnt_4[7:6])
2'b00: seg_num <= dis_data[3:0]; //00h~3fh
2'b01: seg_num <= dis_data[7:4]; //40h~7fh
2'b10: seg_num <= dis_data[11:8]; //80h~bfh
2'b11: seg_num <= dis_data[15:12]; //c0h~ffh
default: seg_num <= 8'h00;
endcase
//段选数据译码,由于seg_num在1s内保持不变,故此信号1s内保持不变
always @(posedge clk or negedge rst_n)
if(!rst_n) seg_duan <= 8'h00;
else
case(seg_num)
4'h0: seg_duan <= SEG_NUM0;
4'h1: seg_duan <= SEG_NUM1;
4'h2: seg_duan <= SEG_NUM2;
4'h3: seg_duan <= SEG_NUM3;
4'h4: seg_duan <= SEG_NUM4;
4'h5: seg_duan <= SEG_NUM5;
4'h6: seg_duan <= SEG_NUM6;
4'h7: seg_duan <= SEG_NUM7;
4'h8: seg_duan <= SEG_NUM8;
4'h9: seg_duan <= SEG_NUM9;
4'ha: seg_duan <= SEG_NUMA;
4'hb: seg_duan <= SEG_NUMB;
4'hc: seg_duan <= SEG_NUMC;
4'hd: seg_duan <= SEG_NUMD;
4'he: seg_duan <= SEG_NUME;
4'hf: seg_duan <= SEG_NUMF;
default: ;
endcase
//位选译码,2的8次方时间分成4段,每段时间内选通一个7段led管
always @ (cnt_4[7:6])
case(cnt_4[7:6])
2'b00: seg_wei <= SEG_WE0;
2'b01: seg_wei <= SEG_WE1;
2'b10: seg_wei <= SEG_WE2;
2'b11: seg_wei <= SEG_WE3;
default: seg_wei <= 4'b1111;
endcase
//-------------------------------------------------
//74HC95驱动译码
reg ds_stcpr; //74HC595的并行时钟输入,上升沿将当前串行输入数据并行输出
reg ds_shcpr; //74HC595的串行时钟输入,上升沿锁存当前串行输入数据
reg ds_datar; //74HC595的串行数据输入
//串行移位时钟产生,在cnt_4所处区间上时,即每隔20H个clk周期,ds_shcpr每个clk都会翻转一次,而剩下20H个周期保持之前的状态不变,在cnt_4的计时大周期内发生4次
always @(posedge clk or negedge rst_n)
if(!rst_n) ds_shcpr <= 1'b0;
else if((cnt_4 > 8'h02 && cnt_4 <= 8'h22) || (cnt_4 > 8'h42 && cnt_4 <= 8'h62)
|| (cnt_4 > 8'h82 && cnt_4 <= 8'ha2) || (cnt_4 > 8'hc2 && cnt_4 <= 8'he2))
ds_shcpr <= ~ds_shcpr;
//串行移位数据产生,在cnt_4的02—22期间,每个clk都将seg_duan,seg_wei的1位送给ds_datar,在一个cnt_4计时大周期内总共送4次
always @(posedge clk or negedge rst_n)
if(!rst_n) ds_datar <= 1'b0;
else
case(cnt_4)
8'h02,8'h42,8'h82,8'hc2: ds_datar <= seg_duan[7];
8'h04,8'h44,8'h84,8'hc4: ds_datar <= seg_duan[6];
8'h06,8'h46,8'h86,8'hc6: ds_datar <= seg_duan[5];
8'h08,8'h48,8'h88,8'hc8: ds_datar <= seg_duan[4];
8'h
8'h
8'h0e,8'h4e,8'h8e,8'hce: ds_datar <= seg_duan[1];
8'h10,8'h50,8'h90,8'hd0: ds_datar <= seg_duan[0];
8'h
8'h
8'h1e,8'h5e,8'h9e,8'hde: ds_datar <= seg_wei[2];
8'h20,8'h60,8'ha0,8'he0: ds_datar <= seg_wei[3];
default: ;
endcase
//并行移位时钟产生,即在23,63,a3,e3时刻置“
always @(posedge clk or negedge rst_n)
if(!rst_n) ds_stcpr <= 1'b0;
else if((cnt_4 == 8'h02) || (cnt_4 == 8'h42) || (cnt_4 == 8'h82) || (cnt_4 == 8'hc2)) ds_stcpr <= 1'b0;
else if((cnt_4 == 8'h23) || (cnt_4 == 8'h63) || (cnt_4 == 8'ha3) || (cnt_4 == 8'he3)) ds_stcpr <= 1'b1;
wire ds_stcp = ds_stcpr;
wire ds_shcp = ds_shcpr;
wire ds_data = ds_datar;
endmodule
-------------------------------------------------------------------------------------------------------------------
1.74HC595相关
2.模块相关
信号定义:
信号名称 |
方向 |
描述 |
Clk |
Input |
时钟信号,25MHz |
Rst_n |
Input |
复位信号,低有效 |
Ds_stcp |
Output |
74HC595并行时钟输入,上升沿将当前串行输入数据并行输出 |
Ds_shcp |
Output |
74HC595串行时钟输入,上升沿所存当前串行输入数据 |
Da_data |
Output |
74HC595的串行输入数据 |
2.程序设计相关
①最开始参数化定义了SEG_NUM0—SEG_NUMF,对应7段数码管的显示,再定义了SEG_WE0—SEG_WE3,对应数码管的位选
②时钟为25MHz,用cnt_1s完成1s计时,1s计时到了,使done_1s信号有效,并使dis_data每秒“+1”
③之后的代码参考下面这张图来说明
Cnt_4每个clk周期计数,其总的计数周期可以分为4段时间,分时扫描显示数据和位选信号。其中seg_num,seg_duan信号在1s时间内不变。
④至于ds_shcp,ds_data,ds_stcp信号的产生就如下图所示
具体的时序就参考特权前辈给的资料里面的对74HC595芯片的资料描述。