感谢发烧友爱好者和小眼睛科技公司提供的FPGA测试机会。前面已经完成了测试一和测试二,今天来完成第3个测试。这次的目的是实现四个数码管可以显示不同的数字,按键 K1 控制第一个数码管,按一下数字加 1,显示从 0 到 9,按键 K2 控制第二个数码管,按一下数字加 1,显示从 0 到 9,类似的,按键 K3 控制第三个数码管,按键 K4 控制第四个数码管。在《MES2KG开发板实验指导》中提供了相应的说明,这次我们还是参考相关介绍来介绍demo的工作原理,并做一些补充。
程序包括按键处理和数码管显示两个主要部分,下面分别介绍。
键盘处理部分包括键盘防抖和键盘计数两个主要部分。键盘防抖在第2次测试已经介绍了,这里只讲计数部分。
计数的原理很简单,就是按键时如果当前值是9,就重置为0,否则当前值加一。
`define UD #1
module key_cnt
(
input clk,//40M,25ns
input rstn_key,
input key,
output reg [3:0]key_times
);
reg key_reg;
always @(posedge clk)
begin
key_reg <= `UD key;
end
always @(posedge clk )
begin
if(key_reg&&~key&&key_times==4'd9)
key_times <=`UD 4'd0;
else if(key_reg&&~key)
key_times <=`UD key_times + 1'b1;
end
endmodule
MES2KG 底板的数码管使用共阳数码管。数码管基本单元是发光二极管。MES2KG 底板采用的是8段数码管,它比七段数码管多一个发光二极管单元(多一个小数点显示)。共阳数码管是指将所有发光二极管的阳极接到一起形成公共阳极(COM)的数码管。共阳数码管在应用时应将公共极 COM接到+5V或+3.3V,当某一字段发光二极管的阴极为低电平时,相应字段就点亮。当某一字段的阴极为高电平时,相应字段就不亮。
数码管显示出 0~9,代码如下,通过传递要显示的数值给到 key 上,可显示对应数值,sel 选择对应的数码管,如需 4 个如果要显示同样的字符,仅需将dig 的 4 位全部置 1,需要做好对应编码。
`define UD #1
module seq_control
(
input [1:0]sel,
input [3:0]key,
output reg [3:0]dig,
output reg [7:0]smg
);
/*===================================================
位选择映射
===================================================*/
always @(*)
begin
case(sel)
2'd0:dig = 4'b0001;
2'd1:dig = 4'b0010;
2'd2:dig = 4'b0100;
2'd3:dig = 4'b1000;
default:dig = 4'b0000;
endcase
end
//共阳极数码管,为0有效,即点亮
always @(*)
begin
case(key)
4'd0:smg = 8'b1000_0001;//"0"
4'd1:smg = 8'b1100_1111;//"1"
4'd2:smg = 8'b1001_0010;//"2"
4'd3:smg = 8'b1000_0110;//"3"
4'd4:smg = 8'b1100_1100;//"4"
4'd5:smg = 8'b1010_0100;//"5"
4'd6:smg = 8'b1010_0000;//"6"
4'd7:smg = 8'b1000_1111;//"7"
4'd8:smg = 8'b1000_0000;//"8"
4'd9:smg = 8'b1000_0100;//"9"
default:smg = 8'b1111_1111;
endcase
end
endmodule
硬件连接上无法同一个时间点显示出不同的数值,所以可以通过刷新显示的方式造成视觉上同时显示了不同的数值,原理和电影显示的原理相同,采用大于 25Hz的刷新频率,闪烁基本消失。实验中取刷新率为 100KHz。
`define UD #1
module div_clk
(
input clk,//40M
output clk_100khz//0.1M
);
reg [8:0]cnt;
always @(posedge clk)
begin
if(cnt == 9'd399)
cnt<= `UD 9'd0;
else
cnt <= `UD cnt + 1'b1;
end
reg flag=1'b0;
always @(posedge clk)
begin
if(cnt == 9'd199)
flag <= `UD 1'b1;
else if(cnt == 9'd399)
flag <= `UD 1'b0;
end
assign clk_100khz = flag;
endmodule
前面只用了7段数码管显示,小数点没有用上。我简单地修改了一下程序,可以让其中一个数码管显示小数点。代码如下:
//共阳极数码管,为0有效,即点亮
always @(*)
begin
case(key)
4'd0:smg = 8'b1000_0001;//"0"
4'd1:smg = 8'b1100_1111;//"1"
4'd2:smg = 8'b1001_0010;//"2"
4'd3:smg = 8'b1000_0110;//"3"
4'd4:smg = 8'b1100_1100;//"4"
4'd5:smg = 8'b1010_0100;//"5"
4'd6:smg = 8'b1010_0000;//"6"
4'd7:smg = 8'b1000_1111;//"7"
4'd8:smg = 8'b1000_0000;//"8"
4'd9:smg = 8'b1000_0100;//"9"
default:smg = 8'b1111_1111;
endcase
// 如果sel变量为2'd2,则清除掉smg的最高位
if (sel == 2'd2) begin
smg[7] = 1'b0;
end
end
然后重新编译、下载程序即可。
下面的视频就是最终实现的效果。
更多回帖