stm32-编码器测速

一、编码器简介

编码电机

旋转编码器

A,B相分别接通道一和二的引脚,VCC,GND接单片机VCC,GND

二、正交编码器工作原理

以前的代码是通过触发外部中断,然后在中断函数里手动进行计次。使用编码器接口的好处就是节约软件资源。对于频繁执行,操作简单的任务,一般设计一个硬件电路模块来自动完成。

使用定时器的编码器接口,再配合编码器,就可以测量旋转速度和旋转方向。编码器测速一般应用在电机控制的项目上。使用PWM驱动电机,再使用编码器测量电机的速度,然后再使用PID算法进行闭环控制。

平横车经常用到

1.计数方式

 2.框图分析

 由图可知,只有CH1和CH2有编码器接口,且编码器只用到了输入捕获结构体的输入滤波和边沿检测器,则其余的结构体成员都不用区配置。

 由框图可知,配置Encoder需要配置GPIO,输入捕获结构体的部分元素,时基单元,我们一般给ARR为65535-1,即最大计数量程,防止计数溢出。PSC=1-1,不分频,直接72M进行计数

3.计数方向与编码器信号的关系

 TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising)

这里TIM_EncoderMode_TI12即对应上面的计数边沿,仅在TI1和TI2计数就相当于只在A或B相的边沿计数,我们一般都使用AB相都计数

极性修改:可以使用上方的函数进行,也可以硬件直接调换AB相引脚

三、固件库使用

 

1.开启GPIO和TIM的时钟

2.配置GPIO结构体,模式配置为上拉输入

3.不用配置内部时钟源,因为编码器托管了时钟,编码器接口就是带方向控制的外部时钟,      所以内部时钟就没有用了    

4.配置时基单元,计数模式就不用配置了,取决于编码器的AB相边沿,ARR为65535-1,     PSC = 1-1不分频

5.配置输入捕获单元(因为是由)TI1FP1和2接入到编码器接口的,所以捕获单元结构体    元素只需配置输入滤波和边沿检测即可,这里边沿检测给上升沿还是下降沿并不是说是

   哪个有效,因为编码器模式下上/下沿都有效,这里指电平极性是否翻转,高电平不反转,

    低电平翻转

6.TIM_EncoderInterfaceConfig();配置编码器,TIM_Cmd();使能定时器

7.使用中断读取Encoder的值(测速度)

   若要测位置就直接读取Encoder的值即可,不需要中断

上拉输入还是下拉输入的选择

一般可以看一下接在这个引脚的外部模块输出的默认电平,如果外部模块空闲默认输出高电平,我们就选择上拉输入,默认输入高电平,如果外部模块默认输出低电平,我们配置下拉输入,默认输入低电平。总结,将需要配置电平的位置和外部模块保持默认状态一致,防止默认电平打架。

如果不确定外部模块输出的默认状态或者外部信号输出功率非常小,这时尽量选择浮空输入,浮空输入没有上下拉电阻去影响外部信号,缺点是当引脚悬空时,没有默认电平,输入就会受噪声干扰,来回不断跳变。

测位置:A、B相各出现了一个下降沿和上升沿,所以计次总共加了4次。

               如果转到0,再往左转,0自减,计数器反向溢出,回到自动重装值,65535,然后继续往下减

                解决方法是:如果我们想让0自减为-1,直接把uint16_t类型强制转换成int16_t即可

 

如果想让编码器测速度,可以在固定的闸门时间读一次CNT,然后把CNT清零,此时CNT的值代表速度,单位是脉冲个数/S 

(测频法)

