绝对值编码器:从调研到开发

前言概述

最近因为工作需要,接触到了一个全新的领域就是编码器采样模块的开发,在接触以前或多或少接触了一些运动控制的知识,但是对于编码器本身的内容还是,一窍不通的。所以在这段开发过程中我将一些自己遇到的困难,有关于技术层面的,但是更多的还是,如何将一个我们用户使用的应用层体验转化为一个纯技术开发的这样一个过程,将这些的困难和解决过程记录下来。
对于一个完全陌生的领域,如何一步步地迈入到了解,深入研究和分析实际应用,最终将他们转化为一个开发者脑海中的蓝图与构思,最终付诸实现,这样一个完整的过程,总结其中的思路变化和探索方式,我相信对很多其他的项目开发也都是有益处的。
本文将涉及到产品的实际应用,代码开发层,硬件上的设计对开发的要求,剖析编码器本身,与友商的成熟产品的分析,甚至是与编码器厂商的斗智斗勇都会涵盖到,写的不好与不够严谨的部分请多包涵,不论如何,祝大家,大年初一生活愉快,新年快乐。


文章目录


一、调研阶段

信息的收集重要性是毋庸置疑的,只不过在我这个单独的项目经验来说,就显得比较坎坷。至于为什么是坎坷的,首先公司里没有提供太多可参考的资料,有一份以前(准确的说是十多年前的代码)做定制的产品的代码,也是做的编码器读取模块,但是对于一个对编码器都尚不清楚的人来说,看着这种代码的感觉就是,每一行都看懂了,但又看不懂他写了个啥,直接移植过来呢,这个旧产品已经没有生产了,代码也没人维护,想跑起来看看什么情况都不可能,更何况CPU也更换了,直接移植恐怕比我新写一份代码要花的精力还要久,而且极大可能还整进来个半生不熟的知识在我脑袋里,所以我干脆就计划全部推翻,从零开始建设这个项目,好在开发的周期并不紧张。

调研阶段的第一件事就是搞清楚,什么是编码器?

随即打开各类网站检索关键字,
绝对值编码器:从调研到开发
然后就是众多我当时看不懂的内容扑面而来,那种感觉就像以前上课老师直接抛了一个“paradigm”单词,然后根据这个单词写一篇论文一样吃了屎的难受。由于CSxN是一个比较偏技术的论坛,所以在这个阶段我在这里找一些了解编码器应用的文章其实不太合适,这里都是一些如何使用或者分析编码器类型的文章更多,于是调转方向,先去度娘那里搜罗了一圈,编码器是什么样的场景。
绝对值编码器:从调研到开发
结果毫不意外,清一色的广告占据前言,受益于导师教会我的第一个社会经验,我开始了我的首次liar角色扮演历程。百度提供的这么多供应商我也不能白白浪费资源了,于是我开始登录这些网站,一开始的时候比较羞涩,我直言相告我正在开发一个产品会用到这些编码器,想咨询一下编码器的使用环境等一些细节内容,有的厂商会毫不避讳的告诉你一些细节,当然我受到的更多的是比较平淡和冷漠的对待,毕竟大家都是出来做生意的,谁也不想浪费时间,不过在这一点上大厂商尤其是进口厂商做的确实很好,技术支持和销售都十分热情,毫不吝啬地提供各类资料以及微信沟通告诉我有些特性在场景中是如何应用的,需要注意什么。在一开始的碰壁之后,我开始调整了一下我的严谨liar身份,于是我开始转换了下我的话术,在之后的沟通中我直接报家门,然后说我的项目中需要采购编码器部件以及使用在我的实验室当中,虽然带一点欺骗但是我说的确实是实话,只不过买谁的就是后话了,在这个过程*应商十分积极主动,都希望达成长久的合作,然后开始获得越来越多的帮助,只不过这当中有一个更为严重的问题,那就是他们都不是开发和实施人员,能得到最好的支持也只能局限在编码器开发者的支持了,至于上层的使用方法和环境其实并不是他们所关注的内容,这很无奈。

在咨询完厂商以后,我需要一些来自现场真正使用这些编码器的经验,但毕竟我们是天天坐办公室的研发,更是一个入职短时间的工程师,所以在经验上很缺乏,但好在之前在实验室工作过程中结识的公司工程部的同事,他们在工厂实施项目中或多或少接触过一些编码器的使用及变频伺服电机的使用。

