【单片机】STM32单片机读取旋转编码器,TIM定时器捕获

news2025/5/23 15:23:06

文章目录

  • 旋转编码器介绍
  • 主程序逻辑直接检测
  • 用外部中断检测下降沿
  • 定时器直接解码旋转编码器

旋转编码器介绍

旋转编码器简单来说,就是会输出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);
            }
        }

    }
}



当然需要记得添加库文件:
在这里插入图片描述

定时器直接解码旋转编码器

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:Python输出\n的用法及优势

Python 输出\n 的用法及优势 在Python编程语言中,我们常常需要输出字符串,并在特定地方换行。在这种情况下,使用\n是一种非常方便的方式。在本文中,我们将详细介绍Python的输出\n的用法及其优势。 什么是\n? \n是一…

Spark17-18-19

17. Spark执行流程 17.1 创建SparkContext 使用spark-submit脚本,会启动SparkSubmit进程,然后通过反射调用我们通过--class传入类的main方法,在main方法中,就行我们写的业务逻辑了,先创建SparkContext,向M…

YOLOv5-7.0添加BottleNet transformer

YOLOv5主干特征提取网络为CNN网络,CNN具有平移不变性和局部性,缺乏全局建模长距离建模的能力,引入自然语言领域的Transformer可以形成CNNTransFormer架构,充分结合两者的优点,提高目标检测效果。 1. BoTNet 论文地址…

BeautifulSoup爬取豆瓣电影数据

BeautifulSoup爬取豆瓣TOP250 豆瓣爬取地址 https://movie.douban.com/top250?formattext BeautifulSoup官网地址 https://www.rddoc.com/doc/BeautifulSoup/4.5.3/zh/quick-start/ 安装所需函数库 pip install beautifulsoup4pip install lxmlpip install requests导入…

IIS安装localhost显示下载,urlrewrite设置

1.取消ftp服务勾选 2. ping localhost ping 127.0.0.1 如果显示 ::1 则需要禁用ipv6 在注册表 找到并单击下面的注册表子项: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters\ 双击“DisabledComponents”以修…

Git2023最新版下载与安装教程(Windows版)

Windows版Git下载与安装教程 1. 下载Git2. 安装Git3. 配置Git 1. 下载Git 打开Git官网下载地址:https://git-scm.com/downloads 点击Download for Windows 选择git版本进行下载 2. 安装Git 双击安装包 点击Next 选择Git的安装路径,点击Next 选择…

【Html】js+css实现平滑滚动

效果 示例 <!DOCTYPE html> <html><head><title> Document </title><style>button{bottom: 0;position: fixed;z-index: 999;left: 0;background: rgb(94, 171, 255);border: 1px red;color: white;font-size: large;font-family: ;}img{…

C++、Redis读取base64格式的图像记录

C、Redis读取base64格式的图像记录 一、案例需求 1.另一台电脑利用C#和Redis将图像数据按照base64格式&#xff0c;存储在某一个key中 2.本机需要使用C和Redis将图像数据获取到&#xff0c;并写入本地。 环境&#xff1a;Ubuntu20、Redis、QT 二、Qt中的Pro文件配置 QT中的…

深度学习记录1(线性回归的实现)

1、整体思路 根据线性回归的定义&#xff0c; &#xff0c;建立线性回归模型&#xff0c;在损失函数的计算上&#xff0c;采用L2 Loss&#xff08;均方误差&#xff09;。同时&#xff0c;对于模型的优化采用随机梯度下降。 2、详细代码分析 import random import torch from…

Day7——Web安全基础下

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 回顾前言一、owasp top 10漏洞&#xff08;了解&#xff09;&#xff08;四年一更&#xff09;1.访问控制崩溃2.敏感数据暴露3.sql注入4.不安全的设计5.安全配置不当…

【单片机】STM32单片机的各个定时器的定时中断程序,标准库

文章目录 定时器1_定时中断定时器2_定时中断定时器3_定时中断定时器4_定时中断定时器5_定时中断 高级定时器和普通定时器的区别&#xff08;https://zhuanlan.zhihu.com/p/557896041&#xff09;&#xff1a; 定时器1_定时中断 TIM1是高级定时器&#xff0c;使用的时钟总线是R…

使用Megascans,Blender和Substance 3D画家创建渔人旅馆(p2)

今天云渲染小编接着Polina Tarakanova分享的Fishermans Inn项目上篇分享&#xff0c;下篇主要是纹理和材料、组装场景、照明等方面的分享。 纹理和材料 随着酒馆的模块化建设完成&#xff0c;是时候进入贴图阶段了。我使用Substance 3D Painter进行了所有的贴图工作。在我的场…

【网站创建】网络杂谈(6)之web网站的创建

涉及知识点 如何创建web网站&#xff0c;web网站创建的步骤&#xff0c;手把手教你如何搭建web网站&#xff0c;web网站创建的过程&#xff0c;深入了解web网站创建。 原创于&#xff1a;CSDN博主-《拄杖盲学轻声码》&#xff0c;更多内容可去其主页关注下哈&#xff0c;不胜感…

基于Java+SpringBoot+Vue的计算机类考研交流平台设计与实现

博主介绍&#xff1a;擅长Java、微信小程序、Python、Android等&#xff0c;专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案例…

React-View-UI组件库封装Loading加载中源码

目录 组件介绍Loading API能力组件源码组件测试源码组件库线上地址 组件介绍 Loading组件是日常开发用的很多的组件&#xff0c;这次封装主要包含两种状态的Loading&#xff0c;旋转、省略号&#xff0c;话不多说先看一下组件的文档页面吧&#xff1a; 正在上传…重新上传取…

掌握imgproc组件:opencv-图像变换

图像变换 1. 基于OpenCV的边缘检测1.1 边缘检测的一般步骤1.2 canny算子1.2.1 Canny边缘检测步骤&#xff1a;1.2.2 Canny边缘检测&#xff1a;Canny()函数1.2.3 Canny边缘检测案例 1.3 sobel算子1.3.1 sobel算子的计算过程1.3.2 使用Sobel算子&#xff1a;Sobel()函数1.3.3 示…

模拟高并发下RabbitMQ的削峰作用

在并发量很高的时候&#xff0c;服务端处理不过来客户端发的请求&#xff0c;这个时候可以使用消息队列&#xff0c;实现削峰。原理就是请求先打到队列上&#xff0c;服务端从队列里取出消息进行处理&#xff0c;处理不过来的消息就堆积在消息队列里等待。 可以模拟一下这个过…

生态+公链:中创面向未来的区块链建设!

未来的区块链市场&#xff0c;一定属于能够将区块链技术与应用完美结合在一起的产品。从互联网的发展历程来看&#xff0c;最后的竞争往往会集中到生态与兼容性。 如何将区块链的落地和应用更加有机地结合在一起&#xff0c;从而让区块链的功能和作用得到最大程度的发挥&#…

机器学习8:特征组合-Feature Crosses

特征组合也称特征交叉&#xff08;Feature Crosses&#xff09;&#xff0c;即不同类型或者不同维度特征之间的交叉组合&#xff0c;其主要目的是提高对复杂关系的拟合能力。在特征工程中&#xff0c;通常会把一阶离散特征两两组合&#xff0c;构成高阶组合特征。可以进行组合的…

css:去除input和textarea默认边框样式并美化

input input默认样式和focus样式 参考element-ui的css&#xff0c;可以实现如下效果 实现代码 <style>/* 去除默认样式 */input {border: none;outline: none;padding: 0;margin: 0;-webkit-appearance: none;-moz-appearance: none;appearance: none;background-im…