riddlecn的个人空间 https://bbs.21ic.com/?751341 [收藏] [复制] [RSS]

日志

AVR单片机通讯用发送标识UDRE和TXC的区别

已有 692 次阅读2013-12-2 10:15 |系统分类:单片机| AVR, TXC, UDRE, 区别

Uart_Sendbyte(0xA3);//3.3ms 1byte
        RtcUpdateData(1);//读8563数据到缓冲区
        g_aTimeBuf[0] &= 0x7f;
        Uart_Sendbyte(g_aTimeBuf[0]);//sc
        g_aTimeBuf[1] &= 0x7f;
        Uart_Sendbyte(g_aTimeBuf[1]);//mn
        g_aTimeBuf[2] &= 0xbf;
        g_aTimeBuf[2] |= 0x80;
        Uart_Sendbyte(g_aTimeBuf[2]);//hr
        g_aTimeBuf[3] &= 0x3f;
        Uart_Sendbyte(g_aTimeBuf[3]);//dt
        g_aTimeBuf[5] &= 0x1f;
        Uart_Sendbyte(g_aTimeBuf[5]);//mo
        //g_aTimeBuf[6] &= 0xff;
        Uart_Sendbyte(g_aTimeBuf[6]);//yr
        Uart_Sendbyte(0X0D);
        while(!(UCSRA&(1<<TXC)));
        UCSRB&=~(1<<TXEN);//发送禁止
        UCSRB|=(1<<RXEN);//接收使能
这是最近做的关于ATMEGA16A的一段程序,串口调试时最后的0DH总是会变成0FDH;最终在网上找到了问题所在,主要是TXC的用法不对,等候发送的语句没有起到作用,发送禁止的时间太早了,把Uart_Sendbyte(0X0D);  后面的语句变成  while( !(UCSRA & (1<<UDRE)) ); 或者 while(UCSRA&(1<<TXC)); 都可以解决此问题  。

附上原文:


                        
AVR单片机通讯用发送标识UDRE和TXC的区别

(转自http://blog.sina.com.cn/s/blog_6c97f3a301017glw.html    by 兰台令史



刚刚似乎弄懂了一个小问题,就是AVR单片机通讯用发送标识UDRETXC的区别。


AVR的说明书上说:


TXC标志位可以用来检验一个数据帧的发送是否已经完成,RXC标志位可以用来检验接收缓冲器中是否还有数据未读出。在每次发送数据之前(在写发送数据寄存器UDR)TXC标志位必须清零。”


“数据寄存器空UDRE标志位表示发送缓冲器是否可以接受一个新的数据。该位在发送缓冲器空时被置"1”;当发送缓冲器包含需要发送的数据时清零。”


“当整个数据帧移出发送移位寄存器,同时发送缓冲器中又没有新的数据时,发送结束标志TXC置位。TXC在传送结束中断执行时自动清零,也可在该位写"1”来清零。”


看完上述的说明之后,我一直疑惑在发送数据时,是不是要同时进行两种操作:


1、判断UDRE1


2、清除TXC标识。


但是在网上见到的实用程序中,并没有上面的第二项操作,似乎也可以行得通。带着这个疑惑,我在网上搜到了一个比较好的回答:



关于AVR的串口,解释如下:


对于发送,有一个UDR缓冲寄存器,还有一个移位寄存器。当你写一次UDR时,单片机会立即把这个数据转到移位寄存器,所以你还可以立即写第二个数据。以后每当UDR缓冲寄存器空的时候,就会产生UDRE中断,而要产生TXC中断,就必须等移位寄存器的数据都发送完毕后才会产生。


对于接收,有两个UDR缓冲寄存器,还有一个移位寄存器。两个接收缓冲器相当于一个FIFO结构。当有数据接收时,如果一个完整的数据被接收到移位寄存器,会将其转到缓冲寄存器。这样会产生RXC中断。


AVR51不同,这样的结构会更好。例如当你的程序很忙在另外一个中断里,这时有串口接收数据。两个缓冲器会为你赢得时间,而不会丢失数据。发送数据也一样。而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;


}



路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)