串口通信的基本原理: 串口通信:按位(bit)发送和接收字节的一种通信方式,其最重要的参数是波特率、数据位、停止位和奇偶校验位。 1. 波特率:衡量符号传输速率的参数。波特率和距离成反比。 2. 数据位:衡量通信中实际数据位的参数。实际数据位取决于通信协议。 3. 停止位:用于表示单个包的最后一位。由于数据是在传输线上定时的,并且每一台设备都有自己的时钟,很可能在通信的两台设备间出现了一些不同步的情况。它不仅仅是表示传输的结束,也是计算机校正时钟同步的机会。 4. 奇偶校验位:在串口通信中是一种检错方式。奇、偶、高、低、无。使得接收设备能够知道一个位的状态,有机会判断传输与接收数据是否不同步。 异步通信: 异步通信采用固定的通信格式,数据以相同的帧格式传送。每一帧由起始位、数据位、奇偶校验位和停止位组成。如下图,每一帧都是由起始位、数据位、奇偶校验位和停止位组成。
在通信线上没有数据传送时处于逻辑“1”状态。当发送设备发送一个字符数据时,首先发出一个逻辑“0”信号,这个逻辑低电平就是起始位。起始位通过通信线传向接收设备,当接收设备检测到这个逻辑低电平后,就开始准备接收数据信号。因此,起始位所起的作用就是表示字符传送开始。 起始位后面紧接着的是数据位,它可以是5位、6位、7位、或8位。数据传送时,低位在前。 奇偶校验位用于数据传送过程中的数据检错,数据通信时通信双方必须约定一致的奇偶校验方式。就数据传送而言,奇偶校验位是冗余位,但它表示数据的一种性质。也有的不要校验位。 在奇偶校验位或数据位后紧接的是停止位,停止位可以是一位、也可以是1.5位或2位。接收端收到停止位后,知道上一字符已传送完毕,同时,也为接收下一字符作好准备。若停止位后不是紧接着传送下一个字符,则让线路保持为“1”。“1”表示空闲位,线路处于等待状态。存在空闲位是异步通信的特性之一。 同步通信: 同步通信时,通信双方共用一个时钟,这是同步通信区分于异步通信的最显著的特点。在异步通信中,每个字符要用起始位和停止位作为字符开始和结束的标志,以致占用了时间。所以在数据块传送时,为提高通信速度,常去掉这些标志,而采用同步通信。同步通信中,数据开始传送前用同步字符来指示(常约定1~2个),并由时钟来实现发送端和接收端的同步,即检测到规定的同步字符后,下面就连续按顺序传送数据,直到一块数据传送完毕。同步传送时,字符之间没有间隙,也不要起始位和停止位,仅在数据开始时用同步字符SYNC来指示,如下图。
异步通信与同步通信的特点: 1 同步通信 进行数据传输时,发送和接收双方要保持完全的同步。因此,要求接收和发送设备必须使用同一时钟。优点是可以实现高速度、大容量的数据传送;缺点是要求发生时钟和接收时钟保持严格同步。
2 异步通信 异步通信是按字符传输的。每传输一个字符就用起始位来进来收、发双方的同步。不会因收发双方的时钟频率的小的偏差导致错误。 这种传输方式利用每一帧的起、止信号来建立发送与接收之间的同步。特点是:每帧内部各位均采用固定的时间间隔,而帧与帧之间的间隔时随机的。接收机完全靠每一帧的起始位和停止位来识别字符时正在进行传输还是传输结束。 改善串口通信数据实时性和可靠性措施: 首先在硬件协议上,CAN,485使用的是差分信号,能有效抑制电磁干扰中的公模信号(很有针对性的设计)。对比UART我们要做的就是改变其对0电位以及1电位的定义,吸收差分信号的优点做改进。对于差模信号改怎么抑制的问题,可以吸收类似NEC码的方式,给0与1信号一个容差时间,存在较大的差模信号存在的情况下,对电平的传输也影响不大。 软件协议上,采取固定帧头帧尾+数据码正反码+CRC校验的方式。事实上一般的通信增加正反码固定帧头帧尾的方式已经很稳定了。 //在发生中断接收时,会主动查询帧头帧尾中数据的正确性,以判断整个数据帧数据的可靠性,以选择接收。 if(RI)
{
REN = 0;
rcvUartdata[rcvUartCount] = SBUF; //接收数据到缓存
if((rcvUartCount % 5 == 0)&&(rcvUartdata[rcvUartCount] != 0x55)) //检测帧头
{
rcvUartdata[rcvUartCount] = 0;
}
else if((rcvUartCount % 5 == 1)&&(rcvUartdata[rcvUartCount] != 0xaa))
{
rcvUartdata[rcvUartCount] = 0;
rcvUartdata[rcvUartCount-1] = 0;
rcvUartCount = rcvUartCount - 1;
}
else if((rcvUartCount % 5 == 4)&&(rcvUartdata[rcvUartCount] != 0xfa)) //检测帧尾
{
rcvUartdata[rcvUartCount] = 0;
rcvUartdata[rcvUartCount-1] = 0;
rcvUartdata[rcvUartCount-2] = 0;
rcvUartdata[rcvUartCount-3] = 0;
rcvUartdata[rcvUartCount-4] = 0;
rcvUartCount = rcvUartCount - 4;
}
else
{
if(rcvUartCount % 5 == 4)
{
revOk** = 1;
}
rcvUartCount ++;
}
if(rcvUartCount == 20)
{
rcvUartCount = 0;
}
RI = 0;
REN = 1;
} //uart数据处理-------------------------------------------------------------------------------------------------- //数据解析时会进行二次确认,保证数据执行的正确性,避免错误数据及指令。
if(revOk**)
{
for(arrayCount = 0;arrayCount < 20; arrayCount += 5)
{
if((rcvUartdata[arrayCount] == 0x55)&&(rcvUartdata[arrayCount+1] == 0xaa)&&(rcvUartdata[arrayCount+4] == 0xfa))
{
instruct = rcvUartdata[arrayCount+2];
ctrolData = rcvUartdata[arrayCount+3];
crcData = rcvUartdata[arrayCount+4];
switch(instruct)
{
case 0x10: lackWaterState = ctrolData; //1 en 0 dis 加水
break;
case 0x20: slaveState = ctrolData; //1 EN 0 dis 开/关机
break;
default: break;
}
instruct = 0;
ctrolData = 0;
crcData = 0;
rcvUartdata[arrayCount] = 0;
rcvUartdata[arrayCount+1] = 0;
rcvUartdata[arrayCount+2] = 0;
rcvUartdata[arrayCount+3] = 0;
rcvUartdata[arrayCount+4] = 0;
}
}
revOk** = 0;
} 串口通信的可靠性与通信实时性就是一对矛盾,提高串口通信的可靠性,建议降低通信波特率。通常建议串口通信,数据采样时钟16倍的波特率时钟,这样可以提高数据传输的可靠性。 网上的一个问题: 怎样提高串口通信程序的可靠性。我个人设计一个串口接收的代码,工作在2M的波特率,总是实际接收的环境中受到干扰,出现某个数据丢失的情况。如果这个这个串口接收代码在FPGA内部环回测试,一点问题都没有哦,请夏老师出招!!!!!!!!!!!!!!!,附件是我设计的串口程序代码,实际系统CLK 是20MHZ,RST是高电平,请夏老师提意见,提出改进措施, 外部条件没法改了。 上述问题作者提到,串口接收代码FPGA内部环回测试没有问题,但在两个系统中相互通讯,接收数据丢失。关键是,内部环回测试,接收和发送用系统时钟都是同一晶振,属于同源晶振,没有相位移动,也不会产生数字电路的亚稳态,所以不会有问题。 改进上述现象的策略: 1. 降低波特率,用接收端的时钟同步接收数据,避免压稳态产生。eg if clk'event clk='1' then rx(7 downto 1)<=rx (6 downto 0); rx(0)<=rxd end ; rx(7)作为接收串行数据进行解析,应该能提高通信可靠性。 2. 外部其他调节不改变的情况下(比如 系统时钟,波特率等不变情况),降低串口通信每次接收数据位数。比如每次异步串口通信接收16位数据变为8位,采用多个次串口通信接收多个数据方式。多个数据采用 包头+包长+数据+校验 格式进行传递和解析。 3. 降低每个数据发送之间间隔时长以及包之间的等待时长。
|