STM32--舵机(SG90)

2023-10-27

舵机

一、介绍

  舵机是一种位置(角度)伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。目前在高档遥控玩具,如航模,包括飞机模型,潜艇模型;遥控机器人中已经使用得比较普遍。舵机是一种俗称,其实是一种伺服马达。

二、 工作原理

  控制信号由接收机的通道进入信号调制芯片,获得直流偏置电压。它内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。最后,电压差的正负输出到电机驱动芯片决定电机的正反转。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。当然我们可以不用去了解它的具体工作原理,知道它的控制原理就够了。就象我们使用晶体管一样,知道可以拿它来做开关管或放大管就行了,至于管内的电子具体怎么流动是可以完全不用去考虑的。

三、舵机的控制

舵机的控制一般需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分。以180度角度伺服为例,那么对应的控制关系是这样的:

时间 角度
0.5ms 0度
1ms 45度
1.5ms 90度
2.0ms 135度
2.5ms 180度
在这里插入图片描述

四、 设计流程

  单片机系统实现对舵机输出转角的控制,必须首先完成两个任务:首先是产生基本的PWM周期信号,本设计是产生20ms的周期信号;其次是脉宽的调整,即单片机模拟PWM信号的输出,并且调整占空比。
  当系统中只需要实现一个舵机的控制,采用的控制方式是改变单片机的一个定时器中断的初值,将20ms分为两次中断执行,一次短定时中断和一次长定时中断。这样既节省了硬件电路,也减少了软件开销,控制系统工作效率和控制精度都很高。
  具体的设计过程:例如想让舵机转向左极限的角度,它的正脉冲为2ms,则负脉冲为20ms-2ms=18ms,所以开始时在控制口发送高电平,然后设置定时器在2ms后发生中断,中断发生后,在中断程序里将控制口改为低电平,并将中断时间改为18ms,再过18ms进入下一次定时中断,再将控制口改为高电平,并将定时器初值改为2ms,等待下次中断到来,如此往复实现PWM信号输出到舵机。用修改定时器中断初值的方法巧妙形成了脉冲信号,调整时间段的宽度便可使伺服机灵活运动。
  为保证软件在定时中断里采集其他信号,并且使发生PWM信号的程序不影响中断程序的运行(如果这些程序所占用时间过长,有可能会发生中断程序还未结束,下次中断又到来的后果),所以需要将采集信号的函数放在长定时中断过程中执行,也就是说每经过两次中断执行一次这些程序,执行的周期还是20ms。
在这里插入图片描述

五、代码实现

舵机主要使用PWM信号进行控制,需要用到定时器输出PWM信号,这里使用的是定时器3和定时器4,没有使用复用功能,具体的引脚如下图:
在这里插入图片描述
sg90.c

#include "sg90.h"
#include "usart.h"

//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void PWM_Init(u16 arr,u16 psc)
{
    GPIO_InitTypeDef GPIO_InitStructure;              //定义GPIO结构体 需要用结构体类型参数时候一定要先在前面定义
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;    //定义TIMx定时器结构体
    TIM_OCInitTypeDef TIM_OCInitStructure;            //定义定时器脉宽调制结构体
    
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3|RCC_APB1Periph_TIM4,ENABLE);          //使能TIM3、4时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);//使能GPIOA时钟和GPIOB时钟
    
