最近拿到一个绝对式编码器基于SSI协议的,需求是把它反馈的位置信息读取出来做误差分析,使用说明书如下,因为是第一次接触这个协议,看了下它的时序图属于同步通信感觉跟IIC和SPI很相似,想着用32去读再通过JScope观测会方便一点。
编码器一共6跟线,VCC和GND外部5V供电,关于D+、D-和C+、C-属于差分IO,由于单片机属于TTL电平,差分信号是485电平,然后淘宝买了两个电平互转模块(这个模块是单通道的,时钟和数据各需要一个,所以买了两个),由于硬件控制流向的,所以使用很简单基本不用找说明文件,切记RX、TX要连对,数据传输过程中有指示灯可以参考。
硬件条件都具备了,其次就是软件,编码器说明书给的SSI时序不是很好,论坛找了找前人做过的,这个说得非常清楚,粘过来给大家(感谢大佬,这也是我开源的原因,互帮互助嘛)。
简单解释下这个它的时序,空闲状态时钟信号为高,每帧数据开始之前需要把时钟拉低持续t1时长,接受完毕之后(这个完毕主要取决于你接受数据帧的位数,我用的是26位,所以代码是按26位配置的)继续拉高进入空闲,想要做连续接收的时候也一样,帧与帧之前还是需要起始拉低结束拉高的,剩下的时间按典型值来设置问题不大。由于单片机本身是没有SSI协议的,我们只是自己模拟时序来进行通信的,所以通信的频率是不受控的,完全取决于程序跑多快。
话不多说,直接上代码!
用到了两个IO引脚(接入电平转换模块后两跟线就变成四根线了分别连接编码器D+、D-和C+、C-),PA0和PA1分别作为时钟信号输出和数据信号输入,先宏定义一下:
#define CLC PAout(0)
#define DAT PAin(1)
初始化的时候main函数里记得将CLC置为1(上电先保持空闲) ,然后就是模拟SSI的代码:
CLC=0;
delay_us(2);
for(i=0;i<26;i++)
{
CLC=1;
delay_us(5);
if(DAT)
SES[i]=1;
else
SES[i]=0;
CLC=0;
delay_us(5);
}
CLC=1;
delay_us(15);
for(j=0;j<26;j++)
{
suc+=SES[j]<<(25-j);//编码器数据是高位在前,需要移下位
}
suc1=(float)suc*360/67108864;
suc2=(int)(suc1*10000);
suc=0;
suc变量就是十进制整型,因为我用的编码器一共是26位,一圈是360°,suc1做了一个浮点型转换,但是由于JScope打印的时候只能看到小数点后两位,然后用suc2做了通骚操作只为了看到后面的位数。这段代码可以单独做个函数把它封装下,我为了图省事直接在main里运行的。
最后附个连线图和效果图:
线还是挺乱的,因为电平模块和编码器都需要供电(这个是打算用pmac的然后做了DB头,最后发现杜邦线是可以和DB头的针脚怼进去的,都是骚操作) 。
由于编码器没装在台子上动,连续的波形就不看了,JScope观测下suc1的值看下还是比较准的。