![]()
![]()
module Segment_scan
(
input clk,
input rst_n,
input [3:0] dat_1, //SEG1 显示的数据输入,左边第一个数码管
input [3:0] dat_2,
input [3:0] dat_3,
input [3:0] dat_4,
input [3:0] dat_5,
input [3:0] dat_6,
input [3:0] dat_7,
input [3:0] dat_8, //SEG8 显示的数据输入,最右边的数码管
input [7:0] dat_en, //数码管数据位显示使能,[MSB~LSB]=[SEG1~SEG8],高有效
input [7:0] dot_en, //数码管小数点位显示使能,[MSB~LSB]=[SEG1~SEG8],高有效
output reg seg_rck,
output reg seg_sck,
output reg seg_din//595发送数据是在sck的作用下一位一位的移位A-B-C-D-E-F-G-H,RCK的作用下并行输出
);
localparam CNT_40KHz = 300;
//1ms 一个数码管刷新一次,8个数码管8ms刷新一次,1s刷新125次,,视觉暂留。
//1ms/16=62.5us,一个周期刷新小于62.5us,取50us,敏感变量的周期就应该是25us,频率就是40k
localparam IDLE = 3'd0;
localparam MAIN = 3'd1;
localparam WRITE = 3'd2;
localparam LOW = 1'b0;
localparam HIGH = 1'b1;
//创建数码管的字库,字库数据依段码顺序有关
//这里字库数据[MSB~LSB]={G,F,E,D,C,B,A}
reg[6:0] seg [15:0]; //共阴极
always @(negedge rst_n) begin
seg[0] = 7'h3f; // 0
seg[1] = 7'h06; // 1
seg[2] = 7'h5b; // 2
seg[3] = 7'h4f; // 3
seg[4] = 7'h66; // 4
seg[5] = 7'h6d; // 5
seg[6] = 7'h7d; // 6
seg[7] = 7'h07; // 7
seg[8] = 7'h7f; // 8
seg[9] = 7'h6f; // 9
seg[10] = 7'h77; // A
seg[11] = 7'h7c; // b
seg[12] = 7'h39; // C
seg[13] = 7'h5e; // d
seg[14] = 7'h79; // E
seg[15] = 7'h71; // F
end
//计数器对系统时钟信号进行计数
reg [9:0] cnt = 1'b0;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt <= 1'b0;
else if(cnt >=CNT_40KHz-1)
cnt <= 1'b0;
else
cnt <= cnt + 1'b1;
end
//根据计数器计数的周期产生分频的脉冲信号
reg clk_40khz = 1'b0;
always@(posedge clk or negedge rst_n)
if(!rst_n)
clk_40khz <= 1'b0;
else if(cnt < (CNT_40KHz>>1))
clk_40khz <= 1'b0;
else
clk_40khz <= 1'b1;
//使用状态机完成数码管的扫描和74HC595时序的实现
reg [15:0] data;
reg [2:0] cnt_main;
reg [5:0] cnt_write;
reg [2:0] state = IDLE;
always@(posedge clk_40khz or negedge rst_n)
begin
if(!rst_n)
begin
state <= IDLE;
cnt_main <= 3'd0; cnt_write <= 6'd0;
seg_din <= 1'b0; seg_sck <= LOW; seg_rck <= LOW;
end
else
begin
case(state)
IDLE:begin//IDLE作为第一个状态,相当于软件复位
state <= MAIN;
cnt_main <= 3'd0;cnt_write <= 6'd0;
seg_din <= 1'b0; seg_sck <= LOW; seg_rck <= LOW;
end
MAIN:begin
cnt_main <= cnt_main + 1'b1;
state <= WRITE; //在配置完发给74HC595的数据同时跳转至WRITE状态,完成串行时序
case(cnt_main)
//对8位数码管逐位扫描
3'd0: data <= {{dot_en[7],seg[dat_1]},dat_en[7]?8'hfe:8'hff};//发送数据高位开始,所以A连接左边第一位数码管,也就是SEG1
3'd1: data <= {{dot_en[6],seg[dat_2]},dat_en[6]?8'hfd:8'hff};
3'd2: data <= {{dot_en[5],seg[dat_3]},dat_en[5]?8'hfb:8'hff};
3'd3: data <= {{dot_en[4],seg[dat_4]},dat_en[4]?8'hf7:8'hff};
3'd4: data <= {{dot_en[3],seg[dat_5]},dat_en[3]?8'hef:8'hff};
3'd5: data <= {{dot_en[2],seg[dat_6]},dat_en[2]?8'hdf:8'hff};
3'd6: data <= {{dot_en[1],seg[dat_7]},dat_en[1]?8'hbf:8'hff};
3'd7: data <= {{dot_en[0],seg[dat_8]},dat_en[0]?8'h7f:8'hff};
default: data <= {8'h00,8'hff};
endcase
end
WRITE:begin
if(cnt_write >= 6'd33)
cnt_write <= 1'b0;
else
cnt_write <= cnt_write +1'b1;
case(cnt_write)
//74HC595是串行转并行的芯片,3路输入可产生8路输出,而且可以级联使用
//74HC595的时序实现,参考74HC595的芯片手册
6'd0: begin seg_sck <= LOW; seg_din <= data[15];end
6'd1: begin seg_sck <= HIGH; end
6'd2: begin seg_sck <= LOW; seg_din <= data[14];end
6'd3: begin seg_sck <= HIGH; end
6'd4: begin seg_sck <= LOW; seg_din <= data[13];end
6'd5: begin seg_sck <= HIGH; end
6'd6: begin seg_sck <= LOW; seg_din <= data[12];end
6'd7: begin seg_sck <= HIGH; end
6'd8: begin seg_sck <= LOW; seg_din <= data[11];end
6'd9: begin seg_sck <= HIGH; end
6'd10: begin seg_sck <= LOW; seg_din <= data[10];end
6'd11: begin seg_sck <= HIGH; end
6'd12: begin seg_sck <= LOW; seg_din <= data[9];end
6'd13: begin seg_sck <= HIGH; end
6'd14: begin seg_sck <= LOW; seg_din <= data[8];end
6'd15: begin seg_sck <= HIGH; end
6'd16: begin seg_sck <= LOW; seg_din <= data[7];end
6'd17: begin seg_sck <= HIGH; end
6'd18: begin seg_sck <= LOW; seg_din <= data[6];end
6'd19: begin seg_sck <= HIGH; end
6'd20: begin seg_sck <= LOW; seg_din <= data[5];end
6'd21: begin seg_sck <= HIGH; end
6'd22: begin seg_sck <= LOW; seg_din <= data[4];end
6'd23: begin seg_sck <= HIGH; end
6'd24: begin seg_sck <= LOW; seg_din <= data[3];end
6'd25: begin seg_sck <= HIGH; end
6'd26: begin seg_sck <= LOW; seg_din <= data[2];end
6'd27: begin seg_sck <= HIGH; end
6'd28: begin seg_sck <= LOW; seg_din <= data[1];end
6'd29: begin seg_sck <= HIGH; end
6'd30: begin seg_sck <= LOW; seg_din <= data[0];end
6'd31: begin seg_sck <= HIGH; end
6'd32: begin seg_rck <= HIGH; end
6'd33: begin seg_sck <= LOW; seg_rck <= LOW;end
default:;
endcase
end
default: state<= IDLE;
endcase
end
end
endmodule