OpenEdv-开源电子网

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

串口通信的数据丢失问题。

[复制链接]

15

主题

58

帖子

0

精华

初级会员

Rank: 2

积分
138
金钱
138
注册时间
2012-3-3
在线时间
0 小时
发表于 2012-3-28 12:00:57 | 显示全部楼层 |阅读模式
我用串口通信,在串口调试助手里面,以 16 进制的形式发送,接收数据,没有任何问题。但是如果以字符形式发送,只有 英文字符 和 数字字符,那么没 11 个字节就会丢失一个字节,把第11 个字节丢失了,但是,其它的字符,还能显示,包括,地11个字符以后的字符。我的程序是,电脑通过串口助手发给单片机,单片机接收到以后再原样发回电脑。

这个单步调试也没法调啊,串口助手 一下 就发完了。

工程在附件里面,请教给位高手了。



64脚实验.rar

3.55 MB, 下载次数: 381

Good?good?study,day?day?up.?立志成为牛人。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-3-28 12:50:32 | 显示全部楼层
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

15

主题

58

帖子

0

精华

初级会员

Rank: 2

积分
138
金钱
138
注册时间
2012-3-3
在线时间
0 小时
 楼主| 发表于 2012-3-28 13:51:47 | 显示全部楼层
回复【2楼】正点原子:
---------------------------------
谢谢原子哥指点,果然要靠自己解决啊。网上查了查资料,终于解决了。ST 公司的例程,看来,也不是最好的。以后,还是向原子哥学习,多操作寄存器了。

问题在这里,
u8 USART_Putc(u8 ch) 

  USART_SendData(USART1, (u8) ch); 
  while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) 
  { 
  } 
  return ch; 

这个问题的根本原因是复位后,TC和TXE标志位默认都是1,很多人喜欢这样写: 
  USART_SendData(USART1, (u8) ch);  
  while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)  
  {  
  }  
while在发送第一个字节时没有起到应有作用,直接跳出,接着写第二个字节,这时第一个字节还未发出,数据被破坏了。
这是,别人的回答,但是,我估计,可能发送 11 个字节后,是不是,也会出现类似复位的情况,TC和TXE标志位变成1了。
把上面修改成:
u8 USART_Putc(u8 ch) 

while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) 
  { 
  } 
  USART_SendData(USART1, (u8) ch);   
  return ch; 

发送之前,等待上一次发送完成,再发送下一个数据。
这样,就再没丢失过了。
Good?good?study,day?day?up.?立志成为牛人。
回复 支持 反对

使用道具 举报

15

主题

58

帖子

0

精华

初级会员

Rank: 2

积分
138
金钱
138
注册时间
2012-3-3
在线时间
0 小时
 楼主| 发表于 2012-3-28 14:58:58 | 显示全部楼层
再补充一下,上面的问题,经过我研究 参考手册 后,又通过板子,实际验证,这样写也是可以的:

while (USART_GetFlagStatus(usart,USART_FLAG_TXE) == RESET);
USART_SendData(usart,data);  
Good?good?study,day?day?up.?立志成为牛人。
回复 支持 反对

使用道具 举报

6

主题

30

帖子

0

精华

初级会员

Rank: 2

积分
75
金钱
75
注册时间
2012-3-4
在线时间
0 小时
发表于 2012-3-28 23:02:39 | 显示全部楼层
回复【楼主位】fanyi:
---------------------------------
Bit 7 TXE: Transmit data register empty
This bit is set by hardware when the content of the TDR register has been transferred into 
the shift register. An interrupt is generated if  the TXEIE bit =1 in the USART_CR1 register. It 
is cleared by a write to the USART_DR register.
0: Data is not transferred to the shift register
1: Data is transferred to the shift register)
Note: This bit is used during single buffer transmission.
Bit 6 TC: Transmission complete
This bit is set by hardware if the transmissi on of a frame containing data is complete and if 
TXE is set. An interrupt is generated if TCIE=1 in the USART_CR1 register. It is cleared by a 
software sequence (a read from the USART_SR register followed by a write to the 
USART_DR register). The TC bit can also be cleared by writing a '0' to it. This clearing 
sequence is recommended only for multibuffer communication.
0: Transmission is not complete
1: Transmission is complete

看下这个。


