一、标准库
Encoder.c-标准库
#include "stm32f10x.h" // Device header
#include "Delay.h"
int8_t Encoder_Count;
/**
* 函 数:旋转编码器初始化
* 参 数:无
* 返 回 值:无
*/
void Encoder_Init(void)
{
/* 开启时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //开启GPIOB的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //开启外部中断所必须的AFIO时钟
/* 初始化GPIOB */
GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO初始化结构体
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //GPIO模式为上拉输入模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* AFIO选择中断引脚 */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14); //选择GPIOB引脚14
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource15); //选择GPIOB引脚15
/* 初始化外部中断EXTI */
EXTI_InitTypeDef EXTI_InitStructure; //定义EXTI初始化结构体
EXTI_InitStructure.EXTI_Line = EXTI_Line14 | EXTI_Line15; //选择配置外部中断的14、15号线
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_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* 初始化嵌套中断控制器NVIC */
NVIC_InitTypeDef NVIC_InitStructure; //定义NVIC初始化结构体
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //由于配置了外部中断14、15号线,通道选择10~15号通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //开启使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
}
/**
* 函 数:旋转编码器获取增量值
* 参 数:无
* 返 回 值:自上此调用此函数后,旋转编码器的增量值
*/
int8_t Encoder_Get(void)
{
int8_t Temp;
Temp = Encoder_Count;
Encoder_Count = 0;
return Temp;
}
/**
* 函 数:EXTI15_10外部中断函数
* 参 数:无
* 返 回 值:无
* 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
* 函数名为预留的指定名称,可以从启动文件"startup_stm32f10x_md.s"复制
* 请确保函数名正确,不能有任何差异,否则中断函数将不能进入
* 旋转编码器无消抖处理
*/
void EXTI15_10_IRQHandler(void)
{
/* 14号线路触发中断 */
if(EXTI_GetITStatus(EXTI_Line14) == SET)
{
//检测另一个引脚电平,确定编码器转向
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)==0)
{
Delay_ms(20);
Encoder_Count--;
}
EXTI_ClearITPendingBit(EXTI_Line14); //必须清除中断标志位
}
/* 15号线路触发中断 */
else if(EXTI_GetITStatus(EXTI_Line15) == SET)
{
//检测另一个引脚电平,确定编码器转向
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)==0)
{
Delay_ms(20);
Encoder_Count++;
}
EXTI_ClearITPendingBit(EXTI_Line15); //必须清除中断标志位
}
}
Encoder.h-标准库
#ifndef __ENCODER_H
#define __ENCODER_H
void Encoder_Init(void);
int8_t Encoder_Get(void);
#endif
二、HAL库
Encoder.c-HAL库
#include "main.h" // Device header
#include "Encoder.h"
int8_t Encoder_Count;
/**
* 函 数:旋转编码器初始化
* 参 数:无
* 返 回 值:无
*/
void Encoder_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = GPIO_A_EXIT4_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIO_A_EXIT4_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = GPIO_B_EXIT5_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIO_B_EXIT5_GPIO_Port, &GPIO_InitStruct);
}
/**
* 函 数:旋转编码器获取增量值
* 参 数:无
* 返 回 值:自上此调用此函数后,旋转编码器的增量值
*/
int8_t Encoder_Get(void)
{
int8_t Temp;
Temp = Encoder_Count;
Encoder_Count = 0;
return Temp;
}
/**
* 函 数:EXTI15_10外部中断函数
* 参 数:无
* 返 回 值:无
* 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
* 函数名为预留的指定名称,可以从启动文件"startup_stm32f10x_md.s"复制
* 请确保函数名正确,不能有任何差异,否则中断函数将不能进入
* 旋转编码器无消抖处理
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_B_EXIT5_Pin)
{
if(HAL_GPIO_ReadPin(GPIO_A_EXIT4_GPIO_Port,GPIO_A_EXIT4_Pin) == GPIO_PIN_SET)
{
HAL_Delay(5);
Encoder_Count--;
HAL_Delay(10);
}
}
if(GPIO_Pin == GPIO_A_EXIT4_Pin)
{
if(HAL_GPIO_ReadPin(GPIO_B_EXIT5_GPIO_Port,GPIO_B_EXIT5_Pin) == GPIO_PIN_SET)
{
HAL_Delay(5);
Encoder_Count++;
HAL_Delay(10);
}
}
}
Encoder.h-HAL库
#ifndef __ENCODER_H
#define __ENCODER_H
void Encoder_Init(void);
int8_t Encoder_Get(void);
#endif
三、README
注意有一些旋转编码器没有z轴开关功能
注意使用旋转编码器时,用delay消抖时,注意tick时钟的优先级要比中断引脚的优先级高
https://blog.csdn.net/qq_64931749/article/details/138274582?fromshare=blogdetail&sharetype=blogdetail&sharerId=138274582&sharerefer=PC&sharesource=weixin_73690807&sharefrom=from_link
注意:
例子
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == KEY0_Pin) //按键按下
{
HAL_Delay(20);
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET)
{
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
}
}
}
HAL_Delay函数本质也是打断程序去执行延时操作,那么,就一定要让系统滴答定时器抢占优先级高于外部中断的抢占优先级(数字越小级别越高),下面是配置优先级步骤:
先修改为抢占优先级与响应优先级各用2位配置(可以不改)
默认系统滴答定时器是最低,我们要把它改为1,然后外部中断比它低一个等级------2即可