首页 | 期刊简介 | 编辑部 | 广告部 | 发行部 | 在线投稿 | 联系我们 | 产品信息索取
2024年4月20日星期六
2011年第01期
 
2010年第12期
 
2010年第11期
2010年第11期
 
2010年第10期
2010年第10期
 
2010年第09期
2010年第09期
 
2010年第09期
2010年第08期
 
2010年第07期
2010年第07期
 
2010年第06期
2010年第06期
 
2010年第05期
2010年第05期
 
2010年第04期
2010年第04期
 
2010年第03期
2010年第03期
 
2010年第02期
2010年第02期
 
2010年第01期
2010年第01期
 
2009年第12期
2009年第12期
 
2009年第11期
2009年第11期
 
2009年第10期
2009年第10期
 
2009年第9期
2009年第9期
 
2009年第8期
2009年第8期
 
2009年第7期
2009年第7期
 
2009年第6期
2009年第6期
 
2009年第5期
2009年第5期
 
2009年第4期
2009年第4期
 
2009年第3期
2009年第3期
 
2009年第2期
2009年第2期
 
2009年第1期
2009年第1期
 
2008年第12期
2008年第12期
 
2008年第11期
2008年第11期
 
2008年第10期
2008年第10期
 
2008年第9期
2008年第9期
 
2008年第8期
2008年第8期
 
2008年第7期
2008年第7期
 
2008年第6期
2008年第6期
 
2008年第5期
2008年第5期
 
2008年第4期
2008年第4期
 
2008年第3期
2008年第3期
 
2008年第2期
2008年第2期
 
2008年第1期
2008年第1期
单片机串行通信接口扩展技术
Serial Communications Interface Expanding Technology
清华大学Motorola单片机与DSP应用开发研究中心 蒋俊峰


摘 要:本文介绍了分时共用和I/O口模拟这两种串行通信接口扩展技术。利用此技术可解决调试和实际应用过程 中,单片机串行通信接口不够或者没有串行通信接口的问题。

关键词:串行通信接口,分时共用,I/O口模拟


前言

单片机的串行通信接口提供了与外设通信极大的方便性,虽然大多数单片机都具有硬件SCI(Serial Communications Interface),但也有一些产品没有SCI,如Motorola的MC68HC908JL3等,对于这些产品的用户来说这是一个缺憾。而且,一般八位单片机只有一个SCI,但在很多实际应用,需要更多的串行通信接口。例如在基于Modem的远程控制系统中,单片机与PC机通信的同时,还需要与Modem芯片进行通信;而在多机系统中,单片机需要与其他主机通信,另外也需要与本机控制台通信。所以利用单片机自身的资源进行串行通信接口的扩展很有意义。

笔者在开发的过程中,总结了一些串行通信接口的扩展技术:分时共用,I/O口模拟。前者利用MCU自身的硬件SCI,通过控制逻辑分时共享使用同一串行通信接口,后者在不增加硬件的条件下,充分利用MCU自身的资源利用I/O口模拟串行通信接口。


串行通信接口原理

单片机的SCI是一个通用异步接收器/发送器UART(Universal Asynchronous Receiver /Transmiter)类型的异步通信接口,通过串行通信协议(如RS-232协议)同主机系统通信。

在一般应用中,MCU简单地把数据写入数据寄存器即可实现一个字符的串行发送,SCI系统完成发送数据的所有细节工作,包括附加起始位和停止位以符合串行格式。SCI的接收器自动探测一个字节的起始位,并通过采样接收数据。接收串行数据并变换成并行数据的所有工作均由SCI完成,不需要MCU的干预。接收到数据后,MCU简单地从数据接收寄存器读取数据即可。

SCI使用标准不归零(NRZ)格式(一个起始位,8个或9个数据位和一个停止位),最常用的格式数据位是8位的,如图1所示。

NRZ数据格式的基本特点如下:
高电平为逻辑1,低电平为逻辑0;
发送/接收数据空闲时TXD、RXD线为高电平;
发送/接收数据串的第一位是起始位(逻辑0);
数据的最低位LSB首先被发送/接收;
数据串的最后一位(第10位或第11位)是停止位(逻辑1)。


分时共用技术

分时共用串行通信接口技术利用MCU自身的硬件SCI,通过控制逻辑分时共享使用同一串行通信接口。控制逻辑分时共用串行通信接口的原理图如图2所示。

图2中U1为74HC32(或门),U2为74HC04(非门),U3为74HC08(与门)。RXD、TXD为从MCU直接引出的SCI接收引脚和发送引脚,PTC0为MCU的I/O口,在此定义为输出,用于控制逻辑片选。当PTC0为高电平时,U1的2引脚和13引脚输入为高,3引脚和11引脚输出恒为高,即TXD1输出恒为高,RXD1输入被屏蔽;而U1的5引脚和10引脚输入为低,6引脚输出为TXD的电平,8引脚输出为RXD2的电平,此时TXD2的输出和RXD2的输入与MCU的TXD和RXD相一致。相反,当PTC0为低电平时,TXD2输出恒为高,RXD2输入被屏蔽,TXD1的输出和RXD1的输入与MCU的TXD和RXD相一致。10K的上来电阻R1确保在初始状态下,即使PTC0未初始化的情况下,PTC0的电平为高,即初始状态下TXD2和RXD2有效。