不论在咨询谁,开发者都需要了解被采访者的思路,供应商提供的建议是站在他的角度,工程同事的意见也是围绕实际应用,但是如何将这些信息筛选出适合研发人员的代码结构,是十分重要的环节。

有了这一段信息的收集,我大致明白了我的核心问题:

“起点 与 终点”

作为一个电子工程师,我们所围绕的问题一直在于“如何使用”,所以“起点”问题就在于怎么用编码器,“终点”问题就是用编码器干什么。
搞清楚什么是编码器的核心就是:读取位置,反馈位置这个问题之后,就要进入更深入的调研,也即是第二个问题,编码器的选型。
关于选型这个事情,对于我们本身开发的模块来说其实没有那么重要,开发嘛就是来什么干什么就对了。但是在这里我的导师引导我了一个思路,或者说是一个更实际的问题:

如果有一天一个客户问道,他们想要一个编码器读取模块,那么我是否需要了解对方使用的实际编码器才能给他们使用,或者说我该问客户关于编码器的什么参数,来判断我的产品是否可以满足客户的需求呢。

围绕这个什么样锅可以炒这碗饭的问题,我需要做出对应的编码器选型工作,这也是最令我头疼的问题,毕竟选型的第一步就是要知道那些参数的含义,而不同的厂商说明书上的参数表达的方式并不一致(比如调零设置的也有叫SET的),有的甚至没有一些参数(比如可靠数据产生时间),那么首先要搞懂这些参数的含义就显得十分重要,此外也要知道为什么有的参数在一些厂家中没有被罗列出来,是不重要还是不具备,又或者是小厂商的遗漏等诸多问题。
撇开这些参数不谈,光光是编码器的分类估计就让人几近崩溃了,光电编码器,绝对值编码器,BISS编码器,电容式编码器,增量编码器,磁电式编码器,差分编码器,正交编码器等等数都数不清楚的名词,再加上之前我接触过的伺服电机,步进电机,脉冲输出模块等等更多的名词在短期内涌入,很容易让自己陷入泥潭而放弃。
好在互联网是强大的,加上同事的帮忙,我大致将编码器的类型都整合出来,市面上的很多命名的方式虽然复杂,但是他们都遵循一个特征:

// “信号采集原理” + “数据可否记忆” + “通信原理” + “分别率”+ 编码器

举个例子, 光电式 绝对值型 SSI 4096 编码器, 也就是本文的主题编码器。这是这个编码器的全名,但是在沟通过程中和实际销售过程中一般我们会直接简化掉,就说是SSI编码器,因为用户在选购中会侧重考虑我一定要SPI通讯的接口,接下来才会考虑他的分辨率和绝对值的特性,当然这两个参数也非常关键,至于他的信号采集原理,一般光电式会比较多,但是当用户考虑这个因素的时候,也一定会考虑使用环境的影响,当出于环境的考虑,那么我们就会接触到光电式的或者是电容式的这一类的名词了。
简而言之,许多命名都为了方便实际需求而存在,虽然对初入门者不太友好,但是了解了以后也就理解了,所以经验十分重要的一点也体现在这里,融会贯通是一门很深的艺术。

搞清楚前两个问题,需要调研的就是最后的,编码器的实际用途是什么。

我们可以很容易的说出,编码器的唯一工作就是读取并反馈当前位置,但是这又有什么应用场景呢,通过调研我简单描述几种可能存在或实际存在的场景。

  1. 工业机器人的位置控制。不同的工业机器人有三轴的,六轴的等等,形象的理解就相当于人类的肘关节,这些关节转动多少的幅度是需要被读取的,这也是编码器的工作内容之一。有了精确的位置读取,这就能提供更高精度的机械臂运动轨迹,所以在这一领域应用的更多的是绝对值编码器,毕竟它能实现掉电保持位置记忆的功能,不然谁也不知道重新上电后的机械臂会把自己的位置记录成什么了,所以绝对值型和增量型的区别在这里显得尤为重要。
  2. 工业流水线的位置锁定。工业化的流水线生产在每个环节中都要特定的事情要做,但是如果运行的位置不够准确,比如一个易拉罐封装,位置没运行到就执行了封装(当然皮带上也会有稳定的结构件保护)。
  3. 最广泛的测距使用。大型设备之间的距离测量,一般在设备之间都是通过一定的机械结构实现拖拽,但是在我们一些电机的控制中,由于存在摩擦和机械结构的影响,其实是很难做到我们要求电机转动1000个脉冲,电机就能转动1000个脉冲的角度的,
    或多或少会存在偏差,甚至在电机正反转的时候也会有一两个脉冲的丢失也属常见,所以在这个阶段需要编码器绕过电机,直接在运动的轴上读取实际的旋转角度就显得尤为重要。
    以上几种情况对于编码器而言都是一种操作,叫做限位开关。

