前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Can通信接口学习笔记[通俗易懂]

Can通信接口学习笔记[通俗易懂]

作者头像
全栈程序员站长
发布2022-08-31 16:25:55
1.5K0
发布2022-08-31 16:25:55
举报
文章被收录于专栏:全栈程序员必看

大家好,又见面了,我是你们的朋友全栈君。

第一步:了解Can通信接口协议,这里推荐大家 <<Can入门教程>>(必读),里面详细说明的can相关知识点;另外推荐大家看有关Can协议标准书籍(选读),相关的pdf书籍下载地址:链接:https://pan.baidu.com/s/1KDtoqkm541xZhoTUpXVJaw 提取码:9dvs

第二步: 特别需要关注点,1、通信速度与传输距离关系,2、通讯接口的硬件连接方式(终端电阻)3、协议帧的种类和格式

4、位时序定义和采样点位置设置 注意:请大家务必了解该知识点,该知识点与支持can协议控制芯片MUC息息相关

Can通信接口学习笔记[通俗易懂]
Can通信接口学习笔记[通俗易懂]
Can通信接口学习笔记[通俗易懂]
Can通信接口学习笔记[通俗易懂]
Can通信接口学习笔记[通俗易懂]
Can通信接口学习笔记[通俗易懂]
Can通信接口学习笔记[通俗易懂]
Can通信接口学习笔记[通俗易懂]

第三步:学习如何使用can控制芯片(STM32系列IC)传输数据

特别说明:stm32芯片的CAN接口是Bxcan接口,芯片仅提供can控制,不支持can传输物理层,所以硬件设计上需要使用CAN收发器连接mcu与CAN总线才可以正常工作,同时需要注意终端电阻。

有关stm32的can知识点,请查看中文数据手册:下载链接如下:链接:https://pan.baidu.com/s/1hlcSPKhZI6FyUinlgQbDnw 提取码:pgo3

stm32的CAN相关知识点:

一、stm32对Can波特率与位时序定义:

● 同步段(SYNC_SEG):通常期望位的变化发生在该时间段内。其值固定为1 个时间单元(1 x tCAN)。 ● 时间段1(BS1):定义采样点的位置。它包含CAN 标准里的 PROP_SEG 和 PHASE_SEG1。其值可以编程为1 到16 个时间单元,但也可以被自动延 长,以补偿因为网络中不同节点的频率差异所造成的相位的正向漂移。 ● 时间段2(BS2) : 定义发送点的位置。它代表CAN 标准里的 PHASE_SEG2。其值可以编程为1 到8 个时间单元,但也可以被自动缩短 以补偿相位的负向漂移

BRP[9:0]: 波特率分频器

PCLK = Can在stm32外设总线上时钟大小(请查看stm23时钟树看can对应的时钟)

bps = PCLK/(BRP[9:0]*(BS1+BS2+SYNC_SEG))

其中SYNC_SEG固定为1个时间单元所以 bps = PCLK/(BRP[9:0]*(BS1+BS2+1)),此时注意跟同步跳转宽度SJW没关系,尽管他也一直设置为1.

Can通信接口学习笔记[通俗易懂]
Can通信接口学习笔记[通俗易懂]

二、stm32的CAN采样点设置

采样点位于时间段1和时间段2之间。根据CIA推荐采样点,最好设置在85%~90%。

计算公式: (BS1+1)/(1+BS1+BS2)

以下是经验值,仅供参考:

75% when 波特率 > 800K

80% when 波特率 > 500K

87.5% when 波特率 <= 500K

75% when 波特率 > 800K

80% when 波特率 > 500K

87.5% when 波特率<= 500K

三:STM32 CAN 过滤器

1)两种过滤模式定义:列表模式 + 掩码模式

列表模式:把我们需要关注的所有CAN报文ID写上去,开始过滤的时候只要对比这张表,如果接收到的报文ID与表上的相符,则通过,如果表上没有,则不通过。但是,这种列表方案有点缺陷,即如果我们只关注一个报文ID,则需要往列表中写入这个ID,如果需要关注两个,则需要写入两个报文ID,如果需要1万个,那么需要写入1万个,可问题是,MCU上的资源是有限的,不可能提供1万个或更多。非常明显,这种列表的方式受到列表容量大小的限制。

