当前位置:网站首页>Esp32 drive encoder -- siq-02fvs3 (vscade + IDF)

Esp32 drive encoder -- siq-02fvs3 (vscade + IDF)

2022-04-23 18:40:00 Please call me Xiao Peng

Tips : This blog serves as a learning note , If there are mistakes, I hope to correct them

One 、 Encoder Introduction

   Encoder is generally divided into hall encoder and grating encoder , The formula I use here SIQ-02FVS3 This mini encoder , and EC11 The driving method is similar , But this encoder is small , But the price is more expensive . The following is the physical picture of the encoder .SIQ-02FVS3 It also has a press button , To achieve multi-function .
 Insert picture description here

   So how do we use this encoder , From the given data book, we can see a waveform , We use this waveform to judge whether the encoder rotates and the direction of encoder rotation , It can be seen from the figure that when CW When the direction turns ,A Rising edge ratio of waveform B The rising edge of the waveform is fast , How fast is it , The data book here gives 24±3°, When from CCW The direction of rotation is exactly the opposite at this time ,B The rising edge of phase is faster than A The rising edge of . In this way, the direction of the encoder can be determined by capturing the order of rising edges .
 Insert picture description here

   After understanding the working mechanism of the encoder, we can have the following methods to realize the state capture of the encoder , With CW Direction, for example .

  • 1、 When detected A At the rising edge of the term , testing B Status of the item , Sure A The rising edge breaks , Detect in interrupt B The level state of .
  • 2、 Simultaneous detection A、B The rising edge of the item , Then judge the direction according to the order of rising edges .
  • 3、 You can capture an item ( for example A term ) The edge of , And then determine A Get when the first edge of the item breaks B and A Level of item , Capture when the second edge triggers an interrupt B and A Level of item , Based on two captures B and A The value of the term can know the direction of rotation .

Two 、 Hardware design

   The hardware design should be noted that if it is detected by interrupt , It's best to use... In hardware 0.1uF Filter capacitor filter , Otherwise, there will be some burrs and starting interruption when rotating , Or use software filtering , But it's more troublesome , Detect the interval time between two rising edges to judge the effective value of receiving and processing interrupt signal .
   The following two pictures capture the level at the time of rotation through the logic analyzer , The first one looks good, with obvious interruption , But after zooming in, it is found that there are burrs in the second picture , This is a circuit without hardware filtering .
 Insert picture description here
 Insert picture description here
   Schematic diagram

 Insert picture description here

3、 ... and 、 Implementation code

   Here I use the third method to capture the encoder state , Plus hardware filtering , At present, it is more accurate to use , Use queues to send data out of interrupts . From the third case, there are two cases of capturing edges , With A Edge break , And then in A Capture in interrupt A、B The state of . Two cases .
  CW Direction, for example , First capture A The rising edge of the edge bit of the item , here A = 1,B = 0; Then the second time you have to capture the falling edge ,A = 0,B = 1. If A The first time you don't catch a rising edge at the edge , What is captured is the falling edge , The second time, you must catch the rising edge .CCW The direction is the same , So we can judge these four situations , Don't worry about anything else , This can filter out interference , So as to achieve more accurate control .

  Encoder.c file

#include "Encoder.h"
#define ESP_INTR_FLAG_DEFAULT 0

