微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > FPGA,CPLD和ASIC > 基于Verilog的UART收发模块

基于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

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top