600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > 通信协议详解(一):UART串口(协议+数据格式+设计实现)

通信协议详解(一):UART串口(协议+数据格式+设计实现)

时间:2023-03-19 21:34:59

相关推荐

通信协议详解(一):UART串口(协议+数据格式+设计实现)

uart串口通信协议及verilog实现

文章目录

一、uart串口通信简介二、串口传输1、数据协议2、整体架构三、串口传输实现1、发送模块2、接收模块四、串口收发仿真总结

一、uart串口通信简介

通用异步收发器UART(Universal Asynchronous Receiver/Transmitter),是一种串行、异步、全双工的通信协议,将所需传输的数据一位接一位地传输,在UART通讯协议中信号线上的状态位高电平代表’1’,低电平代表’0’。其特点是通信线路简单,只要一对传输线就可以实现双向通信,大大降低了成本,但传送速度较慢。

二、串口传输

1、数据协议

在串口通信中,尤其需要关注的是数据流以及波特率。一个数据流由10个数据位组成,包含1位起始位,7位有效数据位,1位奇偶校验位,1位停止位。uart串口信号线上空闲时常驻高电平,当检测到低电平下降沿时认为数据传输开始,到停止位时数据传输结束,一共10位数据位组成一个数据包。

起始位:通信线路上空闲时为“1”,当检测到“0”即下降沿时,认为数据传输开始

有效数据位:传输开始后传递的需要接收和发送的数据值,可以表示指令或数据

奇偶校验位:奇偶校验,通过来校验传输数据中“1”的个数为奇数个(奇校验)或偶数个(偶校验)来指示传输数据是否正确

停止位:数据传输结束,传输线恢复常“1”状态

此外,还需关注数据传输波特率,波特率表示一秒内传输了多少个码元数量,一般波特率为300,1200,2400,9600,19200,38400,115200等。例如9600 Baud表示一秒内传输了9600个码元信息,当一个码元只含1 bit信息时,波特率=比特率

2、整体架构

串口协议用于与其他模块之间的信息交互,包含接收模块发送模块,信号传输线上根据波特率完成码元的接收与发送,因而接收模块主要完成并串转换,串并转换是接收和发送模块必备的基本功能,发送模块完成并串转换,接收模块完成串并转换。

波特率与时钟频率关系如下(码元为单bit时):

三、串口传输实现

1、发送模块

代码如下

//===============//author:LGYSSS//proj:uart_transimitter//===============module uart_tx(clk ,rst_n ,data_vld , //有效信号data_in, //输入信号data_out, //并行转串行输出信号rdy //模块有效信号,示意模块准备接收数据);parameter WIDTH=8;parameter CLK_CNT= 5208;//波特率baud=9600下单码元传输 码元宽度为104166 50MHz下一个时钟周期为20ns,传输一个数据位104166/20=5208个clkparameter NUM_CNT=10;//数据位个数input clk;input rst_n;input [WIDTH-1:0]data_in;input data_vld;output data_out;output rdy;reg data_out; reg [WIDTH-1:0]data_in_reg;reg start_tx;wire [WIDTH-1+2:0] data;reg [12:0]cnt0;wire add_cnt0;wire end_cnt0;reg [3:0]cnt1;wire add_cnt1;wire end_cnt1;always@(posedge clk or negedge rst_n)beginif(!rst_n)start_tx<=0;else if(start_tx==0&&data_vld==1)start_tx<=1;else if(end_cnt1)start_tx<=0;endalways @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt0 <= 0;endelse if(add_cnt0)beginif(end_cnt0)cnt0 <= 0;elsecnt0 <= cnt0 + 1;endendassign add_cnt0 = start_tx;assign end_cnt0 = add_cnt0 && cnt0== CLK_CNT-1;always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt1 <= 0;endelse if(add_cnt1)beginif(end_cnt1)cnt1 <= 0;elsecnt1 <= cnt1 + 1;endendassign add_cnt1 = end_cnt0;assign end_cnt1 = add_cnt1 && cnt1== NUM_CNT-1;always @(posedge clk or negedge rst_n)begin //在数据有vld效时进行数据锁存,进行下一步串并转换if(!rst_n)begindata_in_reg<=0;endelse if(start_tx==0&&data_vld==1)begindata_in_reg<=data_in;endendalways @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)begindata_out <= 1'b1;endelse if(add_cnt0 && cnt0==1-1)begindata_out <= data[cnt1];endendassign data={1'b1,data_in_reg,1'b0}; //起始位,停止位拼接assign rdy=((data_vld==1)||(start_tx==1))?1'b0:1'b1;endmodule

2、接收模块

代码如下:

//===============//author:LGYSSS//proj:uart_receiver//===============module uart_rx(clk ,rst_n ,data_vld ,rx_data_in,rx_data_out);parameter WIDTH=8;parameter CLK_CNT= 5208;//波特率baud=9600下单码元传输 码元宽度为104166 50MHz下一个时钟周期为20ns,传输一个数据位104166/20=5208个clkparameter CLK_CNT_MID=2604;parameter NUM_CNT=10;input clk;input rst_n;input rx_data_in;output reg [WIDTH-1:0] rx_data_out;output reg data_vld;wirestart_rx;reg [19:0] cnt0;wireadd_cnt0;wireend_cnt0;reg [3:0]cnt1;wireadd_cnt1;wireend_cnt1;regflag;reg rx_data_in_reg0;reg rx_data_in_reg1;reg rx_data_in_reg2;always@(posedge clk or negedge rst_n)beginif(!rst_n)beginrx_data_in_reg0<=0;rx_data_in_reg1<=0;rx_data_in_reg2<=0;endelse beginrx_data_in_reg0<=rx_data_in;rx_data_in_reg1<=rx_data_in_reg0;rx_data_in_reg2<=rx_data_in_reg1;endendassign start_rx=(rx_data_in_reg2&&~rx_data_in_reg1)==1; //下降沿检测always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginflag <= 1'b0;endelse if(start_rx)beginflag <= 1'b1;endelse if(end_cnt1)beginflag <= 1'b0;endendalways @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt0 <= 0;endelse if(add_cnt0)beginif(end_cnt0)cnt0 <= 0;elsecnt0 <= cnt0 + 1;endendassign add_cnt0 = flag;assign end_cnt0 = add_cnt0 && cnt0== CLK_CNT-1;always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt1 <= 0;endelse if(add_cnt1)beginif(end_cnt1)cnt1 <= 0;elsecnt1 <= cnt1 + 1;endendassign add_cnt1 = end_cnt0;assign end_cnt1 = add_cnt1 && cnt1== NUM_CNT-1-1;always @(posedge clk or negedge rst_n)begin if(!rst_n)beginrx_data_out<=0;endelse if(cnt0==CLK_CNT_MID-1&&cnt1!=0&&flag==1)beginrx_data_out[cnt1-1]<=rx_data_in_reg2;endendalways @(posedge clk or negedge rst_n)beginif(!rst_n)begindata_vld <= 1'b0;endelse if(end_cnt1)begindata_vld <= 1'b1;endelse begindata_vld <= 1'b0;end endendmodule

四、串口收发仿真

串口发送模块仿真波形:

串口接收模块仿真波形:


总结

看到这里模块功能其实很清晰了,两个模块完成的功能其实就是收发数据的串并转换,传输的内容具体是什么我们是不用关心的,只需要关心数据收发格式,检测到下降沿时开始传输,传输一定数据位时结束当前传输,就完成了一个数据帧的传输,即完成了uart串口通信的一次收/发。.

同时,在本模块设计中笔者是采用锁存器来锁存当vld有效时的信号,当数据流传输速度较大时,我们也可以采取fifo来缓存我们接收的数据,以免造成数据丢失


本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。