单片机模拟串口数据接收程序的实现及优化

2016-09-15 07:03郏正学李炜
单片机与嵌入式系统应用 2016年8期
关键词:接收数据子程序字节

郏正学,李炜

(浙江省空间结构重点实验室,杭州 310058)



单片机模拟串口数据接收程序的实现及优化

郏正学,李炜

(浙江省空间结构重点实验室,杭州 310058)

进行单片机应用系统设计开发时,往往碰到单片机自身携带的串口不够用,这时就需要通过I/O口模拟串口通信。本文简单介绍了串口通信的基础知识,分析了模拟串口接收数据的过程,介绍了模拟串口接收数据的实现方法,以ATmega64A单片机为例,详细介绍了模拟串口数据接收程序的实现及优化方法。

ATmega64A单片机;串口通信;接收程序

引 言

图1 串口通信数据帧格式

随着信息技术的发展,单片机的应用越来越广泛,尤其是在仪器仪表、物联网、自动化、智能化等领域,应用非常多。近年来,各类传感器不断出现,为了提高系统自动化、智能化程度,往往需要单片机与多个传感器等外围器件进行连接通信。这类外围器件中,串口通信用得比较多。因此,在嵌入式应用系统设计开发时,会经常需要多个串口,而一般的单片机自身只有一个或两个串口,串口不够用,这时就需要利用单片机的I/O口模拟串口通信,以满足应用要求。

1 串口通信

在工业上,串口通信用得比较多的是RS232、RS485通信,本文所讲的串口通信是指RS232。RS232串口通信数据帧由起始位、数据位、校验位、停止位组成,数据帧格式如图1所示。St为起始位,1位,低电平;(n)为数据位,数据位可以是5~9位,具体多少位由串口通信协议设定;P为校验位,1位,可以是奇校验或偶校验,也可以是无校验位,是否有校验位,由串口通信协议设定;Sp为停止位,1位或2位,停止位为高电平,停止位是1位还是2位,由串口通信协议设定。

当串口通信协议设定为8个数据位、无校验位、1个停止位时,1个数据帧即由1位的起始位、8位的数据位、1位的停止位组成,帧长度为10位。在串口通信协议中,除了前面的参数设定外,还有1个比较重要的参数——波特率,波特率为串口通信传输数据的速度,单位为bps,即每秒传输的比特数。在串口通信中,可以设定的波特率有2 400、4 800、9 600、14 400、19 200、38 400等等。由于不同参数的串口通信,在编写模拟串口程序时会稍有不同,因此本文以9 600波特率、8位数据位、无校验位、1个停止位为例进行介绍。另外本文所讲的是三线制串口通信,即RxD(接收)、TxD(发送)、GND三线。

串口通信发送或接收数据时,都是按照数据帧格式一位一位发送或接收的。发送数据时,数据低位先发送,高位后发送;接收数据时,数据低位先接收,高位后接收。

2 模拟接收

使用单片机自身的串口功能接收数据时,可以采用查询方式或中断方式接收数据。使用查询方式接收数据时,单片机要不停地查询控制和状态寄存器的相应标志位,以判断是否需要接收数据。一旦有数据需要接收,单片机即运行接收程序接收数据。当没有数据需要接收时,单片机需要处于不定时查询状态,否则就不能及时获知接收数据信息,造成数据丢失。即使查询方式因单片机一直忙于查询而不能处理其他事务,降低了单片机的利用率。使用中断方式接收数据时,当串口没有接收到数据时,单片机可以处理其他事情;当串口接收到数据时单片机立即产生中断,通过中断程序接收数据,这样单片机接收数据比较实时,利用率也高。因此在实际应用中,比较多的是利用中断方式接收数据。

用I/O口模拟串口接收数据时,为了实现中断接收数据,需要选择具有外部中断功能的I/O口作为RxD引脚。之所以使用具有外部中断功能的I/O口,是因为串口通信数据帧的起始位为低电平,利用低电平产生外部中断功能,以实现中断接收数据的目的。

