增量式旋转编码器在STM32平台上的应用

背景

旋钮是仪器仪表上一种常见的输入设备,它的内部是一个旋转编码器,知乎上的这篇科普文章对其工作原理做了深入浅出的介绍。
旋钮在仪器上的样子

我们公司的功率分析仪前面板也用到了该类设备,最近前面板的MCU从MSP430切换成了STM32,因此我要将编码器的驱动移植到STM32。

查看MSP430的代码,看懂其基本思路,是将旋钮的2路输出信号接到2个GPIO管脚,并让这2个管脚作为中断源,驱动在中断里检测2路输出信号的电平组合,并做一些复杂的处理,后台循环根据中断的处理结果获悉旋钮的旋转方向,以及旋转过了几个刻度。

觉得MSP430的处理逻辑太复杂了,而且经过确认,app并不需要知道旋转过了几个刻度,决定用简单的方法来实现旋钮功能。

移植思路

了解所用旋钮的信号时序

我们用的旋钮是日本帝国通信的XRE系列,其原理图:
旋钮的原理图
其时序图:
旋钮的时序图,顺时针
可以看到,因为增量式旋转编码器的2个信号的波形相差1/4周期,因此信号A在跳变时,信号B一定处于稳定的高电平或稳定的低电平。

找到信号波形与旋转方向之间的对应关系

根据时序图可以看出,当A相处于上升沿时,B相总是电平,结合时序图左下角的CLOCKWISE ROTATION注释,我们可以得出结论,只要在A相的上升沿中断里检测到B相为低电平,则说明旋钮在时针旋转。

那怎么检测逆时针旋转呢?旋钮手册里并没有COUNTER-CLOCKWISE ROTATION的内容,其实我们只要从右往左看,就是逆时针的时序图:
旋钮的时序图,逆时针
可以看到,在时针旋转场景里,当A相处于上升沿时,B相总是电平,因此我们只需要在A相的上升沿检测一次B相的电平高低,就能判断出旋转方向!

代码编写

STM32的EXTI中断

与MSP430的GPIO自带中断功能不同,STM32的GPIO是不具备中断能力的,要想当中断管脚用,需要搭配EXTI模块。

网上关于EXTI的样例代码较少,更多的是用STM32CubeMX生成的整套工程代码,我现有的工程就是前任员工基于STM32CubeMX生成的,很难将两个工程自动合并。

想到可以将EXTI工程里的有效代码摘出来,插入现有工程里,尝试了一下,可行。

GPIO和EXTI初始化代码

void encoder_init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};// GPIO initGPIO_InitStruct.Pin = encoder_a2_Pin;GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;   //A相负责触发中断,确定观测时间点GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);GPIO_InitStruct.Pin = encoder_b2_Pin;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;       //软件读取B相的电平高低,从而确定方向GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/* EXTI interrupt init*/HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);       //encoder_a2_Pin是连接到GPIO_PIN_0的,因此对应EXTI的0号中断HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}

中断回调代码

