一个串口的完整FPGA工程

源代码在线查看: txd.v

软件大小: 2023 K
上传用户: archimedes88
关键词: FPGA 串口 工程
下载地址: 免注册下载 普通下载 VIP

相关代码

				/*********************************************************************************************************
				 **                                  All right reserve 2008-2009(C) 
				 **                             Created & maintain by http://www.edaok.net
				 **=======================================================================================================
				 ** 模 块 名:   uart.v
				 ** 描    述:   实现UART的发送功能, 数据帧字节长度可设置, 支持奇偶检验功能; 实现了AVR单片机的通用异步串口
				 **             的大部分功能, (没有多机通信, 同步发送方式)
				 **
				 ** 原 作 者:   Adeko (http://www.edaok.net)
				 ** 参 与 者:   (...welcome you join in)
				 **
				 **=======================================================================================================
				 ********************************************************************************************************/
				
				module txd (
				    clk,
				    rst_n,
				    
				    clk_en,
				    data_i,
				    enable,
				
				    txd_xo,
				
				    ctrl_i,
				    frame_bits_i,
				    stat_o,
				
				    busy_o
				);
				
				input               clk;                                        //  全局时钟时
				input               rst_n;                                      //  全局复位时, 低有效
				
				input               clk_en;
				input   [7:0]       data_i;                                     //  将要发送到UART总线上的数据
				input               enable;                                     //  模块使能线
				
				output              txd_xo;                                     //  UART数据发送端口
				
				input   [4:0]       ctrl_i;                                     //  控制信号输入
				input   [3:0]       frame_bits_i;                               //  帧数据位设置输入
				output  [1:0]       stat_o;                                     //  UART发送器状态输出
				
				output              busy_o;                                     //  发送器正在工作, 非空闲
				                                                                                                        
				
				/*********************************************************************************************************
				 ** UART发送器状态机状态定义
				 ********************************************************************************************************/
				`define TX_STAT_WIDTH       8
				parameter   [`TX_STAT_WIDTH - 1 : 0]
				    TX_IDLE         = `TX_STAT_WIDTH'b0000_0001,                //  总线空闲状态, 等待发送数据
				    TX_READY        = `TX_STAT_WIDTH'b0000_0010,                //  准备发送状态, 把数据放入发送缓冲区
				    TX_START        = `TX_STAT_WIDTH'b0000_0100,                //  发送起始化状态, 把总线拉低(清0)
				    TX_DATA         = `TX_STAT_WIDTH'b0000_1000,                //  发送数据位状态, 往总线逐位输出数据, LSB
				    TX_PARITY       = `TX_STAT_WIDTH'b0001_0000,                //  发送校验位状态, 根据帧格式配置输出
				    TX_STOP1        = `TX_STAT_WIDTH'b0010_0000,                //  发送停止位状态, 往总线写"1"
				    TX_STOP2        = `TX_STAT_WIDTH'b0100_0000,
				    TX_DONE         = `TX_STAT_WIDTH'b1000_0000;                //  发送完志状态
				
				reg [`TX_STAT_WIDTH - 1 : 0]    rStatTxCur,                     //  UART发送器当前的状态, 默认为空闲状态
				                                rStatTxNext;                    //  UART发送器下一个状态
				
				reg     [7:0]       rTxDatSft;
				reg     [3:0]       rTxClkCnt;
				reg     [3:0]       rTxBitCnt;
				reg                 rPlsBaudTick;
				reg                 rPlsStatChanged;
				
				initial                                                         //  为仿真测试初始化
				begin
				    rStatTxCur      				    rStatTxNext     				    rTxDatSft       				    rTxClkCnt       				    rTxBitCnt       				    rPlsBaudTick    				    rPlsStatChanged 				end
				
				
				wire                wFlgParEn   = ctrl_i[4];                    //  1=使能奇偶校验位, 0=禁能
				wire                wFlgParMod  = ctrl_i[3];                    //  1=奇校验, 0=偶校验
				wire                wStopBits   = ctrl_i[2];                    //  1=2位停止位, 0=1位停止位
				wire                wPlsDoneClr = ctrl_i[1];                    //  清除发送完成标志的脉冲
				wire                wFlgTxStart = ctrl_i[0];                    //  启动发送信号
				
				wire    [3:0]       wDatWid     = frame_bits_i;                 //  帧的数据位长度, 实际位数为输入值-'1', 即"8"为'7'
				
				reg                 rFlgDone;                                   //  发送器完成发送标记
				reg                 rFlgNewDat;                                 //  发送器的发送缓冲器数据已载入, 可以申请新的数据
				reg                 rParVal;                                    //  奇偶校验的运算结果, 为偶校验结果, 奇校验则取反
				
				initial 
				begin
				    rFlgDone    				    rFlgNewDat  				    rParVal     				end
				
				
				/*********************************************************************************************************
				 ** 更新当前的状态机, 并处理相关的关键数据
				 ********************************************************************************************************/
				always @(posedge clk or negedge rst_n)
				begin : TX_STAT_UPDATE
				    if (~rst_n) begin
				        rStatTxCur      				        rPlsStatChanged 				    end
				    else begin
				        rStatTxCur      				        rPlsStatChanged 				    end
				end
				
				
				/*********************************************************************************************************
				 ** 根据多个信号和当前状态机的状态, 判断发送器状态机的下一个状态
				 **
				 ** [特别注意]: 
				 ** 状态值使用OneHot编码, 而这种编码一般会优为移位寄存器, 为了防止状态出现00000的情况(如时钟质量差), 
				 ** 在综合器中要设置'safe stat mechine = on'(安全状态机)
				 ********************************************************************************************************/
				always @(
				    rPlsBaudTick or
				    wFlgTxStart or
				    rStatTxCur or
				    rTxClkCnt or 
				    rTxBitCnt or
				    wDatWid or
				    wFlgParEn or 
				    wFlgParMod or
				    clk_en or
				    wStopBits or
				    enable
				    )
				begin : TX_NEXT_STAT_JUDGE
				
				    case (rStatTxCur)                                           //  根据当前状态机的状态, 判断输入信号, 得
				                                                                //  到发送器状态机的下一个状态 
				    TX_IDLE: begin                                              
				        if (wFlgTxStart && enable)                              //  当模块端口的发送数据标志有效, 则启动发送事件
				            rStatTxNext 				        else 
				            rStatTxNext 				    end
				    
				    TX_READY: begin
				        if (clk_en) begin                                       //  同步UART时钟
				            rStatTxNext 				        end 
				        else begin
				            rStatTxNext 				        end
				    end
				
				    TX_START: begin
				        if (rPlsBaudTick)                                       //  持续一个波特位, 进入帧的数据位状态
				            rStatTxNext 				        else
				            rStatTxNext 				    end
				    
				    TX_DATA:
				    begin
				        if ( (rTxBitCnt == wDatWid) && (rPlsBaudTick) ) begin   //  当逐位发送完帧格式设置的位数后, 进入下一状态
				            if (wFlgParEn)
				                rStatTxNext 				            else
				                rStatTxNext 				        end
				        else begin
				            rStatTxNext 				        end
				    end
				
				    TX_PARITY: begin
				        if (rPlsBaudTick)
				            rStatTxNext 				        else
				            rStatTxNext 				    end
				
				    TX_STOP1: begin
				        if (rPlsBaudTick) begin
				            if (wStopBits)                                      //  如果设置了2个停止位, 则再进入停止位
				                rStatTxNext 				            else
				                rStatTxNext 				        end
				        else begin
				            rStatTxNext 				        end
				    end
				
				    TX_STOP2: begin
				        if (rPlsBaudTick)
				            rStatTxNext 				        else
				            rStatTxNext 				    end
				
				    TX_DONE: begin
				        rStatTxNext 				    end
				    
				    default: begin
				        rStatTxNext 				    end 
				
				    endcase
				end
				
				
				reg             rTxdTmp;
				reg             rFlgBusy;
				always @(posedge clk or negedge rst_n)
				begin : TX_STAT_PROCESS
				
				    if (~rst_n) begin
				
				        rTxDatSft   				        rTxdTmp     				
				        rFlgDone    				        rFlgNewDat  				
				        rParVal     				        
				        rFlgBusy    				
				        rTxClkCnt       				        rTxBitCnt       				        rPlsBaudTick    				        
				    end 
				    else begin
				
				        rPlsBaudTick    				
				        if ( (rStatTxCur == TX_IDLE) || 
				             (rStatTxCur == TX_READY) ) begin                   //  下一状态为空闲时, 复位计数器
				            rTxClkCnt   				            rTxBitCnt   				        end
				        else if (clk_en) begin 
				            rTxClkCnt   				            
				            if (rTxClkCnt == 4'hF) begin                        //  UART波特率为clk_en / 16
				                rTxBitCnt   				                rPlsBaudTick   				            end
				        end
				
				        rFlgBusy    				        rFlgNewDat  				
				        if (wPlsDoneClr) begin                                  //  当模块端口清除完成标志有效
				            rFlgDone    				        end
				
				
				        case (rStatTxCur)
				
				        TX_IDLE: begin
				            rTxdTmp 				            rParVal 				            rFlgBusy 				        end
				
				        TX_READY: begin
				            rTxdTmp 				
				            if (rPlsStatChanged) begin
				                rTxDatSft   				                rFlgNewDat  				            end
				        end
				
				        TX_START: begin
				            rTxdTmp 				        end
				        
				        TX_DATA: begin
				            if ( (rPlsBaudTick || rPlsStatChanged) && 
				                (rTxBitCnt != wDatWid) ) begin
				
				                rParVal 				                
				                rTxdTmp 				                
				                rTxDatSft   > 1;
				            end
				        end
				
				        TX_PARITY: begin
				            if (~wFlgParMod)                                    //  偶校验
				                rTxdTmp 				            else
				                rTxdTmp 				        end
				
				        TX_DONE: begin
				            rTxdTmp     				            rFlgDone    				        end
				
				        default: begin
				            rTxdTmp 				        end
				
				        endcase  
				    end
				end
				
				assign  txd_xo  = rTxdTmp;                                      //  输出UART的发送数据 (TxD)
				
				assign  stat_o  = {rFlgDone, rFlgNewDat};
				
				assign  busy_o  = rFlgBusy;
				
				endmodule
				
				/*********************************************************************************************************
				 ** End Of File
				 ********************************************************************************************************/
				
							

相关资源