打印
[单片机芯片]

【沁恒CH32V307开发板测评】CAN测试

[复制链接]
240|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
上一篇测评文章玩了一下SPI接口,还是很顺利的
一、CAN介绍
1、CAN是什么
CAN(Controller Area Network)是一种​​基于差分信号的异步串行通信协议​​,由博世公司于1983年开发,专为解决复杂系统中电子设备的实时数据交换问题。
其核心设计思想为:
​​        1)多主竞争,智能仲裁​​:任何节点均可主动发送数据,通过ID优先级(数值越小优先级越高)实现非破坏性仲裁,高优先级数据自动抢占总线
​        2)​差分抗扰,高可靠传输​​:通过CAN_H/CAN_L双绞线传输差分信号,电压差>0.9V为显性(逻辑0),<0.5V为隐性(逻辑1)。此设计天然抑制共模干扰,适合强电磁环境(如汽车引擎舱)
​​        3)极简布线,高扩展性​​:双线总线可连接多达110个节点,新增设备无需修改网络地址
通俗一点的理解,可以把CAN总线想象成个​​高效的会议讨论组​​:
​​        发言规则​​:谁有紧急消息(ID优先级高)谁先说,其他人自动静音等待(非破坏性仲裁)。
​​        抗干扰能力​​:成员戴降噪耳机(差分信号)确保在嘈杂环境中听清指令。
​​        容错机制​​:有人报错数据时,系统自动要求重说(错误重传)
2、CAN的应用场景
主要有三大应用场景
1)汽车电子​​(最核心场景)
连接发动机控制、ABS刹车、仪表盘等模块。例如:踩刹车时,刹车传感器通过CAN通知发动机降速
​​        2)工业自动化​​
工厂机器人、传感器群通过CAN协同工作,如机械臂收到指令后同步动作
​​        3)智能设备​​
医疗监护仪、电梯控制系统、智能家居设备(如安防传感器)的内部通信
3、优势和劣势
1)优势
高可靠性、实时性强、扩展灵活、成本低​​
2)劣势
数据量小、速率与距离矛盾、偶发冲突问题
二、CAN代码编程
查看哪些引脚支持CAN,如图,PB8;PB9;

开发板上没有CAN收发器,因此使用的CAN收发器型号是TCAN1044;绘制的CAN收发器原理图如下:

硬件准备好了,就需要进行代码编程了
1、初始化CAN GPIO和CAN接口
void CAN_Mode_Init( u8 tsjw, u8 tbs2, u8 tbs1, u16 brp, u8 mode )
{
         GPIO_InitTypeDef GPIO_InitSturcture={0};
         CAN_InitTypeDef CAN_InitSturcture={0};
         CAN_FilterInitTypeDef CAN_FilterInitSturcture={0};
         
         RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE );
         RCC_APB1PeriphClockCmd( RCC_APB1Periph_CAN1, ENABLE );       
         
         GPIO_PinRemapConfig( GPIO_Remap1_CAN1, ENABLE);       
         
         GPIO_InitSturcture.GPIO_Pin = GPIO_Pin_9;
         GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_AF_PP;               
         GPIO_InitSturcture.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init( GPIOB, &GPIO_InitSturcture);
         
         GPIO_InitSturcture.GPIO_Pin = GPIO_Pin_8;
         GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_IPU;       
         GPIO_Init( GPIOB, &GPIO_InitSturcture);
         
         CAN_InitSturcture.CAN_TTCM = DISABLE;               
         CAN_InitSturcture.CAN_ABOM = DISABLE;               
         CAN_InitSturcture.CAN_AWUM = DISABLE;               
         CAN_InitSturcture.CAN_NART = ENABLE;               
         CAN_InitSturcture.CAN_RFLM = DISABLE;               
         CAN_InitSturcture.CAN_TXFP = DISABLE;
         CAN_InitSturcture.CAN_Mode = mode;
         CAN_InitSturcture.CAN_SJW = tsjw;               
         CAN_InitSturcture.CAN_BS1 = tbs1;               
         CAN_InitSturcture.CAN_BS2 = tbs2;               
         CAN_InitSturcture.CAN_Prescaler = brp;               
         CAN_Init( CAN1, &CAN_InitSturcture );
         
         CAN_FilterInitSturcture.CAN_FilterNumber = 0;               

#if (Frame_Format == Standard_Frame)
/* identifier/mask mode, One 32-bit filter, StdId: 0x317 */
         CAN_FilterInitSturcture.CAN_FilterMode = CAN_FilterMode_IdMask;         
         CAN_FilterInitSturcture.CAN_FilterScale = CAN_FilterScale_32bit;
         CAN_FilterInitSturcture.CAN_FilterIdHigh = 0x62E0;         
         CAN_FilterInitSturcture.CAN_FilterIdLow = 0;
         CAN_FilterInitSturcture.CAN_FilterMaskIdHigh = 0xFFE0;         
         CAN_FilterInitSturcture.CAN_FilterMaskIdLow = 0x0006;         



2、配置过滤
/*********************************************************************
  * @fn      CAN_SoftFilterInit
  *
  * [url=home.php?mod=space&uid=247401]@brief[/url]   Initializes the CAN peripheral according to the specified
  *        parameters in the CAN_FilterInitStruct.
  *
  * @param   CAN_FilterInitStruct - pointer to a CAN_FilterInitTypeDef
  *        structure that contains the configuration information.
  *
  * [url=home.php?mod=space&uid=266161]@return[/url]  none
  */
