专栏名称: CW32生态社区
以开放、共享、互助为理念,致力于构建武汉芯源半导体CW32系列MCU生态社区。无论是嵌入式MCU小白还是想要攻破技术难题的工程师,亦或是需求解决方案的产品经理,都可在CW32生态社区汲取营养、共同成长。
目录
相关文章推荐
51好读  ›  专栏  ›  CW32生态社区

【CW32模块使用】EC11旋转编码器

CW32生态社区  · 公众号  · 科技创业 科技自媒体  · 2024-08-28 15:19

主要观点总结

本文介绍了旋转编码器的功能及其在工程中的移植过程。

关键观点总结

关键观点1: 旋转编码器介绍

旋转编码器是一种将旋转位移转换为一连串数字脉冲信号的旋转式传感器,用于控制角位移。

关键观点2: 模块来源

提供了模块实物展示和资料下载链接。

关键观点3: 规格参数

介绍了模块的厂家资料下载、工作电压、工作电流、模块尺寸、旋转角度和通信协议等规格参数。

关键观点4: 移植过程

描述了移植旋转编码器到立创·CW32F030C8T6开发板的过程,包括查看资料、引脚选择、移植至工程等方面。

关键观点5: 关键函数

介绍了关键的函数,如Encoder_GPIO_Init(旋转编码器初始化)、Encoder_Sw_Down(判断编码器是否被按下)、Encoder_Rotation_left和Encoder_Rotation_right(左转和右转服务函数)等。

关键观点6: 移植验证

在main主函数中编写代码进行移植验证,包括开发板初始化、串口初始化、编码器初始化等。


正文

请到「今天看啥」查看全文


旋转编码器是一种将旋转位移转换为一连串数字脉冲信号的旋转式传感器。这些脉冲用来控制角位移。读数系统通常采用差分方式,即将两个波形一样但相位差为180°的不同信号进行比较,以便提高输出信号的质量和稳定性。读数是在两个信号的差别基础上形成的,从而消除了干扰。
0 1
模块来源

>>>

模块实物展示



资料下载链接:

https://pan.baidu.com/s/18pp1KaT2V_llizWvdIXtKA?pwd=8889

资料提取码:8889


2
规格参数

>>>

模块的 厂家资料下载请查看百度网盘链接

工作电压:5V

工作电流:1MA

模块尺寸:18 x 25 mm

旋转角度: 360度

通信协议:相位差

管脚数量:5 Pin(2.54mm间距排针)

0 3
移植过程

>>>

我们的目标是在立创·CW32F030C8T6开发板上能够判断旋转方向、旋转次数和是否按下的功能。首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。

3. 1
查看资料

旋转编码器是通过两个引脚的相位差,实现的旋转方向判断(以后的CLK引脚统一称呼为A相,DT引脚为B相)

当是顺时针旋转时,A相超前B相90度,即A相为下降沿时,B相为低电平;A相为上升沿时,B相为高电平。

当是逆时针旋转时,B相超前A相90度,即A相为下降沿时,B相为高电平;A相为上升沿时,B相为低电平。

而EC11按旋转的输出动作可以分为两种。

一种是转两格,A、B端输出一个完整脉冲(转一格就只是由低电平->高电平或由高电平->低电平);

一种就是转一格,A、B对C端输出一个完整脉冲。


转一格半个脉冲


转一格完整脉冲

因此我们只需检测A相或者B相有发生高低电平跳变时,就判断另一相状态,来决定旋转方向。根据以下真值表,可以发现:

  • 当两相同时为上升沿或者同时为下降沿时,则为顺时针;

  • 当两相不同时为上升沿或者不同时为下降沿时,则为逆时针;

下B相 \ 右A相 上升沿 下降沿
上升沿 顺时针 逆时针
下降沿 逆时针 顺时针
旋转编码器是机械结构的,是机械结构就避免不了在旋转或者按下时有抖动,这里采用定时器每隔10ms扫描一次编码器是否有动作,实现10ms内的消抖。

