基于GD32VW553的SG90舵机PWM驱动与角度控制实战

news2026/3/16 8:40:25
基于GD32VW553的SG90舵机PWM驱动与角度控制实战最近在做一个机器人小项目需要用GD32VW553开发板控制舵机正好手头有最常见的SG90舵机。很多刚开始接触嵌入式控制的朋友可能对如何用单片机精确控制舵机角度有点摸不着头脑。其实原理并不复杂关键是要理解PWM信号和舵机角度之间的对应关系。今天我就以GD32VW553为例手把手带你实现SG90舵机的PWM驱动和角度控制。我会从硬件连接到软件配置再到代码编写一步步详细讲解保证你跟着做一遍就能完全掌握。1. 认识SG90舵机这个小家伙怎么工作在开始动手之前咱们先来了解一下今天的主角——SG90舵机。这可能是市面上最常见、最便宜的9克微型舵机了很多机器人、航模项目都会用到它。1.1 SG90的基本参数根据资料SG90有几个关键参数需要记住工作电压3V~7.2V。实际使用中用5V供电最稳定这也是大多数开发板都能提供的电压。控制方式PWM脉冲宽度调制。这是控制舵机的核心后面会详细讲。转动角度180度。注意市面上还有360度连续旋转的舵机那种只能控制转速不能控制角度。咱们用的是180度版本。转动速度大约0.18秒/60度。这个速度不算快所以如果你控制舵机角度变化太快它可能反应不过来。1.2 PWM控制原理舵机怎么知道要转多少度SG90舵机有三根线棕色线GND地线红色线VCC电源接5V黄色线信号线接MCU的PWM输出引脚舵机内部有个控制电路它通过检测信号线上的PWM脉冲宽度来判断要转到什么角度。PWM信号有几个关键参数周期通常是20ms频率50Hz脉宽高电平持续的时间这个时间决定了舵机角度具体的对应关系是这样的0.5ms脉宽→ 舵机转到0度位置1.0ms脉宽→ 舵机转到45度位置1.5ms脉宽→ 舵机转到90度位置中间位置2.0ms脉宽→ 舵机转到135度位置2.5ms脉宽→ 舵机转到180度位置你可以把脉宽想象成给舵机的指令脉宽越长舵机转的角度就越大。这个线性关系是咱们后面写代码的基础。2. 硬件连接把舵机接到GD32VW553上硬件连接很简单但一定要接对不然舵机可能不工作甚至损坏。2.1 引脚选择根据原始资料我们使用GD32VW553的PA1引脚来控制SG90舵机。为什么选这个引脚因为PA1是TIMER1的通道1TIMER1_CH1可以直接输出PWM信号。注意GD32VW553的很多引脚都有复用功能一定要查数据手册确认引脚支持PWM输出。PA1的复用功能1AF1就是TIMER1_CH1。2.2 接线方法按照下面的表格连接舵机线颜色开发板接口说明棕色线GND接地一定要接不然没有参考电平黄色线PA1信号线接TIMER1_CH1输出红色线5V0电源接开发板的5V输出连接时注意先断电再接线防止短路确保电源正负极不要接反如果舵机负载较重建议单独供电不要直接从开发板取电3. 软件驱动编写创建BSP层代码接下来是重头戏——写代码。咱们采用模块化的方式创建两个文件bsp_sg90.h和bsp_sg90.c把舵机相关的驱动都放在这里面。3.1 头文件定义bsp_sg90.h头文件主要定义引脚、定时器配置以及函数声明。#ifndef BSP_CODE_BSP_SG90_H_ #define BSP_CODE_BSP_SG90_H_ #include gd32vw55x.h #include systick.h /* 使能相关时钟的宏定义 */ #define Module_RCU_Enable() \ rcu_periph_clock_enable(RCU_GPIOA); \ rcu_periph_clock_enable(RCU_TIMER1); /* 定时器相关定义 */ #define BSP_PWM_TIMER_RCU RCU_TIMER1 // 定时器时钟 #define BSP_PWM_TIMER TIMER1 // 使用TIMER1 #define BSP_PWM_TIMER_CH TIMER_CH_1 // 使用通道1 /* GPIO引脚定义 - PA1对应TIMER1_CH1 */ #define BSP_PWM_RCU RCU_GPIOA #define BSP_PWM_PORT GPIOA #define BSP_PWM_PIN GPIO_PIN_1 #define BSP_PWM_AF GPIO_AF_1 // 复用功能1 /* 函数声明 */ void SG90_Init(void); // 舵机初始化 void Set_SG90_Servo_Angle(uint32_t angle); // 设置舵机角度 uint8_t Get_SG90_Servo_Angle(void); // 获取当前角度 #endif /* BSP_CODE_BSP_SG90_H_ */3.2 源文件实现bsp_sg90.c这是核心的实现部分我会逐段解释。#include bsp_sg90.h /* 全局变量记录当前舵机角度 */ uint8_t Servo_Angle 0;首先定义一个全局变量来记录当前角度这样我们就能随时知道舵机在什么位置。3.2.1 角度设置函数这个函数是整个驱动的核心它把角度值转换成PWM的脉宽。void Set_SG90_Servo_Angle(uint32_t angle) { /* 角度范围限制在0-180度 */ if(angle 180) { angle 180; } /* 更新当前角度 */ Servo_Angle angle; /* 关键计算将角度转换为PWM比较值 */ // 0.5ms对应的计数值 ≈ 500 // 2.5ms对应的计数值 ≈ 2500 float min_count 500.0f; // 0度对应的计数值 float max_count 2500.0f; // 180度对应的计数值 float range max_count - min_count; // 有效范围 /* 线性计算角度 - 计数值 */ float ServoAngle min_count (((float)angle / 180.0f) * range); /* 配置定时器通道的比较值改变PWM脉宽 */ timer_channel_output_pulse_value_config(BSP_PWM_TIMER, BSP_PWM_TIMER_CH, (uint32_t)ServoAngle); }这里有个重要的计算过程我解释一下定时器时钟配置后计数频率是1MHz后面会讲怎么配置的1MHz意味着每1us计数1次0.5ms 500us所以对应计数值5002.5ms 2500us所以对应计数值2500中间的角度就按比例线性计算3.2.2 角度读取函数这个函数很简单就是返回当前记录的角度值。uint8_t Get_SG90_Servo_Angle(void) { return Servo_Angle; }提示这个函数返回的是我们软件记录的角度不是从舵机实际读取的。舵机本身没有角度反馈功能所以我们需要自己记录设置的角度。3.2.3 初始化函数初始化函数比较长但每一步都很重要。我会分段解释。void SG90_Init(void) { /* 第一步使能相关时钟 */ Module_RCU_Enable(); // 使能GPIOA和TIMER1的时钟 /* 第二步配置GPIO引脚为复用功能 */ gpio_mode_set(BSP_PWM_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_PWM_PIN); gpio_output_options_set(BSP_PWM_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, BSP_PWM_PIN); gpio_af_set(BSP_PWM_PORT, BSP_PWM_AF, BSP_PWM_PIN); // 设置为AF1功能 /* 第三步配置定时器基本参数 */ timer_parameter_struct timer_initpara; /* 使能定时器时钟 */ rcu_periph_clock_enable(BSP_PWM_TIMER_RCU); /* 配置定时器时钟预分频器CK_TIMERx 2 x CK_APB1 2x80M 160MHz */ rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL2); /* 复位定时器到默认状态 */ timer_deinit(BSP_PWM_TIMER); /* 配置定时器参数 */ timer_initpara.prescaler 160 - 1; // 预分频值160MHz/160 1MHz timer_initpara.alignedmode TIMER_COUNTER_EDGE; // 边沿对齐模式 timer_initpara.counterdirection TIMER_COUNTER_UP; // 向上计数 timer_initpara.period 20000 - 1; // 自动重装载值周期20ms timer_initpara.clockdivision TIMER_CKDIV_DIV1; // 时钟分频 timer_initpara.repetitioncounter 0; // 重复计数器 /* 初始化定时器 */ timer_init(BSP_PWM_TIMER, timer_initpara); /* 第四步使能定时器 */ timer_enable(BSP_PWM_TIMER); /* 第五步配置定时器输出比较功能 */ timer_oc_parameter_struct timer_ocintpara; timer_ocintpara.ocpolarity TIMER_OC_POLARITY_HIGH; // 输出极性为高 timer_ocintpara.outputstate TIMER_CCX_ENABLE; // 使能输出 timer_channel_output_config(BSP_PWM_TIMER, BSP_PWM_TIMER_CH, timer_ocintpara); /* 第六步初始比较值设为0 */ timer_channel_output_pulse_value_config(BSP_PWM_TIMER, BSP_PWM_TIMER_CH, 0); /* 第七步配置为PWM模式0 */ timer_channel_output_mode_config(BSP_PWM_TIMER, BSP_PWM_TIMER_CH, TIMER_OC_MODE_PWM0); /* 第八步禁用影子寄存器立即更新 */ timer_channel_output_shadow_config(BSP_PWM_TIMER, BSP_PWM_TIMER_CH, TIMER_OC_SHADOW_DISABLE); /* 第九步使能自动重装载影子寄存器 */ timer_auto_reload_shadow_enable(BSP_PWM_TIMER); }这里有几个关键点需要理解时钟配置GD32VW553的APB1时钟是80MHz经过预分频器×2后定时器时钟变成160MHz。我们再通过预分频值160分频得到1MHz的计数频率。周期计算我们要产生20ms周期的PWM信号。计数频率1MHz 1,000,000次/秒20ms周期对应的计数值1,000,000 × 0.02 20,000所以自动重装载值设为20000-1因为从0开始计数脉宽范围前面说了0.5ms-2.5ms对应0-180度。0.5ms 500us → 计数值5002.5ms 2500us → 计数值2500这个范围在20ms周期内是合理的4. 主程序测试让舵机动起来驱动写好了现在来写主程序测试一下。#include gd32vw55x.h #include systick.h #include stdio.h #include main.h #include gd32vw553h_eval.h #include bsp_sg90.h int main(void) { /* 系统初始化 */ systick_config(); eclic_priority_group_set(ECLIC_PRIGROUP_LEVEL3_PRIO1); /* 初始化LED、串口等外设 */ gd_eval_led_init(LED1); gd_eval_com_init(EVAL_COM0); /* 打印系统信息 */ printf(\r\n Welcome to use the LC-GD32VW553-HMQ6 development board \r\n); /* 初始化SG90舵机 */ SG90_Init(); printf(\r\nSG90 Init Success\r\n); /* 测试1先转到180度位置等待1秒 */ Set_SG90_Servo_Angle(180); delay_1ms(1000); /* 测试2再转到0度位置等待1秒 */ Set_SG90_Servo_Angle(0); delay_1ms(1000); printf(\r\nSG90 Set Angle Success\r\n); /* 测试3让舵机从0度慢慢转到180度 */ uint8_t i 0; while(1) { Set_SG90_Servo_Angle(i); if(i 180) { i 0; } delay_1ms(10); // 每10ms变化1度 } }这个测试程序做了三件事初始化后先让舵机转到180度最右等待1秒再转到0度最左等待1秒最后进入循环让舵机从0度慢慢转到180度然后再从头开始5. 调试技巧和常见问题在实际项目中你可能会遇到一些问题这里分享几个我踩过的坑5.1 舵机不转动如果舵机完全不动按这个顺序检查电源问题用万用表量一下舵机电源脚有没有5V电压地线问题确保MCU和舵机共地信号线连接确认黄色线接到了PA1引脚代码问题检查定时器是否使能PWM输出是否配置正确5.2 舵机抖动或角度不准电源功率不足如果舵机负载较重开发板的5V输出可能带不动。可以给舵机单独供电但要确保和MCU共地。PWM频率不对SG90要求50Hz20ms周期如果频率偏差太大舵机可能工作不正常。脉宽范围不对确认计算是否正确0.5ms-2.5ms对应500-2500的计数值。5.3 角度有偏差有时候你会发现设置90度舵机可能停在85度或95度位置。这是因为舵机本身有机械误差电源电压影响电压低时扭矩小可能到不了指定位置负载影响如果舵机轴上有负载可能需要更大的扭矩解决方法在代码中做校准比如实际测试0度、90度、180度对应的准确计数值适当增加死区避免在极限位置卡住5.4 多个舵机控制如果你要控制多个舵机有几种方案每个舵机用一个定时器通道GD32VW553的定时器通常有4个通道可以控制4个舵机使用多个定时器如果需要更多舵机可以用多个定时器软件PWM如果对精度要求不高可以用GPIO模拟PWM但会占用CPU资源6. 实际项目应用建议在实际项目中控制舵机我还有几个经验分享平滑运动不要突然让舵机从0度跳到180度这样冲击很大。可以逐步改变角度比如每次变化1-2度中间加个小延时。电源处理如果控制多个舵机一定要用单独的电源模块供电不要直接从开发板取电。开发板的LDO电流有限多个舵机同时工作可能重启。机械保护舵机转到极限位置时不要长时间保持容易烧坏。可以在软件中设置软限位比如实际只让舵机在10-170度范围内运动。状态保存如果系统需要断电记忆可以把舵机角度保存到Flash中上电后恢复到之前的位置。错误处理增加超时检测如果舵机卡住或异常及时停止输出PWM防止持续堵转烧坏。通过这个实战项目你应该已经掌握了用GD32VW553控制SG90舵机的完整流程。从硬件连接到软件驱动再到实际调试每个环节我都尽量把原理讲清楚。在实际项目中你可能需要根据具体需求调整参数但基本的框架和思路是一样的。下次如果你要做机械臂、云台或者机器人关节就可以用这套代码作为基础快速实现舵机控制功能了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2415584.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…