目录
概述
1 系统框架结构
1.1 框架结构介绍
1.2 STM32 Cube配置PWM参数
2 软件实现
2.1 STM32Cube生成项目
2.2 PWM功能的User函数接口
3 测试
3.1 编写测试函数
3.2 功能测试
概述
本文主要介绍使用STM32定时器TIMER-8功能生成4路PWM,用于控制两路电机的运行状态,笔者使用STM32Cube工具配置定时器的相关参数,用于参数PWM信号,并编写测试函数验证其功能。还是用逻辑分析仪捕捉波形,以验证其控制逻辑是否符合设计需求。
1 系统框架结构
1.1 框架结构介绍
使用定时器TIMER8产生4路PWN控制信号,用于控制电机的正转或者反转
电机-1:
CH1 控制电机驱动器 IN1
CH2 控制电机驱动器 IN2
电机-2:
CH3 控制电机驱动器 IN1
CH4 控制电机驱动器 IN2
1.2 STM32 Cube配置PWM参数
1)配置通道参数,选择TIM8,使能4路PWM信号
其对应的IO接口如下:
GPIO配置参数:
2)配置参数
Prescaler 配置为71,定时器TIM8的基准工作频率为 1 M Hz
Count Mode: 配置为up,
Counter Period: 9999 , 定时器重载计数周期为 10ms
3) 使能通道, 通道参数选择默认值,工作参数在程序中定义
2 软件实现
2.1 STM32Cube生成项目
完成项目参数配置之后,即可点击STM32Cube 上的GENERATE PROJECT生产项目代码,项目结构如下,在User/Core目录下可以找到tim.c文件,和PWM相关的配置代码如下,这部分代码不需要程序员编写,STM32Cube会自动生成,但作为一名合格的程序员,应该了解该函数具体干了哪些事情。
该程序主要配置了4个结构体:
1)TIM_ClockConfigTypeDef sClockSourceConfig = {0};
配置定时器的工作时钟
2) TIM_MasterConfigTypeDef sMasterConfig = {0};配置定时器触发模式
3)TIM_OC_InitTypeDef sConfigOC = {0};配置PWM的相关参数
4) TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};配置死锁时间
/* TIM8 init function */
void MX_TIM8_Init(void)
{
/* USER CODE BEGIN TIM8_Init 0 */
/* USER CODE END TIM8_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
/* USER CODE BEGIN TIM8_Init 1 */
/* USER CODE END TIM8_Init 1 */
htim8.Instance = TIM8;
htim8.Init.Prescaler = 71;
htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
htim8.Init.Period = 9999;
htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim8.Init.RepetitionCounter = 0;
htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim8) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim8, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim8) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &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(&htim8, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_4) != 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.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM8_Init 2 */
/* USER CODE END TIM8_Init 2 */
HAL_TIM_MspPostInit(&htim8);
}
2.2 PWM功能的User函数接口
1)初始化函数接口
代码53行:停止定时器
代码54~58行:启动对应通道的PWM
代码60~64行:设置对应通道的占空比
函数源代码:
void pwm_ctrl_Init( void )
{
HAL_TIM_Base_Stop( &htim8 );
HAL_TIM_PWM_Start( &htim8, TIM_CHANNEL_1); // PC6
HAL_TIM_PWM_Start( &htim8, TIM_CHANNEL_2); // PC7
HAL_TIM_PWM_Start( &htim8, TIM_CHANNEL_3); // PC8
HAL_TIM_PWM_Start( &htim8, TIM_CHANNEL_4); // PC9
HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_1);
HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_2);
HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_3);
HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_4);
}
2)启动定时器函数
调用该函数后,定时器启动起来,此时,只需配置占空比就能得到所需的波形
void motor_enable(void)
{
HAL_TIM_Base_Start( &htim8 );
}
3)工作波形控制函数
该函数通道控制不同通道的输入或者输出信号就能控制电机的正转或者反转,前进或者后退
void Motor_CtrlAct( uint8_t type )
{
switch( type )
{
case IDLE:
break;
case STOP_RUN:
HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_1);
HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_2);
HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_3);
HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_4);
break;
case LEFT_RUN:
HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_1);
HAL_TIM_SetPWM_Pulse( 2000, TIM_CHANNEL_2);
HAL_TIM_SetPWM_Pulse( 3000, TIM_CHANNEL_3);
HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_4);
break;
case RIGHT_RUN:
HAL_TIM_SetPWM_Pulse( 3000, TIM_CHANNEL_1);
HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_2);
HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_3);
HAL_TIM_SetPWM_Pulse( 2000, TIM_CHANNEL_4);
break;
case UP_RUN:
HAL_TIM_SetPWM_Pulse( 3000, TIM_CHANNEL_1);
HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_2);
HAL_TIM_SetPWM_Pulse( 3000, TIM_CHANNEL_3);
HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_4);
break;
case DOWN_RUN:
HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_1);
HAL_TIM_SetPWM_Pulse( 3000, TIM_CHANNEL_2);
HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_3);
HAL_TIM_SetPWM_Pulse( 3000, TIM_CHANNEL_4);
break;
}
}
3 测试
3.1 编写测试函数
通过串口接收一个指令数据,以控制PWN的信号,命令参数如下:
enum RUN_STATE
{
IDLE = 0,
STOP_RUN=1,
LEFT_RUN,
RIGHT_RUN,
UP_RUN,
DOWN_RUN,
};
在串口的回调函数中,调用上面的函数
详细代码如下:
void protocol_data_recvByte(uint8_t data )
{
recv_buf[stru_protocl.datCnt++] = data;
Motor_CtrlAct( data );
if( stru_protocl.datCnt >= PROT_FRAME_LEN_RECV)
stru_protocl.datCnt = 0;
}
void UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
uint8_t data;
uint32_t isrflags = READ_REG(huart->Instance->SR);
uint32_t cr1its = READ_REG(huart->Instance->CR1);
if( huart->Instance==USART1 )
{
/* UART in mode Receiver -------------------------------------------------*/
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
data = huart->Instance->DR;
protocol_data_recvByte(data);
}
SET_BIT(huart->Instance->CR1, USART_CR1_RXNEIE);
CLEAR_BIT(huart->Instance->SR, USART_SR_ORE);
}
}
3.2 功能测试
使用逻辑分析仪捕捉PWM的波形
1)发送命令:STOP_RUN = 0x01
2)发送命令: LEFT_RUN=0x02
3)发送命令: RIGHT_RUN=0x03
4) 发送命令: UP_RUN=0x04
5) 发送命令: DOWN_RUN=0x05