IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32F407VET6控制MG996R 180度舵机 -> 正文阅读

[嵌入式]STM32F407VET6控制MG996R 180度舵机

STM32F407VET6控制MG996R 180度舵机

电赛之前想做一下板球控制系统,就先驱动一下舵机。

180与360度舵机

360度舵机与一般舵机的区别是:给一般舵机一个PWM信号,舵机会转到一个特定角度,而给360度舵机一个PWM信号,舵机会以一个特定的速度转动,类似与电机。但与电机不同的是,360舵机是闭环控制,速度控制稳定。
PWM 信号与360舵机转速的关系:

0.5ms----------------正向最大转速;

1.5ms----------------速度为0;

2.5ms----------------反向最大转速;

180度舵机为例:
0.5ms-------2.5%---------0度;

1ms ----------5%-------45度;

1.5ms--------7.5%--------90度;

2ms ----------10%-------135度;

2.5ms --------12.5-------180度;

180度舵机

如上,180度的舵机,角度值与占空比是一一对应的,不管你现在是多少角度,只要是一个给定的占空比,就会到达相应的角度。
以F407驱动,168MHz,TIM2~TIM7的时钟为84M,
舵机需要的周期为20ms,所以
psc = 84-1 = 83;
arr = 20000-1 = 19999;
这样就是 20000 * 84 / 84000000 = 0.02s = 20ms

使用的舵机为MG996R,
? 速度:4.8V@ 0.12±0.01sec/60°——6.0V@ 0.11±0.01sec/60°
? 扭力:4.8V@ 11kg-cm——6.0V@ 13kg-cm
? 电压:4.8V-6V
? 空载工作电流:220±20mA
? 堵转工作电流:2000±30mA
? 响应脉宽时间 ff5usec
? 角度偏差:回中差 ff1°,左右各 45° 误差 ff3°。
使用下面的共射极放大电路提供5V(4.8V到6V)的PWM控制舵机
在这里插入图片描述
由于共射极放大电路的反向功能,所以需要将占空比的值反过来,32输出的是5%占空比的方波,那么共射极输出的方波占空比就是95%

所以
0.5ms-------2.5%---------0度;40000-1000 = 39000;

1ms ----------5%-------45度;40000-2000 = 38000;

1.5ms--------7.5%--------90度;40000-3000 = 37000;

2ms ----------10%-------135度;40000-4000 = 36000;

2.5ms --------12.5%-------180度;40000-5000 = 35000;

CUBEMX配置生成代码(有部分TIM2定时器的配置)

/**
  ******************************************************************************
  * @file    tim.c
  * @brief   This file provides code for the configuration
  *          of the TIM instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "tim.h"

/* USER CODE BEGIN 0 */

/******************************************************************************************************
TIM1、TIM8~TIM11的时钟为APB2时钟的两倍即168M,
TIM2~TIM7、TIM12~TIM14的时钟为APB1的时钟的两倍即84M。
Tout = ((arr+1)*(psc+1))/Tclk;
*******************************************************************************************************/


/* USER CODE END 0 */

TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim3;

/* TIM2 init function */
void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 16799;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 4999;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */
	HAL_TIM_Base_Start_IT(&htim2); //使能定时器 2 和定时器 2 更新中断
  /* USER CODE END TIM2_Init 2 */

}
/* TIM3 init function */
void MX_TIM3_Init(void)
{

  /* USER CODE BEGIN TIM3_Init 0 */

  /* USER CODE END TIM3_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 41;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 39999;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 1000;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */
	HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1); //手动开启TIM3的PWM通道1
  /* USER CODE END TIM3_Init 2 */
  HAL_TIM_MspPostInit(&htim3);

}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspInit 0 */

  /* USER CODE END TIM2_MspInit 0 */
    /* TIM2 clock enable */
    __HAL_RCC_TIM2_CLK_ENABLE();

    /* TIM2 interrupt Init */
    HAL_NVIC_SetPriority(TIM2_IRQn, 1, 2);
    HAL_NVIC_EnableIRQ(TIM2_IRQn);
  /* USER CODE BEGIN TIM2_MspInit 1 */

  /* USER CODE END TIM2_MspInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspInit 0 */

  /* USER CODE END TIM3_MspInit 0 */
    /* TIM3 clock enable */
    __HAL_RCC_TIM3_CLK_ENABLE();
  /* USER CODE BEGIN TIM3_MspInit 1 */

  /* USER CODE END TIM3_MspInit 1 */
  }
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(timHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspPostInit 0 */

  /* USER CODE END TIM3_MspPostInit 0 */

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**TIM3 GPIO Configuration
    PA6     ------> TIM3_CH1
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN TIM3_MspPostInit 1 */

  /* USER CODE END TIM3_MspPostInit 1 */
  }

}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspDeInit 0 */

  /* USER CODE END TIM2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM2_CLK_DISABLE();

    /* TIM2 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM2_IRQn);
  /* USER CODE BEGIN TIM2_MspDeInit 1 */

  /* USER CODE END TIM2_MspDeInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspDeInit 0 */

  /* USER CODE END TIM3_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM3_CLK_DISABLE();
  /* USER CODE BEGIN TIM3_MspDeInit 1 */

  /* USER CODE END TIM3_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
/*****************************************
舵机 20ms的周期,20000*8400/84000000 = 0.02
使用PWM1模式1,有效电平是高电平,所以
***********************************************/
//设置舵机占空比,
void TIM3_CH1_PWM_SetPulse(u16 cmp)
{
	__HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_1,cmp);
}
/************************************
0.5ms-------2.5%---------0度;40000-1000 = 39000;

1ms ----------5%-------45度;40000-2000 = 38000;

1.5ms--------7.5%--------90度;40000-3000 = 37000;

2ms ----------10%-------135度;40000-4000 = 36000;

2.5ms --------12.5%-------180度;40000-5000 = 35000;
*************************************************/
//设定舵机旋转角度
void Servo_ANGLE(float angle)
{
	float temp = 0;
	if(angle > 180)
		angle = 180;
	temp = (angle / 180) * Servo_Period + Servo_Static;
	TIM3_CH1_PWM_SetPulse(Servo_Duty - temp);
	
}

