GD32F470_EC11旋转编码器模块移植

2.2 EC11旋转编码器
旋转编码器是一种将旋转位移转换为一连串数字脉冲信号的旋转式传感器。这些脉冲用来控制角位移。读数系统通常采用差分方式,即将两个波形一样但相位差为180°的不同信号进行比较,以便提高输出信号的质量和稳定性。读数是在两个信号的差别基础上形成的,从而消除了干扰。
2.2.1 模块来源
采购链接:旋转编码器模块,工作的电压5V
资料下载链接:
https://pan.baidu.com/s/18pp1KaT2V_llizWvdIXtKA?pwd=8889
资料提取码:8889
2.2.2 规格参数
工作电压:5V
工作电流:1MA
模块尺寸:18 x 25 mm
旋转角度: 360度
通信协议:相位差
管脚数量:5 Pin(2.54mm间距排针)
工作电流:1MA
模块尺寸:18 x 25 mm
旋转角度: 360度
通信协议:相位差
管脚数量:5 Pin(2.54mm间距排针)
2.2.3 移植过程
我们的目标是在梁山派GD32F470上能够判断旋转方向、旋转次数和是否按下的功能。首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。
2.2.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内的消抖。
在这里插入图片描述

在这里插入图片描述
在中断服务函数中,根据真值表确定旋转的方向。
在这里插入图片描述

2.2.3.2 引脚选择
该模块有5个引脚,具体引脚连接见 表2.2.3.2 各引脚连接。
在这里插入图片描述

旋转编码器立创·梁山派
GNDGND
+5V
SWPA7
DTPA4
CLKPA6

2.2.3.3 移植至工程
打开自己的工程。(这里工程参考见文件2.2.3.3-1)
文件2.2.3.3-1
在这里插入图片描述
新建两个文件。
在这里插入图片描述
点击生成的文件,分别保存并命名为bsp_encoder.c 与 bsp_encoder.h。
在这里插入图片描述
在这里插入图片描述
将bsp_encoder.c 添加至工程目录。
在这里插入图片描述
添加完成之后,则会看到新添的文件。
在这里插入图片描述
添加bsp_encoder.h路径至工程。
在这里插入图片描述
添加路径完成后,会显示出来。
在这里插入图片描述
完成之后全部点击OK,退出配置。编译工程,可以看到在软件界面的左边,会显示我们新增的文件。
在这里插入图片描述
在文件bsp_encoder.c中,编写如下代码。

