模块学习(一)——编码电机

2023-05-16

想实现对电机的测速,因此开始接触编码电机。此次采用的是RS365编码器电机。

一、编码电机的初步了解

通过编码电机可以测出速度。常见一般编码电机分成两种,一是光电编码器,另一个是霍尔编码器。有六个接口,两个是电机的正负极,两个是编码器的正负极,还有两个是A,B相。

倍频的概念:如果只采集A/B相的上升/下降沿,即一倍频。若采集A/B的上升和下降沿,即二倍频,最多可以达到四倍频。这样测出来的速度是非常精确的。
在这里插入图片描述

具体直观了解可由上图可见。

在这里插入图片描述

以上是此次采用的编码电机的各个参数。所以可以得知,减速电机转动一周,可以产生30390个脉冲。若采用四倍频,则可以产生430*390个脉冲,可以大大提高精确度。

软件测量方面,可以采用外部中断捕获上升沿或者下降沿来实现测速。

二、如何测量一定时间内的脉冲

这就要用到TIM的输入捕获功能了,正好之前学习TIM的时候,仅仅涉及到普通PWM波的输出,今天顺便一起学习一下TIMA的输入捕获功能。

1.TIMA

根据手册可知TIMA具有7个输入捕获通道,并且具有广泛的中断功能。

在这里插入图片描述
由上图可初步了解定时器A的工作框图。

具体配置方法如下,这个配置方法之中,参阅了许多资料,最后还是只能靠自己一点点啃数据手册,如有不完善,还希望各位一起交流。

第一步:配置IO口

GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,GPIO_PIN2);//配置为外围输入

配置P2.0为外设输出

第二步:连续模式初始化

 //Start timer in continuous mode sourced by SMCLK
   Timer_A_initContinuousModeParam initContParam = {0};//定义连续模式初始化结构体
   initContParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;//确定时钟源SMCLK
   initContParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;//不分频
   initContParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;//禁用Tim A中断
   initContParam.timerClear = TIMER_A_DO_CLEAR;//重置计数方向等.....
   initContParam.startTimer = false;//先不开启计数器
   Timer_A_initContinuousMode(TIMER_A0_BASE, &initContParam);

第三步:清除比较模式中断

//清楚比较模式中断(初始化比较模式)
   Timer_A_clearCaptureCompareInterrupt(TIMER_A0_BASE,
       TIMER_A_CAPTURECOMPARE_REGISTER_1
       );

第四步:捕获模式初始化

Timer_A_initCaptureModeParam initCapParam = {0};//定义比较模式初始化结构体
   initCapParam.captureRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;//选择TIM_A0的捕获比较通道1
   initCapParam.captureMode = TIMER_A_CAPTUREMODE_RISING_EDGE;//捕获上升沿
   initCapParam.captureInputSelect = TIMER_A_CAPTURE_INPUTSELECT_CCIxA;//确定输入选择为CCIxA(这个不知道怎么看怎么确定)
   initCapParam.synchronizeCaptureSource = TIMER_A_CAPTURE_SYNCHRONOUS;//与时钟同步
   initCapParam.captureInterruptEnable = TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE;//使能捕获中断
   Timer_A_initCaptureMode(TIMER_A0_BASE, &initCapParam);

第五步:开始计时,打开全局中断

Timer_A_startCounter( TIMER_A0_BASE,//开启计时
           TIMER_A_CONTINUOUS_MODE
               );

   //Enter LPM0, enable interrupts开启全局中断
   __bis_SR_register(LPM0_bits + GIE);

   //For debugger
   __no_operation();

第六步:中断服务函数

在main.c中,写上输入捕获的中断服务函数

#pragma vector = TIMER0_A1_VECTOR//定时器中断
__interrupt void Timer_A(void)//生命一个函数为中断函数
{
  static int CNT = -1;
  CNT++;
  switch(__even_in_range(TA0IV,14))//中断标志位——对应捕获通道
  {
    case 2 ://如果是CCR1产生的中断
    GPIO_setOutputHighOnPin(GPIO_PORT_P4,GPIO_PIN7);
    if(CNT % 2 == 0)//记录第一次的上升沿Counter计数值
    {
        edge_count1 = Timer_A_getCaptureCompareCount(TIMER_A0_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_1);//将此时的上升沿计数值存入变量

    }
    else if(CNT % 2 == 1)//检测到下降沿触发
    {
        edge_count2 = Timer_A_getCaptureCompareCount(TIMER_A0_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_1);//将此时的下降沿计数值存入变量
    }
    PWM_Frequency  = (unsigned int)(1000000/(abs(edge_count1 - edge_count2) * 0.948));
    break;
    case 4 : break;
    case 10: break;
    case 14:break;//此时发生计数器溢出
    default: break;
  }
}