#include "encoder.h"void Encoder_Init(void)
{//开启GPIO和TIM3时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//初始化GPIOGPIO_InitTypeDef GPIO_InitStruct;//定义GPIO结构体//GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//输入不需要配置速度GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_IPU;GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_6 | GPIO_Pin_7;GPIO_Init(GPIOA,&GPIO_InitStruct);//因为编码器接口会托管时钟,编码器接口就是带方向控制的外部时钟,所以内部时钟就没有用了	//TIM_InternalClockConfig(TIM2);//配置时基单元//初始化时基单元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_TimeBaseInitStruct.TIM_Prescaler = 1-1;//PSC-预分频器,给0,不分频//TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//计数方向被编码器托管了TIM_TimeBaseInitStruct.TIM_Period = 65535-1;//ARR寄存器-重装载寄存器TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;/*不分频----滤波器的采样频率,                                    可以由内部时钟直接提供,														                 也可以由内部时钟加一个时钟分频而来,分频系数就是由TIM_ClockDivision决定*/TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;//重复计数器,只有高级定时器才有	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);//配置输入捕获单元TIM_ICInitTypeDef TIM_ICInitStruct;TIM_ICStructInit(&TIM_ICInitStruct);TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;//电平极性选择,高电平极性不反        转,低电平极性反转//TIM_ICInitStruct.TIM_ICSelection //直连or交叉连//TIM_ICInitStruct.TIM_ICPrescaler //分频器因子,即每N个边沿跳变事件捕获一次-CCMR1_ICPSTIM_ICInitStruct.TIM_ICFilter = 0xF;//CCMR1_ICFTIM_ICInit(TIM3, &TIM_ICInitStruct);TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;//电平极性选择,高电平极性不反    转,低电平极性反转TIM_ICInitStruct.TIM_ICFilter = 0xF;//CCMR1_ICFTIM_ICInit(TIM3,&TIM_ICInitStruct);TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);//这里的上升沿和上面结构体配置的效果一样,所以前面的可以删去//使能TIMTIM_Cmd(TIM3,ENABLE);
}int16_t Encoder_Get(void)//int16_t 为了显示负数
{int16_t temp;temp = TIM_GetCounter(TIM3);TIM_SetCounter(TIM3,0);//这里每次获得了编码器的值后就清零CNT是为了得到速度//我们使用了中断,一秒进入一次然后读取CNT的值作为旋转速度return temp;
}
#include "bsp_tim.h"void Time_Config()
{//开启时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//选择时基单元的时钟-为内部时钟--定时器上电后默认是内部时钟,故不写这一个也行TIM_InternalClockConfig(TIM2);//初始化时基单元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_TimeBaseInitStruct.TIM_Prescaler = 7200-1;//PSC-预分频器TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数 TIM_TimeBaseInitStruct.TIM_Period = 10000-1;//ARR寄存器-重装载寄存器TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;/*不分频----滤波器的采样频率,可以由内部时钟直接提供,也可以由内部时钟加一个时钟分频而来,分频系数就是由TIM_ClockDivision决定*/TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;//重复计数器,只有高级定时器才有TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);//使能中断-事件更新TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);TIM_ClearFlag(TIM2,TIM_IT_Update);//因为TIM_TimeBaseInit函数最后有一个直接操作UG位的操作//使得直接产生了一个更新事件,因此直接进行给UIE位置1//直接进入了中断,使得我们初始化ARR和PSC还未写入到//影子寄存器,使得Num一上电就是1//所以在进入中断之前先清楚中断标志位//使能中断之后就要进入NVIC了//先优先级分组NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//配置结构体NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;//中断通道NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);//启动定时器TIM_Cmd(TIM2,ENABLE);//在_it文件里编写中断服务函数
}
#include ".\tim\bsp_tim.h"
#include "encoder.h"
#include ".\OLED\OLED.h"int16_t speed;
int main()
{Time_Config();Encoder_Init();OLED_Init();while(1){OLED_ShowSignedNum(1,5,speed,5);}
}
void TIM2_IRQHandler()
{//先获取中断标志位if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET){speed = Encoder_Get();//清楚中断标志位TIM_ClearFlag(TIM2,TIM_FLAG_Update);}
}

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

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

相关文章

从0开始回顾MySQL---事务四大特性

事务概述 事务是一个最小的工作单元。在数据库当中,事务表示一件完整的事儿。一个业务的完成可能需要多条DML语句共同配合才能完成,例如转账业务,需要执行两条DML语句,先更新张三账户的余额,再更新李四账户的余额&…

实现elasticsearch和数据库的数据同步

1. 数据同步 elasticsearch中的酒店数据来自于mysql数据库,因此mysql数据发生改变时,elasticsearch也必须跟着改变,这个就是elasticsearch与mysql之间的数据同步。 1.1. 思路分析 常见的数据同步方案有三种: 同步调用 异步通知…

面试题手撕篇

