Based on the STM32F103 standard library function, write the encoder driver module

Introduction to encoder interface

1. The encoder interface can receive the signal of the incremental (orthogonal) encoder, and automatically controls the CNT to increase or decrease according to the orthogonal signal pulse generated by the encoder rotation, thus indicating the position, rotation direction and rotation speed of the encoder.
2. Each advanced timer and general timer has an encoder interface
3. The two input pins borrow channel 1 and channel 2 of the input capture

Orthogonal encoder

Pictured

Basic structure of encoder interface

Working mode


Three modes
*@param TIM_EncoderMode: Specifies the TIMx encoder mode. This parameter can be one of the following values:
@arg TIM_EncoderMode_TI1: The counter counts on the TI1FP1 edge depending on the TI2FP2 level.
@arg TIM_EncoderMode_TI2: The counter counts TI2FP2 edges depending on the TI1FP1 level.
* @arg TIM_EncoderMode_TI12: The counter counts the TI1FP1 and TI2FP2 sides depending on the level of the other input.

TI1 and TI2 are not reversed

###

TI1 reverse

Driver code

encoder.c

#include "sys.h"
#include "encoder.h"
/**
  * @brief Timer 2 encoder mode
  * @param PA0-channel 1 PA1-channel 2
  * @retval
  */
void Encoder_TIM2_Init(void)
{<!-- -->
/******************************Start clock****************** ************/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//Turn on the clock
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
/****************************Define structure variables****************** ******************/
GPIO_InitTypeDef GPIO_InitStruct;//GPIO
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;//Time base unit
TIM_ICInitTypeDef TIM_ICInitStruct;//Timer input capture

\t
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0 |GPIO_Pin_1;
GPIO_Init(GPIOA, & amp;GPIO_InitStruct);
\t
TIM_TimeBaseStructInit( & TIM_TimeBaseInitStruct);//Initialize the timer.
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period=65535;
TIM_TimeBaseInitStruct.TIM_Prescaler=0;
TIM_TimeBaseInit(TIM2, & amp;TIM_TimeBaseInitStruct);
\t
TIM_EncoderInterfaceConfig(TIM2,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);//Configure the encoder mode
\t
TIM_ICStructInit( & TIM_ICInitStruct);//Initialize input capture
TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter=10;
TIM_ICInit(TIM2, & amp;TIM_ICInitStruct);
\t
TIM_ICInitStruct.TIM_Channel=TIM_Channel_2;
TIM_ICInitStruct.TIM_ICFilter=10;
TIM_ICInit(TIM2, & amp;TIM_ICInitStruct);
\t
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//Configuration overflow update interrupt flag bit
\t
TIM_SetCounter(TIM2,0);//Clear the timer count value
\t
TIM_Cmd(TIM2,ENABLE);//Start the timer
}

/**
  * @brief Timer 3 encoder mode
  * @param PA6-channel 1 PA7-channel 2
  * @retval
  */
void Encoder_TIM3_Init(void)
{<!-- -->
/****************************Start clock************************ ************/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/****************************** Configure pin mode****************** ***************/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, & amp;GPIO_InitStructure);
/******************************Configure time base unit****************** ******************/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, & amp;TIM_TimeBaseInitStructure);
/****************************Input Capture Unit Configuration****************** ******************/
TIM_ICInitTypeDef TIM_ICInitStructure;//Define a structure variable
TIM_ICStructInit( & amp;TIM_ICInitStructure);//Assign an initial value to the structure
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//Channel 1
TIM_ICInitStructure.TIM_ICFilter = 0xF;//
TIM_ICInit(TIM3, & amp;TIM_ICInitStructure);//Structure initialization
/****************************You can continue to use the structure variables defined above****************** *******************/
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICFilter = 0xF;
TIM_ICInit(TIM3, & amp;TIM_ICInitStructure);//Define another initialization and assign the value to channel 2
/******************************Configure encoder mode****************** ******************/
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
\t
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);//Configure overflow update interrupt flag bit
TIM_SetCounter(TIM3,0);//Clear the timer count value
\t
TIM_Cmd(TIM3, ENABLE);//Start the timer
}
/**
  * @brief Read encoder speed entry function
  * @param TIM2 TIM3
  * @retval The count value of the counter at a certain time
  * @attention The return value of TIM_GetCounter is uint16_t, which needs to be cast to a signed type.
  */
