标签:wire led FPGA clk 数码管 按键 rst reg
本工程实现三个数码管界面显示,采用按键二切换界面,每个界面另外两个按键有不同的功能,需要其他功能的,可根据需求更改,同时界面二带有一个故障检测功能,当在界面二利用按键一和按键三组合出1001是,系统不再显示数字,实现故障功能。话不多说,上代码。
实验工程目录
top
顶层文件变量定义
module sy_top(
sys_clk,
sys_rst_n,
key_in,
sel, // 数码管位选信号
seg, // 数码管段选信号
led
);
//输入定义
input sys_clk;
input sys_rst_n;
input [3:0] key_in;
//输出定义
output [5:0] sel;
output [7:0] seg;
output [3:0] led;
//寄存器定义
//中间变量定义
wire [19:0] data; // 数码管显示的数字
wire [5:0] point; // 数码管小数点的位置
wire en; // 数码管显示使能信号
wire sign; // 符号显示
wire total; //总里程数
wire [3:0] led_sel; //led片选
wire [3:0] menu_show; //数码管显示界面控制
wire [11:0] speed; //当前速度显示
实例化数码管
seg_led u_seg_led(
.clk(sys_clk),
.rst_n(sys_rst_n),
.data(data),
.point(point),
.en(~en),
.sign(sign),
.sel(sel),
.seg(seg),
.menu_show(menu_show),
.speed(speed)
);
实例化按键
下面展示一些 内联代码片
。
// A code block
var foo = 'bar';
key_scan u_key_scan(
.clk(sys_clk),
.rst_n(sys_rst_n),
.key_in(key_in), //按键扫描
.data(data), //要显示的数据
.en(en), //数码管使能
.led_sel(led_sel),
.menu_show(menu_show),
.speed(speed)
);
实例化LED
下面展示一些 内联代码片
。
// A code block
var foo = 'bar';
led u_led(
.clk(sys_clk),
.rst_n(sys_rst_n),
.led_sel(led_sel),
.led(led)
);
数码管module
下面展示一些 内联代码片
。
// A code block
var foo = 'bar';
module seg_led(clk, //时钟信号
rst_n, //复位信号
data, //要显示的数字
point, //小数点的位置
en, //数码管失能信号
sign, //符号位
sel, //数码管片选
seg , //数码管位选
menu_show, //数码管显示控制FLAG
speed
);
//parameter define
localparam CLK_DIVIDE = 4'd10 ; // 时钟分频系数
localparam MAX_NUM = 13'd5000 ; // 对数码管驱动时钟(5MHz)计数1ms所需的计数值
//输入定义
input clk;
input rst_n;
input [19:0] data;
input [5:0] point;
input en;
input [3:0] menu_show;
input [11:0] speed;
//输出定义
output [5:0] sel;
output [7:0] seg;
output sign;
//寄存器定义
reg [5:0] sel;
reg [7:0]seg;
reg [ 3:0] clk_cnt ; // 时钟分频计数器
reg dri_clk ; // 数码管的驱动时钟,5MHz
reg [23:0] num ; // 24位bcd码寄存器
reg [12:0] cnt0 ; // 数码管驱动时钟计数器
reg flag ; // 标志信号(标志着cnt0计数达1ms)
reg [2:0] cnt_sel ; // 数码管位选计数器
reg [3:0] num_disp ; // 当前数码管显示的数据
reg dot_disp ; // 当前数码管显示的小数点
//中间变量定义
wire [3:0] data0 ; // 个位数
wire [3:0] data1 ; // 十位数
wire [3:0] data2 ; // 百位数
wire [3:0] data3 ; // 千位数
wire [3:0] data4 ; // 万位数
wire [3:0] data5 ; // 十万位数
wire [3:0] data0_r ; // 个位数
wire [3:0] data1_r ; // 十位数
wire [3:0] data2_r ; // 百位数
wire [3:0] data3_r ; // 千位数
wire [3:0] data4_r ; // 万位数
wire [3:0] data5_r ; // 十万位数
wire [3:0] speed0 ; // 个位数
wire [3:0] speed1 ; // 十位数
wire [3:0] speed2 ; // 百位数
//====================================================
// main code
//====================================================
//提取显示数值所对应的十进制数的各个位
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; // 十万位数
assign data0_r = 4'd9 - data0 ; // 个位数
assign data1_r = 4'd9 - data1 ; // 十位数
assign data2_r = 4'd9 - data2 ; // 百位数
assign data3_r = 4'd9 - data3 ; // 千位数
assign data4_r = 4'd9 - data4 ; // 万位数
assign data5_r = 4'd9 - data5 ; // 十万位数
assign speed0 = speed % 4'd10; // 个位数
assign speed1 = speed / 4'd10 % 4'd10 ; // 十位数
assign speed2 = speed / 7'd100 % 4'd10 ; // 百位数
/*assign data4 = 4'd9 - data0;
assign data5 = 4'd9 - data1;
*/
//对系统时钟10分频,得到的频率为5MHz的数码管驱动时钟dri_clk
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
clk_cnt <= 4'd0;
dri_clk <= 1'b1;
end
else if(clk_cnt == CLK_DIVIDE/2 - 1'd1) begin
clk_cnt <= 4'd0;
dri_clk <= ~dri_clk;
end
else begin
clk_cnt <= clk_cnt + 1'b1;
dri_clk <= dri_clk;
end
end
//将20位2进制数转换为8421bcd码(即使用4位二进制数表示1位十进制数)
always @ (posedge dri_clk or negedge rst_n) begin
if (!rst_n)
num <= 24'b0;
else begin
if (data5 || point[5]) begin //如果显示数据为6位十进制数,
num[23:20] <= data5; //则依次给6位数码管赋值
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 //如果显示数据为5位十进制数,则给低5位数码管赋值
num[19:0] <= {data4,data3,data2,data1,data0};
if(sign)
num[23:20] <= 4'd11; //如果需要显示负号,则最高位(第6位)为符号位
else
num[23:20] <= 4'd10; //不需要显示负号时,则第6位不显示任何字符
end
else begin //如果显示数据为4位十进制数,则给低4位数码管赋值
if (data3 || point[3]) begin
num[15: 0] <= {data3,data2,data1,data0};
num[23:20] <= 4'd10; //第6位不显示任何字符
if(sign) //如果需要显示负号,则最高位(第5位)为符号位
num[19:16] <= 4'd11;
else //不需要显示负号时,则第5位不显示任何字符
num[19:16] <= 4'd10;
end
else begin //如果显示数据为3位十进制数,则给低3位数码管赋值
if (data2 || point[2]) begin
num[11: 0] <= {data2,data1,data0};
//第6、5位不显示任何字符
num[23:16] <= {2{4'd10}};
if(sign) //如果需要显示负号,则最高位(第4位)为符号位
num[15:12] <= 4'd11;
else //不需要显示负号时,则第4位不显示任何字符
num[15:12] <= 4'd10;
end
else begin //如果显示数据为2位十进制数,则给低2位数码管赋值
if (data1 || point[1]) begin
num[ 7: 0] <= {data1,data0};
//第6、5、4位不显示任何字符
num[23:12] <= {3{4'd10}};
if(sign) //如果需要显示负号,则最高位(第3位)为符号位
num[11:8] <= 4'd11;
else //不需要显示负号时,则第3位不显示任何字符
num[11:8] <= 4'd10;
end
else begin //如果显示数据为1位十进制数,则给最低位数码管赋值
num[3:0] <= data0;
//第6、5位不显示任何字符
num[23:8] <= {4{4'd10}};
if(sign) //如果需要显示负号,则最高位(第2位)为符号位
num[7:4] <= 4'd11;
else //不需要显示负号时,则第2位不显示任何字符
num[7:4] <= 4'd10;
end
end
end
end
end
end
end
//每当计数器对数码管驱动时钟计数时间达1ms,输出一个时钟周期的脉冲信号
always @ (posedge dri_clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
cnt0 <= 13'b0;
flag <= 1'b0;
end
else if (cnt0 < MAX_NUM - 1'b1) begin
cnt0 <= cnt0 + 1'b1;
flag <= 1'b0;
end
else begin
cnt0 <= 13'b0;
flag <= 1'b1;
end
end
//cnt_sel从0计数到5,用于选择当前处于显示状态的数码管
always @ (posedge dri_clk or negedge rst_n) begin
if (rst_n == 1'b0)
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;
end
//控制数码管位选信号,使6位数码管轮流显示
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(menu_show)
1'd0 : 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'b111110;
num_disp <= 4'b0;
dot_disp <= 1'b1;
end
endcase
end
1'd1 : begin
case (cnt_sel)
3'd0 :begin
sel <= 6'b111110; //显示数码管最低位
num_disp <= data0_r ; //显示的数据
dot_disp <= ~point[0]; //显示的小数点
end
3'd1 :begin
sel <= 6'b111101; //显示数码管第1位
num_disp <= data1_r ;
dot_disp <= ~point[1];
end
3'd2 :begin
sel <= 6'b111011; //显示数码管第2位
num_disp <= data2_r;
dot_disp <= ~point[2];
end
3'd3 :begin
sel <= 6'b110111; //显示数码管第3位
num_disp <= data3_r;
dot_disp <= ~point[3];
end
3'd4 :begin
sel <= 6'b101111; //显示数码管第4位
num_disp <= data4_r;
dot_disp <= ~point[4];
end
3'd5 :begin
sel <= 6'b011111; //显示数码管最高位
num_disp <= data5_r;
dot_disp <= ~point[5];
end
default :begin
sel <= 6'b111111;
num_disp <= 4'b0;
dot_disp <= 1'b1;
end
endcase
end
2'd2 : begin
case (cnt_sel)
3'd0 :begin
sel <= 6'b111110; //显示数码管最低位
num_disp <= speed0 ; //显示的数据
dot_disp <= ~point[0]; //显示的小数点
end
3'd1 :begin
sel <= 6'b111101; //显示数码管第1位
num_disp <= speed1 ;
dot_disp <= ~point[1];
end
3'd2 :begin
sel <= 6'b111011; //显示数码管第2位
num_disp <= speed2;
dot_disp <= ~point[2];
end
default :begin
sel <= 6'b111111;
num_disp <= 4'b0;
dot_disp <= 1'b1;
end
endcase
end
default : begin
sel <= 6'b111111; //使能信号为0时,所有数码管均不显示
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 <= 8'hc0;
else begin
case (num_disp)
4'd0 : seg <= {dot_disp,7'b1000000}; //显示数字 0
4'd1 : seg <= {dot_disp,7'b1111001}; //显示数字 1
4'd2 : seg <= {dot_disp,7'b0100100}; //显示数字 2
4'd3 : seg <= {dot_disp,7'b0110000}; //显示数字 3
4'd4 : seg <= {dot_disp,7'b0011001}; //显示数字 4
4'd5 : seg <= {dot_disp,7'b0010010}; //显示数字 5
4'd6 : seg <= {dot_disp,7'b0000010}; //显示数字 6
4'd7 : seg <= {dot_disp,7'b1111000}; //显示数字 7
4'd8 : seg <= {dot_disp,7'b0000000}; //显示数字 8
4'd9 : seg <= {dot_disp,7'b0010000}; //显示数字 9
4'd10: seg <= 8'b11111111; //不显示任何字符
4'd11: seg <= 8'b10111111; //显示负号(-)
default:
seg <= {dot_disp,7'b1000000};
endcase
end
end
endmodule
按键module
下面展示一些 内联代码片
。
// A code block
var foo = 'bar';
module key_scan(
clk,
rst_n,
key_in,
data ,
en,
led_sel,
menu_show,
speed
);
//输出定义
input clk;
input rst_n;
input [3:0] key_in;
//输入定义
output [19:0] data;
output en;
output [3:0] led_sel;
output [3:0] menu_show;
output [11:0] speed;
//寄存器定义
reg [31:0] timer;
reg [19:0] count;
reg [3:0] key_scan_r; //按键扫描值KEY
reg [19:0] data;
reg en;
reg [3:0] led_sel;
reg [3:0] menu_show;
reg [11:0] speed;
//中间变量定义
//==============================================
// 采样按键值,20ms扫描一次,采样频率小于按键毛刺频率,相当于滤除掉了高频毛刺信号。
//==============================================
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)//复位信号低有效,复位信号拉低的时候,开始执行此部分
count<=20'd0;
else
begin
if(count==20'd999_999)//20ms扫描一次按键,20ms计数(50M/50-1=999_999)
begin
count <= 20'b0; //计数器计到20ms,计数器清零
key_scan_r <= key_in; //采样按键输入电平
end
else
count<=count+20'b1;
end
end
//====================================================
// 按键信号锁存一个时钟节拍
//====================================================
reg [3:0] key_scan_l;
always @(posedge clk)
key_scan_l <= key_scan_r;
wire [3:0] flag_key = key_scan_l[3:0] & (~key_scan_r[3:0]); //当检测到按键有下降沿变化时,代表该按键被按下,按键有效
//=====================================================
//按键控制num变化
//=====================================================
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
data<=4'b0;
en<=1'b0;
led_sel<=1'd1;
menu_show<=1'd0;
speed<=8'd235;
end
else if(data>99)
begin
data<=0;
end
else if(menu_show>2)
menu_show<=0;
else if(led_sel==4'b1001)
en<=~en;
else
begin
case(menu_show)
4'd0:begin
if ( flag_key[0] ) data<=data + 4'b1;
if ( flag_key[1] ) led_sel<=led_sel+1'd1;
if ( flag_key[2] ) begin menu_show<=menu_show + 1'd1;led_sel<=1'd1;end
if ( flag_key[3] ) data<=data + 4'b1;
end
4'd1:begin
if ( flag_key[0] ) data<=data + 4'b1;
if ( flag_key[1] ) led_sel<=led_sel<<1;
if ( flag_key[2] ) menu_show<=menu_show + 1'd1;
if ( flag_key[3] ) led_sel<=led_sel + 4'b1;
end
4'd2:begin
if ( flag_key[0] ) data<=data + 4'b1;
if ( flag_key[1] ) speed<=1'd0;
if ( flag_key[2] ) menu_show<=menu_show + 1'd1;
if ( flag_key[3] ) speed<=speed + 4'b1;
end
endcase
end
end
endmodule
LED module
下面展示一些 内联代码片
。
// A code block
var foo = 'bar';
module led(
clk, //时钟信号
rst_n, //复位信号
led_sel, //led选择
led //led
);
//输入定义
input clk;
input rst_n;
input [3:0] led_sel;
//输出定义
output [3:0] led;
//寄存器定义
reg [3:0] led;
//中间变量定义
//=====================================================
// LED灯控制
//=====================================================
always @(posedge clk or negedge rst_n) //检测时钟的上升沿和复位的下降沿
begin
if (~rst_n) //复位信号低有效
led <= 4'b0000; //LED灯输出全为低,四个LED灯灭
else if (led_sel == 1'd1) //计数器计到1秒,
led <= 4'b0001; //LED1点亮
else if (led_sel == 2'd2) //计数器计到2秒,
led <= 4'b0010; //LED2点亮
else if (led_sel == 2'd3) //计数器计到3秒,
led <= 4'b0100; //LED3点亮
else if (led_sel == 3'd4) //计数器计到3秒,
led <= 4'b1000; //LED3点亮
else
led <= 4'b0000;
end
endmodule
标签:wire,led,FPGA,clk,数码管,按键,rst,reg 来源: https://blog.csdn.net/Wangxiangang9527/article/details/120938237
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。