原创 PIC24HJ单片机自学笔记-ECAN数据帧通信程序解读2

2014-1-17 05:57 1856 15 15 分类: MCU/ 嵌入式 文集: PIC24HJ单片机自学笔记

 

发送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数据不对,则不会将数据读进来,这个是经过硬件处理的,不需要人工干预。
 
 
 
 
 
PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
15
关闭 站长推荐上一条 /3 下一条