UART 串口通信

编程入门 行业动态 更新时间:2024-10-24 19:16:20

UART <a href=https://www.elefans.com/category/jswz/34/1769224.html style=串口通信"/>

UART 串口通信

第18.1讲 UART串口通信原理讲解_哔哩哔哩_bilibili

并行通信

一个周期同时发送8bit的数据,占用引脚资源多

串行通信

串行通信的通信方式:

  • 同步通信

同一时钟下进行数据传输

  • 异步通信

发送设备和接收设备的时钟不同

但是需要约束波特率(1s内传输的bit数)

串行通信的传输方向:

常见串行通信接口

UART

UART(universal asynchronous receiver-transmitter):通用异步收发传输器

异步串行通信

功能:

  • 发送数据时将并行数据转换为串行数据进行传输
  • 接收数据时将串行数据转换为并行行数据进行传输

协议层

数据格式

校验位:奇偶校验

UART使用两根信号线实现,一根用于串口发送,另一根负责串口接收

传输速率 波特率

串口通信的速率用波特率表示,它表示每秒传输的二进制数据的位数,单位为bps(位/秒)

9600 19200 38400…

1s=109ns1 s = 10^9 ns 1s=109ns

假设波特率是115200 bit/s

那么发送一个bit需要 10910^9109/ 115200 ns

当频率为50Hz的时候,一个周期为 20 ns

发送一个bit需要的周期数为: 109/115200/2010^9/115200/20109/115200/20= 434

拉低的起始位,拉高的数据为,校验位,停止位都需要434个周期

物理层:接口标准

负逻辑电平:

1对应负电压,0对应正电压

3线:TX RX GND

差分传输:

RS232

DB9接口定义

USB接口

Data -/+ 差分信号

实验

实验任务

开发板与上位机通过串口通信,完成数据环回实验

程序设计

串口接收、发送:

uart_recv

串行转并行

