用户注册



邮箱:

密码:

用户登录


邮箱:

密码:
记住登录一个月忘记密码?

发表随想


还能输入:200字
云代码 - c代码库

数据帧接收

2016-06-28 作者: stopshooting举报

[c]代码库

/**********************************************************************************************************
建立头文件"transport.h"
**********************************************************************************************************/
#ifndef __TRANSPORT_H
#define __TRANSPORT_H

#include "stm8_macro.h"

/*********************************************************
 接收数据帧:
 1.结构  : 2字节帧头 + 1字节长度信息 + 数据 + 1字节校验码
 
 2.移植  : 1).IC层,数据的接收中断与发送函数。
           2).CRC_Calculation(u8* ),校验码计算
           
 3.OUTPUT: 1).调用DataFrame_Receive()将接收到的原始数据经过处理、CRC校验,
              将得到的有效数据帧存放于RcvFrameCache.Cache[]中,数据
              不包含帧头。
           2).接收数据超时:调用DataFrame_Receive()接收一帧数据的过程中,
              超过(TIME_OUT)次扫描未接收到数据则输出超时Cmd_TimeOut。
           3).调用getDataFrame(u8* buffer)从RcvFrameCache.Cache[]中获取数据帧
*********************************************************/

//////////////////////// 参数配置 ////////////////////////

// 长度信息计算方法:
// 0: 长度 = 长度信息本身字节数 + 数据 + 校验码
// 1: 长度 = 长度信息本身字节数 + 数据
// 2: 长度 = 数据 + 校验码
// 3: 长度 = 数据
#define LENGTH_METHOD              (0L)

#define FRAME_HEAD1                (0XFFul)//帧头1
#define FRAME_HEAD2                (0xF0ul)//帧头2

#define FRAME_LENGTH_MIN           (5ul)   //一帧数据的最小长度
#define FRAME_LENGTH_MAX           (20ul)  //一帧数据的最大长度

#define ROW_DATA_SIZE              (100ul) // 接收到的原始数据缓存大小
#define FRAME_CACHE_SIZE           (200ul) // 接收到的帧数据缓存大小

#define TIMEOUT_MECHANISMS_ENABLE  1       //超时处理机制  0:失能  1:使能

#if TIMEOUT_MECHANISMS_ENABLE != 0
	#define TIME_OUT               (500ul) //接收一帧数据超时的时间阈值,
								           //单位:调用Command_Receive()函数的周期
#endif

//////////////////////////////////////////////////////////

typedef enum {
  Cmd_NoCmd = 0, //未收到完整数据包
  Cmd_OK,        //接收成功
  Cmd_TimeOut,   //接收超时
  Cmd_LEN_Wrong, //接收到的数据包错误(长度不在范围内)
  Cmd_CRC_Wrong  //CRC校验错误
} _frameRes_;


void Uart_Init(u32 baudrate);
void UartSendData(u8 *ptr, u8 len);
u8   UartSendStr(u8 *str);

u8 CRC_Calculation(u8* pbuf);
_frameRes_ DataFrame_Receive(void);
_frameRes_ getDataFrame(u8 *buffer);
u8 framePakage(u8 *buffer, const u8 cmdDataLen, ...);

#endif /*__TRANSPORT_H*/


/**********************************************************************************************************
建立源文件"transport.c"
***********************************************************************************************************/

#include "transport.h"
#include "stdarg.h"
#include "stm8s.h"



//从接收到的数据帧中获取 总长度 = 长度 + 数据 + 校验码
//len : 长度信息
#if   LENGTH_METHOD == 0
	#define GET_TOTAL_LENGTH(len)  (len)
#elif LENGTH_METHOD == 1
	#define GET_TOTAL_LENGTH(len)  (len+1)
#elif LENGTH_METHOD == 2
	#define GET_TOTAL_LENGTH(len)  (len+1)
#elif LENGTH_METHOD == 3
	#define GET_TOTAL_LENGTH(len)  (len+2)
#else
	#error "wrong define LENGTH_METHOD !"
#endif


typedef enum{
  FINDING_HEAD1 = 0,
  FINDING_HEAD2,
  NEED_LENGTH,
  GETTING_DATA,
  GETTING_CHECKSUM
} RcvStatus_TypeDef;

