OpenEdv-开源电子网

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

STM32F7使用链队列从串口接收数据出现漏掉字节的问题

[复制链接]

6

主题

22

帖子

0

精华

初级会员

Rank: 2

积分
59
金钱
59
注册时间
2017-10-14
在线时间
13 小时
发表于 2019-3-26 11:42:38 | 显示全部楼层 |阅读模式
1金钱

我是用原子的F7开发板,试了下使用链队列从串口接收数据,串口接收数据波特率为115200,一边收一边在main函数while(1)中检测队列是否为空,不空则将数据发送出来,但是当发送大量数据时时不时就会少几个字节,如果使用数组实现队列就不会出现这种问题,链队列中malloc使用C库函数和原子的内存管理都试过,都会出现漏字节的问题,想问下这种情况怎么回事呢?是malloc执行太耗时间了吗?如果在while(1)中再加一些其他的代码,漏字节的现象更严重了

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

6

主题

56

帖子

0

精华

初级会员

Rank: 2

积分
129
金钱
129
注册时间
2019-1-29
在线时间
67 小时
发表于 2019-3-26 15:35:17 | 显示全部楼层
看来你没有用中断模式.

这样你的代码每次读uart的间隔越长, 漏字符的可能性就越大.

最佳的方法还是中断加ringbuff , 然后在非中断的代码里读取ringbuff数据.

ringbuff的大小决定了你在外面能有多长时间的处理间隔.

回复

使用道具 举报

6

主题

22

帖子

0

精华

初级会员

Rank: 2

积分
59
金钱
59
注册时间
2017-10-14
在线时间
13 小时
 楼主| 发表于 2019-3-26 15:41:58 | 显示全部楼层
ZHDX 发表于 2019-3-26 15:35
看来你没有用中断模式.

这样你的代码每次读uart的间隔越长, 漏字符的可能性就越大.

我确实是在串口中断里读取字符的,队列我用的也是循环队列
回复

使用道具 举报

6

主题

56

帖子

0

精华

初级会员

Rank: 2

积分
129
金钱
129
注册时间
2019-1-29
在线时间
67 小时
发表于 2019-3-26 15:44:51 | 显示全部楼层
我是传奇1 发表于 2019-3-26 15:41
我确实是在串口中断里读取字符的,队列我用的也是循环队列

但是你说的 "链队列" 是用 malloc 的啊..

一般 ringbuff 是预先分配好的, 不会临时分配.
回复

使用道具 举报

6

主题

22

帖子

0

精华

初级会员

Rank: 2

积分
59
金钱
59
注册时间
2017-10-14
在线时间
13 小时
 楼主| 发表于 2019-3-26 15:50:19 | 显示全部楼层
ZHDX 发表于 2019-3-26 15:44
但是你说的 "链队列" 是用 malloc 的啊..

一般 ringbuff 是预先分配好的, 不会临时分配.

用数组实现队列才需要预先分配内存,用链表实现队列的目的就是想的是用的时候才分配,每个队列都可以分配不同大小的内存
回复

使用道具 举报

6

主题

56

帖子

0

精华

初级会员

Rank: 2

积分
129
金钱
129
注册时间
2019-1-29
在线时间
67 小时
发表于 2019-3-26 16:03:16 | 显示全部楼层
我是传奇1 发表于 2019-3-26 15:50
用数组实现队列才需要预先分配内存,用链表实现队列的目的就是想的是用的时候才分配,每个队列都可以分配 ...

那样不现实.

malloc的执行时间是很不稳定的.

中断就是要快. 115200的波特率, 每次中断都需要在万分之一秒内处理完. 不然就会漏字符.

只要你分配1024字节的ringbuff, 保证在十分之一秒内去处理一下, 就不会漏.
回复

使用道具 举报

6

主题

22

帖子

0

精华

初级会员

Rank: 2

积分
59
金钱
59
注册时间
2017-10-14
在线时间
13 小时
 楼主| 发表于 2019-3-26 16:27:45 | 显示全部楼层
ZHDX 发表于 2019-3-26 16:03
那样不现实.

malloc的执行时间是很不稳定的.

“malloc的执行时间是不稳定的”这句话怎么说?我刚刚用systick测试了一下C库函数的malloc,分配一个链表节点的时间大约是100个tick,F7跑216M,每个tick是1/216us,100个tick就大约是0.5us,而原子的内存管理malloc分配一个节点大约是500个tick,也就大约是2.5us,115200bps每次中断的时间是69us,怎么会处理不完呢?
回复

使用道具 举报

6

主题

56

帖子

0

精华

初级会员

Rank: 2

积分
129
金钱
129
注册时间
2019-1-29
在线时间
67 小时
发表于 2019-3-26 16:44:24 | 显示全部楼层
你这样测试不反映复杂的实际运行情况.  

除非你的程序就只有1种场合分配内存, 其他场合不用malloc了

在正常的程序里, malloc是被反复执行, 不断地分配释放不同大小的内存, 产生很多内存碎片.

malloc每次需要在内存碎片里寻找最合适的大小, 这就造成了时间上的不确定.  而且这越到后面就越糟糕.

不同的malloc实现由不同的特点,  有一些malloc实现还会不断地花时间去寻找可以拼接一起的内存块, 这就更花时间了.  为的都是要适应内存不足的问题.

