通信接口CAN

CAN通信

目前(2021年6月)我用到的CAN电路原理图:
can电路原理图

  • 判断电路有没有接好,其中一个标准就是,测量接入的电阻阻值是不是60Ω。
  • 上图两个60.4Ω之间,可以接一个电容到GND。

1. Bit Timing(位时序)

参考连接

  • 用于确定波特率。
    CAN 具有 处理长总线长度(与比特率相比)中发现的时间延迟 和 处理总线上节点的时钟晶体频率差异的高级功能。
    位时序的选择非常重要,因为它决定了位速率、采样点和重新同步的能力。
  • 位段(博世标准)
    每个比特分为四段——同步段(synchronisation)、传播段(propagation)和相位段一和二(phase1,2)。
    在这里插入图片描述
    每一段由一个或多个时间量组成。时间量是从 CAN 控制器时钟导出的固定时间量,具有预定标因子。
  • 同步段(Synch_Seg)
    同步段用于同步总线上的各个节点。当在总线上发送一个比特时,预计前沿在该段内。 该段固定为 一个时间量程长。
  • 传播段(Prop_Seg)
    需要传播段来补偿总线中的延迟。段大小在 1 到 8 个时间量程之间可编程。
  • 相位段1(Phase_Seg1),相位段2(Phase_Seg2)
    可以通过重新同步来延长或缩短这些段。
  • 采样点
    通常每一位只有一个采样点,在这种情况下,采样点在TSEG1和TSEG2之间的边缘。
    (但是,有些CAN控制器也可以对每一位采样3次。这种情况下,该位将被采样3次 在一行中,最后一个样本取自 TSEG1 和 TSEG2 之间的边缘。三个样本应该只用于相对较慢的波特率。)

1.1 波特率和采样点的计算

  • 波特率
    总线的波特率可以通过下式计算:
    在这里插入图片描述

  • 采样点
    样品前量子=TSEG1+1
    样品后量子=TSEG2
    采样点通常以位时间的百分比给出。是:(TSEG1+1)/(TSEG1+1+TSEG2)

2. CAN波特率配置

20220727新增补充。

2.1 stm32f107vc

  • 配置为 1000K波特率。
    在这里插入图片描述
  • 配置为 500K波特率。
    在这里插入图片描述
CAN_HandleTypeDef hcan1;
CAN_HandleTypeDef hcan2;
void CAN1_Init(void)
{
  hcan1.Instance = CAN1;
  hcan1.Init.Prescaler = 6;//6--1000K   12--500K 
  hcan1.Init.Mode = CAN_MODE_NORMAL;
  hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan1.Init.TimeSeg1 = CAN_BS1_3TQ;
  hcan1.Init.TimeSeg2 = CAN_BS2_2TQ;
  hcan1.Init.TimeTriggeredMode = DISABLE;
  hcan1.Init.AutoBusOff = DISABLE;
  hcan1.Init.AutoWakeUp = DISABLE;
  hcan1.Init.AutoRetransmission = DISABLE;
  hcan1.Init.ReceiveFifoLocked = DISABLE;
  hcan1.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan1) != HAL_OK)
  {
    Error_Handler();
  }
}
void CAN2_Init(void)
{
  hcan2.Instance = CAN2;
  hcan2.Init.Prescaler = 6;//6--1000K   12--500K 
  hcan2.Init.Mode = CAN_MODE_NORMAL;
  hcan2.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan2.Init.TimeSeg1 = CAN_BS1_3TQ;
  hcan2.Init.TimeSeg2 = CAN_BS2_2TQ;
  hcan2.Init.TimeTriggeredMode = DISABLE;
  hcan2.Init.AutoBusOff = DISABLE;
  hcan2.Init.AutoWakeUp = DISABLE;
  hcan2.Init.AutoRetransmission = DISABLE;
  hcan2.Init.ReceiveFifoLocked = DISABLE;
  hcan2.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan2) != HAL_OK)
  {
    Error_Handler();
  }
}

2.2 HHD32f107

//CAN_BAUD_1M CAN_BAUD_500K CAN_BAUD_250K
#define PROJ_CAN_SRC_NODE		(0x01)
can_init(CAN1, CAN_BAUD_1M, PROJ_CAN_SRC_NODE, 0x0000000);//	can_init(CAN1, CAN_BAUD_1M, 0x7ff, 0x00);
can_init(CAN2, CAN_BAUD_1M, PROJ_CAN_SRC_NODE, 0x0000000);

