日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

串口通信原理

發布時間:2023/12/31 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 串口通信原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

并行通信是指數據的各個位用多條數據線同時進行傳輸?

優點:傳輸速度快

缺點:占用引腳資源多

?串行通信是將數據分成一位一位的形式在一條傳輸線上逐個傳輸

?優點:通信線路簡單、占用引腳資源少

缺點:傳輸速度慢

同步通信:帶時鐘同步信號的數據傳輸;發送方和接收方在同一時鐘的控制下,同步傳輸數據。

異步通信:不帶時鐘同步信號的數據傳輸。發送方與接收方使用各自的時鐘控制數據的發送和接收過程。

串行通信的傳輸方向:

單工 ? :數據只能沿一個方向傳輸

半雙工:數據傳輸可以沿兩個方向,但需要分時進行

全雙工:數據可以同時進行雙向傳輸

下面是常見的串行通信接口

?UART (universal asynchronous receiver-transmitter) 是一種采用異步串行通信方式的通用異步收發傳輸器。它在發送數據時將并行數據轉換成串行數據來傳輸,在接收數據時將接收到的串行數據轉換成并行數據。協議層: ? 通信協議(包括數據格式、傳輸速率等) 物理層:接口類型、電平標準等。

?UART串口通信需要兩根信號線來實現,一根用于串口發送,另外一根負責串口接收。

串口通信的速率用波特率表示,它表示每秒傳輸二進制數據的位數,單位是bps(位/秒) 常用的波特率有9600、19200、38400、57600以及115200等。

針對異步串行通信的接口標準有RS23、RS422、RS485等

1.通信實驗:開發板與上位機通過串口通信,完成數據環回實驗

2.程序設計:

首先是分頻時鐘,用pll去設計ip核,輸入時鐘是50MHZ,輸出一個時鐘為1MHz,用于仿真。

具體ip核設計可以去看前面一篇文章:pll鎖相環(可以根據系統時鐘進行倍頻、分頻、相位偏移等等,而普通的計數器只能分頻)_小泡芙?的博客-CSDN博客

接收模塊:

?

