平衡小车制作系列之二——模块原理解析

文章目录

  • 一、 模块概述
  • 二、 直流电机
    • 2.1 直流电机介绍
    • 2.2 直流电机外围设备介绍
      • 2.2.1 减速器
      • 2.2.2 控制PWM的单片机
      • 2.2.3 编码器
  • 三、 编码器
    • 3.1 编码器介绍
      • 3.1.1 编码器作用
      • 3.1.2 具体原理
    • 3.2 STM32的编码器接口模式
      • 3.2.1 概述
      • 3.2.2 编码器模式配置
    • 3.3 使用方法
      • 3.3.1 核心
      • 3.3.2 代码部分
    • 3.4 编码器实物参数
  • 四、 结尾说明


一、 模块概述

带编码器的直流减速电机,stm32f103系列单片机,蓝牙模块,电源电池,面包板,后续补充…


二、 直流电机

2.1 直流电机介绍

下面是分析直流电机的物理模型图。其中,固定部分有磁铁,这里称作主磁极;固定部分还有电刷。转动部分有环形铁芯和绕在环形铁芯上的绕组。
平衡小车制作系列之二——模块原理解析_第1张图片
把上图中的+和-分别接到电池的正极和负极,电机即可正转;如果是把上图中的+和-分别接到电池的负极和正极那么电机就会反方向转动。电机的转速可以理解为和外接的电压是正相关的。(实际由电枢电流决定!这一点很关键,会在后面的讲解中体现出来。)
总而言之,如果我们可以调节施加在电机上面的直流电压大小,即可实现直流电机调速,改变施加电机上面直流电压的极性,即可实现电机换向。

2.2 直流电机外围设备介绍

2.2.1 减速器

在本次平衡小车项目中,我们使用到的直流电机自带一个减速器,用来降低电机的转速,以提高电机的扭矩。因为直流电机的转速一般都是一分钟几千上万转转速特别的快,减小转速后可以使电机可控性增强,并且转速快电机能产的扭矩就小,通俗的说就是负载一大就很容易转不动(扭矩不够,拉不动)。

2.2.2 控制PWM的单片机

通过改变电机正负极两端的压降就可以改变电机的转速,因此,我们就可以通过改变引脚PWM波的占空比来改变引脚输出的有效电压,但32单片机为3.3V单片机,而要驱动的直流减速电机的电压一般都大于3.3V,并且单片机引脚能输出的电流只有几毫安,而电机的额定电流远远大于这个值,所以单片机是无法直接驱动电机的。因此我们就需要使用电机驱动来帮助单片机来驱动电机转动,例如LM298N。即由电机驱动来提供驱动电机的电压与电流,单片机通过输出PWM波来改变电机驱动输出的电压从而该变电机的转速。
平衡小车制作系列之二——模块原理解析_第2张图片

2.2.3 编码器

后续详细介绍

三、 编码器

3.1 编码器介绍

编码器是将信号或数据进行编制、转换为可用以通信、传输和存储的信号形式的设备。在直流减速电机中,编码器就是将电机的转动信息(比如转速、转动角度等)转换为脉冲信号。按照原理可将其分为:光电编码器(光学式)和霍尔编码器(磁式)。

3.1.1 编码器作用

由上述可知,编码器能够将电机的机械几何位移转化为脉冲信号或数字量。也就是说,通过检测编码器输出的脉冲信号,就能获取电机的转速、转动角度等相关信息。这样,我们不仅能够定量地测量电机转向、转速,还能实现对电机的定性控制。

3.1.2 具体原理

平衡小车制作系列之二——模块原理解析_第3张图片
简单来说,就是电机带动码盘转动,码盘的结构使得当电机在转动时会产生A、B两相的脉冲信号,且这两路脉冲信号的相位差为90°(即正交)。并且由上图可以间接知道,无论电机的转速如何,每一转的脉冲数目都是一致的!
由于A、B信号正交,因此可以根据两个信号谁先到,谁后到来判断方向,根据每个信号脉冲数量的多少以及每一圈电机产生的脉冲数,就可以算出当前行走的距离,如果再加上定时器的话,还可以算出速度。

  • 通过定时器的输入捕获或者GPIO引脚的外部中断来检测边沿变化,以此来检测脉冲数。这方法好像没毛病,当电机正常运转时行得通。

但是如果电机输出的脉冲信号出现了毛刺呢? 会存在误差!

  • 通过软件编写算法来滤去毛刺似乎有点困难,于是我们想到通过硬件来处理这个毛刺。(而STM32正好有硬件编码器,nice!)

