串口加printf重定向一些问题,解决一半,还剩一半

2019-07-20 05:50发布

今天用串口收发数据的时候发现第一字节的数据无法收到。
实际为第一字节收到,但是无法打印在调试助手上。
问题变成,为什么无法打印第一个字节。
这个问题以前碰到过,硬件复位的时候SR的TC为置位导致无法发送第一个字节,清除即可,但是我碰到的不是这个情况。下面背景描述:
首先板B向板A串口3发 0x42 0x0d 0x0a;
板A串口3收到数据后,通过串口1发送给PC串口助手显示,这里串口助手仅能显示0d 0a。下附程序部分:
[mw_shl_code=c,true]        while(1)
        {
                if(USART_RX_STA&0x8000)
                {                                          
                        len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
                        //USART_ClearFlag(USART1,USART_FLAG_TC);   //方案1
                        for(t=0;t<len;t++)
                        {
                               
                                USART_SendData(USART1, USART_RX_BUF[t]);         //向串口1发送数据
                                while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
                        }
                        //delay_ms(1);    //方案2
                        printf(" ");//插入换行
                       
                        USART_RX_STA=0;
                }else
                {
                        times++;
                        if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
                        delay_ms(10);   
                }
        }[/mw_shl_code]
以下是printf的重定向输出函数:
[mw_shl_code=c,true]//重定义fputc函数
int fputc(int ch, FILE *f)
{        
        while((USART1->SR&USART_FLAG_TC)==0);//循环发送,直到发送完毕
        USART1->DR = (u8) ch;
      
//while((USART1->SR&USART_FLAG_TC)==0);//循环发送,直到发送完毕    //方案3
        return ch;
}[/mw_shl_code]

在这个情况下,接收器仅能收到上述代码中的:
printf(" ");//插入换行
串口3接收到的回车和换行没有算在数据当中,被中断函数过滤了。

三种方案解决了这个问题,
1、//USART_ClearFlag(USART1,USART_FLAG_TC);
在发送数据前清空TC位,但是每次发送都要清空
2、//delay_ms(1);   
在发送数据后延时一小会,我觉得不可取
3、//while((USART1->SR&USART_FLAG_TC)==0);//循环发送,直到发送完毕
在重定向函数fputc中将TC标志位等待放到发送数据后面

三种方案之后都可以接收到数据,但是还是不理解为什么原来的情况无法接收到数据,按理说
USART_SendData(USART1, USART_RX_BUF[t]); //向串口1发送数据
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
在这里已经等待了标志位发送完成,不会造成数据寄存器被覆盖的情况,求解惑?
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
14条回答
WengYuH
1楼-- · 2019-07-21 16:17
 精彩回答 2  元偷偷看……
Bigflish
2楼-- · 2019-07-21 18:25
本帖最后由 Bigflish 于 2017-11-13 14:33 编辑

不管是库函数开发还是寄存去的开发,寄存器都是要了解的。
以下是《中文手册》的定义:
》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
位 7  TXE:发送数据寄存器为空 (Transmit data register empty)
当 TDR 寄存器的内容已传输到移位寄存器时,该位由硬件置 1。如果 USART_CR1 寄存器      
中 TXEIE 位 = 1,则会生成中断。通过对 USART_DR 寄存器执行写入操作将该位清零。
0:数据未传输到移位寄存器
1:数据传输到移位寄存器
注意:单缓冲区发送期间使用该位。
位 6  TC:发送完成 (Transmission complete)
如果已完成对包含数据的帧的发送并且 TXE 置 1,则该位由硬件置 1。如果 USART_CR1 寄存      
器中 TCIE = 1,则会生成中断。该位由软件序列清零(读取 USART_SR 寄存器,然后写入      
USART_DR 寄存器)。TC 位也可以通过向该位写入‘0’来清零。建议仅在多缓冲区通信  
时使用此清零序列。
0:传送未完成
1:传送已完成
《《《《《《《《《《《《《《《《《《《《《《《《《《《《《
   结合图片不难明白:
            在发送数据的时候,只要数据从TDR寄存器发送到了移位寄存器上,TXE必定由硬件置1(TDR的值为空,可以在往里写值,准备下一字节的传输,这就是我们理解的“传输完成”),
     接下来数据会自动的往TX线上发送出去,而不占内存,但是会消耗一定的时间,
          在数据从移位寄存器移动到TX线的期间,往TDX写入数值,会使得TXE置0,
          但是要是在这期间没有值往TDX里写,数据完全发送到TX线的同时(此时TXE=1),TC便会由硬件置1.   






WengYuH
3楼-- · 2019-07-21 22:45
Bigflish 发表于 2017-11-13 11:09
不管是库函数开发还是寄存去的开发,寄存器都是要了解的。
以下是《中文手册》的定义:
》》》》》》》》 ...

首先十分感谢你耐心的回答,这个确实是理解的。

后来想了一下,TC空闲时刻就是高所以当执行以下两句时,
            USART_SendData(USART1, USART_RX_BUF[t]);         //向串口1发送数据
            while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
第一次运行的时候虽然向USART_DR 寄存器写入,但是因为没有读取 USART_SR 寄存器,所以TC并不会清零,导致这个时候的while直接跳过,然后开始写入第二个byte,所以用这个标志位如果和printf组合的话,经常会有第一个字节消失的问题。
今天星期一
4楼-- · 2019-07-22 03:24
 精彩回答 2  元偷偷看……
WengYuH
5楼-- · 2019-07-22 08:57
本帖最后由 WengYuH 于 2017-11-18 19:02 编辑
今天星期一 发表于 2017-11-18 16:48
多查一下寄存器手册,带fifo列队的可以一次性填完fifo,为啥要一个个字节操作?

这样吗。。没有了解过,能说具体一些吗?
蓝野先生
6楼-- · 2019-07-22 09:54
 精彩回答 2  元偷偷看……

一周热门 更多>