xQueueHandle encoder_gpio_event_queue = NULL;   // Encoder queue 
static unsigned int Value_count = 0;            // State count 
static int Encoder_A_Last_Value = 0;            // for the first time A Item value 
static int Encoder_B_Last_Value = 0;            // for the first time B Item value 
static int Encoder_A_Value = 0;                 // The second time A Item value 
static int Encoder_B_Value = 0;                 // The second time B Item value 
#define TAG "Encoder"
/***************************************** * @brief GPIO Interrupt handling  * @author wsp * @date 2022-2-21 * ***************************************/
static void IRAM_ATTR encoder_gpio_isr_handler(void * arg)
{
    
    uint32_t GPIO_Queue_Data = 0;       // Send queue variables 
    if(Value_count == 0){
                   // Edge count value , Count the edge value twice 
        Encoder_A_Last_Value = gpio_get_level(Encoder_A);   // Capture A Item value 
        Encoder_B_Last_Value = gpio_get_level(Encoder_B);   // Capture B Item value 
        Value_count  = 1;               // Start the first count 
    }else if(Value_count == 1){
             // Complete an edge capture 
        Encoder_A_Value = gpio_get_level(Encoder_A);        // Capture A Item value 
        Encoder_B_Value = gpio_get_level(Encoder_B);        // Capture B Item value 
        // State judgment processing 
        if(((Encoder_A_Last_Value == 0 && Encoder_A_Value == 1) && (Encoder_B_Last_Value == 1 && Encoder_B_Value == 0)) || ((Encoder_A_Last_Value == 1 && Encoder_A_Value == 0) && (Encoder_B_Last_Value == 0 && Encoder_B_Value == 1))){
            // Clockwise rotation 
            GPIO_Queue_Data = 1;        // The right one 
        }else if(((Encoder_A_Last_Value == 0 && Encoder_A_Value == 1) && (Encoder_B_Last_Value == 0 && Encoder_B_Value == 1)) || ((Encoder_A_Last_Value == 1 && Encoder_A_Value == 0) && (Encoder_B_Last_Value == 1 && Encoder_B_Value == 0))){
      // Counter clockwise rotation 
            GPIO_Queue_Data = 2;        // Second left 
        }
        Encoder_B_Last_Value = 2;       // Clear the status value , Not initialized 0 The reason is that the first global initialization is 0, To distinguish 
        Encoder_A_Last_Value = 2;       // Clear the status value 
        Value_count  = 0;               // Clear the status value 
    }
    if(GPIO_Queue_Data != 0)            // When the state changes   Sending queue 
        xQueueSendFromISR(encoder_gpio_event_queue, &GPIO_Queue_Data, NULL);  
}
/***************************************** * @brief  Encoder initialization  * @author wsp * @date 2022-2-21 * ***************************************/
void Encoder_init(void)
{
    
    gpio_config_t io_conf;                                  // To configure GPIO Structure 
    io_conf.intr_type = GPIO_INTR_DISABLE;                  // Do not enable GPIO interrupt 
    io_conf.mode = GPIO_MODE_INPUT;                         //GPIO The input mode 
    io_conf.pull_down_en = 0;                               // Pull down enable 
    io_conf.pull_up_en = 1;                                 // Pull up does not enable 
    io_conf.pin_bit_mask = Encoder_CHB_GPIO_INPUT_PIN_SEL;  //GPIO Input pin selection 
    gpio_config(&io_conf);                                  // To configure IO Parameters 

    io_conf.intr_type = GPIO_INTR_ANYEDGE;                  // Edge triggered interrupt 
    io_conf.pin_bit_mask = Encoder_CHA_GPIO_INPUT_PIN_SEL;  //GPIO Input pin selection 
    gpio_config(&io_conf);                                  // To configure IO Parameters 

    io_conf.intr_type = GPIO_INTR_DISABLE;                  // Do not enable GPIO interrupt 
    io_conf.pin_bit_mask = Encoder_KEY_GPIO_INPUT_PIN_SEL;  //GPIO Input pin selection 
    gpio_config(&io_conf);                                  // To configure IO Parameters 

    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);        // install GPIO Interruption of service 
    gpio_isr_handler_add(Encoder_A,encoder_gpio_isr_handler,(void * )Encoder_A);// Add interrupt service  
    
    encoder_gpio_event_queue = xQueueCreate(1,sizeof(uint32_t));                // Create a queue 
}
void Encoder_Test(void)
{
    
    char Capure_Enconder_State = 0;
    while(1){
    
        // Get queue information 
        if (pdTRUE == xQueueReceive(encoder_gpio_event_queue, & Capure_Enconder_State, (portTickType)portMAX_DELAY)){
    
            printf("Capure_Enconder_State:%d\n\r",Capure_Enconder_State);
        }
    }   
}

  Encoder.h file

#ifndef _Encoder_H_
#define _Encoder_H_
#include "lvgl/lvgl.h"
#include <stdio.h>
#include "lv_port_indev_Key.h"
#include "lvgl_function.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/ledc.h"
#include "esp_err.h"
#include "sdkconfig.h"

#define Encoder_A 34 // Encoder channel 1 
#define Encoder_B 35 // Encoder channel 2 
#define Encoder_K 13 // Encoder key channel 

#define Encoder_CHA_GPIO_INPUT_PIN_SEL ((1ULL<<Encoder_A))
#define Encoder_CHB_GPIO_INPUT_PIN_SEL ((1ULL<<Encoder_B))
#define Encoder_KEY_GPIO_INPUT_PIN_SEL ((1ULL<<Encoder_K))

extern xQueueHandle encoder_gpio_event_queue;
void Encoder_init(void);
void Encoder_Test(void);
#endif

  main function

void app_main(void)
{
    
    Encoder_init();
    Encoder_Test();
}

Four 、 Show results

   The final display result is quite accurate , There will be no problems when rotating quickly .
 Insert picture description here

版权声明
本文为[Please call me Xiao Peng]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204210609450036.html