记录一下今天参考别人的代码实现了四个电机的测速。

编码器被广泛应用于电机测速,实现电机闭环控制。所以不论是自己做小车还是后续参加各种比赛,必须要学会编码器测速。

一.参数

编码电机其实就是一个带有编码器的电机,我的这个电机是一个带霍尔传感器的电机,型号是JGB37-520,然后我的电机减速比是30(一定要记住,买的时候也要看清电机减速比是多少,涉及到转速的计算),额定电压12V,然后就是编码器的参数了,见下图

电机驱动模块我用的TB6612的四路的板子,就是下面这款,很好用,就是稍微有点贵。

二.常用测速方法

主要分为M法、T法和M/T法,详情见这篇文章STM32 CubeMax 编码器电机测速 原理与实现

三.CubeMX配置

首先是配置PWM输出定时器,我这里使用的是TIM8

然后再配置编码器输入定时器TIM2,TIM3\TIM4\TIM5按照相同的参数配置

这里开启了两个通道计数,就是倍频技术的4倍频

编码器模式下的定时器其实是个计数器,在编码器的脉冲到来时,Counter会相应地加和减,正转时加,反转时减,溢出后到达另一个极端值,比如说向上计数到达20001时会变成0

再设置每隔10ms读取定时器的值的定时器TIM6

最后注意中断优先级TIM6要小于编码器计数的定时器。

四.代码

encoder.c