未发生数据通信时,RxD引脚处于高电平状态。当外部有数据发送过来时,RxD引脚会接收到数据帧格式的二进制数据序列。当接收到1个字节的数据时,RxD引脚接收到1个数据帧;当接收到多个字节的数据时,RxD引脚接收到多个数据帧。接收到数据帧时,RxD引脚首先接收到起始位,由于起始位是低电平,只要事先将外部中断定义成低电平中断,此刻即产生外部中断,单片机转入外部中断处理程序,由外部中断程序对发送来的二进制数据序列按照数据帧的格式进行一位一位地接收,先接收到是数据的低位,后接收到的是数据的高位。接收到1个数据帧的停止位后,如果紧接着接收到低电平信号,则认为有新的数据帧需要接收,此低电平信号是新数据帧的起始位;如果紧接着接收到高电平信号,则判断为没有新的数据帧需要接收,接收数据结束。

3 程序实现

根据上面的描述,编写模拟串口通信数据接收程序就是对外部中断程序的编写。因为波特率是9 600 bps,所以每位数据占用的时间为104 μs。在实现每位数据接收时,接收到一位数据后,需要延时104 μs后再接收另一位数据。在单片机编程时,可以用语句循环实现延时,也可以用定时器实现延时。定时器定时比较精确,因此本文采用定时器延时。

3.1定时器定时子程序

这里以ATmega64A单片机为例,单片机外接晶振为8 MHz。ATmega64A单片机有多个定时器,这里选用定时器TIMER0进行定时,以实现延时之目的。TIMER0为8位定时器/计数器,定时方法是给TCNT0寄存器赋初值,由初值开始计数,TIMER0每计数一个时钟脉冲,TCNT0加1。当TCNT0的值由0xFF变为0x00时,TIMER0的溢出标志位置1,通过该标志位的值判断定时是否已到。TIMER0的时钟源可以由单片机的晶振分频后提供,这里选择8分频,即TIMER0的时钟频率为1 MHz,每个时钟脉冲的时间为1 μs,要实现104 μs定时,给TCNT0赋初值0x98即可。为了使定时器定时子程序可以实现不同的定时时间,将该子程序设计成带参数,通过参数值改变定时时间,定时子程序如下:

void Timer0_Open(unsigned char value){

//通过参数value设定定时时间

TCCR0=0x00;//取消时钟源,TIMER0停止工作

TIFR=0x01;//TIMER0溢出标志清零

TCNT0=value;

//定时器初值,定时时间为(0xFF-value+1)μs

TCCR0=0x02;

//设置时钟8分频,TIMER0获得时钟源后即开始工作

}

3.2接收程序流程图

为了实现中断接收数据,接收数据前RxD引脚开启外部中断功能,一旦有数据起始位到即产生中断,此时立即将该引脚的外部中断功能关闭,同时将该引脚设置为输入,以开始接收数据流,接收程序按照数据帧的格式一位一位地接收数据,数据接收结束后再将此引脚的外部中断功能开启,以等待下一次接收数据。接收多个字节数据的接收程序流程图如图2所示。

4 程序优化

图2 接收程序流程图

按照图2接收程序流程图用C语言编写程序后,经测试,发现可以连续接收到3个字节的数据,前2个字节正确,但第3个字节数据是错误的。通过对测试结果和程序进行分析,发现产生错误的原因是程序在接收相邻位数据的间隔时间超过了104 μs,每接收1位会产生△t误差,连续接收N 位后,产生的累积误差为N△t,当N△t达到104 μs时就会出错。每接收1位数据产生时间误差的主要原因有:①定时器本身有误差;②每次调用延时子程序、子程序返回、执行子程序语句需要时间,设计延时子程序时未将这些时间予以减除;③接收数据之后,调用延时子程序之前执行程序语句产生的时间。

为了降低△t,需要计算调用子程序及返回、执行有关语句所需的时间,以便对延时子程序的延时时间作相应调整。由于程序是用C语言编写的,计算这些时间比汇编语言复杂一些。在精确度要求不是很高的情况下,可以用简便的方法进行估算,估算方法:接收第3个字节出错,说明有可能在接收20位数据后产生的累积时间误差达到104 μs,也有可能是在接收第30个字节时产生的累积误差达到104 μs;假如接收20位数据后产生的累积误差达到104 μs,则说明接收每位产生时间误差为5.2 μs;假如接收30位数据后产生的累积误差达到104 μs,则说明接收每位产生的时间误差为3.47 μs;分别选取3、4、5、6 μs对延时子程序的延时时间作相应调整,进行调试测试,选取最佳的方案即可。

