TIM ETR 计数
1.通用定时器时钟源
而我们要用的 ETR功能就属于 ,外部时钟模式2:外部触发输入ETR。
2. 外部触发输入ETR
外部时钟模式2:外部触发输入ETR
3.TIM ETR 例程
使用步骤:
1)TIMx_SMCR寄存器中的ETF[3:0]用来设置滤波器。
2)TIMx_SMCR寄存器中的ETPS[1:0]设置预分频器,即多少个边沿触发一次计数。
3)置TIMx_SMCR寄存器中的ETP设置上升沿或下降沿计数。
4)令TIMx_SMCR寄存器中的ECE=1选定此模式。
5)启动计数器,写TIMx_CR1寄存器中的CEN=1。
3.1 例程背景
用的步进电机,功能调试完成,能走能停的。但是出现 走的距离并不是实际的物理长度,总是出现或大或小的偏差,造成精度不高。
由于没有用到编码器,作为输出反馈,只能决定先做个实验,捕获下实际输出的脉冲数量。用的 TIM ETR。
STM32F429IGT6, 根据板子情况,选择PA5,TIM2_ETR,
3.2 程序示例
3.2.1 标准库函数
1)F4和F1的复用功能部分不一样。F4要额外添加复位功能映射代码,才能开启此功能。
2)注意计数溢出处理。︿( ̄︶ ̄)︿F429IGT6 ARR是32bit 的
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_PinAFConfig(GPIOA,GPIO_PinSource5,GPIO_AF_TIM2);
#define GENERAL_TIM TIM2
#define GENERAL_TIM_CLK RCC_APB1Periph_TIM2
#define GENERAL_TIM_IRQn TIM2_IRQn
#define GENERAL_TIM_IRQHandler TIM2_IRQHandler
#define ETR_PIN GPIO_Pin_5
#define ETR_GPIO_PORT GPIOA
#define ETR_GPIO_CLK RCC_AHB1Periph_GPIOA
static void TIM_Mode_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(GENERAL_TIM_CLK, ENABLE);
RCC_AHB1PeriphClockCmd ( ETR_GPIO_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin = ETR_PIN ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // F4和F1的复用功能部分不一样
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(ETR_GPIO_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(ETR_GPIO_PORT,GPIO_PinSource5,GPIO_AF_TIM2); // F4和F1的复用功能部分不一样
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF;
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure);
TIM_ETRClockMode2Config(GENERAL_TIM, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0);
TIM_SetCounter(GENERAL_TIM, 0);
TIM_Cmd(GENERAL_TIM, ENABLE);
}
u32 n_Counter1;
int main(void)
{
.......
while(1)
{
n_Counter1 = TIM_GetCounter(GENERAL_TIM); //读取CNT寄存器
}
}
我是对要发的脉冲数进行计数,对比看理论和实际是否一致。没有用到中断,没有处理溢出。
用中断的话,要添加代码。
static void TIMx_NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
TIM_ClearITPendingBit(GENERAL_TIM,TIM_IT_Update); //清除中断标志位,避免第一次自动进入中断一次
TIM_ITConfig(GENERAL_TIM,TIM_IT_Update,ENABLE);
u32 overflow_cnt=0;
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(GENERAL_TIM,TIM_IT_Update) == SET)
{
overflow_cnt++;
//具体的处理使用
}
TIM_ClearITPendingBit(GENERAL_TIM,TIM_IT_Update);
}
3.2.2 HAL库函数
STM32CubeMX配置TIM ETR
parameter settings 默认。
gpio settings 中的上下拉根据自己的电路情况设置。
NVIC 用到的,也要设置。
另外,根据自己电路情况,输入有光耦隔离的,要注意自己光耦器件的电源要不要代码控制,我电路的光耦电源是要自己写代码驱动的。默认板子光耦是无电源的。因此输入是无效的。
直接生成代码就可以了。
引脚重映射代码里也自动配置好,不用额外代码
/* Includes ------------------------------------------------------------------*/
#include "tim.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
TIM_HandleTypeDef htim2;
/* TIM2 init function */
void MX_TIM2_Init(void)
{
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 0xffffffff;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_ETRMODE2;
sClockSourceConfig.ClockPolarity = TIM_CLOCKPOLARITY_NONINVERTED;
sClockSourceConfig.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1;
sClockSourceConfig.ClockFilter = 0;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
HAL_TIM_Base_Start(&htim2); //非自动生成
/* USER CODE END TIM2_Init 2 */
}
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(tim_baseHandle->Instance==TIM2)
{
/* USER CODE BEGIN TIM2_MspInit 0 */
/* USER CODE END TIM2_MspInit 0 */
/* TIM2 clock enable */
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**TIM2 GPIO Configuration
PA5 ------> TIM2_ETR
*/
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN TIM2_MspInit 1 */
/* USER CODE END TIM2_MspInit 1 */
}
}
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{
if(tim_baseHandle->Instance==TIM2)
{
/* USER CODE BEGIN TIM2_MspDeInit 0 */
/* USER CODE END TIM2_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM2_CLK_DISABLE();
/**TIM2 GPIO Configuration
PA5 ------> TIM2_ETR
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5);
/* USER CODE BEGIN TIM2_MspDeInit 1 */
/* USER CODE END TIM2_MspDeInit 1 */
}
}
使用的使用,需启动定时器
/* USER CODE BEGIN 1 */
/*启动定时器*/
HAL_TIM_Base_Start(&htim2);
uint32_t n_Counter1;
static void TIM2_ETRGetCounter(void)
{
n_Counter1 = htim2.Instance->CNT;
/*标准库获取计数器值用TIM_GetCounter函数,HAL函数中,没找到,直接调用值即可*/
}
/* USER CODE END 1 */
4. 补充
4.1.HAL库不需要重映射
标准库中 F4 需要 GPIO_PinAFConfig(ETR_GPIO_PORT,GPIO_PinSource5,GPIO_AF_TIM2);
但是 HAL库不用,因为HAL_GPIO_Init时,已经做好
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)
{
..........................
/* In case of Alternate function mode selection */
if((GPIO_Init->Mode & GPIO_MODE) == MODE_AF)
{
/* Check the Alternate function parameter */
assert_param(IS_GPIO_AF(GPIO_Init->Alternate));
/* Configure Alternate function mapped with the current IO */
temp = GPIOx->AFR[position >> 3U];
temp &= ~(0xFU << ((uint32_t)(position & 0x07U) * 4U)) ;
temp |= ((uint32_t)(GPIO_Init->Alternate) << (((uint32_t)position & 0x07U) * 4U));
GPIOx->AFR[position >> 3U] = temp;
}
/* Configure IO Direction mode (Input, Output, Alternate or Analog) */
temp = GPIOx->MODER;
temp &= ~(GPIO_MODER_MODER0 << (position * 2U));
temp |= ((GPIO_Init->Mode & GPIO_MODE) << (position * 2U));
GPIOx->MODER = temp;
..........................
}
4.2 HAL库不需要添加TIM ETR设置代码
标准库中
TIM_ETRClockMode2Config(GENERAL_TIM, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0);
HAL库中
定时器时钟源配置时,已经设置
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_ETRMODE2;
sClockSourceConfig.ClockPolarity = TIM_CLOCKPOLARITY_NONINVERTED;
sClockSourceConfig.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1;
sClockSourceConfig.ClockFilter = 0;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
/**
* @brief Configures the clock source to be used
* @param htim TIM handle
* @param sClockSourceConfig pointer to a TIM_ClockConfigTypeDef structure that
* contains the clock source information for the TIM peripheral.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIM_ConfigClockSource(TIM_HandleTypeDef *htim, TIM_ClockConfigTypeDef *sClockSourceConfig)
{
switch (sClockSourceConfig->ClockSource)
{
case TIM_CLOCKSOURCE_ETRMODE2:
{
/* Check whether or not the timer instance supports external trigger input mode 2 (ETRF)*/
assert_param(IS_TIM_CLOCKSOURCE_ETRMODE2_INSTANCE(htim->Instance));
/* Check ETR input conditioning related parameters */
assert_param(IS_TIM_CLOCKPRESCALER(sClockSourceConfig->ClockPrescaler));
assert_param(IS_TIM_CLOCKPOLARITY(sClockSourceConfig->ClockPolarity));
assert_param(IS_TIM_CLOCKFILTER(sClockSourceConfig->ClockFilter));
/* Configure the ETR Clock source */
TIM_ETR_SetConfig(htim->Instance,
sClockSourceConfig->ClockPrescaler,
sClockSourceConfig->ClockPolarity,
sClockSourceConfig->ClockFilter);
/* Enable the External clock mode2 */
htim->Instance->SMCR |= TIM_SMCR_ECE;
break;
}
}
}
所以STM32CubeMX生成代码后,直接启动定时器就可以了。
/*启动定时器*/
HAL_TIM_Base_Start(&htim2);