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 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32应用(九)编码器及其测速原理、L298N电机驱动控制编码器电机 -> 正文阅读

[嵌入式]STM32应用(九)编码器及其测速原理、L298N电机驱动控制编码器电机

1.L298N电机驱动

1.1 产品参数

在这里插入图片描述

1.2 实物图和接线

l298n电机驱动模块 电机正反转 电机调速

听完这个视频,这个小玩意你就会了。
在这里插入图片描述

在这里插入图片描述

1.当驱动电压(板子标识为VCC输入,实际可以接受的输入范围是7-12V。一般都是使用航模电池或买电池盒。

在电机驱动,单片机,编码器电机三者使用的过程中,一定要把三者的GND连在一起,也就是共地!!!

2.编码器

【电工知识】编码器是干什么用的,这下终于明白了!

2.1 编码器简介

编码器, 是将信号或数据进行编制、转换为可用以通讯、传输和存储的信号形式的设备。编码器把角位移或直线位移转换成电信号。是工业中常用的电机定位设备,可以精确的测试电机的角位移和旋转位置。 编码器最直接的作用就是可以测量位移,知道位移了就可以计算得到速度了。

简单点,编码器是用来测速的。放在电机上,可以解算出电机的转速

2.2 常用编码器分类

按输出信号分:增量式和绝对式

它们存着最大的区别:在增量编码器的情况下,位置是从零位标记开始计算的脉冲数量确定的,而绝对型编码器的位置是由输出代码的读数确定的。绝对型编码器并不与实际的位置分离。如果电源再次接通,那么位置读数仍是当前的、有效的,不像增量编码器那样,必须去寻找零位标记。

绝对式掉电不丢失读数值,增量式会丢失。

按传感技术分:光电式和霍尔式(激光式、磁式、感应式、电容式等)

1.光电式:就像下图里的一样。当光线透过齿轮盘时,接收器会计数一次,并再传送给CPU。不同的转速,自然在相同时间内的计数值不一样。进而达到测速的功能。(个人理解)

在这里插入图片描述

2.霍尔式
【Arduino 101】霍尔编码器与闭环控制(白话)
霍尔编码器是由霍尔码盘和霍尔元件组成。霍尔码盘是在一定直径的圆板上等分地布置有不同的磁极。霍尔码盘与电动机同轴,电动机旋转时,霍尔元件检测输出若干脉冲信号,为判断转向,一般输出两组存在一定相位差的方波信号(通常相差90°)。

测速还是计算相同时间内的脉冲数,而判断转向呢?

可以看到下图,当顺时针旋转时,A相处在下降沿时,B相是高电平。A相处在上升沿时,B相是低电平;当逆时针旋转时,(即把上面的波形从右向左看)A相处在下降沿时,B相是低电平。A相处在上升沿时,B相是高电平。进而判断正反转。

在这里插入图片描述

2.3 霍尔编码器实物图接线

在这里插入图片描述

编码器单片机
A相接单片机的脉冲检测接口
B相接单片机的脉冲检测接口
+5V(VCC)+5V
GNDGND
编码器电机驱动
M+接电机驱动的输出OUT1
M-接电机驱动的输出OUT2

2.4 编码器倍频原理

编码器计数原理与电机测速原理
在这里插入图片描述

在这里插入图片描述

3.控制编码器电机(PWM模式)

3.1 电机介绍

GB37520 电机为减速电机。即电机头部有一个减速器,电机转动带动减速器里的齿轮后再通过减速器的输出轴输出相应的转速。比如减速比是 1: 30,表示电机转动 30圈,电机的减速器转动一圈。
在这里插入图片描述
在这里插入图片描述

3.2 M法测速(很重要🐱?🏍)

在这里插入图片描述

  • T0是自行设定的时间。
  • M0是在设定时间内的脉冲数。
  • C是单圈总脉冲数。(直流电机轴旋转一圈在霍尔传感器每个引脚有 13个脉冲信号输出。)

这里的磁环是固定在直流电机转轴上的,与减速电机的输出轴是不一样的。减速电机的输出轴是经过减速齿轮变换后的,之前有介绍到该电机的减速比为:1:30, 所以, 如果减速电机输出轴旋转一圈,实际上可以检测到的编码器每相脉冲数量为:13*30=390 个。 再通过单片机的编码器接口4 倍频就是 1560个脉冲信号, 这在我们计算实际位移和速度非常有用。

算出来的n是直流电机的转速,正常来说可以使用了,但我使用的是减速电机。要想得到真正输出轴的转速,还需要除减速比

3.3 工程配置

1.开启PWM的通道1,2作为L298N的输入1,2
在这里插入图片描述

此时的计数值1000,可以理解为最大输出电压数字量是1000。如果我的供电电压是12V,并在程序中设置PWM的输出值为800。则驱动电机的电压为9.6V。 在电机控制中,电压越大,电机转速越快,而通过PWM输出不同的模拟电压,便可以使电机达到不同的输出转速。

2.开启GPIO中断,并打开NVIC选项卡设置中断优先级
在这里插入图片描述
编码器自带了上拉电阻,所以无需外部上拉,可以直接连接到单片机I0读取。(我点上拉了,不过也没关系)
在这里插入图片描述
3.开启串口,检验效果
在这里插入图片描述

3.4 代码编写

int32_t Sum=0;
int32_t Last_sum=0;	//计算脉冲数目
float V_rotate=0;	//转子速度(圈/ms),电机速度等于转子/减速比
float V_Set;		//设定速度
float V_Out=0;		//减速电机速度


int8_t a=0;    //检测是否进入中断
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)//外部中断
{
	a=1;
	/******一倍频*******/
	if(GPIO_Pin==GPIO_PIN_1)//编码器计数,检测到PF1(A相)跳变沿
	{
		if (HAL_GPIO_ReadPin(GPIOF,GPIO_PIN_2)==1)//PF2(B相)高电平正转
			Sum++;
		else  
			Sum--;
	}
}

