本工程實作三個數碼管界面顯示,采用按鍵二切換界面,每個界面另外兩個按鍵有不同的功能,需要其他功能的,可根據需求更改,同時界面二帶有一個故障檢測功能,當在界面二利用按鍵一和按鍵三組合出1001是,系統不再顯示數字,實作故障功能,話不多說,上代碼,
實驗工程目錄
- top
- 實體化數碼管
- 實體化按鍵
- 實體化LED
- 數碼管module
- 按鍵module
- LED module
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
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/335455.html
標籤:其他