3.2 STM32的编码器接口模式

3.2.1 概述

此模式就是特殊的输入捕获模式——在该模式下能计算电机输出脉冲信号的个数,且stm32根据其内部机制能够消除毛刺的干扰。

配置过程:由于编码器接口模式是一种特殊的输入捕获,所以要先配置一下输入捕获(毕竟你要通过捕获边沿来检测脉冲)。
 在输入捕获过程中,我们把A6、A7复用为TIM3,作为输入捕获的引脚,对电机的A、B相脉冲进行输入捕获。
 输入捕获配置完成之后再配置一下编码器模式就可以开始工作了。

3.2.2 编码器模式配置

配置函数void TIM_EncoderInterfaceConfig(TIMx, TIM_EncoderMode, TIM_IC1Polarity, TIM_IC2Polarity)
平衡小车制作系列之二——模块原理解析_第4张图片

  •  TIMx就是输入捕获时设置的TIM3,
  •  polarity就分别是TI1和TI2的捕获极性(TI1是定时器输入通道1,TI2同理),即A、B两相信号的捕获极性(上升沿捕获或者下降沿捕获)
  •  ♥♥♥编码器的模式TIM_EncoderMode:
    a) 当模式选为TIM_EncoderMode_TI1时,计数器仅在TI1的边沿处计数
    b) 当模式选为TIM_EncoderMode_TI2时,计数器仅在TI2的边沿处计数
    c) 当模式选为TIM_EncoderMode_TI12时,计数器在TI1和TI2边沿处均计数
    平衡小车制作系列之二——模块原理解析_第5张图片
    如图,A、B两相正交信号,如果根据模式1或模式2对脉冲信号进行检测,假设我们上升沿捕获一次,那么图中的信号我们只检测到3个上升沿,也就是三个脉冲。但是如果采用模式3,对TI1和TI2检测上升沿,那么同一段时间我们检测到6个上升沿。如果下降沿也检测,那么一共就是12个边沿跳变。每个实际来的脉冲会被检测4次,同样是12/4=3个脉冲,但是这样的话精度大大提高了。至此,我们通过STM32的TIM3的编码器模式,能够测出任意时刻的脉冲值了。

3.3 使用方法

3.3.1 核心

KEY:利用获取的脉冲数来测量电机转动角度、转速。

a) 首先,根据带编码器的直流减速电机的原理,显然无论电机的转速如何,每转产生的脉冲数是固定的。这里假设电机每转产生260个脉冲(具体数据各位自行查看自己的电机参数啦),那么只要我们用‘电机已产生的脉冲数’除以‘260个/转’,就可以得到电机转了多少圈,一圈即为360度,由此便可将脉冲数和转动角度联系起来。

WARNING: 如果使用编码器模式3(TIM_EncoderMode_TI12),我们得到的脉冲数是电机实际产生的脉冲数的四倍。则电机实际产生的脉冲数应为‘得到的计数值’除以4。于是,电机转动圈数为脉冲数除以260再除以4。*

b) 其次,我们根据计数方向(递增计数或递减计数)来判断转动角度。
e.g. TIM_EncoderMode_TI1: Counter counts on TI1FP1 edge depending on TI2FP2 level,意思就是当选择模式1时,计数器根据TI2的电平高低来记录TI1的边沿信号。
平衡小车制作系列之二——模块原理解析_第6张图片
平衡小车制作系列之二——模块原理解析_第7张图片
示例:如下图,电机转动时产生A、B两相信号通过TI1、TI2输入到TIM3。
平衡小车制作系列之二——模块原理解析_第8张图片假设我们选择的是模式1,即计数器仅在TI1的边沿处计数。我们观察TI1的上升沿,若此时对应的TI2信号处于低电平(下图红框),于是根据表格我们可以得到计数方向为递增,假设计数器递增时电机正向转动,则可判断此时电机正转。
在这里插入图片描述
平衡小车制作系列之二——模块原理解析_第9张图片
再譬如,假设我们选择模式2,即计数器仅在TI2的边沿处计数。我们观察TI2的下降沿,若此时对应的TI1信号为高电平(下图蓝框),于是根据表格我们可以得到计数方向为递减,假设计数器递减时电机反向转动,则可判断此时电机反转。
在这里插入图片描述

平衡小车制作系列之二——模块原理解析_第10张图片
也就是说,当以TI1为计数信号时,需要根据TI2的电平(也就是第二纵列的“相对信号的电平”)来进行判断是向上计数还是向下计数。TI2也同理。

