发送ECAN数据:
void sendECAN(mID *message)
{
unsigned long word0=0; //合成帧的前三个字
unsigned long word1=0;
unsigned long word2=0;
//判断帧类型,是扩展帧,则前三个字定义不同,本例中为扩展帧格式
if(message->frame_type==CAN_FRAME_EXT)
{
word0=(message->id & 0x1FFC0000) >> 16; //取帧的最高11位,作为第一个字,右移16位,放到word1
word0=word0+0x0003; //这里是拓展帧,SRR和IDE都设置为1
word1=(message->id & 0x0003FFC0) >> 6; //取得6~17位一共12位
word2=(message->id & 0x0000003F) << 10; //取最后6位,放到字头
}
else
{
word0=((message->id & 0x000007FF) << 2); //这里是标准,SRR和IDE都设置为0
}
if(message->message_type==CAN_MSG_RTR)
{
if(message->frame_type==CAN_FRAME_EXT) //根据帧类型,将远程帧的位置设置为1,表示发送的是远程帧
word2=word2 | 0x0200;
else
word0=word0 | 0x0002;
//远程帧不需要跟数据,所以只需要发送头三个字就行了。FILTER<4:0>这5个位寄存器自动填充。
ecan1msgBuf[message->buffer][0]=word0;
ecan1msgBuf[message->buffer][1]=word1;
ecan1msgBuf[message->buffer][2]=word2;
}
else
{
word2=word2+(message->data_length & 0x0F); //如果是数据帧,先将数据长度在WORD2中写入。
ecan1msgBuf[message->buffer][0]=word0;
ecan1msgBuf[message->buffer][1]=word1;
ecan1msgBuf[message->buffer][2]=word2;
ecan1msgBuf[message->buffer][3]=((message->data[1] << 8) + message->data[0]); //继续填入数据域
ecan1msgBuf[message->buffer][4]=((message->data[3] << 8) + message->data[2]);
ecan1msgBuf[message->buffer][5]=((message->data[5] << 8) + message->data[4]);
ecan1msgBuf[message->buffer][6]=((message->data[7] << 8) + message->data[6]);
}
C1TR01CONbits.TXREQ0=1; //设置该位,请求发送一个帧。
}
在主循环中查找,如果状态为缓存满了,则开始读取。
读取的函数如下:
接收ECAN数据:
/******************************************************************************
*
* Function: rxECAN
* Description: moves the message from the DMA memory to RAM
*
* Arguments: *message: a pointer to the message structure in RAM
* that will store the message.
* Author: Jatinder Gharoo
*
*
******************************************************************************/
void rxECAN(mID *message)
{
unsigned int ide=0;
unsigned int rtr=0;
unsigned long id=0;
//先判断帧是标准的还是扩展帧,次位都定义在word0的最后一位的位置
ide=ecan1msgBuf[message->buffer][0] & 0x0001;
if(ide==0) //如果是标准帧,判断是远程帧还是数据帧
{
message->id=(ecan1msgBuf[message->buffer][0] & 0x1FFC) >> 2; //将ID读出来
message->frame_type=CAN_FRAME_STD; //为标准帧,将帧类型设置
rtr=ecan1msgBuf[message->buffer][0] & 0x0002; //将远程帧还是数据帧的标志读出来。
}
else
{
id=ecan1msgBuf[message->buffer][0] & 0x1FFC; //将11位读出来
message->id=id << 16; //放到ID号的头。
id=ecan1msgBuf[message->buffer][1] & 0x0FFF;//读WORD1,
message->id=message->id+(id << 6); //和刚刚读出来的组在一起
id=(ecan1msgBuf[message->buffer][2] & 0xFC00) >> 10; //继续读WORD2中的ID
message->id=message->id+id; //获取到完整的ID
message->frame_type=CAN_FRAME_EXT; //设置读取到的帧为拓展帧
rtr=ecan1msgBuf[message->buffer][2] & 0x0200;//将远程的标志设置好
}
if(rtr==1) //如果是远程帧,设置结构体消息类型为远程帧类型。
{
message->message_type=CAN_MSG_RTR;
}
else//如果是数据帧,则开始读数据
{
message->message_type=CAN_MSG_DATA; //类型设置为数据帧
message->data[0]=(unsigned char)ecan1msgBuf[message->buffer][3];//开始读数据,从BYTE0开始
message->data[1]=(unsigned char)((ecan1msgBuf[message->buffer][3] & 0xFF00) >> 8); //读高8位,作为BYTE1,保存到结构体数据存储1位置。
message->data[2]=(unsigned char)ecan1msgBuf[message->buffer][4];
message->data[3]=(unsigned char)((ecan1msgBuf[message->buffer][4] & 0xFF00) >> 8);
message->data[4]=(unsigned char)ecan1msgBuf[message->buffer][5];
message->data[5]=(unsigned char)((ecan1msgBuf[message->buffer][5] & 0xFF00) >> 8);
message->data[6]=(unsigned char)ecan1msgBuf[message->buffer][6];
message->data[7]=(unsigned char)((ecan1msgBuf[message->buffer][6] & 0xFF00) >> 8);
message->data_length=(unsigned char)(ecan1msgBuf[message->buffer][2] & 0x000F); //获取数据长度,继续保存到结构体中
}
clearRxFlags(message->buffer); //按照BUFFER号,以及在接收时硬件设置的BUFFER满标志读取,如果是BUFFER1,则把1清空。这里一共用到三个BUFFER,进行三次判断。
}
然后将收到的数据在液晶上显示出来。
ECAN的中断服务程序
void __attribute__((interrupt,no_auto_psv))_C1Interrupt(void)
{
if(C1INTFbits.RBIF) //中断来自已经收到一个存到BUFFER中的数据。
{
if(C1RXFUL1bits.RXFUL1) //如果传送来的数据保存在BUFFER1中
{
canRxMessage.buffer_status=CAN_BUF_FULL; //将这个状态设置给结构体,主程序中将通过这个标志来读BUFFER到RAM中。
canRxMessage.buffer=1; //告诉主程序BUFFER满还不行,还要告诉主程序读取的路径,为BUFFER1
}
else if(C1RXFUL1bits.RXFUL2)
{
canRxMessage.buffer_status=CAN_BUF_FULL;
canRxMessage.buffer=2;
}
else if(C1RXFUL1bits.RXFUL3)
{
canRxMessage.buffer_status=CAN_BUF_FULL;
canRxMessage.buffer=3;
}
else;
C1INTFbits.RBIF = 0; //接收标志要清空
}
else if(C1INTFbits.TBIF) //如果是发送数据产生的中断
{
puts_ecanTx(&canTxMessage); //将发送的数据在液晶上显示出来
C1INTFbits.TBIF = 0; //发送标志清空
}
else;
IFS2bits.C1IF=0; //同时要将ECAN中断标志情况。
}
问题点:
用到了DMA么?这里可以看到,在中断服务程序中只设置了标志,帧是读入到了DMA中,通知主程序在一次大循环后来读出DMA的值。
收到的数据没有MASK和FILTER?:在ECAN初始化函数中已经设置了MASK和FILTER,本例子中,标准模式,每位都需要比较,FILTER的ID是0x123,ID数据不对,则不会将数据读进来,这个是经过硬件处理的,不需要人工干预。
文章评论(0条评论)
登录后参与讨论