不使用void HAL_TIM_Encoder_MspInit(TIM_HandleTypeDef* tim_encoderHandle)增强代码的层级结构注意事项
这是正常用cube Max生成的代码这里以设置编码器为例。 GPIO初始化函数放在HAL_TIM_Encoder_MspInit这个回调函数中。代码正常运行/* TIM3 init function */ void MX_TIM3_Init(void) { TIM_Encoder_InitTypeDef sConfig {0}; TIM_MasterConfigTypeDef sMasterConfig {0}; /* USER CODE BEGIN TIM3_Init 1 */ /* USER CODE END TIM3_Init 1 */ htim3.Instance TIM3; htim3.Init.Prescaler 4-1; htim3.Init.CounterMode TIM_COUNTERMODE_UP; htim3.Init.Period 65535; htim3.Init.ClockDivision TIM_CLOCKDIVISION_DIV1; htim3.Init.AutoReloadPreload TIM_AUTORELOAD_PRELOAD_DISABLE; sConfig.EncoderMode TIM_ENCODERMODE_TI12; sConfig.IC1Polarity TIM_ICPOLARITY_RISING; sConfig.IC1Selection TIM_ICSELECTION_DIRECTTI; sConfig.IC1Prescaler TIM_ICPSC_DIV1; sConfig.IC1Filter 0; sConfig.IC2Polarity TIM_ICPOLARITY_RISING; sConfig.IC2Selection TIM_ICSELECTION_DIRECTTI; sConfig.IC2Prescaler TIM_ICPSC_DIV1; sConfig.IC2Filter 0; if (HAL_TIM_Encoder_Init(htim3, sConfig) ! HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(htim3, sMasterConfig) ! HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM3_Init 2 */ /* USER CODE END TIM3_Init 2 */ } void HAL_TIM_Encoder_MspInit(TIM_HandleTypeDef* tim_encoderHandle) { GPIO_InitTypeDef GPIO_InitStruct {0}; if(tim_encoderHandle-InstanceTIM3) { /* USER CODE BEGIN TIM3_MspInit 0 */ /* USER CODE END TIM3_MspInit 0 */ /* TIM3 clock enable */ __HAL_RCC_TIM3_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**TIM3 GPIO Configuration PA6 ------ TIM3_CH1 PA7 ------ TIM3_CH2 */ GPIO_InitStruct.Pin GPIO_PIN_6|GPIO_PIN_7; GPIO_InitStruct.Mode GPIO_MODE_INPUT; GPIO_InitStruct.Pull GPIO_NOPULL; HAL_GPIO_Init(GPIOA, GPIO_InitStruct); /* USER CODE BEGIN TIM3_MspInit 1 */ /* USER CODE END TIM3_MspInit 1 */ } }再看一下运行不正常的情况。下面是错误案例我把GPIO初始化的函数从HAL_TIM_Encoder_MspInit()剪切出来放在HAL_TIM_Encoder_Init函数的后面void MX_TIM3_Init(void) { TIM_Encoder_InitTypeDef sConfig {0}; TIM_MasterConfigTypeDef sMasterConfig {0}; /* USER CODE BEGIN TIM3_Init 1 */ /* USER CODE END TIM3_Init 1 */ htim3.Instance TIM3; htim3.Init.Prescaler 4-1; htim3.Init.CounterMode TIM_COUNTERMODE_UP; htim3.Init.Period 65535; htim3.Init.ClockDivision TIM_CLOCKDIVISION_DIV1; htim3.Init.AutoReloadPreload TIM_AUTORELOAD_PRELOAD_DISABLE; sConfig.EncoderMode TIM_ENCODERMODE_TI12; sConfig.IC1Polarity TIM_ICPOLARITY_RISING; sConfig.IC1Selection TIM_ICSELECTION_DIRECTTI; sConfig.IC1Prescaler TIM_ICPSC_DIV1; sConfig.IC1Filter 0; sConfig.IC2Polarity TIM_ICPOLARITY_RISING; sConfig.IC2Selection TIM_ICSELECTION_DIRECTTI; sConfig.IC2Prescaler TIM_ICPSC_DIV1; sConfig.IC2Filter 0; if (HAL_TIM_Encoder_Init(htim3, sConfig) ! HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(htim3, sMasterConfig) ! HAL_OK) { Error_Handler(); } /* 剪切代码哪开始位置 */ GPIO_InitTypeDef GPIO_InitStruct {0}; /* TIM3 clock enable */ __HAL_RCC_TIM3_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**TIM3 GPIO Configuration PA6 ------ TIM3_CH1 PA7 ------ TIM3_CH2 */ GPIO_InitStruct.Pin GPIO_PIN_6|GPIO_PIN_7; GPIO_InitStruct.Mode GPIO_MODE_INPUT; GPIO_InitStruct.Pull GPIO_NOPULL; HAL_GPIO_Init(GPIOA, GPIO_InitStruct); /* 剪切代码哪结束位置*/ }下面是正确的代码把在 HAL_TIM_Encoder_MspInit函数中初始化的函数代码剪切到HAL_TIM_Encoder_Init函数前面并注释掉void HAL_TIM_Encoder_MspInit(TIM_HandleTypeDef* tim_encoderHandle)这个函数这里以GPIO初始化函数为例。/* TIM3 init function */ void MX_TIM3_Init(void) { /* 剪切代码的开始位置 */ GPIO_InitTypeDef GPIO_InitStruct {0}; /* TIM3 clock enable */ __HAL_RCC_TIM3_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**TIM3 GPIO Configuration PA6 ------ TIM3_CH1 PA7 ------ TIM3_CH2 */ GPIO_InitStruct.Pin GPIO_PIN_6|GPIO_PIN_7; GPIO_InitStruct.Mode GPIO_MODE_INPUT; GPIO_InitStruct.Pull GPIO_NOPULL; HAL_GPIO_Init(GPIOA, GPIO_InitStruct); /* 剪切代码的结束位置 0 */ TIM_Encoder_InitTypeDef sConfig {0}; TIM_MasterConfigTypeDef sMasterConfig {0}; /* USER CODE BEGIN TIM3_Init 1 */ /* USER CODE END TIM3_Init 1 */ htim3.Instance TIM3; htim3.Init.Prescaler 4-1; htim3.Init.CounterMode TIM_COUNTERMODE_UP; htim3.Init.Period 65535; htim3.Init.ClockDivision TIM_CLOCKDIVISION_DIV1; htim3.Init.AutoReloadPreload TIM_AUTORELOAD_PRELOAD_DISABLE; sConfig.EncoderMode TIM_ENCODERMODE_TI12; sConfig.IC1Polarity TIM_ICPOLARITY_RISING; sConfig.IC1Selection TIM_ICSELECTION_DIRECTTI; sConfig.IC1Prescaler TIM_ICPSC_DIV1; sConfig.IC1Filter 0; sConfig.IC2Polarity TIM_ICPOLARITY_RISING; sConfig.IC2Selection TIM_ICSELECTION_DIRECTTI; sConfig.IC2Prescaler TIM_ICPSC_DIV1; sConfig.IC2Filter 0; if (HAL_TIM_Encoder_Init(htim3, sConfig) ! HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(htim3, sMasterConfig) ! HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM3_Init 2 */ /* USER CODE END TIM3_Init 2 */ }报错原因分析在 HAL 库的标准流程中HAL_TIM_Encoder_Init()内部会调用HAL_TIM_Encoder_MspInit()在配置定时器寄存器之前就完成底层硬件时钟、GPIO 等的初始化。我的错误案例将 GPIO 初始化放在了HAL_TIM_Encoder_Init()之后。此时定时器已经被配置为编码器模式但对应的输入引脚 PA6/PA7 还没有被设为输入模式导致定时器无法正确检测到编码器信号从而读不到数值。疑问在没有配置GPIO前定时器读取的引脚是。不确定的浮空状态。会遭到电磁干扰等影响。会cnt计数器之中的职位随机跳变。但是为什么在配置gpio后cnt寄存器中的数值仍然在随机跳变理论上不会跳变因为gpio电平已经稳定了