嵌入式开发之编码器速度采集

news2024/10/6 9:38:22

 光电编码器,是一种通过光电转换将输出轴上的机械几何位移量转换成脉冲或数字量的传感器。这是应用最多的传感器,光电编码器是由光源、光码盘和光敏元件组成。光栅盘是在一定直径的圆板上等分地开通若干个长方形孔。由于光电码盘与电动机同轴,电动机旋转时,光栅盘与电动机同速旋转,经发光二极管等电子元件组成的检测装置检测输出若干脉冲信号,通过计算每秒光电编码器输出脉冲的个数就能反映当前电动机的转速。此外,为判断旋转方向,码盘还可提供相位相差90º的两路脉冲信号。根据检测原理,编码器可分为光学式、磁式、感应式和电容式。根据其刻度方法及信号输出形式,可分为增量式、绝对式以及混合式三种。

     增量式编码器是直接利用光电转换原理输出三组方波脉冲A、B和Z相;A、B两组脉冲相位差90º,从而可方便地判断出旋转方向,而Z相为每转一个脉冲,用于基准点定位。它的优点是原理构造简单,机械平均寿命可在几万小时以上,抗干扰能力强,可靠性高,适合于长距离传输。其缺点是无法输出轴转动的绝对位置信息。

        本应用采用增量式编码器进行速度和里程的精确测量,在软件设计上采用中断方式采集编码器输入的脉冲信号,本例的脉冲转一圈输出2000个脉冲。采用M/T测速原理,利用PIC32的定时器作为时间参照系,与采集的脉冲数一起进行比例运算,得出实时速度,并可以实现里程的累计预算。应用于实时测速和里程双测量的应用,大量应用于速度校正,里程计量,恒速控制等工业测量控制场景。

 

//************************************************************
//Copyright(C)2010
//					 编码器采样算法源文件
//文件名称:Encoder.c
//文件标识:(内参)
//摘    要:
//			1.配合头文件使用;
//			2.
//			3.
//
//当前版本:1.0
//作    者:xxd
//完成日期:2010.7.7
//
//取代版本:无
//原 作 者:无
//完成日期:无
//encoder  2000脉冲/每转
// |<------------M1--------------------------->|
// |----|    |----|    |----         |----|    |----|
// |    |    |    |    |    .........|    |    |    | 编码器脉冲
//_|    |____|    |____|             |    |____|    |
// |<-------------M2-------------------------->|
// ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||| f
// ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// M/T测速原理图

//采用脉冲捕获技术实现改进的M/T法对增量式编码器进行速度和角度的实时采集
//M/T法测速是表示同时测量一定个数的编码器脉冲和产生这些脉冲所花的时间,在
//整个速度范围内都有较好的准确性,但对于低速,该法需要较长的检测时间才能
//保证结果的准确性,无法满足转速检测系统的快速动态响应指标,原因为采样周
//期确定为产生M1个编码器脉冲的时间,随着转速升高,编码器脉冲频率变大,采
//样周期变小,相对误差就增大了
//        60f     M1
//    N=------ * ----
//         P      M2
//P-------->光电编码器每转的脉冲数 本编码器为2000
//M1------->光电编码器脉冲计数值
//M2------->时钟脉冲计数值
//N-------->转速
//算法改进:
//根据速度情况实时改变M1的值,速度降低则减少M1的值,以改善低速段测速的动态响应性能
//算法软件上采用在高速段增加M1值使采样周期基本不变。因而其相对误差也基本不变,在低
//转速段M1值可降到1,满足系统的动态响应要求
//采用PIC32MX捕获模块和两个定时器实现对输入脉冲的上升沿或下降沿和时钟脉冲准确计数,
//采样周期为10ms
//RC2,接入脚为DIN5,增量编码器输出脉冲接入本脚
//编码器脉冲上升沿触发捕获模块,并将直接计数TIMER3中的数字计数值,在1毫秒的系统时钟中断中
//以每10次计算一次速度
//********************************************************************************

#define  ENCODER_GLOABLE
#include "encoder.h"
#include "Evc300Control.h"

