2019-02-23 12:53 AM
How to use STM32F100 to measure a sinwave's frequency by input cature mode of TIM3 ?
I would like to measure sinewaves of three frequency, 39Khz�?40Khz and 41Khz.
Voltage level (0V-3V)
The 39khz period is 25.64us.
The 40khz period is 25us.
The 41khz period is 24.39us.
I use timer to count.
TIM_CLK= 24M 1s =24000000 clk
counting times = 1s/24000000 clk = 0.042 us/clk , prescaler =1
The timer count once per 0.042 second.
Calculation count value: (I should get the following values )
39kHz: 25.64us/0.042us = 610
40kHz: 25us /0.042us = 595
41kHz: 24.39us/0.042us = 580
Experimentalphoto:
1: at intput 39kHz sinewave
count value=427+425 =852 >> 610
f=1/T=1/(852*0.042us)=27.9Khz it is wrong.
2:at intput 40KHz sinewave
count value =411+410=821>> 595
f=1/T=1/(821*0.042us)=29Khz it is wrong.
3:at intput 41K sinewave
count value =396+395=791>> 580
f=1/T=1/(791*0.042us)=30.1Khz it is wrong.
I study the datasheet and try it ,however I still can't get to correct frequency.
code:
void Rcc_init(void)
{
RCC_DeInit();
RCC_HSICmd(ENABLE);
RCC_PLLConfig(RCC_PLLSource_HSI_Div2,RCC_PLLMul_6);
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET){}
RCC_HCLKConfig(RCC_SYSCLK_Div1);//24M
RCC_PCLK1Config(RCC_HCLK_Div1); //24M
RCC_PCLK2Config(RCC_HCLK_Div1); //24M
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while(RCC_GetSYSCLKSource()!=0x08){}
}
void init(void)
{
Rcc_init();
TIM3_Cap_Init(0xFFFF,0);
}
int main(void)
{
init();
while(1)
{}
}
void TIM3_Cap_Init(uint16_t arr,uint16_t psc)
{
NVIC_InitTypeDef NVIC_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_ICInitTypeDef TIM_ICInitStruct;
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
//--------------------PIN----------------------------//
//PA7 TIM3_CH2 en.CD00246267 P.108
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStruct);
TIM_Cmd(TIM3,DISABLE);
TIM_DeInit(TIM3);
TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //tDTS = tCK_INT
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = arr;
TIM_TimeBaseInitStruct.TIM_Prescaler = psc;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;
TIM_ICInitStruct.TIM_ICFilter = 0; //IC1F
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_ClearFlag(TIM3,TIM_FLAG_Update);
TIM_ClearITPendingBit(TIM3,TIM_IT_Update | TIM_IT_CC2);
TIM_ITConfig(TIM3,TIM_IT_Update | TIM_IT_CC2,ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStruct);
TIM_Cmd(TIM3,ENABLE);
}
#define START 0x01
#define WAIT_RISING 0x02
#define WAIT_FALLING 0x03
uint32_t a[500]={0};
void TIM3_IRQHandler(void)
{
static uint32_t overflow=0;
static uint32_t state=START;
uint32_t Capture_value=0;
static uint16_t i=0;
if(i<500)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET)
{
overflow++;
}
else if (TIM_GetITStatus(TIM3,TIM_IT_CC2)!=RESET)
{
if(state ==START)
{
overflow=0;
TIM_SetCounter(TIM3,0);
state = WAIT_FALLING;
TIM_OC2PolarityConfig(TIM3,TIM_ICPolarity_Falling);
}
else if(state == WAIT_FALLING)
{
Capture_value = TIM_GetCapture2(TIM3);
//printf("1=%d\r\n",Capture_value);
a[i++]=Capture_value+overflow * 65536;
overflow = 0;
state = WAIT_RISING;
TIM_OC2PreloadConfig(TIM3,TIM_ICPolarity_Rising);
TIM_SetCounter(TIM3,0);
}
else // Wait Rising
{
Capture_value = TIM_GetCapture2(TIM3);
//printf("3=%d\r\n",Capture_value);
a[i++]=Capture_value+overflow * 65536;
overflow = 0;
state = WAIT_FALLING;
TIM_OC2PreloadConfig(TIM3,TIM_ICPolarity_Falling);
TIM_SetCounter(TIM3,0);
}
}
else{};
}
TIM_ClearITPendingBit(TIM3,TIM_IT_Update | TIM_IT_CC2);
}
2019-02-23 02:10 AM
Timer channels are digital with trigger voltage defined in datasheet.
If the input is not digital, jitter may occur in the triggering time.
One approach could be to prescale (average) the input in the timer (use channel 1 or 2 as they have more options around for this), so instead of measuring one period, you would measuer 8 periods for example.
I haven't used the internal analog comparator which maybe can convert analog to digital and feed the timer. Again, without hysteresis, there would be glitches if the signal is noisy...
2019-02-23 03:55 AM
Don't do this:
> TIM_SetCounter(TIM3,0);
rather, store the previous capture value and subtract the current from previous.
JW
2019-02-23 05:38 AM
Agreed, use differential approach without disturbing the timer. This way, other channels can also be used when needed in the future.