1 硬件和軟件平臺
- 硬件:自制STM32F103C8T6
- 軟件:STM32CubeMX 6.1.0
- 軟件:Keil V5.28.0.0
- 硬件包:STM32Cube_FW_F1 V1.8.3
2 定時器介紹
STM32的定時器可以通過另外一個定時器的某一個條件被觸發(fā)而啟動榆浓,即同步的工作方式。發(fā)出觸發(fā)信號的定時器工作于主模式(Master)角雷,接受觸發(fā)信號而啟動的定時器工作于從模式(Slave)堕阔。它們之間通過TIM內(nèi)部觸發(fā)連接(ITR)瘦材。使用不同的主從定時器,使用的ITR不同,根據(jù)參考手冊(版本ENV20)可以知道對應(yīng)的ITR车要。
3 CubeMX配置
不再介紹CubeMX創(chuàng)建工程的方法。
3.1 設(shè)置時鐘
在RCC中配置高速時鐘厘熟,選擇外部晶振屯蹦。
在Clock Configuration中選擇HSE,并配置HCLK為72MHz绳姨。
3.2 設(shè)置仿真模式
在SYS設(shè)置仿真模式登澜,此處我使用的是SW,根據(jù)情況自行選擇飘庄。
3.3 設(shè)置主定時器(Master)
此處我使用TIM2作為Master脑蠕,通道2輸出PWM。TIM1為Slave跪削。在CubeMX中選擇TIM2谴仙,配置主定時器。 Channel2選擇PWM Generation CH2碾盐。
預(yù)分頻系數(shù)為71(設(shè)置值不能大于65535)晃跺,計數(shù)器周期為9,這兩個配置控制PWM輸出的頻率毫玖。由于我們時鐘是72MHz掀虎,此處設(shè)置的PWM頻率為100kHz。
設(shè)置Pulse為5付枫,該值和計數(shù)器周期共同控制PWM的占空比烹玉,此處為50%。
使能主從模式阐滩,觸發(fā)事件選擇Update Event二打。禁用輸出比較預(yù)加載。輸出極性Low掂榔。
3.4 設(shè)置從定時器(Slave)
此處我選擇TIM1為Slave继效。由圖1可知症杏,TIM2為Master,TIM1為Slave時莲趣,使用ITR1鸳慈。在CubeMX中選擇TIM1。設(shè)置Slave Mode為Gated Mode喧伞,觸發(fā)源選擇ITR1(根據(jù)自己使用的定時器選擇)走芋,時鐘源選擇內(nèi)部時鐘。
參數(shù)設(shè)置基本是保持默認潘鲫。
使能從定時器的中斷翁逞。此處我使用的是高級定時器作為Slave,如果是通用定時器溉仑,只需使能定時器全局中斷即可挖函。
CubeMX配置完成,點擊GENERATE CODE生成代碼浊竟。
4 代碼
CubeMX已經(jīng)幫我們生成了初始化代碼怨喘,無需修改。
主定時器(此處是TIM2)初始化代碼:
/* TIM2 init function */
void MX_TIM2_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 71;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 9;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
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 = 5;
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
__HAL_TIM_DISABLE_OCxPRELOAD(&htim2, TIM_CHANNEL_2);
HAL_TIM_MspPostInit(&htim2);
}
從定時器(此處是TIM1)初始化代碼:
/* TIM1 init function */
void MX_TIM1_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
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;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
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_ITR1;
if (HAL_TIM_SlaveConfigSynchro(&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();
}
}
在main.c中定義標志位以指示PWM是否處于輸出狀態(tài)振定。
/* USER CODE BEGIN PV */
uint8_t PWM_OK = 0;
/* USER CODE END PV */
在main函數(shù)初始化完成后添加以下代碼必怜。
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim1);
HAL_TIM_PWM_Start_IT(&htim2, TIM_CHANNEL_2);
__HAL_TIM_SET_AUTORELOAD(&htim1, 0);
/* USER CODE END 2 */
在stm32f1xx_it.c中添加外部變量引用和中斷回調(diào)函數(shù),也可以添加到其他文件中后频,根據(jù)自己習慣來梳庆。由于我們使能了TIM1的中斷,此處CubeMX會自動添加TIM1的引用卑惜,只需手動添加TIM2的引用即可膏执。
/* USER CODE BEGIN PV */
extern uint8_t PWM_OK;
/* USER CODE END PV */
/* USER CODE BEGIN EV */
extern TIM_HandleTypeDef htim2;
/* USER CODE END EV */
在中斷回調(diào)函數(shù)中清除中斷標志位,并停止PWM露久。
/* USER CODE BEGIN 1 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == (&htim1))
{
if(__HAL_TIM_GET_FLAG(&htim1, TIM_FLAG_CC1) != RESET)
{
__HAL_TIM_CLEAR_FLAG(&htim1, TIM_FLAG_CC1);
HAL_TIM_PWM_Stop_IT(&htim2, TIM_CHANNEL_2);
HAL_TIM_Base_Stop_IT(&htim1);
}
PWM_OK = 1;
}
}
/* USER CODE END 1 */
在main.c中封裝PWM輸出函數(shù)更米,并在main.h中聲明。
/**
* @brief The application outputs a specified number of pulses.
* @param num is the number of pulses.
*/
void OutPwm(uint32_t num)
{
if(PWM_OK == 1)
{
PWM_OK = 0;
__HAL_TIM_SET_AUTORELOAD(&htim1, num - 1);
HAL_TIM_Base_Start_IT(&htim1);
HAL_TIM_PWM_Start_IT(&htim2, TIM_CHANNEL_2);
}
}
在while(1)中輸出10個脈沖并延遲40ms毫痕。
while (1)
{
HAL_Delay(40);
OutPwm(10);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
5 測試結(jié)果
因為我的硬件中使用了緩沖器將PWM的電平提高到了5V壳快,因此測量結(jié)果都是5Vpp。
可以看到镇草,每40ms有脈沖輸出。
放大細節(jié)可以看到得到100kHz的10個脈沖瘤旨,波形還不錯梯啤。