void EXTI0_IRQHandler(void)
{/* USER CODE BEGIN EXTI0_IRQn 0 *//* USER CODE END EXTI0_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(encoder_a2_Pin);/* USER CODE BEGIN EXTI0_IRQn 1 *//* USER CODE END EXTI0_IRQn 1 */
}void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{/* EXTI line interrupt detected */if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u) // 不用担心多个GPIO共用一个EXTI中断,EXTI会做区分{__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);HAL_GPIO_EXTI_Callback(GPIO_Pin);}
}void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{uint8_t pin_value;switch (GPIO_Pin){case encoder_a2_Pin:{pin_value = HAL_GPIO_ReadPin(encoder_b2_GPIO_Port, encoder_b2_Pin);if (!pin_value) {encoder_msg = ENCODERA_LEFT; // 逆时针旋转} else {encoder_msg = ENCODERA_RIGH; // 顺时针旋转}break;}default:break;}
}

后台循环代码

uint8_t encoder_msg = INVALID_MSG;void encoder_process(void)
{uint8_t out_data[6];if (encoder_msg != INVALID_MSG){data_process(ENCODER_KEY_TYPE, 0, (uint8_t *)&encoder_msg, out_data); //将旋钮消息按约定格式封装成out_dataspi_enque_tx_data(out_data);  // 将out_data通过SPI总线上报主控板encoder_msg = INVALID_MSG;  // clear msg}
}

总结

我的代码相比老工程,在app感知不到功能差异的前提下,逻辑大大简化,中断占用量还减少了一半,值得大家参考。

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

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

相关文章

linux运维的面试题一

1.linux启动过程 1加电 2加载主板bios设置 3加载多重操作系统启动管理器grub 4加载内核系统到内存当中 5加载配置文件 6加载内核模块 7完成相应的初始化工作和启动相应的服务 8启动系统进程 9出现登录界面 10开机启动完成 2.安装过操作系统吗?怎么安装? 1.小批量设…

Vue+ElementUI+nodejs学生宿舍报修管理系统68ozj

本站是一个B/S模式系统,采用vue框架,MYSQL数据库设计开发,充分保证系统的稳定性。系统具有界面清晰、操作简单,功能齐全的特点,使得学生宿舍信息管理系统管理工作系统化、规范化。本系统的使用使管理人员从繁重的工作中…

nodejs+vue+ElementUi美发店理发店管理系统q9xc1

本站是一个B/S模式系统,采用vue框架,MYSQL数据库设计开发,充分保证系统的稳定性。系统具有界面清晰、操作简单,功能齐全的特点,使得美发门店管理系统管理工作系统化、规范化。本系统的使用使管理人员从繁重的工作中解脱…

淘宝商品评论API:电商行业的战略资源与制胜之道

在电商行业,数据是金。而其中,用户评论数据更是无价之宝。它不仅仅反映了商品的质量和卖家的服务态度,更是消费者在决策时的关键参考。正因如此,获得淘宝商品评论API的重要性不言而喻。 一、数据背后的无尽宝藏 淘宝,…

MyBatis的动态SQL!!!

一.if和where的使用。 1.首先在UserMapper接口中声明一个方法&#xff1a; package com.by.mapper;import com.by.pojo.User;import java.util.List;/*** <p>Project: mybatis - UserMapper</p>* <p>Powered by scl On 2023-12-22 15:52:05</p>* <…

纯搬运 solidworks 2021卸载方法,怎么完全彻底卸载删除清理干净solidworks 2021各种残留注册表和文件?

纯搬运 solidworks 2021卸载方法&#xff0c;怎么完全彻底卸载删除清理干净solidworks 2021各种残留注册表和文件&#xff1f; 网址&#xff1a; solidworks 2021卸载方法&#xff0c;怎么完全彻底卸载删除清理干净solidworks 2021各种残留注册表和文件&#xff1f; solidworks…

推荐给前端开发的 5 款 Chrome 扩展

工欲善其事&#xff0c;必先利其器。Chrome 可能是前端开发中使用最多的浏览器。在日常开发中&#xff0c;下列几款 Chrome 扩展也许能让你的开发工作事半功倍 &#x1f680; Vue.js devtools ⚙️ vue 官方专为 vue 应用开发的调试工具。 通过使用它&#xff0c;你可以快速查看…

Iceberg:ZOrder的实现及执行流程分析

ZOrder简介 使用Z-Order索引&#xff0c;可以按任意维度对数据进行排序&#xff0c;以获得更加高效且均衡地范围查询。它即可以作为一级索引&#xff0c;直接影响底层数据组织形式&#xff0c;甚至可以取代二索引&#xff08;更加节省内存&#xff0c;吞吐量也理更高&#xff…

SUSE Linux服务器使用zypper安装nginx

SUSE Linux 的云服务器用户&#xff0c;不能yum,安装软件&#xff0c;可通过 zypper 快速安装软件。 使用 root 账号登录 openSUSE 操作系统的云服务器。 执行 zypper service-list 或 zypper sl 命令 列出软件源 安装软件包 执行 zypper search 或 zypper se 命令&#…

【Linux系统基础】(1)Linux基础命令全面详解

在计算机世界中&#xff0c;Linux操作系统以其稳定性、安全性和开源性而受到广大程序员和系统管理员的喜爱。然而&#xff0c;对于初学者来说&#xff0c;Linux的命令行界面可能会显得有些复杂和难以理解。本文将详细介绍一些常用的Linux基础命令&#xff0c;帮助你更好地理解和…

2023年软件测试已经崩盘了吗?为什么很难找到工作?

最近后台很多粉丝给我留言&#xff1a; 2023年软件测试已经崩盘了吗&#xff0c;为什么都找不到工作了&#xff1f; 确实&#xff0c;今年经济大环境不好&#xff0c;企业也都在降本增效&#xff0c;如果技术能力还在被应届生竞争岗位的阶段&#xff0c;只会越来越难。 找不…

Qt中字符串转换为JS的函数执行

简介 在 QML 中&#xff0c;将 JavaScript 字符串转换为函数通常涉及使用 Function 构造函数或 eval() 函数。但是&#xff0c;QML 的环境对 JavaScript 的支持有一定的限制&#xff0c;因此不是所有的 JavaScript 功能都可以在 QML 中直接使用。 以下介绍都是在Qt5.12.1…