打印
[STM32F1]

第一次发帖有误。。。补帖:关于USART中TXE和TC的问题,求助

[复制链接]
1870|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
dwightwjl|  楼主 | 2014-1-29 15:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 dwightwjl 于 2014-1-29 15:48 编辑

第一次不会发帖,貌似刚一发就把贴莫名其妙得给结了。。。
我再把第一次发帖中的问题粘贴过来:
本渣刚开始学STM32,用的是刘凯老师的视频。在学到UARST时遇到了一个小问题:
下面的代码是在USART初始化完成后的,期望的执行结果是USART1发送ABCDEFGHIJ,调试发现少了个B。而如果把USART_FLAG_TC换成USART_FLAG_TXE,得到的结果就是正确的。另外,将下面代码中的延时利用上时,结果也是正确的。。。隐约得感觉到是与时间有关,但还是不明确问题所在,视频里的刘凯老师也没发现这个BUG(看到他在调试结果显示ACDEFGHI时说到:“我们成功了”)。。。请教各位前辈了!
        data = 'A';
        for(i = 0;i < 10;i++)
        {
                USART_SendData(USART1, data);
                data++;
                 //Delay_MS(1);        
                 while(USART_GetFlagStatus(USART1, USART_FLEAG_TC) == RESET);
        }
沙发
huzi2099| | 2014-1-29 16:07 | 只看该作者
你的程序应该发送前确定前次发送已经完成,所以先while后send
TXE位由硬件来设置,它表明:
●数据已经从TDR移送到移位寄存器,数据发送已经开始
●TDR寄存器被清空
●下一个数据可以被写进USART_DR寄存器而不会覆盖先前的数据

所以应该是TXE

使用特权

评论回复
板凳
huzi2099| | 2014-1-29 16:08 | 只看该作者
delay是不需要的

使用特权

评论回复
地板
huzi2099| | 2014-1-29 16:16 | 只看该作者
TC不对的原因是没有清除TC标记,
"先读一下USART_SR寄存器,再写一下USART_DR寄存器,可以完成对TC位的清零。"
老师也不是万能的哦

使用特权

评论回复
5
dwightwjl|  楼主 | 2014-1-29 16:30 | 只看该作者
huzi2099 发表于 2014-1-29 16:07
你的程序应该发送前确定前次发送已经完成,所以先while后send
TXE位由硬件来设置,它表明:
●数据已经从TDR ...

谢谢解答~但是视频里老师说TC是发送完成,我自己感觉和你说的意思差不多额。我以为是初学,理解得还不是很清楚,TC和TXE最根本的区别是什么呢?

使用特权

评论回复
6
dwightwjl|  楼主 | 2014-1-29 16:32 | 只看该作者
huzi2099 发表于 2014-1-29 16:16
TC不对的原因是没有清除TC标记,
"先读一下USART_SR寄存器,再写一下USART_DR寄存器,可以完成对TC位的清零 ...

这段程序如果用一定要用TC,该怎么改呢?还是根本不能用TC来判断下一次发送允许呢?

使用特权

评论回复
7
huzi2099| | 2014-1-29 20:08 | 只看该作者
本帖最后由 huzi2099 于 2014-1-29 20:13 编辑
dwightwjl 发表于 2014-1-29 16:30
谢谢解答~但是视频里老师说TC是发送完成,我自己感觉和你说的意思差不多额。我以为是初学,理解得还不是 ...


串口发送两个步子,
1: DR写入新的数据后新数据移送到移位寄存器,这个寄存器是看不到的,这步完成后TXE置位
2:移位寄存器合并起始位校验位等逐位发送,移位寄存器全部发完TC置位.
你为什么会丢B而不是A呢?因为你的初始进入循环条件不对也就是TC没有被清除,这时写入移位寄存器和DR都是空的写入是对的,也可以发送,但是注意手册上那句话要读一次SR再写DR才可以清除,所以写入字符A后检测TC是不对的,因此马上就会转到写入字符B,这次写入DR后会清除TC,因为USART_GetFlagStatus函数会读一次SR寄存器,代码如下
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)
{
  FlagStatus bitstatus = RESET;

  /* The CTS flag is not available for UART4 and UART5 */
  if (USART_FLAG == USART_FLAG_CTS)
  {
    assert_param(IS_USART_123_PERIPH(USARTx));
  }  
  
  if ((USARTx->SR & USART_FLAG) != (uint16_t)RESET)
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  return bitstatus;
}
后面再写入时就是这个顺序了读SR写DR都对了。加入延时之所以能对是因为1ms已经发送完了。
知道缘由解决就简单了,循环前空读一次SR就行了。
最好的方式还是把USART_GetFlagStatus放在USART_SendData(USART1, data);前面不会有错。
最好的写入时机还是检测TXE,这个效率高些,因为你不必等到数据发送完。

使用特权

评论回复
8
dwightwjl|  楼主 | 2014-1-29 21:21 | 只看该作者
huzi2099 发表于 2014-1-29 20:08
串口发送两个步子,
1: DR写入新的数据后新数据移送到移位寄存器,这个寄存器是看不到的,这步完成后TXE置位 ...

前辈解释得真详细,让我终于明白了TC和TXE的区别,但我还是不能理解程序的执行结果(少了个B而不是A,教程视频里也是同样的情况,只是主讲人没有发现),如果前辈方便用Keil的话,可以看看我的工程文件,万分感谢!链接是http:||pan*baidu*com|s|1jGoMBp8,把*替换成.,|替换成/就好~

使用特权

评论回复
9
huzi2099| | 2014-1-29 23:05 | 只看该作者
dwightwjl 发表于 2014-1-29 21:21
前辈解释得真详细,让我终于明白了TC和TXE的区别,但我还是不能理解程序的执行结果(少了个B而不是A,教 ...

不想装什么百度什么管家

使用特权

评论回复
10
zxf0168| | 2014-1-29 23:11 | 只看该作者
使用完了记得清零

使用特权

评论回复
11
dwightwjl|  楼主 | 2014-1-30 15:09 | 只看该作者
huzi2099 发表于 2014-1-29 23:05
不想装什么百度什么管家

这都除夕了,就不麻烦了哈,祝前辈新春快乐!以后在21ic社区里还请多多指导!

使用特权

评论回复
12
dwightwjl|  楼主 | 2014-1-30 15:10 | 只看该作者
zxf0168 发表于 2014-1-29 23:11
使用完了记得清零

我试试,谢啦!

使用特权

评论回复
13
shenpingbing| | 2014-1-31 21:54 | 只看该作者
学习一下子

使用特权

评论回复
14
zxf0168| | 2014-2-18 16:02 | 只看该作者
dwightwjl 发表于 2014-1-30 15:10
我试试,谢啦!

嗯嗯,成功了吗

使用特权

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

本版积分规则

2

主题

10

帖子

0

粉丝