您的位置:首页 > 其它

使用Msp430的串口中断接收一包数据

2010-06-25 21:25 351 查看
使用Msp430的串口中断接收一包数据

假设有一数据包,数据格式如表所示:

序号
项 目
长度(字节)
说明
1
数据包头(STX)
1
常量:0x02
2
数据单元长度(Data_len)
2
需传输的数据单元Data部分的长度,高字节在前,低字节在后。
例如:0x0010表示Data部分有16个字节。
3
需传输的数据单元(Data)
不定
长度由Data_len指出,数据单元头两个字节是命令码(终端发送命令到读写器)或状态码(读写器返回数据给终端),后面是其它参数。
4
冗余检验值(LRC)
1
Data部分数据各字节异或值。
5
数据包尾(ETX)
1
常量:0x03
数据包总长度为: Data_len + 5 字节,最长不能超过512字节。

程序实现如下所示:
#include <msp430x22x4.h>

typedef struct newStruct
{
unsigned char startFlag;
unsigned char finishFlag;
unsigned char lenHighFlag;
unsigned char lenLowFlag;
unsigned char dataFlag;
unsigned char lrcFlag;
unsigned char buf[512];
unsigned char lenHigh;
unsigned char lenLow;
unsigned char dataStartIndex;
unsigned short len;
unsigned short index;
unsigned short tempLen;
}rxstruct;
rxstruct rxArray;

void m430_InitUart()
{
P3SEL |= BIT4|BIT5;           // P3.4, P3.5 = USCI_A0 TXD/RXD

UCA0CTL1 |= UCSSEL_2;          // SMCLK

//以下三行为波特率设置使用
UCA0BR1  = 0;
UCA0BR0  = 104;         // 12MHz:1250->9600,625->19200,312->38400,214->56000,104->115200
UCA0MCTL = 0x02;         // Modulation UCBRSx = 1

UCA0CTL1 &= ~UCSWRST;    // Initialize USCI state machine
//IE2 |= UCA0RXIE | UCA0TXIE;  //注意应在初始化USCI之后,设置中断使能,否则不起作用,即若此句放在UCA0CTL1 &= ~UCSWRST;之前,则不会响应中断
IE2 |= UCA0RXIE;
}

unsigned char uart_CalLrc(unsigned char *buf, unsigned short len)
{
unsigned short i;
unsigned char lrc;
lrc = 0x00;

for( i=0; i<len; i++ )
{
lrc ^= buf[i];
}

return lrc;
}

void main()
{
WDTCTL = WDTPW + WDTHOLD;
BCSCTL1 = CALBC1_12MHZ;
DCOCTL  = CALDCO_12MHZ;

m430_InitUart();

rxArray.startFlag = 0;
rxArray.finishFlag = 0;

_EINT();
_BIS_SR(LPM4_bits);
while(1)
{
}
}

#pragma vector = USCIAB0RX_VECTOR
__interrupt void uartRxHandle()
{
unsigned char num;
num = UCA0RXBUF;

if( 0==rxArray.startFlag )//判断是否接收到帧头
{
if( 0x02==num )//判断帧头是否正确
{
rxArray.startFlag = 1;//标志已经接收到帧头
rxArray.finishFlag = 0;
rxArray.lenHighFlag = 0;
rxArray.lenLowFlag = 0;
rxArray.dataFlag = 0;
rxArray.lrcFlag = 0;
rxArray.index = 0;
rxArray.len = 0;//存储帧长度
rxArray.buf[rxArray.index] = num;
rxArray.index++;
}
return;
}

if( 0==rxArray.lenHighFlag )//判断是否接收到帧长度的高字节信息
{
rxArray.lenHighFlag = 1;//标志已经接收到帧长度的高字节
rxArray.lenHigh = rxArray.buf[rxArray.index] = num;
rxArray.index++;
return;
}

if( 0==rxArray.lenLowFlag )//判断是否接收到帧长度的低字节信息
{
rxArray.lenLowFlag = 1;//标志已经接收到帧长度的低字节
rxArray.lenLow = rxArray.buf[rxArray.index] = num;
rxArray.index++;
rxArray.dataStartIndex = rxArray.index;

rxArray.tempLen = rxArray.len = (rxArray.lenHigh<<8) + rxArray.lenLow;//增加一字节的帧尾
if( rxArray.len+5>512 )//如果数据长度大于12,则说明接收的数据长度信息有误,需要重新接收
{
rxArray.startFlag = 0;
rxArray.lenHighFlag = 0;
rxArray.lenLowFlag = 0;
}
return;
}

if( 0==rxArray.dataFlag )
{
rxArray.buf[rxArray.index] = num;//把数据存放到数组中
rxArray.index++;
rxArray.tempLen--;
if( 0==rxArray.tempLen )
{
rxArray.dataFlag = 1;
}
return;
}

if( 0==rxArray.lrcFlag )//接收lrc
{
rxArray.buf[rxArray.index] = num;
rxArray.index++;
rxArray.lrcFlag = 1;
if( 0!=uart_CalLrc( &rxArray.buf[rxArray.dataStartIndex], rxArray.len+1 ) )//判断接收数据的lrc是否正确
{
rxArray.startFlag = 0;
rxArray.lenHighFlag = 0;
rxArray.lenLowFlag = 0;
rxArray.dataFlag = 0;
rxArray.lrcFlag = 0;
}
return;
}

rxArray.buf[rxArray.index] = num;
rxArray.finishFlag = 1;
rxArray.startFlag = 0;
rxArray.lenHighFlag = 0;
rxArray.lenLowFlag = 0;
rxArray.dataFlag = 0;
rxArray.lrcFlag = 0;
if( rxArray.buf[rxArray.index]!=0x03 )//最后一个字节不是0x03,说明数据有误,需要重新接收
{
rxArray.finishFlag = 0;
}

if( rxArray.finishFlag )
{
//收到数据处理部分
}
}


本程序一个致命的bug就是,如果长度信息那两个字节的数据接收时出现错误,会导致不能正确组成一包数据,后面发送过来的数据包也不能正确接收。
如有一包数据(16进制):02 00 02 11 11 00 03,
如果接收过程出现错误,导致将长度的两个字节00 02在接收端变成了00 05,因此接收端会等待接收完5个字节的数据之后才认为完整的接收完一包数据,从而导致后面发送过来的完整的数据包的一部分会被拆分,周而复始的这样恶性循环下去,暂时还没想到好的解决办法!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: