完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
因为串口接收的时候,会把一条数据分成几段来接收。所以采用定时器超时判断接受完一条完整数据。思路是接收到数据后,启动定时器,写入超时时间T,如果超过T,触发定时器超时函数,说明T时间内没有收到数据,完成了一条数据的接收。 struct serial_configure pconfig; rt_err_t env_recv_ind(rt_device_t dev, rt_size_t size) 接收线程里读取不到信号量,则不执行下面的内容,读到信号量,则开始接收数据,把接收的数据保存在数组里,后续处理。 timeout_s.sec = 0; /* 秒 */ 重点在这里,我设置的时间是300ms,经过测试,设置时间短了,经常不能完整接收一条数据。但是300ms也太长了,串口发送数据,中间的间隔,怎么也不至于300ms,但是少于300ms,就接受不完整,300ms,就接收完整。 裸机时候开个定时器,好像超时时间10ms就够了。现在如果一条数据分成5段,则前面4段的等待时间是[0,300]ms,最后一段等待时间是300ms,接收一条完整数据最少要等待300+ms。效率太低了。 我需要修改代码哪个地方,来避免这种情况呢? |
|
相关推荐
10个回答
|
|
给你参考我的代码吧,我采用的中断接收,dma接收也可以使用。但要注意间隔时间
思想是:接收到一个字符后,就开始等待timeoutByte个时间片, 在这个时间片内接收到数据认为数据没有接收完毕,如果没有收到认为接收成功 9600波特率timeoutByte可以为5ms - 20ms modbus规定的报文间隔要大于3.5个字符,你可以算下需要延时多少。 /** * @Brief 串口接收数据 * * @param serial * @param buf 接受缓冲区 * @param bufSize 接受缓冲区大小 * @param timeout timeout时间后还没接收到一个字符认为失败 * @param timeoutByte 两个字符直接超过timeoutByte认为接收完成 * @Return int32_t */ int32_t uartRecvData(rt_device_t serial, char *buf, int32_t bufSize, int32_t timeout, int32_t timeoutByte) { uint32_t len = 0; int16_t resut = 0; while (1) { if (rt_event_recv(&uartEvent, 1 << getUartChannel(serial), RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, timeout, NULL) != RT_EOK) return len; timeout = timeoutByte; resut = rt_device_read(serial, 0, buf + len, bufSize - len); if (resut < 0) return 0; len += resut; if (len > bufSize) return 0; } } /** * @brief 串口中断接收回调函数 * * @param dev * @param size * @return rt_err_t */ static rt_err_t modbusServiceRxCallback(rt_device_t dev, rt_size_t size) { rt_event_send(&uartEvent, 1 << getUartChannel(dev)); return RT_EOK; } |
|
|
|
|
|
|
|
串口接收到数据后触发下面的回调函数,发送事件,上面的函数收到事件就一个字节。那个bytetimeout是啥意思,imeout
|
|
|
|
注释写了timeout和timeoutByte的意思,
这个代码之前是用来做RS485收发的,服务端发送数据后,modbus从机不一定会返回数据(线路连接失败等) 假设timeout为100,表示的就是100ms还没有收到从机返回一个字符就认为接收失败,返回0 假设timeoutByte为10,表示的是接收到从机返回数据字符了,如果10ms内还没有收到新的返回数据数字,表示从机返回数据发送完毕,可以进行解析了 |
|
|
|
看了你的需求,个人感觉可以用中断接收加定时器来
每次进入接收回调函数 停止之前定时器。 把数据存入缓冲区(rtthread内置的有环形缓冲区),并记录接收了多少数据 启动定时器20ms(根据实际情况) 在定时器回调函数使用信号量或者事件通知应用层接收完毕 |
|
|
|
看了你的需求,个人感觉可以用中断接收加定时器来
每次进入接收回调函数 停止之前定时器。 把数据存入缓冲区(rtthread内置的有环形缓冲区),并记录接收了多少数据 启动定时器20ms(根据实际情况) 在定时器回调函数使用信号量或者事件通知应用层接收完毕 |
|
|
|
同时要注意定时器通知应用层后,要确保应用层代码和数据缓冲区资源互斥,
防止应用层代码访问缓冲区数据时,接收到新的串口数据。 或者直接定时器回调函数使用中断模式,在定时器中断中使用消息队列发送给应用层 突然想到rt-thread已经内置了接收缓冲区,串口接收回调中只需要停止之前定时器,再重新启动定时器就好 |
|
|
|
通过延时方式来判断数据是否接收成功的,还是不要用dma了。
dma空闲中断,如果你的数据很长,dma一直在搬运,那就不会触发空闲中断回调 这时想通过延时方式来判断就很不容易 |
|
|
|
你好,我不是通过rt_thread_delay做的。和你这个回复思路是一样的。
我的代码在问题里,DMA接收,接收到数据释放信号量,接收线程收到信号量后,重新开启定时器,把数据放在数组里,定时器超时时间是300ms,如果超时,说明接收完成,处理数据。 感觉思路跟你说的一样,但是这个时间太长了,300ms,我试过设置小一些,但是通信会失败。 |
|
|
|
|
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
AI模型部署边缘设备的奇妙之旅:如何在边缘端部署OpenCV
1379 浏览 0 评论
tms320280021 adc采样波形,为什么adc采样频率上来波形就不好了?
1080 浏览 0 评论
1502 浏览 0 评论
1385 浏览 0 评论
1030 浏览 0 评论
74595 浏览 21 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-18 20:15 , Processed in 0.647351 second(s), Total 60, Slave 53 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号