? ? ? 實(shí)驗(yàn)?zāi)繕?biāo):通過電腦調(diào)試助手向FPGA的UART串口接收模塊發(fā)送數(shù)據(jù),然后數(shù)據(jù)可以穩(wěn)定顯示在數(shù)碼管上。
? ? ? 實(shí)驗(yàn)?zāi)康?/strong>: 練習(xí)UART串口模塊和數(shù)碼管的使用。之前已經(jīng)有文章詳細(xì)講解了串口和數(shù)碼管的開發(fā),故這里直接提供設(shè)計(jì)思路供大家參考。
(串口文章鏈接)https://mp.csdn.net/mp_blog/creation/editor/128935535https://mp.csdn.net/mp_blog/creation/editor/127933111
(數(shù)碼管文章鏈接)https://mp.csdn.net/mp_blog/creation/editor/127933111?
1. 模塊框圖
2. RTL代碼
2.1 頂層模塊
`timescale 1ns/1ns
module smg_uart
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire rx ,
output wire [5:0] sel , //數(shù)碼管位選信號(hào)
output wire [7:0] seg //數(shù)碼管段選信號(hào)
);
parameter UART_BPS = 20'd9600 , //波特率
CLK_FREQ = 26'd50_000_000 ;
wire [7:0] data;
uart_rx
#(
.UART_BPS (UART_BPS ), //串口波特率
.CLK_FREQ (CLK_FREQ ) //時(shí)鐘頻率
)
uart_rx_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.rx (rx ),
.po_data (data )
);
seg_dynamic seg_dynamic_inst
(
.sys_clk (sys_clk) ,
.data (data ) ,
.sys_rst_n (sys_rst_n) ,
.sel (sel ) ,
.seg (seg )
);
endmodule
2.2 UART數(shù)據(jù)接收模塊
`timescale 1ns/1ns
//接收8位串行數(shù)據(jù)后轉(zhuǎn)并行
module uart_rx
#(
parameter UART_BPS = 'd9600, //9600BPS
CLK_FREQ = 'd50_000_000 //50MHZ
)
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire rx ,
output reg [7:0] po_data
);
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS ; //接受1bit數(shù)據(jù)所需多少個(gè)脈沖周期
reg rx_reg1;
reg rx_reg2;
reg rx_reg3;
reg start_nedge;
reg bit_flag;
reg [3:0] bit_cnt;
reg work_en;
reg [15:0] baud_cnt;
reg [7:0] rx_data;
reg rx_flag;
reg po_flag;
reg [7:0] data;
//rx_reg: 進(jìn)行打拍操作,消除亞穩(wěn)態(tài)
always @(posedge sys_clk or negedge sys_rst_n)
if( !sys_rst_n ) begin
rx_reg1 <= 1'b1;
rx_reg2 <= 1'b1;
rx_reg3 <= 1'b1;
end
else begin
rx_reg1 <= rx;
rx_reg2 <= rx_reg1;
rx_reg3 <= rx_reg2;
end
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
start_nedge <= 1'b0;
else if((~rx_reg2) && (rx_reg3))
start_nedge <= 1'b1;
else
start_nedge <= 1'b0;
//work_en:接收數(shù)據(jù)工作使能信號(hào)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
work_en <= 1'b0;
else if(start_nedge == 1'b1)
work_en <= 1'b1;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
work_en <= 1'b0;
//傳輸一位數(shù)據(jù)需要花 5208 脈沖周期
always @(posedge sys_clk or negedge sys_rst_n)
if( !sys_rst_n )
baud_cnt <= 1'b0;
else if (baud_cnt == BAUD_CNT_MAX - 1'b1)
baud_cnt <= 1'b0;
else if (work_en == 1'b1)
baud_cnt <= baud_cnt + 1'b1;
else
baud_cnt <= 1'b0;
//bit_flag:接收數(shù)據(jù)標(biāo)志
always @(posedge sys_clk or negedge sys_rst_n)
if( !sys_rst_n )
bit_flag <= 1'b0;
else if (( baud_cnt == (BAUD_CNT_MAX/2) - 1 ))
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;
always @(posedge sys_clk or negedge sys_rst_n)
if( !sys_rst_n )
bit_cnt <= 1'b0;
else if ((bit_flag == 1'b1) && (bit_cnt < 4'd8))
bit_cnt <= bit_cnt + 1'b1;
else if ((bit_flag == 1'b1) && (bit_cnt == 4'd8))
bit_cnt <= 1'b0;
always @(posedge sys_clk or negedge sys_rst_n)
if( !sys_rst_n )
rx_data <= 1'b0;
else if ((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1))
rx_data <= {rx_reg3, rx_data[7:1]};
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_flag <= 1'b0;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
rx_flag <= 1'b1;
else
rx_flag <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
po_flag <= 1'b0;
else if (rx_flag == 1'b1)
po_flag <= 1'b1;
else
po_flag <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
po_data <= 1'b0;
else if (rx_flag == 1'b1)
po_data <= rx_data;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data <= 1'b0;
else if (po_flag == 1'b1)
data <= po_data;
endmodule
2.3 數(shù)碼管顯示模塊
/* Author: xsy
Create Date: 20221118
Description: 數(shù)碼管驅(qū)動(dòng)模塊
method: / */
`timescale 1ns/1ns
module seg_dynamic
#(
parameter CNT_MAX = 16'd49_999 //數(shù)碼管 刷新 時(shí)間計(jì)數(shù)最大值 1ms
)
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [7:0] data , //數(shù)碼管要顯示的值
output reg [5:0] sel , //數(shù)碼管位選信號(hào)
output reg [7:0] seg //數(shù)碼管段選信號(hào)
);
//wire define
wire [3:0] unit ; //個(gè)位數(shù)
wire [3:0] ten ; //十位數(shù)
wire [3:0] hun ; //百位數(shù)
wire [3:0] tho ; //千位數(shù)
wire [3:0] t_tho ; //萬位數(shù)
wire [3:0] h_hun ; //十萬位數(shù)
//reg define
reg [23:0] data_reg ; //待顯示數(shù)據(jù) 寄存器
reg [15:0] cnt_1ms ; //1ms計(jì)數(shù)器
reg flag_1ms ; //1ms標(biāo)志信號(hào)
reg [2:0] cnt_sel ; //數(shù)碼管位選計(jì)數(shù)器
reg [5:0] sel_reg ; //位選信號(hào)
reg [3:0] data_disp ; //當(dāng)前數(shù)碼管顯示的數(shù)據(jù)
//cnt_1ms:1ms計(jì)數(shù)器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_1ms <= 16'd0;
else if(cnt_1ms == CNT_MAX)
cnt_1ms <= 16'd0;
else
cnt_1ms <= cnt_1ms + 1'b1;
//flag_1ms:1ms標(biāo)志信號(hào)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
flag_1ms <= 1'b0;
else if(cnt_1ms == CNT_MAX - 1'b1)
flag_1ms <= 1'b1; // unit 為BCD碼,可以總效果4'bXXXX
else // ten 為BCD碼,可以總效果4'bXXXX
flag_1ms <= 1'b0; // hun 為BCD碼,可以總效果4'bXXXX
// tho 為BCD碼,可以總效果4'bXXXX
//data_reg:控制數(shù)碼管顯示數(shù)據(jù) // t_tho 為BCD碼,可以總效果4'bXXXX
always@(posedge sys_clk or negedge sys_rst_n) // h_hun 為BCD碼,可以總效果4'bXXXX
if(sys_rst_n == 1'b0)
data_reg <= 24'b0;
//若顯示的十進(jìn)制數(shù)的 十萬 位為非零數(shù)據(jù)則六個(gè)數(shù)碼管全顯示
else if(h_hun) //h_hun非空即數(shù)據(jù)有六位
data_reg <= {h_hun,t_tho,tho,hun,ten,unit};
//若顯示的十進(jìn)制數(shù)的 萬 位為非零數(shù)據(jù)則值顯示在5個(gè)數(shù)碼管上
else if(t_tho)
data_reg <= {4'd11,t_tho,tho,hun,ten,unit}; //4'd11(第六位)我們定義為不顯示
//若顯示的十進(jìn)制數(shù)的 千 位為非零數(shù)據(jù)則值顯示4個(gè)數(shù)碼管
else if(tho)
data_reg <= {4'd11,4'd11,tho,hun,ten,unit};
//若顯示的十進(jìn)制數(shù)的 百 位為非零數(shù)據(jù)則值顯示3個(gè)數(shù)碼管
else if(hun)
data_reg <= {4'd11,4'd11,4'd11,hun,ten,unit};
//若顯示的十進(jìn)制數(shù)的 十 位為非零數(shù)據(jù)則值顯示2個(gè)數(shù)碼管
else if(ten)
data_reg <= {4'd11,4'd11,4'd11,4'd11,ten,unit};
//若上面都不滿足都只顯示 個(gè) 位數(shù)碼管
else
data_reg <= {4'd11,4'd11,4'd11,4'd11,4'd11,unit};
//cnt_sel:標(biāo)記0-5ms所對(duì)應(yīng)顯示的BCD碼
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_sel <= 3'd0;
else if((cnt_sel == 3'd5) && (flag_1ms == 1'b1))
cnt_sel <= 3'd0;
else if(flag_1ms == 1'b1)
cnt_sel <= cnt_sel + 1'b1;
else
cnt_sel <= cnt_sel;
//數(shù)碼管位選信號(hào)寄存器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sel_reg <= 6'b000_000;
else if((cnt_sel == 3'd0) && (flag_1ms == 1'b1))
sel_reg <= 6'b000_001;
else if(flag_1ms == 1'b1)
sel_reg <= sel_reg << 1;
else
sel_reg <= sel_reg;
//控制數(shù)碼管的位選信號(hào),使六個(gè)數(shù)碼管輪流顯示
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_disp <= 4'b0;
else if(flag_1ms == 1'b1)
case(cnt_sel)
3'd0: data_disp <= data_reg[3:0] ; //給第1個(gè)數(shù)碼管賦個(gè)位值
3'd1: data_disp <= data_reg[7:4] ; //給第2個(gè)數(shù)碼管賦十位值
3'd2: data_disp <= data_reg[11:8] ; //給第3個(gè)數(shù)碼管賦百位值
3'd3: data_disp <= data_reg[15:12]; //給第4個(gè)數(shù)碼管賦千位值
3'd4: data_disp <= data_reg[19:16]; //給第5個(gè)數(shù)碼管賦萬位值
3'd5: data_disp <= data_reg[23:20]; //給第6個(gè)數(shù)碼管賦十萬位值
default:data_disp <= 4'b0 ;
endcase
else
data_disp <= data_disp;
//控制數(shù)碼管段選信號(hào),顯示數(shù)字
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
seg <= 8'b1111_1111;
else
case(data_disp)
4'd0 : seg <= 8'b1100_0000; //顯示數(shù)字0
4'd1 : seg <= 8'b1111_1001; //顯示數(shù)字1
4'd2 : seg <= 8'b1010_0100; //顯示數(shù)字2
4'd3 : seg <= 8'b1011_0000; //顯示數(shù)字3
4'd4 : seg <= 8'b1001_1001; //顯示數(shù)字4
4'd5 : seg <= 8'b1001_0010; //顯示數(shù)字5
4'd6 : seg <= 8'b1000_0010; //顯示數(shù)字6
4'd7 : seg <= 8'b1111_1000; //顯示數(shù)字7
4'd8 : seg <= 8'b1000_0000; //顯示數(shù)字8
4'd9 : seg <= 8'b1001_0000; //顯示數(shù)字9
default:seg <= 8'b1111_1111;
endcase
//sel:數(shù)碼管位選信號(hào)賦值
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sel <= 6'b000_000;
else
sel <= sel_reg;
bcd_8421 bcd_8421_inst
(
.sys_clk (sys_clk ), //系統(tǒng)時(shí)鐘,頻率50MHz
.sys_rst_n (sys_rst_n), //復(fù)位信號(hào),低電平有效
.data (data ), //輸入需要轉(zhuǎn)換的數(shù)據(jù)
.unit (unit ), //個(gè)位BCD碼
.ten (ten ), //十位BCD碼
.hun (hun ), //百位BCD碼
.tho (tho ), //千位BCD碼
.t_tho (t_tho ), //萬位BCD碼
.h_hun (h_hun ) //十萬位BCD碼
);
endmodule
2.4? 二進(jìn)制轉(zhuǎn)BCD碼模塊
`timescale 1ns/1ns
module bcd_8421
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [19:0] data , //輸入需要轉(zhuǎn)換的數(shù)據(jù)
output reg [3:0] unit , //個(gè)位BCD碼
output reg [3:0] ten , //十位BCD碼
output reg [3:0] hun , //百位BCD碼
output reg [3:0] tho , //千位BCD碼
output reg [3:0] t_tho , //萬位BCD碼
output reg [3:0] h_hun //十萬位BCD碼
);
reg [4:0] cnt_shift ;//移位判斷計(jì)數(shù)器 移動(dòng)次數(shù)由十轉(zhuǎn)為二進(jìn)制的位數(shù)決定
reg [43:0] data_shift ;//移位判斷數(shù)據(jù) 寄存器 存放BCD碼與二進(jìn)制碼
reg shift_flag ;//移位判斷標(biāo)志信號(hào) 用于控制移位判斷的先后順序
//cnt_shift:從0到21循環(huán)計(jì)數(shù)(當(dāng)計(jì)為20時(shí)進(jìn)行判斷移位,21時(shí)則是取BCD碼數(shù)據(jù))
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_shift <= 5'd0;
else if((cnt_shift == 5'd21) && (shift_flag == 1'b1))
cnt_shift <= 5'd0;
else if(shift_flag == 1'b1)
cnt_shift <= cnt_shift + 1'b1;
else
cnt_shift <= cnt_shift;
//data_shift:計(jì)數(shù)器為0時(shí)賦初值,計(jì)數(shù)器為1~20時(shí)進(jìn)行移位判斷操作
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_shift <= 44'b0;
else if(cnt_shift == 5'd0) //計(jì)數(shù)器為0時(shí)賦初值
data_shift <= {24'b0,data};
else if((cnt_shift <= 20)&&(shift_flag == 1'b0))//<=為小于等于,先判斷再移位
begin
data_shift[23:20] <= (data_shift[23:20] > 4) ?
(data_shift[23:20] + 2'd3) : (data_shift[23:20]);
data_shift[27:24] <= (data_shift[27:24] > 4) ?
(data_shift[27:24] + 2'd3) : (data_shift[27:24]);
data_shift[31:28] <= (data_shift[31:28] > 4) ?
(data_shift[31:28] + 2'd3) : (data_shift[31:28]);
data_shift[35:32] <= (data_shift[35:32] > 4) ?
(data_shift[35:32] + 2'd3) : (data_shift[35:32]);
data_shift[39:36] <= (data_shift[39:36] > 4) ?
(data_shift[39:36] + 2'd3) : (data_shift[39:36]);
data_shift[43:40] <= (data_shift[43:40] > 4) ?
(data_shift[43:40] + 2'd3) : (data_shift[43:40]);
end
else if((cnt_shift <= 20) && (shift_flag == 1'b1))
data_shift <= data_shift << 1;
else
data_shift <= data_shift;
//shift_flag:移位判斷標(biāo)志信號(hào),低電平判斷 高電平移位
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
shift_flag <= 1'b0;
else
shift_flag <= ~shift_flag;
//當(dāng)計(jì)數(shù)器等于20時(shí),移位判斷操作完成,對(duì)各個(gè)位數(shù)的BCD碼進(jìn)行賦值
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
unit <= 4'b0;
ten <= 4'b0;
hun <= 4'b0;
tho <= 4'b0;
t_tho <= 4'b0;
h_hun <= 4'b0;
end
else if(cnt_shift == 5'd21)
begin
unit <= data_shift[23:20];
ten <= data_shift[27:24];
hun <= data_shift[31:28];
tho <= data_shift[35:32];
t_tho <= data_shift[39:36];
h_hun <= data_shift[43:40];
end
endmodule
3. 上板驗(yàn)證
調(diào)試助手發(fā)送十六進(jìn)制數(shù) 34,數(shù)碼管顯示 52;調(diào)試助手發(fā)送十六進(jìn)制數(shù) 88,數(shù)碼管顯示 136;
說明:
???????本人學(xué)習(xí)的是野火家Xilinx Spartan6系列開發(fā)板及配套教程,以上內(nèi)容如有疑惑或錯(cuò)誤歡迎評(píng)論區(qū)指出。
開發(fā)軟件:ise14.7?????仿真:modelsim 10.5文章來源:http://www.zghlxwxcb.cn/news/detail-538013.html
如需上述資料私信或留下郵箱。文章來源地址http://www.zghlxwxcb.cn/news/detail-538013.html
到了這里,關(guān)于FPGA_數(shù)碼管顯示UART串口接收的數(shù)據(jù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!