FPGA UART
上板验证图片
顶层仿真图片
头文件
//head.v //UART参数设置 `define UART_CLK 50_000_000 `define UART_BPS 115200
顶层代码
`include "head.v" module uart_top //========================< 绔彛 >========================================== ( input wire clk , //鏃堕挓锛0Mhz input wire rst_n , //澶嶄綅锛屼綆鐢靛钩鏈夋晥 input wire rx , //FPGA閫氳繃涓插彛鎺ユ敹鐨勬暟鎹 output wire tx //FPGA閫氳繃涓插彛鍙戦€佺殑鏁版嵁 ); //========================< 杩炵嚎 >========================================== wire [7:0] data ; wire data_vld ; wire tx_status ; //========================================================================== //== 妯″潡渚嬪寲 //========================================================================== uart_rx #( .CLK (`UART_CLK) , .BPS (`UART_BPS) ) uart_rx_dut //========================< 绔彛 >========================================== ( .clk(clk) , //鏃堕挓锛0Mhz .rst_n(rst_n) , //澶嶄綅锛屼綆鐢靛钩鏈夋晥 .rx(rx) , //杈撳叆鏁版嵁 .dout(data) , //杈撳嚭鏁版嵁 .dout_flag(data_vld) //杈撳嚭鏁版嵁鐨勬湁鏁堟寚绀 ); uart_tx #( .CLK (`UART_CLK) , .BPS (`UART_BPS) ) uart_tx_dut //========================< 绔彛 >========================================== ( .clk(clk) , //鏃堕挓锛0Mhz .rst_n(rst_n) , //澶嶄綅锛屼綆鐢靛钩鏈夋晥 .din(data) , //闇€瑕佸彂閫佺殑鏁版嵁 .tx_en(data_vld) ,//鍙戦€佸厑璁 .tx(tx) , //鍙戦€佸紩鑴 .tx_status(tx_status) //鍙戦€佺姸鎬 ); endmodule
顶层仿真代码
module uart_top_tb; //========================< 端口 >========================================== reg clk; reg rst_n; reg rx ; wire tx; always #10 clk=~clk; initial begin clk=0; rx=1; rst_n=0; #8681; rst_n=1; rx=1; #8681; rx=0;//开始位 #8681; rx=0;//0 #8681; rx=1;//1 #8681; rx=0;//2 #8681; rx=1;//3 #8681; rx=0;//4 #8681; rx=1;//5 #8681; rx=0;//6 #8681; rx=1;//7 #8681; rx=1;//停止位 #8681; #86810; rx=0;//开始位 #8681; rx=1;//0 #8681; rx=1;//1 #8681; rx=0;//2 #8681; rx=1;//3 #8681; rx=0;//4 #8681; rx=1;//5 #8681; rx=0;//6 #8681; rx=1;//7 #8681; rx=1;//停止位 #8681; #86810; $stop; end uart_top uart_top_dut( .clk(clk) , //时钟,50Mhz .rst_n(rst_n) , //复位,低电平有效 .rx(rx) , //FPGA通过串口接收的数据 .tx (tx) //FPGA通过串口发送的数据 ); endmodule
UART RX 代码
module uart_rx #( parameter CLK = 50_000_000 , //系统时钟,50Mhz parameter BPS = 115200 , //波特率 parameter BPS_CNT = CLK/BPS //波特率计数 ) //========================< 端口 >========================================== ( input wire clk , //时钟,50Mhz input wire rst_n , //复位,低电平有效 input wire rx , //输入数据 output reg [7:0] dout , //输出数据 output reg dout_flag //输出数据的有效指示 ); reg [0:0] rx1=0,rx2=0,rx3=0; reg [15:0] cnt=0; reg [0:0] rx_flag=0; reg [0:0] rxm_flag=0; reg [3:0] bit_cnt=0; wire [0:0] rx_en; assign rx_en=rx3&&~rx2 ; always @(posedge clk or negedge rst_n) begin if(rst_n==0) begin rx1<=1'b1; rx2<=1'b1; rx3<=1'b1; end else begin rx1<=rx; rx2<=rx1; rx3<=rx2; end end always @(posedge clk or negedge rst_n)//开始接收标志 begin if(rst_n==0) rx_flag<=1'b0; else if(rx_en==1'b1) rx_flag<=1'b1; else if(bit_cnt>=4'd9) rx_flag<=1'b0; else rx_flag<=rx_flag; end always @ (posedge clk or negedge rst_n )//比特记数 begin if(rst_n==0) cnt<=16'b0; else if(cnt>=BPS_CNT-1'b1) cnt<=16'b0; else if(rx_flag==1'b1) cnt<=cnt+1'b1; else cnt<=16'b0; end always @ (posedge clk or negedge rst_n ) //位记数 begin if(rst_n==0) bit_cnt<=4'd0; else if(bit_cnt>=4'd9) bit_cnt<=4'd0; else if(cnt>=BPS_CNT-1'b1) bit_cnt<=bit_cnt+4'd1; else bit_cnt<=bit_cnt; end always @ (posedge clk or negedge rst_n )//BIT中间取数标志 begin if(rst_n==0) rxm_flag<=1'b0; else if(cnt==BPS_CNT/2-1'b1) rxm_flag<=1'b1; else rxm_flag<=1'b0; end always @ (posedge clk or negedge rst_n )//捕获数据 begin if(rst_n==0) dout<=8'b0; else if(rxm_flag==1'b1) dout<={rx,dout[7:1]}; else dout<=dout; end always @ (posedge clk or negedge rst_n )//8位数据收集完成标志 begin if(rst_n==0) dout_flag<=1'b0; else if(bit_cnt>=4'd9) dout_flag<=1'b1; else dout_flag<=1'b0; end endmodule
UART RX 仿真代码
`include "head.v" `timescale 1ns/1ns module uart_rx_tb; reg clk ; reg rst_n ; reg rx ; wire [7:0] dout ; wire dout_flag ; always #10 clk=~clk; initial begin clk=0; rst_n=0; rx=1; #8681; rst_n=1; rx=1; #8681; rx=0;//开始位 #8681; rx=0;//0 #8681; rx=1;//1 #8681; rx=0;//2 #8681; rx=1;//3 #8681; rx=0;//4 #8681; rx=1;//5 #8681; rx=0;//6 #8681; rx=1;//7 #8681; rx=1;//停止位 #8681; rx=0;//开始位 #8681; rx=1;//0 #8681; rx=1;//1 #8681; rx=0;//2 #8681; rx=1;//3 #8681; rx=0;//4 #8681; rx=1;//5 #8681; rx=0;//6 #8681; rx=1;//7 #8681; rx=1;//停止位 #8681; $stop; end uart_rx #( .CLK(`UART_CLK) , .BPS(`UART_BPS) )//仿真用 DUT ( .clk(clk) , //时钟,50Mhz .rst_n(rst_n) , //复位,低电平有效 .rx(rx) , //输入数据 .dout(dout) , //输出数据 .dout_flag(dout_flag) //输出数据的有效指示 ); endmodule
UART RX 仿真图片
UART TX 代码
module uart_tx #( parameter CLK = 50_000_000 , //FPGA时钟频率是50MHZ parameter BPS = 115200 , //娉㈢壒鐜 parameter BPS_CNT = CLK/BPS //娉㈢壒鐜囪鏁 ) //========================< 绔彛 >========================================== ( input wire clk ,//FPGA时钟频率是50MHZ input wire rst_n ,//澶嶄綅锛屼綆鐢靛钩鏈夋晥 input wire [7:0] din ,//闇€瑕佸彂閫佺殑鏁版嵁 input wire tx_en ,//鍙戦€佸厑璁 output reg tx , //鍙戦€佸紩鑴 output reg tx_status //鍙戦€佺姸鎬 ); reg [7:0] txdata; reg [15:0] cnt; reg [3:0] bit_cnt; always @ (posedge clk or negedge rst_n ) //鎺ユ敹闇€瑕佸彂閫佺殑鏁版嵁 begin if(rst_n==0) txdata<=8'b0; else if(tx_en==1 && tx_status==0) txdata<=din; else txdata<=txdata; end always @ (posedge clk or negedge rst_n ) //鐢熸垚姝e湪鍙戦€佺姸鎬 begin if(rst_n==0) tx_status<=1'b0; else if(tx_en==1) tx_status<=1'b1; else if (bit_cnt>=4'd9) tx_status<=1'b0; else tx_status<=tx_status; end always @ (posedge clk or negedge rst_n ) //璁℃暟鍣 begin if(rst_n==0) cnt<=16'b0; else if(tx_status==1'b1) begin if(cnt>=BPS_CNT-1'b1) cnt<=16'b0; else cnt<=cnt+1'b1; end else cnt<=16'b0; end always @ (posedge clk or negedge rst_n ) //浣嶈鏁板櫒 begin if(rst_n==0) bit_cnt<=4'd0; else if(bit_cnt>=4'd9) bit_cnt<=4'd0; else if(cnt>=BPS_CNT-1'b1) bit_cnt<=bit_cnt+4'd1; else bit_cnt<=bit_cnt; end always @ (posedge clk or negedge rst_n ) //鍙戦€佹暟鎹 begin if(rst_n==0) tx<=1'b1; else if(tx_status==1'b1) begin case(bit_cnt) 4'd0: tx<=1'b0; 4'd1: tx<=txdata[0]; 4'd2: tx<=txdata[1]; 4'd3: tx<=txdata[2]; 4'd4: tx<=txdata[3]; 4'd5: tx<=txdata[4]; 4'd6: tx<=txdata[5]; 4'd7: tx<=txdata[6]; 4'd8: tx<=txdata[7]; 4'd9: tx<=1'b1; default : tx<=1'b1; endcase end else tx<=1'b1; end endmodule
UART TX 仿真代码
`include "head.v" `timescale 1ns/1ns module uart_tx_tb; reg clk; reg rst_n; reg [7:0] din; reg tx_en; wire tx; wire tx_status; initial begin clk=0; rst_n=0; din=16'h00; tx_en=0; #8681; rst_n=1; din=16'haa; tx_en=1; #20; tx_en=0; #86810; #8681; din=16'hab; tx_en=1; #20; tx_en=0; #86810; #8681; $stop; end always #10 clk=~clk; uart_tx #( .CLK(`UART_CLK) , .BPS(`UART_BPS) ) tx_dut //========================< 端口 >========================================== ( .clk (clk) , //时钟,50Mhz .rst_n(rst_n) , //复位,低电平有效 .din (din) , //需要发送的数据 .tx_en(tx_en) ,//发送允许 .tx (tx) , //发送引脚 .tx_status(tx_status) //发送状态 ); endmodule
UART TX 仿真图片