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; //輸出時間值 精確到ms18 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
就不模擬了,直接放實物圖。