[STM32 Learning] - Timer Encoder Interface & Quadrature Encoder & Encoder Interface Speed Measurement Code Practice


Disclaimer: The study notes are edited according to the stm32 introductory tutorial of Jiangke University of Science and Technology of China, and are only for learning and communication!

foreword

Introduction : This practical case is basically the same as the function of the rotary encoder counting code written when learning external interrupts, except that the previous ones are manually (software ++) counting in the interrupt function by triggering an external interrupt ;This code automatically counts times through the rotary encoder interface of the timer. The advantage of using the encoder interface is to save software resources , avoid frequent interrupts and only perform simple ++ operations (great waste of software resources).
Application scenario : Encoder speed measurement is generally used in motor control projects , use PWM waves to drive the motor, then use the encoder to measure the speed of the motor, and then use the PID algorithm for closed-loop control!
Note : Generally, the motor rotates at a relatively high speed, and a non-contact Hall sensor or grating is used to measure the speed. In this case, a contact-type rotary encoder is used for demonstration for convenience. The motor rotation is simulated by hand-tightening, and the effect is the same!

1. Encoder interface

Chip Manual 14.3.12

1 Introduction

Encoder Interface Encoder interface
1. The encoder interface can receive the signal of the incremental (orthogonal) encoder , and automatically control the CNT self-increment or self-decrement according to the orthogonal signal pulse generated by the encoder rotation , thereby indicating the position of the encoder, Direction of rotation and speed of rotation .
2. Each advanced timer and general-purpose timer has an encoder interface.
3. The encoder interface is actually equivalent to an external clock with direction control , which controls the counting clock and counting direction of CNT at the same time. Borrowing the knowledge points of the cycle measurement method and frequency measurement method in the input capture from the previous section, the encoder speed measurement is actually the frequency measurement method to measure the frequency of the orthogonal pulse , but the encoder count is more advanced: it can not only increase automatically according to the direction of rotation It can also be self-decreasing, which is a speed measurement with direction .
insert image description here
As shown in the green box above:
1. The encoder has two input terminals, which are respectively connected to the A and B two-phase pins of the quadrature encoder. The two input pins borrow the channel 1 and channel 2 of the input capture, that is, TIFP1 and TI2FP2 are connected with TIFP1 and TI2FP2 of the input capture channel below. Therefore, the outermost input pins of the encoder are the two pins TIMx_CH1 and CH2 on the lower left of the figure. The signal passes through channel 1 or 2 from these two pins to TIFP1 and TI2FP2 and then to the encoder interface. CH3 and CH4 have nothing to do with the encoder interface. (Red line)
2. The output part of the encoder is equivalent to the slave mode controller to control the counting clock and counting direction of CNT. The output execution flow is: when an edge signal appears and it is judged to be forward rotation according to the table below, the CNT is controlled to increase automatically, otherwise, it decreases automatically. Note that the 72MHz internal clock CK_PSC that has been used before and the counting direction +/- when the time base unit is initialized will not be used, because at this time the counting clock and the counting direction are both in the state of the encoder interface hosting, and the self-increment or self-decrement of CNT controlled by an encoder. (Green line)
Take out the encoder part alone:
insert image description here
​​working mode: (this table corresponds to the quadrature encoder part below, the forward direction counts up, and the reverse direction counts down)
insert image description here
Only when TI1 counts means that only the edge of phase A is counted. state, the accuracy is lower than that of counting the state of another phase on both the A and B edges.
Example (no inversion) : (the glitch part is an anti-noise function, and the up and down swings are not counted)
The so-called inversion means that the falling edge parameters are selected at the two edge detection and polarity selections, and the signal is flipped through a NOT gate.
insert image description here
Example (TI1 inversion) : (The influence of polarity change on counting)
TI1 inversion, that is, the following TI1 digital wave needs to be inverted from high to low and then correspond to the look-up table to determine whether to count down or up. The role of the inversion function: For example, the actual positive and negative rotation (because it is relative according to the needs) does not correspond to the self-increase and decrement of CNT, so you can invert the phase.
insert image description here

2. Quadrature Encoder

Quadrature: A and B have a 90° phase difference, and the two phases can be used to indicate the direction (forward and reverse are relative):
insert image description here
when an edge signal appears, the count will increase or decrease automatically, whether it is increased or decreased depends on the other The state of the phase is determined so that there can be a direction count.

2. Practical case (encoder interface speed measurement)

insert image description here

