完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
我的思路是,用标准库的时候,定时器向上计数,串口接收到数据后,setcounter为0,定时器的计数器从头开始计数,这样当接收数据的时候,定时器不会中断。当接完一帧数据,不会给setcounter设置为0了,定时器一直计数,就会产生中断,此时处理数据,关闭定时器。 但是现在硬件定时器框架只有write control,没有控制定时器计数器的接口,想实现类似的功能应该怎么写呢?谢谢。 |
|
相关推荐
11个回答
|
|
串口判断一帧结束应该是使用类似空闲中断的原理,比如说串口的通讯参数为 9600bps 8n1,那么一个字节的时间大约为 1ms,假设连续几个毫秒都没有收到新的数据,那么就认为这一帧数据结束了。
因此在使用定时器的时候可以每收到一个字节的数据将定时器清0,然后如果定时器的超时时间到了就认为该数据帧结束了。 |
|
|
|
怎么把定时器清零呢?rtt提供的只有write开始,control啥的。然后我不是一个字节一个字节算的,因为DMA接收会把数据断开,用定时器是为了把DMA接收断开的帧,再拼上。 我是在while里接收一部分数据,比如A0个字节,write定时器,这样有一个超时时间,设为100ms,如果超时了,说明100ms内,没有进while函数,说明一帧接收完成。 超时函数的回调函数给一个标志位,然后读取数据,stop定时器。 如果还没超时,又收到数据,那就再write,不知道可不可以在没stop的情况下write定时器,stop定时器,应该可以把定时器清空了吧。 现在单步调试的时候,每一帧都能分开,全速跑起来,就分不开了。 每两条数据的时间间隔好几s,绝对比100ms大。 代码如下: void read_uart(void *parameter) { rt_uint32_t recv_cnt = 0, old_recv_cnt = 0; rt_uint8_t recv_buff[4096] = {0}; rt_uint8_t *tmp_ptr= recv_buff; rt_uint16_t cnt = 0;//统计一次接收读取几次,可以知道一帧数据被dma分成几次 rt_hwtimerval_t timeout_s; /* 定时器超时值 */ timeout_s.sec = 0; /* 秒 */ timeout_s.usec = 100000; /* 微秒 250ms */ hwtimer_sample(); while(1) { if (rt_sem_take(&env_rx,500) != RT_EOK) { continue; } //循环从串口读数据,放到tmpptr里,然后tmpptr每次增加接收的字符数,避免覆盖 while (recv_cnt = rt_device_read(dev, -1, tmp_ptr, 4096) ) { rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) ; cnt += recv_cnt; tmp_ptr += recv_cnt; old_recv_cnt = recv_cnt; // rt_kprintf("第 %d 次",cnt); } //得到一帧数据,stop定时器,处理数据 if (timeout == 1 && old_recv_cnt != 0 && recv_cnt == 0) { timeout = 0; old_recv_cnt = 0; tmp_ptr = recv_buff; rt_device_control(hw_dev, HWTIMER_CTRL_STOP, RT_NULL); dump_hex(recv_buff, cnt); cnt = 0; } rt_thread_delay(50); } } /* 定时器超时回调函数 */ static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size) { // rt_kprintf("this is hwtimer timeout callback fucntion!n"); rt_kprintf("tick is :%d !n", rt_tick_get()); timeout = 1; return 0; } 07AA是结束符,没有区分开 |
|
|
|
直接使用 DMA + 空闲中断 也可以作为数据帧结束的判断,还能省去定时器
|
|
|
|
我还没用过硬件定时器,用的都是软件定时器,你看看 HWTIMER_CTRL_STOP 停止定时器会把定时器清 0 吗?
|
|
|
|
看了一下源码,下面这个函数可以清 0 定时器
static void timer_stop(rt_hwtimer_t *timer) { TIM_HandleTypeDef *tim = RT_NULL; RT_ASSERT(timer != RT_NULL); tim = (TIM_HandleTypeDef *)timer->parent.user_data; /* stop timer */ HAL_TIM_Base_Stop_IT(tim); /* set tim cnt */ __HAL_TIM_SET_COUNTER(tim, 0); } static const struct rt_hwtimer_ops _ops = { .init = timer_init, .start = timer_start, .stop = timer_stop, .count_get = timer_counter_get, .control = timer_ctrl, }; |
|
|
|
没有,开启dma接收模式,就是dma半满 全满 ,串口空闲中断了,这时候接收的数据会混在一起,分不清帧。
|
|
|
|
你看看上面的 timer_stop() 函数,我看里面实现了定时器清 0 的功能。
|
|
|
|
这个调用control可能调用了。你看我的思路有问题吗?
|
|
|
|
调用下面这个代码 rt_device_control(hw_dev, HWTIMER_CTRL_STOP, RT_NULL); 应该是不能停止定时器的,我看这部分的源代码如下所示,这里面只实现了 HWTIMER_CTRL_FREQ_SET 这个指令。
static rt_err_t timer_ctrl(rt_hwtimer_t *timer, rt_uint32_t cmd, void *arg) { TIM_HandleTypeDef *tim = RT_NULL; rt_err_t result = RT_EOK; RT_ASSERT(timer != RT_NULL); RT_ASSERT(arg != RT_NULL); tim = (TIM_HandleTypeDef *)timer->parent.user_data; switch (cmd) { case HWTIMER_CTRL_FREQ_SET: { rt_uint32_t freq; rt_uint16_t val; /* set timer frequence */ freq = *((rt_uint32_t *)arg); #if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) if (tim->Instance == TIM9 || tim->Instance == TIM10 || tim->Instance == TIM11) #elif defined(SOC_SERIES_STM32L4) if (tim->Instance == TIM15 || tim->Instance == TIM16 || tim->Instance == TIM17) #elif defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32G0) if (0) #endif { #if defined(SOC_SERIES_STM32L4) val = HAL_RCC_GetPCLK2Freq() / freq; #elif defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) val = HAL_RCC_GetPCLK2Freq() * 2 / freq; #endif } else { #if defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) val = HAL_RCC_GetPCLK1Freq() * 2 / freq; #elif defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32G0) val = HAL_RCC_GetPCLK1Freq() / freq; #endif } __HAL_TIM_SET_PRESCALER(tim, val - 1); /* Update frequency value */ tim->Instance->EGR |= TIM_EVENTSOURCE_UPDATE; } break; default: { result = -RT_ENOSYS; } break; } return result; } |
|
|
|
我认为 timer_ctrl 这个函数实现的不全,如果想通过 timer_ctrl 实现停止的话还需要自己把停止的代码加到这个函数里面。
|
|
|
|
我把定时器改成oneshot模式了,感觉可能是跟程序流程有关,假如数据被dma接收分成了两段,第一段接收到信号量,执行while循环,再执行下面的判断超时语句,然后接收第二段数据,同样可以接收到信号量。然后没有新的数据,定时器会超时,此时判断超时的函数在获取信号量的后面,而两段数据已经传完,不会再获得信号量了,这样后面的代码就因为县城被挂起执行不到了。直到下一针数据来到,获得信号量,才会执行到判断超时函数的语句,而此时,就会上一针数据的第二段,和这一帧数据的第一段连起来
你看我分析的有没有道理。 谢谢 |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
971 浏览 0 评论
AI模型部署边缘设备的奇妙之旅:如何在边缘端部署OpenCV
3205 浏览 0 评论
tms320280021 adc采样波形,为什么adc采样频率上来波形就不好了?
1434 浏览 0 评论
2085 浏览 0 评论
1604 浏览 0 评论
75238 浏览 21 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-27 13:10 , Processed in 0.884248 second(s), Total 91, Slave 73 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号