volatile struct{
  u8 Reg[ROW_DATA_SIZE];     //串口接收到的原始数据缓存
  u8 countTail;              //串口接收计数
} RcvRawData;                //接收到的原始数据

struct {
  u8  Cache[FRAME_CACHE_SIZE]; //接收有效指令缓存器,不包含帧头
  u8  countTail;               //
} RcvFrameCache;               //接收到的帧数据

//#define DEBUG
#ifdef DEBUG
struct {
  u16 correctNum;
  u8  errNum;
  u8  errbuf[256];
} FrameNum;
#endif

static void RowDataInput(u8 byte);

////////////////////////////////////////////////////////////

//----------------------------------------------------------------

/******** IC层 ********/

/*
 @Function : UART初始化
             8bit数据位,1位停止位,无校验位,允许接收和发送
 @Input    : 波特率
 @Output   : None
 **/
 
void Uart_Init(u32 baudrate)
{
	UART2_Cmd(DISABLE);

	UART2_DeInit();  //恢复默认值
	
    UART2_Init(baudrate, 
               UART2_WORDLENGTH_8D,            // 8bit数据位
               UART2_STOPBITS_1,               // 1bit停止位
               UART2_PARITY_NO,                // 无校验位
               UART2_SYNCMODE_CLOCK_DISABLE,   // 禁用同步模式
               UART2_MODE_TXRX_ENABLE);        // 发送、接收使能

	UART2_ITConfig(UART2_IT_RXNE_OR, ENABLE);  // 开接收中断 
	
	UART2_Cmd(ENABLE);                         // 使能UART2
}

/*
 @Function : 发送数据
 @Input	    : ptr   数据首地址
             len   要发送的长度
 @Output   : None
 **/
void UartSendData(u8 *ptr, u8 len)
{
    while(len--)
    {
		while(UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET);
		UART2_SendData8(*ptr++);
    }
}

/*
 @Function : 发送数据
 @Input	    : ptr   数据首地址
 @Output   : 发送的字节长度
 **/
u8 UartSendStr(u8 *str)
{
	u8 i;

	for(i=0; *str != 0x00; i++)
	{
		while(UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET);
		UART2_SendData8(*str++);
	}
	return i;
}

/*
 @Function : UART2中断服务函数
 @Input	    : None
 @Output   : None
 **/
@far @interrupt void UART2_IRQHandler(void)
{
	u8 byte;
	
	if(UART2_GetFlagStatus(UART2_FLAG_RXNE) != RESET)
	{
		UART2_ClearFlag(UART2_FLAG_RXNE);
		
		byte = UART2_ReceiveData8();
		
		RowDataInput(byte);
	}
}

//----------------------------------------------------------------

/******** 传输层 ********/

/*
 @Function : CRC计算
 @Input	    : ptr  数据帧首地址,不包含帧头(首地址内容为长度)
 @Output   : CRC校验码
 **/
u8 CRC_Calculation(u8* pbuf)
{
	u8 len, check_code;
	
	len = pbuf[0];
	check_code = (u8)(len ^ pbuf[1] ^ pbuf[len-3] ^ pbuf[len-2]);
	
	return check_code;
}

/*
 @Function : 数据帧CRC校验
 @Input	    : ptr  数据帧首地址
 @Output   : 0  校验失败
             1  校验成功
 **/
static u8 CRC_Check(u8 *pbuf)
{
	u8 len, check_code;
	
	len = pbuf[0];
	check_code = CRC_Calculation(pbuf);

	if(check_code == pbuf[len-1])
	{
		return 1;
	}
	return 0;
}

/*
 @Function : 数据复制
 @Input	    : ptrdes
             ptrsrc
             len    复制的字节长度
 @Output   : 目的地址
 **/
static void* mymemcpy(void* pdes, void* psrc, unsigned int len)
{
	char* ptrdes = (char*)pdes; 
	char* ptrsrc = (char*)psrc;

	if(pdes == 0 || psrc == 0)
		return pdes;
	if(ptrdes>ptrsrc?(ptrdes-ptrsrc<len):(ptrsrc-ptrdes<len))//有重叠
	{
		return pdes;
	}
    while(len--)
    {
        *ptrdes++ = *ptrsrc++;
    }
	return pdes;
}

