
目录
前言
最近用到了STM32驱动HX711称重传感器模块,我这里用的STM32是STM32F103C8T6,这个模块的扭矩力能达到1.6KG/CM,所以记录一下
一、工作原理
- 核心逻辑:STM32 定时器生成 50Hz(20ms 周期)PWM,通过 CCR 值控制 0.5~2.5ms 高电平脉宽,SG90 内部解析脉宽实现角度控制;
- 关键链路:系统时钟→定时器 PSC/ARR(定周期)→定时器 CCR(定脉宽)→PWM 输出→SG90 内部闭环执行→稳定角度;
- 核心映射:角度→CCR 值→脉宽→舵机角度,三者为线性对应关系。
PWM信号控制:
-
信号周期:20ms(50Hz)。
-
脉冲宽度:0.5ms - 2.5ms,对应角度0° - 180°。
-

-

二、接线方式
|-----|-----|
| VIN | 5V |
| GND | GND |
| PWM | PA0 |
三、软件程序
sg90.h
#ifndef __SG90_H
#define __SG90_H
#include "stm32f10x.h"
// 函数声明
void SG90_Init(void); // 舵机初始化(GPIO+定时器PWM配置)
void SG90_Set_Angle(u16 angle); // 舵机角度设置(0~180°)
#endif
sg90.c
#include "sg90.h"
#include "delay.h" // 需自行提供延时函数(用于舵机稳定转动)
/************************* 核心参数说明 *************************
SG90要求:
1. PWM周期:20ms(50Hz)
2. 脉宽范围:0.5ms(0°)~ 2.5ms(180°)
STM32F103系统时钟:72MHz(默认配置)
TIM2时钟:APB1总线时钟(最大36MHz,此处72MHz分频后为36MHz)
定时器配置:
- 预分频器(PSC):7199 → 计数频率=36MHz/(7199+1)=5kHz
- 自动重装值(ARR):99 → PWM周期=(7199+1)*(99+1)/36MHz=20ms
- 脉宽对应值:0.5ms→2.5(5kHz*0.5ms)、2.5ms→12.5(5kHz*2.5ms)
为避免浮点运算,放大2倍:0.5ms→5、2.5ms→25,对应0°→180°
****************************************************************/
// 舵机初始化:配置GPIO+TIM2_CH1 PWM输出
void SG90_Init(void)
{
// 1. 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // GPIOA时钟使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // TIM2时钟使能
// 2. 配置GPIO引脚(PA0 → TIM2_CH1 复用推挽输出)
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出(定时器PWM专用)
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 3. 配置定时器时基参数
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 99; // 自动重装值ARR=99,配合PSC=7199实现20ms周期
TIM_TimeBaseStructure.TIM_Prescaler = 7199; // 预分频器PSC=7199
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;// 时钟分频=1
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// 4. 配置定时器PWM输出通道(CH1)
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1:计数<CCR时输出有效电平
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 使能输出
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 有效电平为高电平(SG90高电平脉宽有效)
TIM_OCInitStructure.TIM_Pulse = 5; // 初始脉宽对应0°(0.5ms)
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
// 5. 使能通道预装载和定时器
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); // 使能CCR1预装载(保证脉宽稳定)
TIM_ARRPreloadConfig(TIM2, ENABLE); // 使能ARR预装载
TIM_Cmd(TIM2, ENABLE); // 启动TIM2
}
// 舵机角度设置:输入0~180°,超出范围自动修正
void SG90_Set_Angle(u16 angle)
{
u16 ccr_val;
// 1. 角度边界修正
if(angle > 180) angle = 180;
if(angle < 0) angle = 0;
// 2. 计算对应CCR1值(线性映射:0°→5,180°→25)
// 公式:ccr_val = 5 + (25-5)*angle/180 = 5 + angle/9
ccr_val = 5 + (angle * 20) / 180;
// 3. 更新CCR1值,改变PWM脉宽
TIM_SetCompare1(TIM2, ccr_val);
// 4. 延时等待舵机稳定转动(SG90转动全程约200ms)
delay_ms(250);
}
main.c
#include "stm32f10x.h"
#include "sg90.h"
#include "delay.h"
int main(void)
{
// 系统初始化
SystemInit(); // STM32系统时钟初始化(默认72MHz)
delay_init(); // 延时函数初始化(需自行实现)
SG90_Init(); // 舵机初始化
while(1)
{
// 测试:0° → 90° → 180° → 90° 循环转动
SG90_Set_Angle(0);
delay_ms(1000);
SG90_Set_Angle(90);
delay_ms(1000);
SG90_Set_Angle(180);
delay_ms(1000);
SG90_Set_Angle(90);
delay_ms(1000);
}
}
关键说明(避坑重点)!!!!
- 延时函数:
delay.h和delay.c需自行实现(可通过 SysTick 定时器实现毫秒 / 微秒延时),舵机转动需要一定时间,不可省略delay_ms(250)。 - 供电问题:SG90 在转动时电流较大,若直接由 STM32 的 5V 引脚供电,可能导致单片机复位,建议使用外部电源模块(如 3.7V 锂电池 + 升压模块至 5V)。
- 角度精度:SG90 为模拟舵机,存在 ±5° 左右的误差,且不可超过 180° 转动(否则会烧毁内部齿轮)。
- 定时器替换:若需更换其他定时器 / 通道(如 TIM3_CH2、PA1),只需修改对应时钟、GPIO 引脚和定时器通道配置即可。
总结
本文介绍了STM32F103C8T6驱动SG90舵机的实现方法。通过定时器生成50Hz(20ms周期)PWM信号,调节0.5-2.5ms脉宽对应0-180°角度控制。详细说明了硬件接线(VIN-5V、GND-GND、PWM-PA0)和软件实现,包括定时器配置、PWM参数计算及角度控制函数。特别强调需注意延时函数实现、外部供电要求、角度精度限制和定时器替换方法。提供完整的工程文件结构(sg90.h/c、main.c)及避坑重点,为舵机控制提供了实用参考方案。