cancel
Showing results for 
Search instead for 
Did you mean: 

How to use STM32F100 to measure a sinwave's frequency by input cature mode of TIM3 ?

cTomm
Associate II

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/2400​0000 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

 0690X000006Do35QAC.png

count value=427+425 =852 >> 610

f=1/T=1/(852*0.042us)=27.9Khz it is wrong.

2:at intput 40KHz sinewave

0690X000006Do3AQAS.bmp

count value =411+410=821>> 595

f=1/T=1/(821*0.042us)=29Khz it is wrong.

3:at intput 41K sinewave

0690X000006Do3FQAS.png

​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);

}

3 REPLIES 3
S.Ma
Principal

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...

Don't do this:

> TIM_SetCounter(TIM3,0);

rather, store the previous capture value and subtract the current from previous.

JW

Agreed, use differential approach without disturbing the timer. This way, other channels can also be used when needed in the future.