打印
[其他产品]

基于PIC32开发CAN监视器

[复制链接]
3429|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
远芳侵古道|  楼主 | 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 | 只看该作者
配置代码:
void CAN1Init(void)

{

           CAN_BIT_CONFIGcanBitConfig;

           UINT baudPrescalar;



           CANEnableModule(CAN1,TRUE);



           CANSetOperatingMode(CAN1,CAN_CONFIGURATION);

           while(CANGetOperatingMode(CAN1)!= CAN_CONFIGURATION);



          CANSetTimeStampPrescalar(CAN1, 80 );

          CANSetCap(CAN1, TRUE );



          canBitConfig.phaseSeg2Tq           = CAN_BIT_2TQ;

          canBitConfig.phaseSeg1Tq           = CAN_BIT_3TQ;

          canBitConfig.propagationSegTq      = CAN_BIT_4TQ;

           canBitConfig.phaseSeg2TimeSelect   = TRUE;

           canBitConfig.sample3Time           = TRUE;

          canBitConfig.syncJumpWidth         = CAN_BIT_2TQ;

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

     

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

           CANConfigureChannelForRx(CAN1,CAN_CHANNEL1, 24, CAN_RX_FULL_RECEIVE);

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

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

           CANLinkFilterToChannel (CAN1, CAN_FILTER1, CAN_FILTER_MASK0,CAN_CHANNEL1);

           CANEnableFilter        (CAN1, CAN_FILTER1, TRUE);

   

           CANEnableChannelEvent(CAN1, CAN_CHANNEL1,CAN_RX_CHANNEL_NOT_EMPTY, TRUE);

           CANEnableModuleEvent (CAN1, CAN_RX_EVENT,TRUE);



           /* These functions are from interruptperipheral

          * library. */   



           /*Step 7: Switch the CAN mode

           * to normal mode. */



           CANSetOperatingMode(CAN1,CAN_LISTEN_ONLY);

           while(CANGetOperatingMode(CAN1)!= CAN_LISTEN_ONLY);         

}

使用特权

评论回复
评论
远芳侵古道 2021-2-24 22:36 回复TA
代码说明:以上代码为笔者自制CAN监视器正在使用的源代码,使用通道1来监听总线的消息。此代码参考了MPLAB X自带的关于CAN模块的示例代码,如果有相关函数不理解,请自行参考MPLAB X自带的示例代码。 
5
远芳侵古道|  楼主 | 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的终端应用程序。

使用特权

评论回复
6
远芳侵古道|  楼主 | 2021-2-24 22:38 | 只看该作者
4. 应用层代码
for ( ;; )

{

if ( can1_rx_chk( CAN_CHANNEL1 ) )

{

can1_rx_read( CAN_CHANNEL1, &can_msg );

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

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

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

usb_printf( "Data:", 0 );

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

{

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

                   }

}

}

使用特权

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

原创为CSDN笔者:xfwangqiang

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

78

主题

816

帖子

0

粉丝