主從定時器的原理已在上篇博文:
基於STM32F429+HAL庫編寫的定時器主從門控模式級聯輸出固定個數PWM脈沖的程序
講解了,這篇重點就講如何實現多通道的PWM級聯輸出。
1.軟件環境
Keil5,Cube5.21
2.Cube配置
選擇定時器3,打開通道1和通道2的PWM輸出,然后開啟主從模式,觸發方式為上升沿觸發。
頻率和占空比的設置請看上篇博文。
生成的代碼 如下
void MX_TIM3_Init(void) { TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_OC_InitTypeDef sConfigOC = {0}; htim3.Instance = TIM3; htim3.Init.Prescaler = 10; htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.Period = 100-1; htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_PWM_Init(&htim3) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 50; sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) { Error_Handler(); } HAL_TIM_MspPostInit(&htim3); }
選擇定時器4,從模式為門控模式,觸發時鍾為TIM3,即ITR2,內部時鍾觸發
生成的代碼如下:
/* TIM4 init function */ void MX_TIM4_Init(void) { TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_SlaveConfigTypeDef sSlaveConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; htim4.Instance = TIM4; htim4.Init.Prescaler = 0; htim4.Init.CounterMode = TIM_COUNTERMODE_UP; htim4.Init.Period = 0xffff; htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; 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_ITR2; if (HAL_TIM_SlaveConfigSynchro(&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(); } }
STM32F429的定時器3通道1,2的PWM復用口
PA6 ------> TIM3_CH1
PA7 ------> TIM3_CH2
3,程序介紹
(1)在主函數里開啟定時器的中斷功能和PWM輸出
TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING) ; // 捕獲比較1中斷使能 TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_2,TIM_ICPOLARITY_RISING) ; // 捕獲比較2中斷使能 __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,6400) ; // 輸入通道1的捕獲比較值CCR1 ,PWM個數為6400個 __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_2,6400) ; // 輸入通道2的捕獲比較值CCR2 HAL_TIM_OC_Start_IT(&htim4,TIM_CHANNEL_1) ; //開啟定時器4通道1的輸入捕獲中斷 HAL_TIM_OC_Start_IT(&htim4,TIM_CHANNEL_2) ; //開啟定時器4通道2的輸入捕獲中斷 PostInit(); //這個是為了控制通道2的復用GPIO口PA7,可忽略 HAL_TIM_PWM_Start_IT(&htim3, TIM_CHANNEL_1); //開啟定時器3通道1的PWM輸出中斷 HAL_TIM_PWM_Start_IT(&htim3, TIM_CHANNEL_2); //開啟定時器3通道2的PWM輸出中斷
(2)在PWM中斷輪詢函數關閉定時器的中斷功能和PWM輸出
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) //重寫PWM中斷輪詢弱函數 { if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1) != RESET) //判斷是否生成中斷標志位SR { if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC1) !=RESET) //定時器中斷使能是否開啟 { __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_CC1); //清除中斷標志位SR if(HAL_TIM_PWM_Stop_IT(&htim3, TIM_CHANNEL_1)==HAL_OK) //關閉定時器3的通道1的PWM輸出 { HAL_TIM_OC_Stop_IT(&htim4,TIM_CHANNEL_1) ; //關閉定時器4的通道1的輸入中斷捕獲 FLAG1_OK = 1; //關閉標志置1 } } } //下面的通道2同理如此 if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC2) != RESET) { if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC2) !=RESET) { __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_CC2); //清除標志位 PostDeInit(); //這個是為了控制通道2的復用GPIO口PA7,可忽略 if(HAL_TIM_PWM_Stop_IT(&htim3, TIM_CHANNEL_2)==HAL_OK) { HAL_TIM_OC_Stop_IT(&htim4,TIM_CHANNEL_2) ; FLAG2_OK = 1; } } } if( FLAG1_OK == 1&&FLAG2_OK == 1) { FLAG1_OK = 0; FLAG2_OK = 0; FLAG1_Static =2; __HAL_TIM_SET_COUNTER(&htim4,0); //如果兩個通道都關閉好了,就把計數裝載值CNT清零 TIM_CCxChannelCmd(TIM3,TIM_CHANNEL_2,TIM_CCx_ENABLE); //這個是為了控制通道2的復用GPIO口PA7,可忽略 // //Delay100ms(); } }
重頭戲來了!!!如果你發現以上代碼,通道1,2的GPIO口只能輸出通道1的波形,說明你的中斷只是進了通道1的,但通道2也觸發了
原因就是兩者的中斷標志位都被清零了,而且是HAL庫自動清零的。
兩個被注釋掉的函數就是HAL庫幫你清零的語句,你手動注釋掉就行了。
4.注意事項
(1)小心使用延遲函數,定時器可能和延遲函數有沖突;
(2)如果你發現你不能輸出超過255個波形,那就在初始化哪里加個__HAL_TIM_SET_AUTORELOAD(&htim4, 0xffff) ,
既往ARR裝載0xffff。
(3)下圖的3個函數是用來調控PA7這個PWM復用口的,如果你發現你的PWM波形神奇的自動下降沿計數的話,就用來試下吧。
void PostDeInit(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin =GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLDOWN; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // GPIO_InitStruct.Alternate = 0x00; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } void PostInit(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin =GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = 0x02; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } TIM_CCxChannelCmd(TIM3,TIM_CHANNEL_2,TIM_CCx_ENABLE);