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


相关推荐
honey ball16 分钟前
时钟频率和GPIO的设定【DSP】
单片机·嵌入式硬件
爱学习的张哥1 小时前
IP层之分片包的整合处理---BUG修复
单片机·tcp/ip·bug
ElePower95271 小时前
浅谈时钟启动和Systemlnit函数
单片机·嵌入式硬件
阿楠小波2 小时前
蓝桥杯嵌入式组第十二届省赛题目解析+STM32G431RBT6实现源码
c语言·stm32·单片机·学习·蓝桥杯
小麦嵌入式2 小时前
Linux驱动开发实战(四):设备树点RGB灯
linux·驱动开发·stm32·单片机·嵌入式硬件·物联网·ubuntu
风起逸尘2 小时前
硬件驱动——51单片机、LED、动态数码管
单片机·嵌入式硬件·51单片机
时空自由民.2 小时前
stm32官方 gcc编译案例
stm32·单片机·嵌入式硬件
与光同尘 大道至简2 小时前
从硬件定时器原理学会多任务调度
stm32·单片机·嵌入式硬件
Wnq100723 小时前
DDS:保障物联网系统的稳定运行和高效协作
java·数据结构·分布式·嵌入式硬件·物联网·深度优先·信号处理
weixin_580382066 小时前
stm32中分析UART中IDLE,RXNE,TC,TXE这些标志位的作用
stm32·单片机·嵌入式硬件