minifly_v1.3学习笔记(二)radiolinkTask

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)*的发送函数。

  • uartslkGetDataWithTimout(&c)

/*从接收队列读取数据(带超时处理)*/
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非空中断
  • atkpPacketDispatch(&rxPacket)

/*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);
		}
	}
}

此函数有以下功能:

  1. 断言检查,将rxPacket发送至rxQueue队列中
  2. 若MsgID不是关电源,开启无线数据指示灯LED_GREEN_L;
  3. 若有需要发送的数据,读取txQueue队列的消息,并保存在txPacket中作为缓冲区
  4. 若数据大小符合要求,则开启发送指示灯,将数据通过串口DMA发送

队列

  1. uartslkDataDelivery队列
    串口2中断接收,radiolinkTask中读取的数据
  2. rxQueue队列
    处理指令的同时,把radiolinkTask接收的数据从rxPacket发送至rxQueue队列中
    见函数atkpPacketDispatch(&rxPacket)
  3. txQueue队列
    同样在函数atkpPacketDispatch(&rxPacket)也会处理txQueue的数据,并存到txPacket打包后,通过串口DMA发送

本任务作为无线连接任务,一定是会存在各种数据的流动的,有的数据在这里就不具体分析了。

发布了21 篇原创文章 · 获赞 2 · 访问量 2853

猜你喜欢

转载自blog.csdn.net/lalala12ll/article/details/101633285