void CAN_SoftFilterInit(CAN_FilterInitTypeDef* CAN_FilterInitStruct)
{
        if(CAN_FilterInitStruct->CAN_FilterNumber > CANSOFTFILTER_MAX_GROUP_NUM){
                return;
        }
        if(CAN_FilterInitStruct->CAN_FilterActivation)
        {
                CANFilterStruct[CAN_FilterInitStruct->CAN_FilterNumber].en = 1;
        }else
        {
                CANFilterStruct[CAN_FilterInitStruct->CAN_FilterNumber].en = 0;
        }
        CANFilterStruct[CAN_FilterInitStruct->CAN_FilterNumber].FR[0].FR_16_H = CAN_FilterInitStruct->CAN_FilterIdHigh;
        CANFilterStruct[CAN_FilterInitStruct->CAN_FilterNumber].FR[0].FR_16_L = CAN_FilterInitStruct->CAN_FilterIdLow;
        CANFilterStruct[CAN_FilterInitStruct->CAN_FilterNumber].FR[1].FR_16_H = CAN_FilterInitStruct->CAN_FilterMaskIdHigh;
        CANFilterStruct[CAN_FilterInitStruct->CAN_FilterNumber].FR[1].FR_16_L = CAN_FilterInitStruct->CAN_FilterMaskIdLow;
        CANFilterStruct[CAN_FilterInitStruct->CAN_FilterNumber].mode = CAN_FilterInitStruct->CAN_FilterMode;
        CANFilterStruct[CAN_FilterInitStruct->CAN_FilterNumber].scale = CAN_FilterInitStruct->CAN_FilterScale;
}



3、配置接收中断
void USB_LP_CAN1_RX0_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void USB_LP_CAN1_RX0_IRQHandler()
{
         int i;
         uint8_t px,pbuf[8];
         if (CAN_GetITStatus(CAN1,CAN_IT_FMP0))
         {
                 px = CAN_Receive_Msg(pbuf);
                 for ( i = 0; i < px; i++)
                 {
                         canexbuf_interrupt[i] = pbuf[i];
                 }
                 if(px)
                 {
                         interrupt_rx_flag = 1;
                 }
                 CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0);
         }
}


4、配置发送和接收函数
/*********************************************************************
  * @fn      CAN_Send_Msg
  *
  * @brief   CAN Transmit function.
  *
  * @param   msg - Transmit data buffer.
  *          len - Data length.
  *
  * @return  0 - Send successful.
  *          1 - Send failed.
  */
u8 CAN_Send_Msg( u8 *msg, u8 len )
{
         u8 mbox;
         u16 i = 0;
         
         CanTxMsg CanTxStructure;

#if (Frame_Format == Standard_Frame)
         CanTxStructure.StdId = 0x317;               
         CanTxStructure.IDE = CAN_Id_Standard;       
   
#elif (Frame_Format == Extended_Frame)
         CanTxStructure.ExtId = 0x12124567;               
         CanTxStructure.IDE = CAN_Id_Extended;       
         
#endif       
         
         CanTxStructure.RTR = CAN_RTR_Data;               
         CanTxStructure.DLC = len;
         
         for( i=0; i<len; i++ )
         {
                 CanTxStructure.Data[i] = msg[i];       
         }
         
         mbox = CAN_Transmit( CAN1, &CanTxStructure);
         i = 0;
         
         while( ( CAN_TransmitStatus( CAN1, mbox ) != CAN_TxStatus_Ok ) && (i < 0xFFF) )
         {
                 i++;
         }
         
         if( i == 0xFFF )
         {
                 return 1;
         }
         else
         {
                 return 0;
         }       
}

/*********************************************************************
  * @fn      CAN_Receive_Msg
  *
  * @brief   CAN Receive function.
  *
  * @param   buf - Receive data buffer.
  *          len - Data length.
  *
  * @return  CanRxStructure.DLC - Receive data length.
  */
u8 CAN_Receive_Msg( u8 *buf )
{
         u8 i;
         
         CanRxMsg CanRxStructure;
         
         if( CAN_MessagePending( CAN1, CAN_FIFO0 ) == 0)         
         {
                 return 0;
         }

#ifdef USE_SOFT_FILTER
         CAN_ReceiveViaSoftFilter( CAN1, CAN_FIFO0, &CanRxStructure );
#else
         CAN_Receive( CAN1, CAN_FIFO0, &CanRxStructure );       
#endif // USE_SOFT_FILTER
         
         for( i=0; i<8; i++ )
         {
                 buf[i] = CanRxStructure.Data[i];
         }
         
         return CanRxStructure.DLC;       
}



5、下载验证
1)发送数据
250K波特率

1M波特率接收

统计发送成功的次数,按1M的波特率去发送,没有出错;发送58055次数据。


2)接收数据
使用USB-CAN软件向开发板发送数据,如图,设备成功接收到

总结:根据测试和数据手册说明,CH32V307VCY6的can最大速率为1M,且稳定性是很不错的,具体还需要根据现场实际情况进行测试。


使用特权

评论回复
沙发
寂静之回响| | 2025-8-4 12:49 | 只看该作者
楼主用的哪家的CAN收发器??

使用特权

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

本版积分规则

6

主题

19

帖子

0

粉丝