#include "encoder.h"Motor motor1;
Motor motor2;
Motor motor3;
Motor motor4;
int t1,t2,t3,t4,j1,j2,j3,j4;void Motor_Init(void)
{HAL_TIM_Encoder_Start(&ENCODER_TIM1, TIM_CHANNEL_ALL);      //开启编码器定时器HAL_TIM_Encoder_Start(&ENCODER_TIM2, TIM_CHANNEL_ALL); HAL_TIM_Encoder_Start(&ENCODER_TIM3, TIM_CHANNEL_ALL); HAL_TIM_Encoder_Start(&ENCODER_TIM4, TIM_CHANNEL_ALL); __HAL_TIM_ENABLE_IT(&ENCODER_TIM1,TIM_IT_UPDATE);           //开启编码器定时器更新中断,防溢出处理__HAL_TIM_ENABLE_IT(&ENCODER_TIM2,TIM_IT_UPDATE); __HAL_TIM_ENABLE_IT(&ENCODER_TIM3,TIM_IT_UPDATE); __HAL_TIM_ENABLE_IT(&ENCODER_TIM4,TIM_IT_UPDATE); HAL_TIM_Base_Start_IT(&GAP_TIM);                       //开启10ms定时器中断__HAL_TIM_SET_COUNTER(&ENCODER_TIM1, 10000);                //编码器定时器初始值设定为10000__HAL_TIM_SET_COUNTER(&ENCODER_TIM2, 10000);__HAL_TIM_SET_COUNTER(&ENCODER_TIM3, 10000);__HAL_TIM_SET_COUNTER(&ENCODER_TIM4, 10000);motor1.lastCount = 0;                                   //结构体内容初始化motor1.totalCount = 0;motor1.overflowNum = 0;                                  motor1.speed = 0;motor1.direct = 0;motor2.lastCount = 0;                                   //结构体内容初始化motor2.totalCount = 0;motor2.overflowNum = 0;                                  motor2.speed = 0;motor2.direct = 0;motor3.lastCount = 0;                                   //结构体内容初始化motor3.totalCount = 0;motor3.overflowNum = 0;                                  motor3.speed = 0;motor3.direct = 0;motor4.lastCount = 0;                                   //结构体内容初始化motor4.totalCount = 0;motor4.overflowNum = 0;                                  motor4.speed = 0;motor4.direct = 0;
}
//M法测速度
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//定时器回调函数,用于计算速度
{if(htim->Instance==ENCODER_TIM1.Instance)//编码器输入定时器溢出中断                    {      if(COUNTERNUM1 < 10000) motor1.overflowNum++;       //如果是向上溢出else if(COUNTERNUM1 >= 10000) motor1.overflowNum--; //如果是向下溢出__HAL_TIM_SetCounter(&ENCODER_TIM1, 10000);             //重新设定初始值if(COUNTERNUM2 < 10000) motor2.overflowNum++;       //如果是向上溢出else if(COUNTERNUM2 >= 10000) motor2.overflowNum--; //如果是向下溢出__HAL_TIM_SetCounter(&ENCODER_TIM2, 10000);             //重新设定初始值if(COUNTERNUM3 < 10000) motor3.overflowNum++;       //如果是向上溢出else if(COUNTERNUM3 >= 10000) motor3.overflowNum--; //如果是向下溢出__HAL_TIM_SetCounter(&ENCODER_TIM3, 10000);             //重新设定初始值if(COUNTERNUM4 < 10000) motor4.overflowNum++;       //如果是向上溢出else if(COUNTERNUM4 >= 10000) motor4.overflowNum--; //如果是向下溢出__HAL_TIM_SetCounter(&ENCODER_TIM4, 10000);             //重新设定初始值}else if(htim->Instance==GAP_TIM.Instance)//间隔定时器中断,是时候计算速度了{motor1.direct = __HAL_TIM_IS_TIM_COUNTING_DOWN(&ENCODER_TIM1);//如果向上计数(正转),返回值为0,否则返回值为1motor1.totalCount = COUNTERNUM1 + motor1.overflowNum * RELOADVALUE1;//一个周期内的总计数值等于目前计数值加上溢出的计数值motor1.speed = (float)(motor1.totalCount - motor1.lastCount) / (4 * MOTOR_SPEED_RERATIO * PULSE_PRE_ROUND) * 10;//算得每秒多少转if(motor1.direct==0){t1=motor1.speed/1;j1=(motor1.speed-t1)*10000;}else{t1=-motor1.speed/1;j1=-(motor1.speed+t1)*10000;}//motor1.speed = (float)(motor1.totalCount - motor1.lastCount) / (4 * MOTOR_SPEED_RERATIO * PULSE_PRE_ROUND) * 10 * LINE_SPEED_C//算得车轮线速度每秒多少毫米motor1.lastCount = motor1.totalCount; //记录这一次的计数值  motor2.direct = __HAL_TIM_IS_TIM_COUNTING_DOWN(&ENCODER_TIM2);//如果向上计数(正转),返回值为0,否则返回值为1motor2.totalCount = COUNTERNUM2 + motor1.overflowNum * RELOADVALUE2;//一个周期内的总计数值等于目前计数值加上溢出的计数值motor2.speed = (float)(motor2.totalCount - motor2.lastCount) / (4 * MOTOR_SPEED_RERATIO * PULSE_PRE_ROUND) * 10;//算得每秒多少转if(motor2.direct==0){t2=motor2.speed/1;j2=(motor2.speed-t2)*10000;}else{t2=-motor2.speed/1;j2=-(motor2.speed+t2)*10000;}//motor1.speed = (float)(motor1.totalCount - motor1.lastCount) / (4 * MOTOR_SPEED_RERATIO * PULSE_PRE_ROUND) * 10 * LINE_SPEED_C//算得车轮线速度每秒多少毫米motor2.lastCount = motor2.totalCount; //记录这一次的计数值motor3.direct = __HAL_TIM_IS_TIM_COUNTING_DOWN(&ENCODER_TIM3);//如果向上计数(正转),返回值为0,否则返回值为1motor3.totalCount = COUNTERNUM3 + motor3.overflowNum * RELOADVALUE3;//一个周期内的总计数值等于目前计数值加上溢出的计数值motor3.speed = (float)(motor3.totalCount - motor3.lastCount) / (4 * MOTOR_SPEED_RERATIO * PULSE_PRE_ROUND) * 10;//算得每秒多少转if(motor3.direct==0){t3=motor3.speed/1;j3=(motor3.speed-t3)*10000;}else{t3=-motor3.speed/1;j3=-(motor3.speed+t3)*10000;}//motor1.speed = (float)(motor1.totalCount - motor1.lastCount) / (4 * MOTOR_SPEED_RERATIO * PULSE_PRE_ROUND) * 10 * LINE_SPEED_C//算得车轮线速度每秒多少毫米motor3.lastCount = motor3.totalCount; //记录这一次的计数值motor4.direct = __HAL_TIM_IS_TIM_COUNTING_DOWN(&ENCODER_TIM4);//如果向上计数(正转),返回值为0,否则返回值为1motor4.totalCount = COUNTERNUM4 + motor4.overflowNum * RELOADVALUE4;//一个周期内的总计数值等于目前计数值加上溢出的计数值motor4.speed = (float)(motor4.totalCount - motor4.lastCount) / (4 * MOTOR_SPEED_RERATIO * PULSE_PRE_ROUND) * 10;//算得每秒多少转if(motor4.direct==0){t4=motor4.speed/1;j4=(motor4.speed-t4)*10000;}else{t4=-motor4.speed/1;j4=-(motor4.speed+t4)*10000;}//motor1.speed = (float)(motor1.totalCount - motor1.lastCount) / (4 * MOTOR_SPEED_RERATIO * PULSE_PRE_ROUND) * 10 * LINE_SPEED_C//算得车轮线速度每秒多少毫米motor4.lastCount = motor4.totalCount; //记录这一次的计数值}
}           

