码迷,mamicode.com
首页 > 其他好文 > 详细

UART协议的FPGA实现(线性序列机)

时间:2017-11-11 16:44:54      阅读:276      评论:0      收藏:0      [点我收藏+]

标签:async   logs   信任   bit   产生   rip   tee   校验位   png   

实现uart其实早就写了,不过不太完善,对于一个完美主义者来说,必须解决掉它。
1.什么是UART?
       通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART,是一种异步收发传输器。是异步通信协议。
2.什么是RS232?
RS232是物理层的电气接口要求。是一种接口标准。uart可以使用rs232物理层来通信。总的来说,对于一项通信任务,通信协议可以使用UART协议,而UART协议可以通过COM端口来实现硬件连线,此协议下的传输方式可以选用RS232或者RS485等。
开发板上的是:
技术分享
UART实现方式:状态机或者线性序列机。
3.什么叫线性序列机?
当知晓信号在每个时刻的改变情况,那么就可以用计数器去拟合信号变化,比如在cnt=5的时候信号变1了,cnt=8的时候信号变0;当然这是可以自定义的。
简单的测试逻辑(回环测试):
技术分享
以下通过线性序列机实现:
首先看看uart协议的数据格式:信号线上空闲的时候为高电平,当出现下跳到低电平的时候表示数据的起始位,接着的是低位在前高位在后的数据流,尾部可加奇偶校验位,最后加停止位,停止位长度可以定义。
技术分享

技术分享

编码实现:
波特率产生,波特率选择。波特率模块塞tx以及rx模块中了。rx中的采样时钟bps要快16倍。
什么叫波特率?
9600bps/s:表示1s信号可以传输9600bit的数据。
波特率与FPGA时钟关系:
总计数等于系统频率除以波特率。比如50m/9600=5208;
 
rtl图:
技术分享

技术分享

回环测试综合资源使用情况以及糟糕条件下的Fmax: 

技术分享

技术分享

通过串口助手测试: 

技术分享

测试ok。
 
代码:
//************************************************
//  Filename      : uart_tx.v                             
//  Author        : kingstacker                  
//  Company       : School                       
//  Email         : kingstacker_work@163.com     
//  Device        : Altera cyclone4 ep4ce6f17c8  
//  Description   :                              
//************************************************
module  uart_tx (
/*i*/   input    wire             clk            ,
        input    wire             rst_n          ,
        input    wire             send_en        ,
        input    wire    [2:0]    bps_set        ,
        input    wire    [7:0]    data_i         ,
/*o*/   output   wire             tx             ,
        output   wire             tx_done 
);
reg send_en_reg0;
reg send_en_reg1;
reg [7:0] data_i_reg;
reg bps_clk;
reg bps_en;
reg [12:0] bps;
reg [12:0] bps_cnt;
reg [3:0] cnt;
reg tx_done_reg;
reg tx_reg;
//bps select;
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        bps <= 13d5207; //324
    end //if
    else begin
        case (bps_set)
                3d0:    bps <= 13d5207;
                3d1:    bps <= 13d2603;
                3d2:    bps <= 13d1301 ;
                3d3:    bps <= 13d867 ;
                3d4:    bps <= 13d433 ;
                default: bps <= 13d5207;
            endcase //case    
    end //else
end //always
always @(posedge clk or negedge rst_n) begin //bps_cnt;
    if (~rst_n) begin
        bps_cnt <= 0;
    end //if
    else begin
        if (bps_en == 1b1) begin
            bps_cnt <= (bps_cnt == bps) ? 13d0 : bps_cnt + 1b1;
        end
        else begin
            bps_cnt <= 0;        
        end    
    end //else
end //always
always @(posedge clk or negedge rst_n) begin //bps_clk;
    if (~rst_n) begin
        bps_clk <= 0;
    end //if
    else begin
        if (bps_cnt == 13d1) begin
            bps_clk <= 1b1;
        end 
        else begin
            bps_clk <= 1b0;       
        end   
    end //else
end //always
always @(posedge clk or negedge rst_n) begin //send_en syn;
    if (~rst_n) begin
        send_en_reg0 <= 0;
        send_en_reg1 <= 0;
    end //if
    else begin
        send_en_reg0 <= send_en;
        send_en_reg1 <= send_en_reg0;    
    end //else
end //always
always @(posedge clk or negedge rst_n) begin //data refresh;
    if (~rst_n) begin
        data_i_reg <= 0;
    end //if
    else begin
        data_i_reg <= (send_en_reg1) ? data_i : data_i_reg;    
    end //else
end //always
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        bps_en <= 1b0;
    end //if
    else begin
        if (send_en_reg1 == 1b1) begin
            bps_en <= 1b1;
        end    
        else begin
            bps_en <= (cnt == 4d10) ? 1b0 : bps_en;
        end
    end //else
end //always
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        cnt <= 0;
    end //if
    else begin
        if (cnt == 4d10) begin
            cnt <= 0;
        end    
        else begin
            cnt <= (bps_clk == 1b1) ? cnt + 1b1 : cnt;
        end
    end //else