/********************************************************************************* 文 件 名: bsp_encoder.c* 版 本 号: 初版* 修改作者: LC* 修改日期: 2023年04月06日* 功能介绍:          ******************************************************************************* 注意事项:
*********************************************************************************/#include "bsp_encoder.h"
#include "systick.h"
#include "bsp_usart.h"
#include "stdio.h"/******************************************************************* 函 数 名 称:Encoder_GPIO_Init* 函 数 说 明:旋转编码器引脚初始化* 函 数 形 参:无* 函 数 返 回:无* 作       者:LC* 备       注:使用定时器每10Ms扫描一次是否有旋转,即通过定时器进行消抖
******************************************************************/
void Encoder_GPIO_Init(void)
{timer_parameter_struct timere_initpara;     // 定义定时器结构体rcu_periph_clock_enable(RCU_ENCODER_LCK);   // 开启CLK引脚时钟rcu_periph_clock_enable(RCU_ENCODER_DT);    // 开启DT引脚时钟rcu_periph_clock_enable(RCU_ENCODER_SW);    // 开启SW引脚时钟    rcu_periph_clock_enable(BSP_TIMER_RCU);     // 开启定时器时钟  /* CK_TIMERx = 4 x CK_APB1  = 4x50M = 200MHZ */rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4); // 配置定时器时钟/* 配置 SW 为上拉输入模式(必须上拉)    */gpio_mode_set(PORT_ENCODER_SW,GPIO_MODE_INPUT,GPIO_PUPD_PULLUP,GPIO_ENCODER_SW);/* 配置 CLK 为输入模式 上拉模式 */ gpio_mode_set(PORT_ENCODER_LCK,GPIO_MODE_INPUT,GPIO_PUPD_PULLUP,GPIO_ENCODER_LCK);  /* 配置 DT 为输入模式 上拉模式 */ gpio_mode_set(PORT_ENCODER_DT,GPIO_MODE_INPUT,GPIO_PUPD_PULLUP,GPIO_ENCODER_DT);  timer_deinit(BSP_TIMER);                                                                                                                  // 复位定时器/* 配置定时器参数 10Ms 扫描一次 *//* f = 240,000,000 / (2400 * 1000) = 100Hz *//* T = 1/f = 1/100 = 0.01 S = 10 MS */timere_initpara.prescaler = 2400-1;                    //  时钟预分频值 0-65535timere_initpara.alignedmode = TIMER_COUNTER_EDGE;      // 边缘对齐                  timere_initpara.counterdirection = TIMER_COUNTER_UP;   // 向上计数    timere_initpara.period = 1000-1;                       // 周期  /* 在输入捕获的时候使用  数字滤波器使用的采样频率之间的分频比例 */timere_initpara.clockdivision = TIMER_CKDIV_DIV1;      // 分频因子         /* 只有高级定时器才有 配置为x,就重复x+1次进入中断 */    timere_initpara.repetitioncounter = 0;                 // 重复计数器 0-255  timer_init(BSP_TIMER,&timere_initpara);                // 初始化定时器/* 配置中断优先级 */nvic_irq_enable(BSP_TIMER_IRQ,2,2);                   // 设置中断优先级为 2,2/* 使能中断 */timer_interrupt_enable(BSP_TIMER,TIMER_INT_UP);       // 使能更新事件中断 /* 使能定时器 */timer_enable(BSP_TIMER);
}/******************************************************************* 函 数 名 称:Encoder_Scanf* 函 数 说 明:判断旋转编码器是否有往哪一个方向旋转* 函 数 形 参:无* 函 数 返 回:1=正转 2=反转* 作       者:LC* 备       注:哪一边正转哪一边反转不需要太在意,你说的算
******************************************************************/
char Encoder_Scanf(void)
{static  FlagStatus    EC11_CLK_Last= RESET;    //EC11的LCK引脚上一次的状态 (A相)static  FlagStatus    EC11_DT_Last = 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不变且为0if((EC11_DT_Last == GET_DT_STATE)&&(GET_DT_STATE == 0))  ScanResult = 1;                                 //正转//A上升沿时,采集的B不变且为1if((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不变且为0if((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( gpio_input_bit_get(PORT_ENCODER_SW, GPIO_ENCODER_SW) == SET ){delay_1ms(100);//消抖return 0;}   else//按下{ delay_1ms(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(timer_interrupt_flag_get(BSP_TIMER,TIMER_INT_FLAG_UP) == SET){timer_interrupt_flag_clear(BSP_TIMER,TIMER_INT_FLAG_UP);  // 清除中断标志位 /* 执行功能 */dat = Encoder_Scanf();//扫描编码器是否扭动if( dat != 0 )//如果有转动{if( dat == 2 )  {Encoder_Rotation_left();}else            {Encoder_Rotation_right();}}}
}

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

