快速学习Stm32舵机控制板控制多个舵机运动以及调速

article/2025/8/18 18:17:54

本次分享stm32对多个舵机的控制,之前讲解过单个舵机的控制。以及控制原理,定时器的使用和pwm的输出来控制一个舵机的角度转向。这次就和大家分享一下多个舵机的控制以及调速。利用单片机实现对 8 个舵机的同时控制,掌握多个舵机控制程序实现方法。从单个舵机控制到多个舵机控制,理解定时器的分时复用。为扩展控制 16 路,24 路舵机打下坚实的基础。

多个舵机控制如下图所示
16路舵机控制板子(维特智能)
在这里插入图片描述
多个舵机控制方案

利用单个定时器中断法。该方案的实现方法是将舵机 20ms 的周期分解成若干份(由于舵机控制信号的最大高电平时间为 2.5 毫秒,故一般分成 8 份以上), 每一份时间完成一个舵机的控制。以将 20ms 平均分解成 8 份为例进行说明:单片机上电初始化时,先将所有的 IO 端口电平拉低;当定时器产生第一次溢出中断时,在中断服务程序中对定时器计数寄存器重新赋值,所赋值为第一个受控舵机控制信号的高电平时间值,并将 IO 口拉高;当定时器产生第二次中断时,继续给寄存器重新赋值,此次所赋值为 2.5ms 减去高电平所得时间值;剩下的17.5ms 时间内重复七次上述操作,这样即可同时完成 8 个舵机的控制。

每20mm的周期,把每个周期分为8分,每份2.5mm 控制一个舵机,总共控制8个舵机

参考demo 本次使用stm32f103 c8t6

主函数

 int main(void)
{   SysTick_Init();		//系统滴答定时器初始化 		Servor_GPIO_Config();Timer_Init();Timer_ON();while (1){	for(i=0;i<8;i++)           //每个舵机到0度{CPWM[i]=500; //给PWM舵机一个0.5ms的高电平脉冲,传入到定时器2 }Delay_ms(1000); for(i=0;i<8;i++)           //每个舵机到180度{CPWM[i]=2500;//给PWM舵机一个2.5ms的高电平脉冲,传入到定时器2 } Delay_ms(1000); }
} 

初始化i/o口

void Servor_GPIO_Config(void)	
{GPIO_InitTypeDef GPIO_InitStructure;	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA, ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable , ENABLE);GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8|GPIO_Pin_15;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_15;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOB, &GPIO_InitStructure);}

GPIO电平反转函数

//整个周期20ms,把每个周期分为8分,每份2.5mm 控制一个舵机,总共控制8个舵机,2.5mm 分为两个动作去做,每两个动作控制一个舵机一共16个动作,就是分时复用法,把时间分成几份去做单独的控制。
void Flip_GPIO_One(void)
{switch(count1)								 //将20ms的舵机控制周期分成8份,每2.5ms控制一个舵机运转{  											      //每个定时器控制8路舵机运转,3个定时器控制24路舵机运转case 1: TIM2->ARR=CPWM[1];		//0.5ms		 //将第一个舵机脉冲宽度值赋值给定时器2			GPIO_SetBits(GPIOB,GPIO_Pin_15);  //同时拉高控制舵机1的引脚的电break;case 2:TIM2->ARR=MAXPWM-CPWM[1]; 	//2ms	 //将2.5ms减去PWM脉宽值的数据赋值定时器2GPIO_ResetBits(GPIOB,GPIO_Pin_15);//同时拉低控制舵机1引脚的电平 break;							 //控制舵机1的引脚在剩下20ms-CPM[0]时间内将一直保持低电平,舵机1按照CPWM值转动case 3:	TIM2->ARR=CPWM[2]; GPIO_SetBits(GPIOA,GPIO_Pin_8);break;case 4:	TIM2->ARR=MAXPWM-CPWM[2];  GPIO_ResetBits(GPIOA,GPIO_Pin_8); break;case 5:	TIM2->ARR=CPWM[3];  GPIO_SetBits(GPIOB,GPIO_Pin_5); break;case 6:	TIM2->ARR=MAXPWM-CPWM[3];  GPIO_ResetBits(GPIOB,GPIO_Pin_5);	break;case 7:	TIM2->ARR=CPWM[4];  GPIO_SetBits(GPIOB,GPIO_Pin_4); break;case 8:	TIM2->ARR=MAXPWM-CPWM[4];  GPIO_ResetBits(GPIOB,GPIO_Pin_4);break;case 9:	TIM2->ARR=CPWM[5];  GPIO_SetBits(GPIOB,GPIO_Pin_3); break;case 10:TIM2->ARR=MAXPWM-CPWM[5];  GPIO_ResetBits(GPIOB,GPIO_Pin_3);break;case 11:TIM2->ARR=CPWM[6];  GPIO_SetBits(GPIOA,GPIO_Pin_15); break;case 12:TIM2->ARR=MAXPWM-CPWM[6];  GPIO_ResetBits(GPIOA,GPIO_Pin_15);break;case 13:TIM2->ARR=CPWM[7];  break;case 14:TIM2->ARR=MAXPWM-CPWM[7];  break;case 15:TIM2->ARR=CPWM[8];  break;case 16:TIM2->ARR=MAXPWM-CPWM[8]; count1=0; break;default:break;}	//count1++;
}