encoder.h

#ifndef _ENCODER_H_
#define _ENCODER_H_#include "stm32f1xx.h"
#include "tim.h"//定时器号
#define ENCODER_TIM1 htim2
#define ENCODER_TIM2 htim3
#define ENCODER_TIM3 htim4
#define ENCODER_TIM4 htim5#define GAP_TIM     htim6#define MOTOR_SPEED_RERATIO 30u    //电机减速比
#define PULSE_PRE_ROUND 11 //一圈多少个脉冲
#define RADIUS_OF_TYRE 40 //轮胎半径,单位毫米
#define LINE_SPEED_C RADIUS_OF_TYRE * 2 * 3.14#define RELOADVALUE1 __HAL_TIM_GetAutoreload(&ENCODER_TIM1)    //获取自动装载值,本例中为20000
#define COUNTERNUM1 __HAL_TIM_GetCounter(&ENCODER_TIM1)        //获取编码器定时器中的计数值#define RELOADVALUE2 __HAL_TIM_GetAutoreload(&ENCODER_TIM2)
#define COUNTERNUM2 __HAL_TIM_GetCounter(&ENCODER_TIM2) #define RELOADVALUE3 __HAL_TIM_GetAutoreload(&ENCODER_TIM3)
#define COUNTERNUM3 __HAL_TIM_GetCounter(&ENCODER_TIM3) #define RELOADVALUE4 __HAL_TIM_GetAutoreload(&ENCODER_TIM4)
#define COUNTERNUM4 __HAL_TIM_GetCounter(&ENCODER_TIM4) typedef struct _Motor
{int32_t lastCount;   //上一次计数值int32_t totalCount;  //总计数值int16_t overflowNum; //溢出次数float speed;         //电机转速uint8_t direct;      //旋转方向
}Motor;
extern int t1,t2,t3,t4,j1,j2,j3,j4;
void Motor_Init(void);
void HAL_TIM_PeriodElapsedCallback1(TIM_HandleTypeDef *htim);#endif

main.c

