完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
|
|
相关推荐
1个回答
|
|
第一步:了解Can通信接口协议,这里推荐大家 <
第二步: 特别需要关注点,1、通信速度与传输距离关系,2、通讯接口的硬件连接方式(终端电阻)3、协议帧的种类和格式 4、位时序定义和采样点位置设置 注意:请大家务必了解该知识点,该知识点与支持can协议控制芯片MUC息息相关 第三步:学习如何使用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. 二、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) 列表模式与掩码模式的对比 3)can 工作模式:32位列表模式,32位掩码模式,16位列表模式,16位掩码模式 在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位带宽掩码模式: 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 tmp =StdIdArray1 ^ (~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 tmp =StdIdArray2 ^ (~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位带宽列表模式: 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位带宽掩码模式 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 tmp =ExtIdArray ^ (~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带宽列表模式 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(); } } |
|
|
|
只有小组成员才能发言,加入小组>>
3278 浏览 9 评论
2956 浏览 16 评论
3458 浏览 1 评论
9000 浏览 16 评论
4051 浏览 18 评论
1110浏览 3评论
572浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
568浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2302浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1859浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-24 15:10 , Processed in 0.904331 second(s), Total 78, Slave 58 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号