/* Private variables ---------------------------------------------------------*/
static INT16S hPrevious_angle=0, hSpeed_Buffer[SPEED_BUFFER_SIZE], hRot_Speed=0;
static INT8U bSpeed_Buffer_Index = 0;
static volatile INT16U hEncoder_Timer_Overflow=0; 
static BOOLEAN bIs_First_Measurement = TRUE;
static BOOLEAN bError_Speed_Measurement = FALSE;

/*******************************************************************************
* Function Name  : ENC_Init
* Description    : General Purpose Timer x set-up for encoder speed/position 
*                  sensors
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void ENC_Init(void)
{
  
  //Clear interrupt flag
    mT3ClearIntFlag();
    ENC_Clear_Speed_Buffer();
    // Setup Timer 3
    OpenTimer3(T3_ON |T3_SOURCE_EXT | T3_PS_1_1, ENCODER_TIMER_TICK);

   // set up the timer interrupt with a priority of 2
    ConfigIntTimer3(T3_INT_ON | T3_INT_PRIOR_3 | T3_INT_SUB_PRIOR_1);
    
    mT3IntEnable(1);    
/*
T3CON = 0x0; // Stop Timer and clear control register
T3CONSET = 0x0002; // Set prescaler at 1:256, external clock source
TMR3 = 0x0; // Clear timer register
PR3 = ENCODER_TIMER_TICK; // Load period register
T3CONSET = 0x8000; // Start Timer
mT3SetIntPriority(1);
mT3IntEnable(1);
*/
}
void ENC_Close()
{
   CloseTimer3();
}
/*******************************************************************************
* Function Name  : ENC_Get_Electrical_Angle
* Description    : Returns the absolute electrical Rotor angle 
* Input          : None
* Output         : None
* Return         : Rotor electrical angle: 0 -> 0 degrees, 
*                                          S16_MAX-> 180 degrees, 
*                                          S16_MIN-> -180 degrees
*                  Mechanical angle can be derived calling this function and 
*                  dividing by POLE_PAIR_NUM
*******************************************************************************/
INT16S ENC_Get_Electrical_Angle(void)
{
  INT32S temp;
  
  temp = (INT32S)(ReadTimer3()) * (INT32S)(U32_MAX / (ENCODER_PPR));         
  temp *= POLE_PAIR_NUM;  
  return((INT16S)(temp/65536)); // INT16S result
}

/*******************************************************************************
* Function Name  : ENC_Get_Mechanical_Angle
* Description    : Returns the absolute mechanical Rotor angle 
* Input          : None
* Output         : None
* Return         : Rotor mechanical angle: 0 -> 0 degrees, S16_MAX-> 180 degrees, 
                                            S16_MIN-> -180 degrees
*******************************************************************************/
INT16S ENC_Get_Mechanical_Angle(void)
{
  INT32S temp;
  
  temp = (INT32S)(ReadTimer3()) * (INT32S)(U32_MAX / (ENCODER_PPR)) ;
  return((INT16S)(temp/65536)); // INT16S result
}

