||
(转自http://blog.sina.com.cn/s/blog_6c97f3a301017glw.html by 兰台令史)
刚刚似乎弄懂了一个小问题,就是AVR单片机通讯用发送标识UDRE和TXC的区别。
AVR的说明书上说:
“TXC标志位可以用来检验一个数据帧的发送是否已经完成,RXC标志位可以用来检验接收缓冲器中是否还有数据未读出。在每次发送数据之前(在写发送数据寄存器UDR前)TXC标志位必须清零。”
“数据寄存器空UDRE标志位表示发送缓冲器是否可以接受一个新的数据。该位在发送缓冲器空时被置"1”;当发送缓冲器包含需要发送的数据时清零。”
“当整个数据帧移出发送移位寄存器,同时发送缓冲器中又没有新的数据时,发送结束标志TXC置位。TXC在传送结束中断执行时自动清零,也可在该位写"1”来清零。”
看完上述的说明之后,我一直疑惑在发送数据时,是不是要同时进行两种操作:
1、判断UDRE为1。
2、清除TXC标识。
但是在网上见到的实用程序中,并没有上面的第二项操作,似乎也可以行得通。带着这个疑惑,我在网上搜到了一个比较好的回答:
“关于AVR的串口,解释如下:
对于发送,有一个UDR缓冲寄存器,还有一个移位寄存器。当你写一次UDR时,单片机会立即把这个数据转到移位寄存器,所以你还可以立即写第二个数据。以后每当UDR缓冲寄存器空的时候,就会产生UDRE中断,而要产生TXC中断,就必须等移位寄存器的数据都发送完毕后才会产生。
对于接收,有两个UDR缓冲寄存器,还有一个移位寄存器。两个接收缓冲器相当于一个FIFO结构。当有数据接收时,如果一个完整的数据被接收到移位寄存器,会将其转到缓冲寄存器。这样会产生RXC中断。
AVR和51不同,这样的结构会更好。例如当你的程序很忙在另外一个中断里,这时有串口接收数据。两个缓冲器会为你赢得时间,而不会丢失数据。发送数据也一样。而51就不是这样的。”
“如果连续写两个缓冲器数据时,因为刚写缓冲的一个数据被移位到了移位寄存器,所以可以立刻再写一个数据。就是说UDRE置位时,单片机还有一个字节在移位寄存器里正在发送。”
结论就是:
常见的循环发送程序(即只判UDRE而不判TXC的发送程序)可以工作,究根结底在于发送数据的连续性:即起始时TXC=0,满足发送条件;而连续发送数据时,因为UDRE置位时,而移位寄存器中仍有数据在发送,故TXC没有置位,也满足发送条件。直到全部数据发送完成,移位寄存器和发送缓冲器都没有数据后,TXC才置位。
需要注意的是:
1、如果之前发送过一轮数据后,再次发送时,必须清除TXC标识,即对该位写“1”。最好是在一轮数据发送完成后检测TXC标识将其清除。
2、如果采用了发送完成中断,则不必手动清除,因为进入发送中断程序后,硬件可自动清除TXC标识。
3、如果不使用中断发送而采用循环发送时,发送过程中因其他中断的缘故,使发送程序暂停超过了一定时间的话,就会导致移位寄存器中的数据发送完成后置TXC标识位,则之后的发送就无法进行了。
4、如果采用485进行通讯,只有在检测到TXC置位时才改变485的状态。因为只有TXC置位时,才代表发送过程的完成。
我认为比较好的发送程序如下:
void uart_putchar(unsigned char
c)
{
while(!(UCSR0A&(1<<UDRE)));
//等待UDR为空
if(UCSR0A&(1<<TXC))
UCSR0A|=(1<<TXC);
//如果TXC置位,清TXC标识(此处可采用位或而不用直写)
UDR0 = c;
}