有了调研的结果,就可以一步步展开项目的实施了,但是依旧会有一些疏漏在过程中进行修正,但大致的方向应该不会有错。

二、编码器分析

1.编码器种类

绝对值编码器:从调研到开发
编码器在他的本身来说有很多不同的种类,以上我对总体上的编码器做出了分类。对于编码器这个宽泛的概念来说,他的核心功能只有一个,那就是读取位置或者是读取角度,其他的很多分类就是要考虑实际使用的环境,以及价格这种经济参数。除此之外编码器的分类就很多了,根据采集信号的原理可以分为光电编码器,电容型编码器等等,这主要取决于编码器内部构造(信号转换模式)的原因,有的是通过光电转换,当然这也是最常用的,也有的是电容,不同的材料和结构设计也造成他们的适用场景和环境容错率(比如电容类型的不适宜一些有强磁环境)有不同。

https://blog.csdn.net/best_xiaolong/article/details/108525563?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164370152816780265493037%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=164370152816780265493037&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-2-108525563.pc_search_result_control_group&utm_term=%E7%94%B5%E5%AE%B9%E7%BC%96%E7%A0%81%E5%99%A8&spm=1018.2226.3001.4187

(这里有一篇我认为写的非常不错的博客, 详细阐述了不同材料特性设计原理的编码器各种特性以及他们的原理)

除了材料还有绝对值型编码器和增量型编码器,他们的区别主要在于,能否做到“掉电保持”,绝对值的编码器及时掉了电也能在重新上电后从上一次的记录开始计数,但是增量型的编码器重新上电后一切就归零了。而SSI编码器就是绝对值型编码器中的一员,“SSI”表示的是它的硬件接口,采用motorola的SPI总线,采用差分信号的方式,这个特性和编码器本身关系不大,只是一个通讯方式的定义,所以可以理解成SSI光电绝对值编码器通过光电方式计数,将获得的脉冲数记录在编码器自身MCU中,然后这个MCU通过SSI串口与我们开发的编码器模块MCU进行通讯,告知我们那个脉冲数(即位置值)。

简而言之,举个形象的例子,编码器材料的不同决定了我们在什么样的餐厅吃饭,绝对值和增量型则决定我们点餐时是否需要参考大众点评的记录(是否记录上次值),SSI与BISS或其他接口协议则决定我们是用勺子还是用筷子,最后的我们吃的是加工过的米粉(格雷码)还是没加工过的米饭(自然二进制码),虽然种类众多,但是归根结底,我们的目的就是只有一个,那就是吃饱(读取位置值)。

2.编码器功能

编码器本身的功能,根据不同的厂商在设计上有些许的差异,但是基本万变不离其宗的有以下几种,这里我将引用两种我实际开发过程中使用的编码器产品,上海了淼绝对值编码器与SICK的绝对值编码器,感谢两家厂商在我调试过程中提供详细和耐心的答疑及技术支持。

从产品自身来说,主要有以下几个功能和参数是我们开发者最为关心的:

通讯方式:SSI格雷码/二进制码
波特率:决定通讯速率
分辨率:决定编码器的精度
机械圈数:决定编码器的转动范围(有的编码器表达方式不同)
零位功能:初始点的配置
方向功能:旋转步序的配置
位置数据生成时间:编码器自身在上电后生成数据的时间要求
供电电压:工作供电范围电压值

以上是我们开发者比较关心的几点,但是作为用户还有工程实施方,还需要参考其他一些关于机械参数,电气特性及环境参数,包括联轴器的直径,法兰尺寸,扭矩等参数还需要结合被测量电机设备的参数进行复核分析和选型。