/* USER CODE BEGIN Header */
/********************************************************************************* @file           : main.c* @brief          : Main program body******************************************************************************* @attention** Copyright (c) 2023 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "bluetooth.h"
#include "Control.h"
#include "oled.h"
#include "encoder.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_TIM8_Init();MX_USART1_UART_Init();MX_I2C2_Init();MX_TIM2_Init();MX_TIM6_Init();MX_TIM3_Init();MX_TIM4_Init();MX_TIM5_Init();/* USER CODE BEGIN 2 */HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1);/* USER CODE END 2 */OLED_Init();OLED_CLS();OLED_ShowChar(14,1,'.',15);OLED_ShowChar(14,2,'.',15);OLED_ShowChar(14,3,'.',15);OLED_ShowChar(14,4,'.',15);OLED_ShowStr(50,5,"By Whelve",2);OLED_ShowStr(60,1,"r/s",1);OLED_ShowStr(60,2,"r/s",1);OLED_ShowStr(60,3,"r/s",1);OLED_ShowStr(60,4,"r/s",1);Motor_Init();/* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */Control();OLED_ShowNum(0,1,t1,2,15);OLED_ShowNum(18,1,j1,5,15);OLED_ShowNum(0,2,t2,2,15);OLED_ShowNum(18,2,j2,5,15);OLED_ShowNum(0,3,t3,2,15);OLED_ShowNum(18,3,j3,5,15);OLED_ShowNum(0,4,t4,2,15);OLED_ShowNum(18,4,j4,5,15);/* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIState = RCC_HSI_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK){Error_Handler();}
}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//*** @brief  This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}#ifdef  USE_FULL_ASSERT
/*** @brief  Reports the name of the source file and the source line number*         where the assert_param error has occurred.* @param  file: pointer to the source file name* @param  line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

代码部分参考自STM32 CubeMax 编码器电机测速 原理与实现

最后效果不错

stm32编码器电机测速(hal库)相关推荐

  1. STM32之增量式编码器电机测速

    STM32之增量式编码器电机测速 编码器 编码器种类 按监测原理分类 光电编码器 霍尔编码器 按输出信号分类 增量式编码器 绝对式编码器 编码器参数 分辨率 精度 最大响应频率 信号输出形式 编码器倍 ...

  2. STM32 CubeMax 编码器电机测速 原理与实现

    编码器电机测速 部分参考:https://blog.csdn.net/lzzzzzzm/article/details/119416134 其他参考部分见图片水印 1. 编码器种类及原理 常见的编码器 ...

  3. STM32定时器编码器模式实现直流有刷电机测速(HAL库)

    前言 最近在做一个单片机大作业,要用到直流有刷,在这里把学习编码器的知识记录一下,学习参考资料: 正点原子DMF407电机控制专题教程_V1.0 编码器测速原理 我所使用的编码器是市面上常见的磁电增量 ...

  4. STM32C8T6编码器电机测速与arduino光电模块测速

    文章目录 前言 一.STM32编码器测速 定时器配置 配置四倍频 二.arduino光电测速 前言 前面也是只学习了四倍频测速的原理,并没有真正实验过,今天正好看到编码器电机了,就尝试一下 一.STM ...

  5. 学习笔记STM32F429使用编码器测速HAL库版本

    void TIM4_Init(u16 arr,u16 psc) { TIM4_Handler.Instance=TIM4; TIM4_Handler.Init.Prescaler=psc;       ...

  6. 51单片机电机测速程序c语言,单片机仿真编码器电机测速程序

    /***********头文件声明************/ #include "reg52.h"//此文件中定义了单片机的一些特殊功能寄存器 /***********数据类型声明 ...

  7. STM32应用(九)编码器及其测速原理、L298N电机驱动控制编码器电机

    文章目录 1.L298N电机驱动 1.1 产品参数 1.2 实物图和接线 2.编码器 2.1 编码器简介 2.2 常用编码器分类 2.3 霍尔编码器实物图接线!!!! 2.4 编码器倍频原理 3.控制 ...

  8. STM32定时器捕获编码器模式测速和方向测不准问题

    ** STM32定时器捕获编码器模式测速和方向测不准问题 问题概述 关于STM32编码器模式电机测速的资料网上一抓一大把,却发现真的拿过来用还是有问题的,比如刚刚做了个东西,是个个头比较大的麦克纳姆轮 ...

  9. STM32应用开发实践教程:智能小车电机测速模块的应用开发

    3.4.1 任务分析 本任务要求设计一个可实现智能小车电机测速的应用程序,具体要点如下. ① 取一个电机作为测速对象. ② 支持按键控制,使用 4 个按键,功能描述如下:  Key1 控制电机正转, ...

最新文章

  1. php文章排序,PHP+Ajax实现后台文章快速排序
  2. python压缩与解压缩
  3. LeetCode 922 Sort Array By Parity II 解题报告
  4. 微信小程序学习笔记(七)
  5. maven 分批打包_maven批量打包,并且显示打包结果
  6. HDLBits答案(14)_Verilog有限状态机(1)
  7. MySQL 5.7.10 免安装配置
  8. c# xls 复制一行_C# 复制Excel单元格格式
  9. open with code 报错没有项目_Python开发:解决Ubuntu安装tesserocr报错
  10. 一键安装lnmp脚本(包括软件版本)
  11. MySQL数据库概述
  12. HDFS的操作SHELL和API
  13. python 渐变色柱形图_Python利用imshow制作自定义渐变填充柱状图(colorbar)
  14. maven的基本命令
  15. twitter数据集_推特宠物数据整理及分析
  16. 后副车架焊接机器人_焊接机器人的工装设计和工装的使用方法
  17. 连接Mysql弹出2005_正确安装数据库SQL2005和安装出现的问题的解决方法
  18. hdu 1249 三角形 (递推)
  19. Faster R-CNN算法详细流程
  20. 计算机基础ps变换蝴蝶,PS利用自由变换制作飞舞的蝴蝶

热门文章

  1. 毕业后的第一年,往往都不会那么好过
  2. 陈安之:成功者都运用“潜意识”的力量
  3. 3分钟整明白啥是 缓存雪崩
  4. 房价上涨难以动摇,2016年持续上涨的局面。
  5. IE6 IE7 IE8 IE9 IE10 Css hack及IE条件注释法
  6. 谈思生物医疗直播—可瑞生物CEO谢兴旺博士“TCR创新药的现状和展望”
  7. C#如何判断当前输入的内容包含全角输入法的内容?
  8. 自适应滤波器算法综述以及代码实现
  9. 传统语音增强——最小均方(LMS)自适应滤波算法
  10. LaTex报错:Environment keywords undefined