舵机控制函数1

void Servo1(void)           //time2 中断里面去调用
{		count1++; Flip_GPIO_One();						 //反转IO电平}

控制舵机速度方案

脉冲细分法。改方案的具体实现操作位:将预期 PWM 值分解成若干 PWM 值,每个 PWM 值对应舵机一个角度,即让舵机从起始位置转动若干次后到达预期位置。由于舵机控制信号的周期为 20ms,忽略舵机的实际转动时间,每产生一次预期 PWM 值,舵机将转动 N 次,将需要 20*Nms 的时间,如此可达到调速的目的。

控制舵机从500-2500之间运行
每次脉宽控制到(2500-500)/n次=脉宽值
通过调整脉宽值进行平滑运行。

/***************************************************************************************************************
函 数 名:作业初位置,末尾置更新函数  
功能描述:从缓存中取一个新的目标位置替换原来的目标位置,原来的目标位置变为新的初位置,一次更替:有效的数据是插补增量,和插补次数,知道这两个量,和当前初位置即可
备    注: 先进先出,循环访问	
****************************************************************************************************************/	void change(void)
{	unsigned char s;if(point_aim==1){point_aim=0;point_now=1;}else{point_aim=1;point_now=0;}n=pos[point_aim][0]/20;	//计算新的插补次数	for(s=1;s<9;s++)	//计算新的插补增量{if(pos[point_aim][s]>pos[point_now][s]){dp=pos[point_aim][s]-pos[point_now][s];dp0[s]=dp/n;}if(pos[point_aim][s]<=pos[point_now][s]){dp=pos[point_now][s]-pos[point_aim][s];dp0[s]=dp/n;dp0[s]=-dp0[s];}}m=0;				  	//m清0}
/***************************************************************************************************************
函 数 名:vpwm()  
功能描述:数据插补,插补时间间隔为20/12ms,由timer0控制,使舵机平滑实现速度控制:另一个功能是执行完一行后去更新下一行数据,即调用change()
备    注:
****************************************************************************************************************/	
void vpwm(void)		 
{unsigned char j=0;static unsigned char flag_Tover;m++;							//用来累加插补过的次数if(m==n)						//n是本行作业要插补的总次数{flag_Tover=1;				//一行数据的执行时间已经完成}for(j=1;j<9;j++){if(abs(CPWM[j]-pos[point_aim][j])<5){						   	//检测靠近终点位置//  how++;				   	//是,则累加一个CPWM[j]=pos[point_aim][j];//并且直接过度到终点位置}	else						//不靠近终点,继续插补{CPWM[j]=pos[point_now][j]+m*dp0[j];}} if(flag_Tover==1){								//从插补次数,和脉宽宽度两方面都到达终点,本作业行完成flag_Tover=0;change();}//return;}

总结
分时复用法
脉冲细分法

对于stm32针对单个舵机控制的原理上一次已经分享大家可以看一下上一期


http://chatgpt.dhexx.cn/article/1i496TP7.shtml

相关文章

51单片机舵机控制

51单片机舵机控制系统 概述硬件设计程序设计PWM波的产生矩阵按键功能与数码管显示参数传递完整程序 外加模块 概述 在这篇博客中&#xff0c;将介绍一个基于51单片机的舵机控制系统&#xff0c;其可以通过矩阵按键输入角度&#xff0c;舵机打到预定角度&#xff0c;并在数码管…

Arduino基础入门篇28—舵机控制

舵机是一种位置「角度」伺服的驱动器&#xff0c;适用于那些需要角度不断变化并可以保持的控制系统。目前在高档遥控玩具、航模、机器人中已经得到普遍使用。舵机是一种俗称&#xff0c;其实是一种伺服马达。本篇通过官方驱动库来实现舵机控制。 1. 舵机介绍 结构组成 舵机实…

OpenMV输出PWM,实现对舵机控制

OpenMV的定时器官方函数介绍&#xff1a;Timer类 – 控制内部定时器 目录 OpenMV的PWM资源介绍 为什么要用OpenMV输出PWM OpenMV的PWM资源分配 资源 注意 建议 PWM输出代码 代码讲解 Timer Timer.channel tim.channel与Timer.channel区别 Timer.channel解析 OpenM…

舵机控制原理及常见问题

舵机控制 工作电压&#xff1a;3.5V/4,2V/4.8V —— 6V/6.8V/7.2V/8.4V(看具体型号参数) 切记&#xff1a;舵机不要接在电脑USB上调试&#xff0c;舵机启动瞬间大电流&#xff08;10-24倍工作电流&#xff09;可能会导致电脑死机 注意事项&#xff1a;PWM波形正确时&#xf…

第9章 舵机控制

有一种电机可以在程序的控制下&#xff0c;在一定范围内连续改变输出轴角度并且可以保持住。这种电机最早被用在航模和船模等遥控模型中&#xff0c;控制各种舵面的转动&#xff0c;这就是舵机。现在舵机除了运用在 遥控模型中&#xff0c;也大量的运用在各种机器人、机械臂的关…

Arduino入门001 - 舵机控制

Arduio基础入门篇001 - 舵机控制 一、舵机介绍 1&#xff0c;结构组成 一般来讲舵机主要由以下几个部分组成&#xff0c;舵盘、减速齿轮组、位置反馈电位计、直流电机、控制电路等。舵机的输入线共有三条&#xff0c;如图1所示&#xff0c;红色中间&#xff0c;是电源线&…

舵机控制(STM32F103C8T6)

前言 本文是以STM32F103C8T6作为主控芯片&#xff0c;通过PB6端口输出PWM&#xff0c;实现控制180舵机。 一、舵机控制原理 &#xff08;一&#xff09;概述 舵机是一种位置伺服驱动器器&#xff0c;是一种带有输出轴的小装置。当我们向伺服器发送一个控制信号时&#xff0c;…

Java 源代码怎么执行的

许多 Java 虚拟机的执行引擎在执行 Java 代码的时候都是解释执行&#xff08;通过解释器执行&#xff09;和编译执行&#xff08;通过即时编译器产生本地代码执行&#xff09;混合运行。 大体流程为&#xff1a; 编写 java 文件源码通过 javac 编译器将 java 源码编译为字节码流…

Java基础-java程序代码截取字符串及判断字符串是否包含某个字符(串)

文章目录 有一串字符串&#xff0c;是一串拼接码&#xff0c;如何截取获取想要的字段&#xff1f;判断字符串是否包含某个字符&#xff08;串&#xff09;indexOf方法 有一串字符串&#xff0c;是一串拼接码&#xff0c;如何截取获取想要的字段&#xff1f; public class Inte…

编写高质量JAVA程序代码的建议

--------------------------------------------------------------------------------------------------- 前言&#xff1a;原著《改善JAVA程序的151个建议》有151个建议&#xff0c;我在拜读的过程根据自己的理解合并了其中的几个&#xff0c;并将每个建议的核心要义进行了一…

java简单记事本代码_简单记事本的java程序代码

展开全部 天啊&#xff0c; 冖_Na0 为什么会有62616964757a686964616fe4b893e5b19e31333262343038我编的记事本代码呢&#xff1f;&#xff1f;&#xff1f;呵呵……你肯定是“请教”过我的吧&#xff1f;&#xff1f; 呵呵……我自己编了一个&#xff0c;不过呢&#xff0c;没…

IntelliJ IDEA 写java程序代码

快捷键 注释 单行&#xff1a;选中代码 ctrl/ 再来一次就是取消 多行&#xff1a;选中代码 ctrlshift/ 再来一次就是取消 格式化 CtrlAltL

Android studio如何运行java程序代码

先看Java程序类 public class GGG {public static void main(String[] args) {System.out.println("我是java程序");} }就是这么简单的一个java程序&#xff0c;在之前studio上可以直接运行&#xff0c;但是像现在升级studio后就发现运行报错&#xff1a; 首先java…

怎样使用lntelliJ IDEA 编写Java程序代码?

下面使用IDEA创建一个Java程序&#xff0c;实现在控制台上打印HelloWorld!的功能&#xff0c;具体步骤如下。 1.创建Java项目 进入New Project界面后&#xff0c;单击New Project选项按钮创建新项目&#xff0c;弹出New Project对话框&#xff0c;如下图所示。 New Projeet 对…

Java学习代码合集

其实我学习java最根本的原因是&#xff1a;我是一个挺关注外在的人&#xff0c;虽然是个程序员&#xff0c;所以我很喜欢写出那些带有漂亮的界面的程序&#xff0c;因为C总是控制台&#xff0c;我不是很喜欢&#xff0c;在这份java代码合集中&#xff0c;我会记录自己学习Java界…

Java开发常用代码

一.获取UUID UUID uuid UUID.randomUUID(); String str uuid.toString(); // 去掉“-” String s str.replaceAll("-", "");二.获取固定格式的时间字符串 第一种 //获取当前时间对象 Date d new Date(); //创建日期格式化类对象,”yyyy/MM/dd HH:mm…

一个简单的Java例程

编写一个程序&#xff0c;输出如下&#xff1a; 1.在IDEA中新建一个helloworld类&#xff0c;注意Java中严格区分大小写 2.在文件中添加如下代码&#xff1a; 源代码如下&#xff1a; public class helloworld{public static void main(String[] args){System.out.println(&q…

Python3读取大文件的方法

Python3读取大文件的方法 1. 方法一&#xff1a;利用yield生成器2. 方法二&#xff1a;利用open()自带方法生成迭代对象&#xff0c;这个是一行一行的读取3. 二者的比较 1. 方法一&#xff1a;利用yield生成器 def readPart(filePath, size1024, encoding"utf-8"):w…

大文件处理(上传,下载)思考

文件处理一直都是前端人的心头病&#xff0c;如何控制好文件大小&#xff0c;文件太大上传不了&#xff0c;文件下载时间太长&#xff0c;tcp直接给断开了&#x1f631;&#x1f631;&#x1f631;等 效果 为了方便大家有意义的学习&#xff0c;这里就先放效果图&#xff0c;如…

python拆分大文件(大文件分割)

python拆分大文件 前言实现过程实验结果 前言 在工作中常常会遇见一些大文件&#xff0c;由于内容太多&#xff0c;使用比如记事本、notePad等软件也打不开&#xff0c;无法查看内容&#xff0c;最好是将整个文件进行拆分&#xff0c;分开处理&#xff0c;现在处理的文件原本是…