3.编码器接口分析

了解完编码器的一些基本功能后,就需要了解,假设我这个时候已经开发了一个读取编码器的产品以后,该如何与编码器接线匹配,引用我开过过程中的实际产品,翻阅他们的手册得知一些关于引脚分配的描述如下:
绝对值编码器:从调研到开发
以上是SICK这款编码器引脚分配与描述图。根据配置,需要的引脚主要是:

Pin1, PIN8用于供电的正负极;
Pin3,11为差分的spi_clk信号,Pin2,10为差分的spi_data信号;
Pin9为调零功能脚;
Pin12为旋转方向脚;

在这里不难发现,编码器spi是通过差分的方式接入,所以在硬件设计上需要加一个差分转单端的电路,此外我们观察到他的调零和旋转方向脚都没有单独提供GND,所以可以推断编码器厂商建议与供电侧供地就可以了,由于我们做不到拆解编码器的能力,所以没办法断言内部一定是做了隔离,咨询了另一个国产的编码器厂商,告诉我他们是没有做隔离的,而且行业中也不太做隔离,所以在这里我大胆地以“共地“的结论来做设计,实际证明确实是可以共用一个GND的。

三、设计模块与分析

1.探索友商

以上的分析主要是围绕着SSI编码器自身,归根结底,我们要设计的是一款读取SSI编码器并执行其他动作的一个复合型模块。所以我还需要了解这样一个复合型模块在实际现场和历史中,承担了什么样的角色。历史总是惊人的相似的,于是我找到了业界大佬,西门子的某款综合型编码器读取模块的说明书:

绝对值编码器:从调研到开发
全篇560多页的说明书就真的离谱,但是大厂的说明书真的写的非常详细,不难找到其中我们需要的信息。

绝对值编码器:从调研到开发
如图所示,西门子这款模块除了我们读取数据的功能外,给每个通道配置了2路DO(数字量输出)和2路DI(数字量输入)。

不难理解,DO是作为终结信号的使用,当位置运动到了比如1000米的时候,本模块会控制DO控制电机不再转动了。那么为什么是2个DO,和2个DI,当然也有很多设备是会给出比较多的接口,用来做一些拓展的工作,或者是预留的接口,也是存在这种可能的。但是这个问题的真实答案,对于并未接触现场实际应用的开发者来说,或许有些许困难,至少对我来说,我无法完全肯定。

通过询问一些编码器厂商和我的工程小伙伴,我了解到,编码器的应用算是比较多的,他们的应用方式大差不差可以总结成,DO确实有一路用作控制电磁阀来启停一段运动控制,DI的话则用来作为一种开始信号的起点,但是并不会都使用这种DI,更多的是上电后,配置好方向和调零后就默认开始运行了,但是有的DO会用作多种动作的复合开关,举个例子,在一个2关节的机械臂中,第一段关节在转动90度的时候需要控制关节1停止,同时呢让关节2开始运动,这时候就需要2个DO的单独控制电磁阀了。

还有一种使用场景,就是之前我们介绍到了两个编码器的功能,一个是调零,一个是方向设置,他们都是需要一个高电平或保持高电平来控制的,这个DO就可以用来控制他们了,也是比较常用的方法,只不过有点浪费这1个高速DO了。总之用法比较多,对于嵌入式开发者来说,只需要将他们加入到我们的设计当中就可以了。

2.设计模块

有了大概的构思,可以做出我们自己模块的功能构思了。

硬件:
1. 需要一个5V差分转单端,用于编码器的差分信号到CPU侧;
2. 需要24V供电电路,用于给编码器供电;
3. 需要至少2路DI和2路DO用于外部控制与采集额外DI信号;
4. 以及其他硬件上设计。

对于本模块特有的,硬件上的设计大概是这样,其他的根据业务需要来增删就可以了。

嵌入式软件:
1. 将DO设成一种脱离上位机控制的连锁输出,即高速输出;
2. 控制24V供电的开关配置;
3. 控制DO使能的开关配置;
4. 配置多圈或单圈的解码;
5. 配置编码器的单圈或多圈的位数;
6. 配置SPI通讯并定期通讯,每路spi只能对应单个SSI编码器;
7. 根据原始码类型进行数据转换(可以直接为数值,也可以分解成圈数+圈值);
8. 根据位置值与目标值判断,对DO的控制输出;
9. 根据DI的触发条件,控制全局功能的运行(不是必须条件);
10. 根据命令控制步序的方向控制与调零设置(可通过DO);