/*******************************************************************************
* Function Name  : ENC_ResetEncoder
* Description    : Write the encoder counter with the value corresponding to
*                  ALIGNMENT_ANGLE
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void ENC_ResetEncoder(void)
{
  //Reset counter
  WriteTimer3(COUNTER_RESET);
}

             
/*******************************************************************************
* Function Name  : ENC_Clear_Speed_Buffer
* Description    : Clear speed buffer used for average speed calculation  
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void ENC_Clear_Speed_Buffer(void)
{   
  INT32U i;

  for (i=0;i<SPEED_BUFFER_SIZE;i++)
  {
    hSpeed_Buffer[i] = 0;
  }
  bIs_First_Measurement = TRUE;
}

/*******************************************************************************
* Function Name  : ENC_Calc_Rot_Speed
* Description    : Compute return latest speed measurement 
* Input          : None
* Output         : INT16S
* Return         : Return motor speed in 0.1 Hz resolution. Since the encoder is
                   used as speed sensor, this routine will return the mechanical
                   speed of the motor (NOT the electrical frequency)
                   Mechanical frequency is equal to electrical frequency/(number 
                   of pair poles).
*******************************************************************************/
INT16S ENC_Calc_Rot_Speed(void)
{   
  INT32S wDelta_angle;
  INT16U hEnc_Timer_Overflow_sample_one, hEnc_Timer_Overflow_sample_two;
  INT16U hCurrent_angle_sample_one, hCurrent_angle_sample_two;
  signed long long temp;
  INT16S haux;
  
  if (!bIs_First_Measurement)
  {
    // 1st reading of overflow counter    
    hEnc_Timer_Overflow_sample_one = hEncoder_Timer_Overflow; 
    // 1st reading of encoder timer counter
    hCurrent_angle_sample_one = ReadTimer3();
    // 2nd reading of overflow counter
    hEnc_Timer_Overflow_sample_two = hEncoder_Timer_Overflow;  
    // 2nd reading of encoder timer counter
    hCurrent_angle_sample_two = ReadTimer3();      

    // Reset hEncoder_Timer_Overflow and read the counter value for the next
    // measurement
    hEncoder_Timer_Overflow = 0;
    haux = ReadTimer3();   
    
    if (hEncoder_Timer_Overflow != 0) 
    {
      haux = ReadTimer3(); 
      hEncoder_Timer_Overflow = 0;            
    }
     
    if (hEnc_Timer_Overflow_sample_one != hEnc_Timer_Overflow_sample_two)
    { //Compare sample 1 & 2 and check if an overflow has been generated right 
      //after the reading of encoder timer. If yes, copy sample 2 result in 
      //sample 1 for next process 
      hCurrent_angle_sample_one = hCurrent_angle_sample_two;
      hEnc_Timer_Overflow_sample_one = hEnc_Timer_Overflow_sample_two;
    }
 /*   
    if ( (ENCODER_TIMER->CR1 & TIM_CounterMode_Down) == TIM_CounterMode_Down)  
    {// encoder timer down-counting
      wDelta_angle = (INT32S)(hCurrent_angle_sample_one - hPrevious_angle - 
                    (hEnc_Timer_Overflow_sample_one) * (4*ENCODER_PPR));
    }
    else  
*/
    {//encoder timer up-counting
      wDelta_angle = (INT32S)(hCurrent_angle_sample_one - hPrevious_angle + 
                    (hEnc_Timer_Overflow_sample_one) * (4*ENCODER_PPR));
    }
    
    // speed computation as delta angle * 1/(speed sempling time)
    temp = (signed long long)(wDelta_angle * SPEED_SAMPLING_FREQ);                                                                
    temp *= SPEED_RESOLVING;  //  resolution
    temp /= (ENCODER_PPR);
        
  } //is first measurement, discard it
  else
  {
    bIs_First_Measurement = FALSE;
    temp = 0;
    hEncoder_Timer_Overflow = 0;
    haux = ReadTimer3();       
    // Check if hEncoder_Timer_Overflow is still zero. In case an overflow IT 
    // occured it resets overflow counter and wPWM_Counter_Angular_Velocity
    if (hEncoder_Timer_Overflow != 0) 
    {
      haux = ReadTimer3(); 
      hEncoder_Timer_Overflow = 0;            
    }
  }
  
  hPrevious_angle = haux;  
 
  return((INT16S) temp);
}

/*******************************************************************************
* Function Name  : ENC_Get_Mechanical_Speed
* Description    : Export the value of the smoothed motor speed computed in 
*                  ENC_Calc_Average_Speed function  
* Input          : None
* Output         : INT16S
* Return         : Return motor speed in 0.1 Hz resolution. This routine 
                   will return the average mechanical speed of the motor.
*******************************************************************************/

INT16S ENC_Get_Mechanical_Speed(void)
{
  return(hRot_Speed);
}
#define PI 3.14159
#define S_PERHOUR   3600 //每小时的秒数
//nRollerDiameter直径单位毫米
float ENC_Get_Line_Speed(int nRollerDiameter)
{
   float fSpeed=0;
   fSpeed=((PI*nRollerDiameter*hRot_Speed*S_PERHOUR)/SPEED_RESOLVING)/1000/1000;//线速度公里每小时
  return(hRot_Speed);
}

