完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
大家好,最近学了原子哥的输入捕获实验,然后自己用FreeRTOS + HAL库做了一遍,有一些疑问请教一下。
一、原子哥的案例简介。 我看的是原子哥HAL库的案例,大体思路是一个定时器输出PWM,每10ms改一次占空比,然后另一个定时器捕获高电平,每10ms输出一次结果。 主要的代码及输出效果图如下: [C] 纯文本查看 复制代码 while(1) { delay_ms(10); tiM_SetTIM1Compare1(TIM_GetTIM1Capture1()+1); if(TIM_GetTIM1Capture1()==499)TIM_SetTIM1Compare1(0); if(TIM5CH1_CAPTURE_STA&0X80) //成功捕获到了一次高电平 { temp=TIM5CH1_CAPTURE_STA&0X3F; temp*=65536; //溢出时间总和 temp+=TIM5CH1_CAPTURE_VAL; //得到总的高电平时间 printf("HIGH:%lld usrn",temp);//打印总的高点平时间 TIM5CH1_CAPTURE_STA=0; //开启下一次捕获 } } 二、我自己的代码A 我仿照原子哥的思路,自己做了下代码。 代码编辑方式是:用FreeRTOS的任务通知模拟事件标志组,在定时器5的更新中断和捕获中断里分别发送任务通知到TIM_IC_Task函数,在这个函数里处理相应的操作。然后在另外一个函数High_Out_Task里每10ms改变一个PWM的占空比,然后输出对应的捕获结果。 但是这种代码的写法输出有点问题,输出的结果比价乱,如下图: 方案A的主要代码如下: [C] 纯文本查看 复制代码 /*********************************************************************************函数名称:TIM_IC_Task*函数句柄:TIM_IC_Task_Handle*输入参数:无*返回值 :无*函数功能:输入捕获实验函数,并使用任务通知的事件标志组。*备注 :此实验输入捕获功能,是实现高电平的捕获。*日期 :2017/12/10********************************************************************************/void TIM_IC_Task(void const * argument){ //static uint32_t temp = 0; static uint32_t NotifyValue = 0; BaseType_t Info = 0; while(1) { Info = xTaskNotifyWait( (uint32_t ) 0x00,//进入函数的时候不清除任务bit (uint32_t ) 0xffffffff,//退出函数的时候清除所有的bit (uint32_t * ) &NotifyValue,//保存任务通知值 (TickType_t ) portMAX_DELAY );//阻塞时间 if(Info == pdPASS )//如果任务通知获取成功 { //printf("111rn"); if((NotifyValue & Event_1) != 0 )//如果Event_1(捕获中断)的事件发生了 { //能运行到此,说明已经触发了输入捕获中断 if((TIM5CH2_CAPTURE_STA&0X80)==0)//如果还未成功捕获 { if(TIM5CH2_CAPTURE_STA&0X40)//如果之前已经标记了上升沿被捕获,说明此次捕获的是低电平 { TIM5CH2_CAPTURE_STA |= 0X80; //标记成功捕获到一次高电平脉宽 TIM5CH2_CAPTURE_VAL = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_2);//获取当前的捕获值. TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_2); //一定要先清除原来的设置!! TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_2,TIM_ICPOLARITY_RISING);//配置TIM5通道2上升沿捕获 } else//还未开始捕获,这次是第一次捕获,捕获的是上升沿 { TIM5CH2_CAPTURE_STA = 0; //清空模拟状态寄存器 TIM5CH2_CAPTURE_VAL = 0; //清空数据缓存变量 TIM5CH2_CAPTURE_STA |= 0X40; //标记捕获到了上升沿 __HAL_TIM_DISABLE(&htim5); //关闭定时器5 __HAL_TIM_SET_COUNTER(&htim5,0); //往定时器5的计数器里写0 TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_2); //一定要先清除原来的设置!! TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_2,TIM_ICPOLARITY_FALLING);//定时器5通道2设置为下降沿捕获 __HAL_TIM_ENABLE(&htim5); //使能定时器5 } } } else if ((NotifyValue & Event_2) != 0)//如果Event_2(更新中断)的事件发生了 { //能运行到此,说明已经触发了定时器5的更新(溢出)中断 if((TIM5CH2_CAPTURE_STA & 0X80) == 0) //还未成功捕获 { if(TIM5CH2_CAPTURE_STA & 0X40) //已经捕获到高电平了 { if((TIM5CH2_CAPTURE_STA & 0X3F) == 0X3F) //高电平太长了 { TIM5CH2_CAPTURE_STA |= 0X80; //标记成功捕获了一次 TIM5CH2_CAPTURE_VAL = 0XFFFF; } else TIM5CH2_CAPTURE_STA ++;//正常记录溢出中断的次数 } } }// if(TIM5CH2_CAPTURE_STA & 0X80)//如果已经标记成功捕获到了一次高电平(完成捕获)// {// temp = TIM5CH2_CAPTURE_STA & 0X3F; // temp *= 50000; //溢出时间总和(这里需要看定时器的重装载值是多少)// temp += TIM5CH2_CAPTURE_VAL; //得到总的高电平时间// //temp /= 1000;// printf("检测到高电平脉冲:%d us.rn",temp);//打印总的高点平时间// TIM5CH2_CAPTURE_STA=0; //开启下一次捕获// } } // vTaskDelay(10);// TIM_SetTIM3Compare1(TIM_GetTIM3Capture1()+1); // if(TIM_GetTIM3Capture1()==499)TIM_SetTIM3Compare1(0); }}/*********************************************************************************函数名称:High_Out_Task*函数句柄:High_Out_Task_Handle*输入参数:无*返回值 :无*函数功能:为输入捕获实验提供变化的高电平变化(GPIO翻转)*备注 :*日期 :2017/12/10********************************************************************************/void High_Out_Task(void const * argument){ //uint32_t C_time = 1; static uint32_t temp = 0; while(1) {// //HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_12);// PBout(12) = ~PBout(12);// C_time += 1;// if(C_time >= 500) C_time = 1;// delay_ms(C_time); vTaskDelay(10); TIM_SetTIM3Compare1(TIM_GetTIM3Capture1()+1); if(TIM_GetTIM3Capture1()==499)TIM_SetTIM3Compare1(0); if(TIM5CH2_CAPTURE_STA & 0X80)//如果已经标记成功捕获到了一次高电平(完成捕获) { temp = TIM5CH2_CAPTURE_STA & 0X3F; temp *= 50000; //溢出时间总和(这里需要看定时器的重装载值是多少) temp += TIM5CH2_CAPTURE_VAL; //得到总的高电平时间 //temp /= 1000; printf("检测到高电平脉冲:%d us.rn",temp);//打印总的高点平时间 TIM5CH2_CAPTURE_STA=0; //开启下一次捕获 } }} 三、我自己的代码B 方案B的思路是把方案A里的两个中断处理部分的函数分开,用两个二值信号量函数来处理。其余部分都一样。 结果是输出的结果比A好了一点,但是输出结果仍然有点乱。如下图: 方案B的主要代码如下: [C] 纯文本查看 复制代码 /*********************************************************************************函数名称:IC_Task*函数句柄:IC_Task_Handle*输入参数:无*返回值 :无*函数功能:输入捕获实验中,处理数据寄存器溢出(更新)的中断回调函数发送任务通知,此函数接受任务通知,并处理。*备注 :此实验输入捕获功能,是实现高电平的捕获,并计时。*日期 :2017/12/10********************************************************************************/void IC_Task(void const * argument){ while(1) { ulTaskNotifyTake(pdTRUE,portMAX_DELAY);//等待任务通知 //能运行到此,说明已经触发了定时器5的更新(溢出)中断 if((TIM5CH2_CAPTURE_STA & 0X80) == 0) //还未成功捕获 { if(TIM5CH2_CAPTURE_STA & 0X40) //已经捕获到高电平了 { if((TIM5CH2_CAPTURE_STA & 0X3F) == 0X3F) //高电平太长了 { TIM5CH2_CAPTURE_STA |= 0X80; //标记成功捕获了一次 TIM5CH2_CAPTURE_VAL = 0XFFFF; //xTaskNotifyGive(Handle_IC_Val_Task_Handle); } else TIM5CH2_CAPTURE_STA ++;//正常记录溢出中断的次数 } } }}/*********************************************************************************函数名称:IC_Task2*函数句柄:IC_Task2_Handle*输入参数:无*返回值 :无*函数功能:输入捕获实验中,触发捕获中断时,中断函数发送任务通知,此函数接受任务通知,并处理。*备注 :此实验输入捕获功能,是实现高电平的捕获,并计时。*日期 :2017/12/10********************************************************************************/void IC_Task2(void const * argument){ while(1) { ulTaskNotifyTake(pdTRUE,portMAX_DELAY);//等待任务通知 //能运行到此,说明已经触发了输入捕获中断 if((TIM5CH2_CAPTURE_STA&0X80)==0)//如果还未成功捕获 { if(TIM5CH2_CAPTURE_STA&0X40)//如果之前已经标记了上升沿被捕获,说明此次捕获的是低电平 { TIM5CH2_CAPTURE_STA |= 0X80; //标记成功捕获到一次高电平脉宽 TIM5CH2_CAPTURE_VAL = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_2);//获取当前的捕获值. TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_2); //一定要先清除原来的设置!! TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_2,TIM_ICPOLARITY_RISING);//配置TIM5通道2上升沿捕获 //xTaskNotifyGive(Handle_IC_Val_Task_Handle); } else//还未开始捕获,这次是第一次捕获,捕获的是上升沿 { TIM5CH2_CAPTURE_STA = 0; //清空模拟状态寄存器 TIM5CH2_CAPTURE_VAL = 0; //清空数据缓存变量 TIM5CH2_CAPTURE_STA |= 0X40; //标记捕获到了上升沿 __HAL_TIM_DISABLE(&htim5); //关闭定时器5 __HAL_TIM_SET_COUNTER(&htim5,0); //往定时器5的计数器里写0 TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_2); //一定要先清除原来的设置!! TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_2,TIM_ICPOLARITY_FALLING);//定时器5通道2设置为下降沿捕获 __HAL_TIM_ENABLE(&htim5); //使能定时器5 } } }}/*********************************************************************************函数名称:High_Out_Task*函数句柄:High_Out_Task_Handle*输入参数:无*返回值 :无*函数功能:为输入捕获实验提供变化的高电平变化(GPIO翻转)*备注 :*日期 :2017/12/10********************************************************************************/void High_Out_Task(void const * argument){// uint32_t C_time = 1;// while(1)// {// //HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_12);// PBout(12) = ~PBout(12);// C_time += 1;// if(C_time >= 300) C_time = 1;// delay_ms(C_time);// } static uint32_t temp = 0; while(1) { delay_ms(10); TIM_SetTIM3Compare1(TIM_GetTIM3Capture1()+1); if(TIM_GetTIM3Capture1()==499)TIM_SetTIM3Compare1(0); if(TIM5CH2_CAPTURE_STA & 0X80) //成功捕获到了一次高电平 { temp = TIM5CH2_CAPTURE_STA & 0X3F; temp *= 65535; //溢出时间总和(这里需要看定时器的重装载值是多少) temp += TIM5CH2_CAPTURE_VAL; //得到总的高电平时间 //temp /= 1000; printf("检测到高电平脉冲:%d us.rn",temp);//打印总的高点平时间 TIM5CH2_CAPTURE_STA=0; //开启下一次捕获 } }} 四、我自己的代码C 最后我把更新中断和捕获中断的处理内容直接写到了回调函数里,FreeRTOS的任务只有一个改变占空比和输出结果的函数。 这一次的输出效果和原子哥的一样了。 如下图: 代码C的主要内容如下: [C] 纯文本查看 复制代码 void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){ //BaseType_t TIM5_pxHigher_2; if(htim == &htim5) {// /* 任务通知模拟事件标志组 */// /* 发送任务通知函数 */// xTaskNotifyFromISR( (TaskHandle_t ) TIM_IC_Task_Handle, //任务通知句柄// (uint32_t ) Event_1 , //任务通知值// (eNotifyAction ) eSetBits, //任务通知更新方法,此处是更新指定的bit// (BaseType_t * ) &TIM5_pxHigher_2); //标记退出函数后是否进行任务切换// // portYIELD_FROM_ISR(TIM5_pxHigher_2);//判断是否需要切换任务 //能运行到此,说明已经触发了输入捕获中断 if((TIM5CH2_CAPTURE_STA&0X80)==0)//如果还未成功捕获 { if(TIM5CH2_CAPTURE_STA&0X40)//如果之前已经标记了上升沿被捕获,说明此次捕获的是低电平 { TIM5CH2_CAPTURE_STA |= 0X80; //标记成功捕获到一次高电平脉宽 TIM5CH2_CAPTURE_VAL = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_2);//获取当前的捕获值. TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_2); //一定要先清除原来的设置!! TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_2,TIM_ICPOLARITY_RISING);//配置TIM5通道2上升沿捕获 } else//还未开始捕获,这次是第一次捕获,捕获的是上升沿 { TIM5CH2_CAPTURE_STA = 0; //清空模拟状态寄存器 TIM5CH2_CAPTURE_VAL = 0; //清空数据缓存变量 TIM5CH2_CAPTURE_STA |= 0X40; //标记捕获到了上升沿 __HAL_TIM_DISABLE(&htim5); //关闭定时器5 __HAL_TIM_SET_COUNTER(&htim5,0); //往定时器5的计数器里写0 TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_2); //一定要先清除原来的设置!! TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_2,TIM_ICPOLARITY_FALLING);//定时器5通道2设置为下降沿捕获 __HAL_TIM_ENABLE(&htim5); //使能定时器5 } } }}/* USER CODE END 4 *//** * @brief Period elapsed callback in non blocking mode * @note This function is called when TIM6 interrupt took place, inside * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment * a global variable "uwTick" used as application time base. * @param htim : TIM handle * @retval None */void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){/* USER CODE BEGIN Callback 0 */ //BaseType_t TIM5_pxHigher_1;/* USER CODE END Callback 0 */ if (htim->Instance == TIM6) { HAL_IncTick(); }/* USER CODE BEGIN Callback 1 *//********************************************* 定时器回调函数 *******************************************/ if(htim == &htim7) { RunTimeCounterValue++; } if(htim == &htim5) {// /* 任务通知模拟事件标志组 */// /* 发送任务通知函数 */// xTaskNotifyFromISR( (TaskHandle_t ) TIM_IC_Task_Handle, //任务通知句柄// (uint32_t ) Event_2 , //任务通知值// (eNotifyAction ) eSetBits, //任务通知更新方法,此处是更新指定的bit// (BaseType_t * ) &TIM5_pxHigher_1); //标记退出函数后是否进行任务切换// // portYIELD_FROM_ISR(TIM5_pxHigher_1);//判断是否需要切换任务 //能运行到此,说明已经触发了定时器5的更新(溢出)中断 if((TIM5CH2_CAPTURE_STA & 0X80) == 0) //还未成功捕获 { if(TIM5CH2_CAPTURE_STA & 0X40) //已经捕获到高电平了 { if((TIM5CH2_CAPTURE_STA & 0X3F) == 0X3F) //高电平太长了 { TIM5CH2_CAPTURE_STA |= 0X80; //标记成功捕获了一次 TIM5CH2_CAPTURE_VAL = 0XFFFF; } else TIM5CH2_CAPTURE_STA ++;//正常记录溢出中断的次数 } } } /* USER CODE END Callback 1 */} [C] 纯文本查看 复制代码 /*********************************************************************************函数名称:High_Out_Task*函数句柄:High_Out_Task_Handle*输入参数:无*返回值 :无*函数功能:为输入捕获实验提供变化的高电平变化(GPIO翻转)*备注 :*日期 :2017/12/10********************************************************************************/void High_Out_Task(void const * argument){ //uint32_t C_time = 1; static uint32_t temp = 0; while(1) {// //HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_12);// PBout(12) = ~PBout(12);// C_time += 1;// if(C_time >= 500) C_time = 1;// delay_ms(C_time); vTaskDelay(10); TIM_SetTIM3Compare1(TIM_GetTIM3Capture1()+1); if(TIM_GetTIM3Capture1()==499)TIM_SetTIM3Compare1(0); if(TIM5CH2_CAPTURE_STA & 0X80)//如果已经标记成功捕获到了一次高电平(完成捕获) { temp = TIM5CH2_CAPTURE_STA & 0X3F; temp *= 50000; //溢出时间总和(这里需要看定时器的重装载值是多少) temp += TIM5CH2_CAPTURE_VAL; //得到总的高电平时间 //temp /= 1000; printf("检测到高电平脉冲:%d us.rn",temp);//打印总的高点平时间 TIM5CH2_CAPTURE_STA=0; //开启下一次捕获 } }} 五、我的疑问 问题1:我自己的代码A/B输出有问题,是因为我的代码组织思路有问题吗?还是说我的FreeRTOS的任务通知功能使用的思路有问题? 问题2:除了代码C把任务处理内容直接放在中断回调函数里的方法,还有其他什么方法能实现原子哥正常输出的结果吗? 希望有知道的前辈指点一下。谢谢。 |
|
相关推荐
2个回答
|
|
没人回复啊
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
883 浏览 1 评论
2278 浏览 5 评论
2590 浏览 9 评论
移植了freeRTOS到STMf103之后显示没有定义的原因?
2397 浏览 6 评论
2300 浏览 7 评论
使用eim外接fpga可是端口一点反应都没有有没有大哥指点一下啊
448浏览 9评论
459浏览 7评论
请教大神怎样去解决iMX6Q在linux3.0.35内核上做AP失败的问题呢
563浏览 6评论
441浏览 5评论
473浏览 5评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-8-17 22:59 , Processed in 1.243095 second(s), Total 81, Slave 62 queries .
Powered by 电子发烧友网
© 2015 www.ws-dc.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号