电机驱动及编码器测速(基于STM32F103C8T6HAL库)

硬件:STM32F103C8T6、电机驱动模块tb6612、25GA370带编码器测速盘直流减速电机。

1.电机驱动

1.1 电机驱动模块tb6612

(1)电机驱动模块tb6612简介

电机驱动需要使用电机驱动模块,电机驱动模块把3.3V的电机信号转换成12V的电机的驱动信号。

上面两个驱动模块主要区别是橙色部分的钽电容,红色驱动模块耐压值16V,除以1.5为工作电压等于10.6V;黑色模块耐压值35V,除以1.5还有23.3V。因此红色模块驱动12V电机可能有一定概率导致钽电容损坏,可以自己更换一个电容,如果不换也可以直接剪掉,这个模块也能使用,只是不能滤波了,效果差一些。

钽电容耐压值_钽电容耐压值代码-CSDN博客

(2)电机驱动模块tb6612使用

stm32学习探究:利用TB6612驱动直流电机-CSDN博客

1.2 硬件电路及引脚配置

(1)硬件电路

(2)HAL库引脚配置

两个电机(平衡小车左右两个电机):PA11和PA8使用定时器生成PWM波 ,使用定时器来生成;PB12~PB15用来控制电机方向

PWM频率:,让f的10kHz,分频PSC=0,ARR=7199。

占空比设置:,全速运行设置Paulse=7200。

1.3 驱动程序编写

(1)创建motor.c和motor.h文件

(2)motor.h

cpp 复制代码
#ifndef _MOTOR_H
#define _MOTOR_H

#include "stm32f1xx_hal.h"
void Load(int moto1,int moto2);    


#endif

(3)motor.c

cpp 复制代码
#include "motor.h"

extern TIM_HandleTypeDef htim1;


/*取绝对值函数*/
int abs(int p)
{
	if(p>0)
		return p;
	else
		return -p;
}

/*电机加载函数*/
void Load(int moto1,int moto2)			//-7200~7200,参数表示左右两个电机转速(占空比),100%为7200
{
	if(moto1<0)
	{
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);       //一高一低电机才能转动
	}
	else
	{
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET);
	}
	__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_4,abs(moto1));         //加载占空比
	if(moto2<0)
	{
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14,GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_RESET);
	}
	else
	{
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14,GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_SET);
	}
	__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,abs(moto2));
}

(3)main.c

①打开 PWM

cpp 复制代码
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_4);

②电机装载速度

cpp 复制代码
Load(-1000,1000);

这款电机满转速330,设置为1000时候转速大概为46转每分钟。

CN1反接(AO1接AM2,AO2接AM1), CN2正接(BO1接BM1,BO2接BM2);因为两个电机左右对称,为了方便程序的编写,其中一个反接时候才能向前。

2.编码器测速

这一节要在上一节的基础上进行。

编码器计数原理与电机测速原理------多图解析 - 知乎 (zhihu.com)

减速比1:30的意思是我们的电机主轴转1圈的话,编码器磁环的轴转30圈。如果电机主轴转1圈的话,输出330个脉冲。

2.1 引脚配置

编码器引脚必须是PA0和PA1、PB6和PB7。

时钟来源是编码器,本事就不是特别快,所以不需要再进行分频。

编码器原理就是统计一段时间内的脉冲信号个数,然后换算到1s下对应脉冲信号个数,就是相应频率。

选择这种模式,A相和B相只要有上升沿都会触发 计数器里面+1,所以比只选择T1或者T2,计数值是快1倍的,这样才小转速情况下也可以读到较大值。

2.2 驱动编写

(1)添加encoder.c和encoder.h

(2)Encoder.h

cpp 复制代码
#ifndef __ENCODER_H__
#define __ENCODER_H__

#include "stm32f1xx_hal.h"
int Read_Speed(TIM_HandleTypeDef *htim);


#endif

(3)Encoder.c

stm32中编码器模式读出"负数"的问题_为什么stm32读取编码电机数值为负值-CSDN博客

cpp 复制代码
#include "encoder.h"


int Read_Speed(TIM_HandleTypeDef *htim)
{
	int temp;
	temp=(short)__HAL_TIM_GetCounter(htim);   //读取编码器的值,这里一定要用short进行转换,因为我们的计数器是16位的,向下计数,-1对应65535,不进行转换会出错
	__HAL_TIM_SetCounter(htim,0);             //定时器寄存器清零
	return temp;
}

(4)main.c

cpp 复制代码
HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_ALL);        //初始化定时器编码器功能
HAL_TIM_Encoder_Start(&htim4,TIM_CHANNEL_ALL);

我们10ms获得一次编码器值,为了获得准确得时间,使用系统滴答定时器获得编码器值:

cpp 复制代码
uint32_t sys_tick;    
int Encoder_Left,Encoder_Right;

添加编码器获取函数:

cpp 复制代码
/*每个10ms读取一次编码器值*/
void Read(void)
{
	if(uwTick-sys_tick<10)           //uwTick是一个全局变量,默认情况下每个1ms递增一次
		return;
	sys_tick=uwTick;                 //sys_tick和uwTick之间值刚好相差10时更新sys_tick的值,然后读取编码器值
	Encoder_Left=Read_Speed(&htim2);
	Encoder_Right=-Read_Speed(&htim4);    //和电机原因一样
}

关于 uwTick:

uwTick从0加到满能够使用40多天才会溢出。

相关推荐
lantiandianzi16 分钟前
基于单片机的燃气报警阀门系统
单片机·嵌入式硬件
单片机成品汇1 小时前
STM32单片机WIFI语音识别智能衣柜除湿消毒照明
stm32·单片机·语音识别
qyx38681 小时前
MR756-ASEMI汽车用整流二极管MR756
单片机·物联网·汽车
ldinvicible1 小时前
stm32mp2 RMII phy调试总结
stm32·macos·r语言
stm 学习ing2 小时前
FPGA 第二讲 初始FPGA
c语言·开发语言·stm32·fpga开发·c#·visual studio·嵌入式实时数据库
stm 学习ing4 小时前
FPGA 第4讲 初识Verilog HDL
c语言·单片机·嵌入式硬件·学习·fpga开发·集成测试·fpga
好想有猫猫5 小时前
【51单片机】LED点阵屏 原理 + 使用
c语言·单片机·嵌入式硬件·51单片机·1024程序员节
嵌入式小章5 小时前
基于STM32的自动化植物浇灌系统教学
stm32·嵌入式硬件·自动化
VirusVIP10 小时前
filezilla向虚拟机Linux传输文件失败且直接在Linux创建文件夹失败
linux·运维·服务器·嵌入式硬件
FPGA小迷弟11 小时前
FPGA在航空航天领域的应用案例解析!!!
stm32·物联网·fpga开发·verilog·fpga