stm32读取编码器的两种方式

该文详细介绍了如何在STM32微控制器中使用外部中断和定时器来读取编码器信号。首先,通过初始化GPIO、NVIC和EXTI,实现了编码器的外部中断读取,根据下降沿触发事件更新计数和方向。其次,利用TIM初始化为编码器接口模式,配置PB6和PB7作为输入,并在定时器中断服务函数中处理编码器计数。文章提供了完整的代码示例,涵盖了中断和定时器两种读取方法。
摘要由CSDN通过智能技术生成

1.使用外部中断 读取

#include "spin.h"


#define encoder_port    GPIOG
#define encoder_pin     (GPIO_Pin_3|GPIO_Pin_5)
#define encoder_pin_A   GPIO_Pin_3  //外部中断引脚
#define encoder_pin_B   GPIO_Pin_5



void Encoder_Init_Exit()
{
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    EXTI_InitTypeDef EXTI_InitStructure;

    NVIC_InitStructure.NVIC_IRQChannel                   = EXTI3_IRQn; //选择触发的通道 EXTI3_IRQn 与 PG3 EXTI_Line3 一致
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;     // 使能
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;          //抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;          //响应优先级
    NVIC_Init(&NVIC_InitStructure);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);
    
    GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IN_FLOATING;// GPIO_Mode_IPU; //配置为上拉模式
    GPIO_InitStructure.GPIO_Pin   = encoder_pin;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(encoder_port, &GPIO_InitStructure);

    // GPIO_PinRemaConfig() 可以用来引脚重映射
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOG, GPIO_PinSource3); //配置AFIO的数据选择器,来选择我们要的引脚,指定外部中断线

    EXTI_InitStructure.EXTI_Line    = EXTI_Line3;                  //需要我们配置中断线,我们用PG3所在的 EXTI_Line3
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;                      //开启中断
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;            //中断模式
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;        //设置触发方式 下降沿触发
    EXTI_Init(&EXTI_InitStructure);                                //调用这个参数,就可以根据这个结构体

}
 
void EXTI3_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line3) == SET) //确认是 EXTI_Line3引发的中断
    {    // encoder_pin_A 设置了外部中断,下降沿触发

        delay_ms(1); //很重要,必不可少, 软件滤波

        if (0 == GPIO_ReadInputDataBit(encoder_port, encoder_pin_A)) //判断 encoder_pin_A是低电平, 经历了下降沿
        {
            if (1 == GPIO_ReadInputDataBit(encoder_port, encoder_pin_B)) //判断 encoder_pin_B 电平状态,
            {
                ++encoder_g.counter;
                encoder_g.dir= 10; //正转标志
            }    
            else
            {
                --encoder_g.counter;
                encoder_g.dir = 20; //反转标志
            }

            printf("count %d\n", Encoder_Readnum_Exit(0));
            printf("dir %d\n", Encoder_ReadDir_Exit());
            
        }
        EXTI_ClearITPendingBit(EXTI_Line3); //手动清除外部中断标志位 
    }
}
/**
 * @brief 正转返回1 反转返回-1 静止返回0
 * 
 */
int Encoder_ReadDir_Exit(void) 
{
    if( 10 == encoder_g.dir ){
        encoder_g.dir= 0;
        return 1;
    }
    else if (20 == encoder_g.dir ){
        encoder_g.dir = 0;
        return -1;
    }
    else{
        encoder_g.dir = 0;
        return 0;
    }
}

/**
 * @brief flag=0 读数cnt不清零  flag=0 读数cnt清零
 *
 */
int Encoder_Readnum_Exit(u8 flag)
{
    int result = encoder_g.counter;

    if (flag){
        encoder_g.counter = 0;
     }

     return result;
}
#ifndef _SPIN_H
#define _SPIN_H

#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "delay.h"
#include "usart.h"