在中断服务函数中,根据真值表确定旋转的方向。

3. 2
引脚选择

该模块有5个引脚,具体引脚连接见 表 各引脚连接。

3. 3
移植至工程

打开自己的工程。(这里工程参考见入门手册工程模板)

移植步骤中的导入.c和.h文件与第二章的第1小节【DHT11温湿度传感器】相同,只是将.c和.h文件更改为ec11.c与ec11.h。这里不再过多讲述,移植完成后面修改相关代码。

在文件ec11.c中,编写如下代码。

/*




    
 * Change Logs: * Date           Author       Notes * 2024-06-19     LCKFB-LP    first version */
#include "ec11.h"#include "stdio.h"

/****************************************************************** * 函 数 名 称:Encoder_GPIO_Init * 函 数 说 明:旋转编码器引脚初始化 * 函 数 形 参:无 * 函 数 返 回:无 * 作 者:LC * 备 注:使用定时器每10Ms扫描一次是否有旋转,即通过定时器进行消抖******************************************************************/void Encoder_GPIO_Init(void){ GPIO_InitTypeDef GPIO_InitStruct; // GPIO初始化结构体 BTIM_TimeBaseInitTypeDef BTIM_TimeBaseInitStruct; // 定时器初始化结构体
RCC_GPIO_ENABLE(); // 使能GPIO时钟 BTIM_RCC_ENABLE(); // 使能BTIM时钟
// 禁止中断,以安全地配置NVIC __disable_irq();
// 开启BTIM1中断,并关联到NVIC NVIC_EnableIRQ(BSP_TIMER_IRQ);
// 允许中断,恢复中断状态 __enable_irq();
GPIO_InitStruct.Pins = GPIO_ENCODER_SW| // GPIO引脚 GPIO_ENCODER_LCK| GPIO_ENCODER_DT; GPIO_InitStruct.Mode = GPIO_MODE_INPUT_PULLUP; // 上拉输入 GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; // 输出速度高 GPIO_Init(PORT_GPIO, &GPIO_InitStruct); // 初始化

// 配置定时器模式、周期和预分频器 BTIM_TimeBaseInitStruct.BTIM_Mode = BTIM_Mode_TIMER; // 设置为定时器模式 BTIM_TimeBaseInitStruct.BTIM_Period = 625 - 1; // 设置周期,使得定时器每10ms产生一次溢出中断 BTIM_TimeBaseInitStruct.BTIM_Prescaler = BTIM_PRS_DIV1024; // 预分频器设置为1024,以降低时钟频
// 使用上述配置初始化定时器BTIM1 BTIM_TimeBaseInit(BSP_TIMER, &BTIM_TimeBaseInitStruct);
// 使能BTIM1的溢出中断 BTIM_ITConfig(BSP_TIMER, BTIM_IT_OV, ENABLE);
// 启动定时器BTIM1 BTIM_Cmd(BSP_TIMER, ENABLE);}

/****************************************************************** * 函 数 名 称:Encoder_Scanf * 函 数 说 明:判断旋转编码器是否有往哪一个方向旋转 * 函 数 形 参:无 * 函 数 返 回:1=正转 2=反转 * 作 者:LC * 备 注:哪一边正转哪一边反转不需要太在意,你说的算******************************************************************/char Encoder_Scanf(void){ static GPIO_PinState EC11_CLK_Last= GPIO_Pin_RESET; //EC11的LCK引脚上一次的状态(A相) static GPIO_PinState EC11_DT_Last = GPIO_Pin_RESET; //EC11的DT引脚上一次的状态(B相) char ScanResult = 0; //当A发生跳变时采集B当前的状态,并将B与上一次的状态进行对比。 if(GET_CLK_STATE !=EC11_CLK_Last) { //若A 0->1 时,B 1->0 正转;若A 1->0 时,B 0->1 正转; //若A 0->1 时,B 0->1 反转;若A 1->0 时,B 1->0 反转 if(GET_CLK_STATE == 1) //EC11_A和上一次状态相比,为上升沿 { //EC11_B和上一次状态相比,为下降沿 if((EC11_DT_Last == 1)&&(GET_DT_STATE == 0)) ScanResult = 1; //正转 //EC11_B和上一次状态相比,为上升沿 if((EC11_DT_Last == 0)&&(GET_DT_STATE == 1)) ScanResult = 2; //反转
//>>>>>>>>>>>>>>>>下面为正转一次再反转或反转一次再正转处理<<<<<<<<<<<<<< //A上升沿时,采集的B不变且为0 if((EC11_DT_Last == GET_DT_STATE)&&(GET_DT_STATE == 0)) ScanResult = 1; //正转 //A上升沿时,采集的B不变且为1 if((EC11_DT_Last == GET_DT_STATE)&&(GET_DT_STATE == 1)) ScanResult = 2; //反转 } else //EC11_A和上一次状态相比,为下降沿 { //EC11_B和上一次状态相比,为下降沿 if((EC11_DT_Last == 1)&&(GET_DT_STATE == 0)) ScanResult = 2; //反转 //EC11_B和上一次状态相比,为上升沿 if((EC11_DT_Last == 0)&&(GET_DT_STATE == 1)) ScanResult = 1; //正转
//>>>>>>>>>>>>>>>>下面为正转一次再反转或反转一次再正转处理<<<<<<<<<<<<<< //A上升沿时,采集的B不变且为0 if((EC11_DT_Last == GET_DT_STATE)&&(GET_DT_STATE == 0)) ScanResult = 2; //反转 //A上升沿时,采集的B不变且为1 if((EC11_DT_Last == GET_DT_STATE)&&(GET_DT_STATE == 1)) ScanResult = 1; //正转 } EC11_CLK_Last = GET_CLK_STATE; //更新编码器上一个状态暂存变量 EC11_DT_Last = GET_DT_STATE; //更新编码器上一个状态暂存变量 return ScanResult; //返回值的取值: 0:无动作; 1:正转; 2:反转; } return 0;}


/****************************************************************** * 函 数 名 称:Encoder_Sw_Down * 函 数 说 明:判断编码器是否被按下 * 函 数 形 参:无 * 函 数 返 回:0=没有被按下 1=被按下 * 作 者:LC * 备 注:请注意消抖******************************************************************/unsigned char Encoder_Sw_Down(void){ //没有按下 if( GET_SW_STATE == GPIO_Pin_SET ) { delay_ms(100);//消抖 return 0; } else//按下 { delay_ms(100);//消抖 // printf("down\r\n"); return 1; }}
/****************************************************************** * 函 数 名 称:Encoder_Rotation_left * 函 数 说 明:左旋转服务函数。当编码器左转时,需要执行的操作 * 函 数 形 参:无 * 函 数 返 回:向左旋转次数 * 作 者:LC * 备 注:无******************************************************************/int Encoder_Rotation_left(void){ static int left_num = 0;//左转次数 left_num++; /* 你的代码写在此处 */ printf("left num = %d\r\n",left_num);
/* 你的代码写在此处 */ return left_num;}
/****************************************************************** * 函 数 名 称:Encoder_Rotation_left * 函 数 说 明:右旋转服务函数。当编码器右转时,需要执行的操作 * 函 数 形 参:无 * 函 数 返 回:向右旋转次数 * 作 者:LC * 备 注:无******************************************************************/int Encoder_Rotation_right(void){ static int right_num = 0;//右转次数 right_num++; /* 你的代码写在此处 */
printf("right num = %d\r\n",right_num); /* 你的代码写在此处 */
return right_num;}

/************************************************函数名称 : BSP_TIMER_IRQHandler功 能 : 基本定时器中断服务函数参 数 : 无返 回 值 : 无作 者 : LC*************************************************/void BSP_TIMER_IRQHANDLER(void){ static char dat = 0; if(BTIM_GetITStatus(BSP_TIMER, BTIM_IT_OV) == SET) { dat = Encoder_Scanf();//扫描编码器是否扭动 if( dat != 0 )//如果有转动 { if( dat == 2 ) { Encoder_Rotation_left(); } else { Encoder_Rotation_right(); }
} } BTIM_ClearITPendingBit(BSP_TIMER, BTIM_IT_OV);}


在文件ec11.h中,编写如下代码。

/* * Change Logs: * Date           Author       Notes * 2024-06-19     LCKFB-LP    first version */#ifndef _BSP_ENCODER_H_#define _BSP_ENCODER_H_
#include "board.h"
#define RCC_GPIO_ENABLE() __RCC_GPIOA_CLK_ENABLE()
#define PORT_GPIO CW_GPIOA
//SW引脚#define GPIO_ENCODER_SW GPIO_PIN_7
//CLK引脚#define GPIO_ENCODER_LCK GPIO_PIN_6
//DT引脚#define GPIO_ENCODER_DT GPIO_PIN_4
//获取CLK引脚的状态#define GET_CLK_STATE GPIO_ReadPin(PORT_GPIO, GPIO_ENCODER_LCK)//获取DT引脚的状态#define GET_DT_STATE GPIO_ReadPin(PORT_GPIO, GPIO_ENCODER_DT)//获取SW引脚的状态#define GET_SW_STATE GPIO_ReadPin(PORT_GPIO, GPIO_ENCODER_SW)
//定时器扫描#define BTIM_RCC_ENABLE() __RCC_BTIM_CLK_ENABLE() // 使能定时器时钟#define BSP_TIMER CW_BTIM1 // 定时器#define BSP_TIMER_IRQ BTIM1_IRQn // 定时器中断#define BSP_TIMER_IRQHANDLER BTIM1_IRQHandler // 定时器中断服务函数

void Encoder_GPIO_Init(void);//旋转编码器初始化unsigned char Encoder_Sw_Down(void);//编码器是否按下int Encoder_Rotation_left(void);//左转服务函数int Encoder_Rotation_right(void);//右转服务函数

#endif


0 4
移植验证

>>>

在自己工程中的main主函数中,编写如下。

/* * Change Logs: * Date           Author       Notes * 2024-06-19     LCKFB-LP    first version */#include "board.h"#include "stdio.h"#include "bsp_uart.h"#include "ec11.h"
int32_t main(void){ board_init(); // 开发板初始化
uart1_init(115200); // 串口1波特率115200
Encoder_GPIO_Init(); printf("encoder demo start\r\n"); while(1) { if( Encoder_Sw_Down() == 1 )//旋转编码器被按下 { printf("Encoder down\r\n"); } }}

移植现象:向右旋转10次,向左旋转10次,按下一次。

模块移植成功案例代码:

链接: https://pan.baidu.com/s/18_4-IfR_pzyy1QvyQE7XkQ?pwd=LCKF

提取码:LCKF


END

往期回顾

REVIEW

【产品应用】CW32电动工具产品开源

【产品应用】基于CW32的智能充电宝(方案开源)

【产品应用】CW-W88水泵通用控制板设计方案(已开源)

【产品应用】基于CW32的角磨机控制器产品方案

【产品方案】基于CW32F030C8的低压无刷风机无感控制器

【产品方案】基于CW32的无刷直流空心杯电机有感控制驱动方案

【产品方案】基于CW32的无刷直流空心杯电机无感方波控制驱动方案

从0到1,开启产品级智能硬件设计之路!

CW32生态社区(WX)群




扫码加入QQ群

3群| 610403240

获取资料及 “开发者扶持计划” 第一手资讯









请到「今天看啥」查看全文