完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
原理说明
捕获信号的频率其实有很多中实现方式,外部中断、输入捕获、使用外部时钟计数器等。对STM32有一定了解的朋友们在测量频率的问题上往往都会想到利用输入捕获,输入捕获的方式在中低频率段(1HZ-200KHZ)的测量还是比较准确的。在高频段还是建议采用外部时钟计数器的方式来实现。 采用输入捕获实现频率测量的实现步骤如下: 设置输入捕获为上升沿检测 记录第一次t1发生上升沿时捕获比较寄存器(CCR)的值cap_val1 记录第二次t2发生上升沿时捕获比较寄存器(CCR)的值cap_val2 根据不同溢出情况计算前后两次捕获值之和,同时根据TIM的计数频率,我们就可以算出捕获脉冲的频率。 代码实现 代码实现的部分主要是在输入捕获中断中对捕获的不同溢出情况进行了处理,实测效果还是不错的,4通道同时测的误差也就在1%左右。 宏定义&变量定义部分: /* IC capture edge define*/ #define IC_RISE_EDGE_1 0 #define IC_RISE_EDGE_2 1 /* Capture TIMER Prescaler and Period define */ #define TIM1_PRESCALER 168-1 #define TIM1_PERIOD 0xFFFF /* IC capture Parameters define*/ #define TIM1_IC_FREQ 168000000/TIM1_PRESCALER #define TIM_ICOF_MAX 0x32 static float g_TIM1IcFreq = TIM1_IC_FREQ; static float g_TIM1Period = TIM1_PERIOD; static float g_FbFreqBuff[SPD_FB_CHAN_NUM] = {0.0}; /* 频率反馈值*/ static float g_DevFbRotateSpdBuff[SPD_FB_CHAN_NUM] = {0.0}; /* 转速反馈值*/ uint16_t g_IcofCntBuff[TIM_IC_MAX] = {0}; /* 定时器溢出计数值*/ /* 定时器捕获通道枚举定义*/ typedef enum { TIM1_IC1 = 0, TIM1_IC2 , TIM1_IC3 , TIM1_IC4 , TIM_IC_MAX , } TIM_IC_Typedef; 定时器初始化部分: void MX_TIM1_Init(void) { TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_IC_InitTypeDef sConfigIC = {0}; TIMER1_Handler.Instance = TIM1; TIMER1_Handler.Init.Prescaler = TIM1_PRESCALER; //168M/168 = 1M计数频率,1us计数一次; TIMER1_Handler.Init.CounterMode = TIM_COUNTERMODE_UP; TIMER1_Handler.Init.Period = TIM1_PERIOD; //溢出时间,65.5ms TIMER1_Handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; TIMER1_Handler.Init.RepetitionCounter = 0; TIMER1_Handler.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_IC_Init(&TIMER1_Handler) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&TIMER1_Handler, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; sConfigIC.ICFilter = 0; if (HAL_TIM_IC_ConfigChannel(&TIMER1_Handler, &sConfigIC, TIM_CHANNEL_1) != HAL_OK) { Error_Handler(); } if (HAL_TIM_IC_ConfigChannel(&TIMER1_Handler, &sConfigIC, TIM_CHANNEL_2) != HAL_OK) { Error_Handler(); } if (HAL_TIM_IC_ConfigChannel(&TIMER1_Handler, &sConfigIC, TIM_CHANNEL_3) != HAL_OK) { Error_Handler(); } if (HAL_TIM_IC_ConfigChannel(&TIMER1_Handler, &sConfigIC, TIM_CHANNEL_4) != HAL_OK) { Error_Handler(); } /*## Start the Input Capture in interrupt mode ##########################*/ HAL_TIM_IC_Start_IT(&TIMER1_Handler,TIM_CHANNEL_1); HAL_TIM_IC_Start_IT(&TIMER1_Handler,TIM_CHANNEL_2); HAL_TIM_IC_Start_IT(&TIMER1_Handler,TIM_CHANNEL_3); HAL_TIM_IC_Start_IT(&TIMER1_Handler,TIM_CHANNEL_4); __HAL_TIM_ENABLE_IT(&TIMER1_Handler,TIM_IT_UPDATE);//更新中断用于溢出计数 } 输入捕获回调函数: void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if(htim-》Instance == TIM1) { if(htim-》Channel==HAL_TIM_ACTIVE_CHANNEL_1) { TIM1CaptureChannel1Callback(); } else if(htim-》Channel==HAL_TIM_ACTIVE_CHANNEL_2) { TIM1CaptureChannel2Callback(); } else if(htim-》Channel==HAL_TIM_ACTIVE_CHANNEL_3) { TIM1CaptureChannel3Callback(); } else { TIM1CaptureChannel4Callback(); } } } 通道1的捕获处理代码: /************************************************************************************************** * @brief :Set PMP01 Control Speed Percent,voltage Control. * @param :none. * @retval :none. * @note :0xFFFF is the Timer1 Period value set in the MX_TIM1_Init()。 * Input capture frequency range:1HZ~100KHZ(best) **/ void TIM1CaptureChannel1Callback(void) { static uint8_t ic_edge = IC_RISE_EDGE_1; static uint32_t cap_val1 = 0; static uint32_t cap_val2 = 0; static uint32_t cap_sum = 0; if(ic_edge == IC_RISE_EDGE_1){ ResetTimerIcofCnt(TIM1_IC1); cap_val1=__HAL_TIM_GET_COMPARE(&TIMER1_Handler, TIM_CHANNEL_1); ic_edge = IC_RISE_EDGE_2; }else{ cap_val2=__HAL_TIM_GET_COMPARE(&TIMER1_Handler, TIM_CHANNEL_1); if(g_IcofCntBuff[TIM1_IC1] == 0){ cap_sum = cap_val2 - cap_val1; }else if(g_IcofCntBuff[TIM1_IC1] == 1){//溢出一个计数周期 cap_sum = (g_TIM1Period - cap_val1) + cap_val2; }else{//溢出N个计数周期 cap_sum = (g_TIM1Period - cap_val1) + g_TIM1Period *(g_IcofCntBuff[TIM1_IC1]-1) +cap_val2; } ProcessIcValue(TIM1_IC1,cap_sum); ic_edge = IC_RISE_EDGE_1; } } 其它三个通道都大同小异,就不全贴出来了。.. 定时器溢出计数函数: void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim-》Instance == TIM1) { TIM1_IcOverflowCntCallback(); } } /************************************************************************************************** * @brief :TIM1 Input capture overflow count callback function. * @param :none. * @retval :none. * @note :0xFF 为避免出现捕获到周期过长的异常输出(只捕获到一个上升沿、输入波形中断等) **/ void TIM1_IcOverflowCntCallback(void) { for(uint8_t i=0;i《4;i++){ if(g_IcofCntBuff[i] 《 TIM_ICOF_MAX){ g_IcofCntBuff[i]++; }else{ g_IcofCntBuff[i]=0; g_FbFreqBuff[i] = 0; } } } 频率&转速计算: /************************************************************************************************** * @brief :Process the Input capture value function. * @param :none. * @retval :none. * @note : **/ static void ProcessIcValue(TIM_IC_Typedef ic_id,uint32_t _icCnt) { g_FbFreqBuff[ic_id] = CalcTheFreq(_icCnt); g_DevFbRotateSpdBuff[ic_id] = CalcTheRpm(g_FbFreqBuff[ic_id]); } /************************************************************************************************** * @brief :Calc the frequency by the capture count. * @param :none. * @retval :none. * @note :频率计算公式:f=1/T,定时器的输入捕获的计数的频率为1MHZ,两次捕获上升沿的差值sum为计数器 CNT计的次数,所以总的周期即为T=1us*sum,所以频率就fq=1000000/sum HZ. 电机转速与频率的公式:n=60f/p, n--电机的转速(转/分); 60--每分钟(秒); f--电源频率(赫兹); p--电机旋转磁场的极对数(电机也分为分2极,4级,6极,8极等);这里按2极来算 **/ static float CalcTheFreq(uint32_t _icValue) { return g_TIM1IcFreq / _icValue; } static float CalcTheRpm(float _freq) { // return (60 * _freq / 2); return (30 * _freq); //由上式简化而来 } 最后再提一下在开篇提到的采用外部时钟计数器方式实现频率信号测量的实现思路,此方式测量高频段信号频率准确率不错,也会大大减少中断次数。 采用外部时钟计数器的方式实现思路: 思路是配置两个定时器,定时器a设置为外部时钟计数器模式,定时器b设置为定时器(比如50ms溢出一次,也可以用软件定时器),然后定时器b中断函数中统计定时器a在这段时间内的增量,简单计算即可。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1874 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1658 浏览 1 评论
1143 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
759 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1720 浏览 2 评论
1963浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
789浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
611浏览 3评论
628浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
590浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-11 11:45 , Processed in 0.653666 second(s), Total 45, Slave 39 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号