概况
本程序使用TIM5通用定时器的输出比较功能实现pwm输出,程序运行时出现舵机向一边旋转直接卡死的故障。
芯片型号:STM32F103ZET6,
所用定时器:TIM5,72分频,
定时器预装载值:20000-1,周期20ms
故障现象
STM32舵机向一边转直接卡死:
2023年10月6日在调试stm32智能小车时舵机出现直接卡死的情况,主要表现为刚下载好程序舵机可以正常工作,完全断开电源小车电源重启舵机直接向右旋转直到完全卡死不动弹。再次下载程序恢复正常,之后每次重启都需要重新下载,舵机才会正常工作。
调试过程
于是本人尝试断开舵机,直接测量pwm波形。
重启之前波形如下,由此可见波形是正常的。
然后断电重启之后就出现问题了,波形杂乱无章。
原因是预分频因子没有配置,导致重启后波形无法正常输出。
添加红圈内代码后工作正常。
完整代码
dri_servo_motor.h
#ifndef __DRI_SERVO_MOTOR_H__
#define __DRI_SERVO_MOTOR_H__
#include "stm32f10x.h"
//定义舵机GPIO引脚,以及所对应的时钟
#define SERVO_GPIO_PIN GPIO_Pin_0
#define SERVO_GPIO_PORT GPIOA
#define SERVO_GPIO_CLK RCC_APB2Periph_GPIOA
//定义舵机定时器
#define SERVO_TIM TIM5
#define SERVO_TIM_CLK RCC_APB1Periph_TIM5
//舵机的定时器时钟开启函数
#define SERVO_TIM_CLK_CMD_FUNC RCC_APB1PeriphClockCmd
#define SERVO_MOTOR_LEFT 150
#define SERVO_MOTOR_RIGHT 30
#define SERVO_MOTOR_MIDDLE 90
/**********************************************
*函数名:dri_servo_motor_init(void)
*功能:初始化舵机GPIO和定时器
*参数:无
*返回值:无
*其他说明:无
***********************************************/
void dri_servo_motor_init(void);
/**********************************************
*函数名:void dri_servo_motor_postion(uint32_t angle)
*功能:舵机设定转角
*参数:
angle:设定角度0-180°超过不会动作
*返回值:无
*其他说明:无
***********************************************/
void dri_servo_motor_postion(uint32_t angle);
#endif
dri_servo_motor.c
#include "dri_servo_motor.h"
#define COMPARISON_VAL(angle) (((2000/180)*angle)+500)
/**********************************************
*函数名:dri_servo_motor_init(void)
*功能: 初始化舵机GPIO和定时器
*参数:无
*返回值:无
*其他说明:无
***********************************************/
void dri_servo_motor_init(void)
{
RCC_APB2PeriphClockCmd(SERVO_GPIO_CLK|RCC_APB2Periph_AFIO,ENABLE);
SERVO_TIM_CLK_CMD_FUNC(SERVO_TIM_CLK,ENABLE);
/*初始化舵机GPIO*/
GPIO_InitTypeDef GPIO_Initstructure;
GPIO_Initstructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Initstructure.GPIO_Pin = SERVO_GPIO_PIN;
GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SERVO_GPIO_PORT,&GPIO_Initstructure);
/*初始化时基单元*/
TIM_TimeBaseInitTypeDef TIMBaseInitstructure;
TIMBaseInitstructure.TIM_CounterMode = TIM_CounterMode_Up;
TIMBaseInitstructure.TIM_Prescaler = 72-1;
TIMBaseInitstructure.TIM_Period = 20000-1;
TIMBaseInitstructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(SERVO_TIM,&TIMBaseInitstructure);
/*输出比较单元初始化*/
TIM_OCInitTypeDef TIM_OCInitstructure;
TIM_OCInitstructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitstructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitstructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitstructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitstructure.TIM_Pulse = COMPARISON_VAL(90);
TIM_OC1Init(SERVO_TIM,&TIM_OCInitstructure);
}
/**********************************************
*函数名:void dri_servo_motor_postion(uint32_t angle)
*功能:舵机设定转角
*参数:
angle:设定角度0-180°超过不会动作
*返回值:无
*其他说明:无
***********************************************/
void dri_servo_motor_postion(uint32_t angle)
{
if(angle > 180) return;
TIM_SetCompare1(SERVO_TIM,COMPARISON_VAL(angle));
TIM_Cmd(SERVO_TIM,ENABLE);
}
main.c
#include "stm32f10x.h"
#include "interface.h"
//蜂鸣器
#include "dri_beep.h"
//滴答定时器
#include "dri_systick.h"
//led
#include "dri_led.h"
//舵机控制程序
#include "dri_servo_motor.h"
int main()
{
uint8_t i = 0;
dri_beep_init();
dri_led_init();
dri_servo_motor_init();
while(1)
{ if(i<3){
dri_servo_motor_postion(SERVO_MOTOR_LEFT);
dri_systick_delay_ms(500);
dri_servo_motor_postion(SERVO_MOTOR_MIDDLE);
dri_systick_delay_ms(500);
dri_servo_motor_postion(SERVO_MOTOR_RIGHT);
dri_systick_delay_ms(500);
i++;
}else{
dri_servo_motor_postion(SERVO_MOTOR_MIDDLE);
}
}
}
现象:
舵机左中右方向依次摆动,动作重复三次。最后回到舵机回到中间停止不动。