/*
 @Function : 封装成帧
 @Attention: STVD 环境下: va_list 在调用va_arg()后地址至少+2,
             故输入的可变形参必须为 2字节变量
 @Input	    : buffer     封装后的数据存入地址
             cmdDataLen 数据长度(不包含:包头,长度,校验码)
             ...        数据(必须为16位变量) (不包含:包头,长度,校验码)
 @Output   : 1 输入数据有误
			  0 成功
 **/
u8 framePakage(u8 *buffer, const u8 cmdDataLen, ...)
{
	unsigned char i;
	unsigned char frame[FRAME_LENGTH_MAX];
	va_list ap;
	
	va_start(ap, cmdDataLen);

	if(cmdDataLen < FRAME_LENGTH_MIN - 1)
	{
		return 1;//输入数据错误
	}
	frame[0] = FRAME_HEAD1;
	frame[1] = FRAME_HEAD2;

	//长度
#if   LENGTH_METHOD == 0
	frame[2] = (unsigned char)(cmdDataLen + 2);
#elif LENGTH_METHOD == 1 || LENGTH_METHOD == 2
	frame[2] = (unsigned char)(cmdDataLen + 1);
#elif LENGTH_METHOD == 3
	frame[2] = (unsigned char)cmdDataLen;
#endif
	//数据
	for(i=0; i<cmdDataLen; i++)
	{
		frame[i+3] = (unsigned char)va_arg(ap, unsigned int);
		i = i;
	}
	va_end(ap);
	
	frame[i+3] = CRC_Calculation(frame+2);
	mymemcpy(buffer, frame, FRAME_LENGTH_MAX);
	return 0;
}

/*
 @Function : 输入接收到的原始数据
 @Input    : byte   接收到的1字节原始数据
 @Output   : None
 **/
static void RowDataInput(u8 byte)
{
	if(++RcvRawData.countTail >= ROW_DATA_SIZE)
	{
		RcvRawData.countTail = 0;
	}
	RcvRawData.Reg[RcvRawData.countTail] = byte;
}

/*
 @Function : 接收数据帧(用于扫描接收数据)
             接收到的数据存储于RcvFrameCache.Cache中
 @Input    : None
 @Output   : 接收状态
 **/
_frameRes_ DataFrame_Receive(void)
{
	static u8 buffer[FRAME_LENGTH_MAX];
	static RcvStatus_TypeDef RcvStatus;
    static u8 rec_countHead;
    static u8 cmd_offset;
	static u8 total_len;
#ifdef TIMEOUT_MECHANISMS_ENABLE
    static u16 timeout;
#endif
    u8 byte;
	_frameRes_ res = Cmd_NoCmd;

    if(rec_countHead != RcvRawData.countTail)//有接收到数据
    {
		if(++rec_countHead >= ROW_DATA_SIZE)
		{
			rec_countHead = 0;
		}
		
        switch(RcvStatus)
        {
            case FINDING_HEAD1 :
				byte = RcvRawData.Reg[rec_countHead];
                if(byte == (u8)(FRAME_HEAD1))
                {
                    RcvStatus = FINDING_HEAD2;
					#ifdef TIMEOUT_MECHANISMS_ENABLE
					timeout = 0x8000;
					#endif
                }
                break;
            case FINDING_HEAD2 :
				byte = RcvRawData.Reg[rec_countHead];
                if(byte == (u8)(FRAME_HEAD2))
                {
                    RcvStatus = NEED_LENGTH;
                }
                else
                {
                    RcvStatus = FINDING_HEAD1;
                }
                break;
            case NEED_LENGTH :
				byte = RcvRawData.Reg[rec_countHead];
                if(byte<FRAME_LENGTH_MIN || byte>FRAME_LENGTH_MAX)
                {
                    RcvStatus = FINDING_HEAD1;
                    res = Cmd_CRC_Wrong;
                    break;
                }
                cmd_offset = 0;
				buffer[cmd_offset++] = byte;
                RcvStatus = GETTING_DATA;
                break;
            case GETTING_DATA :
				byte = RcvRawData.Reg[rec_countHead];
				buffer[cmd_offset++] = byte;
				total_len = GET_TOTAL_LENGTH(buffer[0]);
				if(cmd_offset == total_len - 1)
				{
					RcvStatus = GETTING_CHECKSUM;
				}
                break;
			case GETTING_CHECKSUM :
				byte = RcvRawData.Reg[rec_countHead];
				buffer[cmd_offset] = byte;
				RcvStatus = FINDING_HEAD1;
				timeout = 0;
				if(CRC_Check(buffer))//CRC校验
				{
					if(RcvFrameCache.countTail + total_len - 1 >= FRAME_CACHE_SIZE)
					{
						mymemcpy(&RcvFrameCache.Cache[RcvFrameCache.countTail], 
								  buffer, 
								  (int)(FRAME_CACHE_SIZE - RcvFrameCache.countTail));
						mymemcpy(&RcvFrameCache.Cache[0], 
								  buffer + (FRAME_CACHE_SIZE - RcvFrameCache.countTail), 
								  (int)(RcvFrameCache.countTail + total_len - FRAME_CACHE_SIZE));
						RcvFrameCache.countTail = (u8)(RcvFrameCache.countTail + total_len - FRAME_CACHE_SIZE);
					}
					else
					{
						mymemcpy(&RcvFrameCache.Cache[RcvFrameCache.countTail], 
								  buffer, 
								  total_len);
						RcvFrameCache.countTail += total_len;
					}
					res = Cmd_OK;
				}
				else
				{
					res = Cmd_CRC_Wrong;
				}
				break;
        }
    }
	#if TIMEOUT_MECHANISMS_ENABLE != 0
    else//没有接收到数据
    {
		//超时计时
		if(timeout & 0x8000)
		{
			if((++timeout & ~0x8000) >= TIME_OUT)
			{
				timeout = 0;
				RcvStatus = FINDING_HEAD1;
				res = Cmd_TimeOut;
			}
		}
    }
	#endif
	#ifdef DEBUG
	if(res == Cmd_OK)
		FrameNum.correctNum++;
	else if(res != Cmd_NoCmd)
	{
		static u8 Framecount = 0;
		FrameNum.errNum++;
		FrameNum.errbuf[Framecount++] = res;
	}
	#endif
    return res;
}

