[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;
}