参考博客 开始之前,理解递归 手写 浅拷贝 function shallow(target){if(target instanceof Array){return [...resObj]}else{return Object.assign({},target);} }手写深拷贝 const _sampleDeepClone target > {// 补全代码return JSON.parse(JSON.stringify…

EtherCAT开源主站 IGH 介绍及主站伺服控制过程

目录 前言 IGH EtherCAT主站介绍 主要特点和功能 使用场景 SOEM 主站介绍 SOEM 的特点和功能 SOEM 的使用场景 IGH 主站 和 SOEM对比 1. 功能和复杂性 2. 资源消耗和移植性 3. 使用场景 EtherCAT 通信原理 EtherCAT主站控制伺服过程 位置规划模式 原点复归模式…

Ansible非标记语言YAML与任务剧本Playbook

前言 上篇介绍了 Ansible 单模块(AD-Hoc)的相关内容Ansible自动化运维Inventory与Ad-Hoc-CSDN博客,Ad-Hoc 命令是一次性的、即时执行的命令,用于在远程主机上执行特定任务,这些命令通常用于快速执行简单的任务。当需要…

MS08-067 漏洞利用与安全加固

文章目录 环境说明1 MS08_067 简介2 MS08_067 复现过程3 MS08_067 安全加固 环境说明 渗透机操作系统:2024.1漏洞复现操作系统: Windows XP Professional with Service Pack 2- VL (English)安全加固复现操作系统:Windows XP Professional with Service …

C语言案例2,请编程序将“China“译成密码,密码规律是:用原来的字母后面第4个字母代替原来的字母,变为Glmre,持续更新~

一.题目 /* 请编程序将“China”译成密码,密码规律是:用原来的字母后面第4个字母代替原来的字母。 例如,字母“A”后面第4个字母是“E”,用“E”代替“A”。因此,“China”应译为“Glmre”。 请编一程序,用赋初值的方法使cl,c2,c3,c4,c5 这5个变量的值分…

YoloV5改进策略:下采样改进|HWD改进下采样

摘要 本文使用HWD改进下采样,在YoloV5的测试中实现涨点。 论文解读 在卷积神经网络(CNNs)中,极大池化或跨行卷积等下采样操作被广泛用于聚合局部特征、扩大感受野和最小化计算开销。然而,对于语义分割任务&#xff…

HTML_CSS练习:HTML注释

一、代码示例 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>HTML注释</title> </head> <body><marquee loop"1">马龙强<!--下面的输入框是可以滚动的&#x…

【Python】清理conda缓存的常用命令

最近发现磁盘空间不足&#xff0c;很大一部分都被anaconda占据了&#xff0c;下面是一些清除conda缓存的命令 清理所有环境的Anaconda包缓存 删除所有未使用的包以及缓存的索引和临时文件 conda clean --all清理某一特定环境的Anaconda包缓存 conda clean --all -n 环境名清…

【ansible】ansible的介绍和安装

前言运维自动化 云计算核心职能 搭建平台架构 日常运营保障 性能效率优化 相关工具 代码管理&#xff08;SCM&#xff09;&#xff1a;GitHub、GitLab、BitBucket、SubVersion 构建工具&#xff1a;maven、Ant、Gradle 自动部署&#xff1a;Capistrano、CodeDeploy 持续…

字符串函数(C语言详解)

1.字符串简介 字符串是一串连续的且以\0结尾的字符 char arr[]"zhangsan";//将字符串存到数组里面 char*a"lisi";//常量字符串 char arr1[]{z,h,a,n,g};//字符数组 注意&#xff1a; 1.以第一种形式初始化字符串时&#xff0c;计算机会自动在字符串末尾加…

GraspNet-baseline复现----Linux-Ubuntu

1.基本环境 Ubuntu 20.04Cuda 11.0 、cuDNN 80.0Python 3.7.16PyTorch 1.7.0 2.环境配置 PyTorch的版本对Cuda和Python的版本都有依赖&#xff0c;所以基本步骤是 确定需要安装的PyTorch版本 —> 通过 网站 确定对应的cuda版本和python版本 —> 创建虚拟环境配置环境。…

Node.js基础+原型链污染

Node.js基础 概述&#xff1a;简单来说Node.js就是运行在服务端的JavaScript&#xff0c;Node.js是一个基于Chrome JavaScript运行时建立的一个平台 大小写变换&#xff1a; toUpperCase&#xff08;&#xff09;&#xff1a;将小写字母转为大写字母&#xff0c;如果是其他字…

【C#】.net core 6.0 使用第三方日志插件Log4net,配置文件详细说明

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握。…

使用FFmpeg源码配置程序configure查看所有支持的编码器/解码器/封装/解封装及网络协议

查看支持编码器: configure --list-encoders 查看支持编码器: configure --list-decoders 查看所有支持的封装: configure --list-muxers 查看所有支持的解封装: configure --list-demuxers 查看所有支持的网络通信协议: configure --list-protocols

解决jsp request.getParameter乱码问题(兼容Tomcat 6~8三个版本)

JSP页面写法&#xff1a; <% page contentType"text/html; charsetutf-8" language"java" %> <% page import"java.io.*" %> <%! int getServerVersion(HttpServletRequest request) {ServletContext application request.getS…

移远通信亮相AWE 2024,以科技力量推动智能家居产业加速发展

科技的飞速发展&#xff0c;为我们的生活带来了诸多便利&#xff0c;从传统的家电产品到智能化的家居设备&#xff0c;我们的居家生活正朝着更智能、更便捷的方向变革。 3月14日&#xff0c;中国家电及消费电子博览会&#xff08;Appliance&electronics World Expo&#xf…

【物联网】Modbus 协议及Qinghub物联网平台应用

Modbus 协议简介 QingHub设计器在设计物联网数据采集时不可避免的需要针对Modbus协议的设备做相关数据采集&#xff0c;这里就我们的实际项目经验分享Modbus协议 你可以通过QingHub作业直接体验试用&#xff0c;也可以根据手册开发相应的代码块。 qinghub项目已经全面开源。 …

sqllab第十九关通关笔记

知识点&#xff1a; 错误注入 最大长度为32位&#xff1b;如果目标长度>32时&#xff0c;需要利用截取函数进行分段读取referer注入 insert语句update语句 通过admin admin进行登录发现页面打印除了referer字段的信息 这应该是一个referer注入 首先进行测试一下 构造payl…