3.3.2 代码部分

a)定时器初始化(输入捕获模式)
这里的period即为计数器的重装载值,prescaler即为预分频系数。注意在编码器模式时,要把TIM理解为计数器,而不是定时器,这样的话,时钟信号就不是系统内部产生的,而是通过PA6、PA7输入到TIM3的TI1和TI2的。
计数器原理与普通定时器一致——Period就是计数器每一次能检测脉冲的最大值,每来一个脉冲计数值就加一,当计数值超过period就溢出中断;Prescaler就是对电机产生的脉冲信号进行分频的分频系数。比如当分频系数为2时,每当电机产生两个脉冲,stm32才认为接收到一个有效脉冲,计数值才加一。

/**************************************************************************
函数功能:把TIM2初始化为编码器接口模式
入口参数:无
返回  值:无
**************************************************************************/
void Encoder_Init_TIM2(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
  TIM_ICInitTypeDef TIM_ICInitStructure;  
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能定时器2的时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PA端口时钟
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;	//端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);					      //根据设定参数初始化GPIOA
  
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 预分频器 
  TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD; //设定计数器自动重装值
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上计数  
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
  TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3
  TIM_ICStructInit(&TIM_ICInitStructure);
  TIM_ICInitStructure.TIM_ICFilter = 10;
  TIM_ICInit(TIM2, &TIM_ICInitStructure);
  TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM的更新标志位
  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
  //Reset counter
  TIM_SetCounter(TIM2,0);
  TIM_Cmd(TIM2, ENABLE); 
}
/**************************************************************************
函数功能:把TIM4初始化为编码器接口模式
入口参数:无
返回  值:无
**************************************************************************/
void Encoder_Init_TIM4(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
  TIM_ICInitTypeDef TIM_ICInitStructure;  
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//使能定时器4的时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能PB端口时钟
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;	//端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  GPIO_Init(GPIOB, &GPIO_InitStructure);					      //根据设定参数初始化GPIOB
  
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 预分频器 
  TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD; //设定计数器自动重装值
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上计数  
  TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
  TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3
  TIM_ICStructInit(&TIM_ICInitStructure);
  TIM_ICInitStructure.TIM_ICFilter = 10;
  TIM_ICInit(TIM4, &TIM_ICInitStructure);
  TIM_ClearFlag(TIM4, TIM_FLAG_Update);//清除TIM的更新标志位
  TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
  //Reset counter
  TIM_SetCounter(TIM4,0);
  TIM_Cmd(TIM4, ENABLE); 
}

/**************************************************************************
函数功能:单位时间读取编码器计数
入口参数:定时器
返回  值:速度值
**************************************************************************/
int Read_Encoder(u8 TIMX)
{
    int Encoder_TIM;    
		switch(TIMX)
		{
	   case 2:  Encoder_TIM= (short)TIM2 -> CNT;  TIM2 -> CNT=0;break;
		 case 3:  Encoder_TIM= (short)TIM3 -> CNT;  TIM3 -> CNT=0;break;	
		 case 4:  Encoder_TIM= (short)TIM4 -> CNT;  TIM4 -> CNT=0;break;	
		 default: Encoder_TIM=0;
		}
		return Encoder_TIM;
}
/**************************************************************************
函数功能:TIM4中断服务函数
入口参数:无
返回  值:无
**************************************************************************/
void TIM4_IRQHandler(void)
{ 		    		  			    
	if(TIM4->SR&0X0001)//溢出中断
	{    				   				     	    	
	}				   
	TIM4->SR&=~(1<<0);//清除中断标志位 	    
}
/**************************************************************************
函数功能:TIM2中断服务函数
入口参数:无
返回  值:无
**************************************************************************/
void TIM2_IRQHandler(void)
{ 		    		  			    
	if(TIM2->SR&0X0001)//溢出中断
	{    				   				     	    	
	}				   
	TIM2->SR&=~(1<<0);//清除中断标志位 	    
}

3.4 编码器实物参数

以某宝店铺的驰海电机进行参数学习——CHR-GM37-520ABHL碳刷霍尔编码器减速电机。
平衡小车制作系列之二——模块原理解析_第11张图片
平衡小车制作系列之二——模块原理解析_第12张图片


四、 结尾说明

本文重点参考以下几篇博客文章:
 《带编码器的直流减速电机——基于STM32F407》
 《STM32直流减速电机控制篇》

你可能感兴趣的:(平衡小车,单片机,stm32,嵌入式)