/*******************************************************************************
* Function Name  : ENC_Calc_Average_Speed
* Description    : Compute smoothed motor speed based on last SPEED_BUFFER_SIZE
                   informations and store it variable  
* Input          : None
* Output         : INT16S
* Return         : Return rotor speed in 0.1 Hz resolution. This routine 
                   will return the average mechanical speed of the motor.
*******************************************************************************/
void ENC_Calc_Average_Speed(void)
{   
  INT32S wtemp;
  INT16U hAbstemp;
  INT32U i;
  INT8U static bError_counter;
  
  wtemp = ENC_Calc_Rot_Speed();
  hAbstemp = ( wtemp < 0 ? - wtemp :  wtemp);

/* Checks for speed measurement errors when in RUN State and saturates if 
                                                                    necessary*/  
  if (EVC300_State  == RUN)
  {    
    if(hAbstemp <=MINIMUM_MECHANICAL_SPEED)
    { 
      if (wtemp < 0)
      {
        wtemp = -(INT32S)(MINIMUM_MECHANICAL_SPEED);
      }
      else
      {
        wtemp = MINIMUM_MECHANICAL_SPEED;
      }
      bError_counter++;
    }
    else  if (hAbstemp > MAXIMUM_MECHANICAL_SPEED) 
          {
            if (wtemp < 0)
            {
              wtemp = -(INT32S)(MAXIMUM_MECHANICAL_SPEED);
            }
            else
            {
              wtemp = MAXIMUM_MECHANICAL_SPEED;
            }
            bError_counter++;
          }
          else
          { 
            bError_counter = 0;
          }
  
    if (bError_counter >= MAXIMUM_ERROR_NUMBER)
    {
     bError_Speed_Measurement = TRUE;
    }
    else
    {
     bError_Speed_Measurement = FALSE;
    }
  }//end if(state==RUN)
  else
  {
    bError_Speed_Measurement = FALSE;
    bError_counter = 0;
  }
  
/* Compute the average of the read speeds */
  
  hSpeed_Buffer[bSpeed_Buffer_Index] = (INT16S)wtemp;
  bSpeed_Buffer_Index++;
  
  if (bSpeed_Buffer_Index == SPEED_BUFFER_SIZE) 
  {
    bSpeed_Buffer_Index = 0;
  }

  wtemp=0;

  for (i=0;i<SPEED_BUFFER_SIZE;i++)
    {
    wtemp += hSpeed_Buffer[i];
    }
  wtemp /= SPEED_BUFFER_SIZE;
  
  hRot_Speed = ((INT16S)(wtemp));
}

/*******************************************************************************
* Function Name  : ENC_ErrorOnFeedback
* Description    : Check for possible errors on speed measurement when State is 
*                  RUN. After MAXIMUM_ERROR_NUMBER consecutive speed measurement
*                  errors, the function return TRUE, else FALSE.
*                  Function return 
* Input          : None
* Output         : INT16S
* Return         : boolean variable
*******************************************************************************/
BOOLEAN ENC_ErrorOnFeedback(void)
{
 return(bError_Speed_Measurement); 
}

/*******************************************************************************
* Function Name : ENC_Start_Up
* Description   : The purpose of this function is to perform the alignment of 
*               
* Input : details the input parameters.
* Output : details the output parameters.
* Return : details the return value.
*******************************************************************************/
void ENC_Start_Up(void)
{
    EVC300_State = RUN;
} 

/*******************************************************************************
* Function Name  : TIMx_IRQHandler
* Description    : This function handles TIMx Update interrupt request.
                   Encoder unit connected to TIMx (x = 2,3 or 4)
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
#ifdef USE_IRQ_MAC
void __attribute__( (interrupt(ipl1), vector(12))) BSP_TIM3ISR( void );
#endif
  void TIM3_IRQHandler(void)
  {
    mT3ClearIntFlag();
    if (hEncoder_Timer_Overflow != U16_MAX)  
    {
     hEncoder_Timer_Overflow++;
    }
  
  }


/******************* (C) COPYRIGHT 2008  *****END OF FILE****/

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

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

