程序代码篇---STM舵机控制

news/2025/3/14 0:47:17/

文章目录

  • 前言
  • 1. 头文件和全局变量
  • 2. 舵机GPIO初始化函数
  • 3. TIM7初始化函数
  • 4. 舵机增量偏移计算函数
  • 5. 舵机引脚电平设置函数
  • 6. TIM7中断服务函数
  • 7. 舵机初始化函数
  • 8. 舵机角度设置函数
  • 9. 舵机停止运动函数
  • 10. 舵机偏差设置函数
  • 总结


前言

本次代码实现了基于STM32的舵机控制功能,主要包括舵机的GPIO初始化、PWM信号生成、舵机角度设置、停止运动以及偏差设置等功能。下面我将逐部分详细解释这段代码。


1. 头文件和全局变量

#include "y_servo/y_servo.h"pwmServo_t pwmServo_angle[SERVO_NUM];

#include “y_servo/y_servo.h”:包含了舵机相关的头文件,可能定义了舵机的配置和函数声明。
pwmServo_t pwmServo_angle[SERVO_NUM]:定义了一个全局数组,用于存储每个舵机的控制参数(目标角度、当前角度、增量、时间等)。

2. 舵机GPIO初始化函数

static void servo_gpio_init(void)
{u8 i;GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(SERVO0_GPIO_CLK | SERVO1_GPIO_CLK | SERVO2_GPIO_CLK | SERVO3_GPIO_CLK | SERVO4_GPIO_CLK | SERVO5_GPIO_CLK, ENABLE); /* 使能 舵机 端口时钟 */GPIO_InitStructure.GPIO_Pin = SERVO0_PIN;         /* 配置引脚 */GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /* IO翻转50MHZ */GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  /* 推挽输出 */GPIO_Init(SERVO0_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = SERVO1_PIN;GPIO_Init(SERVO1_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = SERVO2_PIN;GPIO_Init(SERVO2_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = SERVO3_PIN;GPIO_Init(SERVO3_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = SERVO4_PIN;GPIO_Init(SERVO4_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = SERVO5_PIN;GPIO_Init(SERVO5_GPIO_PORT, &GPIO_InitStructure);for (i = 0; i < SERVO_NUM; i++){pwmServo_angle[i].aim = 1500;pwmServo_angle[i].current = 1500;pwmServo_angle[i].increment = 0;pwmServo_angle[i].time = 5000;pwmServo_angle[i].bias = 0;}
}

功能:初始化舵机的GPIO引脚,配置为推挽输出模式,并初始化舵机控制参数。
关键点:
RCC_APB2PeriphClockCmd:使能舵机GPIO端口的时钟。
GPIO_InitStructure:配置GPIO引脚为推挽输出模式,速度为50MHz。
for循环:初始化每个舵机的控制参数,默认角度为1500(舵机中位),时间5000ms,偏差为0。

3. TIM7初始化函数

static void TIM7_Init(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE); //使能定时器的时钟TIM_TimeBaseStructure.TIM_Prescaler = 71;            // 预分频器TIM_TimeBaseStructure.TIM_Period = 9;                //设定计数器自动重装值TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure);TIM_ClearFlag(TIM7, TIM_FLAG_Update);               //清除TIM的更新标志位TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE);//中断优先级NVIC设置NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;              //TIM中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;    //先占优先级0级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;           //从优先级1级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;              //IRQ通道被使能NVIC_Init(&NVIC_InitStructure);                              //初始化NVIC寄存器TIM_Cmd(TIM7, ENABLE);
}

功能:初始化TIM7定时器,用于生成PWM信号控制舵机
关键点:
TIM_TimeBaseStructure.TIM_Prescaler = 71:设置预分频器,将系统时钟分频
TIM_TimeBaseStructure.TIM_Period = 9:设置定时器自动重装值,控制PWM周期。
TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE):使能定时器更新中断。
NVIC_Init:配置TIM7中断优先级

4. 舵机增量偏移计算函数

static void servo_increment_offset(uint8_t index)
{int aim_temp;if (pwmServo_angle[index].increment != 0){aim_temp = pwmServo_angle[index].aim + pwmServo_angle[index].bias;if (aim_temp > 2490)aim_temp = 2490;else if (aim_temp < 500)aim_temp = 500;if (abs(aim_temp - pwmServo_angle[index].current) <= fabs(pwmServo_angle[index].increment + pwmServo_angle[index].increment)){pwmServo_angle[index].current = aim_temp;pwmServo_angle[index].increment = 0;}else{pwmServo_angle[index].current += pwmServo_angle[index].increment;}}
}

功能:根据目标角度和当前角度计算舵机增量偏移,逐步调整舵机角度。
关键点:
aim_temp:计算目标角度加上偏差后的值。
if (aim_temp > 2490):限制舵机角度在500到2490之间。
pwmServo_angle[index].current += pwmServo_angle[index].increment;:逐步调整当前角度。

5. 舵机引脚电平设置函数

static void servo_pin_set(u8 index, BitAction level)
{switch (index){case 0:SERVO0_PIN_SET(level);break;case 1:SERVO1_PIN_SET(level);break;case 2:SERVO2_PIN_SET(level);break;case 3:SERVO3_PIN_SET(level);break;case 4:SERVO4_PIN_SET(level);break;case 5:SERVO5_PIN_SET(level);break;default:break;}
}

功能:根据舵机索引设置对应引脚的电平
关键点:
SERVO0_PIN_SET(level):设置舵机引脚电平(高或低)。

6. TIM7中断服务函数

void TIM7_IRQHandler(void)
{static u8 flag = 0;static u8 duoji_index1 = 0;int temp;if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET) //检查TIM更新中断发生与否{/* 通过改变重装载值和舵机下标索引,每个舵机定时2500(2.5ms),执行8个舵机后完成一个周期20000(20ms) */if (duoji_index1 == 8){duoji_index1 = 0;}if (flag == 0){TIM7->ARR = ((unsigned int)(pwmServo_angle[duoji_index1].current));servo_pin_set(duoji_index1, Bit_SET);servo_increment_offset(duoji_index1);}else{temp = 2500 - (unsigned int)(pwmServo_angle[duoji_index1].current);TIM7->ARR = temp;servo_pin_set(duoji_index1, Bit_RESET);duoji_index1++;}flag = !flag;TIM_ClearITPendingBit(TIM7, TIM_IT_Update);    //清除TIMx更新中断标志}
}

功能:TIM7中断服务函数,用于生成PWM信号控制舵机
关键点:

TIM7->ARR:设置定时器自动重装值,控制PWM占空比。
servo_pin_set:设置舵机引脚电平。
servo_increment_offset:逐步调整舵机角度。

7. 舵机初始化函数

void pwmServo_init(void)
{servo_gpio_init();TIM7_Init();
}

功能:初始化舵机GPIO和TIM7定时器。

8. 舵机角度设置函数

void pwmServo_angle_set(uint8_t index, int aim, int time)
{uint8_t i;//角度数据超出范围,退出if ((aim > 2500) || (aim < 500))return;if (index == 255){for (i = 0; i < SERVO_NUM; i++){pwmServo_angle[i].aim = aim;pwmServo_angle[i].increment = (float)((pwmServo_angle[i].aim - pwmServo_angle[i].current) / (pwmServo_angle[i].time / 20.000));pwmServo_angle[i].time = time;}return;}/* 限制输入值大小 */if (index >= SERVO_NUM)return;if (time > 10000)time = 10000;if (time < 20) /* 执行时间太短,舵机直接以最快速度运动 */{pwmServo_angle[index].aim = aim;pwmServo_angle[index].current = aim;pwmServo_angle[index].increment = 0;}else{pwmServo_angle[index].aim = aim;pwmServo_angle[index].time = time;pwmServo_angle[index].increment = (float)((pwmServo_angle[index].aim - pwmServo_angle[index].current) / (pwmServo_angle[index].time / 20.000));}
}

功能:设置舵机的目标角度和执行时间。
关键点:
if (index == 255):如果索引为255,设置所有舵机的角度。
pwmServo_angle[index].increment:计算舵机角度的增量。

9. 舵机停止运动函数

void pwmServo_stop_motion(uint8_t index)
{uint8_t i;if (index == 255){for (i = 0; i < SERVO_NUM; i++){pwmServo_angle[i].aim = pwmServo_angle[index].current;pwmServo_angle[i].increment = 0.001;}return;}/* 限制输入值大小 */if (index >= SERVO_NUM)return;pwmServo_angle[index].aim = pwmServo_angle[index].current;pwmServo_angle[index].increment = 0.001;
}

功能:停止舵机运动。

10. 舵机偏差设置函数

void pwmServo_bias_set(uint8_t index, int bias)
{/* 限制输入值大小 */if (index >= SERVO_NUM)return;pwmServo_angle[index].bias = bias;pwmServo_angle[index].increment = 0.001;
}

功能:设置舵机的偏差值。

总结

这段代码实现了基于STM32的舵机控制功能,通过TIM7定时器生成PWM信号,控制舵机的角度和运动。代码结构清晰,功能模块化,便于维护和扩展。



http://www.ppmy.cn/news/1578928.html

相关文章

代码随想录算法训练营第十天,150.逆波兰表达式求值,239.滑动窗口最大值,347.前K个高频元素

今日内容&#xff1a;150.逆波兰表达式求值&#xff0c;239.滑动窗口最大值&#xff0c;347.前K个高频元素&#xff0c;栈与队列总结 心得&#xff1a;昨天休息了一天&#xff0c;栈与队列的题都比较典型&#xff0c;之前也是恶补过堆栈的知识&#xff0c;所以做起来相对kmp好一…

go下的Prototype学习笔记

本博文讲解prototype的学习笔记&#xff0c;内容包含了syntax、option go_package、message、service进行讲解&#xff0c;举例了常见写法。 文章目录 1.syntax 声明语法版本2.package 给当前的proto分配包名称3.option4.message4.1 切片数组4.2 map4.3 类型嵌套 5. 消息定义 …

使用vue3.0+electron搭建桌面应用并打包exe

使用vue3.0electron搭建桌面应用并打包exe_如何使用electron将vue3vite开发完的项目打包成exe应用程序-CSDN博客

c语言闯算法--常用技巧

双指针 类别&#xff1a; 同向快慢指针 异常情况&#xff0c;慢指针才动 双向指针 视情况&#xff0c;左右指针动 最长无重复子串 int max(int a, int b){if(a < b){return b;}else{return a;} } int lengthOfLongestSubstring(char* s) {int count[300];for(int i 0; i …

git subtree更新子仓库的方式

在使用 git subtree 管理的仓库中&#xff0c;子仓库的更新可以通过以下步骤完成&#xff1a; 1. 更新子仓库到主仓库 如果子仓库有新的更新&#xff0c;可以将这些更新拉取到主仓库中&#xff1a; git subtree pull --prefix<子仓库路径> <子仓库地址> <分支…

分类操作-01.新增分类

一.新增分类 对员工操作完成后&#xff0c;我们要进行分类操作。分类就是对菜品进行集中管理&#xff0c;将菜品进行分类。分类总大类分为两类&#xff0c;一类是菜品分类&#xff0c;另一类是套餐分类。对于分类&#xff0c;我们定义实体类Category.class。DTO类CategoryDTO.…

代理(Delegate)、闭包(Closure)、Notification(通知中心) 和 swift_event_bus适用场景和工作方式

在 Swift 开发中&#xff0c;在 Swift 开发中&#xff0c;代理&#xff08;Delegate&#xff09;、闭包&#xff08;Closure&#xff09;、Notification&#xff08;通知中心&#xff09; 和 swift_event_bus 主要用于 组件之间的通信&#xff0c;但它们的适用场景和工作方式有…

卷积神经网络(CNN):深度解析其原理与特性

卷积神经网络&#xff08;CNN&#xff09;&#xff1a;深度解析其原理与特性 作为一名深度学习研究者&#xff0c;你可能对Transformer架构的自注意力机制和序列建模能力了如指掌&#xff0c;但对计算机视觉领域的传统霸主——卷积神经网络&#xff08;Convolutional Neural N…