radiolinkTask:无线通信任务。该任务主要负责接收从 NRF51822 发送(串口方式)过 来的数据,然后对数据进行打包和校验,打包成 ATKP 格式并校验无误后发送到 atkpRxAnlTask 的接收队列里,同时回传一帧数据给 NRF51822。
- ATKP格式:详细见atkp.c(基于于匿名科创地面站V4.34通信协议下位机,示例代码修改)。
ATKP格式即为发送给匿名上位机的数据格式。
//atkp.h
/*上行帧头*/
#define UP_BYTE1 0xAA
#define UP_BYTE2 0xAA
/*下行帧头*/
#define DOWN_BYTE1 0xAA
#define DOWN_BYTE2 0xAF
#define ATKP_MAX_DATA_SIZE 30
/*通讯数据结构*/
typedef struct
{
uint8_t msgID;
uint8_t dataLen;
uint8_t data[ATKP_MAX_DATA_SIZE];
}atkp_t;
msgID:功能ID,表示该数据的意义,分为 上行指令ID :upmsgID_e ;下行指令ID :downmsgID_e
这是两个枚举变量
dataLen:数据长度
data:数据数组,最大为30
指令格式: 帧头(AA+AF)+功能ID+数据长度+数据+校验
- 下面对radiolinkTask任务进行分析
//radiolink接收ATKPPacket任务
void radiolinkTask(void *param)
{
rxState = waitForStartByte1;
u8 c;
u8 dataIndex = 0;
u8 cksum = 0;
while(1)
{
if (uartslkGetDataWithTimout(&c))///串口接收到数据
{
switch(rxState)
{
case waitForStartByte1: //帧头第1字节,若等于AA,校验第2字节
rxState = (c == DOWN_BYTE1) ? waitForStartByte2 : waitForStartByte1;
cksum = c;//cksum为校验和
break;
case waitForStartByte2: //若等于AF,读取MsgID,若不等于重头开始
rxState = (c == DOWN_BYTE2) ? waitForMsgID : waitForStartByte1;
cksum += c;
break;
case waitForMsgID:
rxPacket.msgID = c;
rxState = waitForDataLength;//读取MsgID,下一步读取DataLength
cksum += c;
break;
case waitForDataLength:
if (c <= ATKP_MAX_DATA_SIZE)
{
rxPacket.dataLen = c;
dataIndex = 0;
rxState = (c > 0) ? waitForData : waitForChksum1; /*c=0,数据长度为0,校验1*/
cksum += c;
} else
{
rxState = waitForStartByte1;//若数组大小大于设定值,重头开始
}
break;
case waitForData:
rxPacket.data[dataIndex] = c;
dataIndex++;
cksum += c;
if (dataIndex == rxPacket.dataLen)
{
rxState = waitForChksum1;//数据存储完成,校验1
}
break;
case waitForChksum1:
if (cksum == c) /*所有校验正确*/
{
atkpPacketDispatch(&rxPacket);
}
else /*校验错误*/
{
rxState = waitForStartByte1;
IF_DEBUG_ASSERT(1);//断言
}
rxState = waitForStartByte1;//重头开始
break;
default:
ASSERT(0);
break;
}
}
else /*超时处理*/
{
rxState = waitForStartByte1;//重头开始
}
}
}
任务比较简单,主要就是校验帧头AA+AF,并且将功能ID,数据长度,数据存入rxPacket结构体中;然后调用atkpPacketDispatch(&rxPacket);发送出去。
而校验和则是把所有数据相加,取一字节。
大部分的说明已经添加到了代码注释中了。
这里再说一下 uartslkGetDataWithTimout(&c)
的接收函数以及 *atkpPacketDispatch(&rxPacket)
*的发送函数。
/*从接收队列读取数据(带超时处理)*/
bool uartslkGetDataWithTimout(u8 *c)
{
/*接收uartslkDataDelivery(1024个容量)消息*/
if (xQueueReceive(uartslkDataDelivery, c, UARTSLK_DATA_TIMEOUT_TICKS) == pdTRUE)//任务出队函数,读取并删除
{
return true;
}
*c = 0;
return false;
}
函数uartslkGetDataWithTimout(u8 *c)是从uartslkDataDelivery队列中读取的。该队列在串口初始化函数void uartslkInit(void)
中定义;在串口2中断函数void uartslkIsr(void)
中调用xQueueSendFromISR(uartslkDataDelivery, &rxDataInterrupt, &xHigherPriorityTaskWoken);
函数接收。
void __attribute__((used)) USART2_IRQHandler(void)
{
uartslkIsr();
}//串口2非空中断
/*radiolink接收到ATKPPacket预处理*/
static void atkpPacketDispatch(atkp_t *rxPacket)
{
atkpReceivePacketBlocking(rxPacket);
if( rxPacket->msgID == DOWN_POWER)
{;}/*do noting*/
else
{
ledseqRun(DATA_RX_LED, seq_linkup);
/*接收到一个遥控无线数据包则发送一个包*/
if(xQueueReceive(txQueue, &txPacket, 0) == pdTRUE)
{
ASSERT(txPacket.dataLen <= ATKP_MAX_DATA_SIZE);
ledseqRun(DATA_TX_LED, seq_linkup);
uartSendPacket(&txPacket);
}
}
}
此函数有以下功能:
- 断言检查,将rxPacket发送至rxQueue队列中
- 若MsgID不是关电源,开启无线数据指示灯LED_GREEN_L;
- 若有需要发送的数据,读取txQueue队列的消息,并保存在txPacket中作为缓冲区
- 若数据大小符合要求,则开启发送指示灯,将数据通过串口DMA发送
队列
- uartslkDataDelivery队列
串口2中断接收,radiolinkTask中读取的数据 - rxQueue队列
处理指令的同时,把radiolinkTask接收的数据从rxPacket发送至rxQueue队列中
见函数atkpPacketDispatch(&rxPacket)
- txQueue队列
同样在函数atkpPacketDispatch(&rxPacket)
也会处理txQueue的数据,并存到txPacket打包后,通过串口DMA发送
本任务作为无线连接任务,一定是会存在各种数据的流动的,有的数据在这里就不具体分析了。