通过这种逻辑控制方式,在PTC0的控制下,TXD1、RXD1和TXD2、RXD2可以轮流使用MCU的串行通信接口,达到分时共享的目的。这种方式可应用于两个串行通信无需同时进行的场合。


I/O口模拟技术

I/O口模拟串行通信接口技术在不增加硬件的条件下,充分利用MCU自身的资源利用I/O口模拟串行通信接口,即利用I/O口做一个软件串口。软串口的发送和接收时序和硬件SCI一样,空闲状态为高电平,起始位为低电平,数据最低位LSB在前,依次到最高位MSB,最后是停止位,停止位为高电平,具体时序见图1。

这里给出利用MC68HC908GP32的两个普通的I/O引脚PTD4和PTD5实现的软件串口。在MCU总线时钟为2.4576MHz的条件下,波特率为4800,一个起始位,8个数据位,无校验位,一个停止位。程序用C语言编写,编译环境为Hiware C编译器。程序清单如下。

宏定义

#define exit_critical asm sei //关中断
#define enter_critical asm cli //开中断
#define idle asm nop //空闲指令
#define bit5 0x20 //定义位值
#define bit4 0x10
#define RX bit4 //定义SCI接收引脚
#define TX bit5 //定义SCI发送引脚

主程序


主程序完成接收、发送引脚的初始化,调用输入和输出函数
void main_loop(void)
{
unsigned char input;
…… //程序其他初始化
PORTD |= bit5; //SCI发送引脚初始化
DDRD |= bit5; //定义SCI发送引脚为输出
DDRD &= ~bit4; //定义SCI接收引脚为输入
input = getchar(); //调用SCI输入函数
putchar(input); //调用SCI输出函数
……
}

延时程序

为了保证发送和接收延时的精度,采用精简的嵌入式汇编语言编写。延时时间计算公式为(6 n+4)个总线周期。
void delay_time(char n)
{
asm{
L1:
DECA //1个总线周期
CMP #0 //2个总线周期
BGT L1 //3个总线周期
RTS //4个总线周期
}
}

发送函数

MCU总线时钟为2.4576MHz,发送数据遵循NRZ格式:一个起始位,8个数据位,无校验位,一个停止位。波特率为4800,即每位208 S。发送时直接逐位发送,相邻位间的延迟时间为208 S。延时控制通过反汇编代码,参看每条反汇编指令的周期数,进行计算。
void putchar(unsigned char outchar)
{
unsigned char count;
exit_critical; //关中断
PORTD &= ~TX; //输出起始位,低电平
for(count=0;count<8;count++) //8位数据输出
{
delay_time(80); //延时,确保相邻数据位间的间隔为208 S
if((outchar&bit0)==0)
PORTD &= ~TX; //输出位为0,输出低电平
else //输出位为1,输出低电平
{
PORTD |= TX;
idle; //补足空指令,使两种情况执行指令相同
idle;
idle;
}
outchar = outchar>>1; //数据右移,欲输出的位移至最低位
}
delay_time(80); //延时,确保数据MSB与停止位间间隔为208 S
PORTD |= TX; //输出停止位,高电平
delay_time(80); //延时,控制停止位时间长度为208 S
enter_critical; //开中断
}

接收函数

接收函数循环检测起始位的发生,一旦检测到起始位,起始位后大约300 S后,也就是从数据最低位LSB的中间位置起按一定的时间间隔逐位采样,相邻位间开始采样的时间间隔位208 S,为了提高抗干扰能力,每位采样三次。
unsigned char getchar(void)
{
unsigned char inchar,count,temp,i;
do{
}while((PORTD&RX) != 0); //检测起始位
delay_time(118); //起始位后300 s开始采样
for(count=0;count<8;count++) //数据位8位,由低至高接收(LSB至MSB)
{
inchar = inchar>>1; //数据右移,保证最终接收到数据位在最高位
for(i=0,temp=0;i<3;i++) //采样三次
{
if((PORTD&RX) != 0) temp += 1; //采样值为1
else //采样值为0
{
idle; //补足空指令,使两种情况执行指令相同
idle;
idle;
idle;
idle;
}
}
temp /=3; //3次采样值之和除以3
if(temp != 0) inchar |= bit7; //商位1,接收位为高电平
else //商位0,接收位为低电平
{
inchar &= ~bit7;
idle; //补足空指令,使两种情况执行指令相同
idle;
idle;
} delay_time(64); //延时,确保相邻位间开始采样的时间间隔位208 S
}
for(i=0,temp=0;i<3;i++)
{
if((PORTD&RX) != 0) temp += 1; //采样值为1
else //采样值为0
{
idle; //补足空指令,使两种情况执行指令相同
idle;
idle;
idle;
idle;
}
}
temp /=3; //3次采样值之和除以3
if(temp != 0) return(inchar); //停止位正确返回接收数据
else return(-1); //停止位错误返回-1
}

         
版权所有《世界电子元器件》杂志社
地址:北京市海淀区上地东路35号颐泉汇 邮编:100085
电话:010-62985649
E-mail:dongmei@eccn.com