摘要:ISP1032是Lattice公司生产的ISP系列在线可编程器件中的一种,本文介绍了使用一片ISP1032芯片来设计光栅编码器计算机数据采集卡的硬件电路和设计方法,并给出了接口驱动程序。
关键词:ISP1032 光栅编码数据采集 接口 驱动
1 引言
光栅编码器的信号一般应由接口电路完成方向识别和脉冲计数后再送入计算机,由于还要进行地址译码和读取控制,因而线路比较复杂。笔者采用Lattice公司的ISP1032芯片完成了两个光栅编码器的数据采集功能,该设计方法使整个接口卡只要一块ISP1032即可,并且结构简单,无需调试。
2 接口卡组成
用Lattice公司的在线可编程工具ispEXPERTsystem结合ABLE语言进行图1中各线路功能的设计。
2.1 地址译码器设计
I111单元为地址译码器,来自总线的地址a0-a9以及io信号经组合可得到y3、y2、y1、y01、y6、y7六个输出信号,y6、y7是计数器I136、I137的复位信号,y01用作数据总线开通信号,y1用作高、低字节的选通信号,y3、y2作为RS触发器I136的置位、复位信号,I135的输出Q0用于两个计数器I136和I137的选择信号。下面是用ABLE编写的语言代码:
MODULE addr
TITLE'addr decoder'
a9,a8,a7,a6,a5,a4,a3,a2,a1,a0,ior pin;
y3,y2,y1,y01,y6,y7 pin istype'com';
equations
y7=(a9&a8&!a7&!a6&! a5&! A4&!a3&a2&a1&a0&!ior);
y6=(a9&a8&!a7&!a6&!a5&!a4&!a3&!a2&a1&a0&!ior);
y3=(a9&a8&!a7&!a6&!a5&!a4&!a3&!a2&al&a0&!ior);
y2=!(a9&a8&!a7&!a6&!a5&!a4&!a3&!a2&a1&!a0&!ior);
y1=(a9&a8&!a7&!a6&!a5&!a4&!a3&!a2&!a1&!a0&!ior);
y01=(a9&a8&!a7&!a6&!a5&!a4&!a3&!a2&!a1&!ior);
END
2.2 方向识别和计数功能设计
光栅编码器在转动时输出两相脉冲A、B,其相位关系反映了编码器的旋转方向,如图2所示。如果编码器沿着+n方向转动,则输出的波形是A先于B在上升沿出现(用实箭头标出);相反如果编码器沿着-n方向转动,则输出的波形是B先于A在上升沿出现(用虚箭头标出),这两种情况的判断是很容易的,因为只要比较A、B相脉冲上升沿出现的先后就可以了。但是如果编码器的运动是或进或退的,以上方向就不足以输出一个脉冲,而这一位置又恰好使得A(或B)相输出出现在脉冲边沿附近,这样就出现一相上升沿来后而另一相不时出现上升沿下降沿的情况,这时如果沿用前面方法,就不能判断编码器的运动方向,也不能准确记录编码器运动过的角度。
解决这一问题的办法是引入总线时钟信号osc,在每个osc周期内都对A的当前状态和B的前两个状态进行比较,采用D触发器I106、I107、I109和I110作为两个B相脉冲的前状态寄存器实现增减计数的逻辑表达式为:当((bb$bf)&a&!bb)为1时计数器加1,当((bb$bf)&a&!bb)为0时计数器减1。这样只要相脉冲的频率不超过osc的1/3,计数器就不会丢失脉冲,这样的设计同时还具抗干扰作用。该计数器用ABLE语言实现如下:
MODULE count
TITLE 'PULSE bi-direction counter'
a,bb,bf,c,osc pin;
q15,q14,q13,q12,q11,q10,q9,q8 pin istype'reg';
q7,q6,q5,q4,q3,q2,q1,q0 pin istype'reg';
s=[q14..q0];
equations
s.clk=osc;
s.ar=c;
when (bb $ bf)&a&!bb then s:=fb+1
else when (bb $ bf)&a&bb then s:=s.fb-1;
else s;=s.fb;
END
2.3 四通道八位多路选择器设计
数据总线宽度为8位,要读取两个16位的计数器的数值,需分4次进行,并需由fs和hl两信号来控制选取,其ABLE语言实现如下:
MODULE mux21
TITLE'mux21'
Fs,hl pin;
f15,f14,f13,f12,f11,f10,f9,f8,f7,f6,f5,f4,f3,f2,f1,fo pin;
s15,s14,s13,s12,s11,s10,s9,s8,s7,s6,s5,s4,s3,s2,s1,s0 pin;
d7,d6,d5,d4,d3,d2,d1,d0 pin istype'com';
firhei=[f15..f8];
firlow=[f7..f0];
sechei=[s15..s8];
seclow=[s7..s0];
out=[d7..d0];
equations
out=! Fs& (! Hl&firhei#hl&firlow) #fs& (! Hl&sechei#hl&seclow);
END
3 接口卡驱动程序
该卡的接口驱动程序主要用于完成复位和分通道数据读取,可用汇编或C语言来编写。在面向对象编程语言中可将汇编代码嵌入其中,以下这段程序是写在Delphi5.0中的两个过程,该设计需用于“37高炮训练模拟器”项目,效果良好。
Procedure Tcollectiong.ResetCH; //计数器复位过程
Const
Ch2Reset=$307; //通道2的复位地址307H
Ch1Reset=$306; //通道1的复位地址306H
begin
asm
push ax
push dx
mov dx,CH2Reset //通道2的复位地址307H
in ax,dx
mov dx,CH1Reset //通道1的复位地址306H
in al,dx
pop dx
pop ax
end;
End;
Procedure Tcollecting.readCH; //编码器数据读取过程
Const
SelectCH1=$302; //通道1的端口选择地址302H
SelectCH2=$303; //通道2的端口选择地址303H
ReadPort=$300; //通道1、2的数据读取端首地址300H
Var
CH1Value,CH2Value:word;
Begin
Asm
Push ax
Push dx
//Read Ch1
mov dx,SelectCH1 //选择通道1
in al,dx
mov dx,ReadPort //从300H和平301H读取编码器1的16bits脉冲数
in ax,dx
mov CH1Value,ax //将编码器1的值保存于CH1Value中
//Read CH2
mov dx,SelectCH2 //选择通道2
in al,dx
mov dx,ReadPort //从300H和平301H读取编码器2的16bits脉冲数
in ax,dx
mov CH2Value,ax //将编码器2的值保存于CH2Value中
pop dx
pop ax
end;
End;
本文介绍的接口卡如果钭ISP1032的剩余引脚定义为输入输出,即可设计成一块完整的I/O卡。