STM32编码器接口测速,小车类项目你一定用得上!!!
STM32微控制器的编码器接口技术解析 摘要:本文详细介绍了STM32微控制器中的编码器接口技术,主要包含以下内容:1) 编码器接口的基本原理,通过处理正交编码器的A/B两相信号实现位置、方向和速度检测;2) 核心功能包括四倍频技术、方向检测和输入滤波;3) 硬件结构组成,包括GPIO、滤波器和时基单元等模块;4) 具体应用场景如电机控制和机器人技术;5) 完整的初始化步骤和示例代码实现,展示了如
一、学习前提:编码器接口简介

编码器接口是STM32微控制器中用于处理增量式(正交)编码器信号的重要功能。它能够接收来自编码器的A相和B相信号,并根据这些信号自动控制计数器(CNT)的增减,从而确定编码器的位置、旋转方向和旋转速度。每个高级定时器和通用定时器都配备了一个编码器接口,且两个输入引脚通常借用输入捕获的通道1和通道2(即CH1和CH2引脚)。
工作原理
编码器接口的工作原理基于正交信号的特性。正交信号的A相和B相信号之间存在90°的相位差,这种相位差使得可以通过解析A相和B相信号来确定旋转的方向。当编码器旋转时,A相和B相信号的边沿变化会导致定时器计数器(CNT)的值相应增加或减少,从而实现对旋转运动的精确测量。
功能特点
-
四倍频技术:STM32的编码器接口支持四倍频技术,这意味着它能够在每个周期内检测到更多的脉冲,从而提高计数精度。
-
方向检测:通过分析A相和B相信号的相位关系,编码器接口能够自动检测旋转方向,即正转或反转。
-
灵活的软件配置:编码器接口允许通过软件配置来适应不同的编码器类型和应用需求,例如设置编码器模式为2倍频或4倍频,以及选择输入信号的极性和通道。
-
输入滤波:为了减少噪声对信号的影响,编码器接口还支持输入滤波功能,如果一相不变,另一相一直变化,则检测为噪声,不进行反应。
应用场景
编码器接口在需要精确测量和控制旋转运动的场合中非常有用,例如:
-
电机控制:通过编码器接口,可以精确测量电机的转速和位置,实现精确的速度和位置控制。
-
机器人技术:在机器人关节的控制中,编码器接口可以帮助确定关节的精确位置和运动状态。
-
自动化设备:在各种自动化设备中,编码器接口可以用于监控和控制机械部件的旋转运动。
初始化步骤
编码器接口的初始化通常包括以下步骤:
-
开启时钟:开启GPIO和定时器的时钟。
-
配置GPIO:将相关的GPIO引脚配置为输入模式。
-
配置时基单元:设置预分频器、自动重装值等参数。
-
配置输入捕获单元:设置滤波器和极性等参数。
-
配置编码器接口模式:根据需要配置编码器接口的工作模式。
-
启动定时器:最后,启动定时器并进行必要的软件设计,如设置定时器的中断优先级和开启中断。
通过合理配置和编程,STM32微控制器的编码器接口可以显著提升各种应用的性能和可靠性,实现对旋转运动的精确控制和测量。
二、正交编码器接口实现简介
正交编码器接口是一种用于处理正交编码信号的接口技术。正交编码信号由两个相位差为90度的脉冲信号组成,通常称为A相和B相。通过对A相和B相信号的边缘检测和比较,可以确定旋转方向和计算旋转脉冲数,从而实现对旋转角度和速度的精确测量。

图中展示了正交编码器在正转和反转情况下的信号波形。图中的波形清晰地显示了A相和B相信号的相位关系,以及它们如何通过边沿变化来指示旋转方向。
正转情况:
-
在正转时,A相的上升沿通常先于B相的上升沿出现,这意味着当A相信号从低电平变为高电平时,B相信号仍然是低电平。随后,B相信号上升,当B相信号从低电平变为高电平时,A相信号已经处于高电平状态。
反转情况:
-
在反转时,B相的上升沿先于A相的上升沿出现,这与正转的情况相反。即当B相信号从低电平变为高电平时,A相信号仍然是低电平。随后,A相信号上升,当A相信号从低电平变为高电平时,B相信号已经处于高电平状态。
这种相位关系使得可以通过检测A相和B相信号的边沿变化来确定旋转的方向。
三、旋转编码器基本结构