/*
 @Function : 获取数据帧(获取缓存中未处理的数据帧)
             接收到的数据存储于RcvFrameCache.Cache中,
 @Input    : buffer
 @Output   : 接收状态
 **/
_frameRes_ getDataFrame(u8 *buffer)
{
	#ifdef DEBUG
	u8 i;
	u8 framebuf[FRAME_LENGTH_MAX];
	#endif
	vu8 total_len;
	static u8  countHead;
	_frameRes_ fr = Cmd_NoCmd;;
    if(countHead != RcvFrameCache.countTail)
    {
		total_len = RcvFrameCache.Cache[countHead];
		total_len = GET_TOTAL_LENGTH(total_len);
		if(countHead + total_len - 1 >= FRAME_CACHE_SIZE)
		{
			mymemcpy(buffer, 
					 &RcvFrameCache.Cache[countHead], 
					 (int)(FRAME_CACHE_SIZE - countHead));
			mymemcpy(buffer + (FRAME_CACHE_SIZE - countHead), 
					 &RcvFrameCache.Cache[0], 
					 (int)(countHead + total_len - FRAME_CACHE_SIZE));
			countHead = (u8)(countHead + total_len - FRAME_CACHE_SIZE);
		}
		else
		{
			mymemcpy(buffer, 
					 &RcvFrameCache.Cache[countHead], 
					 total_len);
			countHead += total_len;
		}
		fr = Cmd_OK;
		
	#ifdef DEBUG
		for(i=0; i<FRAME_LENGTH_MAX; i++)
		{
			framebuf[i] = 0x00;
		}
		mymemcpy(framebuf, 
			     buffer, 
			     FRAME_LENGTH_MAX);
	#endif
    }
	return fr;
}




网友评论    (发表评论)


发表评论:

评论须知:

  • 1、评论每次加2分,每天上限为30;
  • 2、请文明用语,共同创建干净的技术交流环境;
  • 3、若被发现提交非法信息,评论将会被删除,并且给予扣分处理,严重者给予封号处理;
  • 4、请勿发布广告信息或其他无关评论,否则将会删除评论并扣分,严重者给予封号处理。


扫码下载

加载中,请稍后...

输入口令后可复制整站源码

加载中,请稍后...