end //always
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        tx_done_reg <= 1b0;
        tx_reg <= 1b1;
    end //if
    else begin
        case (cnt)
                0 : begin tx_done_reg <= 1b0;tx_reg <= 1b1; end
                1 : begin tx_reg <= 1b0; end
                2 : begin tx_reg <= data_i_reg[0]; end
                3 : begin tx_reg <= data_i_reg[1]; end
                4 : begin tx_reg <= data_i_reg[2]; end
                5 : begin tx_reg <= data_i_reg[3]; end
                6 : begin tx_reg <= data_i_reg[4]; end
                7 : begin tx_reg <= data_i_reg[5]; end
                8 : begin tx_reg <= data_i_reg[6]; end
                9 : begin tx_reg <= data_i_reg[7]; end
                10: begin tx_done_reg <= 1b1;tx_reg <= 1b1; end
                default:  begin tx_done_reg <= 1b0;tx_reg <= 1b1; end
            endcase //case    
    end //else
end //always
assign tx_done = tx_done_reg;
assign tx = tx_reg;

endmodule
//************************************************
//  Filename      : uart_rx.v                             
//  Author        : kingstacker                  
//  Company       : School                       
//  Email         : kingstacker_work@163.com     
//  Device        : Altera cyclone4 ep4ce6f17c8  
//  Description   : uart rx;                             
//************************************************
module  uart_rx (
/*i*/   input    wire             clk                  ,
        input    wire             rst_n                ,
        input    wire    [2:0]    bps_set              ,
        input    wire             rx                   ,
/*o*/   output   wire    [7:0]    data_o               ,
        output   wire             rx_done              
);
reg  rx_reg0;
reg  rx_reg1;
reg  rx_temp0;
reg  rx_temp1;
reg  bps_clk;
reg  bps_en;
wire rx_neg;
reg [8:0] bps;
reg [8:0] bps_cnt;
reg [7:0] cnt;
reg rx_done_reg;
reg [7:0] data_o_reg;
reg [7:0] data_o_reg1;
always @(posedge clk or negedge rst_n) begin //syn rx;
    if (~rst_n) begin
        rx_reg0 <= 0;
        rx_reg1 <= 0;
    end //if
    else begin
        rx_reg0 <= rx;
        rx_reg1 <= rx_reg0;    
    end //else
end //always
always @(posedge clk or negedge rst_n) begin //neg;
    if (~rst_n) begin
        rx_temp0 <= 0;
        rx_temp1 <= 0;
    end //if
    else begin
        rx_temp0 <= rx_reg1;
        rx_temp1 <= rx_temp0;    
    end //else
end //always
assign rx_neg = (~rx_temp0)&&rx_temp1;
//bps select;
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        bps <= 9d324; //324
    end //if
    else begin
        case (bps_set)
                3d0:    bps <= 9d324;
                3d1:    bps <= 9d162;
                3d2:    bps <= 9d80 ;
                3d3:    bps <= 9d53 ;
                3d4:    bps <= 9d26 ;
                default: bps <= 9d324;
            endcase //case    
    end //else
end //always
always @(posedge clk or negedge rst_n) begin //bps_cnt;
    if (~rst_n) begin
        bps_cnt <= 0;
    end //if
    else begin
        if (bps_en == 1b1) begin
            bps_cnt <= (bps_cnt == bps) ? 9d0 : bps_cnt + 1b1;
        end
        else begin
            bps_cnt <= 0;        
        end    
    end //else
end //always
always @(posedge clk or negedge rst_n) begin //bps_clk;
    if (~rst_n) begin
        bps_clk <= 0;
    end //if
    else begin
        if (bps_cnt == 9d1) begin
            bps_clk <= 1b1;
        end 
        else begin
            bps_clk <= 1b0;       
        end   
    end //else
end //always
always @(posedge clk or negedge rst_n) begin //cnt;
    if (~rst_n) begin
        cnt <= 0;
    end //if
    else begin
        if (bps_en == 1b1) begin
            cnt <= (bps_clk == 1b1) ? cnt + 1b1 : cnt;
        end
        else begin
            cnt <= 0;        
        end    
    end //else
end //always
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        bps_en <= 0;
    end //if
    else begin
        if (rx_neg == 1b1) begin
            bps_en <= 1b1;
        end    
        else begin
            bps_en <= (cnt == 8d159 || (cnt == 8d7 && (rx_reg1))) ? 1b0 : bps_en;
        end
    end //else
end //always
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        rx_done_reg <= 1b0;
        data_o_reg  <= 0;
    end //if
    else begin
        case (cnt)
            0  : begin rx_done_reg   <= 1b0; end 
            23 : begin data_o_reg[0] <= rx_reg1; end 
              39 : begin data_o_reg[1] <= rx_reg1; end 
              55 : begin data_o_reg[2] <= rx_reg1; end 
              71 : begin data_o_reg[3] <= rx_reg1; end 
              87 : begin data_o_reg[4] <= rx_reg1; end 
              103: begin data_o_reg[5] <= rx_reg1; end 
              119: begin data_o_reg[6] <= rx_reg1; end 
              135: begin data_o_reg[7] <= rx_reg1; end 
              159: begin rx_done_reg   <= 1b1; end 
              default: ;
        endcase //case    
    end //else
end //always
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        data_o_reg1 <= 0;
    end //if
    else begin
        data_o_reg1 <= (cnt == 8d159) ? data_o_reg : data_o_reg1;    
    end //else
end //always
assign rx_done = rx_done_reg;
assign data_o  = data_o_reg1;

endmodule

top.v就不贴了,

工程完整源代码可在码云中查看和下载:https://gitee.com/kingstacker/uart

以上。

UART协议的FPGA实现(线性序列机)

标签:async   logs   信任   bit   产生   rip   tee   校验位   png   

原文地址:http://www.cnblogs.com/kingstacker/p/7819258.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!