//    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);                     //TIM3部分重映射 TIM3_CH2->PB5
	
    //设置该引脚为复用输出功能,输出TIM3、4 的PWM脉冲波形	GPIOB.0、1、6、7、8、9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;                               
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                         //复用输出 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;                       //配置输出速率
    GPIO_Init(GPIOB,&GPIO_InitStructure);                                   //初始化GPIOB
	
	 //设置该引脚为复用输出功能,输出TIM3 的PWM脉冲波形	GPIOA 6、7
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;                               
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                         //复用输出 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;                       //配置输出速率
    GPIO_Init(GPIOA,&GPIO_InitStructure);                                   //初始化GPIOA
	

	
	//初始化TIM3
    TIM_TimeBaseStructure.TIM_Period = arr;                                 //设置自动重装载寄存器周期的值 arr=value-1
    TIM_TimeBaseStructure.TIM_Prescaler = psc;                              //设置预分频值 psc=value-1
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;                            //设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;             //TIM向上计数模式
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);                          //初始化TIMx时间基数
    
	//初始化TIM4
    TIM_TimeBaseStructure.TIM_Period = arr;                                 //设置自动重装载寄存器周期的值 arr=value-1
    TIM_TimeBaseStructure.TIM_Prescaler = psc;                              //设置预分频值 psc=value-1
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;                            //设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;             //TIM向上计数模式
    TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure);                          //初始化TIMx时间基数
	
	//初始化TIM3 Channel2 PWM模式     
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                       //选择定时器模式:TIM脉冲宽度调制模式1(改变占空比)
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;           //使能比较输出
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;               //输出极性:TIM输出比较极性高
	TIM_OC1Init(TIM3,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM3 OC1
    TIM_OC2Init(TIM3,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM3 OC2
	TIM_OC3Init(TIM3,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM3 OC2
	TIM_OC4Init(TIM3,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM3 OC2
	
	
    //初始化TIM4 Channel2 PWM模式     
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                       //选择定时器模式:TIM脉冲宽度调制模式1
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;           //使能比较输出
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;               //输出极性:TIM输出比较极性高
	TIM_OC1Init(TIM4,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM4 OC1
    TIM_OC2Init(TIM4,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM4 OC2
	TIM_OC3Init(TIM4,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM4 OC2
	TIM_OC4Init(TIM4,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM4 OC2

 
//    TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);                        //使能TIM3在CCR2上的预装载寄存器
    TIM_Cmd(TIM3, ENABLE);                                                  //使能TIM3
	TIM_Cmd(TIM4, ENABLE);                                                  //使能TIM4
}

main.c

 int main(void)
 {
 	vu8 key=0;	
	delay_init();	    	 //延时函数初始化	  
	LED_Init();		  		//初始化与LED连接的硬件接口
	KEY_Init();         	//初始化与按键连接的硬件接口
	PWM_Init(199,7199); //舵机初始化   不分频。PWM频率=72000000/900=80Khz
	LED0=0;					//先点亮红灯
	 
//计算,假设PWM周期设置为20ms
//公式为:溢出时间Tout=(arr+1)*(psc+1)/Tclk,Tclk为通用定时器的时钟,如果APB1没有分频,则就为系统时钟,72MHZ
	while(1)
	{
 		key=KEY_Scan(0);	//得到键值
	   	if(key)
		{						   
			switch(key)
			{				 
				case WKUP_PRES:	//控制舵机
				TIM_SetCompare1(TIM4,5);//定时器4通道1---0度
				delay_ms(1000);
				TIM_SetCompare1(TIM4,15);//定时器4通道1---90度
				delay_ms(1000);
					break; 
				case KEY1_PRES:	//控制LED1翻转	 
					LED1=!LED1;
					break;
				case KEY0_PRES:	//同时控制LED0,LED1翻转 
					LED0=!LED0;
					LED1=!LED1;
					break;
			}
		}else delay_ms(10); 
	}	 
}

六、舵机工程代码

舵机工程代码

七、备注

  1. 本文章是个人总结,如有错误请指正;
  2. 部分资料来源于网络和开发手册,如有侵权请联系我删除;
  3. 如需上方资料,请与我联系。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32--舵机(SG90) 的相关文章

  • python实现-从带层级的json到markdown无序列表的父子关系的转换

    带层级的json到无序列表的父子关系的转换 从带层级的json到无序列表的父子关系的转换 总结 python中 with的用法一定要跟 as 结合在一起吗 顺便也说下 as 的用法吧 从带层级的json到无序列表的父子关系的转换 首先 我们
  • Timequest Timing Analyzer进行时序分析(二)

    四 用TimeQuest对DAC7512控制器进行时序分析 在对某个对象下时序约束的时候 首先要能正确识别它 TimeQuest会对设计中各组成部分根据属性进行归类 我们在下时序约束的时候 可以通过命令查找对应类别的某个对象 TimeQue
  • 实例解析C++/CLI之接口与泛型

    实例解析C CLI 之接口与泛型 接口 某些时候 让不相关的类分享一组公有成员 以便产生相同的行为 是非常有用的 一个最基本的方法可能是通过一个公共的基类来定义它们 但这种方法太受局限 因为它要求这些类通过继承而互相关联 另外 它们也许还有
  • 又一个大雷引发市场巨震?Silvergate或将跌落:成也加密败也加密?

    这是白话区块链的第1874期原创 作者 Terry出品 白话区块链 ID hellobtc 3月1日 加密友好银行集团 Silvergate Capital布将推迟提交其年度 10 K 报告 10 K 报告是美国证券交易委员会要求的一份文件

随机推荐

  • PPPoE工作流程

    PPPoE 英语 Point to Point Protocol Over Ethernet 以太网上的点对点协议 是将点对点协议 PPP 封装在以太网 Ethernet 框架中的一种网络隧道协议 PPPoE协议及其工作过程 PPPoE的工
  • 【游戏杂记】Rgss3a文件的解包

    Rgss3a文件的解包 在RPG游戏中 如果想提取图片音乐等资源 需要对文件进行解包 这里是解包工具的链接 链接 https pan baidu com s 1 UKyetIHGsw1ibOHFLHUMQ pwd 5422 提取码 5422
  • 转载:Run-Time Check Failure #2分析

    文章出处 http hi baidu com D6 BB D3 B0 C1 F7 C0 CB blog item 0d72bcb477b2bbc236d3cad4 html Run Time Check Failure 2 一般是栈被破坏
  • 34 个 常用 Linux Shell 脚本,运维必备!

    作为一名 Linux 工程师 会写好的脚本不仅能提高工作效率 还能有更多的时间做自己的事 最近在网上冲浪的时候 也注意收集一些大佬写过的脚本 汇总整理一下 欢迎收藏 与君共勉 1 用户猜数字 bin bash 脚本生成一个 100 以内的随
  • 【力扣】两数之和-java

    思路是 两个循环套用 刚刚开始的时候想判断里面数小于目标值 这样遍历的次数会少 后面发现当数组中为负数的时候 if方法失效 判断了负数 后面发现数据中有两个0失效 判断了0 后面发现如果数据中有正有负 方法失效 public int two
  • 2021-08-30爬取网页信息并转成DataFrame

    导入包 from urllib request import urlopen Request from chardet import detect from bs4 import BeautifulSoup import re import
  • Spring多线程事务解决方案

    Spring多线程事务解决方案 多线程事务场景以及解决思路 代码实现 工具类使用演示 效果展示 多线程事务场景以及解决思路 多线程事务场景举例 对批量操作进行性能优化时会用到多线程来并行处理 从而提高运行效率 而时有业务要求保证批量操作事务
  • 如何在SOLIDWORKS中实现装配体缩放

    缩放比例功能 通过选择 插入 gt 功能 gt 缩放比例 可以找到 可用于更改单个零件中所有功能的比例 使用时 此工具在功能树中显示为附加功能 但是 此功能仅限于零件 sldprt 文件使用 您如何缩放SOLIDWORKS装配体 标SOLI
  • 解决运行flutter doctor --android-licenses时报错

    问题描述 配置flutter环境时 会使用flutter doctor命令来检查运行flutter的相关依赖是否配好 能看到还差 Android license status unknown 未解决 C Users ipkiss wu gt
  • 5 个最令人兴奋的 ES13 功能

    ES13 ECMAScript 2022 已经发布很久了 并且更新了许多有用的功能 在这篇文章中 我想与大家分享 5 种我最喜欢的技术 这些技术是我已经开始在工作中实施的 1 顶级await await 是我最喜欢的功能 因为它使我的代码显
  • python调用m文件

    系统环境 windows 64bit matlab 2018b 64bit python3 6 前提 windows下需要有matlab软件和python python调用m文件需要安装matlab engine 注意matlab版本与py
  • 类模板下运算符重载的两种用法

    1 template
  • java编写定时器,定时执行某个方法

    第一步 编写测试类 该类extends TimerTask 重新run 方法 run方法里面就是你要执行的逻辑代码 示例如下 import java text SimpleDateFormat import java util Date i
  • Python如何调用js函数?

    Python如何调用SDK的js函数 一 概述 二 环境准备 三 调用方法 步骤 四 Demo演示基础版 五 常见问题 六 深入了解 待更新 七 参考资料 一 概述 测试web前端 前端SDK web渗透流程等时 难免会需要调用前端js里面
  • 【Linux】浏览器写代码!部署code-server远程vscode网页

    部署code server远程vscode网页 在浏览器上写代码 参考文档 https developer aliyun com article 876967 slide 7 本文首发于 慕雪的寒舍 1 什么是code server 注意
  • 奔跑吧恐龙----基于JavaSwing的一个跑酷游戏

    1 游戏功能 随机出现障碍物 人物可以通过向上跳进行避免 游戏结束后出现分数 对难度进行一定的控制 当分数 gt 1000时难度升级 当分数 gt 4000时 难度再进行升级 并存在音乐播放功能 2 具体实现 2 1 model 1 Din
  • C++基于TCP/IP简单的客户端、服务器通信程序实例

    本篇文章实现了一个基于TCP 的一个非常简单的客户 服务器通信程序实例 该程序中通讯协议使用的是面向连接的TCP协议SOCK STREAM 服务器的ip地址为本地地址即 127 0 0 1 端口号为自定义的5099 大于1024即可 服务端
  • springBoot入门(快速搭建一个springBoot项目)

    目录 一 SpringBoot介绍 1 定义 2 springBoot简化的配置 3 应用打包 二 springBoot项目搭建 1 新建一个spring initializr项目 2 点击下一步 3 之后一个springBoot项目就构建
  • 好用的插件分享

    检查无用代码 Android studio gt 设置 gt Plugins gt 搜索PMD 安装QAPlug PMD 安装完成后重启Android studio
  • STM32--舵机(SG90)

    文章目录 一 介绍 二 工作原理 三 舵机的控制 四 设计流程 五 代码实现 六 舵机工程代码 七 备注 舵机 一 介绍 舵机是一种位置 角度 伺服的驱动器 适用于那些需要角度不断变化并可以保持的控制系统 目前在高档遥控玩具 如航模 包括飞