3. CAN数据接收设置

针对两种MCU的过滤器设置。

stm32f105

网上全是参考代码,这里直接贴上我的过滤器代码

  • 列表模式,CAN1 32位ID过滤,CAN2 16位ID过滤
    CAN_FilterTypeDef  sFilterConfig;
	sFilterConfig.FilterMode =  CAN_FILTERMODE_IDLIST;  //设为列表模式 
	//CAN1----------------------------------------------   
    sFilterConfig.FilterFIFOAssignment = CAN1FIFO;      //接收到的报文放入到FIFO0中 
    sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
    sFilterConfig.FilterActivation = ENABLE;  
    sFilterConfig.SlaveStartFilterBank  = 14; 
	//过滤器0
    sFilterConfig.FilterBank = 0;                       
    sFilterConfig.FilterIdHigh = ((ID1<<3)>>16)&0xffff;
    sFilterConfig.FilterIdLow  = ((ID1<<3)&0xffff)|CAN_ID_EXT; 
    sFilterConfig.FilterMaskIdHigh =((ID2<<3)>>16)&0xffff;
    sFilterConfig.FilterMaskIdLow  =((ID2<<3)&0xffff)|CAN_ID_EXT; 
    HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig);
  
    //过滤器1
    sFilterConfig.FilterBank = 1;
    sFilterConfig.FilterIdHigh     	= ((ID3<<3)>>16)&0xffff;
    sFilterConfig.FilterIdLow     	= ((ID3<<3)&0xffff)|CAN_ID_EXT; 
//    sFilterConfig.FilterMaskIdHigh 	= ((ID4<<3)>>16)&0xffff;
//    sFilterConfig.FilterMaskIdLow  	= ((ID4<<3)&0xffff)|CAN_ID_EXT; 
//    HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig);
    
    //CAN2----------------------------------------
    sFilterConfig.FilterFIFOAssignment = CAN2FIFO;
    sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;
    sFilterConfig.FilterBank = 14;
    sFilterConfig.FilterIdHigh 		= 0x020 <<5;
    sFilterConfig.FilterIdLow  		= 0x021 <<5; 
    sFilterConfig.FilterMaskIdHigh 	= 0x022<<5;
    sFilterConfig.FilterMaskIdLow  	= 0x023 <<5; 
    HAL_CAN_ConfigFilter(&hcan2, &sFilterConfig);
  
    //过滤器15
    sFilterConfig.FilterBank = 15;
    sFilterConfig.FilterIdHigh     	= 0x030 <<5;
    sFilterConfig.FilterIdLow      	= 0x031 <<5; 
    sFilterConfig.FilterMaskIdHigh 	= 0x032<<5;
    sFilterConfig.FilterMaskIdLow  	= 0x033 <<5; 
    HAL_CAN_ConfigFilter(&hcan2, &sFilterConfig);
  
    HAL_CAN_Start(&hcan1);  
    HAL_CAN_ActivateNotification(&hcan1,   CAN_IT_RX_FIFO0_MSG_PENDING);
    HAL_CAN_Start(&hcan2);  
    HAL_CAN_ActivateNotification(&hcan2,   CAN_IT_RX_FIFO1_MSG_PENDING);
  • 如果需要接受全部帧,不进行硬件过滤。如下 所示:
void CAN1_recvALL(void)
{
  CAN_FilterTypeDef  sFilterConfig;
  TxMeg.IDE=CAN_ID_EXT; //扩展帧
  TxMeg.RTR=CAN_RTR_DATA;//数据帧
  sFilterConfig.FilterMode =  CAN_FILTERMODE_IDMASK;  //设为mask模式    
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
  //sFilterConfig.FilterFIFOAssignment = CAN1FIFO;      //接收到的报文放入到FIFO0中 
  sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; //接收到的报文放入到FIFO0中 
  sFilterConfig.FilterActivation = ENABLE;  

  sFilterConfig.FilterBank = 0; //过滤器0
  sFilterConfig.FilterIdHigh = 0x0000;   //基本ID放入到STID中  
  sFilterConfig.FilterIdLow  = 0x0000;    		
  sFilterConfig.FilterMaskIdHigh = 0;//这里设置接收任意ID的CAN数据
  sFilterConfig.FilterMaskIdLow  = 0;//0表示接收来自发送端任意ID的数据 
  sFilterConfig.SlaveStartFilterBank  = 14; 
  HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig);
}
void CAN2_recvALL(void)
{
  CAN_FilterTypeDef  sFilterConfig;
  sFilterConfig.FilterMode =  CAN_FILTERMODE_IDMASK;  //设为mask模式    
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
  sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO1; 
  sFilterConfig.FilterActivation = ENABLE;  
  sFilterConfig.FilterBank = 14;
  sFilterConfig.FilterIdHigh = 0x0000;   //基本ID放入到STID中  
  sFilterConfig.FilterIdLow  = 0x0000;    		
  sFilterConfig.FilterMaskIdHigh = 0;//这里设置接收任意ID的CAN数据
  sFilterConfig.FilterMaskIdLow  = 0;//0表示接收来自发送端任意ID的数据 

  //CAN2 过滤器设置
  HAL_CAN_ConfigFilter(&hcan2, &sFilterConfig);
}