掩码模式:包括验证码和掩码,其中验证码即为我们需要关注的报文大致ID,掩码则是过滤验证码,验证码与掩码进行与操作得到结果值就是验证通过的报文ID。比如验证码设置为0x12345678;掩码0xff00ff00;进行与后结果为 0x12xx56xx;也就是说只要收到报文ID[31:24] = 0x12,ID[15:8] = 0x56(其他位不考虑,可为0或1)都是正确的报文ID,也就是可以通过过滤器;假如设置掩码为0x00000000,则表示任意报文ID都可以通过过滤器。

2) 列表模式与掩码模式的对比

Can通信接口学习笔记[通俗易懂]
Can通信接口学习笔记[通俗易懂]

3)can 工作模式:32位列表模式,32位掩码模式,16位列表模式,16位掩码模式

Can通信接口学习笔记[通俗易懂]
Can通信接口学习笔记[通俗易懂]

在bxCAN中,每个过滤器都存在这么两个寄存器CAN_FxR1和CAN_FxR2,这两个寄存器都是32位的,他的定义并不是固定的,针对不同的工作模式组合他的定义是不一样的,如列表模式-32位宽模式下,这两个寄存器的各位定义都是一样的,都用来存储某个具体的期望通过的CAN ID,这样就可以存入2个期望通过的CAN ID(标准CAN ID和扩展CAN ID均可);若在掩码模式-32位宽模式下时,则CAN_FxR1用做32位宽的验证码,而CAN_FxR2则用作32位宽的屏蔽码。在16位宽时,CAN_FxR1和CAN_FxR2都要各自拆分成两个16位宽的寄存器来使用,在列表模式-16位宽模式下,CAN_FxR1和CAN_FxR2定义一样,且各自拆成两个,则总共可以写入4个标准CAN ID,若在16位宽的掩码模式下,则可以当做2对验证码+屏蔽码组合来用,但它只能对标准CAN ID进行过滤。这个就是bxCAN过滤器的解决方案。 4) 运用实例:

注意:stm32官方提供的demo中,官方提供4个int16_t变量数据表示CAN_FxR1和CAN_FxR1寄存器;它们分别为FilterIdHigh,FilterIdLow,FilterMaskIdHigh, FilterMaskIdLow;在不同的位宽工作模式下组合不一样;

16位带宽模式下(寄存器在不同过滤模式下表示值请参考上图):

CAN_FxR1 = (FilterMaskIdLow << 16 | FilterIdLow)

CAN_FxR2 = (FilterMaskIdHigh<< 16 | FilterIdHigh)

可能有人会有这样疑问,为什么Mask在高16位?其实我们看会上图给出的4中带宽工作模式就可以知道,带mask都是占用寄存器高位的

32位带宽模式下(寄存器在不同过滤模式下表示值请参考上图):

CAN_FxR1 = (FilterIdHigh<< 16 | FilterIdLow)

CAN_FxR2 = (FilterMaskIdHigh<< 16 | FilterMaskIdLow )

运用实例1: 16位带宽掩码模式:

代码语言:javascript
复制
static void CANFilterConfig_Scale16_IdMask(void)
{
  CAN_FilterConfTypeDef  sFilterConfig;
  uint16_t StdIdArray1[10] ={0x7D1,0x7D2,0x7D3,0x7D4,0x7D5,    //定义第一组标准CAN ID
                          0x7D6,0x7D7,0x7D8,0x7D9,0x7DA};
  uint16_t StdIdArray2[10] ={0x751,0x752,0x753,0x754,0x755,    //定义第二组标准CAN ID
                          0x756,0x757,0x758,0x759,0x75A};
  uint16_t      mask,tmp,i,num;
  
  sFilterConfig.FilterNumber = 5;                    //使用过滤器5
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;            //配置为掩码模式
  sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;        //设为16位宽
  
  //配置第一个过滤对
  sFilterConfig.FilterIdLow =StdIdArray1[0]<<5;            //设置第一个验证码
  mask =0x7ff;
  num =sizeof(StdIdArray1)/sizeof(StdIdArray1[0]);
  for(i =0; i<num; i++)                            //计算第一个屏蔽码
  {
    tmp =StdIdArray1[i] ^ (~StdIdArray1[0]);
    mask &=tmp;
  }
  sFilterConfig.FilterMaskIdLow =(mask<<5)|0x10;    //只接收数据帧
  
  //配置第二个过滤对
  sFilterConfig.FilterIdHigh = StdIdArray2[0]<<5;    //设置第二个验证码
  mask =0x7ff;
  num =sizeof(StdIdArray2)/sizeof(StdIdArray2[0]);
  for(i =0; i<num; i++)                    //计算第二个屏蔽码
  {
    tmp =StdIdArray2[i] ^ (~StdIdArray2[0]);
    mask &=tmp;
  }
  sFilterConfig.FilterMaskIdHigh = (mask<<5)|0x10;  //只接收数据帧
  
 
  sFilterConfig.FilterFIFOAssignment = 0;        //通过的CAN 消息放入到FIFO0中
  sFilterConfig.FilterActivation = ENABLE;
  sFilterConfig.BankNumber = 14;
  
if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

运用实例2:16位带宽列表模式:

代码语言:javascript
复制
static void CANFilterConfig_Scale16_IdList(void)
{
  CAN_FilterConfTypeDef  sFilterConfig;
  uint32_t StdId1 =0x123;                        //这里采用4个标准CAN ID作为例子
  uint32_t StdId2 =0x124;
  uint32_t StdId3 =0x125;
  uint32_t StdId4 =0x126;
  
  sFilterConfig.FilterNumber = 1;                //使用过滤器1
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;        //设为列表模式
  sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;    //位宽设置为16位
  sFilterConfig.FilterIdHigh = StdId1<<5;     //4个标准CAN ID分别放入到4个存储中
  sFilterConfig.FilterIdLow = StdId2<<5;
  sFilterConfig.FilterMaskIdHigh = StdId3<<5;
  sFilterConfig.FilterMaskIdLow = StdId4<<5;
  sFilterConfig.FilterFIFOAssignment = 0;            //接收到的报文放入到FIFO0中
  sFilterConfig.FilterActivation = ENABLE;
  sFilterConfig.BankNumber = 14;
  
  if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

运用实例3: 32位带宽掩码模式

代码语言:javascript
复制
static void CANFilterConfig_Scale32_IdMask_ExtendIdOnly(void)
{
  CAN_FilterConfTypeDef  sFilterConfig;
  //定义一组扩展CAN ID用来测试
uint32_t ExtIdArray[10] ={0x1839f101,0x1835f102,0x1835f113,0x1835f124,0x1835f105,
                            0x1835f106,0x1835f107,0x1835f108,0x1835f109,0x1835f10A};
  uint32_t      mask,num,tmp,i;
  
  sFilterConfig.FilterNumber = 3;                    //使用过滤器3
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;            //配置为掩码模式
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;        //设为32位宽
  sFilterConfig.FilterIdHigh =((ExtIdArray[0]<<3) >>16) &0xffff;//数组任意一个成员都可以作为验证码
  sFilterConfig.FilterIdLow =((ExtIdArray[0]<<3)&0xffff) | CAN_ID_EXT;
  
  mask =0x1fffffff;
  num =sizeof(ExtIdArray)/sizeof(ExtIdArray[0]);
  for(i =0; i<num; i++)                //屏蔽码位数组各成员相互同或的结果
  {
    tmp =ExtIdArray[i] ^ (~ExtIdArray[0]);    //都与第一个数据成员进行同或操作
    mask &=tmp;
  }
  mask <<=3;                                    //对齐寄存器
  sFilterConfig.FilterMaskIdHigh = (mask>>16)&0xffff;
  sFilterConfig.FilterMaskIdLow = (mask&0xffff)|0x02;         //只接收数据帧
  sFilterConfig.FilterFIFOAssignment = 0;
  sFilterConfig.FilterActivation = ENABLE;
  sFilterConfig.BankNumber = 14;
  
  if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

运用实例4: 32带宽列表模式

代码语言:javascript
复制
static void CANFilterConfig_Scale32_IdList(void)
{
  CAN_FilterConfTypeDef  sFilterConfig;
  uint32_t StdId =0x321;                //这里写入两个CAN ID,一个位标准CAN ID
  uint32_t ExtId =0x1800f001;            //一个位扩展CAN ID
  
  sFilterConfig.FilterNumber = 0;                //使用过滤器0
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;        //设为列表模式
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;    //配置为32位宽
  sFilterConfig.FilterIdHigh = StdId<<5;            //基本ID放入到STID中
  sFilterConfig.FilterIdLow = 0|CAN_ID_STD;            //设置IDE位为0
  sFilterConfig.FilterMaskIdHigh = ((ExtId<<3)>>16)&0xffff;
  sFilterConfig.FilterMaskIdLow = (ExtId<<3)&0xffff|CAN_ID_EXT;    //设置IDE位为1
  sFilterConfig.FilterFIFOAssignment = 0;            //接收到的报文放入到FIFO0中
  sFilterConfig.FilterActivation = ENABLE;
  sFilterConfig.BankNumber = 14;
  
  if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/151739.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
验证码
腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档