STM32 编码器接口测速

单片机学习!


前言

        如何用编码器旋转控制CNT自增自减,本文介绍编码器接口测速的配置步骤。


一、编码器接口测速配置步骤

第一步、RCC开启时钟,开启GPIO和定时器的时钟。

第二步、配置GPIO,这里举例把PA6和PA7配置成输入模式。

第三步、配置时基单元,这里预分频器一般选择不分频;自动重装一般给最大65535;只需要CNT执行计数。

第四步、配置输入捕获单元,这里输入捕获单元只有滤波器和极性这两个参数有用,其他参数没有用到与编码器无关。

第五步、配置编码器接口模式,这个直接调用库函数就可以配置。

第六步、启动定时器,调用TIM_Cmd函数。


        电路初始化完成之后,CNT就会随着编码器旋转而自增自减。

  • 测编码器位置,直接读出CNT的值即可;
  • 测编码器的速度和方向,需要每隔一段固定的闸门时间,取出一次CNT,然后再把CNT清零,这样就是测频法测量速度了。

二、使用库函数

TIM_EncoderInterfaceConfig函数

定时器编码接口配置。

  • 第一个参数选择定时器;
  • 第二个参数选择编码器模式;
  • 第三、四个参数分别选择通道1和通道2的电平极性。

三、代码配置示例

3.1 RCC开启时钟

第一步、RCC开启时钟,将需要的TIM外设和GPIO外设的时钟打开。

代码示例:


RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使用APB1的开启时钟函数,输入捕获定时器为TIM3。TIM3也是APB1的外设
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//这里计划用TIM3的通道1,根据引脚定义表,TIM3_CH1对应PA6引脚,所以开启GPIOA的时钟
  • 使用APB1的开启时钟函数本文代码示例的输入捕获定时器为TIM3。TIM3也是APB1的外设。
  • 本文代码示例计划用TIM3的通道1,根据引脚定义表,TIM3_CH1对应PA6引脚,所以开启GPIOA的时钟。

3.2 配置GPIO

第二步、配置GPIO,把PA6和PA7配置成上拉输入模式,

GPIO模式可以选择上拉、下拉或者浮空。那么上拉、下拉和浮空如何选择?

上拉和下拉:

        可以看接在引脚的外部模块输出的默认电平,

  • 如果外部模块默认输出高电平,就选择上拉输入,默认输入高电平;
  • 如果外部模块默认输出低电平,就选择下拉输入,默认输入低电平。

GPIO模式和外部模块保持默认状态一致,防止默认电平打架。这是上拉和下拉的选择原则。一般默认高电平是一个习惯的状态,所以上拉输入用的比较多。

浮空:

        如果不确定外部模块输出的默认状态,或者外部信号输出功率非常小的时候就尽量选择浮空输入。浮空输入没有上拉电阻和下拉电阻去影响外部信号。但是缺点是当引脚悬空时没有默认的电平了,输入就会受噪声干扰,来回不断地跳变。

        以上就是三种输入模式的选择原则。

代码示例:

    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Mode= GPIO_Mode_IPU;//这里选择上拉输入
    GPIO_InitStruct.GPIO_Pin= GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStruct.GPIO_Speed= GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStruct);

3.3 配置时基单元

第三步:配置时基单元,包括预分频器、自动重装器、计数模式等,这些参数可用结构体配置。

代码示例:

	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision= TIM_CKD_DIV1;//指定时钟分频,用于信号滤波
	TIM_TimeBaseInitStructure.TIM_CounterMode= TIM_CounterMode_Up;//计数器模式
	TIM_TimeBaseInitStructure.TIM_Period= 65536-1;//ARR自动重装器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler= 0;//PSC预分频器	
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter= 0;//重复计数器的值
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//最后初始化TIM3

  • 指定时钟分频:用于信号滤波
  • 计数器模式:目前这个参数是没有作用的,因为计数方向也是被编码器接口托管的。
  • ARR自动重装器的值:这个值最好设置大一些,防止计数溢出。这里给了最大值,也就是16位的计数器可以满量程计数,这样计数的范围是最大的,而且方便换算为负数。
  • PSC预分频器:预分频器给0,就是不分频。编码器的时钟直接驱动计数器。
  • 重复计数器的值:只有高级定时器才有,这里是初始化通用寄存器,所以值给0.

注:PSC和ARR的取值都要在0~65535之间,不能超范围。

3.4 配置输入捕获单元

        由编码器接口测速配置步骤图可以看出,输入捕获单元并没有全部使用到,编码器接口只使用了通道1和通道2的滤波器和极性选择,所以只需要配置这两部分的参数即可。

        在结构体中只配置其中两部分是不完整的,为了防止结构体中出现的不确定值可能会造成的问题,最好在定义结构体变量之后用TIM_ICStructInit函数给结构体初始化,把结构体的地址传入函数赋一个初始值。

TIM_ICStructInit函数默认给的初始值:

