单片机 :STM32F407
开发板:DMF407电机开发板
平台:keil V5.31
HSE 为8MHZ
HSI为16MHZ
一、梯形加减速


主函数:
int main(void)
{
uint8_t key,t;
char buf[32];
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
key_init(); /* 初始化按键 */
lcd_init(); /* 初始化LCD */
stepper_init(0xFFFF, 84 - 1); /* 168 000 000 / 84 = 2000 000 2M的计数频率 */
g_point_color = WHITE;
g_back_color = BLACK;
lcd_show_string(10,10,200,16,16,"Stepper Motor Test",g_point_color);/* 显示提示信息 */
lcd_show_string(10,30,200,16,16,"KEY0:Start", g_point_color); /* 显示提示信息 */
lcd_show_string(10,50,200,16,16,"KEY1:Set++",g_point_color); /* 显示提示信息 */
lcd_show_string(10,70,200,16,16,"KEY2:Set--",g_point_color); /* 显示提示信息 */
printf("KEY0开启梯形加减速\r\n");
printf("KEY1增加步数\r\n");
printf("KEY2减少步数\r\n");
while (1)
{
t++;
if(t % 20 == 0)
{
sprintf(buf,"Set_Aangle:%d ",g_step_angle); /* 设置的旋转位置(角度)*/
lcd_show_string(10,90,200,16,16,buf,g_point_color);
sprintf(buf,"Add_Aangle:%.2f ",g_add_pulse_count*0.225); /* 累计旋转的角度 */
lcd_show_string(10,110,200,16,16,buf,g_point_color);
LED0_TOGGLE(); /* LED0(红灯) 翻转 */
}
delay_ms(10);
key = key_scan(0);
if(key == KEY0_PRES) /* 开启梯形加减速 */
{
create_t_ctrl_param(SPR*g_step_angle, g_step_accel, g_step_decel, g_set_speed);
g_add_pulse_count=0;
}
else if(key == KEY1_PRES) /* 增加步数 */
{
g_step_angle++;
if(g_step_angle>100) g_step_angle=1;
}
else if(key == KEY2_PRES) /* 减少步数 */
{
g_step_angle--;
if(g_step_angle<1) g_step_angle=100;
}
}
}
电机:
void stepper_init(uint16_t arr, uint16_t psc)
{
GPIO_InitTypeDef gpio_init_struct;
STEPPER_DIR1_GPIO_CLK_ENABLE(); /* DIR1时钟使能 */
STEPPER_DIR2_GPIO_CLK_ENABLE(); /* DIR2时钟使能 */
STEPPER_DIR3_GPIO_CLK_ENABLE(); /* DIR3时钟使能 */
STEPPER_DIR4_GPIO_CLK_ENABLE(); /* DIR4时钟使能 */
STEPPER_EN1_GPIO_CLK_ENABLE(); /* EN1时钟使能 */
STEPPER_EN2_GPIO_CLK_ENABLE(); /* EN2时钟使能 */
STEPPER_EN3_GPIO_CLK_ENABLE(); /* EN3时钟使能 */
STEPPER_EN4_GPIO_CLK_ENABLE(); /* EN4时钟使能 */
gpio_init_struct.Pin = STEPPER_DIR1_GPIO_PIN; /* DIR1引脚 */
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */
gpio_init_struct.Pull = GPIO_PULLDOWN; /* 下拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_LOW; /* 低速 */
HAL_GPIO_Init(STEPPER_DIR1_GPIO_PORT, &gpio_init_struct); /* 初始化DIR1引脚 */
gpio_init_struct.Pin = STEPPER_DIR2_GPIO_PIN; /* DIR2引脚 */
HAL_GPIO_Init(STEPPER_DIR2_GPIO_PORT, &gpio_init_struct); /* 初始化DIR2引脚 */
gpio_init_struct.Pin = STEPPER_DIR3_GPIO_PIN; /* DIR3引脚 */
HAL_GPIO_Init(STEPPER_DIR3_GPIO_PORT, &gpio_init_struct); /* 初始化DIR3引脚 */
gpio_init_struct.Pin = STEPPER_DIR4_GPIO_PIN; /* DIR4引脚 */
HAL_GPIO_Init(STEPPER_DIR4_GPIO_PORT, &gpio_init_struct); /* 初始化DIR4引脚 */
/* 脱机引脚初始化 */
gpio_init_struct.Pin = STEPPER_EN1_GPIO_PIN; /* EN1引脚 */
HAL_GPIO_Init(STEPPER_EN1_GPIO_PORT, &gpio_init_struct); /* 初始化EN1引脚 */
gpio_init_struct.Pin = STEPPER_EN2_GPIO_PIN; /* EN2引脚 */
HAL_GPIO_Init(STEPPER_EN2_GPIO_PORT, &gpio_init_struct); /* 初始化EN2引脚 */
gpio_init_struct.Pin = STEPPER_EN3_GPIO_PIN; /* EN3引脚 */
HAL_GPIO_Init(STEPPER_EN3_GPIO_PORT, &gpio_init_struct); /* 初始化EN3引脚 */
gpio_init_struct.Pin = STEPPER_EN4_GPIO_PIN; /* EN4引脚 */
HAL_GPIO_Init(STEPPER_EN4_GPIO_PORT, &gpio_init_struct); /* 初始化EN4引脚 */
atim_timx_oc_chy_init(arr, psc); /* 初始化PUL引脚,以及脉冲模式等 */
}
/**
* @brief 开启步进电机
* @param motor_num: 步进电机接口序号
* @retval 无
*/
void stepper_star(uint8_t motor_num)
{
/* 开启对应PWM通道 */
switch(motor_num)
{
case STEPPER_MOTOR_1 :
{
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM1||g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM2)
{
HAL_TIM_PWM_Start(&g_atimx_handle, ATIM_TIMX_PWM_CH1);
}
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_TOGGLE)
{
HAL_TIM_OC_Start_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH1);
}
break;
}
case STEPPER_MOTOR_2 :
{
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM1||g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM2)
{
HAL_TIM_PWM_Start(&g_atimx_handle, ATIM_TIMX_PWM_CH2);
}
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_TOGGLE)
{
HAL_TIM_OC_Start_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH2);
}
break;
}
case STEPPER_MOTOR_3 :
{
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM1||g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM2)
{
HAL_TIM_PWM_Start(&g_atimx_handle, ATIM_TIMX_PWM_CH3);
}
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_TOGGLE)
{
HAL_TIM_OC_Start_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH3);
}
break;
}
case STEPPER_MOTOR_4 :
{
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM1||g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM2)
{
HAL_TIM_PWM_Start(&g_atimx_handle, ATIM_TIMX_PWM_CH4);
}
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_TOGGLE)
{
HAL_TIM_OC_Start_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH4);
}
break;
}
default : break;
}
}
/**
* @brief 关闭步进电机
* @param motor_num: 步进电机接口序号
* @retval 无
*/
void stepper_stop(uint8_t motor_num)
{
/* 关闭对应PWM通道 */
switch(motor_num)
{
case STEPPER_MOTOR_1 :
{
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM1||g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM2)
{
HAL_TIM_PWM_Stop(&g_atimx_handle, ATIM_TIMX_PWM_CH1);
}
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_TOGGLE)
{
HAL_TIM_OC_Stop_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH1);
}
break;
}
case STEPPER_MOTOR_2 :
{
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM1||g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM2)
{
HAL_TIM_PWM_Stop(&g_atimx_handle, ATIM_TIMX_PWM_CH2);
}
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_TOGGLE)
{
HAL_TIM_OC_Stop_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH2);
}
break;
}
case STEPPER_MOTOR_3 :
{
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM1||g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM2)
{
HAL_TIM_PWM_Stop(&g_atimx_handle, ATIM_TIMX_PWM_CH3);
}
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_TOGGLE)
{
HAL_TIM_OC_Stop_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH3);
}
break;
}
case STEPPER_MOTOR_4 :
{
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM1||g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM2)
{
HAL_TIM_PWM_Stop(&g_atimx_handle, ATIM_TIMX_PWM_CH4);
}
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_TOGGLE)
{
HAL_TIM_OC_Stop_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH4);
}
break;
}
default : break;
}
}
/********************************************梯形加减速***********************************************/
speedRampData g_srd = {STOP,CW,0,0,0,0,0}; /* 加减速变量 */
__IO int32_t g_step_position = 0; /* 当前位置 */
__IO uint8_t g_motion_sta = 0; /* 是否在运动?0:停止,1:运动 */
__IO uint32_t g_add_pulse_count = 0; /* 脉冲个数累计 */
/*
* @brief 生成梯形运动控制参数
* @param step:移动的步数 (正数为顺时针,负数为逆时针).
* @param accel 加速度,实际值为accel*0.1*rad/sec^2 10倍并且2个脉冲算一个完整的周期
* @param decel 减速度,实际值为decel*0.1*rad/sec^2
* @param speed 最大速度,实际值为speed*0.1*rad/sec
* @retval 无
*/
void create_t_ctrl_param(int32_t step, uint32_t accel, uint32_t decel, uint32_t speed)
{
__IO uint16_t tim_count; /* 达到最大速度时的步数*/
__IO uint32_t max_s_lim; /* 必须要开始减速的步数(如果加速没有达到最大速度)*/
__IO uint32_t accel_lim;
if(g_motion_sta != STOP) /* 只允许步进电机在停止的时候才继续*/
return;
if(step < 0) /* 步数为负数 */
{
g_srd.dir = CCW; /* 逆时针方向旋转 */
ST3_DIR(CCW);
step = -step; /* 获取步数绝对值 */
}
else
{
g_srd.dir = CW; /* 顺时针方向旋转 */
ST3_DIR(CW);
}
if(step == 1) /* 步数为1 */
{
g_srd.accel_count = -1; /* 只移动一步 */
g_srd.run_state = DECEL; /* 减速状态. */
g_srd.step_delay = 1000; /* 默认速度 */
}
else if(step != 0) /* 如果目标运动步数不为0*/
{
/*设置最大速度极限, 计算得到min_delay用于定时器的计数器的值 min_delay = (alpha / t)/ w*/
g_srd.min_delay = (int32_t)(A_T_x10 /speed); //匀速运行时的计数值
/* 通过计算第一个(c0) 的步进延时来设定加速度,其中accel单位为0.1rad/sec^2
step_delay = 1/tt * sqrt(2*alpha/accel)
step_delay = ( tfreq*0.69/10 )*10 * sqrt( (2*alpha*100000) / (accel*10) )/100 */
g_srd.step_delay = (int32_t)((T1_FREQ_148 * sqrt(A_SQ / accel))/10); /* c0 */
max_s_lim = (uint32_t)(speed*speed / (A_x200*accel/10));/* 计算多少步之后达到最大速度的限制 max_s_lim = speed^2 / (2*alpha*accel) */
if(max_s_lim == 0) /* 如果达到最大速度小于0.5步,我们将四舍五入为0,但实际我们必须移动至少一步才能达到想要的速度 */
{
max_s_lim = 1;
}
accel_lim = (uint32_t)(step*decel/(accel+decel)); /* 这里不限制最大速度 计算多少步之后我们必须开始减速 n1 = (n1+n2)decel / (accel + decel) */
if(accel_lim == 0) /* 不足一步 按一步处理*/
{
accel_lim = 1;
}
if(accel_lim <= max_s_lim) /* 加速阶段到不了最大速度就得减速。。。使用限制条件我们可以计算出减速阶段步数 */
{
g_srd.decel_val = accel_lim - step; /* 减速段的步数 */
}
else
{
g_srd.decel_val = -(max_s_lim*accel/decel); /* 减速段的步数 */
}
if(g_srd.decel_val == 0) /* 不足一步 按一步处理 */
{
g_srd.decel_val = -1;
}
g_srd.decel_start = step + g_srd.decel_val; /* 计算开始减速时的步数 */
if(g_srd.step_delay <= g_srd.min_delay) /* 如果一开始c0的速度比匀速段速度还大,就不需要进行加速运动,直接进入匀速 */
{
g_srd.step_delay = g_srd.min_delay;
g_srd.run_state = RUN;
}
else
{
g_srd.run_state = ACCEL;
}
g_srd.accel_count = 0; /* 复位加减速计数值 */
}
g_motion_sta = 1; /* 电机为运动状态 */
ST3_EN(EN_ON);
tim_count=__HAL_TIM_GET_COUNTER(&g_atimx_handle);
__HAL_TIM_SET_COMPARE(&g_atimx_handle,ATIM_TIMX_PWM_CH3,tim_count+g_srd.step_delay/2); /* 设置定时器比较值 */
HAL_TIM_OC_Start_IT(&g_atimx_handle,ATIM_TIMX_PWM_CH3); /* 使能定时器通道 */
}
/**
* @brief 定时器比较中断
* @param htim:定时器句柄指针
* @note 无
* @retval 无
*/
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
__IO uint32_t tim_count = 0;
__IO uint32_t tmp = 0;
uint16_t new_step_delay = 0; /* 保存新(下)一个延时周期 */
__IO static uint16_t last_accel_delay = 0; /* 加速过程中最后一次延时(脉冲周期) */
__IO static uint32_t step_count = 0; /* 总移动步数计数器*/
__IO static int32_t rest = 0; /* 记录new_step_delay中的余数,提高下一步计算的精度 */
__IO static uint8_t i = 0; /* 定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲 */
if(htim->Instance==TIM8)
{
tim_count = __HAL_TIM_GET_COUNTER(&g_atimx_handle);
tmp = tim_count + g_srd.step_delay/2; /* 整个C值里边是需要翻转两次的所以需要除以2 */
__HAL_TIM_SET_COMPARE(&g_atimx_handle,ATIM_TIMX_PWM_CH3,tmp);
i++; /* 定时器中断次数计数值 */
if(i == 2) /* 2次,说明已经输出一个完整脉冲 */
{
i = 0; /* 清零定时器中断次数计数值 */
switch(g_srd.run_state) /* 加减速曲线阶段 */
{
case STOP:
step_count = 0; /* 清零步数计数器 */
rest = 0; /* 清零余值 */
/* 关闭通道*/
HAL_TIM_OC_Stop_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH3);
ST3_EN(EN_OFF);
g_motion_sta = 0; /* 电机为停止状态 */
break;
case ACCEL:
g_add_pulse_count++; /* 只用于记录相对位置转动了多少度 */
step_count++; /* 步数加1*/
if(g_srd.dir == CW)
{
g_step_position++; /* 绝对位置加1 记录绝对位置转动多少度*/
}
else
{
g_step_position--; /* 绝对位置减1*/
}
g_srd.accel_count++; /* 加速计数值加1*/
new_step_delay = g_srd.step_delay - (((2 *g_srd.step_delay) + rest)/(4 * g_srd.accel_count + 1));/* 计算新(下)一步脉冲周期(时间间隔) */
rest = ((2 * g_srd.step_delay)+rest)%(4 * g_srd.accel_count + 1); /* 计算余数,下次计算补上余数,减少误差 */
if(step_count >= g_srd.decel_start) /* 检查是否到了需要减速的步数 */
{
g_srd.accel_count = g_srd.decel_val; /* 加速计数值为减速阶段计数值的初始值 */
g_srd.run_state = DECEL; /* 下个脉冲进入减速阶段 */
}
else if(new_step_delay <= g_srd.min_delay) /* 检查是否到达期望的最大速度 计数值越小速度越快,当你的速度和最大速度相等或更快就进入匀速*/
{
last_accel_delay = new_step_delay; /* 保存加速过程中最后一次延时(脉冲周期)*/
new_step_delay = g_srd.min_delay; /* 使用min_delay(对应最大速度speed)*/
rest = 0; /* 清零余值 */
g_srd.run_state = RUN; /* 设置为匀速运行状态 */
}
break;
case RUN:
g_add_pulse_count++;
step_count++; /* 步数加1 */
if(g_srd.dir == CW)
{
g_step_position++; /* 绝对位置加1 */
}
else
{
g_step_position--; /* 绝对位置减1*/
}
new_step_delay = g_srd.min_delay; /* 使用min_delay(对应最大速度speed)*/
if(step_count >= g_srd.decel_start) /* 需要开始减速 */
{
g_srd.accel_count = g_srd.decel_val; /* 减速步数做为加速计数值 */
new_step_delay = last_accel_delay; /* 加阶段最后的延时做为减速阶段的起始延时(脉冲周期) */
g_srd.run_state = DECEL; /* 状态改变为减速 */
}
break;
case DECEL:
step_count++; /* 步数加1 */
g_add_pulse_count++;
if(g_srd.dir == CW)
{
g_step_position++; /* 绝对位置加1 */
}
else
{
g_step_position--; /* 绝对位置减1 */
}
g_srd.accel_count++;
new_step_delay = g_srd.step_delay - (((2 * g_srd.step_delay) + rest)/(4 * g_srd.accel_count + 1)); /* 计算新(下)一步脉冲周期(时间间隔) */
rest = ((2 * g_srd.step_delay)+rest)%(4 * g_srd.accel_count + 1); /* 计算余数,下次计算补上余数,减少误差 */
/* 检查是否为最后一步 */
if(g_srd.accel_count >= 0) /* 判断减速步数是否从负值加到0是的话 减速完成 */
{
g_srd.run_state = STOP;
}
break;
}
g_srd.step_delay = new_step_delay; /* 为下个(新的)延时(脉冲周期)赋值 */
}
}
}
定时器
void atim_timx_oc_chy_init(uint16_t arr, uint16_t psc)
{
ATIM_TIMX_PWM_CHY_CLK_ENABLE(); /* TIMX 时钟使能 */
g_atimx_handle.Instance = ATIM_TIMX_PWM; /* 定时器x */
g_atimx_handle.Init.Prescaler = psc; /* 定时器分频 */
g_atimx_handle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 向上计数模式 */
g_atimx_handle.Init.Period = arr; /* 自动重装载值 */
g_atimx_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; /* 分频因子 */
g_atimx_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; /*使能TIMx_ARR进行缓冲*/
g_atimx_handle.Init.RepetitionCounter = 0; /* 开始时不计数*/
HAL_TIM_OC_Init(&g_atimx_handle); /* 初始化PWM */
g_atimx_oc_chy_handle.OCMode = TIM_OCMODE_TOGGLE; /* 翻转模式 */
g_atimx_oc_chy_handle.Pulse = 0;
g_atimx_oc_chy_handle.OCPolarity = TIM_OCPOLARITY_HIGH; /* 输出比较极性为高 */
g_atimx_oc_chy_handle.OCNPolarity = TIM_OCNPOLARITY_LOW;
g_atimx_oc_chy_handle.OCFastMode = TIM_OCFAST_DISABLE;
g_atimx_oc_chy_handle.OCIdleState = TIM_OCIDLESTATE_RESET;
g_atimx_oc_chy_handle.OCNIdleState = TIM_OCNIDLESTATE_RESET;
HAL_TIM_OC_ConfigChannel(&g_atimx_handle, &g_atimx_oc_chy_handle, ATIM_TIMX_PWM_CH1); /* 配置TIMx通道y */
HAL_TIM_OC_ConfigChannel(&g_atimx_handle, &g_atimx_oc_chy_handle, ATIM_TIMX_PWM_CH2); /* 配置TIMx通道y */
HAL_TIM_OC_ConfigChannel(&g_atimx_handle, &g_atimx_oc_chy_handle, ATIM_TIMX_PWM_CH3); /* 配置TIMx通道y */
HAL_TIM_OC_ConfigChannel(&g_atimx_handle, &g_atimx_oc_chy_handle, ATIM_TIMX_PWM_CH4); /* 配置TIMx通道y */
HAL_TIM_Base_Start(&g_atimx_handle);
}
/**
* @brief 定时器底层驱动,时钟使能,引脚配置
此函数会被HAL_TIM_OC_Init()调用
* @param htim:定时器句柄
* @retval 无
*/
void HAL_TIM_OC_MspInit(TIM_HandleTypeDef *htim)
{
if (htim->Instance == ATIM_TIMX_PWM)
{
GPIO_InitTypeDef gpio_init_struct;
ATIM_TIMX_PWM_CHY_CLK_ENABLE(); /* 开启通道y的GPIO时钟 */
ATIM_TIMX_PWM_CH1_GPIO_CLK_ENABLE(); /* IO时钟使能 */
ATIM_TIMX_PWM_CH2_GPIO_CLK_ENABLE(); /* IO时钟使能 */
ATIM_TIMX_PWM_CH3_GPIO_CLK_ENABLE(); /* IO时钟使能 */
ATIM_TIMX_PWM_CH4_GPIO_CLK_ENABLE(); /* IO时钟使能 */
gpio_init_struct.Pin = ATIM_TIMX_PWM_CH1_GPIO_PIN; /* 通道y的GPIO口 */
gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
gpio_init_struct.Alternate = ATIM_TIMX_PWM_CHY_GPIO_AF; /* 端口复用 */
HAL_GPIO_Init(ATIM_TIMX_PWM_CH1_GPIO_PORT, &gpio_init_struct);
gpio_init_struct.Pin = ATIM_TIMX_PWM_CH2_GPIO_PIN; /* 通道y的GPIO口 */
HAL_GPIO_Init(ATIM_TIMX_PWM_CH2_GPIO_PORT, &gpio_init_struct);
gpio_init_struct.Pin = ATIM_TIMX_PWM_CH3_GPIO_PIN; /* 通道y的GPIO口 */
HAL_GPIO_Init(ATIM_TIMX_PWM_CH3_GPIO_PORT, &gpio_init_struct);
gpio_init_struct.Pin = ATIM_TIMX_PWM_CH4_GPIO_PIN; /* 通道y的GPIO口 */
HAL_GPIO_Init(ATIM_TIMX_PWM_CH4_GPIO_PORT, &gpio_init_struct);
HAL_NVIC_SetPriority(ATIM_TIMX_INT_IRQn, 2, 2);
HAL_NVIC_EnableIRQ(ATIM_TIMX_INT_IRQn);
}
}
/**
* @brief 高级定时器TIMX NPWM中断服务函数
* @param 无
* @retval 无
*/
void ATIM_TIMX_INT_IRQHandler(void)
{
HAL_TIM_IRQHandler(&g_atimx_handle); /* 定时器共用处理函数 */
}
测试结果:


二、S形加减速实验





主函数:
int main(void)
{
uint8_t key,t;
char buf[32];
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
key_init(); /* 初始化按键 */
lcd_init(); /* 初始化LCD */
stepper_init(0xFFFF, 168 - 1); /* 168 000 000 / 168 = 1000 000 1Mhz的计数频率 */
g_point_color = WHITE;
g_back_color = BLACK;
lcd_show_string(10,10,200,16,16,"Stepper Motor Test", g_point_color);
lcd_show_string(10,30,200,16,16,"KEY0:Run Once", g_point_color);
lcd_show_string(10,50,200,16,16,"KEY1:STEP ++",g_point_color);
lcd_show_string(10,70,200,16,16,"KEY2:STEP --", g_point_color);
printf("KEY0开启S形加减速\r\n");
printf("KEY1增加步数\r\n");
printf("KEY2减少步数\r\n");
while (1)
{
t++;
if(t % 20 == 0)
{
sprintf(buf,"Set_Aangle:%d ",g_step_angle); /*设置的旋转位置(角度)*/
lcd_show_string(10,90,200,16,16,buf,g_point_color);
sprintf(buf,"Add_Aangle:%.2f ",g_add_pulse_count*0.225); /*累计旋转的角度*/
lcd_show_string(10,110,200,16,16,buf,g_point_color);
LED0_TOGGLE(); /*LED0(红灯) 翻转*/
}
delay_ms(10);
key = key_scan(0);
if(key == KEY0_PRES) /* 开启电机S型加减速 */
{
if(g_motor_sta == STATE_IDLE)
{
g_add_pulse_count=0;
stepmotor_move_rel(V_START,V_END,ACCELTIME,DECEELTIME,g_step_angle*SPR );/* 一次加减速运动 */
}
}
else if(key == KEY1_PRES) /* 步数加 */
{
g_step_angle=g_step_angle+1;
if(g_step_angle>=50) g_step_angle=1;
}
else if(key == KEY2_PRES) /* 步数减 */
{
g_step_angle=g_step_angle-1;
if(g_step_angle<=1) g_step_angle=50;
}
}
}
电机:
void stepper_init(uint16_t arr, uint16_t psc)
{
GPIO_InitTypeDef gpio_init_struct;
STEPPER_DIR1_GPIO_CLK_ENABLE(); /* DIR1时钟使能 */
STEPPER_DIR2_GPIO_CLK_ENABLE(); /* DIR2时钟使能 */
STEPPER_DIR3_GPIO_CLK_ENABLE(); /* DIR3时钟使能 */
STEPPER_DIR4_GPIO_CLK_ENABLE(); /* DIR4时钟使能 */
STEPPER_EN1_GPIO_CLK_ENABLE(); /* EN1时钟使能 */
STEPPER_EN2_GPIO_CLK_ENABLE(); /* EN2时钟使能 */
STEPPER_EN3_GPIO_CLK_ENABLE(); /* EN3时钟使能 */
STEPPER_EN4_GPIO_CLK_ENABLE(); /* EN4时钟使能 */
gpio_init_struct.Pin = STEPPER_DIR1_GPIO_PIN; /* DIR1引脚 */
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */
gpio_init_struct.Pull = GPIO_PULLDOWN; /* 下拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_LOW; /* 低速 */
HAL_GPIO_Init(STEPPER_DIR1_GPIO_PORT, &gpio_init_struct); /* 初始化DIR1引脚 */
gpio_init_struct.Pin = STEPPER_DIR2_GPIO_PIN; /* DIR2引脚 */
HAL_GPIO_Init(STEPPER_DIR2_GPIO_PORT, &gpio_init_struct); /* 初始化DIR2引脚 */
gpio_init_struct.Pin = STEPPER_DIR3_GPIO_PIN; /* DIR3引脚 */
HAL_GPIO_Init(STEPPER_DIR3_GPIO_PORT, &gpio_init_struct); /* 初始化DIR3引脚 */
gpio_init_struct.Pin = STEPPER_DIR4_GPIO_PIN; /* DIR4引脚 */
HAL_GPIO_Init(STEPPER_DIR4_GPIO_PORT, &gpio_init_struct); /* 初始化DIR4引脚 */
/* 脱机引脚初始化 */
gpio_init_struct.Pin = STEPPER_EN1_GPIO_PIN; /* EN1引脚 */
HAL_GPIO_Init(STEPPER_EN1_GPIO_PORT, &gpio_init_struct); /* 初始化EN1引脚 */
gpio_init_struct.Pin = STEPPER_EN2_GPIO_PIN; /* EN2引脚 */
HAL_GPIO_Init(STEPPER_EN2_GPIO_PORT, &gpio_init_struct); /* 初始化EN2引脚 */
gpio_init_struct.Pin = STEPPER_EN3_GPIO_PIN; /* EN3引脚 */
HAL_GPIO_Init(STEPPER_EN3_GPIO_PORT, &gpio_init_struct); /* 初始化EN3引脚 */
gpio_init_struct.Pin = STEPPER_EN4_GPIO_PIN; /* EN4引脚 */
HAL_GPIO_Init(STEPPER_EN4_GPIO_PORT, &gpio_init_struct); /* 初始化EN4引脚 */
atim_timx_oc_chy_init(arr, psc); /* 初始化PUL引脚,以及脉冲模式等 */
}
/**
* @brief 开启步进电机
* @param motor_num: 步进电机接口序号
* @retval 无
*/
void stepper_star(uint8_t motor_num)
{
/* 开启对应PWM通道 */
switch(motor_num)
{
case STEPPER_MOTOR_1 :
{
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM1||g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM2)
{
HAL_TIM_PWM_Start(&g_atimx_handle, ATIM_TIMX_PWM_CH1);
}
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_TOGGLE)
{
HAL_TIM_OC_Start_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH1);
}
break;
}
case STEPPER_MOTOR_2 :
{
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM1||g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM2)
{
HAL_TIM_PWM_Start(&g_atimx_handle, ATIM_TIMX_PWM_CH2);
}
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_TOGGLE)
{
HAL_TIM_OC_Start_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH2);
}
break;
}
case STEPPER_MOTOR_3 :
{
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM1||g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM2)
{
HAL_TIM_PWM_Start(&g_atimx_handle, ATIM_TIMX_PWM_CH3);
}
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_TOGGLE)
{
HAL_TIM_OC_Start_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH3);
}
break;
}
case STEPPER_MOTOR_4 :
{
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM1||g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM2)
{
HAL_TIM_PWM_Start(&g_atimx_handle, ATIM_TIMX_PWM_CH4);
}
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_TOGGLE)
{
HAL_TIM_OC_Start_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH4);
}
break;
}
default : break;
}
}
/**
* @brief 关闭步进电机
* @param motor_num: 步进电机接口序号
* @retval 无
*/
void stepper_stop(uint8_t motor_num)
{
/* 关闭对应PWM通道 */
switch(motor_num)
{
case STEPPER_MOTOR_1 :
{
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM1||g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM2)
{
HAL_TIM_PWM_Stop(&g_atimx_handle, ATIM_TIMX_PWM_CH1);
}
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_TOGGLE)
{
HAL_TIM_OC_Stop_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH1);
}
break;
}
case STEPPER_MOTOR_2 :
{
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM1||g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM2)
{
HAL_TIM_PWM_Stop(&g_atimx_handle, ATIM_TIMX_PWM_CH2);
}
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_TOGGLE)
{
HAL_TIM_OC_Stop_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH2);
}
break;
}
case STEPPER_MOTOR_3 :
{
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM1||g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM2)
{
HAL_TIM_PWM_Stop(&g_atimx_handle, ATIM_TIMX_PWM_CH3);
}
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_TOGGLE)
{
HAL_TIM_OC_Stop_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH3);
}
break;
}
case STEPPER_MOTOR_4 :
{
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM1||g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_PWM2)
{
HAL_TIM_PWM_Stop(&g_atimx_handle, ATIM_TIMX_PWM_CH4);
}
if(g_atimx_oc_chy_handle.OCMode == TIM_OCMODE_TOGGLE)
{
HAL_TIM_OC_Stop_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH4);
}
break;
}
default : break;
}
}
/****************************************S型加减速运动*****************************************************/
volatile int32_t g_step_pos = 0; /* 当前位置 */
volatile uint16_t g_toggle_pulse = 0; /* 脉冲频率控制 */
motor_state_typedef g_motor_sta = STATE_IDLE; /* 电机状态 */
speed_calc_t g_calc_t = {0} ;
__IO uint32_t g_add_pulse_count=0; /* 脉冲个数累计 */
/**
* @brief 速度表计算函数
* @param vo,初速度;vt,末速度;time,加速时间
* @retval TRUE:成功;FALSE:失败
*/
uint8_t calc_speed(int32_t vo, int32_t vt, float time)
{
uint8_t is_dec = FALSE;
int32_t i = 0;
int32_t vm =0; /* 中间点速度 */
int32_t inc_acc_stp = 0; /* 加加速所需的步数 */
int32_t dec_acc_stp = 0; /* 减加速所需的步数 */
int32_t accel_step = 0; /* 加速或减速需要的步数 */
float jerk = 0; /* 加加速度 */
float ti = 0; /* 时间间隔 dt */
float sum_t = 0; /* 时间累加量 */
float delta_v = 0; /* 速度的增量dv */
float ti_cube = 0; /* 时间间隔的立方 */
float *velocity_tab = NULL; /* 速度表格指针 */
if(vo > vt ) /* 初速度比末速度大,做减速运动,数值变化跟加速运动相同 */
{ /* 只是建表的时候注意将速度倒序 */
is_dec = TRUE; /* 减速段 */
g_calc_t.vo = ROUNDPS_2_STEPPS(vt); /* 转换单位 起速:step/s */
g_calc_t.vt = ROUNDPS_2_STEPPS(vo); /* 转换单位 末速:step/s */
}
else
{
is_dec = FALSE; /* 加速段 */
g_calc_t.vo = ROUNDPS_2_STEPPS(vo);
g_calc_t.vt = ROUNDPS_2_STEPPS(vt);
}
time = ACCEL_TIME(time); /* 得到加加速段的时间 */
printf("time=%f\r\n",time);
vm = (g_calc_t.vo + g_calc_t.vt) / 2 ; /* 计算中点速度 */
jerk = fabs(2.0f * (vm - g_calc_t.vo) / (time * time)); /* 根据中点速度计算加加速度 */
inc_acc_stp = (int32_t)(g_calc_t.vo * time + INCACCELSTEP(jerk,time)); /* 加加速需要的步数 */
dec_acc_stp = (int32_t)((g_calc_t.vt + g_calc_t.vo) * time - inc_acc_stp); /* 减加速需要的步数 S = vt * time - S1 */
/* 申请内存空间存放速度表 */
accel_step = dec_acc_stp + inc_acc_stp; /* 加速需要的步数 */
if( accel_step % 2 != 0) /* 由于浮点型数据转换成整形数据带来了误差,所以这里加1 */
accel_step += 1;
/* mallo申请内存空间,记得释放 */
velocity_tab = (float*)(mymalloc(SRAMIN,((accel_step + 1) * sizeof(float))));
if(velocity_tab == NULL)
{
printf("内存不足!请修改参数\r\n");
return FALSE;
}
/*
* 目标的S型速度曲线是对时间的方程,但是在控制电机的时候则是以步进的方式控制,所以这里对V-t曲线做转换
* 得到V-S曲线,计算得到的速度表是关于步数的速度值.使得步进电机每一步都在控制当中
*/
/* 计算第一步速度,根据第一步的速度值达到下一步的时间 */
ti_cube = 6.0f * 1.0f / jerk; /* 根据位移和时间的公式S = 1/6 * J * ti^3 第1步的时间:ti^3 = 6 * 1 / jerk */
ti = pow(ti_cube,(1 / 3.0f)); /* ti */
sum_t = ti;
delta_v = 0.5f * jerk * pow(sum_t,2); /* 第一步的速度 */
velocity_tab[0] = g_calc_t.vo + delta_v;
/*****************************************************/
if( velocity_tab[0] <= SPEED_MIN ) /* 以当前定时器频率所能达到的最低速度 */
velocity_tab[0] = SPEED_MIN;
/*****************************************************/
for(i = 1; i < accel_step; i++)
{
/* 步进电机的速度就是定时器脉冲输出频率,可以计算出每一步的时间 */
/* 得到第i-1步的时间 */
ti = 1.0f / velocity_tab[i-1]; /* 电机每走一步的时间 ti = 1 / Vn-1 */
/* 加加速段速度计算 */
if( i < inc_acc_stp)
{
sum_t += ti; /* 从0开始到i的时间累积 */
delta_v = 0.5f * jerk * pow(sum_t,2); /* 速度的变化量: dV = 1/2 * jerk * ti^2 */
velocity_tab[i] = g_calc_t.vo + delta_v;/* 得到加加速段每一步对应的速度 */
/* 当最后一步的时候,时间并不严格等于time,所以这里要稍作处理,作为减加速段的时间 */
if(i == inc_acc_stp - 1)
sum_t = fabs(sum_t - time );
}
/* 减加速段速度计算 */
else
{
sum_t += ti; /* 时间累计 */
delta_v = 0.5f * jerk * pow(fabs( time - sum_t),2); /* dV = 1/2 * jerk *(T-t)^2 看这个逆向看减加速的图 */
velocity_tab[i] = g_calc_t.vt - delta_v; /* V = vt - delta_v */
if(velocity_tab[i] >= g_calc_t.vt)
{
accel_step = i;
break;
}
}
}
if(is_dec == TRUE) /* 减速 */
{
float tmp_Speed = 0;
/* 倒序排序 */
for(i = 0; i< (accel_step / 2); i++)
{
tmp_Speed = velocity_tab[i];
velocity_tab[i] = velocity_tab[accel_step-1 - i]; /* 头尾速度对换 */
velocity_tab[accel_step-1 - i] = tmp_Speed;
}
g_calc_t.decel_tab = velocity_tab; /* 减速段速度表 */
g_calc_t.decel_step = accel_step; /* 减速段的总步数 */
}
else /* 加速 */
{
g_calc_t.accel_tab = velocity_tab; /* 加速段速度表 */
g_calc_t.accel_step = accel_step; /* 加速段的总步数 */
}
return TRUE;
}
/**
* @brief S型加减速运动
* @param vo:初速度;vt:末速度;AcTime:加速时间;DeTime:减速时间;step:步数;
* @retval 无
*/
void stepmotor_move_rel(int32_t vo, int32_t vt, float AcTime,float DeTime,int32_t step)
{
if(calc_speed(vo,vt,AcTime) == FALSE) /* 计算出加速段的速度和步数 */
return;
if(calc_speed(vt,vo,DeTime) == FALSE) /* 计算出减速段的速度和步数 */
return;
if(step < 0)
{
step = -step;
ST3_DIR(CCW);
}
else
{
ST3_DIR(CW);
}
if(step >= (g_calc_t.decel_step+g_calc_t.accel_step) ) /* 当总步数大于等于加减速度步数相加时,才可以实现完整的S形加减速 */
{
g_calc_t.step = step;
g_calc_t.dec_point = g_calc_t.step - g_calc_t.decel_step; /* 开始减速的步数 */
}
else /* 步数不足以进行足够的加减速 */
{
/* 步数不足不足以运动,要把前面申请的速度表所占内存释放,以便后续可重复申请 */
myfree(SRAMIN,g_calc_t.accel_tab); /* 释放加速段速度表 */
myfree(SRAMIN,g_calc_t.decel_tab); /* 释放减速段速度表 */
printf("步数不足,参数设置错误!\r\n");
return;
}
g_calc_t.step_pos = 0;
g_motor_sta = STATE_ACCEL; /* 电机为加速状态 */
g_calc_t.ptr = g_calc_t.accel_tab; /* 把加速段的速度表存储到ptr里边 */
g_toggle_pulse = (uint32_t)(T1_FREQ/(*g_calc_t.ptr));
g_calc_t.ptr++;
__HAL_TIM_SET_COUNTER(&g_atimx_handle,0);
__HAL_TIM_SET_COMPARE(&g_atimx_handle,TIM_CHANNEL_3,(uint16_t)(g_toggle_pulse/2)); /* 设置定时器比较值 */
HAL_TIM_OC_Start_IT(&g_atimx_handle,ATIM_TIMX_PWM_CH3); /* 使能定时器通道 */
ST3_EN(EN_ON);
}
/**
* @brief 定时器比较中断
* @param htim:定时器句柄指针
* @note 无
* @retval 无
*/
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
volatile uint32_t Tim_Count = 0;
volatile uint32_t tmp = 0;
volatile float Tim_Pulse = 0;
volatile static uint8_t i = 0;
if(htim->Instance==TIM8)
{
i++; /* 定时器中断次数计数值 */
if(i == 2) /* 2次,说明已经输出一个完整脉冲 */
{
i = 0; /* 清零定时器中断次数计数值 */
g_step_pos ++; /* 当前位置 */
if((g_motor_sta!=STATE_IDLE)&&(g_motor_sta != STATE_STOP))
{
g_calc_t.step_pos ++;
}
switch(g_motor_sta)
{
case STATE_ACCEL:
g_add_pulse_count++;
Tim_Pulse = T1_FREQ / (*g_calc_t.ptr); /* 由速度表得到每一步的定时器计数值 */
g_calc_t.ptr++; /* 取速度表的下一位 */
g_toggle_pulse = (uint16_t) (Tim_Pulse / 2); /* 翻转模式C需要除以2 */
if(g_calc_t.step_pos >= g_calc_t.accel_step) /* 当大于加速段步数就进入匀速 */
{
myfree(SRAMIN,g_calc_t.accel_tab); /* 运动完要释放内存 */
g_motor_sta = STATE_AVESPEED;
}
break;
case STATE_DECEL:
g_add_pulse_count++;
Tim_Pulse = T1_FREQ / (*g_calc_t.ptr); /* 由速度表得到每一步的定时器计数值 */
g_calc_t.ptr++;
g_toggle_pulse = (uint16_t) (Tim_Pulse / 2);
if(g_calc_t.step_pos >= g_calc_t.step )
{
myfree(SRAMIN,g_calc_t.decel_tab); /* 运动完要释放内存 */
g_motor_sta = STATE_STOP;
}
break;
case STATE_AVESPEED:
g_add_pulse_count++;
Tim_Pulse = T1_FREQ /g_calc_t.vt;
g_toggle_pulse = (uint16_t) (Tim_Pulse / 2);
if(g_calc_t.step_pos >= g_calc_t.dec_point )
{
g_calc_t.ptr = g_calc_t.decel_tab; /* 将减速段的速度表赋值给ptr */
g_motor_sta = STATE_DECEL;
}
break;
case STATE_STOP:
HAL_TIM_OC_Stop_IT(&g_atimx_handle, ATIM_TIMX_PWM_CH3); /* 开启对应PWM通道 */
g_motor_sta = STATE_IDLE;
break;
case STATE_IDLE:
break;
}
}
/* 设置比较值 */
Tim_Count=__HAL_TIM_GET_COUNTER(&g_atimx_handle);
tmp = 0xFFFF & (Tim_Count + g_toggle_pulse);
__HAL_TIM_SET_COMPARE(&g_atimx_handle,TIM_CHANNEL_3,tmp);
}
}
定时器:
void atim_timx_oc_chy_init(uint16_t arr, uint16_t psc)
{
ATIM_TIMX_PWM_CHY_CLK_ENABLE(); /* TIMX 时钟使能 */
g_atimx_handle.Instance = ATIM_TIMX_PWM; /* 定时器x */
g_atimx_handle.Init.Prescaler = psc; /* 定时器分频 */
g_atimx_handle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 向上计数模式 */
g_atimx_handle.Init.Period = arr; /* 自动重装载值 */
g_atimx_handle.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; /* 分频因子 */
g_atimx_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; /*使能TIMx_ARR进行缓冲*/
g_atimx_handle.Init.RepetitionCounter = 0; /* 开始时不计数*/
HAL_TIM_OC_Init(&g_atimx_handle); /* 初始化PWM */
g_atimx_oc_chy_handle.OCMode = TIM_OCMODE_TOGGLE; /* 翻转模式 */
g_atimx_oc_chy_handle.Pulse = 0;
g_atimx_oc_chy_handle.OCPolarity = TIM_OCPOLARITY_HIGH; /* 输出比较极性为高 */
g_atimx_oc_chy_handle.OCNPolarity = TIM_OCNPOLARITY_LOW;
g_atimx_oc_chy_handle.OCFastMode = TIM_OCFAST_DISABLE;
g_atimx_oc_chy_handle.OCIdleState = TIM_OCIDLESTATE_RESET;
g_atimx_oc_chy_handle.OCNIdleState = TIM_OCNIDLESTATE_RESET;
HAL_TIM_OC_ConfigChannel(&g_atimx_handle, &g_atimx_oc_chy_handle, ATIM_TIMX_PWM_CH1); /* 配置TIMx通道y */
HAL_TIM_OC_ConfigChannel(&g_atimx_handle, &g_atimx_oc_chy_handle, ATIM_TIMX_PWM_CH2); /* 配置TIMx通道y */
HAL_TIM_OC_ConfigChannel(&g_atimx_handle, &g_atimx_oc_chy_handle, ATIM_TIMX_PWM_CH3); /* 配置TIMx通道y */
HAL_TIM_OC_ConfigChannel(&g_atimx_handle, &g_atimx_oc_chy_handle, ATIM_TIMX_PWM_CH4); /* 配置TIMx通道y */
HAL_TIM_Base_Start(&g_atimx_handle);
}
/**
* @brief 定时器底层驱动,时钟使能,引脚配置
此函数会被HAL_TIM_PWM_Init()调用
* @param htim:定时器句柄
* @retval 无
*/
void HAL_TIM_OC_MspInit(TIM_HandleTypeDef *htim)
{
if (htim->Instance == ATIM_TIMX_PWM)
{
GPIO_InitTypeDef gpio_init_struct;
ATIM_TIMX_PWM_CHY_CLK_ENABLE(); /* 开启通道y的GPIO时钟 */
ATIM_TIMX_PWM_CH1_GPIO_CLK_ENABLE(); /* IO时钟使能 */
ATIM_TIMX_PWM_CH2_GPIO_CLK_ENABLE(); /* IO时钟使能 */
ATIM_TIMX_PWM_CH3_GPIO_CLK_ENABLE(); /* IO时钟使能 */
ATIM_TIMX_PWM_CH4_GPIO_CLK_ENABLE(); /* IO时钟使能 */
gpio_init_struct.Pin = ATIM_TIMX_PWM_CH1_GPIO_PIN; /* 通道y的GPIO口 */
gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
gpio_init_struct.Alternate = ATIM_TIMX_PWM_CHY_GPIO_AF; /* 端口复用 */
HAL_GPIO_Init(ATIM_TIMX_PWM_CH1_GPIO_PORT, &gpio_init_struct);
gpio_init_struct.Pin = ATIM_TIMX_PWM_CH2_GPIO_PIN; /* 通道y的GPIO口 */
HAL_GPIO_Init(ATIM_TIMX_PWM_CH2_GPIO_PORT, &gpio_init_struct);
gpio_init_struct.Pin = ATIM_TIMX_PWM_CH3_GPIO_PIN; /* 通道y的GPIO口 */
HAL_GPIO_Init(ATIM_TIMX_PWM_CH3_GPIO_PORT, &gpio_init_struct);
gpio_init_struct.Pin = ATIM_TIMX_PWM_CH4_GPIO_PIN; /* 通道y的GPIO口 */
HAL_GPIO_Init(ATIM_TIMX_PWM_CH4_GPIO_PORT, &gpio_init_struct);
HAL_NVIC_SetPriority(ATIM_TIMX_INT_IRQn, 2, 2);
HAL_NVIC_EnableIRQ(ATIM_TIMX_INT_IRQn);
}
}
/**
* @brief 高级定时器TIMX NPWM中断服务函数
* @param 无
* @retval 无
*/
void ATIM_TIMX_INT_IRQHandler(void)
{
HAL_TIM_IRQHandler(&g_atimx_handle); /* 定时器共用处理函数 */
}
实验结果:

增加日志