对嵌入式来说,将DO设置成高速输出的含义是,区别与一般的上位机控制DO输出的方式,省略掉总线上的时间,因为对于采集SSI编码器的核心功能就是高速反馈,将所有的逻辑处理都归于MCU内,读取数据,判断条件,控制DO即可输出,这样可以规避掉反馈上位机以后的总线上的时间,基本来说响应时间只受限于通讯配置的波特率,做到高速即时。
然后添加一些自己需要的诊断内容就可以了。

四、单元调试

有了整个构思和产品的完整回路设计后,就可以开始进行单独的调试了。

1.配置SPI

我用的是M0的内核,一款低成本的芯片,同样先选择SICK这款的编码器进行尝试,调通后再对其他国产的编码器进行测试与调试。

2.查阅芯片手册

绝对值编码器:从调研到开发
看下芯片手册,找到PC4~7都是spi的通用接口,我们只用到了PC7和PC6两个引脚,这是Motorola spi的特性,一般来说spi的4个脚为以下:

SCLK:串行时钟,用来同步数据传输,由主机输出;
MOSI:主机输出从机输入(Master Output Slaver Input)数据线;
MISO:主机输入从机输出数据线;
SS:片选线,低电平有效,由主机输出。

那么为什么有一些没用到,通过观察和阅读一些资料,就像我们之前看到的编码器引脚图,

绝对值编码器:从调研到开发
通常编码器他自身并不存在片选脚,这也就是说,我们在做通讯的时候只能做到1对1的主从通信,spi的总线功能实际上是被抛弃,那么也就不存在MOSI的数据线,换句话说我们的通讯过程就是,主机MCU发出定量CLK的读数据信号,从机编码器就会通过MISO反馈给出数据信号,没有了拉片选的这些动作,确实简化了功能但也浪费了总线。
代码如下(示例):

void InterfaceInit_SsiChn(void)
{
	/*ssi chn0 配置*/
		EnablePeripheral(CLK_0_PORT, CLK_0_PIN, FUNC_ALT_1);
		EnablePeripheral(DATA_0_PORT, DATA_0_PIN, FUNC_ALT_1);
		EnablePeripheral(MOSI_0_PORT, MOSI_0_PIN, FUNC_ALT_1);//未使用
		EnablePeripheral(nSS_0_PORT, nSS_0_PIN, FUNC_GPIO);//未使用

		spi0.DeviceID 	     = SSP_0;
		spi0.ClockRate 	  = RATE_115200;
		spi0.ClockPolarity  = HIGH;	//SPI 控制器使总线时钟在两帧传输之间保持高电平,主设备的时钟极性应该与从设备相反
		spi0.ClockPhase  = CPHA_SECOND; 	//控制器在帧传输的第一个时钟跳变沿捕获串行数据
		Spi_Initial(&spi);//

}

3.GPIO调试

以上是配置标准spi的过程,在这之前我用最朴实的GPIO方式也调过一段通讯,当初是为了验证编码器的一些功能,比如波特率以及clk信号数量对编码器的要求。
由于是GPIO模拟SPI通讯,所以我还不具备差分转单端的电路模块,就直接拿了一个以前做的5V高速脉冲输出模块来调试。
一共四根线:

Wire1 连接输出高速脉冲通道+与SSI编码器的CLK+
Wire2 连接输出高速脉冲通道-与SSI编码器的CLK-
Wire3 连接SSI编码器的DATA+与示波器,此外将示波器GND与编码器GND相连(只看趋势的话也可以不连)。
Wire4连接SSI编码器的DATA-与示波器,此外将示波器GND与编码器GND相连(只看趋势的话也可以不连)。

接线完成,就可以测试一下了,我的这个高速脉冲模块是可以调频和定脉冲个数输出的。
测试对象1:设置输出脉冲(模拟spi的波特率)的频率为1kHz,10kHz的时候,示波器抓不到任何信号。当设置到100kHz的时候,示波器可以抓到如图的信号了。
绝对值编码器:从调研到开发

