一、简介
旋转编码器:用来测量位置、速度或旋转方向的装置,当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度和方向
类型:机械触点式/霍尔传感器式/光栅式
本篇采用的是机械触点式的旋转编码器


二、硬件电路图

图中的左边,接了一个上拉电压,当旋转编码器没有旋转时,A端口是高电平,当旋转编码器旋转时电路与接地连通,A端口输出低电平。

这个旋转编码器就是利用A、B的相位差,来判断它的旋转方向。
三、调用库函数
调用的函数
GPIO.h
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
Line:线、线路;Config(Configuration):配置;Source:源、来源
将指定的 GPIO 引脚,映射到 STM32 的外部中断控制器(EXTI)的对应中断线(Line)上。
exti.h
DeInit(De-Initialize):反初始化 / 复位初始化;Generate:生成;SW:Software,软件;Interrupt:中断;Flag:标志位;Pending:挂起的;
EXTI 反初始化
void EXTI_DeInit(void);//所有 EXTI 中断线的配置恢复为芯片复位默认状态
EXTI 核心初始化
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);//结构体中的配置写入 EXTI 寄存器
EXTI 结构体初始化
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);//将EXTI_InitTypeDef结构体的所有成员赋上标准库默认值
软件触发 EXTI 中断
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);通过代码手动触发指定 EXTI 中断线
获取 EXTI 中断状态【中断服务函数首选】
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
清除 EXTI 中断挂起位【中断服务函数必用】
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
misc.h
Priority:优先级;Group:分组;Vector:向量;
NVIC 优先级分组配置函数
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
NVIC 初始化函数
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
代码:
打开GPIOB和AFIO的时钟,选择B0,B1GPIO口,配置为上拉输入模式。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
AFIO选择线路,必须一个一个的选择。
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);
配置EXTI
选择EXTI_Line0 和 EXTI_Line1通道并使能ENABLE,配置成中断模式EXTI_Mode_Interrupt,下降沿触发EXTI_Trigger_Falling。
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStructure);
配置NVIC
选择优先级分组2,即2 位抢占优先级 + 2 位响应优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
配置 EXTI0_IRQn(对应 PB0 编码器引脚)
因为目前只有这一个中断,所以占优先级Priority和响应优先级SubPriority配置为1即可。
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
配置 EXTI1_IRQn(对应 PB1 编码器引脚)
仅修改中断通道,响应优先级配置为2,复用其他参数,
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_InitStructure);
执行逻辑
定义一个全局变量用来计数
int16_t Encoder_Count;
逆时针旋转
A先输出低电平,B后输出低电平,所以通道EXTI_Line0先触发中断,然后等待B输出电平,读取到B1口的低电平就执行 Encoder_Count --,执行完要将中断复位。
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0) == SET)
{
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
Encoder_Count --;
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
顺时针旋转
与逆时针旋转相反。
void EXTI1_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line1) == SET)
{
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
{
Encoder_Count ++;
}
EXTI_ClearITPendingBit(EXTI_Line1);
}
}
返回计数
逆时针就返回-1,顺时针就返回1;
int16_t Encoder_Get(void)
{
int16_t Temp;
Temp = Encoder_Count;
Encoder_Count = 0;
return Temp;
}
声明
中断函数不用声明,达到中断条件,硬件会自动执行。

在main中调用相关函数

中断函数在md.s文件中

STM32F1 系列单片机的中断通道(IRQn)编号映射表在stm32f10x.h。
