2022年4月1日
Kshine
1. 背景需求
(1)项目需要,使得CAN具有FIFO收发的功能。CAN1和CAN2的接收和发送都需要具有一定的数据缓冲功能。
(2)FIFO,先存入的数据,先被读出。这就像是一个管道,或者说是一个传送带。(下图请忽略)
(3)存放数据的管道,长度不可能无限制的长。因而必须考虑改用环形队列。当管道装满数据后,先放的数据还没有被拿走,时效性算是最差的,因而将最新的数据(这次要放入管道的数据)覆盖最开始的数据。(下图请忽略)
(4) 在设计环形队列的时候,首尾的连接处需要格外注意。
2. 环形队列的设计
- 在代码中的体现,实际就是一个定长的数组。
- 可以通过双指针配合操作(相当于图中的两个小人配合操作)。(一开始试过,太绕了)
- 可以通过单指针,知道数据个数的方式操作。(本人采取的方式,比较直接易懂)
2.1 简述思路
- 上图所示,是我实际写代码时,使用的思路。
- 变量名解释:rh1 (接收通道1的开头,读取数据时的起始位置);fifoDataLen (当前已存放的字节数,可用来找到数据的尾部,即写入数据时的起始位置);RR (从rh1到数组最右边的剩余字节长度,Right Remain)。
- 由上图可知,读取数据的位置rh1,是会变化的。每次读取N个字节,rh1就会向右移动N个字节。方便下次读到未被读出的数据。
- 在写入和读取数据的时候,都需要考虑 数组首尾连接处的特殊处理。
2.2 代码
- 函数声明与宏定义
#define CAN_FIFO_MEMSIZE (1024)
/*---------------------------------
初始化某一端口(收发双路)的FIFO
输入参数:port 端口,1-CAN1 2-CAN2
---------------------------------*/
int init_MyFifo(uint16_t port);
/*---------------------------------
该函数一般不使用,仅在调试的时候使用。
初始化某一端口(收发双路)的FIFO,并重新指定缓冲区(缓冲区的长度还是要等于CAN_FIFO_MEMSIZE)
输入参数:port 端口,1-CAN1 2-CAN2
rcvSnd ,1-接收通道,2-发送通道
buf,指定的外部缓冲区
---------------------------------*/
int init_MyFifo_Buff(uint16_t port,uint8_t rcvSnd,uint8_t* buf);
/*---------------------------------
从环形队列里面读取指定长度的数据
输入参数:port 端口,1-CAN1 2-CAN2
rcvSnd ,1-接收通道,2-发送通道
data,用于存放读取得到的数据
len,需要读取的字节数
---------------------------------*/
int loopBuffRead (uint32_t port,uint8_t rcvSnd,uint8_t* data,int len);
/*---------------------------------
向环形队列里面写入指定长度的数据
输入参数:port 端口,1-CAN1 2-CAN2
rcvSnd ,1-接收通道,2-发送通道
data,需要写入的源数据
len,需要写入的字节数
---------------------------------*/
int loopBuffWrite(uint32_t port,uint8_t rcvSnd,uint8_t* data,int len);
- 双路收发4通道缓冲区定义
static uint8_t CAN1_FIFO_RCV[CAN_FIFO_MEMSIZE];
static int CAN1_FIFO_RcvLen=0;
static uint8_t *CAN1_R=NULL; //数据开头位置
static uint8_t CAN1_FIFO_SND[CAN_FIFO_MEMSIZE];
static int CAN1_FIFO_SndLen=0;
static uint8_t *CAN1_S=NULL; //数据开头位置
static uint8_t CAN2_FIFO_RCV[CAN_FIFO_MEMSIZE];
static int CAN2_FIFO_RcvLen=0;
static uint8_t *CAN2_R=NULL; //数据开头位置
static uint8_t CAN2_FIFO_SND[CAN_FIFO_MEMSIZE];
static int CAN2_FIFO_SndLen=0;
static uint8_t *CAN2_S=NULL; //数据开头位置
- 详细函数实现
int init_MyFifo(uint16_t port)
{
if(port == 1)
{
CAN1_R = CAN1_FIFO_RCV;
CAN1_S = CAN1_FIFO_SND;
CAN1_FIFO_RcvLen = 0;
CAN1_FIFO_SndLen = 0;
}
else if(port == 2)
{
CAN2_R = CAN2_FIFO_RCV;
CAN2_S = CAN2_FIFO_SND;
CAN2_FIFO_RcvLen = 0;
CAN2_FIFO_SndLen = 0;
}
else return -1;
//FIFO初始化时,打印该信息
printf("-> FIFO: Port%d, Len%d\n\r",port,CAN_FIFO_MEMSIZE);
return 0;
}
int init_MyFifo_Buff(uint16_t port,uint8_t rcvSnd,uint8_t* buf)
{
if(port == 1)
{
if(rcvSnd==1)
{
CAN1_R = buf;
CAN1_FIFO_RcvLen = 0;
}
else if(rcvSnd==2)
{
CAN1_S = buf;
CAN1_FIFO_SndLen = 0;
}
}
else if(port == 2)
{
if(rcvSnd==1)
{
CAN2_R = buf;
CAN2_FIFO_RcvLen = 0;
}
else if(rcvSnd==2)
{
CAN2_S = buf;
CAN2_FIFO_SndLen = 0;
}
}
return 0;
}
int loopBuffRead(uint32_t port,uint8_t rcvSnd,uint8_t* data,int len)
{
uint8_t *fifoAddress=NULL;
uint8_t *p=NULL;
int fifoDataLen = 0;
if(len <= 0) return -2;//-2 CAN接收错误;
if(port == 1)
{
if(rcvSnd == 1)
{
fifoAddress = CAN1_FIFO_RCV;
fifoDataLen = CAN1_FIFO_RcvLen;
p = CAN1_R;
}
else if(rcvSnd == 2)
{
fifoAddress = CAN1_FIFO_SND;
fifoDataLen = CAN1_FIFO_SndLen;
p = CAN1_S;
}
else
return -2;
}
else if(port == 2)
{
if(rcvSnd == 1)
{
fifoAddress = CAN2_FIFO_RCV;
fifoDataLen = CAN2_FIFO_RcvLen;
p = CAN2_R;
}
else if(rcvSnd == 2)
{
fifoAddress = CAN2_FIFO_SND;
fifoDataLen = CAN2_FIFO_SndLen;
p = CAN2_S;
}
else
return -2;
}
else
return -2;
if(p==NULL)return -1;
//-------------------------------------------------//
if(len>fifoDataLen) return -3; //-3 接收缓冲区长度小于CAN报文长度。
int RR = fifoAddress+CAN_FIFO_MEMSIZE - p;
if(RR <= 0)
{
RR = CAN_FIFO_MEMSIZE;
p = fifoAddress;
}
if(len < RR)
{
memcpy(data,p,len);
p +=len;
}
else //len >= RR
{
//数据分两边
memcpy(data,p,RR);
memcpy(data+RR,fifoAddress,len-RR);
p = fifoAddress + len-RR;
}
fifoDataLen -= len;
//-------------------------------------------------//
if(port == 1)
{
if(rcvSnd == 1)
{
CAN1_FIFO_RcvLen = fifoDataLen;
CAN1_R = p;
}
else if(rcvSnd == 2)
{
CAN1_FIFO_SndLen = fifoDataLen;
CAN1_S = p;
}
}
else if(port == 2)
{
if(rcvSnd == 1)
{
CAN2_FIFO_RcvLen = fifoDataLen;
CAN2_R = p;
}
else if(rcvSnd == 2)
{
CAN2_FIFO_SndLen = fifoDataLen;
CAN2_S = p;
}
}
return 0;
}
int loopBuffWrite(uint32_t port,uint8_t rcvSnd,uint8_t* data,int len)
{
uint8_t *fifoAddress=NULL;
uint8_t *p=NULL;
int fifoDataLen = 0;
if(len <= 0) return -2;
if(port == 1)
{
if(rcvSnd == 1)
{
fifoAddress = CAN1_FIFO_RCV;
fifoDataLen = CAN1_FIFO_RcvLen;
p = CAN1_R;
}
else if(rcvSnd == 2)
{
fifoAddress = CAN1_FIFO_SND;
fifoDataLen = CAN1_FIFO_SndLen;
p = CAN1_S;
}
else
return -2;
}
else if(port == 2)
{
if(rcvSnd == 1)
{
fifoAddress = CAN2_FIFO_RCV;
fifoDataLen = CAN2_FIFO_RcvLen;
p = CAN2_R;
}
else