关键词:多功能接口 串行通信 软件译码
AT89C52(简称89C52)的广泛使用,使单片机的价格大大下降。目前,89C52的市场零售价已经低于8255、8279、8253、8250等专用接口芯片中的任何一种;而89C52的功能实际上远远超过以上芯片。因此,如把89C52作为接口芯片使用,在经济上是合算的。在本人设计的系统中,将89C52设计为多功能可编程接口,其相关程序固化在片内的Flash ROM中。该芯片(以下简称多功能接口)具有如下功能:①有1个专用的键盘/显示接口;②有1个全双工异步串行通信接口;③有2个16位定时/计数器。这样,1个89C52芯片,承担了3个专用接口芯片的工作;不仅使成本大大下降,而且优化了硬件结构和软件设计,给用户带来许多方便。
1 硬件结构
把89C52当作接口使用,接口自身必须尽可能地少占用硬件资源,与主系统之间的连接线也应尽可能少,这样才能少占主机引脚,把更多的资源留给系统。本设计中,主机与多功能接口之间采用串行通信。主机与多功能接口之间有四根连接线:CE、CLK、DAT、INTR。CE用于作片选信号输入端。此引脚为低电平时,主机能与多功能接口进行数据传送。CLK为时钟输入端,当主机向多功能接口发送指令时,此引脚电平上升表示数据有效。DAT为串行数据输入/输出端。INTR为多功能接口输出端。当多功能接口内的数据准备好时,由INTR向主机发低电平,通知主机,数据已准备就绪,可以进行读操作。该信号可供主机查询,也可用作发向主机的中断请求信号。
89C52的P0、P1、P2口用作键盘/显示接口。用程序扫描的方法进行键盘输入和显示输出。P0口作为字段口,P1口作为键盘的列输入口,P2作为显示器的字位口以及键盘的行扫描输出口。由于显示器字位口电流较大,P2口需进行电流驱动。该多功能接口最多可连接8个LED显示器和1个8×8链盘矩阵。其硬件原理如图1所示。
P3.2、P3.3、P3.6、P3.7分别用作CE、CLK、DAT和INTR信号;而P3.0、P3.1用作异步串行通信数据线RXD和TXD;P3.4、P3.5分别是OUT0/T0和OUT1/T1信号线。该引脚在定时器工作于连续脉冲方式时,可输出通断比与频率可编程的连续脉冲;工作在计数器方式时,该引脚作为外部计数脉冲输入端输入计数脉冲。
图1
2 通信协议
实现多功能接口的关键是主机和多功能接口之间的通信。在本设计中,采用主从方式进行通信,所有的操作都由主机发出操作指令。多功能接口在收到主机发来的操作指令后,对操作码进行软件译码。根据操作码的内容转入相应的工作通道,并从操作数部分获取所需要的数据。
多功能接口采用串行方式与主机通信。串行数据从DAT引脚送入芯片,并由CLK端同步。当片选信号CE变低后,DAT引脚上的数据在CLK引脚的上升沿被写入多功能接口的寄存器中。
串行接口的时序如图2所示。
图2
由于多功能接口接收指令的工作用软件进行,因此,图中的t1、t2、t3、t4、t5时间较长,要求t1-t4时间在10μs~1000μs。指令有两类:一类写指令,一类是读指令。写指令中不管是操作码还是操作数,其数据传送方向均为从主机到多功能接口;而对读指令来讲,操作码部分的数据方向是从主机到多功能接口,而操作数部分的数据方向是从多功能接口到主机。
t5是读指令中操作码与操作数之间需要的时间间隔,t5应在30μs~1000μs的范围。在读操作时,CLK时钟的上升沿来到时,多功能接口将数据送到DAT引脚上。
3 指令编码
多功能接口共有13条指令。指令长度为1字节、2字节、3字节和4字节不等。
(1)复位指令
机器码为00H。当多功能接口收到复位指令后,所有字符消隐,所有定时器清零,定时中断和串行中断关闭。其状态与系统上电复位的情况相似。
(2)显示数据指令
该指令向多功能接口的显示缓冲器中发送显示数据。这是一个2字节指令,其指令编码如下:
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
dip | 0 | 0 | 0 | d3 | d2 | d1 | d0 |
其中dip为小数点控制位,a2、a1、a0为位地址,d3、d2、d1、d0为待显示的字符,其格式如表1、2所列。
(3)闪烁指令
该指令控制各个数码管的闪烁属性。d7~d0分别对应数码管1~8,1为闪烁,0为不闪烁。
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
d7 | d6 | d5 | d4 | d3 | d2 | d1 | d0 |
(4)循环左移指令
指令码为11H。该指令将所有显示从左向右移动1位。
表1
a2 | a1 | a0 | 显示位 |
0 | 0 | 0 | 1 |
0 | 0 | 1 | 2 |
0 | 1 | 0 | 3 |
0 | 1 | 1 | 4 |
1 | 0 | 0 | 5 |
1 | 0 | 1 | 6 |
1 | 1 | 0 | 7 |
1 | 1 | 1 | 8 |
表2
d3 | d2 | d1 | d0 | 显示字符 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 1 | 1 |
0 | 0 | 1 | 0 | 2 |
0 | 0 | 1 | 1 | 3 |
0 | 1 | 0 | 0 | 4 |
0 | 1 | 0 | 1 | 5 |
0 | 1 | 1 | 0 | 6 |
0 | 1 | 1 | 1 | 7 |
1 | 0 | 0 | 0 | 8 |
1 | 0 | 0 | 1 | 9 |
1 | 0 | 1 | 0 | - |
1 | 0 | 1 | 1 | H |
1 | 1 | 0 | 0 | L |
1 | 1 | 0 | 1 | P |
1 | 1 | 1 | 0 | E |
1 | 1 | 1 | 1 | 空 |
(5)循环右移指令
指令码为12H。该指令将所有显示从右向左移动1位。
(6)读键盘指令
指令为2字节指令,操作数为读到的键值。各键盘的键值如图1所示。该指令格式如下:
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 |
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
d7 | d6 | d5 | d4 | d3 | d2 | d1 | d0 |
(7)连续脉冲输出指令
该指令对定时器进行编程。使OUT0/OUT1输出连续脉冲,脉冲的通断比和频率可以通过编程设定。其指令为4,格式如下:
第1字节
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
0 | 0 | 0 | 1 | 0 | 0 | 1 | 1/0 |
第2字节
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
M3 | M2 | M1 | M0 | N3 | N2 | N1 | N0 |
第3字节
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
f15 | f14 | f13 | f12 | f11 | f10 | f9 | F8 |
第4字节
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0 |
其中M:N是脉冲的通断比,M或N的设置范围是1~10。f15~f0是频率设置,其设置范围是1~9999Hz。采用BCD码设置。指令操作码中,D0设置定时器0或定时器1工作。
(8)定时器方式指令
该指令为3字节指令。操作码为22H、23H,其中D0位确定对定时器0还是定时器1进行操作。第2、第3字节为定时时间。
(9)计数器方式指令
该指令为3字节指令。操作码为24H、25H,其中D0位确定对定时器0还是定时器1进行操作。第2、第3字节为计数初值。
(10)读计数器指令
为3字节指令。操作码为26H、27H,第2、第3字节为从计数器读到的计数值。操作码的D0位确定对计数器0还是计数器1进行操作。通过该指令读以16位计数器的当前计数值。
(11)串行发送指令
该指令对异步串行通信进行初始化,其指令格式如下:
第1字节
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
0 | 0 | 1 | 1 | 0 | a2 | a1 | a0 |
表2字节
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
b1 | b0 | d5 | d4 | d3 | d2 | d1 | d0 |
第3字节
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
d7 | d6 | d5 | d4 | d3 | d2 | d1 | d0 |
第4字节
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
d7 | d6 | d5 | d4 | d3 | d2 | d1 | d0 |
串行通信采用批传送的方法进行。每条指令传送1个数据帧。指令中,第1、第2字节用来进行串行通信初始化,第3字节以后是发送的各个数据。b1、b0用来确定奇校验、偶校验还是不校验。第2字节的操作数d5、d4、d3、d2、d1、d0用来设定该帧数据的个数,最多1帧可发送64个字符。a2、a1、a0设定串行通信的波特率。其波特率如表3所列。
表3
a2 a1 a0 | 波特率/baud |
0 0 0 | 110 |
0 0 1 | 150 |
0 1 0 | 300 |
0 1 1 | 600 |
1 0 0 | 1200 |
1 0 1 | 2400 |
1 1 0 | 4800 |
1 1 1 | 9600 |
(12)串行接收指令
指令格式如下:
第1字节
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
0 | 0 | 1 | 1 | 1 | a2 | a1 | a0 |
第2字节
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
b1 | b0 | d5 | d4 | d3 | d2 | d1 | d0 |
第3字节
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
d7 | d6 | d5 | d4 | d3 | d2 | d1 | d0 |
第4字节
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
d7 | d6 | d5 | d4 | d3 | d2 | d1 | d0 |
指令编码与串行发送送似,第3字节之后为接收到的数据。
(13)读状态指令
指令格式如下:
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
0 | 0 | 0 | d4 | d3 | d2 | d1 | d0 |
在键盘输入、计数器回等或串行通信中断时,多功能接口将向INTR发出负脉冲,主机在响应后应发读状态指令,查询状态标志,确定是哪个状态标志动作。其中d0为键盘输入标志,d1为计数器0回零动作。d2为计数器1回零标志。d3为串行接收结束标志,d4为串行发送结束标志。
4 多功能接口的软件设计
在主程序中进行显示扫描和键盘扫描,如有键盘输入,则找出键盘矩阵的键号。键号存入键值寄存器,并置位状态标志,同时发出INTR负脉冲,通知主机来取键值。
主机通过指令对多功能接口进行操作。主机首先要将CE置0。该下降沿通过P3.2向多功能接口发出外部中断。在中断服务程序中,多功能接口进行取指和译码操作,并通过散转指令转入相应的处理通道。则中断返回。至此,一条指令的取指-译码-执行的过程才告结束。程序回到主循环继续进行显示扫描和键盘扫描。
所谓取指操作实际上就是多功能接口与主机进行通信的过程。由于采取软件进行通信,t1、t2、t3、t4、t5的宽度有一定的范围。
在接收到主机的操作指令后,多功能接口与外设的串行通信及有关定时器的操作采用中断方式进行。在中断结束时,置位状态标志,并向主机发INTR负脉冲。该负脉冲可供主机查询,也可作为向主机发出的中断请求信号。完成以上工作后,返回主程序。
89C52有三个定时器,其中T2在中串行通信时间来作为串行通信的波特率发生器。这样T0和T1就可以出借给用户作定时器内。T2在波特率发生器方式时,可置位T2CON寄存器中的TCLK位或RCLK位。在TH2、TL2中装入计数初值,使T2从这个初值开始计数,但并不置位FT2。RCAR2H和RCAP2L中的常数由软件设定后,T2的溢出率是严格不变的,因而使串行通信的波特率非常稳定。
5 应用实例
在本刊网络补充版(http://www.dpj.com.cn)中,给出主机为AT89C52时的应用实例。程序的功能为等待键盘输入,然后将所读到的键盘码转换成十进制后送LED数码管显示。