相关文章

spark和zeppelin认证不一致:Only one of --proxy-user or --principal can be provided

spark和zeppelin认证不一致&#xff1a;Only one of --proxy-user or --principal can be provided 如果配置principal认证方式&#xff0c;zeppelin走的是hadoop权限&#xff0c;如果配置proxy-user认证方式&#xff0c;zeppelin走的是当前登录用户的权限&#xff08;ranger控…

GitHub上cambel的ur3项目调试经验

按照https://github.com/cambel/ur3/wiki/Compile-from-source配置环境时&#xff0c;遇到以下问题&#xff1a; catkin clean时报错 [clean] Error: The current or desired workspace could not be determined. Please run catkin clean from within a catkin workspace or…

【学会动态规划】第 N 个泰波那契数(1)

目录 动态规划怎么学&#xff1f; 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 4. 空间优化 写在最后 动态规划怎么学&#xff1f; 学习一个算法没有捷径&#xff0c;更何况是学习动态规划&#xff0c; 跟…

MySQL 中索引是如何实现的,有哪些类型的索引,如何进行优化索引

MySQL 中的索引 前言 上篇文章聊完了 MySQL 中的锁&#xff0c;这里接着来看下 MySQL 中的索引。 一般当我们数据库中的某些查询比较慢的时候&#xff0c;正常情况下&#xff0c;一顿分析下来&#xff0c;大多数我们会考虑对这个查询加个索引&#xff0c;那么索引是如何工作的呢…

从零开始的前后端分离项目学习(前后端从零环境搭建)

一、 前后端分离介绍&#xff1a; 前端独立编写客户端代码&#xff08;用户交互数据展示&#xff09;&#xff0c;后端独立编写服务端代码&#xff08;提供数据处理接口&#xff09;&#xff0c;并提供数据接口就行。 前端通过Ajax访问后端数据借口&#xff0c;将model展示到…

使用VESD脉冲离子风机5年内至少可节省一半的维护成本

之前的文章有给大家详细介绍过&#xff0c;来自VESD的脉冲离子风机&#xff0c;它有着特殊的设计&#xff1a;插拔式结构和可水洗针架&#xff0c;因此对我们的很多客户来说&#xff0c;这款风机性价比是非常高的。 早在15年以前&#xff0c;VESD就对市面上大部分风机进行过测试…

解决Google浏览器网页覆盖问题

在使用 Google 进行搜索的时候出现打开新页面会覆盖当前页面的问题 针对此问题&#xff0c;解决方法如下&#xff1a; 1、首先在浏览器的地址栏中随便搜索内容 2、页面的 右上角有个⚙️的设置图标&#xff0c;点进去 点击 “查看所有设置” 3、在结果打开方式中进行勾选 设…

uniapp打包APP实现应用内整包更新或热更新

思路&#xff1a; 1.首先要理解更新方式的区别 静默更新、弱更新以及强制更新。 APP更新机制-静默更新、弱更新、强更新 - 知乎 2.其次要理解不同更新方式要用到的插件----------这里推荐插件应用市场的插件。 app升级、整包更新和热更新组件 支持vue3 支持打开安卓、苹果应…

使用 SMT求解机 根据变迁关系生成迁移后系统的状态

本文的例子来源于2011年发布的论文 IC3: Where Monolithic and Incremental Meet 文章目录 Ⅰ、变迁系统的介绍状态图变迁公式 Ⅱ、SMT求解机简介公式的计算计算另一状态 结果展示参考文献 Ⅰ、变迁系统的介绍 状态图 论文中给出了一个系统的状态迁移图和它的的变迁公式。现在…

【近场社交项目】数据库系统期末设计——概念设计部分

数据库系统期末设计——概念设计部分&#x1f60e; 前言&#x1f64c;项目设计&#xff08;1&#xff09;各个实体属性ER图&#xff08;2&#xff09;各个业务功能的ER图 总结撒花&#x1f49e; &#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢的座右铭&#x…