/*******************************舵机占空比设置函数*******************************************/
void set_steering_gear_dutyfactor(u16 dutyfactor)
{
	//对占空比所需要的CCR值做边界处理
	dutyfactor = 2.5/20*PWM_PERIOD_COUNT < dutyfactor ? 2.5/20*PWM_PERIOD_COUNT : dutyfactor;
	dutyfactor = 0.5/20*PWM_PERIOD_COUNT > dutyfactor ? dutyfactor : 0.5/20*PWM_PERIOD_COUNT;
	
	TIM3_CH1_PWM_SetPulse(PWM_PERIOD_COUNT - dutyfactor);
}

/*******************************设置舵机角度,传入角度值然后计算占空比,调用占空比设置函数*******************************************/
void set_steering_gear_angle(u16 angle_temp)
{
	//把角度转换成占空比所需要的计数值
	angle_temp = (0.5 + angle_temp / 180.0 * (2.5 - 0.5)) / 20.0 * PWM_PERIOD_COUNT;
	set_steering_gear_dutyfactor(angle_temp);
}

//定时器2中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM2)
	{
		HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
	}
}


/* USER CODE END 1 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

封装舵机旋转角度函数

法1

(错误代码)

//设定舵机旋转角度
void Servo_ANGLE(u8 angle)
{
	u16 temp = 0;
	if(angle > 180)
		angle = 180;
	temp = (angle / 180) * Servo_Period + Servo_Static;
	
	TIM3_CH1_PWM_SetPulse(Servo_Duty - temp);
	
}

发现只有180度才是正常的,其他的都是2.5的占空比,也就是angle是0的时候对应的值,把各个值printf一遍才发现,是C语言基础知识不牢啊。angel只要设定的是<180度,那么一个小于180的数除以180一定是0啊。所以这样是错误的。

那么修改(改为float类型的变量):

//设定舵机旋转角度
void Servo_ANGLE(float angle)
{
	float temp = 0;
	if(angle > 180)
		angle = 180;
	temp = (angle / 180) * Servo_Period + Servo_Static;
	TIM3_CH1_PWM_SetPulse(Servo_Duty - temp);
	
}

法2

/*******************************舵机占空比设置函数*******************************************/
void set_steering_gear_dutyfactor(u16 dutyfactor)
{
	//对占空比所需要的CCR值做边界处理
	dutyfactor = 2.5/20*PWM_PERIOD_COUNT < dutyfactor ? 2.5/20*PWM_PERIOD_COUNT : dutyfactor;
	dutyfactor = 0.5/20*PWM_PERIOD_COUNT > dutyfactor ? dutyfactor : 0.5/20*PWM_PERIOD_COUNT;
	
	TIM3_CH1_PWM_SetPulse(PWM_PERIOD_COUNT - dutyfactor);
}

/*******************************设置舵机角度,传入角度值然后计算占空比,调用占空比设置函数*******************************************/
void set_steering_gear_angle(u16 angle_temp)
{
	//把角度转换成占空比所需要的计数值
	angle_temp = (0.5 + angle_temp / 180.0 * (2.5 - 0.5)) / 20.0 * PWM_PERIOD_COUNT;
	set_steering_gear_dutyfactor(angle_temp);
}
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-24 11:39:31  更:2021-07-24 11:40:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 10:16:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计