module uart_recv (input               clk,input               rst,input               uart_rxd,output reg [7:0]    uart_data,output reg          uart_done
);// 抓取接收信号下降沿(获取数据接收的标志)
reg uart_rxd_cur, uart_rxd_pre;
wire start_flag;
assign start_flag = ~uart_rxd_cur & uart_rxd_pre;
always @(posedge clk or posedge rst) beginif(rst) beginuart_rxd_cur <= 1'b0;uart_rxd_pre <= 1'b0;endelse beginuart_rxd_cur <= uart_rxd;uart_rxd_pre <= uart_rxd_cur;end
end// 定义常量
parameter CLK_FREQ = 50000000;
parameter UART_BPS = 115200;
// 不可更改的常量
localparam BPS_CNT = CLK_FREQ / UART_BPS;reg rx_flag;
reg [3:0] rx_cnt;
reg [8:0] clk_cnt;always @(posedge clk or posedge rst) beginif(rst)rx_flag <= 1'b0;else beginif(start_flag)rx_flag <= 1'b1;else if(rx_cnt == 4'd9 && (clk_cnt == BPS_CNT/2))// 8个bit数据传输完成,且经过半个波特的停止位rx_flag <= 1'b0;elserx_flag <= rx_flag;end
end// clk_cnt 计数
always @(posedge clk or posedge rst) beginif(rst)clk_cnt <= 1'b0;else if(rx_flag) beginif(clk_cnt < BPS_CNT - 1)clk_cnt <= clk_cnt + 1'b1;elseclk_cnt <= 9'd0;endelseclk_cnt <= 9'b0;
end// rx_cnt 根据 clk_cnt 计数
always @(posedge clk or posedge rst) beginif(rst)rx_cnt <= 4'd0;else if(rx_flag) beginif(clk_cnt == BPS_CNT - 1)rx_cnt <= rx_cnt + 1'b1;elserx_cnt <= rx_cnt;endelserx_cnt <= 4'b0;end// 在中间值的时候赋值
reg [7:0] rx_data; // 临时寄存器(寄存数据)
always @(posedge clk or posedge rst) beginif(rst)rx_data <= 8'd0;else if(rx_flag) beginif(clk_cnt == BPS_CNT / 2) beginrx_data[rx_cnt - 4'b1] <= uart_rxd_pre;endelserx_data <= rx_data;endelserx_data <= 8'd0;
end// 设置输出数据uart_data和输出完成信号uart_done
always @(posedge clk or posedge rst) beginif(rst) beginuart_data <= 8'd0;uart_done <= 1'b0;endelse if(rx_cnt == 4'd9) beginuart_data <= rx_data;uart_done <= 1'b1;endelse beginuart_data <= 8'd0;uart_done <= 1'b0;end
endendmodule

uart_send

并行转串行

module uart_send (input   clk,input   rst,input   uart_en,input   [7:0] uart_din,output  reg uart_txd,output  uart_rx_busy
);// 抓取uart_en上升沿
reg uart_en_pre, uart_en_cur;
wire en_flag;
assign en_flag = ~uart_en_pre & uart_en_cur;always @(posedge clk or posedge rst) beginif(rst) beginuart_en_pre <= 1'b0;uart_en_cur <= 1'b0;endelse beginuart_en_cur <= uart_en;uart_en_pre <= uart_en_cur; end
endreg [7:0] tx_data;
reg tx_flag;
reg [3:0] tx_cnt;
reg [8:0] clk_cnt;
// 定义常量
parameter CLK_FREQ = 50000000;
parameter UART_BPS = 115200;
// 不可更改的常量
localparam BPS_CNT = CLK_FREQ / UART_BPS;
// 写信号忙
assign uart_rx_busy = tx_flag;// clk_cnt 计数
always @(posedge clk or posedge rst) beginif(rst)clk_cnt <= 1'b0;else if(tx_flag) beginif(clk_cnt < BPS_CNT - 1)clk_cnt <= clk_cnt + 1'b1;elseclk_cnt <= 9'd0;endelseclk_cnt <= 9'b0;
end// tx_cnt 根据 clk_cnt 计数
always @(posedge clk or posedge rst) beginif(rst)tx_cnt <= 4'd0;else if(tx_flag) beginif(clk_cnt == BPS_CNT - 1)tx_cnt <= tx_cnt + 1'b1;elsetx_cnt <= tx_cnt;endelsetx_cnt <= 4'b0;endalways @(posedge clk or posedge rst) beginif(rst) begintx_flag <= 1'b0;tx_data <= 8'd0;endelse beginif(en_flag) begin    // 写使能tx_flag <= 1'b1;    // 写标志tx_data <= uart_din; // 暂存数据endelse if(tx_cnt == 4'd9 && clk_cnt == (BPS_CNT-BPS_CNT/16)) begin// 传输结束tx_flag <= 1'b0;tx_data <= 8'd0;endelse begintx_flag <= tx_flag;tx_data <= tx_data;endend
end// uart_txd 传输数据
always @(posedge clk or posedge rst) beginif(rst)uart_txd <= 1'b1;else if(tx_flag) beginif(tx_cnt == 4'd0) uart_txd <= 1'b0; // start bit拉低else if(tx_cnt == 4'd9) uart_txd <= 1'b1; // stop bit拉低else uart_txd <= tx_data[tx_cnt - 4'b1]; // 传输数据(cnt比bit位计数多1)endelse uart_txd <= 1'b1;
endendmodule

uart_loopback_top

三个模块对应信号连接

module uart_loopback_top(input  sys_clk,input  sys_rst,input  uart_rxd,output uart_txd
);wire uart_en;
wire [7:0] uart_din;
wire [7:0] uart_data;
wire uart_done;
wire uart_rx_busy;uart_recv uart_recv_u(.clk        (sys_clk),.rst        (sys_rst),.uart_rxd   (uart_rxd),.uart_data  (uart_data),.uart_done  (uart_done) );uart_send uart_send_u(.clk            (sys_clk),.rst            (sys_rst),.uart_en        (uart_en),.uart_din       (uart_din),.uart_txd       (uart_txd),.uart_rx_busy   (uart_rx_busy)
);uart_loop uart_loop_u(.clk         (sys_clk),.rst         (sys_rst),.recv_done   (uart_done),.recv_data   (uart_data),.tx_busy     (uart_rx_busy),.send_en     (uart_en),.send_data   (uart_din)
);endmodule

约束

create_clock -period 20.000 -name clk [get_ports {sys_clk}]#Clock signal
set_property -dict { PACKAGE_PIN L16   IOSTANDARD LVCMOS33 } [get_ports { sys_clk }];#Buttons
set_property -dict { PACKAGE_PIN R18   IOSTANDARD LVCMOS33 } [get_ports { rst }];set_property -dict { PACKAGE_PIN B12   IOSTANDARD LVCMOS18 } [get_ports { uart_rxd }];
set_property -dict { PACKAGE_PIN C12   IOSTANDARD LVCMOS18 } [get_ports { uart_txd }];

这里的约束找不到对应的 zybo 开发板的,并没有跑起来

更多推荐

UART 串口通信

本文发布于:2023-06-16 01:23:53,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/736982.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:串口   通信   UART

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!