【Redis】特殊数据类型 Geo (地理位置)

&#x1f3af;前言 除了五中基本的数据类型外&#xff0c;Redis还支持两种特殊的数据类型&#xff0c;第一种 Geo (地理位置)&#xff1a;用于存储地理位置相关的数据&#xff0c;例如经纬度、距离等。第二种 Stream (流)&#xff1a;是一个高级的列表类型&#xff0c;支持对列…

Python基于pandas库导出excel文件

将Pandas数据框架导出到Excel文件中 让我们看看如何将Pandas数据框架导出到Excel文件中。 实列代码&#xff1a; import time import pandas as pd from io import BytesIO from flask import make_response,def export_navi():# 所有DataFrame合并集合df_list []# 创建一个数…

理工大学|校企联手创典范,布局存储新未来

某理工大学地质灾害防治与地质环境保护国家重点实验室的前身是1989年由原国家计委、国家教委批准&#xff0c;在某理工大学&#xff08;原某地质学院&#xff09;“地质工程”国家重点学科基础上建立的国家专业实验室&#xff0c;该实验室是我国地质灾害防治领域目前唯一的国家…

唯一无副作用禁用Win10/11更新方法,一键暂停1000周

作为一个现代化的系统&#xff0c;Windows 很早便配备了自动更新功能以快速获取新功能、修复安全漏洞。 不过到实际使用中嘛&#xff0c;自动弹出、重启自动进行、新版本大量 Bug … 体验十分糟糕。 种种原因导致&#xff0c;经常就有朋友要禁止 Win10/11 自动更新方法。 我们…

MySQL-存储函数练习

创建表并插入数据 ​ 字段名 数据类型 主键 外键 非空 唯一 自增 ​ id INT 是 否 是 是 否 ​ name VARCHAR(50) 否 否 是 否 否 ​ glass VARCHAR(50) 否 否 是 否 否mysql>…

vue项目启动前端时让本地局域网其他设备访问本项目时的配置

文章目录 编辑package.json优化 编辑package.json "dev": "vite --host [本机ip]" ,案例 优化 这样的话实用性更好&#xff0c;我们访问的话依然可以正常访问服务端的ip "dev": "vite --host 0.0.0.0" ,

Kylin麒麟系统设置开机自动登录roo账户

1.安装麒麟系统后&#xff0c;默认root用户是不开启的&#xff0c;首先得设置root用户密码命令。 sudo passwd root 此时会要求输入密码&#xff0c;输入您当前用户登录密码即可。 2.以root权限修改 /usr/share/lightdm/lightdm.conf.d/60-kylin.conf 文件,如提示输入密码&am…

itheima苍穹外卖项目学习笔记--Day1:项目介绍与开发环境搭建

苍穹外卖 Day1:a. 项目概述b. 开发环境搭建(1). 前端环境搭建(2). 后端环境搭建(3). 前后端联调 c. 完善登录功能d. Swagger Day1: a. 项目概述 b. 开发环境搭建 (1). 前端环境搭建 前端工程基于 nginx 运行启动nginx&#xff1a;双击 nginx.exe 即可启动 nginx 服务&#x…

用C语言进行学生成绩排序(简单选择排序和对堆排序)

一.选择排序 选择排序的基本思想是:每一趟(如第i趟)在后面n-i1 (i1,2…,n-1) 个待排序元素中选取关键字最小的元素&#xff0c;作为有序子序列的第i个元素&#xff0c;直到第n-1趟做完&#xff0c;待排序元素只剩下1个&#xff0c;就不用再选了。选择排序中的堆排序算法是历年考…

IDEA配置Maven教程

IDEA配置Maven教程 &#x1f495;1、mavne的下载&#x1f495;2、maven的安装&#x1f49e;3、配置Maven环境变量&#x1f49e;4、配置 Maven 本地仓库存放路径&#x1f496; 5、settings.xml配置&#xff1b;&#x1f496;6、IDEA配置maven&#xff1b;&#x1f496;7、清理下…