完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
在使用串口发送数据的时候,一包数据大概260个字节左右,发送的时候是整包发的,但是好像在发送的过程中被打断了,接收方可以接收到,但是可以看到是分了几次才接收到的,这种情况怎么处理? 接收方用的是串口空闲中断来接收数据。 rt_err_t my_uart_putchar(const char *name,const rt_uint8_t c) |
|
相关推荐
1个回答
|
|
接收方使用串口空闲中断的提前是:发送方要连续发送。如果接收方超过一个字节周期接收不到数据视为空闲,则发送方的发送线程不能被打断超过一个字节周期。如果是115200波特率的话,这个周期大概是86us。被打断超过这个时间是很容易的,比如在另一个线程打印了一条日志。
解释方法有很多,以下是几种方案: 提高发送线程的优先级,并保证比他高优先级的线程和中断函数中不执行长时间的操作,比如打印日志。更简单一点,将发送线程优先级提至最高,那只需要保证中断函数中不执行长时间操作即可。不建议关中断,115200波特率的一个字节是86us,十几个字节能达到1ms,这是相当长的时间。关中断的话,可能会丢失很多数据。 使用DMA发送。 接收方使用软件来检测空闲,而不是硬件。这样可以放宽实时要求,比如1ms接收不到数据视为本包结束。当然,这样会牺牲一点传输带宽。人家每86us就可以发新包,而你得等1ms。 下面贴出我日常使用的接收代码,即第3种方案。 初始化串口时通过rt_device_set_rx_indicate设置回调,在回调中发送一个数据事件。 /** * 硬件串口接收数据的回调函数 * * @param stream 串口流 * @param drv 串口设备 * @param size 待接收的数据大小 * * @return */ rt_err_t serial_stream_rx_notify(serial_stream_t *stream, rt_device_t dev, rt_size_t size) { rt_event_send(stream->serial_rx_event, SERIAL_RX_EVENT); return RT_EOK; } 这是接收一个字节的函数,其先调用rt_device_read读取,若有数据则直接返回。若无数据,则等待数据事件。等待成功了再读取数据,若超时则返回失败。 /** * 从串口流读取单个字节数据 * * @param stream 串口流 * @param timeout 超时时间 * * @Return 实际读取的字节数 */ rt_int32_t serial_stream_read_byte(serial_stream_t *stream, rt_tick_t timeout) { rt_uint8_t data; rt_err_t ret; rt_uint32_t event; while(RT_TRUE) { if(rt_device_read(stream->serial, 0, &data, 1) == 1) { return data; } ret = rt_event_recv(stream->serial_rx_event, SERIAL_RX_EVENT, RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, timeout, &event); if(ret != RT_EOK) { return -1; } } } 当然,你肯定不是想一个字节一个字节的接收的,所以请看下面这个函数。其负责接收一整包数据。请注意,有两个超时时间。begin_timeout是首字节超时,cont_timeout是字节间超时。cont_timeout是负责分包的,那为什么还要有个begin_timeout呢?想象一下,我并不知道对方什么时候会发数据,它可能1个小时只发1包数据,如果我使用1ms超时来接收,那将不停地收到空数据。虽然这也没啥问题,不过笔者不喜欢哈哈。如果长时间无数据也不需要做额外操作的话,可以把begin_timeout设置为RT_WAITING_FOREVER。 rt_size_t serial_stream_read_bytes2(serial_stream_t *stream, rt_uint8_t *buf, rt_size_t size, rt_tick_t begin_timeout, rt_tick_t cont_timeout) { rt_size_t i; rt_int32_t data; for(i = 0; i < size; i++) { data = serial_stream_read_byte(stream, i == 0 ? begin_timeout : cont_timeout); if(data == -1) { break; } buf = (rt_uint8_t)data; } return i; } |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
I.MX6ULL-飞凌 ElfBoard ELF1板卡- 应用层更改引脚复用的方法
3173 浏览 0 评论
1341 浏览 0 评论
【英飞凌PSoC 6 RTT开发板试用】串口测试标准输入输出重定向
1112 浏览 0 评论
4627 浏览 0 评论
1821 浏览 0 评论
55459 浏览 21 评论
【参与有奖】激扬代码,千元现金!RT-Thread主题征文大赛
56986 浏览 88 评论
277551 浏览 75 评论
50731 浏览 31 评论
15972 浏览 53 评论
野火 ISO STM32资料合集(程序、原理图、项目初高级篇)
18091 浏览 46 评论
13262 浏览 50 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-4-29 01:10 , Processed in 0.411256 second(s), Total 37, Slave 31 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号