stm32 TIM编码器接口——江协教程踩坑经验分享

江协stm32学习:6-7~6-8 TIM编码器接口

一、编码器接口(Encoder Interface)简介

1、功能概述

编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制 CNT 自增或自减,从而指示编码器的位置、旋转方向和旋转速度

2、相关结构

  • 每个高级定时器和通用定时器都拥有 1 个编码器接口

  • 两个输入引脚借用了输入捕获的通道 1 和通道 2

3、设计理念

对于需要频繁执行,操作又比较简单的任务,一般会设计一个硬件模块使得其自动完成,以免占据软件资源。编码器测速一般应用在电机控制的项目上,使用PWM驱动电机,再使用编码器测量电机的速度,然后再使用PID算法进行闭环控制

4、信号测量

这个编码器测速实际上就是测频法测正交脉冲的频率。正交信号频率更高,A、B相都可以计次,相当于计次频率提高了一倍,其次可以抗噪声

如果出现了边沿信号,并且对应另一相的状态为正转,则控制CNT自增,否则自减

 二、工作电路

1、基本电路结构

编码器输入部分:与CH1、CH2相连,输入捕获前面的输入滤波器和边沿检测器编码器继续使用,但是后面的是否交叉、预分频器和CCR寄存器则与编码器无关。
编码器输出部分:相当于从模式控制器,去控制CNT的计数时钟和计数方向

※ 注意:此处时基单元中配置的内部时钟和时基单元初始化时设置的计数方向并没有使用,因为此处这属于编码器托管状态,计数器的增加减少由编码器控制

2、编码器工作模式

工作模式:既可以是全部的上升下降沿都计数,也可以是忽略一些

实例:

①均不反相

②T1反相

抗噪声:实例中可以看出如果出现跳变多次的情况计数器就会+-+-来回摆动使得最终的计数值不受毛刺噪声的影响

对于反相的理解:由于编码器是上升沿和下降沿都有效,所以极性选择的时候不再是边沿的极性选择,而是高低电平的极性选择。如果选择上升沿的参数就是信号直通过来,高低电平极性不反转;反之则要通过一个非门过来,高低电平极性反转,所以这里就会由两个控制极性是否反转的参数,对应于两个实例中的是否反相

三、程序编写

1、编写步骤

Step 1 RCC开启时钟。TIM外设和GPIO外设的时钟打开
Step 2 GPIO初始化,这里需要把PA6和PA7配置成输入模式
Step 3 配置时基单元,这里预分频器一般选择不分频,自动重装一般给最大65535。
Step 4 配置输入捕获单元,滤波器、极性这两个参数配置好就行,其余用不到。
Step 5 配置编码器接口模式,这个调用库函数即可。
Step 6 调用TIM_Cmd函数,开启定时器。
Step 8 如果想要测量编码器的位置,直接读取CNT的值就好;如果想要测量编码器的速度和方向,需要每隔一段固定得闸门时间,取出一次CNY,然后把CNT清零。

※ GPIO的引脚模式,可以看外部模块输出的默认电平,如果外部模块空闲默认为输出高电平,选择上拉输入,默认输入高电平;如果外部模块空闲默认为输出低电平,选择下拉输入,默认输入低电平;如果不确定或者外部输出功率很小,可以选择浮空输入。总而言之就是和外部模块保持默认状态一致,防止默认电平打架。

2、库函数——配置 STM32 的定时器编码器接口

void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode, uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity);

TIM_TypeDef* TIMx:
        作用 :选择具体的定时器。
uint16_t TIM_EncoderMode:
        作用 :设置编码器的工作模式。通常有以下几种模式:
        TIM_EncoderMode_TI1:仅使用 TI1 通道进行编码器计数。
        TIM_EncoderMode_TI2:仅使用 TI2 通道进行编码器计数。
        TIM_EncoderMode_TI12:同时使用 TI1 和 TI2 通道进行编码器计数(精度最高)
uint16_t TIM_IC1Polarity:
        作用 :设置输入通道 1(TI1)的极性(确定 TI1 通道的信号跳变沿触发方式)。取值为:
        TIM_ICPolarity_RisingEdge:上升沿有效。
        TIM_ICPolarity_FallingEdge:下降沿有效。
uint16_t TIM_IC2Polarity:
        作用 :设置输入通道 2(TI2)的极性(确定 TI2 通道的信号跳变沿触发方式)。取值与 TI1 类似。

#include "stm32f10x.h"

// 定义使用的定时器
#define TIMx TIM2
// 定义使用的 GPIO
#define GPIOx GPIOA
#define GPIO_Pin GPIO_Pin_0 // PA0

void Encoder_Init(void)
{
    TIM_ICInitTypeDef  TIM_ICInitStruct;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitStruct;

    // Step 1: RCC开启时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 使能 TIM3 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能 GPIOA 时钟

    // Step 2: GPIO初始化
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入模式
    GPIO_Init(GPIOx, &GPIO_InitStructure);

    // Step 3: 配置时基单元
    TIM_TimeBaseInitStruct.TIM_Period =65535; // 设置自动重装载寄存器
    TIM_TimeBaseInitStruct.TIM_Prescaler = 71; // 设置预分频器,定时器时钟为 1MHz
    TIM_TimeBaseInitStruct.TIM_ClockDivision = 0; // 时钟分频因子为 0
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
    TIM_TimeBaseInit(TIMx, &TIM_TimeBaseInitStruct);

    // Step 4: 配置输入捕获单元
    TIM_ICStructInit(&TIM_ICInitStruct); // 初始化输入捕获结构体
    TIM_ICInitStruct.TIM_Channel = TIM_Channel_1; // 选择通道 1
    TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; // 上升沿触发,可以删掉,因为后面的库函数配置编码器的时候也会配置一遍极性,所以相当于重复配置了,会被后面的配置覆盖(如果之前使用了结构体初始化的话)
    TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; // 直接捕获模式,这个和下面的一个预分频器没有用,但是参数不全可能会出问题,所以要么还是配置一个,要么用结构体初始化一个默认值。
    TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; // 预分频器系数为 1
    TIM_ICInitStruct.TIM_ICFilter = 0xF; // 最大滤波
    TIM_ICInit(TIM3, &TIM_ICInitStruct);
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
    TIM_ICInitStructure.TIM_ICFilter = 0xF;
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI;
    TIM_ICInit(TIM3, &TIM_ICInitStructure);

    TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);

    TIM_Cmd(TIMx, ENABLE); // 启动定时器
}

uint16_t Encoder_Get(void) //测速
{
    int16_t Temp;
    Temp = TIM_GetCounter(TIM3);
    TIM_SetCounter(TIM3, 0)
    return Temp;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值