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


文章目录

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

前言

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


1. 头文件和全局变量

c 复制代码
#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初始化函数

c 复制代码
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初始化函数

c 复制代码
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. 舵机增量偏移计算函数

c 复制代码
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. 舵机引脚电平设置函数

c 复制代码
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中断服务函数

c 复制代码
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. 舵机初始化函数

c 复制代码
void pwmServo_init(void)
{
    servo_gpio_init();
    TIM7_Init();
}

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

8. 舵机角度设置函数

c 复制代码
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. 舵机停止运动函数

c 复制代码
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. 舵机偏差设置函数

c 复制代码
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信号,控制舵机的角度和运动。代码结构清晰,功能模块化,便于维护和扩展。


相关推荐
智商偏低22 分钟前
单片机之helloworld
单片机·嵌入式硬件
青牛科技-Allen2 小时前
GC3910S:一款高性能双通道直流电机驱动芯片
stm32·单片机·嵌入式硬件·机器人·医疗器械·水泵、
森焱森4 小时前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
白鱼不小白4 小时前
stm32 USART串口协议与外设(程序)——江协教程踩坑经验分享
stm32·单片机·嵌入式硬件
S,D4 小时前
MCU引脚的漏电流、灌电流、拉电流区别是什么
驱动开发·stm32·单片机·嵌入式硬件·mcu·物联网·硬件工程
芯岭技术7 小时前
PY32F002A单片机 低成本控制器解决方案,提供多种封装
单片机·嵌入式硬件
youmdt8 小时前
Arduino IDE ESP8266连接0.96寸SSD1306 IIC单色屏显示北京时间
单片机·嵌入式硬件
嘿·嘘8 小时前
第七章 STM32内部FLASH读写
stm32·单片机·嵌入式硬件
Meraki.Zhang8 小时前
【STM32实践篇】:I2C驱动编写
stm32·单片机·iic·驱动·i2c
几个几个n10 小时前
STM32-第二节-GPIO输入(按键,传感器)
单片机·嵌入式硬件