文章目录
- 旋转编码器介绍
- 主程序逻辑直接检测
- 用外部中断检测下降沿
- 定时器直接解码旋转编码器
旋转编码器介绍
旋转编码器简单来说,就是会输出2个PWM,依据相位可以知道旋转方向,依据脉冲个数可以知道旋转的角度。一般旋转一圈有一个固定数值的脉冲个数。
旋转编码器广泛用于电机、或者角度传感器,STM32的定时器可以直接接入这两个波形获取到信息。
前两个引脚(接地和Vcc)用于为编码器供电,我这里采用3.3V的供电。除了以顺时针方向和逆时针方向旋转旋钮外,编码器还有一个开关(低电平有效),按下内部的旋钮可以按下该开关。来自此开关的信号通过引脚3(Switch)获得。最后它有两个输出引脚。
主程序逻辑直接检测
主程序中不要加延时,否则可能检测不到下降沿。
//旋转编码器
//CLK–PA0
//DT—PA1
//SW—PA2
3.3V供电。
#include "sys.h"
#include "usart.h"
//旋转编码器
//CLK--PA0
//DT---PA1
//SW---PA2
#define CLK_in PAin(0)
#define DT_in PAin(1)
#define SW_in PAin(2)
u32 encoder_cnt = 100000;//旋转脉冲计数
u8 direction = 0;//旋转方向 1正传
u8 dt_high_flag = 0;
void rotary_encoder_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /* 使能时钟 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; /* 设置成上拉输入 */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化PC13
}
int main(void) {
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* 设置NVIC中断分组2:2位抢占优先级,2位响应优先级 */
delay_init(); /* 延时函数初始化 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); /* 关闭jtag,使能SWD,可以用SWD模式调试 */
delay_ms(500); /* 等待稳定 */
uart_init(115200);
rotary_encoder_Init();
while (1) {
if (SW_in == 0) {
delay_ms(10);
if (SW_in == 0) {
printf("SW_in=0\r\n");
while (SW_in == 0);
}
}
//DT_in是下降沿的时候,如果CLK_in是高电平,那么就是正转,如果CLK_in是低电平,那么就是反转
if (DT_in == 1 && dt_high_flag == 0) {
dt_high_flag = 1;
}
if (DT_in == 0 && dt_high_flag == 1) {
dt_high_flag = 0;
if (CLK_in == 1) {
direction = 0;
} else {
direction = 1;
}
if (direction == 1) {
encoder_cnt++;
} else {
encoder_cnt--;
}
printf("direction=%d\r\n", (int) direction);
printf("encoder_cnt=%d\r\n", encoder_cnt);
}
}
}
顺时针转一圈可以得到一些结果,这个旋钮有明显的触感。顺时针转一个刻度就加1,逆时针转一个刻度就减1。
direction=1
encoder_cnt=100001
direction=1
encoder_cnt=100002
direction=1
encoder_cnt=100003
direction=1
encoder_cnt=100004
direction=1
encoder_cnt=100005
direction=1
encoder_cnt=100006
direction=1
encoder_cnt=100007
direction=1
encoder_cnt=100008
direction=1
encoder_cnt=100009
direction=0
encoder_cnt=100008
direction=1
encoder_cnt=100009
direction=1
encoder_cnt=100010
direction=1
encoder_cnt=100011
direction=1
encoder_cnt=100012
direction=1
encoder_cnt=100013
direction=1
encoder_cnt=100014
direction=1
encoder_cnt=100015
direction=1
encoder_cnt=100016
direction=1
encoder_cnt=100017
direction=1
encoder_cnt=100018
direction=1
encoder_cnt=100019
direction=1
encoder_cnt=100020
用外部中断检测下降沿
将DT输入设置为外部中断 ,下降沿触发,明显好用多了。
#include "sys.h"
#include "usart.h"
//旋转编码器
//CLK--PA0
//DT---PA1
//SW---PA2
#define CLK_in PAin(0)
#define DT_in PAin(1)
#define SW_in PAin(2)
u32 encoder_cnt = 100000;//旋转脉冲计数
u8 direction = 0;//旋转方向 1正传
u8 dt_high_flag = 0;
void rotary_encoder_Init(void) {
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); /* 使能时钟 */
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); /* 关闭JTAG功能 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /* 使能时钟 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; /* 设置成上拉输入 */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure);
//将DT_in PAin(1)设置为外部中断,下降沿触发
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);
EXTI_InitStructure.EXTI_Line = EXTI_Line1; /* 外部中断线1 */
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; /* 设置为中断请求 */
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; /* 下降沿触发 */
EXTI_InitStructure.EXTI_LineCmd = ENABLE; /* 使能中断 */
EXTI_Init(&EXTI_InitStructure); /* 配置 */
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; /* 外部中断1 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; /* 抢占优先级2 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; /* 子优先级2 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; /* 使能中断 */
NVIC_Init(&NVIC_InitStructure); /* 配置 */
}
void EXTI1_IRQHandler(void) {
if (CLK_in == 1) {
direction = 0;
} else {
direction = 1;
}
if (direction == 1) {
encoder_cnt++;
} else {
encoder_cnt--;
}
printf("direction=%d\r\n", (int) direction);
printf("encoder_cnt=%d\r\n", encoder_cnt);
EXTI_ClearITPendingBit(EXTI_Line1); /* 清除LINE1上的中断标志位 */
}
int main(void) {
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* 设置NVIC中断分组2:2位抢占优先级,2位响应优先级 */
delay_init(); /* 延时函数初始化 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); /* 关闭jtag,使能SWD,可以用SWD模式调试 */
delay_ms(500); /* 等待稳定 */
uart_init(115200);
rotary_encoder_Init();
while (1) {
if (SW_in == 0) {
delay_ms(10);
if (SW_in == 0) {
printf("SW_in=0\r\n");
while (SW_in == 0);
}
}
}
}
当然需要记得添加库文件: