第7章 直流有刷电机编码器测速
本章我们主要来学习编码器测速的原理,并实现直流有刷电机的速度检测。在实际的电机控制中,我们时常需要关注电机的转速,并以此来了解电机的运行状态,因此,如何获得一个准确的电机速度至关重要。
本章分为如下几个小节:
7.1 编码器简介
7.2 编码器测速原理
7.3 编码器测速实现
7.1 编码器简介
1)概念:编码器是一种能将直线位移、角位移数据转换为脉冲信号、二进制编码的设备。它本质上就是一个传感器,可以把角位移或直线位移转换成电信号,并反馈给控制器,使控制器知道当前机械运动的位置、角度等信息。编码器的实物图如图7.1.1所示:
图7.1.1 编码器实物
2)特点:精度高、结构简单、体积小、使用可靠、性价比高,等等。
3)应用场景:数控机床、机器人、雷达、光电经纬仪、地面指挥仪、高精度闭环调速系统、伺服系统等诸多领域。
4)编码器的分类:编码器的分类方式有很多,我们这里列举两种分类方式:按检测原理和编码类型,详见下图:
图7.1.2 编码器分类
从图7.1.2中可以看到,编码器按照检测原理可以分为光电式和磁电式;按照编码类型可分为增量式和绝对式。在实际的应用中,这四类编码器并不是相对独立的,它们经过组合后,就变成了光电绝对式、光电增量式、磁电绝对式和磁电增量式这四种编码器。
5)编码器原理:我们这里主要介绍磁电增量式、光电增量式以及光电绝对式这3种常用编码器的工作原理。
① 磁电增量式
原理:利用霍尔效应,将位移转换成计数脉冲,用脉冲个数计算位移和速度。
磁电增量式编码器的具体工作原理如图7.1.3所示:
图7.1.3 磁电增量式编码器工作原理
图7.1.3中,磁电增量式编码器的结构包含:磁盘、霍尔传感器以及信号转换电路3个部分,其中,磁盘是由一个个交替排布的S极和N极磁极组成;霍尔传感器可以把磁场的变化转换成电信号的变化,它通常有A、B两相(有的还有Z相),这两相的安装位置形成一定的夹角,这使得输出的A、B两相信号有90°的相位差;信号转换电路可以把电信号转换成脉冲信号。
在实际应用中,磁盘会装在电机的转轴上,它会随着电机的转轴旋转,而磁盘上面的S极和N极就会交替地经过霍尔传感器的A、B两相,霍尔传感器就可以把磁盘上的磁场变化转换为电信号的变化,输入到信号转换电路中,经过信号的转换之后,我们就可以得到A、B两相脉冲信号了。从上图中可以看到,A、B两相脉冲信号存在90°的相位差,而磁盘的正反转方向就决定了是A相信号在前还是B相在前。
② 光电增量式
原理:利用光电系统,将位移转换成计数脉冲,用脉冲个数计算位移和速度。
光电增量式编码器的具体工作原理如图7.1.4所示:
图7.1.4 光电增量式编码器工作原理
图7.1.4中,光电增量式编码器的结构包含:光电码盘、光源、透镜、受光元件以及信号转换电路5个部分,其中,光电码盘上有一个个均匀排布的透光孔;光源和透镜形成一个聚光系统;受光元件可以把光线的变化转换成电信号的变化,它通常有A、B两相(有的还有Z相),这两相的安装位置形成一定的夹角,这使得输出的A、B两相信号有90°的相位差;信号转换电路可以把电信号转换成脉冲信号。
在实际应用中,光电码盘会装在电机的转轴上,它会随着电机的转轴旋转,而码盘上面的透光孔会间歇性地经过A、B两相,受光元件就可以把光线变化转换为电信号的变化,输入到信号转换电路中,经过信号的转换之后,我们就可以得到A、B两相脉冲信号了。从上图中可以看到,A、B两相脉冲信号存在90°的相位差,而码盘的正反转方向就决定了是A相信号在前还是B相在前。
③ 光电绝对式
原理:当码盘处于不同位置(角度)时,光敏元件根据受光与否转换出相应的电平信号,最后转换成二进制数输出。
光电绝对式编码器的结构总体来说和光电增量式很类似,都是由光电码盘、光源、透镜、受光元件以及信号转换电路5个部分,但是它们码盘结构和输出信号含义不同。光电绝对式编码器的自然二进制码盘如图7.1.5所示:
图7.1.5 自然二进制码盘
图7.1.5中,光电绝对式编码器的二进制码盘上有很多圈线槽,我们称为码道。上图中的二进制码盘有4个码道,按照自然二进制的方式排列,这个码盘一共被分为2^4 = 16个区域,这些区域中,黑块不透光,代表1;白块透光,代表0。当码盘随着电机转轴旋转,光线会照射到不同的区域,受光元件就能感受到不同的光线情况,最后经过信号的处理,就可以直接输出该区域对应的二进制码了,而我们通过这个二进制码即可得出码盘(电机转轴)的当前位置(角度)。大家需要注意:二进制码盘的每一个位置对应一个确定的二进制码,因此这一类编码器常被应用于位置以及角度测量。
上述的自然二进制码盘读数很方便直观,但是它在实际应用中容易造成读数偏差很大,例如:当码盘停止旋转时,光线照射在0000和1111这两个相邻的区域之间,此时输出的二进制数可能是0000~1111中的任何一个,此时的读数和码盘的实际位置可能就相差很远了。为了避免读数和实际位置出现巨大偏差,我们可以改进一下二进制码的排列方式,使用格雷码形式,如图7.1.6所示:
图7.1.6 格雷码码盘
图7.1.6中,格雷码盘有4个码道,同样的也能表示16个二进制数,但是任意相邻的两个区域之间的二进制码只有一位不同。当我们采用格雷码盘时,如果码盘停止旋转,光线照射到码盘相邻两个区域之间,其最终输出的二进制数最多只会相差一位,此时位置的偏差范围就很小了。
6)编码器基本参数:
① 分辨率:编码器每个计数单位之间产生的距离,它是编码器可以测量到的最小的距离。对于增量式编码器,分辨率表示为编码器的转轴每旋转一圈所输出的脉冲数(PPR),也称为多少线,直流有刷电机教程中所使用的编码器是11线的。
② 精度:编码器分辨率和精度是两个独立的概念,精度是指编码器输出的信号数据与实际位置之间的误差,常用角分′、角秒″表示。
③ 最大响应频率:编码器每秒能输出的最大脉冲数,单位Hz,也称为PPS。
④ 最大转速:指编码器机械系统所能承受的最高转速。
7.2 编码器测速原理
本章节中我们所使用的编码器是磁电增量式编码器,它安装在直流有刷电机的尾部,实物图如图7.2.1所示:
图7.2.1 直流有刷电机编码器实物
图7.2.1中,直流有刷电机的编码器有A、B两相,它们会输出两个相位差为90°的脉冲。当电机正转时,A相脉冲在前;当电机反转时,则是B相脉冲在前。
有了A、B两相脉冲信号之后,我们应该如何去处理这些信号,把它们转换成电机的转速呢?这里就涉及到一个非常重要的功能:定时器编码器接口模式。
STM32定时器的编码器接口模式就相当于带有方向选择的外部时钟,也就是说,在此模式下,外部输入的脉冲信号可以作为计数器的时钟,而计数的方向则是由脉冲相位的先后所决定的。定时器编码器接口模式的原理如图7.2.2所示:
图7.2.2 定时器编码器接口原理
图7.2.2中,当电机(编码器)正转时,输出两相脉冲信号,A相脉冲在前,此时编码器接口把脉冲信号作为计数器的脉冲,计数方式为递增计数;当电机(编码器)反转时,计数方式就变成了递减计数。
上述的内容只是对编码器接口的原理进行简单的介绍,让大家有一个感性的认识,接下来我们深入研究一下编码器接口的原理:
1)编码器接口框图
我们首先看编码器的接口框图部分,了解一下脉冲信号进入编码器接口的途径,这里以通用定时器为例,具体框图如图7.2.3所示:
图7.2.3 通用定时器编码器接口框图
图7.2.3中,A、B两相脉冲信号从TIMx_CH1和TIMx_CH2这两个通道输入,经过滤波器和边沿检测器(可以设置滤波和反相)的处理,进入到编码器接口控制器中。大家需要注意,TIMx_CH3和TIMx_CH4是不支持编码器接口模式的。
2)编码器接口计数原理
编码器接口可以利用输入脉冲的边沿进行计数,我们通过计数值的变化量,就可以算出输入脉冲信号的变化量,也就可以进一步计算出电机的转速了。接下来我们看一下编码器接口是如何根据脉冲边沿计数的,它的计数方向与输入脉冲信号的关系如表7.2.1所示:
有效边沿 | 相反信号的电平 (TI1FP1对应TI2, TI2FP2对应TI1) | TI1FP1信号 | TI2FP2信号 | ||
上升 | 下降 | 上升 | 下降 | ||
仅在TI1处计数 | 高 | 递减 | 递增 | 不计数 | 不计数 |
低 | 递增 | 递减 | 不计数 | 不计数 | |
仅在TI2处计数 | 高 | 不计数 | 不计数 | 递增 | 递减 |
低 | 不计数 | 不计数 | 递减 | 递增 | |
在TI1和TI2处均计数 | 高 | 递减 | 递增 | 递增 | 递减 |
低 | 递增 | 递减 | 递减 | 递增 |
表7.2.1 计数方向与输入脉冲信号的关系
表7.2.1来自于《STM32F4xx参考手册_V4(中文版).pdf》中的表75(第415页),上表中的有效边沿我们可以通过代码去配置,一共有3种边沿检测方式,其中仅在TI1处计数表示只检测TI1上的脉冲边沿变化,这时候的计数方向需要结合TI2FP2上的电平情况来确定,其他的两种边沿检测方式原理也是一样的,下面我们以一个实例来理解这个表格的内容:
假设我们把A相接在CH1(TI1),B相接在CH2(TI2),选择仅在TI1处计数(仅检测A相边沿)。此时编码器接口计数方向和输入脉冲信号的关系如下表:
有效边沿 | B相信号 | A相信号 | |
上升 | 下降 | ||
仅在A相边沿计数 | 高 | 递减 | 递增 |
低 | 递增 | 递减 |
表7.2.2 仅在A相边沿计数
编码器输出的A、B两相脉冲信号如图7.2.4所示:
图7.2.4 A、B相脉冲信号
图7.2.4中,A、B两相输出的脉冲信号有两种情况:当编码器正转,A相在前;当编码器反转,B相在前,我们选择仅在TI1处计数,也就是只检测A相的边沿。接下来我们分别介绍这两种情况下的计数方向:
正转:当A相上升沿到来时(图中①处),我们需要关注B相的电平高低,从图7.2.4中可看到B相此时是低电平,结合表7.2.2,可以得知此时计数方向为递增计数;当A相下降沿到来时(图中②处),从图中可以看到B相此时是高电平,结合表7.2.2,可以得知此时计数方向为递增计数;当A相上升沿再次到来时(图中③处),同理可得此时计数方向为递增计数。综上所得,我们可以知道此时编码器正转对应的计数方向就是递增计数。
反转:当A相上升沿到来时(图中④处),我们需要关注B相的电平高低,从图7.2.4中可看到B相此时是高电平,结合表7.2.2,可以得知此时计数方向为递减计数;当A相下降沿到来时(图中⑤处),从图中可以看到B相此时是低电平,结合表7.2.2,可以得知此时计数方向为递减计数;当A相上升沿再次到来时(图中⑥处),同理可得此时计数方向为递减计数。综上所得,我们可以知道此时编码器反转对应的计数方向就是递减计数。
上述的就是仅在TI1处计数的实例分析,其他两种边沿计数方式的原理是一样的,大家可以举一反三,我们这里就不再展开分析。
注意:1、选择仅在TI1或者TI2处计数,就相当于对脉冲信号进行了2倍频(两个边沿),此时如果编码器输出10个脉冲信号,那么就会计数20次。2、选择的是在TI1和TI2处均计数,就相当于对脉冲信号进行了4倍频,此时如果编码器输出10个脉冲信号,那么就会计数40次。因此,我们通过计数次数来计算电机速度的时候,需要除以相应的倍频系数。
至此,A、B两相脉冲信号的变化就转换成了定时器的计数变化。接下来我们就可以通过一分钟内计数的变化量来计算电机的速度,具体公式如下:
电机转速 = 一分钟内计数变化量 / 倍频系数 / 编码器线数 / 减速比
到这里,编码器的测速原理就介绍完了,接下来我们开始实现直流有刷电机的测速实验。
7.3 编码器测速实现
本小节我们来学习使用直流有刷电机的编码器测速功能,关于编码器测速的原理大家可以回顾上一小节的内容。我们这里选择通用定时器的编码器接口来实现测速功能,而高级定时器则用于电机的基础驱动。
7.3.1 TIM2/TIM3/TIM4/TIM5寄存器
下面介绍TIM2/TIM3/TIM4/TIM5的几个与编码器测速相关且重要的寄存器,相关内容可以参考《STM32F4xx参考手册_V4(中文版).pdf》定时器相关章节。
- 控制寄存器 1(TIMx_CR1)
TIM2/TIM3/TIM4/TIM5的控制寄存器1描述如图7.3.1.1所示:
图7.3.1.1 TIMx_CR1寄存器
上图中我们只列出了本实验需要用的位:CEN位,此位用于使能计数器的工作,必须要设置该位为1,才可以开始计数;DIR位,在编码器模式下可通过读取该位来判断计数方向。
- 捕获/比较模式寄存器1(TIMx_CCMR1)该寄存器在编码器接口模式中作为输入功能,其描述如图7.3.1.2所示:
-
图7.3.1.2 TIMx_CCMR1寄存器
大家需要注意:TIMx_CCMR1寄存器对应于通道1和通道2的设置,CCMR2寄存器对应通道3和通道4,而通道3和通道4是不支持编码器接口模式的,所以这里只用到TIMx_CCMR1。
上图中的CC1S[1:0]这两个位用于CCR1的通道配置,这里我们设置IC1S[1:0]=01,也就是配置IC1映射在TI1上。
输入捕获1预分频器IC1PSC[1:0],这个比较好理解。我们是1次边沿就触发1次计数,所以选择00就是了。
输入捕获1滤波器IC1F[3:0],这个用来设置输入采样频率和数字滤波器长度。其中,fCK_INT是定时器时钟源频率,按照例程的配置为84Mhz,而fDTS则是根据TIMx_CR1的CKD[1:0]的设置来确定的,如果CKD[1:0]设置为00,那么fDTS=fCK_INT。N值采样次数,举个简单的例子:假设IC1F[3:0]=0011,并设置IC1映射到TI1上。表示以fCK_INT为采样频率,当连续8次都是采样到TI1为高电平或者低电平,滤波器才输出一个有效输出边沿。当8次采样中有高有低,那就保持原来的输出,这样可以滤除高频干扰信号,从而达到滤波的效果。 - 捕获/比较使能寄存器(TIMx_CCER)TIM2/TIM3/TIM4/TIM5的捕获/比较使能寄存器,该寄存器控制着各个输入输出通道的开关和极性。TIMx_CCER寄存器描述如图7.3.1.3所示:
- 图7.3.1.3 TIMx_CCER寄存器
我们要用到这个寄存器的4个位,分别是CC1E、CC1P、CC2E和CC2P位,上图中只列出了CCIE和CCIP位,其他两个位同理。要使能编码器接口模式,必须设置CC1E和CC2E为1,而CC1P和CC2P设置的是边沿触发的方向。
- 从模式控制寄存器(TIMx_SMCR)
TIM2/TIM3/TIM4/TIM5的从模式控制寄存器描述如图7.3.1.4所示:
图7.3.1.4 TIMx_SMCR寄存器
该寄存器的SMS[2:0]位,用于从模式选择,其实就是选择计数器输入时钟的来源。在编码器模式中,如果需要仅在 TI1边沿处计数,则设置SMS[2:0]=010;如果需要仅在 TI2边沿处计数,则设置SMS[2:0]=001;如果需要在 TI1、TI2边沿处都计数,则设置SMS[2:0]=011。本实验我们在TI1和TI2边沿处均计数,也就是对脉冲信号进行4倍频。
7.3.2 硬件设计
1. 例程功能
1、本实验以电机开发板的直流有刷电机驱动接口1为例,基于电压温度电流采集实验,加入编码器测速功能,利用TIM3_CH1(由PC6复用)和TIM3_CH2(由PC7复用)作为编码器脉冲信号输入接口。
2、当按键0按下,就增大PWM的比较值变量,电机将加速,当按键1按下,就减小PWM的比较值变量,电机将减速,当比较值变量为正数时电机正转,反之电机反转,按下按键2则马上停止电机。
3、定时器6中断里面计算电机速度。
4、屏幕显示按键功能信息以及电机转速。
5、串口打印驱动板电压、电流、温度和转速信息。
6、LED0闪烁指示程序运行。
2. 硬件资源
1)LED灯
LED0 – PE0
2)独立按键
KEY0 – PE2
KEY1 – PE3
KEY2 – PE4
3)定时器1、3、6
TIM1正常输出通道 PA8
TIM1互补输出通道 PB13
TIM3 编码器A相输入通道 PC6
TIM3 编码器B相输入通道 PC7
4)SD(刹车)信号输出 PF10
5)ADC
ADC1通道9 PB1(电压)
ADC1通道0 PA0(温度)
ADC1通道8 PB0(电流)
6)串口1
USART1_TX PB6(发送)
USART1_RX PB7(接收)
3. 原理图
图7.3.2.1 直流有刷电机接口原理图
图7.3.2.1就是我们DMF407电机开发板的直流有刷电机接口1原理图,本实验我们除了用到基础驱动以及电压温度电流采集所需的引脚,还需要用到PM1_ENCA(PC6)、PM1_ENCB(PC7)这两个引脚,它们分别用于连接编码器的A、B两相。
本实验的硬件接线部分和上一章节一模一样,这里不再赘述,大家可以回顾上一章节的实验内容。
7.3.3 程序设计
7.3.3.1. 定时器的HAL库驱动
定时器在HAL库中的驱动代码在前面已经介绍了部分,这里我们再介绍几个本实验用到的函数。
1. HAL_TIM_Encoder_Init函数
定时器的编码器接口初始化函数。其声明如下:
HAL_StatusTypeDef HAL_TIM_Encoder_Init(TIM_HandleTypeDef *htim, TIM_Encoder_InitTypeDef *sConfig);
- 函数描述:用于初始化编码器接口模式。
- 函数形参:形参1是TIM_HandleTypeDef结构体类型指针变量,用于配置定时器基本参数。形参2是TIM_Encoder_InitTypeDef结构体类型指针变量,用于配置编码器模式参数。重点了解一下TIM_Encoder_InitTypeDef结构体指针类型,其定义如下:
该结构体成员用于配置编码器接口的参数。成员变量EncoderMode用来设置编码器模式,我们可以选择仅在TI1 / TI2处计数或者在TI1、TI2处均计数。本实验中我们选择在TI1、TI2处均计数,也就是4倍频。
成员变量IC1Polarity在编码器模式下用于设置输入信号是否反相,它设定的是 TIMx_CCER 寄存器的 CCxNP 位和 CCxP 位。本实验我们不需要输入信号反相。
成员变量ICSelection用来设置通道映射关系,它设定 TIMx_CCMRx 寄存器的 CCxS[1:0] 位的值。在编码器接口模式下,此成员设置为输入模式即可(其他型号芯片不一定),本实验我们选择TIM_ICSELECTION_DIRECTTI。
成员变量ICPrescaler用来设置输入捕获的时钟分频系数,本实验不需要分频,所以选择TIM_ICPSC_DIV1。
成员变量ICFilter用来设置滤波器长度,可选设置 0x0 至 0x0F。它设定 TIMx_CCMRx 寄存器ICxF[3:0] 位的值。- 函数返回值:HAL_StatusTypeDef枚举类型的值。2. HAL_TIM_Encoder_Start函数定时器的编码器接口模式启动函数,其声明如下:
- 函数描述:用于启动定时器的编码器接口模式。
- 函数形参:形参1是TIM_HandleTypeDef结构体类型指针变量。
形参2是定时器通道,范围:TIM_CHANNEL_1到TIM_CHANNEL_4。 - 函数返回值:
HAL_StatusTypeDef枚举类型的值。
定时器的编码器模式配置步骤
1)开启TIMx和输入通道的GPIO时钟,配置该IO口的复用功能输入
首先开启TIMx的时钟,然后配置GPIO为复用功能。本实验我们默认用到定时器3通道1和通道2,对应IO是PC6,PC7,它们的时钟开启方法如下:
IO口复用功能是通过函数HAL_GPIO_Init来配置的。
2)初始化TIMx,设置TIMx的ARR和PSC等参数
使用定时器的输入捕获功能时,通过HAL_TIM_Encoder_Init函数来初始化定时器ARR和PSC等参数。
注意:该函数会调用:HAL_TIM_Encoder_MspInit函数,我们可以通过后者存放定时器和GPIO时钟使能、GPIO初始化、中断使能以及优先级设置等代码。
3)设置TIMx_CHy的编码器模式,开启编码器通道
在HAL库中,定时器的编码器接口模式是通过HAL_TIM_Encoder_Init函数来设置定时器的编码器通道,包括映射关系,输入滤波和输入分频等。
4)使能定时器更新中断,配置定时器中断优先级
通过__HAL_TIM_ENABLE_IT函数使能定时器更新中断。
通过HAL_NVIC_EnableIRQ函数使能定时器中断。
通过HAL_NVIC_SetPriority函数设置中断优先级。
编码器在电机运行时会一直旋转并输出脉冲信号,如果时间较长,那么定时器计数就会溢出,我们必须对溢出必须做处理,否则电机速度的计算结果就不准了。
5)编写中断服务函数
定时器3中断服务函数为:TIM3_IRQHandler,当发生中断的时候,程序就会执行中断服务函数。HAL库为了使用方便,提供了一个定时器中断通用处理函数HAL_TIM_IRQHandler,该函数会调用一些定时器相关的回调函数,用于给用户处理定时器中断到了之后,需要处理的程序。本实验我们用到更新(溢出)中断回调函数HAL_TIM_PeriodElapsedCallback。详见本例程源码。
7.3.3.2 程序流程图
图7.3.3.2.1 编码器测速程序流程图
7.3.3.3 程序解析
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。关于基础驱动和电压温度电流采集的代码我们不再赘述,大家可以回顾相应的章节。
注意:本实验需要用到TIM3的编码器模式和TIM6的更新中断,相关的定时器驱动源码包括两个文件:dcmotor_tim.c和dcmotor_tim.h。
首先看dcmotor_tim.h头文件的几个宏定义:
可以把上面的宏定义分成四部分:
第一部分是通用定时器3编码器模式输入通道对应的IO口宏定义;
第二部分是通用定时器3编码器模式输入通道的相应宏定义;
第三部分是定时器6更新中断的相应宏定义;
第四部分是编码器参数的结构体,这个结构体用于管理编码器的计数值和速度。
下面看dcmotor_tim.c的程序,首先是通用定时器的编码器接口模式初始化函数。
HAL_TIM_Encoder_Init初始化定时器3的基础工作参数和编码器接口,如:ARR、PSC、编码器模式、滤波器等,第二部分则是调用HAL_TIM_Encoder_Start函数开启编码器通道。最后是使能更新中断和清除中断标志位。通道对应的IO、时钟开启和NVIC的初始化都在HAL_TIM_Encoder_MspInit函数里编写,其定义如下:
该函数调用HAL_GPIO_Init函数初始化定时器输入通道对应的IO,并且开启GPIO时钟,使能定时器。其中要注意IO口复用功能的选择一定要选对了。最后配置中断抢占优先级和响应优先级,以及打开定时器中断。
接着我们看基本定时器6的中断初始化函数及其底层初始化函数。
这一部分函数和基本定时器中断实验是一样的,这里不再赘述,我们使用定时器6来定时计算电机速度,本实验中配置溢出时间为1ms,也就是1ms进入一次定时器6的更新中断。
下面开始看中断服务函数的逻辑程序,HAL_TIM_IRQHandler函数会调用下面的回调函数,我们的逻辑代码就是放在回调函数里,函数定义如下:
进入更新中断回调函数后,先判断是不是定时器3的寄存器基地址,如果是则读取CR1寄存器的DIR位,判断计数溢出的方向,如果DIR位为1,就是递减计数,说明是向下溢出,我们让变量g_timx_encode_count自减1;如果DIR位为0,就是递增计数,说明是向上溢出,我们让变量g_timx_encode_count自增1,变量g_timx_encode_count将用于计算总的计数值。
如果是定时器6的寄存器基地址,就先获取编码器的计数总值,然后每隔50ms计算一次电机速度,其中所涉及到的两个函数我们后续再介绍。
接下来看编码器计数总值的计算函数。
代码中通过调用__HAL_TIM_GET_COUNTER函数来获取当前的计数值,然后进行编码器计数总值的计算,这里需要用到变量g_timx_encode_count,具体的计算公式如下:
计数总值 = 当前计数值 + g_timx_encode_count * 65536
获取到计数总值之后,我们就可以计算电机的速度了,本实验中电机速度计算相关源码包括两个文件:dc_motor.c和dc_motor.h。
首先看dc_motor.h头文件的几个宏定义:
ROTO_RATIO和REDUCTION_RATIO是用于速度计算的系数,ROTO_RATIO等于编码器的线数*倍频系数,教程中采用的直流有刷电机编码器线数为11,也就是说编码器每旋转一圈就输出11个脉冲信号;REDUCTION_RATIO代表电机的减速比,我们算出编码器的速度之后,就可以根据减速比计算电机的速度了。Motor_TypeDef这个结构体是用于管理电机的参数的,我们本实验中只需要用到speed(实际速度)这个成员。
下面看dcmotor_tim.c的程序,我们只看电机速度计算函数。
电机的速度计算步骤如下:
第一步,计算50毫秒内计数变化量;
第二步,计算1min内计数变化量:g_encode.speed * ((1000 / ms) * 60;
第三步,除以编码器旋转一圈的计数次数(REDUCTION_RATIO);
第四步,除以减速比(ROTO_RATIO)即可得出电机转速;
我们累计计算10次电机速度,然后进行冒泡排序,把10次电机速度值从小到大排序,接着将中间的6次速度值累加求平均值,最后再进行一阶低通滤波。由于冒泡排序和一阶低通滤波的详细介绍篇幅过长,我们这里不做展开,大家感兴趣的话可以去网上搜索相关的内容。
在main.c里面编写如下代码:
我们只看本实验新增的内容,先看gtim_timx_encoder_chy_init(0XFFFF, 0)这个语句,这两个形参分别设置自动重载寄存器的值为65535,以及预分频器寄存器的值为0。定时器3是16位的计数器,这里设置为最大值65535。预分频系数,我们设置为不分频,定时器3的计数频率是84MHz。接着看btim_timx_int_init(1000 - 1 , 84 - 1)这个语句,这里设置了定时器6的计数频率为84M/84=1M Hz,计数周期为1ms,也就是1ms进入一次更新中断。最后就是在串口以及屏幕上输出电机速度值了。
7.3.4 下载验证
下载代码后,可以看到LED0在闪烁,说明程序已经正常在跑了,LCD上显示按键功能以及电机速度信息,当我们按下KEY0,比较值变量motor_pwm将增大;按下KEY1,比较值变量motor_pwm将减小;按下KEY2,电机将停止。比较值变量motor_pwm为正数时,电机正转,反之电机反转,其绝对值越大,电机的速度越快。我们再打开串口调试助手,选择对应的串口端口,我这边是COM3,可以看到串口打印的按键信息、电压、温度、电流以及电机速度值,如图7.3.4.1所示:
图7.3.4.1打印按键信息、电压、温度、电流以及速度值