void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct)
{
  /* Set the default configuration */
  TIM_ICInitStruct->TIM_Channel = TIM_Channel_1;
  TIM_ICInitStruct->TIM_ICPolarity = TIM_ICPolarity_Rising;
  TIM_ICInitStruct->TIM_ICSelection = TIM_ICSelection_DirectTI;
  TIM_ICInitStruct->TIM_ICPrescaler = TIM_ICPSC_DIV1;
  TIM_ICInitStruct->TIM_ICFilter = 0x00;
}

        结构体初始值赋值好后,再指定通道为1,滤波器为0xF,电平极性为上升沿。

代码示例:

	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICStructInit(&TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;//TIM_Channel选择通道
	TIM_ICInitStructure.TIM_ICFilter=0xF;//TIM_ICFilter用来配置输入捕获的滤波器
	TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//TIM_ICPolarity极性
	TIM_ICInit(TIM3,&TIM_ICInitStructure);


        TIM_Channel选择通道,因为TIM_ICInit函数只有一个,所以要靠结构体的这个参数来指定是配置哪个通道。这里先配置通道1.

        TIM_ICFilter用来配置输入捕获的滤波器,如果信号有毛刺和噪声,就可以增大滤波器参数,可以有效避免干扰。参数的取值范围0x0到0xF之间,数越大滤波效果越好,每个数值对应的采样频率和采样次数,可查看参考手册。

        注意滤波器和分频器的区别,虽然两者都可以计次,但是滤波器计次并不会改变信号的原有频率,一般滤波器的采样频率会远高于信号频率,所以它只会滤除高频噪声,使信号更平滑,1KHz滤波之后仍然是1KHz,信号频率不会变化。而分频器就是对信号本身进行计次了,会改变频率。1KHz,2分频之后就是500Hz,4分频之后就是250Hz。

        TIM_ICPolarity极性

  • TIM_ICPolarity_Rising上升沿触发
  • TIM_ICPolarity_Falling下降沿触发
  • TIM_ICPolarity_BothEdge上升沿下降沿都触发

        电平极性为上升沿并不代表上升沿有效,因为编码器接口始终都是上升沿、下降沿都有效的。这里的上升沿参数代表的是高低电平极性不反转。也就是之前博文说的TI1、TI2是否反相(STM32 TIM编码器接口-CSDN博客 )对应通道给上升沿就是不反相,给下降沿就是反相。这里的极性参数在配置编码器接口的时候也有,这里的配置也可以删掉。

        参数配置好后,最后传给函数TIM_ICInit,把这些参数写入到通道1。还有通道2的配置,

加上通道2配置后的代码示例:

	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICStructInit(&TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;//TIM_Channel选择通道1
	TIM_ICInitStructure.TIM_ICFilter=0xF;//TIM_ICFilter用来配置输入捕获的滤波器
	TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//TIM_ICPolarity极性
	TIM_ICInit(TIM3,&TIM_ICInitStructure);
	
	TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;//TIM_Channel选择通道2
	TIM_ICInitStructure.TIM_ICFilter=0xF;//TIM_ICFilter用来配置输入捕获的滤波器
	TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//TIM_ICPolarity极性
	TIM_ICInit(TIM3,&TIM_ICInitStructure);

        选择通道2,滤波器为0xF,电平极性为上升沿。配置好之后再调用TIM_ICInit函数,把配置的参数写入到通道2.

代码逻辑总结:

        首先定义结构体变量,然后TIM_ICStructInit函数给结构体赋一个初始值,再部分修改需要配置的参数,调用TIM_ICInit函数配置一遍电路,这个结构体变量的配置调用TIM_ICInit函数之后,就写入到硬件寄存器了,所以调用TIM_ICInit函数之后这个结构体可以换个值继续使用,不需要重新定义新的结构体了。

3.5 配置编码器接口模式

        配置编码器接口只需要调用一个函数就可以了。

代码示例:

	TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);

    TIM_EncoderInterfaceConfig函数用于定时器编码接口配置。

第一个参数:选择定时器TIM3。

第二个参数:编码器模式,一般选择TI1和TI2都计数。

  • TIM_EncoderMode_TI1:仅在TI1计数。
  • TIM_EncoderMode_TI2:仅在TI2计数。
  • TIM_EncoderMode_TI12:TI1和TI2都计数。

后两个参数是IC1和IC2的极性,可更具实际情况来配置,这里选择TIM_ICPolarity_Rising。

  • TIM_ICPolarity_Falling,选择这个参数就是通道反相。
  • TIM_ICPolarity_Rising,选择这个参数就是通道不反相

        这里TIM_EncoderInterfaceConfig函数的后两个参数和配置输入捕获单元的极性参数是一样的,实际的效果确实就是一样的,这两个地方的参数其实都是配置的同一个寄存器。这里属于重复配置,后面配置的参数会覆盖前面的参数,可以将输入捕获单元配置的极性参数删掉,只使用后面函数来配置极性。这里需要注意TIM_EncoderInterfaceConfig函数和配置输入捕获单元结构体的代码先后位置,后面的配置会覆盖前面的配置。

3.6 启动定时器

        启动定时器,调用TIM_Cmd函数。

代码示例:

	TIM_Cmd(TIM3,ENABLE);

        以上初始化配置就结束了,调用后编码器旋转就能控制CNT自增自减。


总结

        以上就是今天要讲的内容,本文仅仅简单介绍了编码器接口测速配置步骤、需要用到的库函数以及具体参数配置。

  • 41
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值