本文介绍如何用STM32F107VC(Waveshare Open107V实验板)实现高精度的频率计。
开发环境:
IDE:STM32CubeIDE 1.8
固件库:STM32Cube_FW_F1_V1.8.4
操作系统:FREERTOS CMSIS_V1
函数发生:RIGOL DG5072函数信号发生器,产生0-3.3V的方波
硬件:Waveshare Open107V,STM32F107VC, 晶振25MHz,工作频率72MHz
思路:
1.用TIM3做外部脉冲输入,模式为:Slave Mode- External Clock Mode 1, Trigger Source:TI2FP2,上升沿触发,下拉。不产生中断
2.用TIM7做定时器,1ms产生一次中断,优先级为0(不使用rtos的函数,如果使用的话,最高优先级只能是5)
3.声明一个16bit的全局数组FrBuf,长度为1200(需要大于1000,等于的话结果波动很大,大多少没有测试),每次TIM7中断时,将TIM3计数存入FrBuf,位置用位置计数器bufEndFr标识。
4.利用FREERTOS的Timer,设定超时为1秒,每次超时从bufEndFr开始,完后计算1001个单元之间的差值,将差值累加则得到最近一秒的频率,发送至串口。
测试结果:
无输入:0
1Hz:1
2Hz:2
10Hz:10
30K:29999
50K:49998-99
80K:79997-98
90K:89997
100K:99996-97
500k:49983-84
900k:89969-70
1M:999966-67
10M:9999665-66
20M:19999330-31
30M:29998995-96
34M: 33998861-62
34.5M:34498797-34498828
35M:3490xxxx-3494xxxx
结论:
1.34MHz以下,测量绝对误差不超过0.0034%
2.最高频率为34MHz
3.低于1Hz也可以测量,需要进一步改进算法
4.不采用FREERTOS也很容易实现,结果一致。
关键代码:
//TIM7 定时器的中断响应
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 0 */
/*先读TIM3再判断是否是TIM7中断与先判断再读TIM3结果一样,因此先判断后读更节省资源*/
//uint16_t n = LL_TIM_GetCounter(TIM3);先读TIM3再判断是否是TIM7中断
if (htim->Instance == TIM7)
{
FrBuf[bufEndFr] = LL_TIM_GetCounter(TIM3);//n;//
if(bufEndFr >= C_BUF_TOP) bufEndFr = 0;
else bufEndFr++;
}
/* USER CODE END Callback 0 */
if (htim->Instance == TIM6) {
HAL_IncTick();
}
/* USER CODE BEGIN Callback 1 */
/* USER CODE END Callback 1 */
}/*FREERTOS中的定时响应函数,1秒钟一次
osTimerStart(myTimer01Handle, 1000);//in void MX_FREERTOS_Init(void)
*/
/* CallBack_Timer01 function */
void CallBack_Timer01(void const * argument)
{
/* USER CODE BEGIN CallBack_Timer01 */
uint16_t i, n, n1, count;
uint32_t sum = 0;
n = Decrement(bufEndFr, C_BUF_TOP);
for(i = 0; i < COUNT_1S; i++)
{
n1 = Decrement(n, C_BUF_TOP);
count = (FrBuf[n] >= FrBuf[n1]) ? (FrBuf[n] - FrBuf[n1]) : (0xFFFF - FrBuf[n1] + FrBuf[n] + 1 );
sum = sum + count;
n = n1;
}
nFrequency = sum;
BSP_LED1_Toggle();//for test
printf("Fr: %8ld\n", sum);//Send via USART1 to computer
/* USER CODE END CallBack_Timer01 */
}
uint16_t Decrement(uint16_t num, uint16_t top)
{
if( num == 0 )
{
return top;
}
return (--num);
}具体代码见: