请教马老师,有关USART,涉及到UDRE0,以及发送缓冲器的问题?
您好!我有几个关于USART的问题,困扰几周,程序进展缓慢,特向您求助。
我的程序大概要求是做一个双机通讯用串口USART连接,一个是ATMega48,另一个是ATMega169,用GCC编译器。使用RTS和CTS控制流量。
从48向169发送数据的时候,由于169要用一个长度为8bytes的FIFO,当这个FIFO满的时候,我要disable 169的 RTS(连到48的CTS),那么当48检测到CTS为低电平时,48停止发送数据。我的程序运行正常,但是问题在于用示波器观测的时候,当CTS被拉低之后,48继续发送一个数据,虽然不影响程序,但是由于我的总程序中需要进行模式转换,于是这个多出来的一个数据处理起来比较麻烦,所以希望达到取消这个一个数据的效果,弄了好几天,还是不行。
一开始的时候,一旦CTS被拉低,48会继续发送三个数据,(1个在48的发送缓冲器,另外一个在169的2个接收缓冲器)这些都不影响结果。为了达到我想要的效果,我采取了一些办法,减少了2个数据,这最后一个,真的不知道了。
在我采取的这些办法中,我有几个问题不太明白:
1)在datasheet中,我的理解是要等发送缓冲器空的时候才可以往里写入数据,所以顺序是先检测这个条件,然后写数据到UDR0:
while (!(UCSR0A & (1<<UDRE0)));
UDR0=data;
但是如果我调换这两语句的位置,我可以减少一个多余的数据,而且结果正确。
那么应该如何正确理解这个顺序问题呢?
另外一个多余的数据是控制时序,这个我懂了,然后就剩下这最后一个了。可以给我一点启发吗?谢谢
2)有关JTAG仿真的正确性,UDRE0 总是为1,无论TXEN0的值是多少?
在我用JTAG仿真调试我的程序过程中,在检测到(用外部中断)CTS被拉低的时候,我disable TXEN0,禁止发送,但是UDRE0一直都为1,那么48还是一直发送数据(其实什么也没发出去),但是记数器还是在继续增加,我觉得好奇怪。然后我用AVRstudio模拟的时候,一旦禁止了发送,那么程序就一直等待CTS再一次被拉高,才继续进行。
我的解决办法就是在发送程序中加入一个条件,其实这个条件按理来说是完全不需要的。
希望得到一些启示,我每天满脑子都是这些,弄不出来,又着急又难过:(
-----此内容被Lily1979于2007-03-10,06:34:47编辑过 一般的MCU上的USART硬件接口实现的是简易的3线方式,不是完全的RS232标准。因此使用硬件方式控制流量(RTS、CTS)需要软件完成,对程序员要求非常高,不容易实现。
建议你改变传送方式,采用软件控制流量,不需要RES、CTS了,通过48和169的USART一收一发交互实现:169向48发送请求数据命令--》48收到命令后连续发送8个数据,然后等待--》169接收和处理收到的8个数据--》169处理完成后,再向48发送请求数据命令(/或重发命令)。
如果数据传送时间要求比较高,可以采用提高系统时钟和通信的BPS解决,如19200或更高,但要使用外部晶体,如11.0592M。不要使用4M、8M等频率的晶体。
=============================================================================
1)在datasheet中,我的理解是要等发送缓冲器空的时候才可以往里写入数据,所以顺序是先检测这个条件,然后写数据到UDR0:
while (!(UCSR0A & (1<<UDRE0)));
UDR0=data;
但是如果我调换这两语句的位置,我可以减少一个多余的数据,而且结果正确。
关于这个问题,我的理解是:
while (!(UCSR0A & (1<<UDRE0)));
UDR0=data; ====》这个数据一般要发送的,除非你的while语句刚执行完就被中断打断了,而且在中断中关掉的发送允许标志。不过中断返回后这个数据还是写进了UDR0,一旦允许发送开放,它还是发出去了。如果在UDR0=data执行后才关掉发送允许标志,那么这个数据要发送完,以后的数据不发送了。
交换一下:
UDR0=data; ======》这个数据不一定发送,因为前一个数据没发完
的话,这个数据白写。
while (!(UCSR0A & (1<<UDRE0)));
以下是手册中的说明:
The transmit buffer can only be written when the UDRE Flag in the UCSRA Register is set. Data written to UDR when the UDRE Flag is not set, will be ignored by the USART Transmitter. When data is written to the transmit buffer, and the Transmitter is enabled, the Transmitter will load the data into the transmit Shift Register when the Shift Register is empty. Then the data will be serially transmitted on the TxD pin.
TXEN: Transmitter Enable
Writing this bit to one enables the USART Transmitter. The Transmitter will override normal port operation for the TxD pin when enabled. The disabling of the Transmitter (writing TXEN to zero) will not become effective until ongoing and pending transmissions are completed, i.e., when the transmit Shift Register and transmit Buffer Register do not contain data to be transmitted. When disabled, the transmitter will no longer override the TxD port.
关于第2个问题我不好回答,因为它与你的程序编写和调试方法有关。我一直不赞成采用什么在板或在芯片的调试,尤其是调试通信接口。因为通信协议是有严格的时间时序的,而且是双方协同的,你随便打断一方的程序运行或改变运行时序(在线调试需要打断或改变运行时序的)都会造成通信过程的乱套。 谢谢马老师的回答。
对于第一个问题,我觉得这个在一个程序中,如果只有USART_Rx中断,或者即使有别的中断只要不影响到接受数据的操作时,这2种方式都是可以接受的,但是在时序上会有区别。
我还是有一点模糊,得用示波器观测比较一下。
对于RTS 和CTS的使用问题,我必须得使用,因为我的项目实际上不是双机通讯,而是48和一个无线模块的通讯,这个无线模块的接口必须要用到RTS 和CTS. 由于考虑到这个模块的复杂性,我用169来代替它先进行仿真。
不知道马老师对无线通讯模块有什么好的文章呢?我用的这个模块是OWSPA311g,是基于BGW211 的。
页:
[1]