Чт мар 27, 2014 12:19:01
/* Includes ----------*/
#include "stm32f4_discovery.h"
/* Private define ----------*/
#define freqMeasureWindow (uint16_t) 16800; // тиков - время (окно) измерения (макс)
/* Private function prototypes ----------*/
void TIM1_Config(void); // Конфиг. таймера времени,
void TIM1_GPIO_config(void); // его портов,
void TIM1_NVIC_config(void); // источника прерываний.
void TIM4_Config(void); // конфиг счетчика импульсов
void TIM4_NVIC_config(void); // источника прерываний
void TIM4_ETR_GPIO_config(void); // его портов
/* Private functions ----------*/
/*****************************************************************************************
* @brief Main program
* @param None
* @retval None
*/
int main(void)
{
/*!< At this stage the microcontroller clock setting is already configured,
this is done through SystemInit() function which is called from startup
file (startup_stm32f4xx.s) before to branch to application main.
To reconfigure the default setting of SystemInit() function, refer to
system_stm32f4xx.c file
*/
// TIM1 Configuration
TIM1_NVIC_config();
TIM1_GPIO_config();
TIM1_Config();
// TIM4 Configuration
TIM4_NVIC_config();
TIM4_ETR_GPIO_config();
TIM4_Config();
while (1){
};
}
/***********************************************************************************************
* @brief Configure the TIM1 Pins.
* @param None
* @retval None
*/
void TIM1_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // Time Base Structure
TIM_ICInitTypeDef TIM_ICInitStructure; // Input Capture management structure
/* TIM1 clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
/* TIM1 deinitialization */
TIM_DeInit(TIM1);
// Time base configuration // по факту задаем только ARR (auto-reload register)
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = 0; // TIM1 max = 168 MHz Предделитель
TIM_TimeBaseStructure.TIM_Period = freqMeasureWindow; // tic's ~ 100us Окно измерения = period*предделитель/168 (us)
// Specifies the period value to be loaded into the active Auto-Reload Register at the next update event */
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0000; // only for advanced-control timers TIM1 and TIM8
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* TIM1 configuration: Input capture mode ----------
The Rising edge is used as active edge,
The TIM1 CCR1 is used to compute the frequency value for CH1 connected to PA8 or PE9
The TIM1 CCR2 is used to compute the frequency value for CH2 connected to PA9 or PE11
The TIM1 CCR3 is used to compute the frequency value for CH3 connected to PA10 or PE13
---------- */
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; // Specifies the active edge of the input signal
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; /* TIM Input 1, 2, 3 or 4 is selected to be
* connected to IC1, IC2, IC3 or IC4, respectively */
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; // TIM Input Capture Prescaler = no prescaler
// Capture performed each time an edge is detected on the capture input
TIM_ICInitStructure.TIM_ICFilter = 0x0; // Specifies the input capture filter = no filter
// This parameter can be a number between 0x0 and 0xF
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInit(TIM1, &TIM_ICInitStructure);
//TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
//TIM_ICInit(TIM1, &TIM_ICInitStructure);
//TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;
//TIM_ICInit(TIM1, &TIM_ICInitStructure);
// Syncronization parameters
TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update); // выдать Trigger по событию Update. нужно чтобы сбрасывать
// TIM4, который считает входные фронты
TIM_SelectInputTrigger(TIM1, TIM_TS_TI1FP1); // со входа TI1_FP1
TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Trigger); // The counter starts at a rising edge of the trigger TRGI
TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable); // p553 Ref.Man.
// Enable the CC1 Interrupt Request
TIM_ITConfig(TIM1, TIM_IT_CC1 | TIM_IT_Update, ENABLE);
// Чтобы синхронизировать начало счета с фронтом измеряемого импульса
TIM_SelectOnePulseMode (TIM1, TIM_OPMode_Single); // Counter stops counting at the next update event
// (clearing the bit CEN)
// TIM enable counter
//TIM_Cmd(TIM1, ENABLE);
}
/******************************************************************************************
* @brief Configure the Pin7 Port B for TIM1 chanel 2 Alternative Function.
* @param None
* @retval None
**/
void TIM1_GPIO_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; // Структура регистров для конфигурации портов
/* GPIOA clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
// TIM1 chennel 1,2,3 configuration : PA8, PA9, PA10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOE, &GPIO_InitStructure); // инициализировать структуру для PA
// Connect TIM pin to AF1 */
GPIO_PinAFConfig(GPIOE, GPIO_PinSource9, GPIO_AF_TIM1 );
}
/******************************************************************************************
* @brief Configure the NVIC for TIM1.
* @param None
* @retval None
**/
void TIM1_NVIC_config(void)
{
NVIC_InitTypeDef NVIC_InitStructure; // Структура для конфигурации регистров прерываний
/* Enable and set TIM1 capture compare interrupt*/
NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Enable and set TIM1 update interrupt & TIM10 global */
NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_TIM10_IRQn ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/***********************************************************************************************
* @brief Configure the TIM4 as
* @param None
* @retval None
*/
void TIM4_Config(void)
{
// TIM4 clock enable
RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM4, ENABLE);
// TIM4 deinitialization
TIM_DeInit(TIM4);
// external clock mode source mode 2
TIM_ETRClockMode2Config(TIM4, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00); // счетик CNT тактируется от ETR (PE0),
// prescaler выкл, по переднему фронту
// Slave mode reset
TIM_SelectInputTrigger (TIM4, TIM_TS_ITR0); // Internal trigger 0 for TIM4,TIM3,TIM2 is TIM1 for TIM4 (p658 in Ref.Man)
TIM_SelectSlaveMode (TIM4, TIM_SlaveMode_Reset); // TIM4 CNT, presc will be reinited by TIM1_Update event (p658 in Ref.Man)
TIM_SelectMasterSlaveMode(TIM4, TIM_MasterSlaveMode_Enable);
// TIM enable counter
TIM_Cmd(TIM4, ENABLE);
}
/******************************************************************************************
* @brief Configure the Pin0 Port E for TIM4 ETR(External trigger) Alternative Function.
* @param None
* @retval None
**/
void TIM4_ETR_GPIO_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; // Структура регистров для конфигурации портов
/* GPIOB clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
// TIM4 ETR configuration : PE.00
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOE, &GPIO_InitStructure); // инициализировать структуру
// Connect TIM pin to AF2
GPIO_PinAFConfig(GPIOE, GPIO_PinSource0, GPIO_AF_TIM4); // TIM4_ETR PE0
}
/******************************************************************************************
* @brief Configure the NVIC for TIM1.
* @param None
* @retval None
**/
void TIM4_NVIC_config(void)
{
NVIC_InitTypeDef NVIC_InitStructure; // Структура для конфигурации регистров прерываний
/* Enable and set TIM1 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/* Includes ----------*/
#include "stm32f4xx_it.h"
/* Private define ----------*/
#define HClkFreq (uint32_t)168000000
/* Private variables ----------*/
__IO uint16_t lastCCRValue = 0; //
__IO uint16_t impCount = 0; // количество импульсов (фронтов) пришедших на TIM4.ETR
// обновление по событию TIM1_Update
__IO uint32_t freqW = 0; // частота вычисленная средняя по окну
__IO uint32_t freq1[40]; // массив посчитаных частот каждого импульса в пределах окна
__IO uint32_t freq1Sum; // сумма значений freq1[] для расчета freq1Avg
__IO uint32_t freq1Avg; // среднее арифметическое посчитаных частот каждого импульса в пределах окна
/******************************************************************************/
/* STM32F4xx Peripherals Interrupt Handlers */
/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
/* available peripheral interrupt handler's name please refer to the startup */
/* file (startup_stm32f4xx.s). */
/******************************************************************************/
/**
* @brief This function handles TIM1 update interrupt request and TIM10 global.
* @param None
* @retval None
*/
void TIM1_UP_TIM10_IRQHandler(void)
{
TIM1->SR = ~TIM_IT_Update;
freq1Avg = freq1Sum / (impCount-1);
freq1Sum = 0;
freqW = HClkFreq * (impCount-1) / lastCCRValue;
} // end func
/********************************************************************************
* @brief This function handles TIM1 update interrupt request and TIM10 global.
* @param None
* @retval None
*/
void TIM1_CC_IRQHandler(void)
{
//TIM_ClearITPendingBit (TIM1, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3); // clear interrupt flag. необязательно. само сбросится при чтении CCRx
lastCCRValue = TIM1 -> CCR1;
impCount = TIM4 -> CNT;
freq1[impCount-1] = HClkFreq * (impCount-1) / lastCCRValue;
freq1Sum += freq1[impCount-1];
}
Чт мар 27, 2014 12:54:03
Reciprocal counting - http://www.spectracomcorp.com/Desktopmodules/Bring2Mind/DMX/Download.aspx?EntryId=446&PortalId=0Reprocical counter.
Чт мар 27, 2014 15:10:31
ut1wpr писал(а):Reciprocal counting - http://www.spectracomcorp.com/Desktopmodules/Bring2Mind/DMX/Download.aspx?EntryId=446&PortalId=0Reprocical counter.
Чт мар 27, 2014 15:13:09
Чт мар 27, 2014 17:15:55
Это с точностью +-10Гц?HHIMERA писал(а):4 знака...
Пт мар 28, 2014 14:22:20
Пт мар 28, 2014 15:10:27
Пт мар 28, 2014 15:31:05
Пт мар 28, 2014 17:06:34
Потому что в 0 сбрасывается по событию Update Generation от TIM1. TIM4 считает фронты.akl писал(а):Почему TIM4.CNT считает с 1, а не с 0?
Без сомнений. New frequency counting principle improves resolution 3.Reciprocal counting.HHIMERA писал(а):А это точно... Reciprocal counter???
Пт мар 28, 2014 17:39:51
Пт мар 28, 2014 17:55:33
HHIMERA писал(а):Это НЕ Reciprocal counter!!!
Должно быть так...
Finput = (Fref * Ninput) / Nref
где Ninput количество входных периодов за определённое время... а Nref - количество референсных периодов за это же время...
Пт мар 28, 2014 18:30:28
Пт мар 28, 2014 23:56:12
Сб мар 29, 2014 04:35:05
Сб мар 29, 2014 10:34:30
akl писал(а):при Fo=168МГц время измерения будет 16'800 тактов, по окончании которых будет последний активный фронт Fx.
Пн мар 31, 2014 09:43:40
Пн мар 31, 2014 10:42:54
Наверное картинка одному мне понятна потому как я ее рисовалЛеонид Иванович писал(а):Ну так я же не разбираюсь в STM32, поэтому прочитать программу не могу По временной диаграмме тоже ничего не понятно. Если бы было описание словами, что делаем шаг за шагом, я бы вынес вердикт.
1. исп-ся 2 таймера в связке.Леонид Иванович писал(а):P.S. Посмотрел немножко программу. Если по каждому фронту входного сигнала генерируется прерывание, так вообще таймера 4 не нужно, входные периоды можно считать программно. Такой частотомер реализуется на чем угодно, был бы только аппаратный захват таймера. Но такой вариант неинтересен, должна быть возможность измерять частоты до 1/2 Fclk.
void TIM1_UP_TIM10_IRQHandler(void)
{
TIM1->SR = ~TIM_IT_Update; // сброс флага TIM1_Update
freqW = HClkFreq * (impCount-1) / TIM1 -> CCR1;
}
Пн мар 31, 2014 10:51:22
ага. вон какую петицию накатал...HHIMERA писал(а):Дык... ща ЛИ нарисуется... проведёт экспертизу метОды... и вынесет вердикт... мне лень...
Пн мар 31, 2014 11:37:38
kybin писал(а):2. прерывание по фронту генерируется для расчета длительности каждого импульса. Забивания их в массив. Вычисления ср. арифметического. Это пережиток прошлых вариаций. Его нужно убрать.
и сделать так:...
Пн мар 31, 2014 12:26:44
kybin писал(а):HHIMERA, а что насчет tизм ~= 100 мкс?
вон какую петицию накатал...