STM32 измерение частоты.
В одной из прошлых статей рассказывал про режим захвата у STM32 и приводил пример как с его помощью измерить период сигнала. Но таким способом не получится ТОЧНО измерить период высокочастотного сигнала.(дальше станет понятно какой сигнал считать высокочастотным)
Предположим, что частота исcледуемого сигнала 1MНz, а наш таймер работает с частотой 72MНz. Переведем значения частоты в период.
1MHz = 1/10^6 = 1 uS
72MHz = 1/72*10^6 = 0,0138 uS
Посчитаем сколько тактов сделает таймер за 1uS,
1/0,0138 = 72,46 такта
округлим до 73. Итого ошибка составляет 0,54 такта, что меньше 1 процента.
А теперь увеличим частоту исследуемого сигнала в 10 раз и произведем те же расчеты.
10MHz = 1/10^7 = 0.1 uS
72MHz = 1/72*10^6 = 0.0138 uS
Посчитаем сколько тактов сделает таймер за 1uS,
0,1/0,0138 = 7,246 такта
округлим до 8 тактов, теперь ошибка составляет почти 10%, то есть вместо 10МHz мы получим 11MHz.
Понятно, что такая точность ни куда не годится, а причина заключается в том, что мы измеряли длительность импульса, а для получения более точного результата надо измерять количество импульсов в секунду(то есть частоту) и потом вычислять период.
Количество импульсов в секунду можно получить двумя способами.
Первый способ в лоб, настраиваем один из выводов МК на внешнее прерывание(на который будет подаваться исследуемый сигнал) и запускаем таймер, который отсчитает одну секунду. При каждом попадании в прерывание увеличиваем значение переменной на единицу и через секунду мы получим частоту исследуемого сигнала.
Второй способ, реализуется с помощью вывода ETR(external trigger input). Тут все проще, достаточно правильно инициализировать этот вывод и он сам будет считать количество импульсов, по заданному фронту. Как его настроить опишу ниже.
Для начала надо настроить фильтр в регистре TIMx_SMCR, битовое поле ETF[3:0](N — количество событий)
В том же регистре установить значение предделителя
ETPS[1:0]: External trigger prescaler
Там же выбрать фронт срабатывания
ETP: External trigger polarity
И настроить пин в режим ETR
Включить таймер установив CEN = 1 в регистре CR1.
Так как регистр CNT 16-разрядный максимальная частота, которую мы можем измерить 65536 Hz. Я подал с генератора сигналов 50 КНz и запустил код, представленный ниже, на чипе STM32F103VE.
Результат порадовал, скрин можно увеличить кликнув по нему.
А как же все таки измерить 10 MHz ?
Для этого надо использовать два таймера, один будет считать импульсы на выводе ETR, а второй считать сколько раз первый переполнился.
Предположим, что частота исcледуемого сигнала 1MНz, а наш таймер работает с частотой 72MНz. Переведем значения частоты в период.
1MHz = 1/10^6 = 1 uS
72MHz = 1/72*10^6 = 0,0138 uS
Посчитаем сколько тактов сделает таймер за 1uS,
1/0,0138 = 72,46 такта
округлим до 73. Итого ошибка составляет 0,54 такта, что меньше 1 процента.
А теперь увеличим частоту исследуемого сигнала в 10 раз и произведем те же расчеты.
10MHz = 1/10^7 = 0.1 uS
72MHz = 1/72*10^6 = 0.0138 uS
Посчитаем сколько тактов сделает таймер за 1uS,
0,1/0,0138 = 7,246 такта
округлим до 8 тактов, теперь ошибка составляет почти 10%, то есть вместо 10МHz мы получим 11MHz.
Понятно, что такая точность ни куда не годится, а причина заключается в том, что мы измеряли длительность импульса, а для получения более точного результата надо измерять количество импульсов в секунду(то есть частоту) и потом вычислять период.
Количество импульсов в секунду можно получить двумя способами.
Первый способ в лоб, настраиваем один из выводов МК на внешнее прерывание(на который будет подаваться исследуемый сигнал) и запускаем таймер, который отсчитает одну секунду. При каждом попадании в прерывание увеличиваем значение переменной на единицу и через секунду мы получим частоту исследуемого сигнала.
Второй способ, реализуется с помощью вывода ETR(external trigger input). Тут все проще, достаточно правильно инициализировать этот вывод и он сам будет считать количество импульсов, по заданному фронту. Как его настроить опишу ниже.
Для начала надо настроить фильтр в регистре TIMx_SMCR, битовое поле ETF[3:0](N — количество событий)
В том же регистре установить значение предделителя
ETPS[1:0]: External trigger prescaler
- 00 — выключен
- 01 — на 2
- 10 — на 4
- 11 — на 8
Там же выбрать фронт срабатывания
ETP: External trigger polarity
- 0 — возрастающий
- 1 — убывающий
И настроить пин в режим ETR
- ECE = 1
Включить таймер установив CEN = 1 в регистре CR1.
Так как регистр CNT 16-разрядный максимальная частота, которую мы можем измерить 65536 Hz. Я подал с генератора сигналов 50 КНz и запустил код, представленный ниже, на чипе STM32F103VE.
#include "stm32f10x.h"
volatile uint16_t tic = 0;
void TIM6_IRQHandler(void)
{
TIM2->CR1 &= ~TIM_CR1_CEN;//останавливаем счет
tic = TIM2->CNT;
TIM2->CNT = 0;
TIM6->CNT = 0;
TIM6->SR &= ~TIM_SR_UIF; //сбрасываем флаг прерывания
TIM2->CR1 |= TIM_CR1_CEN;//запускаем таймер
TIM6->CR1 |= TIM_CR1_CEN;//запускаем таймер
}
void ETR_Input_Init(void)
{
// Тактирование TIM2 и GPIOA, PA0 input-float
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
//базовые настройки таймера ни кто не отменял
TIM2->PSC = 1 - 1;
TIM2->CNT = 0;
TIM2->ARR = 60000 - 1;
TIM2->CR1 &= ~TIM_CR1_DIR;//считаем вверх
TIM2->SMCR &= ~TIM_SMCR_ETF;//настраиваем фильтр
TIM2->SMCR &= ~TIM_SMCR_ETPS;//предделитель 0
TIM2->SMCR &= ~TIM_SMCR_ETP;//возрастающий
TIM2->SMCR |= TIM_SMCR_ECE; //внешнее тактирование
}
void Tim6_Init(void)
{
RCC->APB1ENR |= RCC_APB1ENR_TIM6EN;
TIM6->PSC = 7200 -1;//новая частота = 10kHz
TIM6->ARR = 10000;//период = 1sec
TIM6->CR1 &= ~TIM_CR1_DIR;//считаем вверх
TIM6->CR1 |= TIM_CR1_OPM; //достчитав до конца таймер выключается
TIM6->DIER |= TIM_DIER_UIE; //разрешить прерывания
NVIC->ISER[1] = NVIC_ISER_SETENA_22;
}
int main(void)
{
ETR_Input_Init();
Tim6_Init();
TIM2->CR1 |= TIM_CR1_CEN;//запускаем таймер
TIM6->CR1 |= TIM_CR1_CEN;//запускаем таймер
while(1){}
}
Результат порадовал, скрин можно увеличить кликнув по нему.
А как же все таки измерить 10 MHz ?
Для этого надо использовать два таймера, один будет считать импульсы на выводе ETR, а второй считать сколько раз первый переполнился.
Похожие статьи