打印

关于STM32串口发送的奇怪问题

[复制链接]
11748|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
我在用串口连续发送一串数字时,第一个数总是发不出去,我用STM32F103ZE,STM32F103CB都是这样的情况,以下是代码:
        USART_SendData(USART1,0x06);
                while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);      

        USART_SendData(USART1,0x07);
                while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);                       

        USART_SendData(USART1,0x08);
                while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);

        USART_SendData(USART1,0x09);
                while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);

        USART_SendData(USART1,0x10);
                while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
串口的初始化代码:
    USART_InitTypeDef USART_InitStructure;

        USART_InitStructure.USART_BaudRate=UARTBaud;
        USART_InitStructure.USART_WordLength=USART_WordLength_8b;
        USART_InitStructure.USART_StopBits=USART_StopBits_1;
        USART_InitStructure.USART_Parity=USART_Parity_No;
        USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
        USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
        USART_Init(USART1, &USART_InitStructure);

    USART_ITConfig(USART1,USART_IT_RXNE, ENABLE);

    USART_Cmd(USART1, ENABLE);
发完之后的现象:

我是以十六进制接收的,但总是缺少第一个数0x06
沙发
denike| | 2011-8-4 10:00 | 只看该作者
改成  while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
  {
  }
即可

使用特权

评论回复
板凳
ringsearch|  楼主 | 2011-8-4 10:51 | 只看该作者
呵呵,试通了,但是不太明白。 USART数据发送有两个标志,一个是TXE表示发送数据寄存器空,另一个是TC表示发送结束,而且当TC置位时,TXE肯定置位了,用TXE应该只是可以更有效的利用串口发送,我用TC的标志,应该是更可靠才对,因为只有数据发送结束TC才会置位。而且我刚才又试了一遍,只要第一个用TXE,其它用什么标志无所谓,都能正常发送。希望谁能解答下这个疑问,呵呵。

使用特权

评论回复
地板
江陵龙少| | 2011-8-4 20:03 | 只看该作者
顶起来

使用特权

评论回复
5
相信哥咯| | 2011-8-4 22:44 | 只看该作者
估计06被07覆盖了,看库函数:P

使用特权

评论回复
6
ringsearch|  楼主 | 2011-8-5 08:38 | 只看该作者
呵呵,覆盖应该不可能,发送函数就是一个寄存器赋值:USARTx->DR = (Data & (uint16_t)0x01FF);而且发送也是等到上一个数发送完成,产生TC标志了才发送第二个数的。

使用特权

评论回复
7
ringsearch|  楼主 | 2011-8-6 11:16 | 只看该作者
没有人回答了吗??????

使用特权

评论回复
8
ploto| | 2011-8-6 14:15 | 只看该作者
第一句话之前没有while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);      保护啊。所以如果以前还有数据没有发的话,就覆盖了。
这个while很耗时啊,如果是9600的话,几乎为1ms。

使用特权

评论回复
9
zchong| | 2011-8-6 16:53 | 只看该作者
这个问题的根本原因是复位后,TC和TXE标志位默认都是1,很多人喜欢这样写:
  USART_SendData(USART1, (u8) ch);  
  while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)  
  {  
  }  
while在发送第一个字节时没有起到应有作用,直接跳出,接着写第二个字节,这时第一个字节还未发出,数据被破坏了
知道本质以后,You can do whatever you want to do!

使用特权

评论回复
10
kavieen| | 2011-8-6 21:45 | 只看该作者
赞成8楼得说法,while的确很费时,另外 当TDR寄存器中的数据被硬件转移到移位寄存器的时候,TXE被硬件置位(注意:单缓冲器传输中使用该位),而 当包含有数据的一帧发送完成后,并且TXE=1时,由硬件将该位置’1’,只有在多缓存通讯中才推荐这种清除程序。其中TC判断的是一帧数据,而TXE是当数据写到DR就被置位了,所以TC的时间比较长,很容易被下一次数据覆盖~~~所以一般喜欢判断TXE,数据写到DR就可以了 ,剩下的工作就交给硬件了,楼主无需再担心~~~

