基于Verilog的UART收发模块
时间:10-02
整理:3721RD
点击:
//;=================================================================*
//; 模块功能说明: UART Transmit and Receiver *
//; 文件版本: v1.00 *
//; 开发人员: *
//; 创建时间: 2014-06-13 *
//;=================================================================*
//; 程序修改记录(最新的放在最前面):
//; , :
//;读者需要了解串口的通信协议方便理解程序。
//;原理根据定时器来完成定时的接收和定时的发送。重点是波特率的概念。
//;根据接收字节数,利用状态机完成分段处理。
///////////////////////////////////////////////////////////////////////////////////
module uart(
input clk100m,//系统时钟
input reset_n, //复位
input rx_en,//接收使能
input tx_en,//发送使能
input [7:0] tx_data,//待发送数据
output [7:0] rx_data,//已接收数据
output uart_tx_out,//串行发送
input uart_rx_in, //串行接收
output rx_Busy,//当正在接收时拉高Busy。
output rx_Finish,//接收到正确帧拉高一个脉宽。
output tx_Busy,//当正在发送时拉高Busy。
output tx_Finish//当发送到完一帧拉高一个脉宽。
);
//宏定义///////////////////////////////////////////////////////////////////////////
parameter baud_rate = 10414;//接收波特率计算:N=(1/9600)*(1/f)
parameter baud_rate_half = 5207;//中间采样时钟
//UART接收部分/////////////////////////////////////////////////////////////////////
//一帧起始检测/////////////////////////////////////////////////////////////////////
reg rx_in1;
reg rx_in2;
reg rx_in3;
reg rx_in4;
wire rx_fall_flag;
assign rx_fall_flag = rx_in4 && rx_in3 && (!rx_in2) && (!rx_in1);//下降沿输出高脉冲
always @ (posedge clk100m or negedge reset_n)
begin
if(~reset_n)begin
rx_in1 <= 1'b1;
rx_in2 <= 1'b1;
rx_in3 <= 1'b1;
rx_in4 <= 1'b1;
end else begin//连续4次采样进行滤波去抖
rx_in1 <= uart_rx_in;
rx_in2 <= rx_in1;
rx_in3 <= rx_in2;
rx_in4 <= rx_in3;
end
end
//接收波特率生成/////////////////////////////////////////////////////////////////////
reg [13:0] rxcnt_bps;
reg rxcnt_en;
wire rxbps_clk;
assign rxbps_clk = (rxcnt_bps == baud_rate_half)? 1'b1 : 1'b0;//产生中间采样时钟
always @ (posedge clk100m or negedge reset_n)
begin
if(~reset_n)begin
rxcnt_bps <= 0;
end else if(rxcnt_bps == baud_rate)begin
rxcnt_bps <= 14'b0;
end else if(rxcnt_en)begin
rxcnt_bps <= rxcnt_bps + 1;
end else begin
rxcnt_bps <= 0;
end
end
//接收控制/////////////////////////////////////////////////////////////////////
reg [7:0] rxdata;
reg rxBusy;
reg rxFinish;
reg [3:0] rxstate;//状态机
assign rx_data = rxdata;
assign rx_Busy = rxBusy;
assign rx_Finish = rxFinish;
always @ (posedge clk100m or negedge reset_n)//原理定时中间采样
begin
if(~reset_n)begin
rxdata <= 8'b0;
rxBusy <= 1'b0;
rxFinish <= 1'b0;
rxstate <= 4'b0;
rxcnt_en <= 1'b0;
end else if(rx_en)begin
case(rxstate)
4'd0 :
if(rx_fall_flag)begin//检测到由高到低,起始位
rxstate <= rxstate+1;//进入下一个状态
rxcnt_en <= 1'b1;//使能波特率采样时钟模块
rxFinish <= 1'b1;//置忙信号
rxBusy <= 1'b1;
end
4'd1 :
if(rxbps_clk)begin//起始位
rxstate <= rxstate+1;//进入下一个状态
end
4'd2, 4'd3, 4'd4, 4'd5, 4'd6, 4'd7, 4'd8, 4'd9 :
if(rxbps_clk)begin//接收数据
rxstate <= rxstate+1;//进入下一个状态
rxdata[rxstate - 2] <= uart_rx_in;//接收存储数据,先发地位
end
4'd10 :
if(rxbps_clk)begin//校验位
rxstate <= rxstate+1;//进入下一个状态
end
4'd11 :
if(rxbps_clk)begin//停止位
rxstate <= rxstate+1;//进入下一个状态
end
4'd12 :
begin
rxstate <= rxstate+1;//进入下一个状态
rxFinish <= 1'b1;//产生接收完成高脉冲
rxcnt_en <= 1'b0;//停止波特率采样模块
end
4'd13 :
begin
rxstate <= 4'b0;//返回初始状态
rxBusy <= 1'b0;//不忙,接收完成
rxFinish <= 1'b0;//产生接收完成高脉冲
end
endcase
end
end
//UART发送部分/////////////////////////////////////////////////////////////////////
//发送波特率生成/////////////////////////////////////////////////////////////////////
reg [13:0] txcnt_bps;
wire txbps_clk;
assign txbps_clk = (txcnt_bps == baud_rate_half)? 1'b1 : 1'b0;//产生中间采样时钟
always @ (posedge clk100m or negedge reset_n)
begin
if(~reset_n)begin
txcnt_bps <= 0;
end else if(txcnt_bps == baud_rate)begin
txcnt_bps <= 14'b0;
end else if(tx_en)begin
txcnt_bps <= txcnt_bps + 1;
end else begin
txcnt_bps <= 0;
end
end
//接收控制/////////////////////////////////////////////////////////////////////
reg txBusy;
reg txFinish;
reg [3:0] txstate;//状态机
reg r_uart_tx_out;
assign tx_Busy = txBusy;
assign tx_Finish = txFinish;
assign uart_tx_out = r_uart_tx_out;
always @ (posedge clk100m or negedge reset_n)//原理定时发送
begin
if(~reset_n)begin
r_uart_tx_out <= 8'b0;
txBusy <= 1'b0;
txFinish <= 1'b0;
txstate <= 4'b0;
end else if(tx_en)begin//使能发送
case(txstate)
4'd0:
if(txbps_clk)begin
txstate <= txstate + 1;//进入下一状态
r_uart_tx_out <= 1'b0;//发送起始位
txBusy <= 1'b1;//拉高忙指示信号
end
4'd1, 4'd2, 4'd3, 4'd4, 4'd5, 4'd6, 4'd7, 4'd8, : //发送数据位
if(txbps_clk)begin
txstate <= txstate + 1;
r_uart_tx_out <= tx_data[txstate - 1];
end
4'd9: //发送校验位
if(txbps_clk)begin
txstate <= txstate + 1;
r_uart_tx_out <= 1'b1;
end
4'd10: //发送停止位
if(txbps_clk)begin
txstate <= txstate + 1;
r_uart_tx_out <= 1'b1;
end
4'd11: //输出状态信号
if(txbps_clk)begin
txstate <= txstate + 1;
txFinish <= 1'b1;//输出完成指示脉冲
txBusy <= 1'b0;//拉低忙指示信号
end
4'd12:
begin
txstate <= 4'b0;//回到初始状态
txFinish <= 1'b0;//输出完成指示脉冲
end
endcase
end
end
endmodule
//; 模块功能说明: UART Transmit and Receiver *
//; 文件版本: v1.00 *
//; 开发人员: *
//; 创建时间: 2014-06-13 *
//;=================================================================*
//; 程序修改记录(最新的放在最前面):
//; , :
//;读者需要了解串口的通信协议方便理解程序。
//;原理根据定时器来完成定时的接收和定时的发送。重点是波特率的概念。
//;根据接收字节数,利用状态机完成分段处理。
///////////////////////////////////////////////////////////////////////////////////
module uart(
input clk100m,//系统时钟
input reset_n, //复位
input rx_en,//接收使能
input tx_en,//发送使能
input [7:0] tx_data,//待发送数据
output [7:0] rx_data,//已接收数据
output uart_tx_out,//串行发送
input uart_rx_in, //串行接收
output rx_Busy,//当正在接收时拉高Busy。
output rx_Finish,//接收到正确帧拉高一个脉宽。
output tx_Busy,//当正在发送时拉高Busy。
output tx_Finish//当发送到完一帧拉高一个脉宽。
);
//宏定义///////////////////////////////////////////////////////////////////////////
parameter baud_rate = 10414;//接收波特率计算:N=(1/9600)*(1/f)
parameter baud_rate_half = 5207;//中间采样时钟
//UART接收部分/////////////////////////////////////////////////////////////////////
//一帧起始检测/////////////////////////////////////////////////////////////////////
reg rx_in1;
reg rx_in2;
reg rx_in3;
reg rx_in4;
wire rx_fall_flag;
assign rx_fall_flag = rx_in4 && rx_in3 && (!rx_in2) && (!rx_in1);//下降沿输出高脉冲
always @ (posedge clk100m or negedge reset_n)
begin
if(~reset_n)begin
rx_in1 <= 1'b1;
rx_in2 <= 1'b1;
rx_in3 <= 1'b1;
rx_in4 <= 1'b1;
end else begin//连续4次采样进行滤波去抖
rx_in1 <= uart_rx_in;
rx_in2 <= rx_in1;
rx_in3 <= rx_in2;
rx_in4 <= rx_in3;
end
end
//接收波特率生成/////////////////////////////////////////////////////////////////////
reg [13:0] rxcnt_bps;
reg rxcnt_en;
wire rxbps_clk;
assign rxbps_clk = (rxcnt_bps == baud_rate_half)? 1'b1 : 1'b0;//产生中间采样时钟
always @ (posedge clk100m or negedge reset_n)
begin
if(~reset_n)begin
rxcnt_bps <= 0;
end else if(rxcnt_bps == baud_rate)begin
rxcnt_bps <= 14'b0;
end else if(rxcnt_en)begin
rxcnt_bps <= rxcnt_bps + 1;
end else begin
rxcnt_bps <= 0;
end
end
//接收控制/////////////////////////////////////////////////////////////////////
reg [7:0] rxdata;
reg rxBusy;
reg rxFinish;
reg [3:0] rxstate;//状态机
assign rx_data = rxdata;
assign rx_Busy = rxBusy;
assign rx_Finish = rxFinish;
always @ (posedge clk100m or negedge reset_n)//原理定时中间采样
begin
if(~reset_n)begin
rxdata <= 8'b0;
rxBusy <= 1'b0;
rxFinish <= 1'b0;
rxstate <= 4'b0;
rxcnt_en <= 1'b0;
end else if(rx_en)begin
case(rxstate)
4'd0 :
if(rx_fall_flag)begin//检测到由高到低,起始位
rxstate <= rxstate+1;//进入下一个状态
rxcnt_en <= 1'b1;//使能波特率采样时钟模块
rxFinish <= 1'b1;//置忙信号
rxBusy <= 1'b1;
end
4'd1 :
if(rxbps_clk)begin//起始位
rxstate <= rxstate+1;//进入下一个状态
end
4'd2, 4'd3, 4'd4, 4'd5, 4'd6, 4'd7, 4'd8, 4'd9 :
if(rxbps_clk)begin//接收数据
rxstate <= rxstate+1;//进入下一个状态
rxdata[rxstate - 2] <= uart_rx_in;//接收存储数据,先发地位
end
4'd10 :
if(rxbps_clk)begin//校验位
rxstate <= rxstate+1;//进入下一个状态
end
4'd11 :
if(rxbps_clk)begin//停止位
rxstate <= rxstate+1;//进入下一个状态
end
4'd12 :
begin
rxstate <= rxstate+1;//进入下一个状态
rxFinish <= 1'b1;//产生接收完成高脉冲
rxcnt_en <= 1'b0;//停止波特率采样模块
end
4'd13 :
begin
rxstate <= 4'b0;//返回初始状态
rxBusy <= 1'b0;//不忙,接收完成
rxFinish <= 1'b0;//产生接收完成高脉冲
end
endcase
end
end
//UART发送部分/////////////////////////////////////////////////////////////////////
//发送波特率生成/////////////////////////////////////////////////////////////////////
reg [13:0] txcnt_bps;
wire txbps_clk;
assign txbps_clk = (txcnt_bps == baud_rate_half)? 1'b1 : 1'b0;//产生中间采样时钟
always @ (posedge clk100m or negedge reset_n)
begin
if(~reset_n)begin
txcnt_bps <= 0;
end else if(txcnt_bps == baud_rate)begin
txcnt_bps <= 14'b0;
end else if(tx_en)begin
txcnt_bps <= txcnt_bps + 1;
end else begin
txcnt_bps <= 0;
end
end
//接收控制/////////////////////////////////////////////////////////////////////
reg txBusy;
reg txFinish;
reg [3:0] txstate;//状态机
reg r_uart_tx_out;
assign tx_Busy = txBusy;
assign tx_Finish = txFinish;
assign uart_tx_out = r_uart_tx_out;
always @ (posedge clk100m or negedge reset_n)//原理定时发送
begin
if(~reset_n)begin
r_uart_tx_out <= 8'b0;
txBusy <= 1'b0;
txFinish <= 1'b0;
txstate <= 4'b0;
end else if(tx_en)begin//使能发送
case(txstate)
4'd0:
if(txbps_clk)begin
txstate <= txstate + 1;//进入下一状态
r_uart_tx_out <= 1'b0;//发送起始位
txBusy <= 1'b1;//拉高忙指示信号
end
4'd1, 4'd2, 4'd3, 4'd4, 4'd5, 4'd6, 4'd7, 4'd8, : //发送数据位
if(txbps_clk)begin
txstate <= txstate + 1;
r_uart_tx_out <= tx_data[txstate - 1];
end
4'd9: //发送校验位
if(txbps_clk)begin
txstate <= txstate + 1;
r_uart_tx_out <= 1'b1;
end
4'd10: //发送停止位
if(txbps_clk)begin
txstate <= txstate + 1;
r_uart_tx_out <= 1'b1;
end
4'd11: //输出状态信号
if(txbps_clk)begin
txstate <= txstate + 1;
txFinish <= 1'b1;//输出完成指示脉冲
txBusy <= 1'b0;//拉低忙指示信号
end
4'd12:
begin
txstate <= 4'b0;//回到初始状态
txFinish <= 1'b0;//输出完成指示脉冲
end
endcase
end
end
endmodule