FPGA学习之秒表
作者:互联网
1、资源
a、FPGA控制板;
b、两个级联的74HC595控制 8段8位共阳极数码管;
c、两个按键;
2、想法
实现秒表功能;
初始状态,秒表零。
按下按键1:开始跑秒;
再次按下按键1,停止跑秒;---->往后分两种情况:
---->a、再次按下按键1,继续跑秒;
---->b、再次按下按键2,秒表清零。
3、实现
3.1、模块划分
a、时间模块:计时功能
b、BCD码转换模块:将2进制转换成10进制;
c、数码管动态显示模块;
d、按键检测模块;
e、整合模块。
3.2、具体实现
此处补模块图
3.2.1、时间模块
板载时钟20ns周期,计算计数值如下表。
输入:
开始计时、停止计时、计时清零
输出:
1ms计时完成、时间值
模块图
代码:
1 `timescale 1ns/10ps 2 module ShiJian_JiShuQi( 3 clk, 4 rst_n, 5 JiShuQi_KaiShi, 6 JiShuQi_TingZhi, 7 JiShuQi_QingLing, 8 JiShu_1ms_WanCheng, 9 ShiJianZhi 10 ); 11 input clk; 12 input rst_n; 13 input JiShuQi_KaiShi; //开始计数 14 input JiShuQi_TingZhi; //暂停计数 15 input JiShuQi_QingLing; //清零计数器 16 output JiShu_1ms_WanCheng; //计数1ms完成 17 output reg [22:0]ShiJianZhi; //输出时间值 精确到ms 18 19 reg JiShuQi_ZhuangTai; //计时状态,计时置1,停止计时置0 20 reg [5:0]JiShuQi_ns ; //ns计数器 21 reg [9:0]JiShuQi_us ; //us计数器 22 reg [9:0]JiShuQi_ms ; //ms计数器 23 reg [5:0]JiShuQi_s ; //s计数器 24 reg [6:0]JiShuQi_min; //分钟计数器 25 26 wire JiShu_1us_WanCheng; //完成1us计数,时间进位标志 27 // wire JiShu_1ms_WanCheng; //完成1ms计数,时间进位标志 28 wire JiShu_1s_WanCheng; //完成1s计数,时间进位标志 29 wire JiShu_1min_WanCheng; //完成1min计数,时间进位标志 30 wire JiShu_max; //记满120分钟,时间清零 31 32 localparam //系统时钟20ns 33 JiShuQi_ns_max = 6'd49, //1000ns 34 JiShuQi_us_max = 10'd999, //1000us 35 JiShuQi_ms_max = 10'd999, //1000ms 36 JiShuQi_s_max = 6'd59, //1s 37 JiShuQi_min_max = 7'd120; //120min 38 //仿真 39 /* localparam 40 JiShuQi_ns_max = 6'd5, 41 JiShuQi_us_max = 10'd5, 42 JiShuQi_ms_max = 10'd5, 43 JiShuQi_s_max = 6'd5, 44 JiShuQi_min_max = 7'd120; */ 45 46 assign JiShu_1us_WanCheng = JiShuQi_ns == JiShuQi_ns_max?1'b1:1'b0;//ns计数器记满时进位标志1 47 assign JiShu_1ms_WanCheng = (JiShuQi_us == JiShuQi_us_max)&&JiShu_1us_WanCheng?1'b1:1'b0;//us 48 assign JiShu_1s_WanCheng = (JiShuQi_ms == JiShuQi_ms_max)&&JiShu_1ms_WanCheng?1'b1:1'b0; 49 assign JiShu_1min_WanCheng = (JiShuQi_s == JiShuQi_s_max)&&JiShu_1s_WanCheng?1'b1:1'b0; 50 assign JiShu_max = (JiShuQi_min== JiShuQi_min_max)&&JiShu_1min_WanCheng?1'b1:1'b0; 51 52 always@(posedge clk or negedge rst_n) 53 if(!rst_n) 54 #1 JiShuQi_ZhuangTai <= 1'b0; 55 else if(JiShuQi_KaiShi) //开始置1 56 #1 JiShuQi_ZhuangTai <= 1'b1; 57 else if(JiShuQi_TingZhi) //停止置0 58 #1 JiShuQi_ZhuangTai <= 1'b0; 59 else 60 #1 JiShuQi_ZhuangTai <= JiShuQi_ZhuangTai; 61 //ns计数器 62 always@(posedge clk or negedge rst_n) 63 if(!rst_n) 64 #1 JiShuQi_ns <= 6'd0; 65 else if(JiShu_1us_WanCheng || JiShuQi_QingLing) 66 #1 JiShuQi_ns <= 6'd0; 67 else if(JiShuQi_ZhuangTai) 68 #1 JiShuQi_ns <= JiShuQi_ns + 1'b1; 69 else //无计时状态时时间值保持 70 #1 JiShuQi_ns <= JiShuQi_ns; 71 //us计数器 72 always@(posedge clk or negedge rst_n) 73 if(!rst_n) 74 #1 JiShuQi_us <= 10'd0; 75 else if((JiShu_1ms_WanCheng&&JiShu_1us_WanCheng) || JiShuQi_QingLing) 76 #1 JiShuQi_us <= 10'd0; 77 else if(JiShuQi_ZhuangTai && JiShu_1us_WanCheng) 78 #1 JiShuQi_us <= JiShuQi_us + 1'b1; 79 else 80 #1 JiShuQi_us <= JiShuQi_us; 81 //ms计数器 82 always@(posedge clk or negedge rst_n) 83 if(!rst_n) 84 #1 JiShuQi_ms <= 10'd0; 85 else if((JiShu_1s_WanCheng&&JiShu_1ms_WanCheng) || JiShuQi_QingLing) 86 #1 JiShuQi_ms <= 10'd0; 87 else if(JiShuQi_ZhuangTai && JiShu_1ms_WanCheng) 88 #1 JiShuQi_ms <= JiShuQi_ms + 1'b1; 89 else 90 #1 JiShuQi_ms <= JiShuQi_ms; 91 //s计数器 92 always@(posedge clk or negedge rst_n) 93 if(!rst_n) 94 #1 JiShuQi_s <= 6'd0; 95 else if((JiShu_1min_WanCheng && JiShu_1s_WanCheng) || JiShuQi_QingLing) 96 #1 JiShuQi_s <= 6'd0; 97 else if(JiShuQi_ZhuangTai && JiShu_1s_WanCheng) 98 #1 JiShuQi_s <= JiShuQi_s + 1'b1; 99 else 100 #1 JiShuQi_s <= JiShuQi_s; 101 //min计数器 102 always@(posedge clk or negedge rst_n) 103 if(!rst_n) 104 #1 JiShuQi_min <= 7'd0; 105 else if((JiShu_max&&JiShu_1min_WanCheng) || JiShuQi_QingLing) 106 #1 JiShuQi_min <= 7'd0; 107 else if(JiShuQi_ZhuangTai && JiShu_1min_WanCheng) 108 #1 JiShuQi_min <= JiShuQi_min + 1'b1; 109 else 110 #1 JiShuQi_min <= JiShuQi_min; 111 //输出时间值 112 always@(posedge clk or negedge rst_n) 113 if(!rst_n) 114 #1 ShiJianZhi <= 23'd0; 115 else if(JiShu_1ms_WanCheng) 116 #1 ShiJianZhi <= {JiShuQi_min,JiShuQi_s,JiShuQi_ms}; 117 else 118 #1 ShiJianZhi <= ShiJianZhi; 119 120 endmodule
仿真:
1 `timescale 1ns/10ps 2 `define clk_period 20 3 module ShiJian_JiShuQi_tb(); 4 reg clk ; 5 reg rst_n; 6 reg JiShuQi_KaiShi; 7 8 initial clk = 0; 9 always#(`clk_period/2) clk = ~clk; 10 11 initial begin 12 JiShuQi_KaiShi = 0; 13 rst_n = 0; 14 #(`clk_period*2); rst_n = 1; 15 #(`clk_period*2);JiShuQi_KaiShi = 1; 16 #(`clk_period*1);JiShuQi_KaiShi = 0; 17 18 #(`clk_period*1000*10); 19 $stop; 20 end 21 ShiJian_JiShuQi ShiJian_JiShuQi( 22 .clk(clk), 23 .rst_n(rst_n), 24 .JiShuQi_KaiShi(JiShuQi_KaiShi), 25 .JiShuQi_TingZhi(), 26 .JiShuQi_QingLing(), 27 .JiShu_1ms_WanCheng(), 28 .ShiJianZhi() 29 ); 30 endmodule
仿真图:
3.2.2 BCD转换模块
此处参考:https://blog.csdn.net/xs20180801/article/details/84716098
BCD转换模块作用是将输入的时间值【分-分-分-秒-秒-毫秒-毫秒-毫秒】转换成BCD码,共32位。
BCD转换模块在此处分BCD转换模块和BCD控制模块。
a、BCD转换模块:
功能:即将输入的10位2进制数(此处去值最大的毫秒值,最大值为999)转换为【11:0】的BCD码--->【11:8】、【7:4】、【3:0】。
输入:
转换使能、待转换数值【9:0】
输出:
转换完成使能、BCD转换值【11:0】。
b、BCD转换控制模块:
功能:也就是依次将需要转换的数值【分分分】、【秒秒】、【毫秒毫秒毫秒】送入BCD转换模块,并取出BCD转换值组合后输出。此处也可以例化成3个BCD转换模块,同时转换。时间重要还是面积重要来取舍。
输入:
BCD转换使能(此处将计时器1ms计时完成信号做使能)
待转换数值【22:0】(时间值)
输出:
转换完成使能
BCD转换值【31:0】(完整值)。
BCD转换模块代码
1 `timescale 1ns/10ps 2 module BCD_ZhuanHuan_module( 3 clk, 4 rst_n, 5 BCD_KaiShi, 6 BCD_DaiZhuanZhi, 7 BCD_WanCheng, 8 BCD_Zhi 9 ); 10 input clk; 11 input rst_n; 12 input BCD_KaiShi; //开始转换 13 input [9:0]BCD_DaiZhuanZhi; //待转换数值 14 output reg BCD_WanCheng; //本次转换完成 15 output reg [11:0]BCD_Zhi; //BCD转换值 16 17 reg [21:0]BCD_YiWei; //10 + 3 * 4 = 22 位 结构【BCD值 + 原始值】 18 reg [3:0]BCD_JiShuQi; //移位次数 19 reg ZhuanHuan_ZhuangTai; //BCD转换状态 20 21 localparam YiWeiZhi = 4'd10; //计数10次:0~9移位;10值输出 22 wire ZhuanHuan_WanCheng; //转换完成标志 23 24 assign ZhuanHuan_WanCheng = BCD_JiShuQi == YiWeiZhi ? 1'b1:1'b0;//计数器计数10时使能 25 // 26 always@(posedge clk or negedge rst_n) 27 if(!rst_n) 28 #1 ZhuanHuan_ZhuangTai <= 1'b0; 29 else if(BCD_KaiShi) 30 #1 ZhuanHuan_ZhuangTai <= 1'b1; 31 else if(ZhuanHuan_WanCheng) 32 #1 ZhuanHuan_ZhuangTai <= 1'b0; 33 else 34 #1 ZhuanHuan_ZhuangTai <= ZhuanHuan_ZhuangTai; 35 //移位计数器 36 always@(posedge clk or negedge rst_n) 37 if(!rst_n) 38 #1 BCD_JiShuQi <= 4'd0; 39 else if(ZhuanHuan_WanCheng) 40 #1 BCD_JiShuQi <= 4'd0; 41 else if(ZhuanHuan_ZhuangTai) 42 #1 BCD_JiShuQi <= BCD_JiShuQi + 1'b1; 43 else 44 #1 BCD_JiShuQi <= 4'd0; 45 //左移加3 此处用阻塞赋值 46 always@(posedge clk or negedge rst_n) 47 if(!rst_n) 48 #1 BCD_YiWei = 22'd0; 49 else if(BCD_KaiShi) //开始只能是一个脉冲 50 #1 BCD_YiWei = {12'd0,BCD_DaiZhuanZhi};//装载初始值 51 else if(ZhuanHuan_ZhuangTai && BCD_JiShuQi < YiWeiZhi)begin//0~9移位 52 #1 if(BCD_YiWei[21:18] >= 3'd5) BCD_YiWei[21:18] = BCD_YiWei[21:18] + 2'd3; 53 #1 if(BCD_YiWei[17:14] >= 3'd5) BCD_YiWei[17:14] = BCD_YiWei[17:14] + 2'd3; 54 #1 if(BCD_YiWei[13:10] >= 3'd5) BCD_YiWei[13:10] = BCD_YiWei[13:10] + 2'd3; 55 #1 BCD_YiWei = BCD_YiWei << 1'b1; 56 end 57 else //清零 58 #1 BCD_YiWei = 22'd0; 59 // 60 always@(posedge clk or negedge rst_n) 61 if(!rst_n) 62 #1 BCD_Zhi <= 12'd0; 63 else if(ZhuanHuan_WanCheng) 64 #0.5 BCD_Zhi <= BCD_YiWei[21:10]; 65 else 66 #1 BCD_Zhi <= 12'd0; 67 // 68 always@(posedge clk or negedge rst_n)//此处延迟一个时钟周期,与值一起送出去 69 if(!rst_n) 70 #1 BCD_WanCheng <= 1'b0; 71 else 72 #1 BCD_WanCheng <= ZhuanHuan_WanCheng; 73 endmodule
BCD转换模块仿真
1 `timescale 1ns/10ps 2 `define clk_period 20 3 module BCD_ZhuanHuan_module_tb(); 4 reg clk; 5 reg rst_n; 6 reg BCD_KaiShi; 7 reg [9:0]BCD_DaiZhuanZhi; 8 9 initial clk = 0; 10 always#(`clk_period/2) clk = ~clk; 11 12 initial begin 13 rst_n = 0; 14 BCD_KaiShi = 0; 15 BCD_DaiZhuanZhi = 10'd0; 16 #(`clk_period*3) rst_n = 1; 17 #(`clk_period*3) ; 18 BCD_KaiShi = 1; 19 BCD_DaiZhuanZhi = 10'd999; 20 #(`clk_period*1) ; 21 BCD_KaiShi = 0; 22 23 #(`clk_period*20) ; 24 $stop; 25 26 27 end 28 29 30 BCD_ZhuanHuan_module BCD_ZhuanHuan_module( 31 .clk(clk), 32 .rst_n(rst_n), 33 .BCD_KaiShi(BCD_KaiShi), 34 .BCD_DaiZhuanZhi(BCD_DaiZhuanZhi), 35 .BCD_WanCheng(), 36 .BCD_Zhi() 37 ); 38 endmodule
BCD转换模块仿真图
BCD控制模块代码
1 `timescale 1ns/10ps 2 module BCD_KongZhi_module( 3 clk, 4 rst_n, 5 BCD_KongZhi_KaiShi, 6 ShiJianZhi, 7 BCD_ZhuanHuanZhi, 8 BCD_ZhuanHuan_WanCheng 9 ); 10 input clk; 11 input rst_n; 12 input BCD_KongZhi_KaiShi; //此处接1ms转换完成信号 13 input [22:0]ShiJianZhi; 14 output reg [31:0]BCD_ZhuanHuanZhi; 15 output reg BCD_ZhuanHuan_WanCheng; 16 17 localparam KongXian_ZhuangTai = 2'b00, //空闲状态 18 BCD_FuZhi_ZhuangTai = 2'b01, //给BCD转换模块赋值 19 DengDaiZhuanHuan_ZhuangTai = 2'b10; //等待BCD转换模块转换完成 20 reg[1:0]CS; 21 reg[1:0]NS; 22 reg[1:0]JiShuQi; 23 wire BCD_WanCheng; 24 wire [11:0]BCD_Zhi; 25 reg BCD_KaiShi; 26 reg[9:0]BCD_DaiZhuanZhi; 27 reg[22:0]ShiJianZhi_JiCunQi; 28 //1 29 always@(posedge clk or negedge rst_n) 30 if(!rst_n) 31 #1 CS <= 2'd0; 32 else 33 #1 CS <= NS; 34 //2 35 always@(BCD_KongZhi_KaiShi,BCD_WanCheng,CS,JiShuQi)begin 36 NS = 2'bxx; 37 case(CS) 38 KongXian_ZhuangTai : 39 if(BCD_KongZhi_KaiShi) //开始使能、状态改变 40 NS = BCD_FuZhi_ZhuangTai; 41 else 42 NS = KongXian_ZhuangTai; 43 BCD_FuZhi_ZhuangTai : 44 NS = DengDaiZhuanHuan_ZhuangTai; //赋值后,直接进入等待转换状态 45 DengDaiZhuanHuan_ZhuangTai :begin 46 if(BCD_WanCheng && JiShuQi == 2'd2)//共需转换3次,若转换完,直接进入空闲状态 47 NS = KongXian_ZhuangTai; 48 else if(BCD_WanCheng && JiShuQi < 2'd2)//未转换完,再次进入赋值状态 49 NS = BCD_FuZhi_ZhuangTai; 50 else 51 NS = DengDaiZhuanHuan_ZhuangTai; 52 end 53 default:NS = KongXian_ZhuangTai; 54 endcase 55 end 56 //3 57 always@(posedge clk or negedge rst_n) 58 if(!rst_n)begin 59 BCD_KaiShi <= 1'b0; 60 JiShuQi <= 2'd0; //计数器也在此处赋值 61 BCD_ZhuanHuanZhi <= 32'd0; //值整合也在此处实现 62 BCD_ZhuanHuan_WanCheng <= 1'b0; 63 end 64 else begin 65 case(CS) 66 KongXian_ZhuangTai:begin 67 #1 JiShuQi <= 2'd0; 68 BCD_KaiShi <= 1'b0; 69 BCD_ZhuanHuanZhi <= 32'd0; //BCD转换值每次都清零 70 BCD_ZhuanHuan_WanCheng <= 1'b0; 71 end 72 BCD_FuZhi_ZhuangTai:begin 73 #1 BCD_KaiShi <= 1'b1; 74 end 75 DengDaiZhuanHuan_ZhuangTai:begin 76 #1 BCD_KaiShi <= 1'b0; 77 if(BCD_WanCheng && JiShuQi == 2'd0)begin 78 JiShuQi <= JiShuQi + 1'b1; 79 BCD_ZhuanHuanZhi[11:0] <= BCD_Zhi; 80 end 81 else if(BCD_WanCheng && JiShuQi == 2'd1)begin 82 JiShuQi <= JiShuQi + 1'b1; 83 BCD_ZhuanHuanZhi[19:12] <= BCD_Zhi[7:0]; 84 end 85 else if(BCD_WanCheng && JiShuQi == 2'd2)begin 86 BCD_ZhuanHuanZhi[31:20] <= BCD_Zhi; 87 BCD_ZhuanHuan_WanCheng <= 1'b1; 88 end 89 else begin 90 JiShuQi <= JiShuQi; 91 BCD_ZhuanHuanZhi <= BCD_ZhuanHuanZhi; 92 end 93 end 94 default:begin 95 BCD_KaiShi <= 1'b0; 96 JiShuQi <= 2'd0; 97 BCD_ZhuanHuanZhi <= 32'd0; 98 BCD_ZhuanHuan_WanCheng <= 1'b0; 99 end 100 endcase 101 end 102 //时间值寄存 103 always@(posedge clk or negedge rst_n) 104 if(!rst_n) 105 #1 ShiJianZhi_JiCunQi <= 22'd0; 106 else if(BCD_KongZhi_KaiShi) 107 #1 ShiJianZhi_JiCunQi <= ShiJianZhi; 108 else 109 #1 ShiJianZhi_JiCunQi <= ShiJianZhi_JiCunQi; 110 //待转换数值,直接用查找表实现的。个人感觉比较直观些 111 always@(*) 112 case(JiShuQi) 113 2'd0:BCD_DaiZhuanZhi = ShiJianZhi_JiCunQi[9:0]; //转ms 114 2'd1:BCD_DaiZhuanZhi = {4'b0000,ShiJianZhi_JiCunQi[15:10]}; 115 2'd2:BCD_DaiZhuanZhi = {3'b000,ShiJianZhi_JiCunQi[22:16]}; 116 default:BCD_DaiZhuanZhi = 10'd0; 117 endcase 118 BCD_ZhuanHuan_module BCD_ZhuanHuan_module( 119 .clk(clk), 120 .rst_n(rst_n), 121 .BCD_KaiShi(BCD_KaiShi), 122 .BCD_DaiZhuanZhi(BCD_DaiZhuanZhi), 123 .BCD_WanCheng(BCD_WanCheng), 124 .BCD_Zhi(BCD_Zhi) 125 ); 126 endmodule
BCD控制模块仿真代码
1 `timescale 1ns/10ps 2 `define clk_period 20 3 module BCD_KongZhi_module_tb(); 4 reg clk; 5 reg rst_n; 6 reg KaiShi; 7 reg [22:0]ShiJianZhi; 8 initial clk = 1; 9 always#(`clk_period/2) clk = ~clk; 10 11 initial begin 12 rst_n = 0; 13 KaiShi = 0; 14 ShiJianZhi = 23'd0; 15 #(`clk_period*2) rst_n = 1; //时间值:12:58:332 16 #(`clk_period*5) ;KaiShi = 1; ShiJianZhi = 23'b000_1100_11_1010_01_0100_1100; 17 #(`clk_period*1) KaiShi = 0; 18 #(`clk_period*80); 19 20 KaiShi = 1; ShiJianZhi = 23'b000_1101_1010_1001_0100_1111; 21 #(`clk_period*1) KaiShi = 0; 22 #(`clk_period*80); 23 24 $stop; 25 end 26 27 28 BCD_KongZhi_module tt( 29 .clk(clk), 30 .rst_n(rst_n), 31 .BCD_KongZhi_KaiShi(KaiShi), 32 .ShiJianZhi(ShiJianZhi ), 33 34 .BCD_ZhuanHuanZhi(), 35 .BCD_ZhuanHuan_WanCheng() 36 ); 37 endmodule
BCD控制模块仿真图
转换周期860ns,满足计时器的要求的
3.2.3、数码管动态显示模块
74hc595本身有两个时钟频率,一个是移位时钟的频率,一个是寄存器(显示)时钟的频率。
数据输入的频率是1000HZ,也就是BCD转换完成频率
几个显示频率计算如下
模块划分
a、单数码管显示;
b、多数码管动态显示;
单数码管显示:(74HC595单字符显示)
条件:
74HC595
8个位置
单字符显示。
输入:
待显示字符;
待显示位置。
输出:
移位时钟
显示时钟
串行值
显示完成,也就是动态显示时,需要知道的一个信号
需要处理的:
上级系统输入信号
待显示字符
待显示位置
上面两个上级系统输入信息要求
1、 上级系统需要将值一直保持;
2、 寄存该值,一直到完成一次显示,再次取值。
如果采用第二种方式,就要有个取值时机。在模块内部加一个计数器,或者利用移位时钟,在完成16次移位后,也是完成一次移位后,再重新取值。
输出信号
两个时钟的信号
由上表获得的信息(芯片信息表,不插图):
移位时钟的频率最大是4mhz(按最小的算)。时长也就是250ns 且高电平需要保持110ns的时间。
显示时钟:因为我们这里要完整的显示一次,需要先移位16次,再显示,就是和移位时钟保持16倍的关系即可,也就是16*4mhz,且高电平也要有110ns的保持时间。
移位时钟置高之前,待移位的数值应该保持75ns至少
更新时钟置高之前,移位时钟至少需要走过半个时钟周期。
移位时钟:查数据表直到移位频率最大值 至少有4MHZ
这里有个想法,计数移位时钟,计数到17,再送一个显示时钟。
直接贴代码:
1 module SuMaGuan_XianShi( 2 clk, 3 rst_n, 4 XinXi, 5 XianShi_WanCheng, 6 YiWeiShiZhong, 7 XianShiShiZhong, 8 ChuanHangZhi 9 ); 10 input clk; 11 input rst_n; 12 input [15:0]XinXi; //段选编码+位选值顺序也是这样 13 output XianShi_WanCheng; //完成一次编码值的显示 14 output YiWeiShiZhong; 15 output XianShiShiZhong; 16 output reg ChuanHangZhi; 17 18 reg[7:0]JiShuQi_YWPL; //移位时钟频率计数器,计数值12,频率=4mhz(稍微小) 19 reg[4:0]JiShuQi_YWCS; //移位时钟次数计数器,记录移位时钟的次数。 20 reg[15:0]XinXi_JCQ; //一次移位操作前,先寄存一次信息值 21 22 localparam YWPL = 8'd12; //移位时钟频率 4mhz(稍微小),高低电平1:1 23 /* wire [7:0]YWPL; 24 wire [31:0]ttt; 25 assign YWPL = ttt[7:0]; */ 26 localparam YWCS = 5'd18; //18次为一个字符的显示频率,0.222mhz 27 wire YWPL_JM; //JiShuQi_YWPL计数器记满标记 28 wire YWCS_JM; //JiShuQi_YWCS计数器记满标记 29 assign YWPL_JM = JiShuQi_YWPL == YWPL ? 1'b1:1'b0;//记满标记1 30 assign YWCS_JM = JiShuQi_YWCS == YWCS ? 1'b1:1'b0;//记满标记1 31 // 32 always@(posedge clk or negedge rst_n)//移位计数器记满置0,持续计数 33 if(!rst_n) 34 JiShuQi_YWPL <= 8'd0; 35 else if(YWPL_JM) 36 JiShuQi_YWPL <= 8'd0; 37 else 38 JiShuQi_YWPL <= JiShuQi_YWPL + 1'b1; 39 // 40 always@(posedge clk or negedge rst_n)//计数器记满置0,持续计数 41 if(!rst_n) 42 JiShuQi_YWCS <= 5'd0; 43 else if(YWCS_JM)//最大计数值也要持续一个移位频率后才清零 44 JiShuQi_YWCS <= 5'd0; 45 else if(JiShuQi_YWPL == (YWPL >>1'b1)) 46 JiShuQi_YWCS <= JiShuQi_YWCS + 1'b1; 47 else 48 JiShuQi_YWCS <= JiShuQi_YWCS; 49 // 50 always@(posedge clk or negedge rst_n) 51 if(!rst_n) 52 XinXi_JCQ <= 16'd0; 53 else if(!(JiShuQi_YWPL||JiShuQi_YWCS)) //取值时机,在双计数器都是0时取新值 54 XinXi_JCQ <= XinXi; 55 else 56 XinXi_JCQ <= XinXi_JCQ; 57 // 58 assign YiWeiShiZhong = (JiShuQi_YWPL <= (YWPL >>1'b1))&&(JiShuQi_YWCS <= 4'd15) ? 1'b1:1'b0; 59 assign XianShiShiZhong = (JiShuQi_YWCS == 5'd17) ? 1'b1:1'b0; 60 assign XianShi_WanCheng = (YWCS_JM ) ?1'b1:1'b0; 61 //串行值 做一个查找表吧 62 always@(*) 63 case(JiShuQi_YWCS) 64 4'd00:ChuanHangZhi = XinXi_JCQ[15]; //段选编码dp h 65 4'd01:ChuanHangZhi = XinXi_JCQ[14]; //段选编码g 66 4'd02:ChuanHangZhi = XinXi_JCQ[13]; //段选编码f 67 4'd03:ChuanHangZhi = XinXi_JCQ[12]; //段选编码e 68 4'd04:ChuanHangZhi = XinXi_JCQ[11]; //段选编码d 69 4'd05:ChuanHangZhi = XinXi_JCQ[10]; //段选编码c 70 4'd06:ChuanHangZhi = XinXi_JCQ[09]; //段选编码b 71 4'd07:ChuanHangZhi = XinXi_JCQ[08]; //段选编码a 72 4'd08:ChuanHangZhi = XinXi_JCQ[07]; //位选信号8 73 4'd09:ChuanHangZhi = XinXi_JCQ[06]; //位选信号7 74 4'd10:ChuanHangZhi = XinXi_JCQ[05]; //位选信号6 75 4'd11:ChuanHangZhi = XinXi_JCQ[04]; //位选信号5 76 4'd12:ChuanHangZhi = XinXi_JCQ[03]; //位选信号4 77 4'd13:ChuanHangZhi = XinXi_JCQ[02]; //位选信号3 78 4'd14:ChuanHangZhi = XinXi_JCQ[01]; //位选信号2 79 4'd15:ChuanHangZhi = XinXi_JCQ[00]; //位选信号1 80 default:ChuanHangZhi = 1'b0; //默认情况置0 81 endcase 82 83 /* tz tz( 84 .probe(), 85 .source(ttt) 86 ); */ 87 endmodule
1 module DongTai_ShuMaGuan( 2 clk, 3 rst_n, 4 XianShiZhi, 5 XianShiZhi_En, 6 XianShiShiZhong, 7 ChuanHangZhi, 8 YiWeiShiZhong 9 ); 10 input clk; 11 input rst_n; 12 input[31:0]XianShiZhi; //8个数码管依次待显示的BCD值 从【高位-->低位】 13 input XianShiZhi_En; //取待显示值的使能 14 output XianShiShiZhong; 15 output ChuanHangZhi; 16 output YiWeiShiZhong; 17 18 wire XianShi_WanCheng; //完成一个数码管的显示 19 wire [15:0]XinXi; //段选编码+位选值顺序也是这样 20 21 reg [2:0]JiShuQi; //循环记录显示了几个数码管 22 reg [31:0]XianShiZhi_r1; //显示值存储器1 23 wire[31:0]XianShiZhi_r2; //显示值存储器2 24 wire XianShi_1Lun; //数码管显示完一轮 JiShuQi== 3'd7 && XianShi_WanCheng 25 reg [7:0]DuanXuanXinHao; //待显示数码管编码 26 reg [7:0]WeiXuanXinHao; //待显示数码管位置信号 27 reg[3:0]DaiXianShiZhi; //待显示数值 28 // 29 always@(posedge clk or negedge rst_n) 30 if(!rst_n) 31 XianShiZhi_r1 <= 32'd0; 32 else if(XianShiZhi_En)//取值使能来的时候先存值 33 XianShiZhi_r1 <= XianShiZhi; 34 else 35 XianShiZhi_r1 <= XianShiZhi_r1; 36 // 37 assign XianShi_1Lun = (JiShuQi== 3'd7 && XianShi_WanCheng) ? 1'b1:1'b0; 38 // 39 assign XianShiZhi_r2 = XianShi_1Lun ? XianShiZhi_r1:XianShiZhi_r2;//判断有无显示完一轮,若显示完一轮,就取XianShiZhi_r1,若没有,就先将一轮显示完,初始时会出现未知 40 // 41 always@(posedge clk or negedge rst_n) 42 if(!rst_n) 43 JiShuQi <= 3'd0; 44 else if(XianShi_WanCheng) //显示完一个数码管记一次值 45 JiShuQi <= JiShuQi + 1'b1; 46 else //此处未记满清零是因为刚好只能记到7 47 JiShuQi <= JiShuQi; 48 49 //位选查找表 50 always@(*) 51 case(JiShuQi) 52 4'd 0: WeiXuanXinHao = 8'b0000_0001; 53 4'd 1: WeiXuanXinHao = 8'b0000_0010; 54 4'd 2: WeiXuanXinHao = 8'b0000_0100; 55 4'd 3: WeiXuanXinHao = 8'b0000_1000; 56 4'd 4: WeiXuanXinHao = 8'b0001_0000; 57 4'd 5: WeiXuanXinHao = 8'b0010_0000; 58 4'd 6: WeiXuanXinHao = 8'b0100_0000; 59 4'd 7: WeiXuanXinHao = 8'b1000_0000; 60 default:WeiXuanXinHao = 8'b0000_0000; 61 endcase 62 //时间值查找表 63 always@(*) 64 case(JiShuQi) 65 4'd 0: DaiXianShiZhi = XianShiZhi_r2[3:0]; 66 4'd 1: DaiXianShiZhi = XianShiZhi_r2[7:4]; 67 4'd 2: DaiXianShiZhi = XianShiZhi_r2[11:8]; 68 4'd 3: DaiXianShiZhi = XianShiZhi_r2[15:12]; 69 4'd 4: DaiXianShiZhi = XianShiZhi_r2[19:16]; 70 4'd 5: DaiXianShiZhi = XianShiZhi_r2[23:20]; 71 4'd 6: DaiXianShiZhi = XianShiZhi_r2[27:24]; 72 4'd 7: DaiXianShiZhi = XianShiZhi_r2[31:28]; 73 default:DaiXianShiZhi = 4'd0; 74 endcase 75 always@(*) 76 case(DaiXianShiZhi) 77 4'h0 : DuanXuanXinHao = 8'hc0 ; 78 4'h1 : DuanXuanXinHao = 8'hf9 ; 79 4'h2 : DuanXuanXinHao = 8'ha4 ; 80 4'h3 : DuanXuanXinHao = 8'hb0 ; 81 4'h4 : DuanXuanXinHao = 8'h99 ; 82 4'h5 : DuanXuanXinHao = 8'h92 ; 83 4'h6 : DuanXuanXinHao = 8'h82 ; 84 4'h7 : DuanXuanXinHao = 8'hf8 ; 85 4'h8 : DuanXuanXinHao = 8'h80 ; 86 4'h9 : DuanXuanXinHao = 8'h90 ; 87 4'ha : DuanXuanXinHao = 8'h88 ; 88 4'hb : DuanXuanXinHao = 8'h83 ; 89 4'hc : DuanXuanXinHao = 8'hc6 ; 90 4'hd : DuanXuanXinHao = 8'ha1 ; 91 4'he : DuanXuanXinHao = 8'h86 ; 92 4'hf : DuanXuanXinHao = 8'h8e ; 93 default:DuanXuanXinHao = 8'hff; 94 endcase 95 96 assign XinXi = {DuanXuanXinHao,WeiXuanXinHao}; 97 SuMaGuan_XianShi SuMaGuan_XianShi( 98 .clk(clk), 99 .rst_n(rst_n), 100 .XinXi(XinXi), 101 .XianShi_WanCheng(XianShi_WanCheng), 102 .YiWeiShiZhong(YiWeiShiZhong), 103 .XianShiShiZhong(XianShiShiZhong), 104 .ChuanHangZhi(ChuanHangZhi) 105 ); 106 endmodule
//此模块只为测试数码管仿真用
1 module top( 2 clk, 3 rst_n, 4 YiWeiShiZhong, 5 XianShiShiZhong, 6 ChuanHangZhi 7 ); 8 input clk; 9 input rst_n; 10 output YiWeiShiZhong; 11 output XianShiShiZhong; 12 output ChuanHangZhi; 13 14 // wire [15:0]XinXi; //段选编码+位选值顺序也是这样 15 // wire XianShi_WanCheng; //完成一次编码值的显示 16 17 // wire [31:0]XianShiZhi; 18 19 DongTai_ShuMaGuan DongTai_ShuMaGuan( 20 .clk(clk), 21 .rst_n(rst_n), 22 .XianShiZhi(32'h12345678), 23 .XianShiZhi_En(1'b1), 24 .XianShiShiZhong(XianShiShiZhong), 25 .ChuanHangZhi(ChuanHangZhi), 26 .YiWeiShiZhong(YiWeiShiZhong) 27 ); 28 /* SuMaGuan_XianShi SuMaGuan_XianShi( 29 .clk(clk), 30 .rst_n(rst_n), 31 .XinXi(16'h0010), 32 .XianShi_WanCheng(), 33 .YiWeiShiZhong(YiWeiShiZhong), 34 .XianShiShiZhong(XianShiShiZhong), 35 .ChuanHangZhi(ChuanHangZhi) 36 ); */ 37 /* tz tz( 38 .probe(), 39 .source(XianShiZhi) 40 ); */ 41 42 /* input [0:0] probe; 43 output [15:0] source; */ 44 45 endmodule
仿真:
1 `timescale 1ns/10ps 2 `define clk_period 20 3 module top_tb(); 4 reg clk; 5 reg rst_n; 6 7 initial clk = 1; 8 always#(`clk_period/2) clk = ~clk; 9 10 initial begin 11 rst_n = 0; 12 #(`clk_period*2) rst_n = 1; 13 #(`clk_period*1000*8); 14 $stop; 15 end 16 17 top top( 18 .clk(clk), 19 .rst_n(rst_n), 20 .YiWeiShiZhong(), 21 .XianShiShiZhong(), 22 .ChuanHangZhi() 23 ); 24 endmodule
仿真图如下
3.2.4 按键检测模块 (省略)
3.2.5整合模块
此模块一个连接整合的作用,还有个就是状态机
直接贴代码
1 `timescale 1ns/10ps 2 module ZhengHe( 3 clk, 4 rst_n, 5 AnJian_ShuRu1, 6 AnJian_ShuRu2, 7 ChuanHangZhi, 8 YiWeiShiZhong, 9 XianShiShiZhong 10 ); 11 12 input clk; 13 input rst_n; 14 input AnJian_ShuRu1; 15 input AnJian_ShuRu2; 16 output ChuanHangZhi; 17 output YiWeiShiZhong; 18 output XianShiShiZhong; 19 20 wire AnJian_YouXiao1; 21 wire AnJian_YouXiao2; 22 wire AnJian_ZhuangTai1; 23 wire AnJian_ZhuangTai2; 24 reg KaiShi_JiShi; 25 reg TingZhi_JiShi; 26 reg QingLing_ShiJian; 27 wire JiShu_1ms_WanCheng; 28 wire [22:0]ShiJianZhi; 29 wire [31:0]BCD_ZhuanHuanZhi; //时机情况 30 wire BCD_ZhuanHuan_WanCheng; 31 32 reg [2:0]CS; 33 reg [2:0]NS; 34 localparam KongXian_ZhuangTai = 3'b000, 35 JiShi_ZhuangTai = 3'b001, 36 ZanTing_ZhuangTai = 3'b010, 37 QingLing_ZhuangTai = 3'b100; 38 // 39 always@(posedge clk or negedge rst_n) 40 if(!rst_n) 41 CS <= 3'd0; 42 else 43 CS <= NS; 44 // 45 always@(CS,AnJian_YouXiao1,AnJian_YouXiao2,AnJian_ZhuangTai1,AnJian_ZhuangTai2)begin 46 NS = 3'bxxx; 47 case(CS) 48 KongXian_ZhuangTai : 49 if(AnJian_YouXiao1&&AnJian_ZhuangTai1) 50 NS = JiShi_ZhuangTai; 51 else 52 NS = KongXian_ZhuangTai; 53 JiShi_ZhuangTai : 54 if(AnJian_YouXiao1&&AnJian_ZhuangTai1) 55 NS = ZanTing_ZhuangTai; 56 else 57 NS = JiShi_ZhuangTai; 58 ZanTing_ZhuangTai :begin 59 if(AnJian_YouXiao1&&AnJian_ZhuangTai1) 60 NS = JiShi_ZhuangTai; 61 else if(AnJian_YouXiao2&&AnJian_ZhuangTai2) 62 NS = QingLing_ZhuangTai; 63 else 64 NS = ZanTing_ZhuangTai; 65 end 66 QingLing_ZhuangTai : 67 NS = KongXian_ZhuangTai; 68 default:NS = KongXian_ZhuangTai; 69 endcase 70 end 71 //3 72 always@(posedge clk or negedge rst_n) 73 if(!rst_n)begin 74 KaiShi_JiShi <= 1'b0; 75 TingZhi_JiShi <= 1'b0; 76 QingLing_ShiJian <= 1'b0; 77 end 78 else begin 79 case(CS) 80 KongXian_ZhuangTai :begin 81 QingLing_ShiJian <= 1'b0; 82 if(AnJian_YouXiao1&&AnJian_ZhuangTai1) 83 KaiShi_JiShi <= 1'b1; 84 else 85 ; 86 end 87 JiShi_ZhuangTai :begin 88 KaiShi_JiShi <= 1'b0; 89 if(AnJian_YouXiao1&&AnJian_ZhuangTai1) 90 TingZhi_JiShi <= 1'b1; 91 else 92 ; 93 end 94 ZanTing_ZhuangTai :begin 95 TingZhi_JiShi <= 1'b0; 96 if(AnJian_YouXiao1&&AnJian_ZhuangTai1) 97 KaiShi_JiShi <= 1'b1; 98 else if(AnJian_YouXiao2&&AnJian_ZhuangTai2) 99 QingLing_ShiJian <= 1'b1; 100 else 101 ; 102 end 103 QingLing_ZhuangTai : 104 QingLing_ShiJian <= 1'b0; 105 default:begin 106 KaiShi_JiShi <= 1'b0; 107 TingZhi_JiShi <= 1'b0; 108 QingLing_ShiJian <= 1'b0; 109 end 110 endcase 111 end 112 113 114 115 116 DanAnJianJianCe_module AnJian1( 117 .clk(clk), 118 .rst_n(rst_n), 119 .JianCe_En(1'b1), 120 .AnJian_ShuRu(AnJian_ShuRu1), 121 .AnJian_YouXiao(AnJian_YouXiao1), 122 .AnJian_ZhuangTai(AnJian_ZhuangTai1) 123 ); 124 DanAnJianJianCe_module AnJian2( 125 .clk(clk), 126 .rst_n(rst_n), 127 .JianCe_En(1'b1), 128 .AnJian_ShuRu(AnJian_ShuRu2), 129 .AnJian_YouXiao(AnJian_YouXiao2), 130 .AnJian_ZhuangTai(AnJian_ZhuangTai2) 131 ); 132 133 ShiJian_JiShuQi ShiJian_JiShuQi( 134 .clk(clk), 135 .rst_n(rst_n), 136 .JiShuQi_KaiShi(KaiShi_JiShi), 137 .JiShuQi_TingZhi(TingZhi_JiShi), 138 .JiShuQi_QingLing(QingLing_ShiJian), 139 .JiShu_1ms_WanCheng(JiShu_1ms_WanCheng), 140 .ShiJianZhi(ShiJianZhi) 141 ); 142 143 BCD_KongZhi_module BCD_KongZhi_module( 144 .clk(clk), 145 .rst_n(rst_n), 146 .BCD_KongZhi_KaiShi(JiShu_1ms_WanCheng), 147 .ShiJianZhi(ShiJianZhi ), 148 .BCD_ZhuanHuanZhi(BCD_ZhuanHuanZhi), 149 .BCD_ZhuanHuan_WanCheng(BCD_ZhuanHuan_WanCheng) 150 ); 151 wire [31:0]BCD_ZhuanHuanZhi_r; 152 assign BCD_ZhuanHuanZhi_r = QingLing_ShiJian ? 32'd0: BCD_ZhuanHuan_WanCheng ? BCD_ZhuanHuanZhi :BCD_ZhuanHuanZhi_r; 153 154 DongTai_ShuMaGuan DongTai_ShuMaGuan( 155 .clk(clk), 156 .rst_n(rst_n), 157 .XianShiZhi(BCD_ZhuanHuanZhi_r), 158 .XianShiZhi_En(BCD_ZhuanHuan_WanCheng||QingLing_ShiJian), 159 .XianShiShiZhong(XianShiShiZhong), 160 .ChuanHangZhi(ChuanHangZhi), 161 .YiWeiShiZhong(YiWeiShiZhong) 162 ); 163 endmodule
就不仿真了,直接放实物图。
标签:FPGA,clk,BCD,学习,WanCheng,rst,秒表,reg,JiShuQi 来源: https://www.cnblogs.com/wxh8821/p/15107587.html