之前在学习STM32的基本定时器的输出PWM的相关调试、使用DMA接收串口数据的相关内容,今天和大家分享一下利用DMA和定时器中断请求,来修改定时器的比较值的相关调试内容。
学习内容:使用DMA从内存到外设的传输功能,完成定时器输出PWM的脉冲宽度的改变。
软件编程学习调试步骤:
目标是配置 TIM1 通道 3 以生成频率等于 1 KHz 的互补 PWM(脉宽调制)信号,以及一个可变占空比,该占空比在特定数量的更新 DMA 请求后由 DMA 更改。
此重复请求的数量由 TIM1 重复计数器定义,每 4 个更新请求,TIM1 通道 3 占空比更改为 aCCValue_Buffer定义的下一个新值。
在主程序开始时,调用 HAL_Init() 函数来重置所有外围设备,
初始化 Flash 接口和系统。
SystemClock_Config() 函数用于配置 STM32U083RCTx 设备的系统时钟:CPU 频率为 48 MHz
定时器配置图如下:

软件代码如下:
/* Compute the value of ARR register to generate signal frequency at 17.57 Khz */
uwTimerPeriod = (uint32_t)((SystemCoreClock / 1000) - 1);
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_TIM1_Init();
/* USER CODE BEGIN 2 */
/* Compute CCR1 value to generate a duty cycle at 75% */
aCCValue_Buffer[0] = (uint32_t)(((uint32_t) 75 * (uwTimerPeriod - 1)) / 100);
/* Compute CCR2 value to generate a duty cycle at 50% */
aCCValue_Buffer[1] = (uint32_t)(((uint32_t) 50 * (uwTimerPeriod - 1)) / 100);
/* Compute CCR3 value to generate a duty cycle at 25% */
aCCValue_Buffer[2] = (uint32_t)(((uint32_t) 25 * (uwTimerPeriod - 1)) / 100);
/*## Start PWM signal generation in DMA mode ############################*/
if (HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_3, aCCValue_Buffer, 3) != HAL_OK)
{
/* Starting Error */
Error_Handler();
}定时器1的初始化部分:
/**
* @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_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {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 = uwTimerPeriod;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 3;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 0;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.BreakFilter = 0;
sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT;
sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;
sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH;
sBreakDeadTimeConfig.Break2Filter = 0;
sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM1_Init 2 */
/* USER CODE END TIM1_Init 2 */
HAL_TIM_MspPostInit(&htim1);
}DMA的初始化如下:
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Ch4_7_DMA2_Ch1_5_DMAMUX_OVR_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Ch4_7_DMA2_Ch1_5_DMAMUX_OVR_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Ch4_7_DMA2_Ch1_5_DMAMUX_OVR_IRQn);
}使用HAL库操作DMA时候,我们只需要在cube中配置DMA的传输方向就可以。不像标准库的底层驱动一样
使用DMA更新脉宽的学习过程中的记录如下:
上面提到的 PWM 信号频率值是理论值(当系统时钟频率正好为 48 MHz 时获得)。由于生成的系统 clock frequency 可能因板而异,因此观察到的 PWM 信号频率可能略有不同。
使用 HAL_Delay() 时必须小心,此函数根据 SysTick ISR 中递增的变量提供准确的延迟(以毫秒为单位)。这意味着,如果 HAL_Delay() 是从外围 ISR 进程调用的,则 SysTick 中断必须具有更高的优先级(数值较低)。
此示例需要确保 SysTick 时基始终设置为 1 毫秒,才能执行正确的 HAL 操作。
PWM输出可变脉宽的波形如下图所示:

我要赚赏金