#ifndef _BSP_ENCODER_H_
#define _BSP_ENCODER_H_#include "gd32f4xx.h"//SW引脚
#define RCU_ENCODER_SW      RCU_GPIOA 
#define PORT_ENCODER_SW     GPIOA
#define GPIO_ENCODER_SW     GPIO_PIN_7//CLK引脚
#define RCU_ENCODER_LCK      RCU_GPIOA 
#define PORT_ENCODER_LCK     GPIOA
#define GPIO_ENCODER_LCK     GPIO_PIN_6//DT引脚
#define RCU_ENCODER_DT      RCU_GPIOA 
#define PORT_ENCODER_DT     GPIOA
#define GPIO_ENCODER_DT     GPIO_PIN_4//获取CLK引脚的状态
#define GET_CLK_STATE   gpio_input_bit_get(PORT_ENCODER_LCK,GPIO_ENCODER_LCK)
//获取DT引脚的状态
#define GET_DT_STATE    gpio_input_bit_get(PORT_ENCODER_DT,GPIO_ENCODER_DT)//CLK引脚的外部中断
#define CLK_EXTI_IRQN                EXTI5_9_IRQn            // 外部中断6
#define CLK_EXTI_PORT_SOURCE         EXTI_SOURCE_GPIOA       // 外部中断端口资源
#define CLK_EXTI_PIN_SOURCE          EXTI_SOURCE_PIN6        // 外部中断引脚资源
#define CLK_EXTI_LINE                EXTI_6                  // 外部中断
#define CLK_EXTI_IRQHANDLER          EXTI5_9_IRQHandler      // 外部中断函数名
//DT
#define DT_EXTI_IRQN                 EXTI4_IRQn              // 外部中断4
#define DT_EXTI_PORT_SOURCE          EXTI_SOURCE_GPIOA       // 外部中断端口资源
#define DT_EXTI_PIN_SOURCE           EXTI_SOURCE_PIN4        // 外部中断引脚资源
#define DT_EXTI_LINE                 EXTI_4                  // 外部中断
#define DT_EXTI_IRQHANDLER           EXTI4_IRQHandler        // 外部中断函数名//定时器扫描
#define BSP_TIMER_RCU                RCU_TIMER5              // 定时器时钟
#define BSP_TIMER                    TIMER5                  // 定时器
#define BSP_TIMER_IRQ                TIMER5_DAC_IRQn         // 定时器中断
#define BSP_TIMER_IRQHANDLER         TIMER5_DAC_IRQHandler   // 定时器中断服务函数void Encoder_GPIO_Init(void);//旋转编码器初始化
unsigned char Encoder_Sw_Down(void);//编码器是否按下
int Encoder_Rotation_left(void);//左转服务函数
int Encoder_Rotation_right(void);//右转服务函数#endif

2.2.4 移植验证
在自己工程中的main主函数中,编写如下。

/********************************************************************************* 文 件 名: main.c* 版 本 号: 初版* 修改作者: LC* 修改日期: 2023年04月06日* 功能介绍:          ******************************************************************************* 注意事项:
*********************************************************************************/#include "gd32f4xx.h"
#include "systick.h"
#include "bsp_usart.h"
#include "bsp_encoder.h"
#include "stdio.h"int main(void)
{nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);  // 优先级分组systick_config();                //滴答定时器初始化 1msusart_gpio_config(115200U);Encoder_GPIO_Init();printf("encoder demo start\r\n");while(1){if( Encoder_Sw_Down() == 1 )//旋转编码器被按下{printf("Encoder down\r\n");}              }
}

移植成功示例,见文件2.2.4-1 。
文件2.2.4-1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/587903.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FPGA常用IP核之FIFO学习

IP核是FPGA芯片公司提供的逻辑功能块&#xff0c;在FPGA芯片中可以进行优化和预先配置&#xff0c;可以直接在用户设计的程序中使用&#xff0c;应用范围很广。在FPGA设计开发过程中使用IP核&#xff0c;可以大大的缩短开发周期&#xff0c;高度优化的IP核可以使FPG开发工程师专…

R统计实战:详解机器学习Adaboost的操作步骤与应用

一、引言 机器学习是人工智能的核心领域之一&#xff0c;其重要性体现在其能够从数据中自动学习并改进的能力上。在实际问题中&#xff0c;机器学习已经被广泛应用于各个领域&#xff0c;包括但不限于金融、医疗、电子商务、社交网络等。例如&#xff0c;在金融领域&#xff0c…

银行监管报送系统介绍(十五):金融审计平台

《“十四五”国家审计工作发展规划》中重点强调&#xff0c;金融审计&#xff1a;以防范化解重大风险、促进金融服务实体经济&#xff0c;推动深化金融供给侧结构性改革、建立安全高效的现代金融体系为目标&#xff0c;加强对金融监管部门、金融机构和金融市场运行的审计。 —…

