數碼管顯示進行簡單的介紹,數碼管顯示原理在數電中已經給出了比較詳細的介紹,我就不贅述了,因為我們用的是至芯的開發板,其上的數碼管顯示模塊采用的是共陽極的數碼管,為低電平有效,0-F的顯示碼依次為:
數碼管的輸入有3個位選和8個段選給出,位選信號sel來控制哪個數碼管先亮,段選信號seg來控制數碼管顯示什么,位選本來應該是有6個的但是為了節約資源,采用了3-8譯碼器將6根線減少到3根,節約了FPGA的引腳資源。
因為人眼有一個視覺載留,所以60HZ來掃描的時候,數碼管會讓人眼覺得是同時點亮,所以時鍾要大於60hz
下面是具體的代碼實現:
module scan_led( input wire clk_1k, input wire rst_n, input wire [31:0] d, output wire [2:0] dig,//sel output wire [7:0] seg ); reg [7:0] seg_r; reg [2:0] dig_r; reg [3:0] disp_dat; reg [2:0] count; assign dig =dig_r; assign seg =sig_r; // 時鍾不能直接接全局時鍾,這里的時鍾驅動給的是1k的 always @(posedge clk_1k or negedge rst_n) begin if(!rst_n) count <=3'b000; else if(count == 3'd5) count <=3'b000; else count <=count +1'b1; end always @(posedge clk_1k or negedge rst_n) begin case (count) 3'd0:disp_dat = d[31:28]; 3'd1:disp_dat = d[27:24]; 3'd2:disp_dat = d[23:20]; 3'd3:disp_dat = d[19:16]; 3'd4:disp_dat = d[15:12]; 3'd5:disp_dat = d[11:8]; 3'd6:disp_dat = d[7:4]; 3'd7:disp_dat = d[3:0]; endcase case (count) 3'd0:dig_r = 3'd0; 3'd1:dig_r = 3'd1; 3'd2:dig_r = 3'd2; 3'd3:dig_r = 3'd3; 3'd4:dig_r = 3'd4; 3'd5:dig_r = 3'd5; 3'd6:dig_r = 3'd6; 3'd7:dig_r = 3'd7; endcase end always @(disp_dat) begin case(disp_dat) 4'h0:seg_r = 8'hc0; 4'h1:seg_r = 8'hf9; 4'h2:seg_r = 8'ha4; 4'h3:seg_r = 8'hb0; 4'h4:seg_r = 8'h99; 4'h5:seg_r = 8'h92; 4'h6:seg_r = 8'h82; 4'h7:seg_r = 8'hf8; 4'h8:seg_r = 8'h80; 4'h9:seg_r = 8'h90; 4'ha:seg_r = 8'h88; 4'hb:seg_r = 8'h83; 4'hc:seg_r = 8'hc6; 4'hd:seg_r = 8'ha1; 4'he:seg_r = 8'h86; 4'hf:seg_r = 8'h8e; endcase end endmodule
另一種寫法:
module display1 (clk, rst_n , sel, seg); input clk; input rst_n; //兩個輸出,位選sel和段選seg output reg [2:0] sel; output reg [7:0] seg; //數碼管掃描需要一個慢時鍾 clk_slow,而產生慢時鍾則需要一個計數器 cnt reg [15:0] cnt; reg clk_slow; //這個always塊用來產生慢時鍾clk_slow always @ (posedge clk) begin if(!rst_n) begin cnt <= 0; clk_slow <= 1; //復位時clk_slow靜止不動 end else begin cnt <= cnt + 1; //復位結束后cnt開始計數 clk_slow <= cnt[12]; //掃描沒有必要非得是60Hz整,大於60Hz即可 end end //下面這個always塊用於掃描數碼管,也就是sel循環地變化, //時鍾每一次上升沿sel變化一次,所以在括號里寫上時鍾上升沿作為觸發條件 always @ (posedge clk_slow or negedge rst_n) begin if(!rst_n) begin sel <= 0; //復位時sel靜止 end else begin sel <= sel + 1; //復位后sel開始掃描 if(sel >= 5) sel <= 0; //因為只有6個數碼管,所以讓sel在0-5之間循環 end end always @ (*) begin if(!rst_n) seg <= 8'b11111111; //按下復位鍵時讓數碼管熄滅,共陽極數碼管0亮1滅 else begin case(sel) 0: seg <= 8'b11111001; //右起第1個數碼管上顯示1 1: seg <= 8'b10100100; //右起第2個數碼管上顯示2 2: seg <= 8'b10110000; 3: seg <= 8'b10011001; 4: seg <= 8'b10010010; 5: seg <= 8'b10000010; //右起第6個數碼管上顯示6 default: seg <= 8'b11111111; endcase end end endmodule