上位机程序图:
/*
* File: RF.C
* use: 圆梦小车无线通讯模块
* 主要实现小车与PC机软件的通信交流.
* 同时也期望可为处理小车之间的通信创建必要的条件
* Main point:
* 实现数据的可靠传输,即主、从机可检测数据传输中的错误,并尝试恢复
* 实现基本的多机通信机制,单主机、多从机
* 设计有效的通信协议,基本的协议分层,使代码易于移植
* By: lstzixing
* Date: 2009-6-1
*/
#include <inttypes.h>
#include "app.h"
#define RF_MASTER_ADDR 0x0 /* 主结点地址 ` */
#define RF_BROADCAST_ADDR 0xff /* 广播地址 */
#define RF_LOCALHOST_ADDR 0x1 /* 本机地址 */
#define RF_PREAMBLE 0x53 /* RF帧前导码 */
#define RF_FRAME_HDR_LEN 8 /* RF帧头部长度 */
#define RF_FRAME_DATA_LEN 20 /* RF数据域限长 */
#define RF_FRAME_MAX_LEN ( RF_FRAME_HDR_LEN + RF_FRAME_DATA_LEN )
#define RF_CFLAG_NAK 0x0 /* RF控制帧标志 NAK */
#define RF_TASK_PRIO 0x3 /* RF任务的优先级 */
#define RF_TASK_STK_LEN 100 /* RF任务的堆栈深度 */
#define RF_SLAVENODE_TIMEOUT 0x2 /* 从结点等待数据帧超时量,以OS的时钟为基准 */
typedef struct /* 通信帧 */
{
INT8U preamble; /* 通信帧前导码 */
INT8U len; /* 帧长度 */
INT8U src; /* 源结点地址 */
INT8U dest; /* 目的结点地址 */
INT8U seq; /* 序列号 */
INT8U cflag; /* 命令字 */
INT16U crc; /* CRC校验域 */
INT8U data[RF_FRAME_DATA_LEN]; /* 有效数据域 */
}RFFrame;
typedef BOOLEAN ( * CMDFun )( void * pdata, INT8U * len );
/* --------------------------------------------------------- */
OS_STK RFTaskStk[ RF_TASK_STK_LEN ]; /* RF任务堆栈区 */
static RFFrame rxFrame; /* 帧缓冲区 */
static RFFrame txFrame;
static INT8U recvError;
static OS_EVENT * rxSem, * txSem; /* 驱动层与应用层同步信号量 */
/* --------------------------------------------------------- */
static void RFSlaveNodeTask( void * pdata );
static void RFLowLevelInit( void );
static void RFLowLevelOutput( void );
void RFLowLevelInput( void );
void RFLowLeveOutputIsr( void );
/* ----------------------RF命令支持 --------------------- */
#define RF_CFLAG_READ_MEM 0x1 /* 请求读内存码 */
#define RF_CFLAG_WRITE_MEM 0x2 /* 请求写内存码 */
#define RF_CFLAG_LED_FLASH 0x3 /* 请求闪烁LED码*/
static BOOLEAN LEDFlash( void * pdata, INT8U * len ); /* RF_CFLAG_LED_FLASH支持 */
#define CMD_TBL_ENTRY_NR ( sizeof(CMDTbl) / sizeof( CMDFun ) )
const CMDFun CMDTbl[] = { /* RF命令表 */
( CMDFun )0, ( CMDFun )0, ( CMDFun )0,
LEDFlash
};
/* ---------------------- RF初始化 --------------------------*/
void RFInit( void )
{
recvError = 0;
rxSem = OSSemCreate(0);
txSem = OSSemCreate(1);
OSTaskCreate( RFSlaveNodeTask, ( void * )0, &RFTaskStk[ RF_TASK_STK_LEN - 1 ], RF_TASK_PRIO );
RFLowLevelInit();
}
/* --------------------- 创建数据帧 --------------------- */
static RFFrame * RFMakeFrame( RFFrame * frame, INT8U dest, INT8U seq, INT8U len, INT8U cflag )
{
if( frame != ( void * )0 )
{
frame->preamble = RF_PREAMBLE;
frame->src = RF_LOCALHOST_ADDR;
frame->dest = dest;
frame->len = len + RF_FRAME_HDR_LEN;
frame->seq = seq;
frame->cflag = cflag;
}
return frame;
}
/* --------------------- RF从结点任务 --------------------- */
static void RFSlaveNodeTask( void * pdata )
{
INT8U err;
INT8U len;
static INT8U lastSeq = 0;
static BOOLEAN firstRecv = TRUE;
pdata = pdata;
while(1)
{
/* 等待底层数据帧到达 */
OSSemPend( rxSem, RF_SLAVENODE_TIMEOUT, &err );
if( err == OS_TIMEOUT )
{
firstRecv = TRUE;
}
else if( rxFrame.dest == RF_LOCALHOST_ADDR )
{
/* 仅处理往本机的帧 */
if( firstRecv )
{
/* 首次接收到新帧,刷新帧序列号 */
firstRecv = FALSE;
lastSeq = rxFrame.seq - 1;
}
if( recvError == FALSE )
{
/* 帧在传输过程中未发生错误 */
if( rxFrame.seq != lastSeq )
{
/* 如果收到的帧是新的请求, 处理并响应 */
lastSeq = rxFrame.seq;
if( rxFrame.cflag < CMD_TBL_ENTRY_NR )
{
if( ( *( CMDTbl + rxFrame.cflag) )( txFrame.data, &len ) )
RFMakeFrame( &txFrame, rxFrame.src, lastSeq, len, rxFrame.cflag & 0x80 );
else
RFMakeFrame( &txFrame, rxFrame.src, lastSeq + 1, len, rxFrame.cflag );
RFLowLevelOutput( );
}
}
else
{
/* 重复帧,丢弃,重发帧 */
RFLowLevelOutput( );
}
}
else
{
/* 传输错误,发送NAK响应 */
RFMakeFrame( &txFrame, rxFrame.src, 0, 0, RF_CFLAG_NAK );
RFLowLevelOutput( );
}
}
}
}
/* ---------------------- RF底层初始化 ----------------- */
static void RFLowLevelInit( void )
{
/* RF底层硬件初始化,移植部分!!! */
UCSRB = 1<<RXCIE | 1<<TXCIE | 1<<RXEN | 1<<TXEN; // 收发使能,接收中断
UCSRC = 1<<URSEL| 1<<UPM1| 1<<UPM0| 1<<UCSZ1| 1<<UCSZ0; // 异步,8位字节,奇校验
UBRRL = ((INT32U)F_OSC / (16*(INT32U)UART_BAUD ) - 1 ) & 0xff; // 设置波特率
UBRRH = ((INT32U)F_OSC / (16*(INT32U)UART_BAUD ) - 1 ) >> 8;
}
/* ---------------------- RF底层数据发送处理 ----------------- */
static void RFLowLevelOutput( void )
{
static INT8U * data = (INT8U *)&txFrame;
static INT8U RFLowLevelOutputIndex = 0;
INT8U err;
while( RFLowLevelOutputIndex < txFrame.len )
{
/* 将DATA送至硬件端口,移植部分!!! */
UDR = data[ RFLowLevelOutputIndex++ ];
OSSemPend( txSem, 0, &err );
}
/* 发送完毕后关闭发送 */
RFLowLevelOutputIndex = 0;
}
/* ---------------------- RF底层数据发送中断处理 ----------------- */
void RFLowLeveOutputIsr( void )
{
/* 向调用RFLowLevelOutput的任务发信号,
* 指示发送完成.必须在中断中调用! */
OSSemPost( txSem );
}
/* ---------------------- RF底层数据接收处理 ----------------- */
void RFLowLevelInput( void )
{
static INT8U len;
static INT8U RFLowLevelInputIndex = 0;
INT8U * ptr;
INT8U data;
/* 从实际链路读取数据,移植部分!!! */
data = UDR;
ptr = (INT8U *)&rxFrame;
if( data == RF_PREAMBLE && RFLowLevelInputIndex == 0 )
{
/* 数据为前导码,且写索引为0, 指示新帧开始 */
ptr[ RFLowLevelInputIndex++ ] = data;
}
else
{
if( RFLowLevelInputIndex == 1 )
{
/* 获取数据帧长 */
len = data > RF_FRAME_MAX_LEN ? RF_FRAME_MAX_LEN : data;
}
ptr[ RFLowLevelInputIndex++ ] = data;
if( RFLowLevelInputIndex >= len )
{
/* 接收完毕,重置索引 */
RFLowLevelInputIndex = 0;
OSSemPost( rxSem );
}
}
}
/* ---------------------- RF_CFLAG_LED_FLASH 命令支持 ---------------- */
static BOOLEAN LEDFlash( void * pdata, INT8U * len )
{
*len = 0;
LEDToggle( LED1 );
return FALSE;
}
文章评论(0条评论)
登录后参与讨论