使用特权

评论回复
11
江陵龙少| | 2011-8-6 23:13 | 只看该作者
本帖最后由 江陵龙少 于 2011-8-6 23:19 编辑

楼主的程序我试过了,没有丢失第1个字节,用的是STM32F103VC

我的理解是:
USART_SendData(USART1,0x06);    //1
                while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);      //2

当执行第1条语句时,TXE立马被清零,这时TC还是1吗?
TC: Transmission complete
This bit is set by hardware if the transmission of a frame containing data is complete and if
TXE is set.


TC置位的条件应该是,TXE置位后经过一段时间移位寄存器移位完成,这时TC才置位

使用特权

评论回复
12
ploto| | 2011-8-7 11:28 | 只看该作者
一般的用TXE就可以了, TC一般用于需要延时的场合,比如说是232/485转换器,需要得到TC后,才能将发送改变成接收,否则最后一个字节发送不完全。

使用特权

评论回复
13
ringsearch|  楼主 | 2011-8-11 08:35 | 只看该作者
呵呵,非常感谢各位的回答,弄明白了。

使用特权

评论回复
14
sunnyhey| | 2012-12-23 14:23 | 只看该作者
zchong  说的很对,确实是这样的!

使用特权

评论回复
15
fengonge| | 2014-8-3 18:02 | 只看该作者
使用USART_FLAG_TC时,在你第一次传输之前(一般是死循环的开始之前)加入一个USART_ClearFlag(USART2,USART_FLAG_TC)就可以解决了!
关于USART_FLAG_TC与USART_FLAG_TXE两者的却别上面已经有讲到了

使用特权

评论回复
16
xgdgxb| | 2014-12-10 18:42 | 只看该作者
相信哥咯 发表于 2011-8-4 22:44
估计06被07覆盖了,看库函数

错误回答

使用特权

评论回复
17
xgdgxb| | 2014-12-10 18:43 | 只看该作者
zchong 发表于 2011-8-6 16:53
这个问题的根本原因是复位后,TC和TXE标志位默认都是1,很多人喜欢这样写:
  USART_SendData(USART1, (u8 ...

回答的太精彩了

使用特权

评论回复
18
xgdgxb| | 2014-12-10 18:44 | 只看该作者
zchong 发表于 2011-8-6 16:53
这个问题的根本原因是复位后,TC和TXE标志位默认都是1,很多人喜欢这样写:
  USART_SendData(USART1, (u8 ...

回答的太精彩了

使用特权

评论回复
19
TYZZD| | 2014-12-10 20:00 | 只看该作者
复位后TXE、TC都是1。
但他们的清零方式有点差别
对TXE:“清零TXE位总是通过对数据寄存器的写操作来完成的。”
对TC使用下列软件过程清除TC位:
1.读一次USART_SR寄存器;
2.写一次USART_DR寄存器。
注: TC位也可以通过软件对它写’0’来清除。此清零方式只推荐在多缓冲器通信模式下使用。

楼主程序
USART_SendData(USART1,0x06);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);      
USART_SendData(USART1,0x07);
……

执行完 USART_SendData(USART1,0x06);后,TXE清零,但TC并没有清零,所有
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET); 为假,马上执行下一句 (这句有读USART_SR寄存器
USART_SendData(USART1,0x07); 把0x06覆盖了。这句写USART_DR寄存器,这时TXE,TC都清零了

所以后面的数据不会再被覆盖
把第二句改为
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);也可以,因为第一句执行后TXE清零了


使用特权

评论回复
20
清风致影| | 2014-12-11 09:26 | 只看该作者
先while   再USART_SendData  就解决了嘛
最近怎么老有人挖老帖:lol

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

36

帖子

1

粉丝