根据上述思路和方法对延时进行调整,通过调试测试,选取结果较好的方案对延时时间进行调整,以优化程序,优化后的接收程序语句如下:

EIMSK&=0xFE; //关闭外部中断使能

DDRD&=0xFE; //PD0引脚设为输入

while(ReceiveContinue){

//程序开始时已赋值为1,ReceiveContinue等于1,继续接收

Timer0_Ooen(0x99) ;

//起始位延时103 μs

for( unsigned char i=0;i<8;i++){

//接收一个字节的 8个位

while( ! ( TIFR& 0x01) );

//前一位延时结束

ReceiveRegister>>= 1;

if(PIND&0x01)

//读取PD0即RxD引脚的值

ReceiveRegiste|= 0x80;

//如果PD0为高电平,说明接收到二进制1,否则为0

Timer0_Ooen(0x9C);

//延时100 μs

}

while( ! ( TIFR& 0x01) );

ReceiveBuffer[ReceiveCount]=ReceiveRegister;

//将接收到数据存放在接收缓存器

ReceiveCount++;

//接收到1个字节后该值加1

ReceiveRegister=0;

//赋值为0,以便接收下一个字节数据

StartTimer0(0x9B) ;

//延时101 μs

while( ! ( TIFR& 0x01) );

if(PIND&0x01)

//PD0为1,无起始位,接收结束

ReceiveContinue=0;

}

EIMSK |= 0x01;

//开外部中断 0

需要说明的是,上述程序的前提是ATmega64A单片机采用INT0引脚作为模拟串口通信的接收端口。

5 测试结果

分别对优化前和优化后的程序进行了测试,优化前的程序只能连续接收3个字节的数据,接收到的前2个字节数据是正确的,第3个字节数据是错误的。

优化后的程序可以连续接收48个字节的数据,接收到的数据是正确的,超过48个字节就容易出错。要使程序能连续接收更多字节的数据,还需要进一步优化。

结 语

本文主要介绍了用单片机I/O口模拟串口通信接收数据的过程方法、数据接收程序的实现及优化方法。通过优化,数据接收程序连续接收数据的能力得到了大大的增强,可以实现连续接收48个字节的数据,能满足较多场合的应用要求。

在优化过程中,提出了简便地估算程序运行产生时间误差的方法,通过估算得到的误差值,对程序的延时时间进行调整调试,实现程序的优化,这是本文的新颖之处。本文的不足之处:一是仅通过调整延时时间进行程序优化,未进行其他优化;二是优化后的数据接收程序,连续接收数据能力有限,有待进一步优化提高。

[1] Atmel .Atmel-8160E-ATmega64A_Datasheet_Complete-09/2015[EB/OL].[2016-05].http://www.atmel.com/.

郏正学(工程师),主要从事嵌入式应用系统设计开发。

Realization and Optimization of Serial Port Data Receiving Program Based on MCU

Jia Zhengxue,Li Wei

(Zhejiang Provincial Key Laboratory of Space Structures,Hangzhou 310058,China)

In the design,we often encounter the case that the quantity of the serial ports of MCU is not enough.In order to meet the application requirements,the serial communication can be simulated by using the I/O ports.In the paper,the basic knowledge of the serial communication is introduced.The process of simulating the serial ports receiving data is analyzed.The realization method of simulating the serial port receiving data is introduced.Taking ATmega64A MCU as the example,the realization and optimization of the receiving data program are introduced in detail.

ATmega64A MCU;serial port communication;receiving program

TP311

A

(责任编辑:杨迪娜2016-05-03)

猜你喜欢
接收数据子程序字节
No.8 字节跳动将推出独立出口电商APP
基于稀疏对称阵列的混合信源定位
No.10 “字节跳动手机”要来了?
低复杂度多输入多输出雷达目标角度估计方法
基于LoRa的低能耗物联网技术研究
简谈MC7字节码
浅谈子程序在数控车编程中的应用
子程序在数控车加工槽中的应用探索
西门子840D系统JOG模式下PLC调用并执行NC程序
基于ESPRIT的ULA波达方向估计改进算法