编码器接口的基本结构,它主要由以下几个部分组成:
-
GPIO(通用输入输出端口):
-
图中显示了两个GPIO端口,每个端口都连接到一个滤波器。
-
GPIO端口用于接收来自编码器的A相和B相信号。
-
-
滤波器:
-
每个GPIO端口后都有一个滤波器,用于滤除输入信号中的噪声,以确保信号的稳定性和准确性。
-
滤波器有助于提高信号的质量,减少由于电磁干扰或其他噪声源引起的误触发。
-
-
边沿检测极性选择:
-
滤波器后的信号会经过边沿检测极性选择电路,用于确定信号的边沿类型(上升沿或下降沿)。
-
这个选择电路可以根据应用需求来设置,以适应不同的编码器信号特性。
-
-
编码器接口:
-
编码器接口是整个结构的核心部分,它接收经过处理的A相和B相信号。
-
编码器接口负责解析这些信号,并根据信号的变化来控制计数器的增减。
-
-
时基单元:
-
时基单元包括预分频器(PSC)和计数器(CNT)。
-
预分频器用于调整计数器的计数频率,以匹配编码器的信号频率。
-
计数器用于记录编码器的脉冲数,从而确定旋转的角度和速度。
-
-
ARR(自动重装载器):
-
ARR用于设置计数器的最大值,当计数器达到这个值时,会自动重置为0,重新开始计数。
-
这个功能可以用于实现周期性测量,或者在达到某个计数值时触发特定的操作。
-
四、可实现功能
-
信号接收:
接口通过GPIO端口接收来自编码器的A相和B相信号。 -
信号处理:
滤波器用于去除信号中的噪声,保证信号清晰。边沿检测极性选择电路识别信号的上升沿或下降沿,确定编码器的旋转方向。 -
计数与测量:
编码器接口解析信号,控制内部计数器(CNT)根据信号变化进行计数。计数器记录脉冲数,用于计算编码器的旋转角度和速度。 -
周期性测量:
自动重装载器(ARR)设定计数器的最大值,实现周期性计数和测量。 -
方向检测:
通过分析A相和B相信号的相位关系,接口能够自动检测编码器的旋转方向
五、现象和代码
最终实现顺时针旋转为正速度,逆时针旋转为负速度。

代码:encorder.c
#include "stm32f10x.h" // Device header
int16_t Encoder_Count; // 定义一个全局变量,用于存储编码器的计数值
// 编码器初始化函数
void Encoder_Init(void)
{
// 使能GPIOB和AFIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
// 配置GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; // 设置为输入上拉模式
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1; // 配置PB0和PB1引脚
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; // 设置速度为50MHz
GPIO_Init(GPIOB,&GPIO_InitStructure);
// 配置AFIO,用于引脚重映射
// 配置GPIOB的14引脚为外设中断线路。
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);
// 配置EXTI(外部中断/事件控制器)
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line=EXTI_Line0|EXTI_Line1; // 配置PB0和PB1的外部中断线路
EXTI_InitStructure.EXTI_LineCmd=ENABLE; // 使能中断线路
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; // 设置为中断模式
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; // 设置触发方式为下降沿触发
EXTI_Init(&EXTI_InitStructure);
// 配置NVIC(嵌套向量中断控制器)
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn; // EXTI0中断通道
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; // 使能中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1; // 设置抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1; // 设置子优先级为1
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设置中断优先级分组
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel=EXTI1_IRQn; // EXTI1中断通道
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; // 使能中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1; // 设置抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority=2; // 设置子优先级为2
NVIC_Init(&NVIC_InitStructure);
}
// 获取编码器计数值的函数
int16_t Encoder_Get(void)
{
int16_t Temp;
Temp=Encoder_Count; // 读取计数值
Encoder_Count=0; // 清零计数值
return Temp; // 返回计数值
}
// EXTI0中断处理函数
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0)==SET) // 检查中断标志位
{
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0) // 读取PB1引脚的状态
{
Encoder_Count--; // 如果PB1为低电平,则计数器减1
}
EXTI_ClearITPendingBit(EXTI_Line0); // 清除中断标志位
}
}
// EXTI1中断处理函数
void EXTI1_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line1)==SET) // 检查中断标志位
{
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==0) // 读取PB0引脚的状态
{
Encoder_Count++; // 如果PB0为低电平,则计数器加1
}
EXTI_ClearITPendingBit(EXTI_Line1); // 清除中断标志位
}
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.H"
#include "ENCODER.H"
int16_t Num;
int main()
{
OLED_Init();
Encoder_Init();
OLED_ShowString(1,3,"chenxi");
while(1)
{
Num+=Encoder_Get();
OLED_ShowSignedNum(2,1,Num,5);//显示速度
}
}
更多推荐



所有评论(0)