int16_t Read_Speed(int TIMx)
{<!-- -->
int16_t value_1;
switch(TIMx)
{<!-- -->
case 2:value_1=(int16_t)TIM_GetCounter(TIM2);TIM_SetCounter(TIM2,0);break;//IF is timer 2, 1. Collect the count value of the encoder and save it. 2. Clear the timer count value to zero.
case 3:value_1=(int16_t)TIM_GetCounter(TIM3);TIM_SetCounter(TIM3,0);break;
default:value_1=0;
}
return value_1;
}

int16_t Encoder_Get(void)
{<!-- -->
int16_t Temp;
Temp = TIM_GetCounter(TIM3);//uint16_t type
TIM_SetCounter(TIM3, 0);//Clear the timer count value
return Temp;
}
void TIM2_IRQHandler(void)
{<!-- -->
if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=0)
{<!-- -->
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
void TIM3_IRQHandler(void)
{<!-- -->
if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=0)
{<!-- -->
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
}
}

encoder.h

#ifndef __ENCODER_H
#define __ENCODER_H
#include "stm32f10x.h" // Device header

void Encoder_TIM2_Init(void);
void Encoder_TIM3_Init(void);
int16_t Encoder_Get(void);
void TIM2_IRQHandler(void);
void TIM3_IRQHandler(void);
int16_t Read_Speed(int TIMx);

#endif

sys.h

#ifndef __SYS_H
#define __SYS_H
#include "stm32f10x.h"
#include "Delay.h"
#include "OLED.h"
#include "encoder.h"

/****************************************************** *******************/
 

//0, does not support ucos
//1, support ucos
#define SYSTEM_SUPPORT_OS 0 //Define whether the system folder supports UCOS
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t    
\t 
//Bit band operation to achieve 51 similar GPIO control functions
//For specific implementation ideas, refer to Chapter 5 of <<CM3 Authoritative Guide>> (pages 87~92).
//IO port operation macro definition
#define BITBAND(addr, bitnum) ((addr & amp; 0xF0000000) + 0x2000000 + ((addr & amp;0xFFFFF)<<5) + (bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
//IO port address mapping
#define GPIOA_ODR_Addr (GPIOA_BASE + 12) //0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE + 12) //0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE + 12) //0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE + 12) //0x4001140C
#define GPIOE_ODR_Addr (GPIOE_BASE + 12) //0x4001180C
#define GPIOF_ODR_Addr (GPIOF_BASE + 12) //0x40011A0C
#define GPIOG_ODR_Addr (GPIOG_BASE + 12) //0x40011E0C

#define GPIOA_IDR_Addr (GPIOA_BASE + 8) //0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE + 8) //0x40010C08
#define GPIOC_IDR_Addr (GPIOC_BASE + 8) //0x40011008
#define GPIOD_IDR_Addr (GPIOD_BASE + 8) //0x40011408
#define GPIOE_IDR_Addr (GPIOE_BASE + 8) //0x40011808
#define GPIOF_IDR_Addr (GPIOF_BASE + 8) //0x40011A08
#define GPIOG_IDR_Addr (GPIOG_BASE + 8) //0x40011E08
 
//IO port operation, only for a single IO port!
//Make sure the value of n is less than 16!
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //Output
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //Input

#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //Output
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //Input

#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //Output
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //Input

#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //Output
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //Input

#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //Output
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //Input

#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //Output
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //Input

#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //Output
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //Input

//The following is the assembly function
void WFI_SET(void); //Execute WFI instruction
void INTX_DISABLE(void);//Close all interrupts
void INTX_ENABLE(void); //Enable all interrupts
void MSR_MSP(u32 addr); //Set stack address

#endif