FPGA学习记录——实验二 串口传输

232串口协议是通信接口中最简单的协议之一,使用两根线(一根为接收数据线,一根为发送数据线)就能完成数据传输。数据在这两根线上串行传输。

 

其协议原理如下:

 空闲状态时传输线被置为高电平。开始传输数据的时候要先给一个开始标志,此时将传输线电平置低。然后由低位到高位依次传输数据。数据传输完成后,要给一个停止标志,此时传输线必须保持一段时间的高电平然后再进入空闲状态。

串口传输时需要设置波特率,波特率决定了数据传输的速度,波特率越高数据传的越快。一般常用的波特率有9600bps 19200bps 38400bps 115200bps等。如上图所示,在9600bps波特率情况下,每个状态要保持1/9600s。

串口接收代码:

// Company: 
// Engineer: Abshdbeh
// 
// Create Date: 
// Design Name: 
// Module Name: 
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module uart_rx
#(parameter CLK_FREQ='d100_000_000,
            BAUD_FREQ='d9600)
(
    input clk,
    input rst,
    input rxd,
    output reg [7:0] rx_data,
    output reg rx_done

    );
    
    parameter MAX   =   CLK_FREQ/BAUD_FREQ;
    parameter IDLE  =   4'd0    ,
              START =   4'd1    ,
              RD0   =   4'd2    ,
              RD1   =   4'd3    ,
              RD2   =   4'd4    ,
              RD3   =   4'd5    ,
              RD4   =   4'd6    ,
              RD5   =   4'd7    ,
              RD6   =   4'd8    ,
              RD7   =   4'd9    ,
              END   =   4'd10   ;
    
    reg rxd0             ;
    reg rxd1             ;
    reg [3:0] state     ;
    reg flag            ;
    reg [13:0] baud_cnt ;
    reg rd_flag         ;
    reg clr_flag        ;
    
    initial
        begin
            state=IDLE;
        end
    
    always@(posedge clk or negedge rst)
        if(!rst)
            rxd0 <= 1'b1;
        else
            rxd0 <= rxd;
    
   always@(posedge clk or negedge rst)
        if(!rst)
            rxd1 <= 1'b1;
        else
            rxd1 <= rxd0; 
            
   always@(posedge clk or negedge rst)
        if(!rst)
            flag <= 1'b0;
        else if(baud_cnt==MAX-2)
            flag <= 1'b1;
        else
            flag <= 1'b0;
    
   always@(posedge clk or negedge rst)
        if(!rst)
            baud_cnt <= 14'd0;
        else if(state==IDLE)
            baud_cnt <= 14'd0;
        else if(baud_cnt==MAX-1)
            baud_cnt <= 14'd0;
        else
            baud_cnt <= baud_cnt+1'b1;         
            
   always@(posedge clk or negedge rst)
        if(!rst)
            state <= IDLE;
        else
            case(state)
                IDLE:   
                    if(!rxd1)
                        state <= START;
                START:
                    if(flag)
                        state <= RD0;
                RD0:
                    if(flag)
                        state <= RD1;
                RD1:
                    if(flag)
                        state <= RD2;        
                RD2:
                    if(flag)
                        state <= RD3;        
                RD3:
                    if(flag)
                        state <= RD4;
                RD4:
                    if(flag)
                        state <= RD5; 
                RD5:
                    if(flag)
                        state <= RD6;
                RD6:
                    if(flag)
                        state <= RD7;
                RD7:
                    if(flag)
                        state <= END; 
                END:
                    if(flag)
                        state <= IDLE;             
               default: state <= IDLE;         
            endcase
            
    always@(posedge clk or negedge rst)
        if(!rst)
            rd_flag <= 1'b0;
        else 
            case(state)
                RD0,RD1,RD2,RD3,RD4,RD5,RD6,RD7:
                    if(baud_cnt==((MAX/2)-1))
                        rd_flag <= 1'b1;
                    else
                        rd_flag <= 1'b0;
                default: rd_flag <= 1'b0;    
            endcase
            
    always@(posedge clk or negedge rst)
        if(!rst)
            rx_data <= 8'd0;
        else if(rd_flag)
                case(state)
                    RD0:    rx_data[0] <= rxd1;
                    RD1:    rx_data[1] <= rxd1;
                    RD2:    rx_data[2] <= rxd1;
                    RD3:    rx_data[3] <= rxd1;
                    RD4:    rx_data[4] <= rxd1;
                    RD5:    rx_data[5] <= rxd1;
                    RD6:    rx_data[6] <= rxd1;
                    RD7:    rx_data[7] <= rxd1;
                    default: rx_data <= 8'd0;
                endcase
        else if(clr_flag)
            rx_data <= 8'd0;
            
     always@(posedge clk or negedge rst)
        if(!rst)
            rx_done <= 1'b0;
        else if(state==END && baud_cnt==14'd1)
            rx_done <= 1'b1;
        else
            rx_done <= 1'b0;
            
    always@(posedge clk or negedge rst)
        if(!rst)
            clr_flag <= 1'b0;
        else if(state==END && baud_cnt==((MAX/2)-1))
            clr_flag <= 1'b1;
        else
            clr_flag <= 1'b0;
    
endmodule

串口发送代码:

// Company: 
// Engineer: Abshdbeh
// 
// Create Date: 
// Design Name: 
// Module Name: 
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module uart_tx        
#(parameter CLK_FREQ='d100_000_000,              
            BAUD_RATE='d9600,
            BIT_NUM='d64)
(
    input clk,
    input rst,
    input [BIT_NUM-1:0] tx_data,
    input tx_start,
    output reg txd,
    output reg tx_done
    );
    
    localparam BAUD_CNT_MAX=CLK_FREQ/BAUD_RATE,
              BYTE_CNT_MAX=BIT_NUM/8;
    localparam IDLE  =   4'd0,
              START =   4'd1,
              TX0   =   4'd2,
              TX1   =   4'd3,
              TX2   =   4'd4,
              TX3   =   4'd5,
              TX4   =   4'd6,
              TX5   =   4'd7,
              TX6   =   4'd8,
              TX7   =   4'd9,
              END   =   4'd10;
              
    reg [13:0] baud_cnt;
    reg [4:0] byte_cnt;
    reg [3:0] state;
    reg turn_flag;
    reg byte_flag;
    reg [7:0] date_temp;
    
    initial
        begin
            state=IDLE;
            date_temp=0;
            txd=1;
            byte_cnt=0;
        end
    
    always@(posedge clk or negedge rst)         
        if(!rst)
            state <= IDLE;
        else
            case(state)
                IDLE:   if(tx_start)
                            state <= START;
                START:  if(turn_flag)
                            state <= TX0;
                TX0:    if(turn_flag)
                            state <= TX1;
                TX1:    if(turn_flag)
                            state <= TX2;
                TX2:    if(turn_flag)
                            state <= TX3;
                TX3:    if(turn_flag)
                            state <= TX4;
                TX4:    if(turn_flag)
                            state <= TX5;
                TX5:    if(turn_flag)
                            state <= TX6;
                TX6:    if(turn_flag)
                            state <= TX7;
                TX7:    if(turn_flag)
                            state <= END;
                END:    begin
                            if(tx_done)
                                state <= IDLE;
                            else if(turn_flag)
                                state <= START;
                        end
                default:    state <= IDLE;    
            endcase
    
   always@(posedge clk or negedge rst)
        if(!rst)
            turn_flag <= 1'b0;
        else
            case(state)
                START,TX0,TX1,TX2,TX3,TX4,TX5,TX6,TX7,END:
                    if(baud_cnt==BAUD_CNT_MAX-2)
                        turn_flag <= 1'b1;
                    else
                        turn_flag <= 1'b0;
                default: turn_flag <= 1'b0;
            endcase
            
    always@(posedge clk or negedge rst)
        if(!rst)
           baud_cnt <= 14'd0;
        else
            case(state)
               START,TX0,TX1,TX2,TX3,TX4,TX5,TX6,TX7,END:
                    if(baud_cnt==BAUD_CNT_MAX-1)
                        baud_cnt <= 14'd0;
                    else
                        baud_cnt <= baud_cnt+1'b1;
            default:    baud_cnt <= 14'd0;
            endcase
            
    always@(posedge clk or negedge rst)
        if(!rst)
             byte_flag  <= 1'b0;
        else
            case(state)
               END:
                    if(baud_cnt==BAUD_CNT_MAX-2)
                        byte_flag <= 1'b1;
                    else
                        byte_flag <= 1'b0;
            default:    byte_flag<= 1'b0;
            endcase  
    
    always@(posedge clk or negedge rst)
        if(!rst)
            byte_cnt <= 5'd0;
        else
            case(state)
                END:
                    if(tx_done)
                        byte_cnt <= 5'd0;
                    else if(byte_flag)
                        byte_cnt <= byte_cnt+1'b1;
                default:    byte_cnt <= byte_cnt;
            endcase
     
    always@(*)
                date_temp <= tx_data[(byte_cnt*8)+:8];
            
    always@(posedge clk or negedge rst)
        if(!rst)
            txd <= 1'b1;
        else 
            case(state)
                IDLE,END:   txd <= 1'b1;
                START:  txd <= 1'b0;
                TX0:    txd <= date_temp[0];
                TX1:    txd <= date_temp[1];
                TX2:    txd <= date_temp[2];
                TX3:    txd <= date_temp[3];
                TX4:    txd <= date_temp[4];
                TX5:    txd <= date_temp[5];
                TX6:    txd <= date_temp[6];
                TX7:    txd <= date_temp[7];
                default:    txd <= 1'b1;
            endcase
            
    always@(posedge clk or negedge rst)
        if(!rst)
            tx_done <= 1'b0;
        else if((state==END) && (byte_cnt==BYTE_CNT_MAX-1) && (baud_cnt==BAUD_CNT_MAX-2))
            tx_done <= 1'b1;
        else
            tx_done <= 1'b0;
    
endmodule

 串口环回顶层代码:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: Abshdbeh
// 
// Create Date: 
// Design Name: 
// Module Name: uart_loop
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module uart_loop(
    input clk,
    input rst,
    input rxd,
    
    output txd
    );
    
    wire [7:0] rx_data;
    wire rx_done;
    
    uart_rx
#(.CLK_FREQ  ('d100_000_000  ),
  .BAUD_FREQ ('d9600         ))
  uart_rx_inst
(
    .clk        (clk),
    .rst        (rst),
    .rxd        (rxd ),
    .rx_data    (rx_data),
    
    .rx_done    (rx_done)

    );
    
    wire tx_done;
    reg [7:0] tx_data;
    reg tx_start;
    
    always@(posedge clk or negedge rst)
        if(!rst)
            tx_start <= 1'b0;
        else if(rx_done==1'b1)
            tx_start <= 1'b1;
        else
            tx_start <= 1'b0;
            
    always@(posedge clk or negedge rst)
        if(!rst)
            tx_data <= 'd0;
        else if(rx_done==1'b1)
            tx_data <= rx_data;
    
    uart_tx        
#(.CLK_FREQ     ('d100_000_000  ),              
  .BAUD_RATE    ('d9600         ),
  .BIT_NUM      ('d8           ))
   uart_tx_inst
(
    .clk            (clk),
    .rst            (rst),
    .tx_data        (tx_data),
    .tx_start       (tx_start),
    
    .txd            (txd),
    .tx_done        (tx_done)
    
    );

    
endmodule

将程序下载到板子上,打开串口助手,进行测试,结果如下:

 

 注意:要勾选十六进制显示和十六进制发送,否则不会显示结果

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Abshdbeh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值