OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3664|回复: 2

USART发送中断,挖了TC的祖坟

[复制链接]

0

主题

0

帖子

0

精华

新手上路

积分
31
金钱
31
注册时间
2019-4-21
在线时间
6 小时
发表于 2019-4-25 01:01:12 | 显示全部楼层 |阅读模式
本帖最后由 shaoyinli 于 2019-4-25 01:27 编辑

  谈起USART,许多人一笑而过,不就是USART么但谈到TC中断用一万个表情...(希望大神不要打我)。小菜我这几天真的是被TC给搞得生活不能自理,各种清除状态都不起作用,而且会出现各种各样的奇怪现象,倔强的本小菜展现了强大的求生欲...TC的水很深吗?没错,TC的水确实很深。
切入正题...首先,在USART被使能后,也就是USART_Cmd()调用后,TC就会被置1,如果开了中断,程序就发疯了的进中断。还好小菜我还没疯——ST的参考手册上有一句话:在数据传输过程中,若TE上有个上升沿(除了在智能卡模式下),会在数据字传输完成之后发送一个“前导符”(空闲总线)。于是小菜我先使能UE(即调用USART_Cmd(USART1,ENABLE))再使能TE(即在USART_Init( )中的参数结构体中设置USART_Mode=USART_Mode_Tx)会使TE上出现一个上升沿,导致前导符的发送;或者先使能TE再使能UE,由于UE是USART的上电开关,同样会导致TE上出现一个上升沿,导致前导符的发送。将TE的使能与UE的使能分别去掉再实验,都不会发送前导符。前导符的发送完成是系统的第一次数据发送完成,所以会使TC置1,这就是使能USART的发送数据功能之后即使不做任何操作TC也会置1的原因。此时我心中无比狂喜~TC也不过如此嘛..于是我在使能之后立即使用USART_ClearFlag(USART1,USART_FLAG_TC)来一波清除,motherfucker不起作用!TC仍然会抽风似的置1,我得世界颠覆了...
于是小菜我不得不大胆瞎猜:是时间同步的问题,即发送前导符需要一定的时间,当TC手动清除之后前导符还没发送完成,这样就导致清除TC后,TC还是会被置1,也就是不是加清除函数不起作用,而是作用时间不够。通过测量,小菜我是对的~~奉上数据:
baudrateleading character sending  time/us baudrate*time
115200 95 10944000
76800 141 10828800
14400 762 10972800
9600 1144 10982400
使用正点原子提供的delay()函数,精确到了us,机智的小菜我发现前导符的发送时间与波特率成反比,哦~理当如此。这样一来,程序刚开始时,在手动清除TC位之前只要有足够的延时,问题就解决啦!此时的小菜我几乎到达了人生的巅峰。。。(以上使用stm32f103rct6,系统时钟72Mhz)


  通过以上的说法,TC好像也不难啊But,事儿还没完呢,小菜我说好要挖了TC的祖坟的~通过不不懈的百度,小菜我看到了一句话:TC是所有字符发送完成的标志位,所有字符~所有字符~一个大嘴巴把小菜我打的世界再一次颠覆。Tmd TC参考手册也没说清楚啊!!!于是小菜我一行代码一行代码的测试,发现TC还确实是Tmd所有字符发送完成的标志位。于是急于求生的小菜我又想:芯片是怎么知道所有字符发送完成中的这个Fucking所有的呢???---停顿时间,机智的小菜我立刻想到。其实也只有这种方法能做到,也就是芯片里面有一个检测发送一字节数据之后停顿时间的机制,若停顿时间超过某一值,就认为当前的所有字符发送完成。通过测试,小菜我又是对的再次奉上数据:
baudrate effective stop time/us
baudrate*effective stop time
115200 171 19699200
76800 257 19737600
14400 1386 19958400
9600 2080 19968000
呵呵,有效停顿时间与波特率成反比~~
于是乎,之前小菜遇到的所有灵异现象就都说得通了。另外,小菜在此提醒,不要使用发送一字节就检测一次TC状态的这种方法,虽然也能发送成功,但是很费时间,听小菜我娓娓道来:程序段如:
  for(n=0;n<16;n++)
{
while(!USART_GetFlagStatus(USART1,USART_FLAG_TC));
USART_SendData(USART1,Test[n]);
}  

基于之前说的通过检测停顿来确定是否发送完成,由于使用了
while(!USART_GetFlagStatus(USART1,USART_FLAG_TC));发送每一个字节后,程序都要停顿足够时间(即有效完成停顿时间)以将TC置1,所以导致不必要的时间延迟。

咋样,说的有道理吧单字发送串的时候最好用TXE,因为它不会闹事,而且清除也十分容易。而长字符串的发送使用TC直接检测是否全部发送完成则十分的方便。
此时的小菜我面容安详,似乎拯救了宇宙,并且感叹人生的无限美好~~~




2019-04-25_0-25-35.jpg
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

6

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
208
金钱
208
注册时间
2016-8-2
在线时间
54 小时
发表于 2020-10-14 13:07:13 | 显示全部楼层
谢谢楼主,说的很详细,这么好的帖子怎么没人回复
回复 支持 反对

使用道具 举报

50

主题

1805

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
6662
金钱
6662
注册时间
2016-5-29
在线时间
910 小时
发表于 2020-10-14 15:41:53 | 显示全部楼层
像 串口 这种慢速通信协议,最好使用DMA来发送与接收.初始化完成后,就变得非常简单与可靠了.不与 " TC "打交道.不存在这种 "烦恼" .
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-17 15:15

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表