首页 > 范文大全 > 正文

基于DSP2812的双缓冲串口程序设计

开篇:润墨网以专业的文秘视角,为您筛选了一篇基于DSP2812的双缓冲串口程序设计范文,如需获取更多写作素材,在线客服老师一对一协助。欢迎您的阅读与分享!

【摘要】以dsp2812为例,分析了常用串口程序的缺点,提出了一种工程上实用的串口通讯程序的设计方法。利用DSP2812的FIFO和队列数据结构,对串行数据进行了两级双向缓冲,在中断中完成数据收发,高效可靠的实现了DSP的串行通讯。

【关键词】DSP2812;串行通讯;FIFO队列

引言

TMS320F2812是国内广大的工程技术人员非常熟悉一种DSP芯片,它速度快,功能强,广泛应用于电机控制,电力电子等领域。如何高效可靠的实现DSP与上位PC机或其它从机间的串行通讯,是DSP系统开发的一个基本问题。本文将以DSP2812为例,针对这一问题展开讨论,并给出一种切实可行的解决方案。

1.常用串口收发程序及其存在的问题

常用的串口发送程序如下所示,以DSP2812的SCIA发送一字节数据为例:

void SCIASendChar(unsigned char schar) { //schar为待发送的数据

SciaRegs.SCITXBUF=schar; //将数据送入发送数据缓冲寄存器

while(SciaRegs.SCICTL2.bit.TXRDY==0); //等待发送器缓冲寄存器就绪

while(SciaRegs.SCICTL2.bit.TXEMPTY==0); //等待发送器数据为空

}

这是一种查询等待标志位的方式。由于有while循环存在,CPU要等待一个字节的数据发送完成后才能继续进行其它工作,这造成了大量指令周期的浪费,会引起数据发送有延迟、通讯效率低、占用较多的CPU资源、其它模块的执行时间无法得到保证等一系列问题。当系统要求的实时性较高时,是不允许采取这种方式的。

常用的串行中断接收程序如下所示,以DSP2812的SCIA接收中断为例:

