赞
踩
参考:
巨详细的UART文档,学习UART的保证你不后悔 - 数字IC设计资料(IC前端|FPGA|ASIC) - EETOP 创芯网论坛 (原名:电子顶级开发网) -
USART串口协议 - 孤情剑客 - 博客园 (cnblogs.com)
《通信IC设计》 李庆华著 (第一章中的uart例子)
UART 的全称是通用异步收发器(Universal Asynchronous Receiver/Transmitter),是实现设备之间低速数据通信的标准协议。
是一种通用的串行、异步通信总线。
该总线有两条数据线,可以实现全双工的发送和接收在嵌入式系统中常用于主机与辅助设备之间的通信。
“异步”:
指不需要额外的时钟线进行数据的同步传输, 是一种串行总线接口,只需占用两根线就可以完成数据的收发(一根接收数据,一根发送数据),常用的标准通信波特率有 9600bps、115200bps 等。
注意:master和slave只是一种模式,不是固定发送模块或者接收使用。
按数据传送的方式,通信可分为
是指设备之间通过少量数据信号线(一般是 8 根以下),地线以及控制信号线,按数据位形式一位一位地传输数据的通讯方式。
一般是指使用 8、 16、 32 及 64 根或更多的数据线进行传输的通讯方式,
根据通信的数据同步方式,又分为同步和异步两种。可以根据通信过程中是否有使用到时钟信号进行简单的区分。
在异步通信中,不使用时钟信号进行数据同步,它们直接在数据信号中穿插一些同步用的信号位,或者把主体数据进行打包,以数据帧的格式传输数据。例如规定由起始位、数据位、奇偶校验位、停止位等。
某些通信中还需要双方约定数据的传输速率,以便更好地同步 。
波特率(bps)是衡量数据传送速率的指标。
在同步通信中,收发设备双方会使用一根信号线表示时钟信号,在时钟信号的驱动下双方进行协调,同步数据。
通信中通常双方会统一规定在时钟信号的上升沿或下降沿对数据线进行采样。
串口通信:
串口按位(bit)发送和接收字节。尽管比特字节(byte)的串行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。
串口通信协议:
指规定了数据包的内容,内容包含了起始位、主体数据、校验位及停止位,双方需要约定一致的数据包格式才能正常收发数据的有关规范。
串口通讯的数据包由发送设备通过自身的发送数据端口( TXD )传输到接收设备的接收数据端口(RXD)。
在串口通讯的协议层中,规定了数据包的内容,它由起始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据 。
下面虚线分开的每一格就是代表一个码元。
串口通讯的一个数据包从起始信号开始,直到停止信号结束。
UART设备在不发送数据时,数据信号线上总是呈现高电平状态,称为空闲状态(又称MARK状态)。
当有数据发送时,信号线变成低电平,并持续1位的时间,用于表示发送字符的开始,该位称为起始位,也称SPACE状态。
起始位之后,在信号线上依次出现待发送的每一位字符数据,并且按照先低位后高位的顺序逐位发送。待发送的位数可以选择5位、6位、7位或8位。
数据位的后面可以加上一位奇偶校验位,也可以选择不加。
最后传送的是停止位。一般选择1位、1.5位或2位。
例子:传输0x55信号
0x55的二进制数为01010101,
UART传输采用LSB模式( bit 0最先传输)
因此传输线信号的切换过程为:1-0 -1-0 - 1-0 -1-0。
码元是通信信号调制的概念,通信中常用时间间隔相同的符号来表示一个二进制数字,这样的信号称为码元。
串口异步通讯中由于没有时钟信号,所以两个通讯设备之间需要约定好波特率,即每个码元的长度,以便对信号进行解码 。
常见的波特率为4800、 9600、 115200 等。
每bit时间宽度:bit_width=1/ Baudrate
每bit时钟周期数: bit_num_clk=bit_width/T (T是时钟周期)
波特率和比特率之间的关系
波特率的大小与比特率一致
常见的通讯传输中,用 0V 表示数字 0, 5V 表示数字 1,
那么一个码元可以表示两种状态 0 和 1,
所以一个码元等于一个二进制比特位,
此时波特率的大小与比特率一致。
因为很多常见的通讯中一个码元都是表示两种状态,人们常常直接以波特率来表示比特率 。
波特率的大小与比特率不一致
如果在通讯传输中,有 0V、2V、 4V 、 6V 分别表示二进制数 00、 01、 10、 11,
那么每个码元可以表示四种状态,即两个二进制比特位,
所以码元数是二进制比特位数的一半,
这个时候的波特率为比特率的一半。
对数据传输正确性的一种校验方法。
有效数据中,“1”的个数计算
缩减运算符
缩减运算是对单个操作数进行的运算,结果是1位的二进制数。
第一步先将操作数的第1位和第2位进行与、或、非运算,第二步将运算结果与第3位进行与、或、非运算,以此类推直至最后一位。
举例:
- reg[3:0]B;
- reg C;
-
- C=^B;//相当于 C=((B[0]^B[1])^B[2])^B[3];
有效数据中,“1”的个数计算
- //输入的有效数据
- data[7:0];
-
- //计算有效数据1的个数
- ^data[7:0]=1'b1 //1的个数为奇数;
- ^data[7:0]=1'b0 //1的个数为偶数
奇校验、偶校验方式:
发送方发送数据后计算奇偶性
接收方收到数据后再一次计算奇偶性
接收方计算出的奇偶校验位与发送方一致,表示在此次传输过程中未发生错误。
例子:
注意:
UART通信协议,通过协议规定收发双方的行为;通过约定动作获得收发同步;通过冗余实现容错传输。
具体实现思路如下:
波特率是单位时间内传送的二进制数据的位数,以位/秒( bps)表示,也称为比特率。
目前最常用的波特率是9600bps 和1152 00bps,其余速率可以通过收发双方约定实现。
假定当前时钟频率为f,而波特率为Baud,则相当于一个位,可以采样N=f/Baud个样点。
但由于收发双方是异步的,双方的位对齐位置会逐渐漂移,所以接收方需要找到最佳采样(判断)位置。而实际上最佳采样位置就是发送数据的中心位置,即在N/2处采样最佳。
UART的接收状态机就是通过判断当前样点序列是否等于N/2作为存储当前接收值的依据。
例子:8倍采样的情形
可以发现最佳采样位置就是第4位或第5个位处。
在IC设计中,可以通过设定N实现任意波特率的速率,而这个N寄存器就是波特率寄存器。
收发的通信基准时钟电路可以认为是一个N倍分频电路。
UART的发送原理如下。
状态规划:
UART的接收原理如下。
在UART接收过程中,有几个基本的电路状态判断技巧:
起始位的判断:
在接收端开始接收数据位之前,通常需要搜索起始位。
接收端通常以N倍波特率的速率读取线路状态,检测线路上出现低电平的时刻。
因为异步传输的特点是以起始位为基准同步的,但通信线路噪声也极有可能使信号由1跳变到0,所以接收器以N倍的波特率对这种跳变进行检测,直至在连续N/2个接收时钟以后采样值仍然是低电平,才认为这是一个真正的起始位,而不是噪声引起的。
其中,若有一次采样得到的为高电平,则认为起始信号无效,也就是说,要返回初始状态重新等待起始信号的到来。
最佳采样点:
最可靠的接收应该是接收时钟的出现时刻正好对着数据位的中央,即前面提到的第N/2个采样位置。
合法UART接收状态的判断:
当采样计数器计数结束后,所有数据位都已经输入完成。最后需要对停止位的高电平进行检测,若正确检测到高电平,则说明本帧各位传输格式正确,可以将数据转存到数据寄存器中。否则说明本帧接收有误,定时关系出错。
接收器的功能的状态机(省略奇偶校验情况)
波特率 bandrate= 115200bit/s,周期 T=1/50MHz=20ns
传输1bit时间 T_1bit=[1/115200(s)] * ns
传输1bit需要的时钟周期数T_num=T_1bit / T =433 (二进制 1 1011 0010 位宽9)
一共需要传输的数据个数 N=1bit起始位+8bit有效数据位+ 1bit结束位=10(二进制 1010 位宽4)
两个计数器
counter1( uart_bit_cnt):
- always@(posedge clk_i or negedge rst_n_i)
- begin
- if(!rst_n_i)
- uart_bit_cnt<=9'b0;
- else if(uart_en)
- begin
- if(uart_bit_cnt==9'd433)
- uart_bit_cnt<=9'd0;
- else
- uart_bit_cnt<= uart_bit_cnt+1'b1;
- end
- end
counter2(uart_bit_num):
- always@(posedge clk_i or negedge rst_n_i)
- begin
- if(!rst_n_i)
- uart_bit_num<=4'b0;
- else if(uart_en)
- begin
- if(uart_bit_cnt==9'd433)
- uart_bit_num<= uart_bit_num+1'b1;
- end
- else
- uart_bit_num<=4'b0;
- end
输入的并行数据存入FIFO/寄存器
- //输入的数据data_in[7:0]
- //存入的寄存器堆tx_buffer[7:0]
- assign tx_buffer=data_in;
uart使能 uart_tx_en
- always@(posedge clk_i or negedge rst_n_i)
- begin
- if(!rst_n_i)
- uart_tx_en<=1'b0;
- else if (en_data_i)
- uart_tx_en<=1'b1;
- else if ((uart_bit_num==4'd10)&&(uart_bit==9'd433))
- uart_tx_en<=1'b0;
- end
状态0:等待空闲ready 空闲标志为高电平 ready=1。如果空闲标志拉低,跳到状态1。
- always@(posedge clk_i or negedge rst_n_i)
- begin
- if(!rst_n_i)
- rdy <=1'b1;
- else if(((uart_bit_num==4'd10)&&(uart_bit==9'd433)))
- rdy <=1'b1;
- else if( uart_tx_en)
- rdy <=1'b0;
- end
状态1: uart使能,时钟周期数uart_bit_cnt=433 uart_bit_num=0,传输数据0位,起始位。跳到状态2。
- if(uart_bit_num==0)
- tx<=1'b0;
状态2: uart使能,时钟周期数为uart_bit_cnt=433,1<=uart_bit_num<=8时,传输有效数据。跳到状态3。
- if (uart_bit_num>=4'd1 &&uart_bit_num<=4'd8&&)
- TX <= tx_buffer[uart_bit_num-1];
状态3: uart使能,时钟周期数uart_bit_cnt=433 uart_bit_num=8,传输数据9位,校验位。跳到状态4。
- if(uart_bit_num==4'd9)
-
- TX <=^tx_buffer;
状态4: uart使能,时钟周期数uart_bit_cnt=433 uart_bit_num=9,传输数据10位,停止位。跳到状态0。
- if(uart_bit_num==4'd10)
- TX <=1'b0;
状态0:空闲识别
- always@(posedge clk_i or negedge rst_n_i)
- begin
- if(uart_bit_cn==433)
- uart_bit_cn<=0;
- else
- uart_bit_cn<=uart_bit_cn+1;
-
- if(uart_bit_cn==0)
- begin
- if(RX)
- uart_bit_num <= uart_bit_num+1;
- else//如果接收到不是1的数据,说明空闲结束
- begin
- uart_bit_num <=0;
- uart_bit_cnt<=0;
- state<=1;
- end
- end
- if( uart_bit_num==9) //连续接收10个1,判断是空闲,跳到状态1等待起始位
- begin
- uart_bit_num <=0;
- uart_bit_cnt<=0;
- state<=1;
- end
- end
-
状态1:找起始位:找下降沿
将下降沿(RX)做一个时钟周期的延时(RX_delay)
将RX反向,与RX_delay相与,得到一个尖。
看到这个尖,就知道起始位到了。
~RX&RX_delay =1
- RX_delay<=RX;//有时钟就在动,不需要条件
- en_data_out<=0;
- if(~RX&RX_delay)
- state<=2;
状态2: 收数据:(数据中间比较可靠)
uart_bit_cnt=216,1<uart_bit_num<8
- //接收数据的buffer
- //uart_rx_buf[7:0]
- //输出数据data_out[7:0]
-
- always@(posedge clk_i or negedge rst_n_i)
- begin
- if(!rst_n_i)
- uart_rx_buf<=8'd0;
- else if(uart_bit_cnt==9'd216 &&uart_bit_num>=4'd1 &&uart_bit_num<=4'd8)
- uart_rx_buf[uart_bit_num-1]<=RX;
- end
- assign data_out = uart_rx_buf;
-
- state<=3;
状态3:产生校验位(奇校验)
- if(uart_bit_num==4'd9)
- RX <=^uart_rx_buf;
- state<=4;
状态4:检测到停止位为高电平
uart_bit_num=8,RX=1 检测到高电平.产生使能脉冲。
否则采样出错。跳到状态0。
- if(uart_bit_cnt=433&& uart_bit_num=10)
- if(RX)
- en_data_out<=1;
- state<=0;
- else
- state<=0;
- //--band rate : 115200 每秒传输的bit位
- //--check bit : odd
- //--stop bit : 1bit
- //--clock freq : 50MHz
- //--clock num of uart bit:434clk_i 传输1bit需要的时钟周期 1/115200*10^9ns/20ns=434
-
- module uart
- (
- input clk_i,
- input rst_n_i,
- //--TX
- input [7:0] data_in,
- input en_data_i,
- output reg rdy,
- output TX,
- //--RX
- input RX,
- output en_data_out,
- output [7:0] data_out,
- //检查收发数据是否一致标志
- output flag
- )
- reg [8:0] uart_bit_cnt;
- reg [3:0] uart_bit_num;
-
- reg uart_en;
- wire [7:0] tx_buffer;
- reg uart_tx_en;
-
- reg [2:0] tx_sate;
- reg [2:0] rx_sate;
- wire RX_delay;
-
- wire [7:0] uart_rx_buf;
- //counter1:传输1bit数据需要的时钟周期数
- always@(posedge clk_i or negedge rst_n_i)
- begin
- if(!rst_n_i)
- uart_bit_cnt<=9'b0;
- else if(uart_en)
- begin
- if(uart_bit_cnt==9'd433)
- uart_bit_cnt<=9'd0;
- else
- uart_bit_cnt<= uart_bit_cnt+1'b1;
- end
- end
- //counter2:传输数据的个数。
- always@(posedge clk_i or negedge rst_n_i)
- begin
- if(!rst_n_i)
- uart_bit_num<=4'b0;
- else if(uart_en)
- begin
- if(uart_bit_cnt==9'd433)
- uart_bit_num<= uart_bit_num+1'b1;
- end
- else
- uart_bit_num<=4'b0;
- end
-
- //-----连接发送模块和接收模块
- always@(*)
- begin
- tx_next1=TX;
- tx_next2= tx_next1;
- RX = tx_next2;
- end
-
-
- //--------------TX发送数据-----------------------------------
- //输入的并行数据存入FIFO/寄存器
- assign tx_buffer = data_in;
-
- //uart使能 uart_tx_en
- always@(posedge clk_i or negedge rst_n_i)
- begin
- if(!rst_n_i)
- uart_tx_en<=1'b0;
- else if (en_data_i)
- uart_tx_en<=1'b1;
- else if ((uart_bit_num==4'd10)&&(uart_bit_cnt==9'd433))
- uart_tx_en<=1'b0;
- end
-
- always@(posedge clk_i or negedge rst_n_i)
- begin
- if(!rst_n_i)
- begin
- rdy <=1'b1;
- tx_sate<=3'd0;
- uart_tx_en<=0;
- uart_bit_num<=0;
- uart_bit_cnt<=0;
- TX<=1'b1;
- end
- else
- begin
- case(tx_sate)
- 0: //状态0:等待空闲ready
- begin
- if(((uart_bit_num==4'd10)&&(uart_bit==9'd433)))
- rdy <=1'b1;
- else if( uart_tx_en)
- rdy <=1'b0;
- tx_sate<=3'd1;
-
- 1://发送起始位
- begin
- if(uart_tx_en && (uart_bit_num==4'd0))
- TX<=1'b0;
- if(uart_tx_en && (uart_bit_num==4'd1))
- tx_sate<=3'd2;
-
- 2://发送有效数据
- begin
- if (uart_tx_en && (uart_bit_num>=4'd1) && (uart_bit_num<=4'd8))
- TX <= tx_buffer[uart_bit_num-1];
- if(uart_tx_en && (uart_bit_num==4'd9))
- tx_sate<=3'd3;
-
-
- 3://发送校验位
- begin
- if(uart_tx_en && uart_bit_num==4'd9)
- TX <=^tx_buffer;
- if(uart_tx_en && (uart_bit_num==4'd10))
- tx_sate<=3'd4;
-
- 4://发送 停止位
- if(uart_tx_en && uart_bit_num==4'd10)
- TX <=1'b0;
- if(uart_tx_en && (uart_bit_num==4'd10)&&(uart_bit==9'd433))
- tx_sate<=3'd0;
-
- end
- end
- //--------------------------接收数据--------------------------------
- always@(posedge clk_i or negedge rst_n_i)
- begin
- if(!rst_n_i)
- begin
- rx_state<=0;
- uart_bit_cn<=0;
- uart_bit_num <=0;
- RX_delay<=0;
- data_out<=0;
- en_data_out<=0;
- uart_rx_buf<=8'd0;
- end
- else
- begin
- RX_delay<=RX;//有时钟就在动,不需要条件
-
- case(rx_state)
- 0://空闲识别
- begin
- if(uart_bit_cn==433)
- uart_bit_cn<=0;
- else
- uart_bit_cn<=uart_bit_cn+1;
- if(uart_bit_cn==0)
- begin
- if(RX)
- uart_bit_num <= uart_bit_num+1;
- else//如果接收到不是1的数据,说明空闲结束
- begin
- uart_bit_num <=0;
- uart_bit_cnt<=0;
- rx_state<=1;
- end
- if( uart_bit_num==9) //连续接收10个1,判断是空闲,跳到状态1等待起始位
- begin
- uart_bit_num <=0;
- uart_bit_cnt<=0;
- rx_state<=1;
- end
-
- end
- 1://起始位判断
- begin
- if(~RX&RX_delay)
- rx_state<=2;
- end
- 2://接收有效数据
- begin
- if(uart_bit_cnt==9'd216 &&uart_bit_num>=4'd1 &&uart_bit_num<=4'd8)
- uart_rx_buf[uart_bit_num-1]<=RX;
- assign data_out = uart_rx_buf;
-
- if(uart_bit_cnt==9'd433 &&uart_bit_num>=4'd9 )
- rx_state<=3;
- end
- 3://产生校验位(奇校验)
- begin
- if(uart_bit_num==4'd9)
- RX <=^uart_rx_buf;
- if(uart_bit_cnt==9'd433 &&uart_bit_num>=4'd10 )
- rx_state<=4;
- end
- 4://检测到停止位 高电平
- begin
- if(uart_bit_cnt=433&& uart_bit_num=10)
- if(RX)
- en_data_out<=1;
- rx_state<=0;
- else
- rx_state<=0;
- end
- end
- end
- //检查收发数据是否一致
- always@(*)
- begin
- if(^tx_buffer==1&&^uart_rx_buf==1)
- falg=1;
- else
- falg=0;
-
- end
- endmodule
参考:
巨详细的UART文档,学习UART的保证你不后悔 - 数字IC设计资料(IC前端|FPGA|ASIC) - EETOP 创芯网论坛 (原名:电子顶级开发网) -
USART串口协议 - 孤情剑客 - 博客园 (cnblogs.com)
《通信IC设计》 李庆华著 (第一章中的uart例子)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。