数码之家

 找回密码
 立即注册
搜索
查看: 82|回复: 3

EC11_12编码器检测程序

[复制链接]
发表于 昨天 13:32 | 显示全部楼层 |阅读模式

爱科技、爱创意、爱折腾、爱极致,我们都是技术控

您需要 登录 才可以下载或查看,没有账号?立即注册

x

测试平台STM32F103
//头文件


#ifndef __ENCODER_H__
#define __ENCODER_H__

#include "stm32f103xg.h"
#include "stm32f1xx_hal_gpio.h"

#define EC_IDLE_CNT 10

typedef struct
{
        GPIO_TypeDef *port_a; //PORT A
        uint16_t pin_a;       //PIN  A
        GPIO_TypeDef *port_b; //PORT B
        uint16_t pin_b;       //PIN  B
        uint8_t a;
        uint8_t b;
        uint8_t status;
        uint8_t cnt;
        void (*turn_l)(uint32_t *btns);
        void (*turn_r)(uint32_t *btns);
        void (*idle)(uint32_t *btns);
}encoder_t;

extern encoder_t ec1, ec2, ec3, ec4, ec5;

void encoder_detect(uint32_t *btns);
void encoder_init(void);

#endif


//源文件

#include "encoder.h"
#include "stm32f1xx_hal.h"
#include "tm1629.h"
#include "usart.h"
#include "main.h"

void ec1_turn_l(uint32_t *btns)
{
        *btns |= (1<<2);  
        //ToDo here...
}

void ec1_turn_r(uint32_t *btns) {
        *btns |= (1<<3);  
        //ToDo here...
}

void ec2_turn_l(uint32_t *btns) {
        *btns |= (1<<5);
        //ToDo here...
}

void ec2_turn_r(uint32_t *btns) {
        *btns |= (1<<6);
        //ToDo here...
}

void ec3_turn_l(uint32_t *btns) {
        *btns |= (1<<8);
        //ToDo here...
}

void ec3_turn_r(uint32_t *btns) {
        *btns |= (1<<9);  
        //ToDo here...
}

void ec4_turn_l(uint32_t *btns) {
        *btns |= (1<<11);
        //ToDo here...
}

void ec4_turn_r(uint32_t *btns) {
        *btns |= (1<<12);
        //ToDo here...
}

void ec5_turn_l(uint32_t *btns) {
        *btns |= (1<<14);
        //ToDo here...
}

void ec5_turn_r(uint32_t *btns) {
        *btns |= (1<<15);
        //ToDo here...
}

void ec1_idle(uint32_t *btns) {
        *btns &= ~((1<<2) | (1<<3));
        //ToDo here...
}

void ec2_idle(uint32_t *btns) {
        *btns &= ~((1<<5) | (1<<6));
        //ToDo here...
}

void ec3_idle(uint32_t *btns) {
        *btns &= ~((1<<8) | (1<<9));
        //ToDo here...
}

void ec4_idle(uint32_t *btns) {
        *btns &= ~((1<<11)|(1<<12));
        //ToDo here...
}

void ec5_idle(uint32_t *btns) {
        *btns &= ~((1<<14)|(1<<15));
        //ToDo here...
}

//定义5个编码器,数量可随意增减
encoder_t ec1 = { GPIOC, GPIO_PIN_14, GPIOC, GPIO_PIN_15, 0, 0, 0, 0, ec1_turn_l, ec1_turn_r, ec1_idle};
encoder_t ec2 = { GPIOC, GPIO_PIN_1,  GPIOC, GPIO_PIN_2 , 0, 0, 0, 0, ec2_turn_l, ec2_turn_r, ec2_idle};
encoder_t ec3 = { GPIOA, GPIO_PIN_4,  GPIOA, GPIO_PIN_5 , 0, 0, 0, 0, ec3_turn_l, ec3_turn_r, ec3_idle};
encoder_t ec4 = { GPIOC, GPIO_PIN_4,  GPIOC, GPIO_PIN_5 , 0, 0, 0, 0, ec4_turn_l, ec4_turn_r, ec4_idle};
encoder_t ec5 = { GPIOB, GPIO_PIN_10, GPIOB, GPIO_PIN_2 , 0, 0, 0, 0, ec5_turn_l, ec5_turn_r, ec5_idle};

//主要的检测函数就是这个,其余的都可以忽略
void detect(encoder_t *ec, uint32_t *btns)
{
        if (ec->a==1 && ec->b==1) {
                ec->status = 0;
                ec->cnt = 0;
                return;
        } else if (ec->a==0 && ec->b==1 && (ec->status==0)) {
                ec->status = 'L';
        } else if (ec->a==1 && ec->b==0 && (ec->status==0)) {
                ec->status = 'R';
        } else if (ec->a==0 && ec->b==0) {
                if (ec->status != 0xFF) {
                        if (ec->status=='L') {
                                ec->turn_l(btns);
                                ec->status = 0xFF;
                        } else if (ec->status=='R') {
                                ec->turn_r(btns);
                                ec->status = 0xFF;
                        }
                } else {
                        if (ec->cnt < EC_IDLE_CNT) { //可以定义检测生效后的延迟时间,避免短时间内连续有效触发
                                ec->cnt++;
                                if (ec->cnt == (EC_IDLE_CNT-1)) {
                                        ec->idle(btns); //release button
                                }
                        }
                }
        }
}