interrupt void SCIA_RXINT(void) {

DINT;

rxdata=SciaRegs.SCIRXBUF.bit.RXDT; //读取数据

PieCtrl.PIEACK.all |= (1

EINT; }

DSP每收到一个字节的数据都会进入中断,当接收的数据量较大时,会占用较多的CPU资源,效率低。

2.FIFO控制寄存器设置和使用队列数据结构的说明

DSP2812含有一个16级深度的发送/接收FIFO。使用FIFO可以减少收发数据的延迟和对CPU资源的占用,高效的实现串口数据收发。

FIFO是一个缓冲寄存器,通过FIFO发送数据时,可以一次性连续写入多个数据(最多16个),DSP会自动将这些数据发送出去,无需CPU干预,还可以设置发送完成后进中断;通过FIFO接收数据时,经由设置SCIFFRX寄存器,可以实现接收若干个字节的数据后(最多16个)进入中断,在中断中处理这些数据,这就减少了接受多个数据时,CPU进中断的次数,提高了效率。

使用FIFO时,有两个问题需要明确:

(1)如何访问FIFO

写发送FIFO通过SCITXBUF寄存器,读接收FIFO通过SCIRXBUF寄存器。

(2)FIFO中断

FIFO模式有两个中断,一个用于FIFO发送,一个用于FIFO接收。对于FIFO发送中断来说,当使能FIFO,且使能TXFIFO中断后,标准的TXINT将不再起作用,该中断仅作为SCI FIFO发送中断工作;对于串行接收中断而言,RXINT中断是SCI FIFO接收、接收错误和接收FIFO溢出的共同中断。

FIFO发送和接收中断都可以设置为匹配中断。对FIFO发送来说,SCIFFTX寄存器中的位TXFFST4-0表明当前的发送FIFO中有多少个字节的数据,位TXFFIL4-0为用户设定的接收FIFO中断匹配级别,当TXFFST4-0的值小于或等于TXFFIL4-0的值时,产生发送匹配中断;对FIFO接收来说,SCIFFRX寄存器中的位RXFIFST4-0表明当前接收FIFO中有多少个字节的数据,位RXFFIL4-0为用户设定的发送FIFO中断匹配级别,当RXFIFST4-0的值大于或等于RXFFIL4-0的值时,产生接收匹配中断。

FIFO寄存器可以设置为:

/*使能FIFO,发送FIFO空,禁用TXFIFO中断,清除TXFIFO中断标志,使能TXFFIVL匹配中断,匹配值为0,即:当TXFIFO中数据为0时进入发送中断。*/

SciaRegs.SCIFFTX.all=0xe060;

/*清RXFFOVF标志,使能FIFO接收,接收FIFO空,清除RXFFINT中断标志,使能RXFFIVL匹配中断,匹配值为16,即:FIFO中的数据大于等于16时进入发送中断*/

SciaRegs.SCIFFRX.all=0x6070;

/*禁止串口自动检测波特率*/

SciaRegs.SCIFFCT.all=0;

程序使用队列数据结构,可以更好的将串口程序模块化。同时,利用队列对串行数据再做一级缓冲,不仅保证了数据的顺序,而且解除了使用FIFO最多一次写入16个字节的限制,最多能写入的数据个数取决于队列缓冲区的大小,而这是由用户定义的。只要发送队列缓冲区中有待发送的数据,就采用中断间歇性的进行发送。串行接收采用类似方式,接收到一定数量的数据后再通知上层程序,CPU不必频繁进入中断。

队列是一种先入先出的线性表,它只允许在表的一端写入数据,而在另一端读取数据。它的操作一般有以下函数:

//获取队列中的数据,buf为指向队列的指针,rdata为指向读到的数据的指针

QueueRead(unsigned char *rdata, void *buf);

//向队列中写入数据,buf为指向队列的指针,wdata为要写入的数据

QueueWrite(void *buf,unsigned char wdata);

//获取队列中元素个数

QueueNData(void *Buf)

本文使用了两个队列来对串行数据进行缓冲,一个是DSP串行发送数据的队列TxQueue,另一个是DSP串行接收数据的队列RxQueue。各有100级深度。

3.串行发送

利用队列和FIFO的串口发送程序由两部分组成。一部分是供主程序调用的应用型函数,另一部分为中断程序,它完成数据的发送。以下是一个应用型函数的例子,DSP2812串行发送一个字节的数据:

void SciaSendChar(unsigned char sChar) { //sChar为待发送的数据

QueueWrite(TxQueue,sChar); //sChar入队,TxQueue为指向发送队列的指针

if(SciaRegs.SCIFFTX.bit.TXFFIENA==0) //允许 TXFIFO 匹配中断

SciaRegs.SCIFFTX.bit.TXFFIENA=1;

}

SciaSendChar(unsigned char sChar)函数由主函数调用,它将要发送的数据入队。而后使能FIFO发送中断。

在上文的FIFO设置中,已设置当TXFIFO中数据为0时进入发送中断,由于串行通讯开始前TXFIFO中并无数据,所以一旦FIFO发送中断打开,就立即进入该中断程序。

串行发送中断程序的一种写法:

interrupt void SCITXINTA_ISR(void) { // SCI-A中断服务程序

unsigned char temp=0,i=0; //定义局部变量

//ReadByte为从队列中读到的数据,pReadByte为指向ReadByte的指针

unsigned char ReadByte,*pRead

-Byte; pReadByte=&ReadByte;

SciaRegs.SCIFFTX.bit.TXINTCLR=1; //清中断标志

PieCtrl.PIEACK.bit.ACK9=1; EINT; //允许同组其他中断,允许嵌套

temp=QueueNData(TxQueue); //获取发送队列中元素个数

if((temp>0)&&(temp

for(i=0;i

QueueRead(pReadByte,TxQueue);

SciaRegs.SCITXBUF=

ReadByte; }}

else if(temp>16) { //若元素个数大于16,则在FIFO中写入16个元素

for(i=0;i

QueueRead(pReadByte,TxQueue);

SciaRegs.SCITXBUF=

ReadByte; }}

else //以上两种情况都不是,说明发送队列中已无元素,发送完,关中断

SciaRegs.SCIFFTX.bit.TXFFIENA=0; //禁用TXFIFO匹配中断

return; }

串行数据的发送是在中断中完成的,只要发送队列中还有数据,就会间歇性进入该中断,中断程序会判断当前发送队列还有多少个元素等待发送,若不足16个,则把数据全部写入FIFO,若大于16个,则写入16个,写入FIFO的数据,DSP会自动发送出去,无需CPU的干预。当发送队列中无数据时,则判定为发送完,关闭中断,防止因FIFO空而反复进入该中断。

若CPU有其他的关键进程需要响应,则可以把该关键进程的中断优先级设置得高于串行发送中断,这样在发送数据时依然可以响应关键进程。

4.串行接收

利用FIFO的串行接收程序同样由两部分组成,一部分是串行接收中断,另一部分是从串行接收队列中取数的程序。

串行接收中断的一种实现方法:

interrupt void SCIRXINTA_ISR(void)

{ // SCI-A,FIFO接收中断服务程序

unsigned char i=0; //循环变量

unsigned char Rxdata,; //暂存接收到的数据

SciaRegs.SCIFFRX.bit.RXFFINTCLR=1; //清中断标志

PieCtrl.PIEACK.bit.ACK9=1; EINT; //响应同组其他中断,允许嵌套

for(i=0;i

QueueWrite(RxQueue, Rxdata); //存往串行接收数据队列RxQueue

}}

在上文的FIFO设置中,我们令FIFO中的数据大于等于16时进入串行接收中断,中断程序只需要取出数据并将之存往串行接收队列RxQueue即可。在这里有一个隐含的约定,即,串行接收的数据数量必须大于等于16字节,否则由于串行接收匹配中断的执行条件不满足,将导致该中断不执行,无法处理FIFO接收的数据。

在主函数或其他中断程序(如定时中断)中再处理RxQueue中接收到的数据,这样处理起来非常灵活,实际应用中可根据需要编写程序。下面给出在主函数中处理RxQueue的一个简单例子供参考。

if(QueueNData(RxQueue)>50) { //若RxQueue队列数据超过50个

for(i=0;i

QueueRead(pReadByte,TxQueue); //pReadByte=&ReadByte,ReadByte为从队列中取出的数据

ReceivedData[i]=ReadByte; } } //存往ReceiveData数组

总结

本文提出了一种工程上实用的DSP串行通讯的方法。该方法采用DSP的FIFO和数据队列对串行数据进行了两级双向缓冲,利用中断完成数据收发,有实时性好,可靠性高等优点,可以方便的移植到其他芯片上,有一定的通用性。该程序已在作者的一个项目中得到应用,运行稳定。

参考文献

[1]TMS320x281x Serial Communications Interface(SCI)Reference Guide.TI公司,2009,7.

[2]严蔚敏,吴伟民编著.数据结构(C语言版)[M].

2002,9.

[3]陈明计,等编著.嵌入式实时操作系统Small RTOS51原理与应用[M].2005,7.

作者简介:

王刚(1981—),男,河北保定人,硕士,湖南湘潭江南机器集团有限公司工程师。

林明辉(1981—),男,海南文昌人,大学本科,湖南湘潭江南机器集团有限公司工程师。