中断服务函数中这种编写方式,对于低频50HZ,100HZ是比较准确的。

看效果图
在这里插入图片描述
在这里插入图片描述

问题:

一旦频率上升超过1Khz,就不准确了。对于此时才用的是MCLK时钟,频率为1.054Mhz,也就是说CNT计数器每次+1,对应的时间是0.948us,按理来说,可测量频率范围应该在0-1.054Mhz之间,而实际可测频率仅有几百HZ,这是为什么呢??

采用一下测量方法,效果依然不好,这是为啥啊啊啊啊啊
下面这部分进行了10倍分频…因此是105400

#pragma vector = TIMER0_A1_VECTOR//定时器中断
__interrupt void Timer_A(void)//生命一个函数为中断函数
{
  static int CNT = -1;
  CNT++;
  switch(__even_in_range(TA0IV,14))//中断标志位——对应捕获通道
  {
    case 2 ://如果是CCR1产生的中断
        PWM_Frequency = 105400/Timer_A_getCounterValue(TIMER_A0_BASE);
        Timer_A_clear(TIMER_A0_BASE);
        break;
    case 4 : break;
    case 10: break;
    case 14:break;//此时发生计数器溢出
    default: break;
  }
}

等我解决后再来继续补充!如果各位大佬有解决办法,也麻烦留言评论一下,谢谢!

问题在昨日晚八点解决!但是具体原因我还是不太清楚为啥。在那之后,我将主频升到16MHZ之后,发现对于频率的测量可以精准到1KHZ误差之内,再改进一下算法,现在误差只有十几赫兹了,代码如下。

基本配置

 GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,GPIO_PIN2);//配置为外围输入

    //Start timer in continuous mode sourced by SMCLK
   Timer_A_initContinuousModeParam initContParam = {0};//定义连续模式初始化结构体
   initContParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;//确定时钟源SMCLK
   initContParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_10;//不分频
   initContParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;//禁用Tim A中断
   initContParam.timerClear = TIMER_A_DO_CLEAR;//重置计数方向等.....
   initContParam.startTimer = false;//先不开启计数器
   Timer_A_initContinuousMode(TIMER_A0_BASE, &initContParam);

   //清除比较模式中断(初始化比较模式)
   Timer_A_clearCaptureCompareInterrupt(TIMER_A0_BASE,
       TIMER_A_CAPTURECOMPARE_REGISTER_1
       );

   Timer_A_initCaptureModeParam initCapParam = {0};//定义比较模式初始化结构体
   initCapParam.captureRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;//选择TIM_A0的捕获比较通道1
   initCapParam.captureMode = TIMER_A_CAPTUREMODE_FALLING_EDGE;//捕获上升沿
   initCapParam.captureInputSelect = TIMER_A_CAPTURE_INPUTSELECT_CCIxA;//确定输入选择为CCIxA(这个不知道怎么看怎么确定)
   initCapParam.synchronizeCaptureSource = TIMER_A_CAPTURE_SYNCHRONOUS;//与时钟同步
   initCapParam.captureInterruptEnable = TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE;//使能捕获中断
   Timer_A_initCaptureMode(TIMER_A0_BASE, &initCapParam);

   Timer_A_startCounter( TIMER_A0_BASE,//开启计时
           TIMER_A_CONTINUOUS_MODE
               );

   //Enter LPM0, enable interrupts开启全局中断
   __bis_SR_register(LPM0_bits + GIE);

   //For debugger
   __no_operation();

中断服务函数

#pragma vector = TIMER0_A1_VECTOR//定时器中断
__interrupt void Timer_A(void)//生命一个函数为中断函数
{
  static unsigned int CNT = 0;

  switch(__even_in_range(TA0IV,14))//中断标志位——对应捕获通道
  {
    case 2 ://如果是CCR1产生的中断
        if(CNT % 2 == 0)//记录第一次的上升沿Counter计数值
        {
//            edge_count1 = Timer_A_getCounterValue(TIMER_A0_BASE);//将此时的上升沿计数值存入变量
            edge_count1 = Timer_A_getCaptureCompareCount(TIMER_A0_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_1);
        }
        else if(CNT % 2 == 1)//记录第二次上升沿Counter计数值
        {
            edge_count2 = Timer_A_getCaptureCompareCount(TIMER_A0_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_1);//将此时的下降沿计数值存入变量
            Timer_A_clear(TIMER_A0_BASE);
        }
        PWM_Frequency  = (unsigned int)(1600000/(float)(abs(edge_count1 - edge_count2)));
        //PWM_Frequency = 1600000/Timer_A_getCounterValue(TIMER_A0_BASE);
        //Timer_A_clear(TIMER_A0_BASE);
        break;
    case 4 : break;
    case 10: break;
    case 14:break;//此时发生计数器溢出
    default: break;
  }
  CNT++;

  // Enable global interrupt
  _BIC_SR_IRQ(LPM0_bits);
}

