stm32读取编码器的两种方式

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
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
驱动编码器需要使用STM32的定时器和GPIO来读取编码器的脉冲信号。在STM32中,可以使用中断法或者轮询法来读取编码器的脉冲信号。 中断法的实现步骤如下: 1. 配置定时器和GPIO的引脚,将编码器的A、B两个信号引脚连接到STM32的GPIO引脚上。 2. 在定时器的初始化函数中,配置定时器的计数模式为边沿对齐模式,并设置自动装载值。 3. 在定时器的中断回调函数中,读取定时器的计数值,根据A、B两个信号的变化情况来判断编码器的旋转方向。 4. 根据编码器的旋转方向来更新电机的角度和速度。 轮询法的实现步骤如下: 1. 配置定时器和GPIO的引脚,将编码器的A、B两个信号引脚连接到STM32的GPIO引脚上。 2. 在定时器的初始化函数中,配置定时器的计数模式为边沿对齐模式,并设置自动装载值。 3. 在定时器的定时中断函数中,读取GPIO引脚的电平值,根据A、B两个信号的变化情况来判断编码器的旋转方向。 4. 根据编码器的旋转方向来更新电机的角度和速度。 以上是驱动编码器的基本步骤,具体的实现可以参考引用\[2\]和引用\[3\]中的代码示例。 #### 引用[.reference_title] - *1* *3* [STM32应用(九)编码器及其测速原理、L298N电机驱动控制编码器电机](https://blog.csdn.net/weixin_45751396/article/details/119721030)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [STM32 编码器驱动/旋转编码器旋钮encoder](https://blog.csdn.net/denghuajing/article/details/122683502)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值