[其他产品] 基于PIC32开发CAN监视器

[复制链接]
 楼主| 远芳侵古道 发表于 2021-2-24 22:34 | 显示全部楼层 |阅读模式
引言:CANController AreaNetwork)是目前使用非常广泛的一种通信方式,被大量应用于汽车、船泊、数控加工设备、机器人以及各种自动化设备。与之相关的工作人员——工程师、设备师、维修师、开发人员都将频繁与其打交道,不管是开发人员的初期调试,还是维修师检测设备的状况,对CAN总线的数据量都有监视的渴望,对两根差分的信号线,相通过示波器来监视总线上的数据,恐怕让人神精。当然,市面上也有商用CAN监视器,本人也用过,使用也还算方便,但不知道为啥,已经坏掉了好几个(与我无关),因为本人现在跳到一家资金捉襟见肘的小公司,咖啡都不给买,工资也发不起的扣老板,自制一台CAN监视器的想法诞生了。
 楼主| 远芳侵古道 发表于 2021-2-24 22:35 | 显示全部楼层
1. 框架图




        PC <<---->>USB接口<<---->>MCP2200<<---->>PIC32<<---->>CAN Transceiver<<---->>CAN 总线








关于USB接口,在这里就是与上位机PC通信的方式,是笔者惯用方式,一根USB线就可以,并且在PIC32里只需要做UART的驱动就可以了,十分简单。读者也可自行选择其他方式,比如使用PIC32自带的USB功能,HID或CDC都可以,用232芯片转换也行吧。

 楼主| 远芳侵古道 发表于 2021-2-24 22:35 | 显示全部楼层
2. PIC32 关于 CAN 模块的配置
请将CAN模块配置为监听模式(Listen-Onlymode)。

以下引自Microchip公司手册DS61154C_CN:

监听模式是正常工作模式的一种变化形式。如果监听模式被激活,则CAN模块会出现在CAN总线上,但处于被动状态。它会接收报文,但不会发送报文。CAN模块不会产生错误标志,也不会应答信号。在该状态下,错误计数器不再工作。监听模式可用来检测CAN总线上的波特率。要使用此功能,必须至少有另外两个互相通信的节点。波特率可以通过测试一些不同值以实证方式检测。该模式也可用作总线监视器,因为CAN总线不会影响数据通信。

 楼主| 远芳侵古道 发表于 2021-2-24 22:36 | 显示全部楼层
配置代码:
  1. void CAN1Init(void)

  2. {

  3.            CAN_BIT_CONFIGcanBitConfig;

  4.            UINT baudPrescalar;



  5.            CANEnableModule(CAN1,TRUE);



  6.            CANSetOperatingMode(CAN1,CAN_CONFIGURATION);

  7.            while(CANGetOperatingMode(CAN1)!= CAN_CONFIGURATION);



  8.           CANSetTimeStampPrescalar(CAN1, 80 );

  9.           CANSetCap(CAN1, TRUE );



  10.           canBitConfig.phaseSeg2Tq           = CAN_BIT_2TQ;

  11.           canBitConfig.phaseSeg1Tq           = CAN_BIT_3TQ;

  12.           canBitConfig.propagationSegTq      = CAN_BIT_4TQ;

  13.            canBitConfig.phaseSeg2TimeSelect   = TRUE;

  14.            canBitConfig.sample3Time           = TRUE;

  15.           canBitConfig.syncJumpWidth         = CAN_BIT_2TQ;

  16.            CANSetSpeed( CAN1, &canBitConfig,SYSTEM_FREQ, CAN_SPD_1MHZ );

  17.      

  18.            CANAssignMemoryBuffer(CAN1,CAN1MessageFifoArea,(24* 16) );

  19.            CANConfigureChannelForRx(CAN1,CAN_CHANNEL1, 24, CAN_RX_FULL_RECEIVE);

  20.           CANConfigureFilterMask  (CAN1, CAN_FILTER_MASK0, 0, CAN_SID,CAN_FILTER_MASK_IDE_TYPE);

  21.            CANConfigureFilter     (CAN1, CAN_FILTER1, 0x00, CAN_SID);

  22.            CANLinkFilterToChannel (CAN1, CAN_FILTER1, CAN_FILTER_MASK0,CAN_CHANNEL1);

  23.            CANEnableFilter        (CAN1, CAN_FILTER1, TRUE);

  24.    

  25.            CANEnableChannelEvent(CAN1, CAN_CHANNEL1,CAN_RX_CHANNEL_NOT_EMPTY, TRUE);

  26.            CANEnableModuleEvent (CAN1, CAN_RX_EVENT,TRUE);



  27.            /* These functions are from interruptperipheral

  28.           * library. */   



  29.            /*Step 7: Switch the CAN mode

  30.            * to normal mode. */



  31.            CANSetOperatingMode(CAN1,CAN_LISTEN_ONLY);

  32.            while(CANGetOperatingMode(CAN1)!= CAN_LISTEN_ONLY);         

  33. }

