(10)uart串口通信

一、uart简介

 

 

二、uart串口通信实验

 其中:

  sys_clk为系统时钟。uart_rxd为串口从上位机接收到的数据,

  当检测到uart_rxd出现下降沿(起始位),start_flag产生正向脉冲,rx_flag也被拉高,

  clk_cnt为时钟计数器,由0计数到433,rx_cnt为接收数据计数器,当计数到第九位且时钟计数达到波特率的一半时,将rx_flag置低。

  在实验中,我们将传入的8bit数据存入一个临时寄存器rx_data(图中未体现),当计数到第九个时,uart_done信号产生正向脉冲,表示一次串口通信结束,此时将临时寄存器rx_data赋值给数据输出uaret_data。

  注:为了防止亚稳态的影响,我们将打两拍后的uart_rxd赋值给临时寄存器中

 

三、实验:

uart_loopback_top.v

module uart_loopback_top(
    input               sys_clk     ,
    input               sys_rst_n   ,

    input               uart_rxd    ,
    output              uart_txd    
);

wire uart_en;
wire [7:0]  uart_din;
wire [7:0]  uart_data;
wire        uart_done;
wire        uart_tx_busy;



uart_recv uart_recv_inst(
    .sys_clk    (sys_clk    )   ,
    .sys_rst_n  (sys_rst_n  )   ,

    .uart_rxd   (uart_rxd   )   ,
    .uart_data  (uart_data    ) ,
    .uart_done  (uart_done   )
);

uart_send uart_send_inst(
    .sys_clk    (sys_clk    )   ,
    .sys_rst_n  (sys_rst_n  )   ,

    .uart_en    (uart_en    )   ,
    .uart_din   (uart_din   )   ,

    .uart_txd   (uart_txd   )   ,
    .uart_tx_busy(uart_tx_busy)
);

uart_loop uart_loop_inst(
    .sys_clk    (sys_clk    )   ,
    .sys_rst_n  (sys_rst_n  )   ,

    .recv_done  (uart_done  )   ,
    .recv_data  (uart_data   )  ,
    .tx_busy    (uart_tx_busy)  ,

    .send_en    (uart_en    )   ,
    .send_data  (uart_din   )
);
endmodule

uart_recv.v

module uart_recv(
    input               sys_clk     ,
    input               sys_rst_n   ,

    input               uart_rxd    ,

    output  reg [7:0]   uart_data   ,
    output  reg         uart_done
);

parameter  CLK_FREQ = 50000000;
parameter  UART_BPS = 115200;
parameter BPS_CNT = (CLK_FREQ/UART_BPS);

reg         uart_rxd_d0;
reg         uart_rxd_d1;
reg         rx_flag;
reg [3:0]   rx_cnt;
reg [8:0]   clk_cnt;
reg [7:0]   rx_data;    

wire start_flag;