/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);
/* USER CODE END 2 */
while (1)
{
	__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,700);
	Last_sum=Sum;
	HAL_Delay(100);	
	V_rotate=(Sum-Last_sum)/1.30f; //转速(圈/s)
	V_Out=V_rotate/30;//电机速度单位(转/秒)
	printf("V_Out is %f\r\n",V_Out);
}

3.5 实验效果

在这里插入图片描述

4.控制编码器电机(编码器模式)

参考博客:STM32 Cubemax(六) —— STM32利用定时器编码器模式处理带编码器直流电机

这里可以延续上面的工程内容,需要修改以下几个方面。

4.1 工程配置

1.修改定时器TIM1为编码器模式
在这里插入图片描述
在这里插入图片描述

2.修改GPIO引脚和模式
在这里插入图片描述
3.开启TIM2_CHANNEL1
在这里插入图片描述
在这里插入图片描述

4.开启一个10ms定时器来写中断函数
在这里插入图片描述

4.2 实物连接和连线解释

在这里插入图片描述

电机驱动的输入IN1和IN2接输出GPIO,PE12和PE10,单片机输出的PWM信号接到电机驱动的ENA(使能端A,上下都行)。这样的话一路PWM通过IN1,IN2的状态来控制PWM输出信号输出到OUT1还是OUT2,进而控制正反转。

4.3 代码编写

0.基本函数测试

HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);//打开定时器的encoder模式
Direction = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim1);//可以获得当前电机的转向
enc1 = (__HAL_TIM_GET_COUNTER(&htim1));//获取encoder编码器的计数值

如果debug模式下enc1读数为0或为最大20000,建议接串口,用串口输出数据。

1.在阅读上面的博客完成配置后
motor.h:

#ifndef __MOTOR_H
#define __MOTOR_H

#include "main.h"
#include "tim.h"
#include "PID.h"

#define RR 30u    //电机减速比
#define RELOADVALUE __HAL_TIM_GetAutoreload(&htim1)    //获取自动装载值,本例中为20000
#define COUNTERNUM __HAL_TIM_GetCounter(&htim1)        //获取编码器定时器中的计数值
#define IN1(state) HAL_GPIO_WritePin(GPIOE,GPIO_PIN_12,(GPIO_PinState)(state))    //IN1
#define IN2(state) HAL_GPIO_WritePin(GPIOE,GPIO_PIN_10,(GPIO_PinState)(state))    //IN2

//电机结构体
typedef struct _Motor
{
	int32_t lastAngle;        //上10ms转过的角度
	int32_t totalAngle;       //总的角度
	int16_t loopNum;          //防超上限
	float speed;              //电机输出轴目前转速,单位为RPM
	float set;
}Motor;

void Motor_Init(void);
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
void Clockwise_rotation(void);
void Counterclockwise_rotation(void);
void stop(void);

#endif

motor.c:

#include "motor.h"

Motor motor;

void Motor_Init(void)
{
	HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);      //开启编码器定时器
  __HAL_TIM_ENABLE_IT(&htim1,TIM_IT_UPDATE);         	 //开启编码器定时器更新中断,防溢出处理
	HAL_TIM_Base_Start_IT(&htim6);                       //开启10ms定时器中断
	HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);            //开启PWM
	__HAL_TIM_SET_COUNTER(&htim1, 10000);                //编码器定时器初始值设定为10000
	motor.loopNum = 0;                                   //防溢出
}


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==htim6.Instance)		         //10ms中断
	{
		int16_t pluse = COUNTERNUM - RELOADVALUE/2;											
		motor.totalAngle = pluse + motor.loopNum * RELOADVALUE/2;  
		motor.speed = (float)(motor.totalAngle - motor.lastAngle)/(4*13*RR)*6000;			//进行速度计算,根据前文所说的,4倍频,编码器13位,减速比30,再乘以6000即为每分钟输出轴多少转
		motor.lastAngle = motor.totalAngle;         //更新转过的圈数
	}
	else if(htim->Instance == htim1.Instance)      //如果是编码器更新中断,即10ms内,脉冲数超过了计数范围,需要进行处理
	{
		if(COUNTERNUM < 10000)	motor.loopNum++;
		else if(COUNTERNUM > 10000)	motor.loopNum--;
		__HAL_TIM_SetCounter(&htim1, 10000);             //重新设定初始值			
	}
}
void Clockwise_rotation(void)
{
	IN1(1);
	IN2(0);
	__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,2000);
}
void Counterclockwise_rotation(void)
{
	IN1(0);
	IN2(1);
	__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,2000);
}
void stop()
{
	IN1(0);
	IN2(0);
}

关于这两行代码的理解

		int16_t pluse = COUNTERNUM - RELOADVALUE/2;											
		motor.totalAngle = pluse + motor.loopNum * RELOADVALUE/2;  

在这里插入图片描述

至此,你肯定对电机驱动和编码器,以及简单的操控电机有所了解。后续博客会更新经典控制算法PID的原理和代码。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-17 15:33:32  更:2021-08-17 15:33:58 
 
开发: 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年11日历 -2024/11/25 21:42:51-

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