国产芯片HHD32107

  • 国产芯片文件资料给的不全,且有一些不严谨的地方。只能够按照对stm32 can的理解,来理解国产芯片。
  • 资料中显示,该国产芯片,具有双CAN。但是未具体介绍过滤器是如何使用的。实际使用中发现,can2不能正常的接收数据和发送数据,因而只能对can1进行调试。
  • can1 看起来仅有一个过滤器,实验发现,过滤器实际处于mask模式下,因为项目需要用到的ID比较简单,没有统一的ID特征位,不需要再用mask过滤一遍,索性mask寄存器AMR全部设置为无效位,硬件不过滤。全部接收。最终实行软件代码过滤
  • 能正常工作,就不要去动他了。
// 设置滤波器
	can->MOD.bit.AFM 	= 0x01;  //1 数据接受采用 4-byte 过滤器(32位过滤器)
								 //0 数据接受采用 2 个 shoter 过滤器(2个16位过滤器)
// 设置接收帧过滤,可以接收任何标识符
		/*
		ACR/AMR屏蔽字属性:
		ACR用于指定CAN ID二进制中关注位和忽略位;
		AMR用于规定ACR中那些二进制位生效,哪些无效.AMR中0代表有效位,1代表无效位;
		*/
		// Acceptance Code Register (注册两个ID,实际不需要)
		can->DATAINFO.FILTER.ACR[0].all  = ((filterID << 5) >> 8 ) & 0xFF;   //Identifier
		can->DATAINFO.FILTER.ACR[1].all  = (filterID << 5) &0xE0 ;  		 //Identifier
		can->DATAINFO.FILTER.ACR[2].all  = 0xFF;
		can->DATAINFO.FILTER.ACR[3].all  = 0xFF;

		//Acceptance Mask Register (mask设置,不对任何位进行判定)
		can->DATAINFO.FILTER.AMR[0].all = 0xFF;//((mask << 5) >> 8 ) & 0xFF;
		can->DATAINFO.FILTER.AMR[1].all = 0xFF;//(mask << 5) &0xE0 ;
		can->DATAINFO.FILTER.AMR[2].all = 0xff;
		can->DATAINFO.FILTER.AMR[3].all = 0xff; 

CAN的两种标准

CAN官网入口
我的阿里云参考资料(文件已上传,当前阿里云盘没有分享功能)

  • 2.0A 标准。标识符ID 长度为11bit 。
  • 2.0B 标准。标识符ID 长度支持11位和29bit。
    2.0B标准帧
    2.0B扩展帧

注意:在编写MCU程序时会发现,如果CAN收发芯片,没有接在一个总线中,can驱动代码会卡在等待的死循环中。关于这一点,我们在添加了实时系统之后,在can等待循环中,需要添加系统的delay函数,用以自动切换线程任务。

实际数据帧波形图解析

  • 以2.0A标准帧为例,发送数据,11bit的ID数值为1,发送8个字节的数据(0x12,0x23,0x34,0x45,0x56,0x67,0x78,0x89)。
  • 电表笔 高接CANH,低接CANL,得到的高电平表示0,低电平表示1。
  • 关于速率,当前采用的是500Kbit的速率,在示波器上看,也就是2us一个bit。下图中记录了原始的高低电平。
  • 通过示波器观察每次can总线上的数据,会发现“**位填充”**现象,即总线上,5bit持续同样的电平,发送方会在后面补充1bit的反向电平。

can实际数据波形图解析

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值