void encoder_detect(uint32_t *btns)
{
        ec1.a = !HAL_GPIO_ReadPin(ec1.port_a, ec1.pin_a);
        ec1.b = !HAL_GPIO_ReadPin(ec1.port_b, ec1.pin_b);
        detect(&ec1, btns);
       
        ec2.a = !HAL_GPIO_ReadPin(ec2.port_a, ec2.pin_a);
        ec2.b = !HAL_GPIO_ReadPin(ec2.port_b, ec2.pin_b);
        detect(&ec2, btns);
       
        ec3.a = !HAL_GPIO_ReadPin(ec3.port_a, ec3.pin_a);
        ec3.b = !HAL_GPIO_ReadPin(ec3.port_b, ec3.pin_b);
        detect(&ec3, btns);
       
        ec4.a = !HAL_GPIO_ReadPin(ec4.port_a, ec4.pin_a);
        ec4.b = !HAL_GPIO_ReadPin(ec4.port_b, ec4.pin_b);
        detect(&ec4, btns);
       
        ec5.a = !HAL_GPIO_ReadPin(ec5.port_a, ec5.pin_a);
        ec5.b = !HAL_GPIO_ReadPin(ec5.port_b, ec5.pin_b);
        detect(&ec5, btns);
}

void encoder_set_inputmode(GPIO_TypeDef* port, int pin)
{
        GPIO_InitTypeDef GPIO;
        GPIO.Pin = pin;
        GPIO.Mode = GPIO_MODE_INPUT;
        GPIO.Pull = GPIO_PULLUP;
        HAL_GPIO_Init(port, &GPIO);
}

void encoder_init(void)
{
        encoder_set_inputmode(ec1.port_a, ec1.pin_a);
        encoder_set_inputmode(ec1.port_b, ec1.pin_b);

        encoder_set_inputmode(ec2.port_a, ec2.pin_a);
        encoder_set_inputmode(ec2.port_b, ec2.pin_b);

        encoder_set_inputmode(ec3.port_a, ec3.pin_a);
        encoder_set_inputmode(ec3.port_b, ec3.pin_b);

        encoder_set_inputmode(ec4.port_a, ec4.pin_a);
        encoder_set_inputmode(ec4.port_b, ec4.pin_b);

        encoder_set_inputmode(ec5.port_a, ec5.pin_a);
        encoder_set_inputmode(ec5.port_b, ec5.pin_b);
}


//应用
uint32_t buttons=0; //用变量中不同的位存储编码器的开关状态,请看上面的turn_l,turn_r,idle事件中的定义

void main(void)
{
    //init...
    //...
    encoder_init();
    //...

    while(1)
    {

        if (flag1ms)  //扫描频率,在定时器中断中1ms使能一次该标志
        {
            flag1ms = 0;
            encoder_detect(&buttons);
        }

}



打赏

参与人数 1家元 +6 收起 理由
ifus + 6 優秀文章

查看全部打赏

发表于 昨天 17:32 | 显示全部楼层
有没有快速旋转和慢转的区分方法?旋转速度到一定时,数据+10,慢转+1
回复 支持 反对

使用道具 举报

 楼主| 发表于 4 小时前 | 显示全部楼层
guer 发表于 2025-5-23 17:32
有没有快速旋转和慢转的区分方法?旋转速度到一定时,数据+10,慢转+1

快慢功能可以在外部用定时监测实现吧,与编码器检测本身无关,
示例宏代码:
int ecsw, ecsw_bak; //记录当前的,上一次的编码器触发状态
int ticks; //程序中应该有一个定时器驱动的ticks服务函数
ecsw = encoder_get(); //获取一次有效的编码器触发
if(ecsw != EC_VALID) //有效的触发
{
    if((get_ticks()-ticks) >= TRIGGER_LONG && ecsw==ecsw_bak)
    { //检测到连续两次触发了同一个编码器的同一次方向,并且间隔超过了TRIGGER_LONG
        //用户的代码,处理长触发
        goto exit;
    }
    //处理短触发逻辑
    //...
exit:
    ticks = get_ticks();
    ecsw = ecsw_bak;
}
使用这种逻辑思路,可处理多个阶梯的长触发,例如1秒的,3秒的,5秒的
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层
程序模块化,强,很方便使用
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-5-24 13:42 , Processed in 0.078000 second(s), 10 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

快速回复 返回顶部 返回列表