//Encoder.c
#include "stm32f10x.h"                  // Device header
/*第一步:RCC开启时钟,开启GPIO和定时器的时钟
  第二步:配置GPIO,需要把PA6和PA7配置成输入模式
  第三步:配置时基单元,其中prescaler一般选择不分频,自动重装ARR一般给最大65535,只需要个CNT执行计数就可
  第四步:配置捕获单元,这里只需要滤波器和极性两个参数,其他参数与编码器无关
  第五步:配置编码器接口模式,一个库函数即可
  最后:TIM_Cmd启动定时器
电路初始化完成后,CNT会随着编码器旋转而自增自减。
若想测编码器的位置,直接读出CNT的值即可;若想测编码器的速度和方向,就需要每隔一段固定的闸门时间取出一次CNT,然后再把CNT清零(测频法测速度)
*/
void Encoder_Init(){
    
    
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE );
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	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, &GPIO_InitStructure);
	
	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;//不分频,编码器时钟直接驱动计数器CNT
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter= 0 ;
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
	
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICStructInit(&TIM_ICInitStructure);//保证结构体配置完整,无用参数为初始化默认值
	
	TIM_ICInitStructure.TIM_Channel= TIM_Channel_1;
	TIM_ICInitStructure.TIM_ICFilter= 0xF;//0x0~0xF数越大滤波效果越好
	TIM_ICInitStructure.TIM_ICPolarity= TIM_ICPolarity_Rising;//边沿检测和极性选择
	//这里的上升沿与之前不同,不代表上升沿有效,因为编码器始终时上升下降沿都有效,这里表示高低电平极性不翻转
	//TIM_ICInitStructure.TIM_ICPrescaler= TIM_ICPSC_DIV1;//无效参数可不要,但要保证结构体完整加TIM_ICStructInit()函数
	//TIM_ICInitStructure.TIM_ICSelection= TIM_ICSelection_DirectTI;//无效参数可不要
	TIM_ICInit(TIM3,&TIM_ICInitStructure);
	
	TIM_ICInitStructure.TIM_Channel= TIM_Channel_2;
	TIM_ICInitStructure.TIM_ICFilter= 0xF;
	TIM_ICInitStructure.TIM_ICPolarity= TIM_ICPolarity_Rising;
	TIM_ICInit(TIM3,&TIM_ICInitStructure);
	
	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);
	//后两个参数与上面配置通道1、2时的TIM_ICPolarity_Rising一样,所以上面的可以删掉
	
	TIM_Cmd(TIM3,ENABLE);
}

int16_t Encoder_Get(void){
    
    
	int16_t Temp;
	Temp = TIM_GetCounter(TIM3);//读取CNT
	TIM_SetCounter(TIM3,0);//清零CNT
	return Temp;
	
}
//Timer.c
//在6-1定时器定时中断工程上更改

#include "stm32f10x.h" 
#include "Encoder.h"
extern int16_t Speed;//extern表示跨文件使用变量

void Timer_Init(void){
    
    
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE );
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision= TIM_CKD_DIV1;//1倍时钟分频
	TIM_TimeBaseInitStructure.TIM_CounterMode= TIM_CounterMode_Up;//向上计数模式
	TIM_TimeBaseInitStructure.TIM_Period= 10000-1;//ARR自动重装器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler= 7200-1;//PSC预分频器的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter= 0 ;//重复计数器的值,高级定时器才有,赋0
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//时基单元初始化
	
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel= TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority= 1;
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM2,ENABLE);
}

void TIM2_IRQHandler (void){
    
    
	if (TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){
    
    
		Speed=Encoder_Get();//每隔一秒读取一下速度,存在Speed里
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//最后别忘清除标志位
	}
	
}
//main.c
#include "stm32f10x.h"   // Device header
#include "Delay.h"   
#include "OLED.h"
#include "Timer.h"
#include "Encoder.h"

uint16_t Speed;
int main(void){
    
    
	OLED_Init();
	//Timer_Init();
	Encoder_Init();
	
	OLED_ShowString(1,1,"Speed:");
	
	while(1){
    
    
		OLED_ShowSignedNum(1,7,Speed,5);//可显示正数或负数
		//Delay_ms(1000);
		//因为手转比较慢,闸门时间就给1s。如果电机飞速旋转可给短点,可提高速度刷新频率,且防止计数器溢出
		//Delay实现闸门时间会阻塞程序;可用Timer.c文件的TIM2_IRQHandler ()中断函数实现闸门时间
	}
}

Summary

Hardware and software resources are complementary ! The hardware is not enough for the software to make up, and the software is too tired for the hardware to replace! For example, PWM can directly use a timing interrupt, and then manually count in the interrupt, and manually reverse the level; for example, an external interrupt can be used for input capture, and the CNT can be manually taken out and placed in a variable in the interrupt; for example, the encoder interface in this case It can also be implemented with external interrupts. But this will waste software resources. Generally, when hardware resources are available, hardware resources should be used first, and the saved software resources can be used to do more important things .
insert image description herePrevious highlights:
STM32 timer input capture (IC)
STM32 timer output comparison (PWM wave)
STM32 timing interrupt
STM32 external interrupt
STM32GPIO intensive talk
...

Guess you like

Origin blog.csdn.net/weixin_51658186/article/details/129632478