loliweive:
听闻楼主有远距离多机通信编程的经历,希望楼主可以讲一讲RS485总线在工程中的应用实例,谢谢!
吴坚鸿:
485通讯跟普通串口通讯方式有一个最大的区别是,485通讯要多增加一个IO口来控制数据流的方向,输出低电平时表示接受数据的状态,输出高电平时表示发送数据的状态。485的通讯协议一般都是用主机对从机广播呼叫的模式。即平时所有从机处于接受数据的状态(流控IO口处于低电平),主机发送呼叫某个从机的地址,相应的从机收到数据后,马上切换到发送数据的状态(流控IO口处于高电平),然后往主机返回对应的数据,从机对主机发送完数据之后,从机又马上切换到接受数据的状态(流控IO口处于低电平)。从机在发送数据时,在程序上有一个要特别注意的细节:
void eusart_send(unsigned char ucSendData)
{
ES = 0; //关串口中断
TI = 0; //清零串口发送完成中断请求标志
rede_dr=1; //流控IO,切换至发送数据的状态,准备发送数据,
delay_short(4); //此处最关键,必须插入几个空延时,等待芯片切换到发送数据的状态
SBUF =ucSendData; //发送一个字节
delay_short(400);
rede_dr=0; //流控IO,发送完数据之后,务必马上把从机切换回接收数据的状态,把总线释放
TI = 0; //清零串口发送完成中断请求标志
ES = 1; //允许串口中断
}
cjseng:
SBUF =ucSendData; //发送一个字节
delay_short(400);
这种做法实在是令人无语啊!!!不用中断方式不是不可以,但为什么要用延时?你能确定delay_short(400); 刚好够发送一个字节?换用不同晶振还要调整这个延时时间,换用不同厂家的单片机可能也要调整,这样不累啊?
你不会判断TI啊?if(TI==1)表示一个字节表示一个字节发送结束,这么好的标志位不用,竟然用延时?
另外,485通讯要用一个IO来控制收发切换,这是不错,但是232转485模块,可没有多余的IO来控制,照样可以收发切换的。
实际上我做的485通讯,经常是不用单独的IO来控制收发切换的,我的程序也不对收发进行控制,有硬件自动完成。用好了485芯片,是有办法进行自动收发切换的。
吴坚鸿:
(1)如果你不想用delay_short(400)延时,我还有另外一种延时方式,请参考我第四十三节:通过串口用计数延时方式发送一串数据。但是大部分的串口发送数据项目,我还是喜欢直接用delay_short(400)延时 ,感觉简单好用。
(2)delay_short(400)延时的时间根据实际项目的晶振来调整一下就可以了,真不累。
(3)为什么不用 TI标志位?根据我个人的经验,我觉得PIC单片机和51单片机的TI都不是很可靠,即使判断了TI,还是要加点延时,才能保证发送一串数据时不丢失。但是, 在这里,我不得不夸一下STM32单片机,我用STM32单片机的时候,是直接判断标志位的,不用加延时,STM32的标志位还是比较可靠。
(4)至于232转485模块不用IO口控制收发切换的问题,它内部是如何自动切换的,这个秘密我没有深入研究过,如果你有时间,希望跟大家分享一下。
cjseng:
判断TI标志位会出错,最主要的原因是收发两端的波特率有误差,略加延时即可解决,比如增加一个位的发送时间即可,在你这里,基本上只要delay(2)就可以了,不需要400。这种现象经常出现在连续大数据量连续收发。
485自动切换收发,最简单的就是将TX、/RE、DE三个引脚直接相连。这不是秘密,是常用的方法。
吴坚鸿:
(1)我这里的delay(400)已经包含了发送数据时候的时间。你说的方法先判断TI,再delay(2)可能也没问题。我认为差距不大的,而且两种办法,我认为直接delay(400)会更加简洁一些。
(2)TX、/RE、DE三个引脚直接相连,我没有安全感。因为在切换发送数据状态时就没有延时了,所以我还是会坚持多用一个IO口控制切换。
lmx89:
讨教:如何确定TI标志位出错,有什么现象吗?会出现乱码?
cjseng:
TI标志位不会出错的,它只是发送完一个字节的标志,发送完一个字节,TI由硬件自动置1.这个出错的几率基本为0。
但是,如果发送端和接收端波特率存在误差,那么在发送端发送完一个字节后,TI已经置1了,但是接收端还没有接收完这个字节,此时如果发送端继续发送下一个字节,这样就会出错。
接收端以波特率的16倍频对接收到的电平进行采样,在16个采样周期中以7、8、9三个采样结果进行评判,至少有2次采样结果一致就确定信号电平。如果波特率存在较大误差,接收端的7、8、9三个采样周期就会逐渐与发送端失去同步,导致接收不正确。
发送一个字节,包含起始位、8位数据、一个奇偶校验位(可选)、停止位,在起始位时双方进行同步,但是如果波特率存在较大误差,可能未接收到停止位,就已经失步了。
这种现象就是帧错误。波特率越高,帧错误就越容易发生。
所以,有的设备上可以选择停止位的长度:1位、1.5位、2位。通常选择2位时,帧错误的现象就基本没有了。
在单片机上,一般不能设置停止位的长度,我们可以在发送完一个字节(TI==1)的情况下,略作延时,延时一位的发送时间,就相当于加长了停止位,这样就能确保通讯可靠。
接收端出现乱码的另一个原因,就是接收缓冲区内的数据未及时处理,这种现象通常在大数据量通讯时出现,比如常用的串口调试助手连续接收大数据时就会出现。
吴坚鸿:
非常专业,非常细致的解释。佩服。