律所如何做好内容运营,提升品牌影响力

近年来&#xff0c;随着品牌推广方式的改变&#xff0c;中国律所也开始关注内容营销&#xff0c;期待能够凭借内容营销增强影响力。今天&#xff0c;媒介盒子就从内容传播的逻辑出发&#xff0c;和大家聊聊律所如何做好内容运营&#xff0c;提升品牌影响力。 一、品牌形象管理 …

Vue2(十二):Vuex环境搭建、Vuex工作原理、Vuex开发者工具、几个配置项、多组件共享数据、Vuex模块化

一、Vuex 1.概念 专门在Vue中实现集中式状态&#xff08;数据&#xff09;管理的一个Vue插件&#xff08;use引入&#xff09;&#xff0c;对vue应用中多个组件的共享状态进行集中式的管理&#xff08;读&#xff0f;写&#xff09;&#xff0c;也是一种组件间通信的方式&…

Python框架下的qt设计之JSON格式化转换小程序

JSON转换小程序 代码展示&#xff1a; 主程序代码&#xff1a; from PyQt6.QtWidgets import (QApplication, QDialog, QMessageBox )import sys import jsonclass MyJsonFormatter(jsonui.Ui_jsonFormatter,QDialog): # jsonui是我qt界面py文件名def __init__(self):super()…

Python+requests+Pytest+logging+allure+pymysql框架详解

一、框架目录结构 1)tools目录用来放公共方法存储,如发送接口以及读取测试数据的方法,响应断言 数据库断言 前置sql等方法;2)datas目录用例存储接口用例的测试数据,我是用excel来存储的数据,文件数据 图片数据等;3)testcases目录用来存放测试用例,一个python文件对应…

基于深度学习的危险物品检测系统(网页版+YOLOv8/v7/v6/v5代码+训练数据集)

摘要&#xff1a;本文详细介绍基于YOLOv8/v7/v6/v5的危险物品检测技术。主要采用YOLOv8技术并整合了YOLOv7、YOLOv6、YOLOv5的算法&#xff0c;进行了细致的性能指标对比分析。博客详细介绍了国内外在危险物品检测方面的研究现状、数据集处理方法、算法原理、模型构建与训练代码…

使用 Docker Compose 部署邮件服务器

使用 Docker Compose 部署邮件服务器 很多时候为了方便&#xff0c; 我们都直接使用第三方邮箱进行收发邮件。 但第三方邮箱有些要求定期修改密码&#xff0c;有些限制发邮箱的次数&#xff0c; 对于一些个人和企业来说&#xff0c; 有自己的域名和服务器为什么不自己搭建一个邮…

【六 (2)机器学习-机器学习建模步骤/kaggle房价回归实战】

一、确定问题和目标&#xff1a; 1、业务需求分析&#xff1a; 与业务团队或相关利益方进行深入沟通&#xff0c;了解他们的需求和期望。 分析业务流程&#xff0c;找出可能的瓶颈、机会或挑战。 思考机器学习如何帮助解决这些问题或实现业务目标。 2、问题定义&#xff1a;…

论文阅读RangeDet: In Defense of Range View for LiDAR-based 3D Object Detection

文章目录 RangeDet: In Defense of Range View for LiDAR-based 3D Object Detection问题笛卡尔坐标结构图Meta-Kernel Convolution RangeDet: In Defense of Range View for LiDAR-based 3D Object Detection 论文&#xff1a;https://arxiv.org/pdf/2103.10039.pdf 代码&…

元宇宙虚拟空间的场景构造(二)

前言 该文章主要讲元宇宙虚拟空间的场景构造&#xff0c;基本核心技术点&#xff0c;不多说&#xff0c;直接引入正题。 场景的构造 使用引入的天空模块 this.sky new Sky(this); 在Sky模块里&#xff0c;有设置对其中的阳光进行不同时间段的光线处理。而天空又是怎么样的…