放大示波器,看下每帧的间隔
绝对值编码器:从调研到开发
10us正好对应到我们设置的频率100kHz,也恰好验证编码器的反馈符合spi的通信速率原则。
回到SICK这款编码器的使用手册,我们可以看到,他其实对波特率还是有要求的。
绝对值编码器:从调研到开发
编码器产品手册中只提到了该款编码器可以支持的最大时钟频率,小于2 MHz,但是并没有给出实际下限,于是找寻了一些其他厂商的SSI编码器说明手册,其中有大多数都提到了支持的时钟频率100kHz是作为最低频率要求,如图为上海时易某款编码器:

绝对值编码器:从调研到开发
同时比对西门子SSI编码器的组态说明,大多数编码器模块的时钟频率配置下限都是100k或125k左右,一方面在线缆通信中有要求,另一方面算是通用行规。

OK,现在证实了编码器确实对通信速率有一定要求,不能过低,但是对CLK数量是否有要求呢,比如一个33位的SSI绝对值编码器,如果只发出了10个时钟信号的时候,编码器能否正确反馈值。

测试对象2:时钟信号数量对编码器的影响;

经过实际测试,当发出信号(10bits)远远少于编码器的位数(33bits)时,data线上没有任何反响,当增到接近33bits后,会产生data但是并不完整。

当发出的信号数量大于33bits或要求的位数时,是可以正常反馈data信号。
换句话说,只要满足我们spi通讯过程中的读取位数一定要大于编码器自身的总位数(有的编码器有err位,可以不包含)。
绝对值编码器:从调研到开发
以上图为例,他是包含了单圈数和多圈数,所以只要发出33个以上时钟信号,就可以正常读取数据,至于这个err位的数据是否要使用,根据调研,很多厂商的编码器并不包含这些错误位的信息,所以应该可以认为是不属于通用信息的组件信息了。

4.读取SPI数据

使用spi的方式读取,就是普通的方式,这里我就略过了。
但是需要检验下读取的数据与波形是否正确,
绝对值编码器:从调研到开发
确认调试端可以读到数据,再去重新抓取波形
绝对值编码器:从调研到开发
波形正确。

5.转换码值

通过上一步,我们可以得到一个原始的码值,这个码值可以是二进制码,也可以指格雷码,看具体的编码器说明书中描述的情况而定,不过在软件设计中是需要考虑进去并加入上位机的配置。这里我以格雷码为准,将格雷码转换为我们需要的单圈值与圈数值。
绝对值编码器:从调研到开发
由于上一步我读取出的数据实际是存在一个数组,每八位相伴,但是实际圈数是例如上图的,12位多圈值,18位单圈值,还有3位的err值,为了做到通用的编码器读取模块,我们需要对任意n位多圈,m位单圈值(其中n+m<=40)都做到支持读取与正确的转换。

实际操作和调试,只要按照手册的高低位顺序,将数据转化为二进制码就可以了。难度并不大,但是需要摸索下。
代码如下(示例):

void Data_process(U8 *pData,U8 DeviceID)
{
Singletunrs_startBits	= Singleturns_StartBit;	//获得单圈起始位
		Singletunrs_nums 		= Singleturns_BitLen; 	//获得单圈位数
		Multiturns_startBits	= Multiturns_StartBit;	//获得多圈起始位
		Multiturns_nums 		= Multiturns_BitLen;		//获得多圈位数
		ERR_startBits			= Err_StartBit;			//获得错误码起始位(处于32位内的err位)
		ERR_nums 				= Err_BitLen;			//获得错误码位数(处于32位内的err位)
Sourcecode = ((pData[0]<<24)+  (pData[1] << 16)+ (pData[2] << 8) + (pData[3]<<0)); //原始码整合(格雷码)
Sourcecode = Decimal(Sourcecode);转成二进制码

//获得单圈格雷码处理
	Graycode_Single = Sourcecode_Gray <<(Singletunrs_startBits); //向左,以单圈起始位,将多圈值清除
	Graycode_Single = Graycode_Single>>(Singletunrs_startBits) ;//向右,移位恢复
	Graycode_Single = Graycode_Single>>(32 -(Singletunrs_startBits +Singletunrs_nums ));//单圈起始位加单圈位长度即32位中右侧空间,
																						//获得仅单圈值的格雷码值

	//获得多圈格雷码处理
	Graycode_Muilti = Sourcecode_Gray <<(Multiturns_startBits);
	Graycode_Muilti = Graycode_Muilti >>(Multiturns_startBits);
	Graycode_Muilti = Graycode_Muilti >>(32 -(Multiturns_startBits + Multiturns_nums));

	//获得单圈二进制码处理
	Result_Signleturns = Graycode_Single;//20220107
	//获得多圈二进制码处理
	Result_Multiturns = Graycode_Muilti;

}

