一、项目背景与目标

1.1 项目概述

本项目基于STM32F103C8T6微控制器,设计并实现一个双舵机控制系统。系统通过按键触发,控制两个舵机依次执行"0°→180°→0°"的往返动作,并在OLED显示屏上实时记录和显示动作执行的累计次数。

1.2 技术指标

项目 规格
主控芯片 STM32F103C8T6
控制对象 2个SG90标准舵机(0°~180°)
控制方式 PWM脉宽调制(50Hz)
显示模块 0.96寸OLED(I2C接口)
输入方式 独立按键(PB0)
计数范围 0~255
供电方式 STM32(USB)/ 舵机(独立5V/2A)

1.3 功能要求

  1. 按下按键PB0一次

  2. 舵机1执行:0°→180°→0°(往返一次)

  3. 舵机2执行:0°→180°→0°(往返一次)

  4. OLED屏幕显示累计动作次数+1

  5. 等待下一次按键触发

1.4 系统框图

text

                    ┌──────────────────────────────────────┐
                    │           STM32F103C8T6              │
                    │                                      │
    ┌──────────┐    │    ┌─────────────┐                   │
    │  按键    │────│────│   GPIO输入  │                   │
    │  (PB0)   │    │    │  (上拉输入) │                   │
    └──────────┘    │    └─────────────┘                   │
                    │          │                           │
                    │          ▼                           │
                    │    ┌─────────────┐    ┌──────────┐   │   ┌─────────┐
                    │    │  主控逻辑   │──── │ TIM2_CH1 │────│──│ 舵机1   │
                    │    │  (main.c)   │    │  (PA0)   │  │    │ (PA0)   │
                    │    └─────────────┘    └──────────┘  │    └─────────┘
                    │          │                          │
                    │          ▼                          │
                    │    ┌─────────────┐    ┌──────────┐  │    ┌─────────┐
                    │    │  OLED显示   │    │ TIM3_CH1 │────│── │ 舵机2   │
                    │    │  (I2C)      │    │  (PA6)   │  │    │ (PA6)   │
                    │    └─────────────┘    └──────────┘  │    └─────────┘
                    │                                     │
                    └─────────────────────────────────────┘

二、硬件设计

2.1 器件选型

器件 型号 数量 说明
主控芯片 STM32F103C8T6 1 ARM Cortex-M3,72MHz
舵机 SG90(标准版) 2 0°~180°角度控制
OLED 0.96寸 SSD1306 1 I2C接口,128×64
按键 轻触开关 1 6×6×5mm
电源 5V/2A适配器 1 舵机独立供电
杜邦线 公对母/母对母 若干 连接线

2.2 引脚分配表

外设 功能引脚 STM32引脚 片上资源 说明
舵机1 信号线 PA0 TIM2_CH1 独立定时器通道1
舵机2 信号线 PA6 TIM3_CH1 独立定时器通道1
OLED SCL PB8 I2C1_SCL I2C时钟线
OLED SDA PB9 I2C1_SDA I2C数据线
按键 信号 PB0 GPIO输入 内部上拉

2.3 舵机工作原理

2.3.1 控制信号规范

舵机通过PWM(脉冲宽度调制)信号控制,周期固定为20ms(50Hz):

text

┌─────────────────────────────────────────────────────────┐
│                   20ms (50Hz)                           │
│  ┌──────┐                                               │
│  │ 脉宽  │                                              │
│  └──────┘                                               │
│  ←0.5~2.5ms→                                            │
└─────────────────────────────────────────────────────────┘
2.3.2 角度与脉宽对应关系
角度 脉宽 计数值(1MHz时钟)
0.5ms 500
45° 1.0ms 1000
90° 1.5ms 1500
135° 2.0ms 2000
180° 2.5ms 2500
2.3.3 计算公式

脉宽(μs) = (角度 / 180) × 2000 + 500

2.4 硬件连接图

                    ┌─────────────────────────────────────┐
                    │         STM32F103C8T6               │
                    │                                     │
   舵机1  ── 黄色 ──│ PA0  (TIM2_CH1)                      │
   舵机1  ── 红色 ──│ 5V  (独立电源)                       │
   舵机1  ── 棕色 ──│ GND (共地)                           │
                    │                                    │
   舵机2  ── 黄色 ──│ PA6  (TIM3_CH1)                     │
   舵机2  ── 红色 ──│ 5V  (独立电源)                       │
   舵机2  ── 棕色 ──│ GND (共地)                          │
                    │                                    │
   OLED   ── VCC ──│ 3.3V                                │
   OLED   ── GND ──│ GND                                 │
   OLED   ── SCL ──│ PB8                                 │
   OLED   ── SDA ──│ PB9                                 │
                    │                                    │
   按键    ── 一端 ──│ PB0                                │
   按键    ── 另一端 ──│ GND                              │
                    └─────────────────────────────────────┘

2.5 舵机选型注意事项

标准舵机 vs 360°舵机对比
对比项 标准舵机(SG90) 360°舵机(SG90-360)
控制方式 角度控制 速度控制
旋转范围 0°~180°(有限位) 无限制(连续旋转)
停止条件 到达目标角度自动停止 只有PWM=1.5ms时停止
位置反馈 有(内部电位器) 无(电位器固定)
适用场景 机械臂、云台、转向 车轮、传送带

