记录学习日常,此实验借鉴正点原子的例程,这次代码好长呀。第一个模块是一个计数器,让数据100ms变化一次,设置一个100ms计数器与一个计数满的标志信号。上代码:
module count(
input clk,
input rst_n,
output reg en,
output reg [5:0]point,
output reg [19:0]data,
output reg signal
);
reg flag;
reg[22:0]cnt;
//100ms数据变化一次
parameter MAX_CNT = 23'd5000_000;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
flag <= 1'b0;
cnt <= 23'd0;
end
else if(cnt < MAX_CNT - 1)begin
flag <= 1'b0;
cnt <= cnt + 1'b1;
end
else begin
flag <= 1'b1;
cnt <= 23'd0;
end
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
en <= 1'b0;
point <= 6'b0;
data <= 20'd0;
signal <= 1'b0;
end
else begin
en <= 1'b1;
signal <= 1'b0;
point <= 6'b0;
if(flag)begin
if(data < 20'd999_999)
data <= data + 1'b1;
else
data <= 20'd0;
end
end
endmodule
第二个模块代码量更大;第一步因为数码管的时钟频率为5MHZ所以对于50MHZ的开发板来说需要设置一个十分频时钟,设置一分频计数器来产生分频时钟。时钟计数器最大值应该是10/2-1当计数满4时分频时钟翻转。
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
dri_clk <= 1'b0;
clk_cnt <= 4'd0;
end
else if(clk_cnt == CLK_DIVIDE/2-1'b1)begin
dri_clk <= ~dri_clk;
clk_cnt <= 4'd0;
end
else begin
dri_clk <= 1'b0;
clk_cnt <= clk_cnt + 1'b1;
end
第二部分:总共6位数码管最大数位999_999,对于每个数取模为:
assign data0 = data & 4'd10;
assign data1 = data / 4'd10 %4'd10;
assign data2 = data / 7'd100 %4'd10;
assign data3 = data / 10'd1000 %4'd10;
assign data4 = data / 14'd10000 %4'd10;
assign data5 = data / 17'd100000;
第三部分:对于定义【23:0】num来说是因为每四位数组成一个BCD码,这里我不是很清楚为什么要有这一步。还有一种说法是:一个数码管需要显示16种状态所以一个数码管需要有【3:0】的位宽。有大佬明白的可以指导下。
always@(posedge dri_clk or negedge rst_n)
if(!rst_n)
num <= 24'd0;
else begin
if(data5 || point[5])begin
num[23:20] <= data5;
num[19:16] <= data4;
num[15:12] <= data3;
num[11:8] <= data2;
num[7:4] <= data1;
num[3:0] <= data0;
end
else begin
if(data4 || point[4])begin
num[19:0] <= {data4,data3,data2,data1,data0};
if(signal)
num[23:20] <= 4'd11;
else
num[23:20] <= 4'd10;
end
else begin
if(data3 || point[3])begin
num[15:0] <= {data3,data2,data1,data0};
num[23:20] <= 4'd10;
if(signal)
num[19:16] <= 4'd11;
else
num[19:16] <= 4'd10;
end
else begin
if(data2 || point[2])begin
num[11:0] <= {data2,data1,data0};
num[23:16] <= {2{4'd10}};
if(signal)
num[15:12] <= 4'd11;
else
num[15:12] <= 4'd10;
end
else begin
if(data1 || point[1])begin
num[7:0] <= {data1,data0};
num[23:12] <= {3{4'd10}};
if(signal)
num[11:8] <= 4'd11;
else
num[11:8] <= 4'd10;
end
else begin
num[3:0] <= data0;
num[23:8] <= {4{4'd10}};
if(signal)
num[7:4] <= 4'd11;
else
num[7:4] <= 4'd10;
end
end
end
end
end
end
第四部分:
//让数码管亮1ms
always@(posedge dri_clk or negedge rst_n)
if(!rst_n)begin
flag <= 1'b0;
cnt0 <= 13'd0;
end
else if(cnt0 < MAX_NUM - 1)begin
flag <= 1'b0;
cnt0 <= cnt0 + 1'b1;
end
else begin
flag <= 1'b1;
cnt0 <= 13'd0;
end
//显示当前显示的数码管
always@(posedge dri_clk or negedge rst_n)
if(!rst_n)
cnt_sel <= 3'b0;
else if(flag)begin
if(cnt_sel < 3'd5)
cnt_sel <= cnt_sel + 1'b1;
else
cnt_sel <= 3'b0;
end
else
cnt_sel <= cnt_sel;
接下来就要写数码管显示的数据部分:
always @ (posedge dri_clk or negedge rst_n) begin
if(!rst_n) begin
sel <= 6'b111111; //位选信号低电平有效
num_disp <= 4'b0;
dot_disp <= 1'b1; //共阳极数码管,低电平导通
end
else begin
if(en) begin
case (cnt_sel)
3'd0 :begin
sel <= 6'b111110; //显示数码管最低位
num_disp <= num[3:0] ; //显示的数据
dot_disp <= ~point[0]; //显示的小数点
end
3'd1 :begin
sel <= 6'b111101; //显示数码管第1位
num_disp <= num[7:4] ;
dot_disp <= ~point[1];
end
3'd2 :begin
sel <= 6'b111011; //显示数码管第2位
num_disp <= num[11:8];
dot_disp <= ~point[2];
end
3'd3 :begin
sel <= 6'b110111; //显示数码管第3位
num_disp <= num[15:12];
dot_disp <= ~point[3];
end
3'd4 :begin
sel <= 6'b101111; //显示数码管第4位
num_disp <= num[19:16];
dot_disp <= ~point[4];
end
3'd5 :begin
sel <= 6'b011111; //显示数码管最高位
num_disp <= num[23:20];
dot_disp <= ~point[5];
end
default :begin
sel <= 6'b111111;
num_disp <= 4'b0;
dot_disp <= 1'b1;
end
endcase
end
else begin
sel <= 6'b111111; //使能信号为0时,所有数码管均不显示
num_disp <= 4'b0;
dot_disp <= 1'b1;
end
end
end
最后数码管段选:
always @ (posedge dri_clk or negedge rst_n) begin
if (!rst_n)
seg_led <= 8'hc0;
else begin
case (num_disp)
4'd0 : seg_led <= {dot_disp,7'b1000000}; //显示数字 0
4'd1 : seg_led <= {dot_disp,7'b1111001}; //显示数字 1
4'd2 : seg_led <= {dot_disp,7'b0100100}; //显示数字 2
4'd3 : seg_led <= {dot_disp,7'b0110000}; //显示数字 3
4'd4 : seg_led <= {dot_disp,7'b0011001}; //显示数字 4
4'd5 : seg_led <= {dot_disp,7'b0010010}; //显示数字 5
4'd6 : seg_led <= {dot_disp,7'b0000010}; //显示数字 6
4'd7 : seg_led <= {dot_disp,7'b1111000}; //显示数字 7
4'd8 : seg_led <= {dot_disp,7'b0000000}; //显示数字 8
4'd9 : seg_led <= {dot_disp,7'b0010000}; //显示数字 9
4'd10: seg_led <= 8'b11111111; //不显示任何字符
4'd11: seg_led <= 8'b10111111; //显示负号(-)
default:
seg_led <= {dot_disp,7'b1000000};
endcase
end
end
这些是我对动态数码管的理解。大家可以一起讨论。