尤其注意中断服务函数中的最后一句话,作用大概是是能全局中断的同时退出低功耗模式,如果缺少这句话,会使得你的代码一直在跑中断函数,而无法跑主函数!别问我为啥知道,我试了一整个上午才解决!!!望各位避坑!

接下来就是进行测速了!

unsigned int V_detect(unsigned int FRQ)
{
    //我们测出的频率就是单位时间内的脉冲数
    //对应该编码电机轮子一圈产生4.5 * 12 = 54个脉冲
    //轮子半径 32.5mm
    unsigned int speed = 0;
    float circle = 3.141*2*0.0325;
    speed = (unsigned int)(((float)FRQ/54)*circle);

    return speed;
}

这样测速就完成啦!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

模块学习(一)——编码电机 的相关文章

  • PX4编写CAN应用程序控制底盘运动

    目录 一 在PX4平台中添加自己的应用程序 1 建立应用程序 Hello can c文件 xff1a Kconfig文件 xff1a CMakeLists txt文件 xff1a 2 编译应用程序及固件 3 测试应用 xff08 硬件 xf
  • PyCharm2021安装教程

    Windows安装PyCharm2021教程 一 下载安装PyCharm二 安装Python三 配置PyCharm环境四 使用PyCharm五 PyCharm简介 一 下载安装PyCharm 1 进入官网PyCharm的下载地址 xff1a
  • ROS学习(二)创建功能包

    在上一讲中我们已经创建好工作空间catkin ws xff0c 我们要在其src文件中创建功能包 文章目录 一 创建功能包二 编译功能包三 查看功能包的依赖3 1一阶依赖3 2间接依赖 四 定制功能包自定义package xml文件4 1
  • 双冒号(::)和单冒号(:)在 C++ 中的含义和作用

    目录 一 双冒号 xff08 xff09 在C 43 43 中的含义和作用 二 单冒号 xff08 xff09 在C 43 43 中的含义和作用 双冒号 xff08 xff09 和单冒号 xff08 xff09 在 C 43 43 中都是特
  • 【OpenCV教程】OpenCV中的数据类型

    文章目录 1 CV 8U2 CV 8S3 CV 16U4 CV 16S5 CV 16F6 CV 32S7 CV 32F8 CV 64F9 一图流 1 CV 8U CV 8U 占8位的unsigned CV 8UC n 占8位的unsigne
  • 【ROS教程】安装ROS全流程及可能遇到的问题

    文章目录 1 配置Softerware amp Updates2 添加软件源3 设置key4 更新并安装4 1 更新4 2 安装 ros noetic desktop full 4 2 1 安装aptitude4 2 2 安装ROS软件包
  • 【unix】unix环境高级编程

    文章目录 1 UNIX基础知识1 基本知识2 文件和目录3 输入和输出4 程序和进程5 出错处理6 用户标识7 信号8 时间9 系统调用和库函数 标准化和实现1 标准化 ISO C POSIX Single UNIX Specificati
  • 在 Ubuntu 中安装 VSCode

    在 Ubuntu 中安装 VSCode 如果想要通过 ubuntu 安装 vscode 有三种方式 xff0c 可以通过应用中心下载 xff0c 也可以通过安装包下载 xff0c 以及指令安装 方式一 xff1a 首先在 ubuntu 桌面
  • 常用命名规范分类:匈牙利命名法、下划线命名法、驼峰命名法、帕斯卡命名法

    目录 1 匈牙利命名法 xff08 Hungarian xff09 变量属性 2 下划线命名法 xff08 UnderScoreCase xff09 3 驼峰命名法 xff08 小驼峰命名法 xff09 xff08 Camel xff09
  • keil5无法跳转自己要查询的函数

    之前用keil5的时候想要查询函数的意思 xff0c 去跳转结果给我报错 xff0c 出现这个报错信息 原因是编译的时候没有勾选这个按钮 xff1a 勾选上之后重新编译就不会报错了
  • Linux 安装 Node.js | NPM

    超级简单 yum y install nodejs 验证安装 安装node js 会自动一起安装npm 注意 python V 是大写字母V 错写为小写会进入python的编辑模式 执行exit 退出 执行node 启动node终端 两次C
  • 树莓派连接不上WIFi,VNC失效,SSH失效

    笔记 xff1a 树莓派连接不上wifi的解决方法 xff1a 1 xff0c usb连接手机 xff0c 手机设置中搜索 xff0c usb共享网络 xff0c 然后代开usb连接网络 2 xff0c 右键树莓派wifi标志符 xff0c
  • C++中类的运算符重载教程(一),内附完整代码与解析

    目录 xff1a 一 xff1a 加号运算符重载 对 43 重载函数的理解 xff1a xff08 个人理解 xff0c 仅供参考 xff09 二 xff1a 左移运算符的重载 对 lt lt 重载函数的理解 xff08 个人理解 xff0
  • 关于ros中pcl_ros和ros链接问题Makefile:140的一种解决方案

    本人在ros学习pcl和slam过程中 xff0c 使用catkin make进行编译 xff0c 最终只报了错误Makefile 140和make j4 l4错误 xff0c 诸如此类错误 xff0c 多为链接过程出现问题 坑多日 xff
  • rosbag播放过程ctrl+z暂停后继续播放的方法

    rviz 43 rosbag播放暂停与继续播放 rosbag播放暂停的方式可以在rosbag运行窗口 space按键进行控制 该方法用于进程管理的学习扩展 问题描述 xff1a rosbag包播放过程ctrl 43 z暂停播放恢复播放方法
  • github上docker镜像创建容器

    docker介绍 三个概念 1 镜像 xff1a 类似于模版 xff0c 在没有添加实例化前不能使用 2 容器 xff1a 镜像实例化 3 docker xff1a 放容器的一个载体 总结 xff1a docker就像一艘船 xff0c 上
  • vi/vim基本命令

    目录 打开创建文档模式介绍显示行号增删改查光标移动文档操作 打开创建文档 span class token function vim span hello txt 打开已存在hello txt文档或者创建一个不存在的hello txt文档
  • 关于leetcode刷题详细介绍

    虽然刷题一直饱受诟病 xff0c 不过不可否认刷题确实能锻炼我们的编程能力 xff0c 相信每个认真刷题的人都会有体会 现在提供在线编程评测的平台有很多 xff0c 比较有名的有 hihocoder xff0c LintCode xff0c
  • leetcode:13罗马数字转整数c++

    思路分析 两种情况 1 不同的罗马数字都是从左到右依次相加 2 不同的就是末尾数是4和9的情况 xff0c 也就是IV VIV xff08 if xff09 代码框架 整体过程 从题目中字符和数字的对应关系 xff0c 不难想到数据结构un
  • leetcode:20有效的括号——stack

    思路分析 题目匹配的情况有两中 xff1a 和 xff08 xff09 匹配成功的思路是每个 或者其他右包围结构都是和最近的 或者其他左包围结构匹配 最近 匹配的思想应该使用stack结构对数据进行操作 代码框架 1 遍历整个string

