/********************************************************************************************************** |
建立头文件"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; |
} |