module uart_recv(input sys_clk, //系統時鐘input sys_rst_n, //系統復位,低電平有效input uart_rxd, //UART接收端口output reg uart_done, //接收一幀數據完成標志信號output reg [7:0] uart_data //接收的數據);//parameter define parameter CLK_FREQ = 50000000; //系統時鐘頻率 parameter UART_BPS = 9600; //串口波特率 localparam BPS_CNT = CLK_FREQ/UART_BPS; //為得到指定波特率,//需要對系統時鐘計數BPS_CNT次 //reg define reg uart_rxd_d0; reg uart_rxd_d1; reg [15:0] clk_cnt; //系統時鐘計數器 reg [ 3:0] rx_cnt; //接收數據計數器 reg rx_flag; //接收過程標志信號 reg [ 7:0] rxdata; //接收數據寄存器//wire define wire start_flag;//***************************************************** //** main code //***************************************************** //捕獲接收端口下降沿(起始位),得到一個時鐘周期的脈沖信號 assign start_flag = uart_rxd_d1 & (~uart_rxd_d0); //對UART接收端口的數據延遲兩個時鐘周期 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; endelse beginuart_rxd_d0 <= uart_rxd; uart_rxd_d1 <= uart_rxd_d0;end end//當脈沖信號start_flag到達時,進入接收過程 always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) rx_flag <= 1'b0;else beginif(start_flag) //檢測到起始位rx_flag <= 1'b1; //進入接收過程,標志位rx_flag拉高else if((rx_cnt == 4'd9)&&(clk_cnt == BPS_CNT/2))rx_flag <= 1'b0; //計數到停止位中間時,停止接收過程elserx_flag <= rx_flag;end end//進入接收過程后,啟動系統時鐘計數器與接收數據計數器 always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) begin clk_cnt <= 16'd0; rx_cnt <= 4'd0;end else if ( rx_flag ) begin //處于接收過程if (clk_cnt < BPS_CNT - 1) beginclk_cnt <= clk_cnt + 1'b1;rx_cnt <= rx_cnt;endelse beginclk_cnt <= 16'd0; //對系統時鐘計數達一個波特率周期后清零rx_cnt <= rx_cnt + 1'b1; //此時接收數據計數器加1endendelse begin //接收過程結束,計數器清零clk_cnt <= 16'd0;rx_cnt <= 4'd0;end end//根據接收數據計數器來寄存uart接收端口數據 always @(posedge sys_clk or negedge sys_rst_n) begin if ( !sys_rst_n) rxdata <= 8'd0; else if(rx_flag) //系統處于接收過程if (clk_cnt == BPS_CNT/2) begin //判斷系統時鐘計數器計數到數據位中間case ( rx_cnt )4'd1 : rxdata[0] <= uart_rxd_d1; //寄存數據位最低位4'd2 : rxdata[1] <= uart_rxd_d1;4'd3 : rxdata[2] <= uart_rxd_d1;4'd4 : rxdata[3] <= uart_rxd_d1;4'd5 : rxdata[4] <= uart_rxd_d1;4'd6 : rxdata[5] <= uart_rxd_d1;4'd7 : rxdata[6] <= uart_rxd_d1;4'd8 : rxdata[7] <= uart_rxd_d1; //寄存數據位最高位default:; endcaseendelse rxdata <= rxdata;elserxdata <= 8'd0; end//數據接收完畢后給出標志信號并寄存輸出接收到的數據 always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) beginuart_data <= 8'd0; uart_done <= 1'b0;endelse if(rx_cnt == 4'd9) begin //接收數據計數器計數到停止位時 uart_data <= rxdata; //寄存輸出接收到的數據uart_done <= 1'b1; //并將接收完成標志位拉高endelse beginuart_data <= 8'd0; uart_done <= 1'b0; end endendmodule

發送模塊

module uart_send(input sys_clk, //系統時鐘input sys_rst_n, //系統復位,低電平有效input uart_en, //發送使能信號input [7:0] uart_din, //待發送數據output reg uart_txd //UART發送端口);//parameter define parameter CLK_FREQ = 50000000; //系統時鐘頻率 parameter UART_BPS = 9600; //串口波特率 localparam BPS_CNT = CLK_FREQ/UART_BPS; //為得到指定波特率,對系統時鐘計數BPS_CNT次//reg define reg uart_en_d0; reg uart_en_d1; reg [15:0] clk_cnt; //系統時鐘計數器 reg [ 3:0] tx_cnt; //發送數據計數器 reg tx_flag; //發送過程標志信號 reg [ 7:0] tx_data; //寄存發送數據//wire define wire en_flag;//***************************************************** //** main code //***************************************************** //捕獲uart_en上升沿,得到一個時鐘周期的脈沖信號 assign en_flag = (~uart_en_d1) & uart_en_d0;//對發送使能信號uart_en延遲兩個時鐘周期 always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) beginuart_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//當脈沖信號en_flag到達時,寄存待發送的數據,并進入發送過程 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_flag拉高tx_data <= uart_din; //寄存待發送的數據endelse if ((tx_cnt == 4'd9)&&(clk_cnt == BPS_CNT/2))begin //計數到停止位中間時,停止發送過程tx_flag <= 1'b0; //發送過程結束,標志位tx_flag拉低tx_data <= 8'd0;endelse begintx_flag <= tx_flag;tx_data <= tx_data;end end//進入發送過程后,啟動系統時鐘計數器與發送數據計數器 always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) begin clk_cnt <= 16'd0; tx_cnt <= 4'd0;end else if (tx_flag) begin //處于發送過程if (clk_cnt < BPS_CNT - 1) beginclk_cnt <= clk_cnt + 1'b1;tx_cnt <= tx_cnt;endelse beginclk_cnt <= 16'd0; //對系統時鐘計數達一個波特率周期后清零tx_cnt <= tx_cnt + 1'b1; //此時發送數據計數器加1endendelse begin //發送過程結束clk_cnt <= 16'd0;tx_cnt <= 4'd0;end end//根據發送數據計數器來給uart發送端口賦值 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: ;endcaseelse uart_txd <= 1'b1; //空閑時發送端口為高電平 endendmodule

?頂層模塊

?

module uart_top(input sys_clk, //外部50M時鐘input sys_rst_n, //外部復位信號,低有效//uart接口input uart_rxd, //UART接收端口output uart_txd //UART發送端口);//parameter define parameter CLK_FREQ = 50000000; //定義系統時鐘頻率 parameter UART_BPS = 115200; //定義串口波特率//wire define wire uart_en_w; //UART發送使能 wire [7:0] uart_data_w; //UART發送數據 wire clk_1m_w; //1MHz時鐘,用于仿真調試//***************************************************** //** main code //***************************************************** pll_clk u_pll( //時鐘分頻模塊,用于調試.inclk0 (sys_clk),.c0 (clk_1m_w) );uart_recv #( //串口接收模塊.CLK_FREQ (CLK_FREQ), //設置系統時鐘頻率.UART_BPS (UART_BPS)) //設置串口接收波特率 u_uart_recv( .sys_clk (sys_clk), .sys_rst_n (sys_rst_n),.uart_rxd (uart_rxd),.uart_done (uart_en_w),.uart_data (uart_data_w));uart_send #( //串口發送模塊.CLK_FREQ (CLK_FREQ), //設置系統時鐘頻率.UART_BPS (UART_BPS)) //設置串口發送波特率 u_uart_send( .sys_clk (sys_clk),.sys_rst_n (sys_rst_n),.uart_en (uart_en_w),.uart_din (uart_data_w),.uart_txd (uart_txd));endmodule

仿真模塊

?

`timescale 1 ns/ 1 ns module uart_top_tb();parameter T = 20; reg sys_clk; reg sys_rst_n; reg uart_rxd;wire uart_txd;wire uart_en_w; //UART發送使能 wire [7:0] uart_data_w; //UART發送數據 wire clk_1m_w; reg uart_en; //發送使能信號 reg [7:0] uart_din; //待發送數據reg uart_done; //接收一幀數據完成標志信號 reg [7:0] uart_data; initial begin sys_clk = 1'b0;sys_rst_n = 1'b0;uart_rxd = 1;#200 sys_rst_n = 1'b1;//模擬發送一幀數據#200 uart_rxd = 0; //起始位#110000 uart_rxd = 0; #110000 uart_rxd = 1; #110000 uart_rxd = 1; #110000 uart_rxd = 0; #110000 uart_rxd = 0; #110000 uart_rxd = 1; #110000 uart_rxd = 0; #110000 uart_rxd = 1; //停止位#1500000 $stop;end always #(T/2) sys_clk = ~sys_clk; pll_clk u_pll( //時鐘分頻模塊,用于調試.inclk0 (sys_clk),.c0 (clk_1m_w) );u_uart_recv( .sys_clk (sys_clk), .sys_rst_n (sys_rst_n),.uart_rxd (uart_rxd),.uart_done (uart_en_w),.uart_data (uart_data_w));u_uart_send( .sys_clk (sys_clk),.sys_rst_n (sys_rst_n),.uart_en (uart_en_w),.uart_din (uart_data_w),.uart_txd (uart_txd)); endmodule

rtl圖:

總結

以上是生活随笔為你收集整理的串口通信原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。