TIM编码器接口函数及应用
TIM编码器接口函数及应用
文章目录
- TIM编码器接口函数及应用
- 1.编码器接口简介
- 2.正交编码器
- 2.2工作模式
- 2.3实例1(均不反相)
- 3.编码器接口框图
- 3.1以通用计时器为例
- 3.2编码器接口基本结构
- 3.2.1实现步骤
- 4.用到的库函数
- 5.编码器接口测速(实操)
- 5.1接线图
- 5.2代码编写
- 5.2.1主函数main.c
- 5.2.2函数定义Encoder.c
- 5.2.3函数声明Encoder.h
1.编码器接口简介
手册14.3.12编码器接口模式有相关介绍
- Encoder Interface 编码器接口
- 编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度
- 每个高级定时器和通用定时器都拥有1个编码器接口
- 两个输入引脚借用了输入捕获的通道1(CH1)和通道2(CH2)
2.正交编码器
正交编码器一般可以测量位置,或者带有方向的速度值
一般有A相和B相两个,分别为超前和滞后90°的关系(图中正转为A相超前B相90°,反转是B相滞后A相90°)
可以根据边沿状态和另一相状态来确定正转还是反转
2.2工作模式
总结:正转的方向都是向上计数,反转的方向都是向下计数
2.3实例1(均不反相)
3.编码器接口框图
3.1以通用计时器为例
3.2编码器接口基本结构
3.2.1实现步骤
- RCC开启时钟,开启GPIO和定时器的时钟
- 配置GPIO,这里把PA6和PA7配置成输入模式
- 配置时基单元
- 配置输入捕获单元,这里的输入捕获单元只有滤波器和极性两个参数有用
- 配置编码器接口模式
- 最后,调用TIM_Cmd,启动定时器
4.用到的库函数
void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode,
uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity);
void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode,uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity);定时器编码器接口配置,第一个参数选择定时器,第二个参数选择编码器模式,第三个参数选择通道1编码器的极性,第四个参数选择通道2编码器的极性
5.编码器接口测速(实操)
5.1接线图
5.2代码编写
5.2.1主函数main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "KEY.h"
#include "OLED.h"
//#include "OLED_Font.h"
#include "Timer.h"
#include "Encoder.h"
int16_t Speed;
int main(void){
OLED_Init();
Timer_Init();
Encoder_Init();
OLED_ShowString(1,1,"Speed:");
while(1){
//CNT = Encoder_GetCounter();
OLED_ShowSignedNum(1,7,Speed,5);
//获取CNT的值,每秒获取一次
//Delay_ms(1000);
}
}
void TIM2_IRQHandler(void){
if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET){
Speed = Encoder_GetCounter();
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
配置中断函数
//void TIM2_IRQHandler(void){
// if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET){
// num++;
//
// //清除标志位
// TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
// }
//}
5.2.2函数定义Encoder.c
#include "stm32f10x.h" // Device header
void Encoder_Init(void){
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
//开启GPIO通道
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_Structure;
GPIO_Structure.GPIO_Mode = GPIO_Mode_IPU;//如果外部模块默认输出高电平,就配置上拉输入,默认输入高电平
//如果外部模块默认输出低电平,就配置下拉输入,默认输入低电平
//不确定外部状态或者输出功率特别小,就选择浮空输入(没有上拉输入和下拉输入去影响外部信号,缺点是悬空的时候就没有默认电平了)
GPIO_Structure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_Structure);
//选择时钟源去掉,因为编码器接口就是一个带方向控制的外部时钟
//TIM_InternalClockConfig(TIM2);
//配置时基单元
TIM_TimeBaseInitTypeDef TIM_Structure;
TIM_Structure.TIM_ClockDivision = TIM_CKD_DIV1;
//TIM_Structure.TIM_CounterMode = TIM_CounterMode_Up;编码器接口托管
TIM_Structure.TIM_Period = 65535 - 1; //ARR
TIM_Structure.TIM_Prescaler = 1 - 1; //PSC
TIM_Structure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3,&TIM_Structure);
//初始化输入捕获单元
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter = 0xF;
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;//上升沿并不代表上升沿有效,因为编码器接口都是上升沿和下降沿都有效的,这里的上升沿表示高低电平极性不反转
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;
TIM_ICInitStruct.TIM_ICFilter = 0xF;
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;//上升沿并不代表上升沿有效,因为编码器接口都是上升沿和下降沿都有效的,这里的上升沿表示高低电平极性不反转
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);//第二个是哪个相计数,这里的配置会覆盖前面的,所以前面的可以去掉
TIM_Cmd(TIM3,ENABLE);
}
int16_t Encoder_GetCounter(){
int16_t temp;
temp = TIM_GetCounter(TIM3);
//读取后清零
TIM_SetCounter(TIM3,0);
return temp;
}
5.2.3函数声明Encoder.h
#ifndef __ENCODER_H
#define __ENCODER_H
void Encoder_Init(void);
int16_t Encoder_GetCounter(void);
#endif