而且你的程序在外面用while的方式不断探测有没有数据可读,  数据处理完后, 就肯定要执行free,  free内部函数执行到一半, 碰巧uart中断就来了, 在IRQ理执行malloc ,

那样有锁的就会锁超时, 没锁的会产生不确定的的问题.

回复

使用道具 举报

6

主题

22

帖子

0

精华

初级会员

Rank: 2

积分
59
金钱
59
注册时间
2017-10-14
在线时间
13 小时
 楼主| 发表于 2019-3-26 16:52:40 | 显示全部楼层
ZHDX 发表于 2019-3-26 16:44
你这样测试不反映复杂的实际运行情况.  

除非你的程序就只有1种场合分配内存, 其他场合不用malloc了

确实,你说的对,忘记了malloc是需要去寻找可用的内存来分配的了
回复

使用道具 举报

6

主题

22

帖子

0

精华

初级会员

Rank: 2

积分
59
金钱
59
注册时间
2017-10-14
在线时间
13 小时
 楼主| 发表于 2019-3-26 17:11:30 | 显示全部楼层
本帖最后由 我是传奇1 于 2019-3-26 17:12 编辑
我是传奇1 发表于 2019-3-26 16:52
确实,你说的对,忘记了malloc是需要去寻找可用的内存来分配的了

我刚刚测了如果用的是原子内存管理的mallco,先分配了5K个节点的内存,再分配一个节点的内存,再去释放这一个节点的内存,这时候在内存管理表中寻找一个节点的可用内存去分配和释放肯定要很久了,但是分配这一个节点也只用了28us,释放的时间也不到1us,况且实际我用队列的时候队列中的数据肯定不会堆积到5K个节点这么多,这怎么解释呢?
回复

使用道具 举报

6

主题

22

帖子

0

精华

初级会员

Rank: 2

积分
59
金钱
59
注册时间
2017-10-14
在线时间
13 小时
 楼主| 发表于 2019-3-26 17:12:53 | 显示全部楼层
ZHDX 发表于 2019-3-26 16:44
你这样测试不反映复杂的实际运行情况.  

除非你的程序就只有1种场合分配内存, 其他场合不用malloc了

我刚刚测了如果用的是原子内存管理的mallco,先分配了5K个节点的内存,再分配一个节点的内存,再去释放这一个节点的内存,这时候在内存管理表中寻找一个节点的可用内存去分配和释放肯定要很久了,但是分配这一个节点也只用了28us,释放的时间也不到1us,况且实际我用队列的时候队列中的数据肯定不会堆积到5K个节点这么多,这怎么解释呢?
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2019-3-26 18:20:07 | 显示全部楼层
所有方便你用的库函数都一定不释代价的保证安全性, 要求速度的就只能自己动手
写个循环的缓存也没有多复杂, 自己动手吧
回复

使用道具 举报

6

主题

22

帖子

0

精华

初级会员

Rank: 2

积分
59
金钱
59
注册时间
2017-10-14
在线时间
13 小时
 楼主| 发表于 2019-3-26 18:44:28 | 显示全部楼层
edmund1234 发表于 2019-3-26 18:20
所有方便你用的库函数都一定不释代价的保证安全性, 要求速度的就只能自己动手
写个循环的缓存也没有多复 ...

解决问题当然容易,我当然知道用数组写个循环队列就能搞定,我只是搞清楚用链队列出问题的原因在哪
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2019-3-26 18:58:54 | 显示全部楼层
我是传奇1 发表于 2019-3-26 18:44
解决问题当然容易,我当然知道用数组写个循环队列就能搞定,我只是搞清楚用链队列出问题的原因在哪

单凭你一楼提供的一点点信息, 只能猜了, 我猜你的问题在发送那里, 是用库函数发的吧?
回复

使用道具 举报

6

主题

22

帖子

0

精华

初级会员

Rank: 2

积分
59
金钱
59
注册时间
2017-10-14
在线时间
13 小时
 楼主| 发表于 2019-3-26 19:18:57 | 显示全部楼层
edmund1234 发表于 2019-3-26 18:58
单凭你一楼提供的一点点信息, 只能猜了, 我猜你的问题在发送那里, 是用库函数发的吧?

串口发送数据除了使用库函数还有什么办法呢
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2019-3-26 19:24:46 | 显示全部楼层
我是传奇1 发表于 2019-3-26 19:18
串口发送数据除了使用库函数还有什么办法呢

寄存器啊, 其实问题不在库函数, 而在库函数的工作方式, 发送后就在哪儿死停, 等到发送完成才退出, 发一个字节的时间就等于收一个字节的时间啊, 你再来个SYSTICK中断, 那来足够的时间给你处理接收?
当然, 你说的问题能有n个可能性, 我只是根据仅有的信息猜的
回复

使用道具 举报

6

主题

56

帖子

0

精华

初级会员

Rank: 2

积分
129
金钱
129
注册时间
2019-1-29
在线时间
67 小时
发表于 2019-3-26 19:25:08 | 显示全部楼层
剩下的只能靠你自己了.  毕竟是你自己写的代码, 又没POST上来.

我也只能靠最可能的方向去找原因.

IRQ的要求很高, 除了时限问题, 还有一个问题是 "线程安全"

也就是说你的关键代码也很容易因为被中断而产生各种诡异的问题.

所以像FreeRTOS这种操作系统才会做出任务间通信机制,  包括IRQ


又或者什么原因都不是呢? 只是代码有BUG
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-10 04:03

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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