typedef struct E_g{
    int counter;   //计数    
    u8 dir;        //旋转方向 正为+  反为- 静为 0
    u8 sw;         //按键状态 按下置1

}Encoder_g;

static Encoder_g  encoder_g={
    .counter=0,
    .dir=0,
    .sw=0
};

void Encoder_Init_Exit();
int Encoder_Readnum_Exit(u8 flag);
int Encoder_ReadDir_Exit(void);

#endif

2.定时器作编码电机模式读取


#include "encoder.h"
 
 
/**************************************************************************
函数功能:单位时间读取编码器B计数
入口参数:无
返回  值:计数值
**************************************************************************/
int Read_Encoder(TIM_TypeDef *TIMx)
{
    return (short)TIMx->CNT;
}
/**************************************************************************
函数功能:把TIM初始化为编码器接口模式
端口配置: PB6 PB7
入口参数:无
返回  值:无
**************************************************************************/
 void Encoder_Init_TIMx(TIM_TypeDef* TIMx )
 {
     TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
     TIM_ICInitTypeDef TIM_ICInitStructure;
     GPIO_InitTypeDef GPIO_InitStructure;

    // NVIC_InitTypeDef NVIC_InitStructure;
    //  NVIC_InitStructure.NVIC_IRQChannel                   = TIM3_IRQn;
    //  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;      //抢占优先级3
    //  NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;      //子优先级3
    //  NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE; // IRQ通道使能
    //  NVIC_Init(&NVIC_InitStructure);                                //根据指定的参数初始化VIC寄存器

     /*----------------------------不同定时器 修改这里 以及中断函数配置--------------------------------*/

     // GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);  //重映射配置  引脚冲突时配置

     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);  //使能定时器3的时钟
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PB端口

     GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_6 | GPIO_Pin_7; //端口配置
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   //浮空输入
     GPIO_Init(GPIOA, &GPIO_InitStructure);                  //初始化PB端口

     

     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_TimeBaseInit(TIMx, &TIM_TimeBaseStructure);               //初始化定时器3

     TIM_EncoderInterfaceConfig(TIMx, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); //使用编码器模式3(TIM_ICPolarity_Rising或者TIM_ICPolarity_Falling效果相同,都是4倍频)

     TIM_ICStructInit(&TIM_ICInitStructure);  //把TIM_ICInitStruct 中的每一个参数按缺省值填入
     TIM_ICInitStructure.TIM_ICFilter = 10;   //设置滤波器长度
     TIM_ICInit(TIMx, &TIM_ICInitStructure);  //根据 TIM_ICInitStruct 的参数初始化外设	TIMx

     TIM_ClearFlag(TIMx, TIM_FLAG_Update);        //清除TIM的更新标志位
     TIM_ITConfig(TIMx, TIM_IT_Update, ENABLE);   //使能定时器中断
     TIM_SetCounter(TIMx, 0);                     //计数初值设定
     TIM_Cmd(TIMx, ENABLE);                       //使能定时器
}

/**************************************************************************
 *  函数功能:TIM中断服务函数
 *
 *  功能:防止定时器cnt计数溢出
 * 
 *  入口参数:无
 *  
 *  返 回 值:无
 **************************************************************************/
// void TIM3_IRQHandler(void) 
// {
//     if (_TIM3_->SR & 0X0001) //溢出中断
//     {
//     }
//     _TIM3_->SR &= ~(1 << 0); //清除中断标志位
//  }
#ifndef _encoder_H_
#define _encoder_H_

#include "stm32f10x.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_gpio.h"
#define ENCODER_TIM_PERIOD (u16)(65535)    

typedef struct bianmadianji 
{
    int coder;
    u8 mode;  

}G_ENCODER;

static G_ENCODER g_ENCODER={0,0};

void Encoder_Init_TIMx(TIM_TypeDef* TIMx);

int Read_Encoder(TIM_TypeDef* TIMx);

#endif
 

  • 4
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值