STM32正交编码器接口

STM32四路正交编码器接口

一、主要内容

  1. 芯片型号、使用引脚及初始化程序源码
  2. TIM2端口重映射问题
  3. 与JTAG接口冲突时的现象及解决方法

二、芯片型号、使用引脚及初始化程序源码

芯片型号:STM32F103RET6
使用定时器:TIM2、TIM3、TIM4、TIM5
使用引脚:
     TIM2—PA15、PB3(remap)
     TIM3—PA6、PA7
     TIM4—PB6、PB7
     TIM5—PA0、PA1
初始化程序源码:
(其中TIM2的配置有特殊需要注意的地方,其他配置相同,调试时遇到的问题和解决方法见下文)

#include "stm32f10x.h"
#include "encoder.h"


void TIM2_Mode_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_ICInitTypeDef TIM_ICInitStructure;      

    //PA15 ch1, PB3 ch2 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);

    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);        // 关闭JTAG功能
    GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);            // 重映射TIM2的CH1、CH2到PA15和PB3
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;         
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);                           
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;         
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);                           

    TIM_DeInit(TIM2);
    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
    TIM_TimeBaseStructure.TIM_Period = 50000;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1 ;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);              

    TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge ,TIM_ICPolarity_BothEdge);
    TIM_ICStructInit(&TIM_ICInitStructure);
    TIM_ICInitStructure.TIM_ICFilter = 6;
    TIM_ICInit(TIM2, &TIM_ICInitStructure);

    TIM_ClearFlag(TIM2, TIM_FLAG_Update);
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    //Reset counter
    TIM2->CNT = 0;

    TIM_Cmd(TIM2, ENABLE);
}


void TIM3_Mode_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_ICInitTypeDef TIM_ICInitStructure;      

    //PA6 ch1, PA7 ch2 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;         
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);                           

    TIM_DeInit(TIM3);
    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
    TIM_TimeBaseStructure.TIM_Period = 50000;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1 ;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);              

    TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge ,TIM_ICPolarity_BothEdge);
    TIM_ICStructInit(&TIM_ICInitStructure);
    TIM_ICInitStructure.TIM_ICFilter = 6;
    TIM_ICInit(TIM3, &TIM_ICInitStructure);

    TIM_ClearFlag(TIM3, TIM_FLAG_Update);
    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
    //Reset counter
    TIM3->CNT = 0;

    TIM_Cmd(TIM3, ENABLE);
}


void TIM4_Mode_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_ICInitTypeDef TIM_ICInitStructure;      

    //PB6 ch1, PB7 ch2 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;         
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);                           

    TIM_DeInit(TIM4);
    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
    TIM_TimeBaseStructure.TIM_Period = 50000;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);              

    TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge ,TIM_ICPolarity_BothEdge);
    TIM_ICStructInit(&TIM_ICInitStructure);
    TIM_ICInitStructure.TIM_ICFilter = 6;
    TIM_ICInit(TIM4, &TIM_ICInitStructure);

    TIM_ClearFlag(TIM4, TIM_FLAG_Update);
    TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
    //Reset counter
    TIM4->CNT = 0;

    TIM_Cmd(TIM4, ENABLE);
}


void TIM5_Mode_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_ICInitTypeDef TIM_ICInitStructure;      

    //PA0 ch1 A,PA1 ch2 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;         
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);                           

    TIM_DeInit(TIM5);
    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
    TIM_TimeBaseStructure.TIM_Period = 50000;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);              

    TIM_EncoderInterfaceConfig(TIM5, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge ,TIM_ICPolarity_BothEdge);
    TIM_ICStructInit(&TIM_ICInitStructure);
    TIM_ICInitStructure.TIM_ICFilter = 6;
    TIM_ICInit(TIM5, &TIM_ICInitStructure);

    TIM_ClearFlag(TIM5, TIM_FLAG_Update);
    TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE);
    //Reset counter
    TIM5->CNT = 0;

    TIM_Cmd(TIM5, ENABLE);
}

在使用时,读取TIMx->CNT寄存器中的数据即可。

三、 TIM2端口重映射问题

问题描述

在一开始调试的时候,TIM2的初始化程序和其他定时器的相同,这时旋转TIM2连接的编码器,计数没有变化,旋转TIM5连接的编码器时,TIM2和TIM5的计数同时变化并且数值相同。

解决方法

引脚定义
引脚定义
引脚定义

从手册中可以看出PA15和PB3的TIM2功能需要进行重映射,否则在PA0和PA1上编码器信号既进入TIM2,又进入TIM5,因此会导致TIM2和TIM5的计数相同。

在PA15和PB3作为TIM2编码器信号输入引脚时,需要进行IO重映射:

GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);            // 重映射TIM2的CH1、CH2到PA15和PB3

四、与JTAG接口冲突时的现象及解决方法

问题描述

在TIM2进行IO重映射后,仍不能正常使用,无论如何旋转编码器,计数器的值只有0、1、MAX三个值(在0上+1或-1)

解决方法

编码器模式中计数器样例
从手册中编码器模式下的计数器变化过程中可以看出,当两相编码器的一个信号不变,另一个信号变化时,计数器计数值会在某个数值上下波动,和上述问题情况类似,因此猜测是因为编码器其中一相的信号没有捕获到。
引脚定义
引脚定义
再次查阅手册发现PA15和PB3引脚的默认功能为JTAG功能,需要关闭后才能正确使用,否则JTDO为输出引脚,无法捕获到编码器信号,所以会出现计数值只有0,1,MAX三个值的现象。这里仅关闭JTAG功能,保留SWD以便调试使用:

    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);        // 关闭JTAG功能

五、参考链接

http://blog.csdn.net/wang328452854/article/details/50579832
http://www.openedv.com/posts/list/54017.htm
http://www.openedv.com/posts/list/0/57077.htm

  • 7
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
正交编码器(Quadrature Encoder)是一种常用的位置传感器,用于测量旋转或线性运动的位移和方向。它由两个光电传感器和一个光栅盘组成,光栅盘被分隔为等距的刻线。 STM32是一款非常流行的单片机系列,提供了HAL库(Hardware Abstraction Layer),简化了对硬件的访问和操作。 在使用STM32 HAL库进行正交编码器相关的编程时,可以按照以下步骤进行: 1. 初始化正交编码器的GPIO:设置编码器的引脚作为输入,注意使能引脚也需要设置为输入。 2. 配置编码器的外部中断(External Interrupt):通过HAL库的函数调用来配置外部中断,使得在编码器的每个脉冲之前和之后都触发中断。 3. 在中断服务函数(Interrupt Service Routine)中对编码器信号进行处理:编码器每次脉冲时,中断服务函数被调用。可以通过测量脉冲的方向和数量来计算运动的位移。 4. 使用计时器(Timer)进行速度测量:HAL库提供了内置的计时器功能,可以用于测量编码器的转速。通过计时器的输入捕获(Input Capture)功能,可以精确地测量两个脉冲的时间间隔,从而计算出转速。 5. 根据需求进行功能扩展:根据具体应用的需求,可以使用HAL库的其他功能,如PWM输出控制电机速度、外设和通信接口的配置等。 通过使用STM32 HAL库,我们可以方便地实现对正交编码器的读取、位置计算和速度测量等功能,大大简化了硬件的驱动和编程工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值