复位的时候TC为1,那么写入数据寄存器之后,由于仅仅就读取SR寄存器(就是USART_GetFlagStatus这个函数),但是没有往数据寄存器中写入数据(这个写入时在读取SR寄存器之后写入的,与前一个写入不同。a read from the USART_SR register followed by a write to the 
USART_DR register:这个是手册上的。),所以就不会把TC清零。也就是说第一次写入数据的时候,由于TC是1,所以第一个while判断是没有用的。第二次写入数据的时候,就把TC清零了,之后的判断就有用了。而你改变顺序之后,就是先读SR寄存器,然后写入数据寄存器,这就把TC位清零了。
但是TXE就不同了。只要把数据写入数据寄存器,TXE就自动清零了,所以第一个while判断数据是否移入到移位寄存器就有效果了。
回复 支持 反对

使用道具 举报

15

主题

58

帖子

0

精华

初级会员

Rank: 2

积分
138
金钱
138
注册时间
2012-3-3
在线时间
0 小时
 楼主| 发表于 2012-3-29 14:26:58 | 显示全部楼层
回复【5楼】Trigger:
---------------------------------
Trigger 兄果然是高手,都开始研究英文版的手册了。经过你这么一说,我再看了一下参考手册,对USART寄存器的TC, TXE的操作过程,理解的更深了。

while (USART_GetFlagStatus(usart,USART_FLAG_TXE) == RESET); 
USART_SendData(usart,data);

这两句任意交换顺序都是可以的。

我就不明白,为什么,没有人使用这个方式发生数据,而,非要去使用 TC 位,这个清零麻烦,容易出错的标志位。?????

难道仅仅是因为,官方例程是这么写的????????????





Good?good?study,day?day?up.?立志成为牛人。
回复 支持 反对

使用道具 举报

6

主题

30

帖子

0

精华

初级会员

Rank: 2

积分
75
金钱
75
注册时间
2012-3-4
在线时间
0 小时
发表于 2012-3-29 18:52:31 | 显示全部楼层
回复【6楼】fanyi:
---------------------------------
我是菜鸟...真心是菜鸟...看英文手册是英文对中文手册不放心。
回复 支持 反对

使用道具 举报

8

主题

90

帖子

0

精华

初级会员

Rank: 2

积分
146
金钱
146
注册时间
2012-7-27
在线时间
1 小时
发表于 2012-8-13 17:20:32 | 显示全部楼层
回复【6楼】fanyi:
---------------------------------
发十六进制数据的时候,我的也是总是丢失第一个数据,这和你的问题一样么?哪里解决啊
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-8-13 20:13:09 | 显示全部楼层
回复【8楼】zhaojiangbao:
---------------------------------
你代码的问题.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

8

主题

90

帖子

0

精华

初级会员

Rank: 2

积分
146
金钱
146
注册时间
2012-7-27
在线时间
1 小时
发表于 2012-8-13 21:36:51 | 显示全部楼层
回复【9楼】正点原子:
---------------------------------
回复【9楼】正点原子:
---------------------------------
回复【9楼】正点原子:
---------------------------------
我改!改找!这是个进步的过程!
回复 支持 反对

使用道具 举报

1

主题

5

帖子

0

精华

初级会员

Rank: 2

积分
115
金钱
115
注册时间
2012-12-13
在线时间
23 小时
发表于 2012-12-21 10:44:40 | 显示全部楼层
感谢各位仁兄,小弟刚好遇到此问题,就在这里找到了答案,感谢这个这么好的平台。
回复 支持 反对

使用道具 举报

0

主题

10

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2010-12-29
在线时间
3 小时
发表于 2014-1-15 17:05:13 | 显示全部楼层
回复【6楼】fanyi:
---------------------------------
没错,大家都根据ST例程写的
回复 支持 反对

使用道具 举报

0

主题

10

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2010-12-29
在线时间
3 小时
发表于 2014-1-15 17:06:08 | 显示全部楼层
----本楼纯占位,待下楼讨论----
回复 支持 反对

使用道具 举报

0

主题

10

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2010-12-29
在线时间
3 小时
发表于 2014-1-16 09:47:36 | 显示全部楼层
回复【6楼】fanyi:

  TC 是发送完成标志,TXE是数据发送至移位寄存器的标志,用法略有区别,至于
while (USART_GetFlagStatus(usart,USART_FLAG_TXE) == RESET); 
USART_SendData(usart,data);
 这个while语句在前还是在后,个人认为,ST原本目的是为了照顾引脚复用的情况,当判断while 在前判断TC或TXE的时候,这两条语句执行完毕之后,如果串口被复用被改变了输出状态,则可能导致串口内的数据无法正常送出。
如果判断TC在前,判断while 在后(st现有做法),那么就出现丢首字节的问题。
如果判断TXE在前判断while 在后,则因TXE并不代表当前传输完毕,所以串口复用的时候依然会存在可能导致尾字节无法送出的问题。

