正点原子MiniFly V1.2学习笔记二---radiolinkTask

  第1个任务radiolinkTask 处理串口接收到的数据包,把命令提取出来。

一、数据包格式

  一条指令,包含 功能ID 和数据。功能ID–就是接收方用来区别需要做什么事,数据 --指令中需要的数据。另外,为了区别指令的开始位置,要在开始加上 帧头,为了保证接收正确,还要在最后加上一个校验,如果接收方发现校验错了,就把该指令丢弃。
  在atkp.h中:
1、宏定义,定义帧头,功能ID 等
2、结构体 数据定义
3、atkp.c中的函数声名,方便其它模块通过包含atkp.h头文件,就可以调用atkp.c中的函数

指令格式: 帧头(AA+AF)+功能ID+数据长度+数据+校验
正点原子MiniFly V1.2学习笔记二---radiolinkTask_第1张图片

二、任务void radiolinkTask(void *param)

xTaskCreate(radiolinkTask, "RADIOLINK", 150, NULL, 5, NULL);

任务优先级被定义为 5

    //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
					rxState = (c == DOWN_BYTE1) ? waitForStartByte2 : waitForStartByte1;
					cksum = c;
					break;
				case waitForStartByte2:  #帧头第2字节AF
					rxState = (c == DOWN_BYTE2) ? waitForMsgID : waitForStartByte1;
					cksum += c;
					break;
				case waitForMsgID:
					rxPacket.msgID = c;
					rxState = waitForDataLength;
					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;
					}
					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;
		}
	}
}

  任务的流程如下:
1、调用uartslkGetDataWithTimout(&c)获取1个字节
2、识别出帧头AA+AF
3、把功能ID,数据长度+数据 存到变量rxPacket中
4、这里采用的校验码是把前面所有的数据相加,只取1个字节。如果校验码正确,把接收到的存在rxPacket中的指令通过函数atkpPacketDispatch(&rxPacket);发送出去,然后回到开头等待帧头AA+AF
5、如果检验错误,也重新等待帧头AA+AF
6、如果1超时都没有获得1个字节,继续等待帧头AA+AF

  整个过程的逻辑还是比较简单,这就是系统的好处

三、函数uartslkGetDataWithTimout(&c)

上面的任务中,需要获取1个字节,这不是直接从串口获取,而是从队列uartslkDataDelivery获得。
正点原子MiniFly V1.2学习笔记二---radiolinkTask_第2张图片

四、函数atkpPacketDispatch(atkp_t *rxPacket)

解析出来的指令,调用atkpPacketDispatch(&rxPacket)把它发送到队列rxQueue中,发送的是指令的指针。然后看一下txQueue队列,有没有数据要回复给发送方,如果有,则取一条数据回复过去。
正点原子MiniFly V1.2学习笔记二---radiolinkTask_第3张图片

五、整个任务的框架

正点原子MiniFly V1.2学习笔记二---radiolinkTask_第4张图片

六、队列的定义

1、uartslkDataDelivery队列
正点原子MiniFly V1.2学习笔记二---radiolinkTask_第5张图片
2、rxQueue队列
正点原子MiniFly V1.2学习笔记二---radiolinkTask_第6张图片
3、txQueue队列
正点原子MiniFly V1.2学习笔记二---radiolinkTask_第7张图片

七、串口是怎么把一个字节接收到队列uartslkDataDelivery的

1、串口2初始化
正点原子MiniFly V1.2学习笔记二---radiolinkTask_第8张图片
2、串口2中断接收数据 到队列中
正点原子MiniFly V1.2学习笔记二---radiolinkTask_第9张图片

八、从txQueue取指令发送到串口

正点原子MiniFly V1.2学习笔记二---radiolinkTask_第10张图片
正点原子MiniFly V1.2学习笔记二---radiolinkTask_第11张图片

九、队列在什么地方定义

  从上面分析我们看到,串口中断接收到的数据放进队列uartslkDataDelivery中,在任务中,再从该队列读取数据。那么队列就相当于全局变量了,它需要定义在什么地方呢?
  1、uartslkDataDelivery队列----定义在uart_syslink.c开头----使用到该队列的函数:初始化函数,串口中断函数,从队列读数据函数,都定义在这个.c文件里---------任务函数通过包含#include "radiolink.h"头文件来调用这个.c文件的函数
正点原子MiniFly V1.2学习笔记二---radiolinkTask_第12张图片
正点原子MiniFly V1.2学习笔记二---radiolinkTask_第13张图片
正点原子MiniFly V1.2学习笔记二---radiolinkTask_第14张图片
正点原子MiniFly V1.2学习笔记二---radiolinkTask_第15张图片
  2、同理,rxQueue队列的,定义,初始化,向队列发送消息,从队列获取消息的函数,都定义在atkp.c文件里

  3、txQueue队列好像有点特殊,它在两个地方定义了usblink.c 和radiolink.c,这两个c文件里的队列只是同名而已,其实它是两个不同的队列,因为在定义的时候加了static 只限本文件使用,所以txQueue相当于每个文件的局部变量。

十、疑问

  这里有一个疑问,把接收到的指令解包到变量rxPacket中,然后把变量rxPacket的指针发送到队列rxQueue中,如果指令没有处理,接收第二指令的时候不是会把第一个指令覆盖了?因为都是接收到同一个变量里的啊。

  FreeRTOS的队列是值传递,发送函数的第二个参数就是指向 待发数据 的指针,在发送函数里会从该指令复制N个字节到队列里,N就是在队列初始化中定义的项目大小。
在这里插入图片描述

你可能感兴趣的:(FreeRTOS)