标签:定时器 CubeMax TIM Init CODE USER STM32F4 HAL RCC
实验准备
开发板:STM32F411E-DISCO或其它开发板(Firmware Package根据开发板下载)
软件:Keil uVision5、STM32CubeMX(Firmware Package:STM32Cube FW_F4 V1.23.0)
实验原理
利用CubeMX根据芯片手册配置定时器同步来实现自定义脉冲数PWM输出对电机进行控制。主定时器产生PWM波,从定时器对主定时器发出的脉冲进行计数。
STM32F4xx定时器内部触发连接
CubeMX 时钟配置表
/** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/**Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /**Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 4; RCC_OscInitStruct.PLL.PLLN = 96; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4; RCC_OscInitStruct.PLL.PLLQ = 4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /**Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { Error_Handler(); } }
|
主定时器TIM5配置(主:TIM5----从:TIM1)
/** * @brief TIM5 Initialization Function * @param None * @retval None */ static void MX_TIM5_Init(void) {
/* USER CODE BEGIN TIM5_Init 0 */ // TIM_ClockConfigTypeDef sClockSourceConfig; /* USER CODE END TIM5_Init 0 */
TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_OC_InitTypeDef sConfigOC = {0};
/* USER CODE BEGIN TIM5_Init 1 */
/* USER CODE END TIM5_Init 1 */ htim5.Instance = TIM5; htim5.Init.Prescaler = 48-1; htim5.Init.CounterMode = TIM_COUNTERMODE_UP; htim5.Init.Period = 400-1; htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; if (HAL_TIM_PWM_Init(&htim5) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 200; sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim5, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM5_Init 2 */
/* USER CODE END TIM5_Init 2 */ HAL_TIM_MspPostInit(&htim5);
}
|
从定时器TIM1配置(主:TIM5----从:TIM1) 从定时器TIM1需要开中断NVIC
/** * @brief TIM1 Initialization Function * @param None * @retval None */ static void MX_TIM1_Init(void) {
/* USER CODE BEGIN TIM1_Init 0 */
/* USER CODE END TIM1_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_SlaveConfigTypeDef sSlaveConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM1_Init 1 */
/* USER CODE END TIM1_Init 1 */ htim1.Instance = TIM1; htim1.Init.Prescaler = 0; htim1.Init.CounterMode = TIM_COUNTERMODE_UP; htim1.Init.Period = 65535; htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim1.Init.RepetitionCounter = 0; if (HAL_TIM_Base_Init(&htim1) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } sSlaveConfig.SlaveMode = TIM_SLAVEMODE_GATED; sSlaveConfig.InputTrigger = TIM_TS_ITR0; if (HAL_TIM_SlaveConfigSynchronization(&htim1, &sSlaveConfig) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM1_Init 2 */
/* USER CODE END TIM1_Init 2 */
}
|
主定时器TIM2配置(主:TIM2----从:TIM4)
/** * @brief TIM2 Initialization Function * @param None * @retval None */ static void MX_TIM2_Init(void) {
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_OC_InitTypeDef sConfigOC = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */ htim2.Instance = TIM2; htim2.Init.Prescaler = 48-1; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 400-1; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 200; sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */ HAL_TIM_MspPostInit(&htim2);
}
|
从定时器TIM4配置(主:TIM2----从:TIM4)从定时器TIM4需要开中断NVIC
/** * @brief TIM4 Initialization Function * @param None * @retval None */ static void MX_TIM4_Init(void) {
/* USER CODE BEGIN TIM4_Init 0 */
/* USER CODE END TIM4_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_SlaveConfigTypeDef sSlaveConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM4_Init 1 */
/* USER CODE END TIM4_Init 1 */ htim4.Instance = TIM4; htim4.Init.Prescaler = 0; htim4.Init.CounterMode = TIM_COUNTERMODE_UP; htim4.Init.Period = 65535; htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; if (HAL_TIM_Base_Init(&htim4) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } sSlaveConfig.SlaveMode = TIM_SLAVEMODE_GATED; sSlaveConfig.InputTrigger = TIM_TS_ITR1; if (HAL_TIM_SlaveConfigSynchronization(&htim4, &sSlaveConfig) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM4_Init 2 */
/* USER CODE END TIM4_Init 2 */
}
|
添加中断回调函数(注意次函数一定要添加在“/* USER CODE BEGIN 4 */”和“/* USER CODE END 4 */”之间,这样cubemx更新代码时不会清除掉)
/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if(htim==(&htim1)) { PWM1_OK = 0; if(__HAL_TIM_GET_FLAG(&htim1, TIM_FLAG_CC1) != RESET) //判断是否触发中断 { __HAL_TIM_CLEAR_FLAG(&htim1, TIM_FLAG_CC1); //清除中断标志位 HAL_TIM_PWM_Stop_IT(&htim5, TIM_CHANNEL_1); //关闭主定时器的PWM输出 HAL_TIM_Base_Stop_IT(&htim1); //关闭从定时器的计数 } } if(htim==(&htim4)) { PWM2_OK = 0; if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_CC1) != RESET) //判断是否触发中断 { __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_CC1); //清除中断标志位 HAL_TIM_PWM_Stop_IT(&htim2, TIM_CHANNEL_1); //关闭主定时器的PWM输出 HAL_TIM_Base_Stop_IT(&htim4); //关闭从定时器的计数 } } }
void PWM_out1(uint32_t pulse_data) { if(PWM1_OK == 1) //标志判断 { PWM1_OK = 0; TIM5->ARR=speed1; TIM5->CCR1=(speed1>>1); __HAL_TIM_SET_AUTORELOAD(&htim1,pulse_data-1); //ARR装载要输出的PWM脉冲数 HAL_TIM_Base_Start_IT(&htim1); //从定时器计数开启 HAL_TIM_PWM_Start_IT(&htim5, TIM_CHANNEL_1); //主定时器PWM脉冲输出 } } void PWM_out2(uint32_t pulse_data) { if(PWM2_OK == 1) //标志判断 { PWM2_OK = 0; TIM2->ARR=speed2; TIM2->CCR1=(speed2>>1); __HAL_TIM_SET_AUTORELOAD(&htim4,PWM_pulse-1); //ARR装载要输出的PWM脉冲数 HAL_TIM_Base_Start_IT(&htim4); //从定时器计数开启 HAL_TIM_PWM_Start_IT(&htim2, TIM_CHANNEL_1); //主定时器PWM脉冲输出 } }
/* USER CODE END 4 */
|
在主函数前 添加私有变量 添加私有函数声明
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */ uint8_t PWM1_OK = 0; uint8_t PWM2_OK = 0; uint32_t PWM_pulse = 0; uint16_t speed1=80; //电机默认速度 uint16_t speed2=80; //电机默认速度 /* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/ /* USER CODE BEGIN PFP */ void PWM_out1(uint32_t pulse_data); void PWM_out2(uint32_t pulse_data);
/* USER CODE END PFP */
|
在主函数 中添加PWM输出函数
/* Infinite loop */ /* USER CODE BEGIN WHILE */ PWM1_OK = 1; PWM2_OK = 1; PWM_pulse = 20; speed1=400; //电机默认速度 数值越大脉冲周期越大 电机速度越慢 speed2=400; //电机默认速度 数值越大脉冲周期越大 电机速度越慢 while (1) { /* USER CODE END WHILE */
/* USER CODE BEGIN 3 */ PWM_out1(PWM_pulse); PWM_out2(PWM_pulse); } /* USER CODE END 3 */
|
引脚输出脉冲观察(PA0、PA5)
标签:定时器,
CubeMax,
TIM,
Init,
CODE,
USER,
STM32F4,
HAL,
RCC
From: https://www.cnblogs.com/RXZS-Magic/p/16821577.html