所以这个问题的解决方案要根据各人的实际使用情况来确定:

如果串口不会复用,则建议选用判断TXE标志。亦即:
USART_SendData(usart,data);  //A
while (USART_GetFlagStatus(usart,USART_FLAG_TXE) == RESET);  //B
//这里选用TXE而不是TC,是因为TXE默认为1,当A执行后,TXE就立刻变成了0,所以接下来的while就起作用了。
//如果选用TC,同样TC默认是1,但是A执行后TC在某种情况下,【注意不是绝对的,同样一个printf语句,在程序的不同地方执行,有时候TC会立即变成0,有时候却不会,具体什么原因懒得查了】却不能立刻变成0,所以接下来的while语句不成立,所以就直接跳走了,所以再来第二个字节的话,就可能第一个字节就被覆盖了,从而导致丢字节


如果串口被复用则建议采用保险的做法,亦即楼主给出的解决方案,虽然该方案会浪费一点点时间和略有些麻烦。

回复【5楼】Trigger:
---------------------------------
Trigger 兄果然是高手,都开始研究英文版的手册了。经过你这么一说,我再看了一下参考手册,对USART寄存器的TC, TXE的操作过程,理解的更深了。
while (USART_GetFlagStatus(usart,USART_FLAG_TXE) == RESET); 
USART_SendData(usart,data);
这两句任意交换顺序都是可以的。
我就不明白,为什么,没有人使用这个方式发生数据,而,非要去使用 TC 位,这个清零麻烦,容易出错的标志位。?????
难道仅仅是因为,官方例程是这么写的????????????


---------------------------------
回复 支持 反对

使用道具 举报

0

主题

10

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2010-12-29
在线时间
3 小时
发表于 2014-1-16 09:51:36 | 显示全部楼层
回复【3楼】fanyi:

回复【2楼】正点原子:
---------------------------------
谢谢原子哥指点,果然要靠自己解决啊。网上查了查资料,终于解决了。ST 公司的例程,看来,也不是最好的。(ST的例程是安全的,但有时候确实也会出点小问题)以后,还是向原子哥学习,多操作寄存器了。
问题在这里,
u8 USART_Putc(u8 ch) 

  USART_SendData(USART1, (u8) ch); 
  while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) 
  { 
  } 
  return ch; 

这个问题的根本原因是复位后,TC和TXE标志位默认都是1,(为1的时候,表示传输完毕,这种设定没有错)很多人喜欢这样写: 
  USART_SendData(USART1, (u8) ch);  
  while(USART_GetFlagStatus(USART1, 
......
---------------------------------
回复 支持 反对

使用道具 举报

0

主题

10

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2010-12-29
在线时间
3 小时
发表于 2014-1-16 09:56:32 | 显示全部楼层
回复【6楼】fanyi:

回复【5楼】Trigger:
---------------------------------
Trigger 兄果然是高手,都开始研究英文版的手册了。经过你这么一说,我再看了一下参考手册,对USART寄存器的TC, TXE的操作过程,理解的更深了。
while (USART_GetFlagStatus(usart,USART_FLAG_TXE) == RESET); 
USART_SendData(usart,data);
这两句任意交换顺序都是可以的。(在串口没被复用的情况下,亦即串口发送数据后,引脚的设定状态没有被改变的情况下,这样写是没有问题的,而且while在前还是在后都无所谓)
我就不明白,为什么,没有人使用这个方式发生数据,而,非要去使用 TC 位,这个清零麻烦,容易出错的标志位。?????
难道仅仅是因为,官方例程是这么写的????????????


---------------------------------
回复 支持 反对

使用道具 举报

20

主题

46

帖子

0

精华

初级会员

Rank: 2

积分
165
金钱
165
注册时间
2013-7-4
在线时间
5 小时
发表于 2014-5-17 11:12:56 | 显示全部楼层
刚碰到,标记下,以后详细看
回复 支持 反对

使用道具 举报

4

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
55
金钱
55
注册时间
2014-4-3
在线时间
1 小时
发表于 2015-4-9 18:33:55 | 显示全部楼层
mark!!!大牛分析得挺透彻的
回复 支持 反对

使用道具 举报

33

主题

218

帖子

0

精华

高级会员

Rank: 4

积分
568
金钱
568
注册时间
2015-1-12
在线时间
75 小时
发表于 2021-12-23 11:41:08 | 显示全部楼层
顶起,改进学习
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-19 22:18

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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