随机推荐

  • leetcode:21合并两个有序连表——slist

    思路分析 链表 xff1a 头节点为空 xff0c 每个节点有一个指针 xff0c 指向下一个节点的地址 俩链表节点之间比较 xff0c 用遍历 96 96 for xff0c 因为是list xff0c 可以直接通过迭代器 xff08 指
  • leetcode:53最大子数组和

    思路分析 有2个变量是一直变化的 1 最大集合的第一个元素 2 存放最大的变量 0 变量初始化 span class token keyword int span res span class token operator 61 span
  • Ubuntu安装docker及出现问题解决

    Ubuntu安装docker及出现问题解决 文章目录 Ubuntu安装docker及出现问题解决一 安装docker二 解决docker安装成功后 xff0c docker命令无法正常使用的问题 一 安装docker docker的安装可参
  • stl大全

    什么是STL xff1f 大佬 xff1a 为什么C 43 43 比C更受人欢迎呢 xff1f 除了C 43 43 的编译令人感到更舒适 xff0c C 43 43 的标准模板库 xff08 STL xff09 也占了很重要的原因 当你还在
  • input 图片上传

    使用 在vue项目中使用input上传图片给后台时 xff0c 需要对图片文件流和请求头进行一些处理 1 获取上传图片文件流 span class token tag span class token tag span class toke
  • Unix环境高级编程代码(实时更新)

    实例1 3 列出一个目录中所有文件 xff08 ls c xff09 include 34 apue h 34 include lt dirent h gt int main int argc char argv DIR dp struct
  • ROS入门(二):launch文件解析

    ROS入门 xff08 二 xff09 xff1a launch文件解析 文章目录 ROS入门 xff08 二 xff09 xff1a launch文件解析一 launch文件的运行二 launch文件格式1 浏览顺序 xff08 Eval
  • RLException: [**] is neither a launch file in package [**] nor is [**] a launch file name,.......

    按照网上现有对这个问题的解决方法 xff1a 方法1 xff0c 在工作空间下source 方法2 xff1a 对其进行路径添加 这个问题的来源还有一种来源 xff0c 你得确定你在终端运行的这个launch文件名是否写对 xff0c 打开
  • Linux 安装node.js和npm教程

    第一步 xff1a 去node js官网下载安装包 或者直接 wget https nodejs org dist v10 15 0 node v10 15 0 linux x64 tar xz 第二步 xff1a 解压 tar xf no
  • could not establish connection to “hostname”

    解决方案 Try to delete the fingerprint a single line that corresponds to this particular connection not the whole file saved
  • 基于UCOSIII的环境检测项目

    基于UCOSIII的环境检测项目 运用STM32F103C8T6开发板为项目核心板 xff0c 并加入UCOSIII实时操作系统 在操作系统基础上 xff0c 搭配外围传感器实现基于STM32环境检测项目开发 主要运用库函数在操作系统基础上
  • 进程与线程

    进程与线程 讲线程之前要了解 xff1a 进程间的通信 xff08 Inter Process Communication IPC xff1a 理论上 xff0c 进程之间是独立的 xff0c 但实际上往往是多个进程之间的互相配合完成复杂的
  • STM32的八种工作模式

    一 模式介绍 STM32单片机具有高性能 低成本 低功耗的优点 xff0c 与它打交道就必须先了解它的几种工作模式 xff0c 它共有八种IO口模式 xff0c 分别是 xff1a 模拟输入 浮空输入 上拉输入 下拉输入 开漏输出 推挽输出
  • matlab学习笔记

    matlab笔记 上课期间自己整理的一系列matlab相关用法的笔记 xff0c 自认为也并不非常有条理 xff0c 但还是囤放在这里 xff0c 供需要的人查阅 取用 写在前面 help 43 函数名 xff1a 查找某函数的使用方法lo
  • 计算机组成原理——总线

    一 总线概述 1 xff0e 基本概念 xff08 1 xff09 总线简图 每个总线可能由很多根信号线组成 xff08 2 xff09 总线的物理实现 如上图 xff0c 4根信号线组成 一根 总线 xff0c 所有硬件部件都可以通过这根
  • 计算物理学复习笔记(一) 连续随机变量的抽样(直接、变换抽样,三类舍选法)

    文章目录 前言 前置知识一 直接抽样法二 变换抽样法三 舍选法1 第一类舍选法2 第二类舍选法3 第三类舍选法 总结 前言 使用教材 xff1a 马文淦 计算物理学 xff0c 限于篇幅 xff0c 这本书上部分知识写得并不十分详细 xff
  • Keil MDK配置ARM汇编/C语言混合开发环境

    Keil MDK配置ARM开发环境 1 安装Keil MDK 安装方法这里不再说明 xff0c 懂得都懂 xff01 x1f436 2 安装ARM开发包 在Keil MDK5之后 xff0c 不再原生支持ARM7 9 xff0c 需要自行安
  • ESP8266初学(一) 遇问题大全及解决方案(持续更新)

    最近开始学习wifi模块 xff0c 谁知一开始用PC连接调试wifi模块就遇到了很多问题 一 输入指令后没有反应 刚起步就头大 快乐地接好各种接口各种线 xff0c 连上电脑发现它冒蓝光光了 xff0c 好耶 xff01 然后兴致勃勃打开
  • PTA实验题:6-4 派生类的定义和使用 (10 分)

    按要求完成下面的程序 xff1a 1 定义一个Animal类 xff0c 包含一个void类型的无参的speak方法 xff0c 输出 animal language 2 定义一个Cat类 xff0c 公有继承自Animal类 xff0c
  • 模块学习(一)——编码电机

    想实现对电机的测速 xff0c 因此开始接触编码电机 此次采用的是RS365编码器电机 一 编码电机的初步了解 通过编码电机可以测出速度 常见一般编码电机分成两种 xff0c 一是光电编码器 xff0c 另一个是霍尔编码器 有六个接口 xf