对于格雷码和二进制码,为什么会产生两种不同的码类型,查阅资料和网上帮助,根本原因也是和使用差分spi一致的,为了减少数据的错误。格雷码在每次数据发生变化时只会变化1个位,但是二进制码会产生多位变化的可能,相对来说不够安全可靠。增加说一点,差分信号的目的也是为了减少长线缆与信号传输过程中的其他干扰产生的影响。

通过上述方法,可以满足如下情况任一:
只含有单圈值的。
只含有单圈值和多圈值的。
包含单圈值和多圈值及错误位的。
任意满足不大于40bits的圈数位数组合。

对于用户来说,只需要提前在上位机中配置对应圈数的起始位和位数,没有则填空,就可以达到通用的目的。

在这个过程中,我观察到有的类似编码器读取模块,并不会将圈数全部拆解出来,而是作为一个整体的数据直接展示给用户,这种方法其实也可以,只不过不够直观,采用拆解的方式在直观体验上来说会好一些,可以看到具体的圈数(比如第1圈的第某某位置),否则就是一团数字,对与不对的也只能凭借经验来判断了。

6.调试Tp与Tm值

关于Tp与Tm,他们表达的含义是单稳态的出发时间Tm,与时间间隔Tp。
绝对值编码器:从调研到开发
Tm和Tp描述的对象都是SSI编码器本身的特性,Tm偏向于对编码器产生一个稳定准确的数据以及到spi发送的这个过程提出一个时间间隔上的要求,这个只和编码器本身有关,与波特率无关。

而Tp则要求大于Tm就可以了,可以将Tp视作为每次SSI通讯的间隔时间,那么在开发过程中,我的做法是将配置spi的波特率,根据例如40bits的时间计算出一个单次通讯spi的耗时TimeConsumption_spi。
TC_spi = (1000000us / baudRate)*40bits;
If(TC_spi >Tm)
{
Tp = TC_spi;
}
Else
{
Tp = TC_spi; +Tm;
}

这是一种我认为比较简单粗暴,还有优化的余地,不过也是够用的一种方式。

在设计如此的功能时,我们也需要考虑到芯片的内部时钟是不是可以做到足够的精确,比如我用的MCU定时器可能无法达到如此精确的单个微秒。

7.调试调零功能

在读取到编码器的值之后,就可以进行一些调零的辅助功能,
绝对值编码器:从调研到开发
比较简单的调试就是,直接将SET脚捅到24V供电上,就能看到读取回来的数据调零了,不过在正常使用中,可以用我们的DO进行控制。然后继续转动,就可以看到读回来的数据与波形的变化:
绝对值编码器:从调研到开发
转动前

绝对值编码器:从调研到开发
转动后

由于我使用的是单圈的编码器,所以能看到左边波形也随之转动了,如果是多圈值在左则能看到右边的波形先动,但是具体的要看编码器的高低位对应的单圈或多圈了。

8.调试旋转方向功能

这个与调零是类似的,区别仅在于,CCW/CW脚需要持续给一个高或低电平才能保持,不像调零,是通过一个沿触发。具体应用也可以是接到DO上,或者干脆不接,使用默认的方向就可以了。

9.集成功能调试

有了完整的数据(单圈与多圈的自然二进制值),有了完整的spi配置,也有了控制调零和方向的配置,接下来就需要将全部的东西整合成一个完整的模块了。这里较多内容设计工作内容不方便详述,我尽量提供一个设计的思路与需要考虑的问题,在不同的开发对象和产品适用环境中的具体细节也是有差异,或者说本文所涉及到的都是应用于工控领域及自动化领域(不知道这样表述是否正常),再或者说编码器本身应用场景也都在这一些相关领域的占比较多,但是作为一个开发者,凭借自身对自我领域的了解与拓展,我相信对应不同的场景肯定是可以做出完美的开发方案的。