本项目必须使用标准舵机!(其实是主播连接完之后发现自己手边的sg90都是360°的,随着烧录开始疯狂的旋转也是非常之崩溃,所以没有特殊需要大家就不要买升级改装过的sg90了。。。


三、软件设计

这里主播是使用了b站江科协老师免费分享的标准库,相对基础薄弱的同学来说hal库的配置可能会相对麻烦一点,所以主播在进行一系列的CubeMX的使用之后选择了在老师的源代码的基础上进行改装!!Or2

3.1 开发环境

项目 版本/工具
IDE Keil MDK V5
固件库 STM32F10x_StdPeriph_Lib V3.5.0
调试器 ST-Link V2
编程语言 C语言

3.2 工程结构

3.3 核心代码详解

3.3.1 PWM驱动(PWM.c)

设计思路

  • 使用两个独立定时器避免通道冲突

  • TIM2_CH1(PA0)控制舵机1

  • TIM3_CH1(PA6)控制舵机2

  • 每个定时器独立配置,互不干扰


3.3.2 舵机驱动(Servo.c)

3.3.3 按键驱动(Key.c)

3.3.4 主程序(main.c)

3.4 程序流程图

┌─────────────────────────────────────┐
│             系统启动                 │
└───────────────┬─────────────────────┘
                ▼
┌─────────────────────────────────────┐
│           初始化外设                 │
│    OLED_Init() / Key_Init()         │
│    Servo_Init()                     │
└───────────────┬─────────────────────┘
                ▼
┌─────────────────────────────────────┐
│         舵机复位到0°                │
│    Servo1_SetAngle(0)               │
│    Servo2_SetAngle(0)               │
└───────────────┬─────────────────────┘
                ▼
┌─────────────────────────────────────┐
│          显示初始界面                │
│    "Dual Servo"                     │
│    "Count: 000"                     │
│    "Press PB0 to Start"             │
└───────────────┬─────────────────────┘
                ▼
        ┌───────────────┐
        │  按键按下?   │
        │ Key_GetNum()  │
        └───────┬───────┘
                │ 是
                ▼
┌─────────────────────────────────────┐
│       显示"Running..."              │
└───────────────┬─────────────────────┘
                ▼
┌─────────────────────────────────────┐
│  舵机1: 0° → 180° → 0°             │
│  每个动作间隔1000ms                  │
└───────────────┬─────────────────────┘
                ▼
┌─────────────────────────────────────┐
│  舵机2: 0° → 180° → 0°             │
│  每个动作间隔1000ms                  │
└───────────────┬─────────────────────┘
                ▼
┌─────────────────────────────────────┐
│   Count++                           │
│   OLED显示更新后的计数值             │
└───────────────┬─────────────────────┘
                ▼
┌─────────────────────────────────────┐
│  显示"Press PB0 to Start"           │
│  等待下次按键                        │
└─────────────────────────────────────┘

四、调试过程与问题解决

4.1 问题一:舵机疯狂旋转不停止

现象描述

舵机接入后持续高速旋转,完全不听指令,无法停在指定角度。

初步排查
  1. 检查PWM频率 → 50Hz正常 ✅

  2. 检查GPIO配置 → 复用推挽正常 ✅

  3. 检查定时器配置 → 周期20ms正常 ✅

根本原因

检查舵机型号发现——购买的是 "SG90 360度连续旋转舵机"。(我真的要哭了,等我有💴了一定要统一硬件界的度量衡!!!

问题分析

两种舵机的本质区别:

舵机类型 控制方式 停止条件
标准舵机(0°~180°) 角度控制 到达目标角度自动停止
360°舵机 速度控制 只有PWM=1.5ms时才停止

解决方案

更换为标准SG90舵机(0°~180°版本),购买时确认没有"360°"或"连续旋转"字样。

经验教训

舵机外观相似,但内部结构完全不同。购买前必须确认型号,我的改装版和普通版都没有信息被标出来,建议

4.2 问题二:单定时器双通道异常

现象描述

使用TIM2的CH1(PA0)和CH2(PA1)时:

  • PA0:舵机不转动 ❌

  • PA1:舵机疯狂旋转 ❌

问题分析
  • 两个通道共用同一个定时器,可能存在通道冲突

  • 初始化顺序可能导致通道配置相互覆盖

  • 映射关系容易搞混

解决方案

改用两个完全独立的定时器:

舵机 定时器 通道 引脚
舵机1 TIM2 CH1 PA0
舵机2 TIM3 CH1 PA6
方案优势
  • ✅ 完全独立,互不干扰

  • ✅ 避免通道映射混乱

  • ✅ 代码清晰,易于调试

  • ✅ 可靠性更高

4.3 问题三:舵机供电不足

现象描述

舵机动作时出现抖动、卡顿,偶尔复位重启。

根本原因

STM32的USB供电(5V/500mA)无法驱动两个舵机。舵机瞬间启动电流可达1A以上。

解决方案

采用独立5V/2A电源供电:

text

┌──────────┐      ┌─────────────┐
│ 5V/2A    │─────▶│  舵机VCC    │
│ 电源     │      │             │
│ GND      │─────▶│  舵机GND    │
└──────────┘      │             │
         │        │  STM32 GND  │
         └───────▶│  (共地)   │
                  └─────────────┘

4.4 问题四:OLED显示异常

现象描述

OLED无显示或显示乱码。

原因分析
  • I2C时序不匹配

  • 上电初始化延时不足

  • 供电不稳定

解决方案
  1. 确认I2C地址为0x78

  2. 增加上电延时(100ms以上)

  3. 按照SSD1306标准初始化序列配置

4.5 问题五:按键误触发

现象描述

未按下按键时,系统偶尔自动触发。

根本原因

GPIO浮空输入,电平不稳定。

解决方案

c

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  // 内部上拉

同时增加软件消抖(20ms延时)。


五、实验结果

5.1 硬件连接展示

5.2 系统性能

参数 指标
PWM频率 50Hz(精度±0.1Hz)
角度精度 ±1°
舵机响应时间 < 200ms
单次动作周期 约2.4秒
计数范围 0~255
系统功耗 < 10W(峰值)
动作间隔可调 100~1000ms

六、技术要点总结

6.1 PWM控制要点

要点 说明
周期 20ms(50Hz),固定不变
脉宽范围 0.5ms~2.5ms
角度计算公式 pulse = angle/180 × 2000 + 500
定时器时钟 1MHz(72MHz/72)
计数值范围 500~2500

6.2 双定时器方案优势

对比项 单定时器双通道 双定时器方案
通道冲突 可能存在
代码清晰度 较复杂 清晰
调试难度 较高
扩展性 受限于通道数 易于扩展
可靠性

6.3 舵机选型要点

购买舵机时注意事项:
├── 确认类型
│   ├── 标准舵机(0°~180°)→ 角度控制,本项目使用
│   └── 360°舵机 → 速度控制,本项目不能用
├── 确认参数
│   ├── 工作电压:4.8V~6V
│   ├── 扭矩:根据负载选择
│   └── 尺寸:9g/12g/20g等
└── 确认配件
    ├── 舵机臂(十字/一字/圆盘)
    ├── 螺丝
    └── 杜邦线

七、踩坑经验总结

7.1 硬件坑

序号 坑点 正确做法
1 买了360°舵机当标准舵机用 购买时确认型号,看是否有"360°"(很多不会标的!)
2 用USB供电驱动舵机 使用独立5V/2A以上电源
3 忘记共地连接 确保STM32与舵机GND相连
4 信号线接触不良 使用杜邦线并确保连接牢固

7.2 软件坑

序号 坑点 正确做法
1 单定时器通道冲突 使用独立定时器
2 引脚映射错误 核对数据手册确认复用功能
3 延迟时间不足 舵机动作至少500ms
4 按键无上拉 配置内部上拉或外接上拉电阻

7.3 调试方法论

调试流程:
1. 先确认硬件(型号、供电、连接)
2. 再验证基本功能(固定PWM输出测试)
3. 分模块调试(PWM→舵机→按键→OLED)
4. 最后整合完整逻辑
5. 逐步添加功能,不要一次性集成

八、项目总结

8.1 项目成果

本次项目成功实现了:

  1. ✅ 基于STM32F103的双舵机精确角度控制

  2. ✅ 按键触发舵机往返动作(0°→180°→0°)

  3. ✅ OLED实时显示动作累计次数

  4. ✅ 系统稳定可靠,无异常旋转

8.2 关键技术决策

决策点 选择 原因
舵机类型 标准SG90 需要角度控制
控制方式 双定时器 避免通道冲突
供电方式 独立电源 保证驱动能力
显示方案 I2C OLED 接口简单,占用引脚少

8.3 心得体会

嵌入式开发中,硬件确认是第一关。本次项目中,一个"360°舵机"的误判导致了大量时间浪费在软件调试上,而实际上问题根源在硬件选型。

核心教训

在嵌入式开发中,遇到异常现象时,应该先确认硬件是否选型正确,再检查软件逻辑。很多时候,问题不在代码,而在硬件本身。

8.4 改进方向

  1. 限位保护:软件限制角度范围(0°~180°),防止舵机过载

  2. 状态指示:增加LED指示系统运行状态

  3. 串口调试:通过USART输出调试信息

  4. 数据存储:增加EEPROM保存计数

  5. 多模式切换:支持单舵机/双舵机模式切换

  6. 速度控制:实现舵机缓动效果


十、附录

附录A:物料清单

序号 名称 型号 数量
1 STM32开发板 STM32F103C8T6 1
2 舵机 SG90标准版 2
3 OLED 0.96寸 I2C 1
4 按键 轻触开关 1
5 电源 5V/2A 1
6 杜邦线 公对母/母对母 若干

附录B:代码获取

完整项目源码已上传github,

代码链接🔗

GitHub - guanli-1020/Dual-Servo-with-OLED-Counter: Dual Servo with OLED Counter · GitHub

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