评论

代码说明:以上代码为笔者自制CAN监视器正在使用的源代码,使用通道1来监听总线的消息。此代码参考了MPLAB X自带的关于CAN模块的示例代码,如果有相关函数不理解,请自行参考MPLAB X自带的示例代码。  发表于 2021-2-24 22:36
 楼主| 远芳侵古道 发表于 2021-2-24 22:37 | 显示全部楼层
3. 应用层代码的准备
   CAN自定义数据结构

typedef struct _CAN_MSG_TYPE

{

       struct

       {

                unsigned short sid;                                // 标准ID

                unsigned short timer;                          // 接收时间

       } ;

       long size;                                                                               //数据个数

                                  unsigned char data[8];                                      // 数据buffer

} CAN_MSG_TYPE;



        CAN消息检测函数

long can1_rx_chk( long channel )

{

      long ret;

      

      if ( !C1INTbits.RBIF )

      {

                    return 0;

      }

      if((CANGetModuleEvent(CAN1)& CAN_RX_EVENT) == 0)

      {

                    return 0;

      }            

      

                    

      if(CANGetChannelEvent(CAN1, channel) & CAN_RX_CHANNEL_NOT_EMPTY )

      {

                    ret        = 1;

      }                          

      else

      {

                    ret        = 0;

      }

      

      return ret;

}



CAN消息读取函数

void can1_rx_read( long channel, CAN_MSG_TYPE*msg )

{

      CANRxMessageBuffer* message;

      longi;

      

      message        = CANGetRxMessage(CAN1,channel);         

      msg->sid          = message->msgSID.SID;

      msg->size        = message->msgEID.DLC;

       msg->timer     =message->msgSID.CMSGTS;



      

      for( i = 0; i < 8; i++ )

      {

                    msg->data[i]= message->data[i];

      }

      

      CANUpdateChannel(CAN1,channel);

}

USB打印函数

void usb_printf( char*str, long dat );
此函数稍有复杂,并不在这里贴出代码,请读者自行编写或是采用更为简单的方法。

此函数的功能为与标准C语言里的printf函数类似,目的是通过UART模块将字符打印到PC的终端应用程序。

 楼主| 远芳侵古道 发表于 2021-2-24 22:38 | 显示全部楼层
4. 应用层代码
  1. for ( ;; )

  2. {

  3. if ( can1_rx_chk( CAN_CHANNEL1 ) )

  4. {

  5. can1_rx_read( CAN_CHANNEL1, &can_msg );

  6. usb_printf( "\r\nID:%h\r\n", can_msg.sid);

  7. usb_printf( "Timer:%dus\r\n", can_msg.timer);

  8. usb_printf( "Size:%d\r\n", can_msg.size);

  9. usb_printf( "Data:", 0 );

  10. for ( index = 0; index < 8; index++ )

  11. {

  12.                             usb_printf( "%d", can_msg.data[index] );

  13.                    }

  14. }

  15. }

 楼主| 远芳侵古道 发表于 2021-2-24 22:39 | 显示全部楼层
5.敲完代码编译,小伙伴们就可以了在PC的超级终端上看到CAN总线上的数据,当然也可以使用其它能够接收串口数据的其他应用软件。有个地方要请小伙伴们引起注意,就是CAN总线上的数据量与UART的通信速率的问题,请通过计算总线上的数据量来设置合理的UART速率,否则会得不到正确的总线数据。希望能够帮到一些正在为CAN通信纠结的小伙伴们,但也请小伙伴们尊重原创。

原创为CSDN笔者:xfwangqiang
您需要登录后才可以回帖 登录 | 注册

本版积分规则

85

主题

886

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部