assign start_flag = (!uart_rxd_d0) & (uart_rxd_d1);

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        begin
        uart_rxd_d0 <= 1'b0;
        uart_rxd_d1 <= 1'b0;
        end
    else
        begin
        uart_rxd_d0 <= uart_rxd;
        uart_rxd_d1 <= uart_rxd_d0;
        end
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        rx_flag <= 1'b0;
    else
        begin
        if(start_flag == 1)
            rx_flag <= 1'b1;
        else if ((rx_cnt == 4'd9)&&(clk_cnt ==(BPS_CNT/2)))
            rx_flag <= 1'b0;
        else
            rx_flag <= rx_flag;
        end
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        clk_cnt <= 9'd0;
    else if(rx_flag)begin
        if (clk_cnt == BPS_CNT-1)
            clk_cnt <= 9'd0;
        else
            clk_cnt <= clk_cnt + 1'b1;
    end
    else
        clk_cnt <= 9'd0;
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        rx_cnt <= 4'd0;
    else if(rx_flag)begin
        if (clk_cnt == BPS_CNT-1)
            rx_cnt <= rx_cnt + 1'b1;
        else
            rx_cnt <= rx_cnt;
    end
    else
        rx_cnt <= 4'd0;
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        rx_data <= 8'd0;
    else if(rx_flag) begin
        if (clk_cnt == (BPS_CNT-1)/2)begin       
            case(rx_cnt)
                4'd1: rx_data[0] <=uart_rxd_d1;     
                4'd2: rx_data[1] <=uart_rxd_d1;
                4'd3: rx_data[2] <=uart_rxd_d1;
                4'd4: rx_data[3] <=uart_rxd_d1;
                4'd5: rx_data[4] <=uart_rxd_d1;
                4'd6: rx_data[5] <=uart_rxd_d1;
                4'd7: rx_data[6] <=uart_rxd_d1;
                4'd8: rx_data[7] <=uart_rxd_d1;
                default:;
            endcase
        end
        else
            rx_data <= rx_data;
    end
    else
        rx_data <= 8'd0;
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        uart_data <= 8'd0;
        uart_done <= 1'b0;
    end
    else if(rx_cnt == 4'd9)begin
        uart_data <= rx_data;
        uart_done <= 1'b1;
    end
    else begin
        uart_data <= 8'd0;
        uart_done <= 1'b0;
    end
end

endmodule

uart_send.v

module uart_send(
    input               sys_clk     ,
    input               sys_rst_n   ,

    input               uart_en     ,
    input    [7:0]      uart_din    ,

    output   reg        uart_txd    ,
    output              uart_tx_busy
);

parameter  CLK_FREQ = 50000000;
parameter  UART_BPS = 115200;
parameter BPS_CNT = (CLK_FREQ/UART_BPS);

reg         uart_en_d0, uart_en_d1;
reg         tx_flag;
reg  [7:0]  tx_data;
reg  [8:0]  clk_cnt;
reg  [3:0]  tx_cnt;

wire en_flag;

assign uart_tx_busy = tx_flag;
assign en_flag = (uart_en_d0) & (!uart_en_d1);

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        begin
        uart_en_d0 <= 1'b0;
        uart_en_d1 <= 1'b0;
        end
    else
        begin
        uart_en_d0 <= uart_en;
        uart_en_d1 <= uart_en_d0;
        end
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        tx_flag <= 1'b0;
        tx_data <= 8'd0;
    end
    else if(en_flag)begin
        tx_flag <= 1'b1;
        tx_data <= uart_din;
    end
    else if((tx_cnt == 4'd9)&&(clk_cnt == BPS_CNT-BPS_CNT/16))begin
        tx_flag <= 1'b0;
        tx_data <= 8'd0;
    end
    else begin
        tx_flag <= tx_flag;
        tx_data <= tx_data;
    end
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        clk_cnt <= 9'd0;
    else if(tx_flag)begin
        if (clk_cnt == BPS_CNT-1)
            clk_cnt <= 9'd0;
        else
            clk_cnt <= clk_cnt + 1'b1;
    end
    else
        clk_cnt <= 9'd0;
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        tx_cnt <= 4'd0;
    else if(tx_flag)begin
        if (clk_cnt == BPS_CNT-1)
            tx_cnt <= tx_cnt + 1'b1;
        else
            tx_cnt <= tx_cnt;
    end
    else
        tx_cnt <= 4'd0;
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        uart_txd <= 1'b1;
    else if(tx_flag)
        case(tx_cnt)
            4'd0: uart_txd <= 1'b0;
            4'd1: uart_txd <= tx_data[0];     
            4'd2: uart_txd <= tx_data[1];
            4'd3: uart_txd <= tx_data[2];
            4'd4: uart_txd <= tx_data[3];
            4'd5: uart_txd <= tx_data[4];
            4'd6: uart_txd <= tx_data[5];
            4'd7: uart_txd <= tx_data[6];
            4'd8: uart_txd <= tx_data[7];
            4'd9: uart_txd <= 1'b1;
            default:;
        endcase
    else
        uart_txd <= 1'b1;
end

endmodule

uart_loop.v

module uart_loop(
    input               sys_clk         ,
    input               sys_rst_n       ,    

    input               recv_done       ,
    input       [7:0]   recv_data       ,
    input               tx_busy         ,

    output  reg         send_en         ,
    output  reg [7:0]   send_data


);

reg         recv_done_d0;
reg         recv_done_d1;
reg         tx_ready;

wire        recv_done_flag;

assign recv_done_flag = (recv_done_d0) & (!recv_done_d1);

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        begin
        recv_done_d0 <= 1'b0;
        recv_done_d1 <= 1'b0;
        end
    else
        begin
        recv_done_d0 <= recv_done;
        recv_done_d1 <= recv_done_d0;
        end
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)begin
        send_en <= 1'b0;
        send_data <= 8'd0;
        tx_ready <= 1'b0;
    end
    else begin
        if(recv_done_flag)begin
            tx_ready <= 1'b1;
            send_en <= 1'b0;
            send_data <= recv_data;
        end
        else if((!tx_busy)&&(tx_ready))begin
            tx_ready <= 1'b0;
            send_en <= 1'b1;
        end
    end
end
endmodule

开发板连接:

 

串口通信:

 可以看到发出去的8位数据被成功地发送回来,证明实验成功


一开始打开设备管理器发现没有串口,添加过时硬件之后发现只有一个CMO3还是坏的,进行以下操作后成功使用COM5串口:

1.将串口的线换了个usb口插入

2.更新了一下ch340的驱动

我觉得很大程度上是第二个解决了,因为我在更新的时候显示已存在的驱动比这个新,但我还是更新了,没想到就解决了,现在长这个样子:

 

posted @ 2024-05-19 05:46  xuxuxu69  阅读(42)  评论(0编辑  收藏  举报