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