从整体的方案上来说,我们需要做的只有两件事,第一件事,将编码器的功能涵盖进入产品设计当中,其中需要做的最重要的事情就是,分清楚编码器自身的功能的筛分,什么是在配置阶段使用,什么是在工作运行中时候,什么是属于模块化的功能,什么是属于用户比较关心的问题。

那么围绕这几个问题,我简单描述一下,也会抛出一些需要开发者思考的问题,可能表述也许不够好,但可以作为一个实践过程中的参考点:

1. 在编码器初次上电过程中,绝对值编码器自己产生一个准确数据会有延时,在要求上电后立刻进行工作的场景的中,需要考虑这一个短暂的时间间隔会对数据正确性带来的影响,如果场景中不需要如此严苛的要求,一般都是可以忽略的,但还是需要开发者考虑这一要素,正因为有这个差异,在有的产品手册中会明确标出,有的也没有标记该参数指标。
绝对值编码器:从调研到开发
2. 编码器需要的相关配置有,波特率,单圈或多圈,单圈多圈的起始位以及位数,是否有错误位,格雷码或二进制码,电子调零的下降或上升沿触发(及脉宽要求),旋转方向的高电平或低电平保持触发,spi通讯间隔的配置要求,这些需要在MCU中做出配置。
3. 第2条中的内容配置,需要区别哪些是可以一次性配置,哪些是可以重新配置的,这样的区别可以保证在不切断本产品模块的供电情况下,配合上位机使用,重新配置新的SSI编码器,提高使用体验。
4. 编码器的圈值位数需要和你的数据类型相匹配,以防溢出,这些需要在使用手册中明确标识。
5. 时刻明确这个模块核心要做的事情只有一件:
IF(A > B)
{
//控制DO输出HIGH
}
ELSE
{
//控制DO输出LOW
}
而编码器提供的就是B,A就是我们需要的目标的位置,逻辑很清晰明朗,其他的一切工作都是围绕这个核心展开的,所以我们要考虑什么时候使用调零,使用方向旋转,什么时候需要DI的介入,作为开发者需要将其罗列出来并梳理好。
6. 本模块需要做的事情就是在超过上限范围后输出,或者是低于下限范围后输出,使其保持在一个范围内,所以不存在一个“复位”的概念,除非是更换了设备和模块导致需要的重新初始化。
7. 在运行过程中,调节上限值与下限值的时候,对输出的控制是否符合安全和可靠的要求,数据是否发生跳变,如果发生跳变会有什么措施防范。
8. 由于绝对值编码器是保存上电前的位置值的,所以在模块拿到上下限位置之前的逻辑判断,需要做出保护。
9. 需不需要将圈值拆解成单圈和多圈的方式,有的产品是不做这个拆解的,这也是比较广泛的用法,在我的开发中我使用了拆解,所以在判断的时候需要将两者叠加以后做判断,不复杂但是需要考虑。

综上所述,我简单将我自己的开发出来的拓扑图画了下,画的不专业,仅供思路表达使用:
绝对值编码器:从调研到开发


历程回顾

到这里,所有的开发相关和调研相关的内容就全部写完了,写的一般,思路可以供参考。其实整个项目现在回头来看,技术层的东西真的非常少,花的更多的精力都在了编码器的调研,友邻产品的调研以及考虑如何整合到自己公司的结构框架上,但是说这个东西能有多大应用其实还是要看公司整体的业务倾向,作为一个螺丝钉我们无法表达太多建议,但是我认为在这个项目中更值得吸取和总结的东西,是一个程序员如何宏观的看待一个产品从涉入盲区到布局结构,最终付诸实践达到目的的过程,或许未来不会接触相似的东西,但是总归是要学习和借鉴其他的领域知识,方法或许不再适用但思路还是可以参考的。自此感谢很多帮助过的同事,更像是朋友的关系让工作更轻松和愉快,也很感谢那些供应商提供的建议和可以参考的资料帮助。

上一篇:使用整洁架构优化你的 Gradle Module


下一篇:background 背景图片 在IE8中不显示解决方法