CAN的分时复用和发送中断FIFO

**注:**关于CAN的分时复用和发送FIFO,这里受我师父小猫爪教导,得到了一些理解,在这里作为记录,后续有新的理解再进行更新。这里建议有些经验的人观看,不然会比较辛苦!有问题辛苦指出,和大家一起学习!

CAN的分时复用

​ 先谈谈分时复用是什么吧:can的分时复用实际上也就是给我们每一个发送出去的报文,加上一层offset。这层offset实际上也就是dbc文件里面的那个offset,也就是我们的延时。

​ 那么这个延时到底有什么作用呢?这个作用就是在CAN Mailbox邮箱数量不够的情况下,在一定程度上,减少因为邮箱数量不够,而带来的拥堵。而且CAN的发送也是有仲裁机制的,这里仲裁机制还要走个发送优先级,因此难免会导致报文的周期不稳定。

​ 我师傅给我举了个例子,在这里分享给大家:比如说mailbox的数量为1,我CAN报文的数量为8,且都按100ms的报文周期发送。此时,我8个CANID的报文都要进行一个发送,那么我肯定是要在这一个mailbox里面进行发送的,但我又不能一次性给他全部发送出去,CANmailbox还没有那么伟大,雨露均沾。只能让每个报文排队,一个一个来。那么这时候问题来了,我CAN的报文发送周期比如说是5ms一次,那么我肯定是在每5ms发出一帧报文,这时候分时复用offset的作用就体现出来了!A报文的offset设置为5msB报文offset设置为10msC报文offset设置为15ms....... (注意,这里最好按照CANID的优先级高低!设置) 以此类推。这时候CAN报文就会按照A、B、C....一直到最后一个报文的顺序从这一个mailbox邮箱里面发送出去。这样就避免了全部在第一个5ms发生踩踏事故的情况,每一个报文都可以按照自己的周期稳定发出!

注意,这里其实offset不建议设置成0ms开始,因为你0ms开始的话,我邮箱发送报文也是需要时间的,那么之后的每一帧都会出现这个微秒级别的延时,看起来就很难受,因此从5ms开始设置就好了。

只能说,老法师不愧是老法师!!!
在这里插入图片描述

那么到这里你以为就完了吗?当然没有,这时候聪明的我提问了,如果说我的100ms周期CAN报文数量有21个肿么办呢?这时候,发送FIFO就派上用场了!

CAN发送FIFO

​ 这时候有人可能会说,那我可以设置offset105ms啊,挤一挤不就好了!当然不行!如果这样设置的话,当我第一个100ms周期的20个报文发送完以后,第二个100ms的开始5ms的邮箱里面又会同时要发送2个报文,拥挤又出现了!!! 这种方法在这就行不通了(除非这个报文周期是200ms)!

​ 那么这时候就只能用上我们的中断发送FIFO了,大家一定对CanIf_TxConfirmation()这个回调函数不陌生吧!没错,就是他能解决我们的大问题!我们可以在RAM区域设置一个FIFO来存储我们要发送的报文。比如我21个报文全挤在一坨要发送,这时候我就把他们全部存储在FIFO里面,然后我发送完一帧报文之后,就通过CanIf_TxConfirmation()这个函数去确认FIFO这个队列,如果还有报文未发送,那么我就继续发。查到没有要发送的报文了我就停止发送!大家知道中断其实是很快的,相对于我5msTask来说,中断就能在5ms以内一顿往外发不知道多少帧报文了,而且只用一个邮箱!太香了!!

​ 其实在AUTOSAR有类似的流程图的:
在这里插入图片描述
​ 缓冲区的相关篇幅在原文第43页:

在这里插入图片描述

总结

​ 其实到这里大家也都清楚了,分时复用解决的实际上是一个CAN总线拥堵的一个问题,而中断FIFO实际上解决的是一个邮箱(mailbox)数量不够的问题。那么他们两个可以共用吗?答案是当然可以!!!

​ 以上均为师傅教导和个人总结,欢迎大家指正,再次感谢!!!

### STM32F103C8T6 CAN通信中断问题解决方案 在STM32F103C8T6上实现CAN通信时,如果遇到中断问题,通常可能涉及以下几个方面的原因分析解决方法: #### 1. **硬件配置** 确保CAN控制器的引脚配置正确。对于STM32F103C8T6,其CAN功能默认映射到PA11 (CAN_RX) PA12 (CAN_TX)[^1]。需确认这些GPIO被设置为复用推挽模式。 ```c // 配置 GPIO 引脚用于 CAN RX/TX void GPIO_Configuration(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; // CAN TX GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // CAN RX GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStructure); } ``` #### 2. **CAN外设初始化** 检查CAN外设是否已正确定义波特率其他参数。错误的波特率设定可能导致数据传输失败或者无法触发中断事件。 ```c // 初始化 CAN 外设 void CAN_Configuration(void) { CAN_InitTypeDef CAN_InitStruct; RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); CAN_StructInit(&CAN_InitStruct); CAN_InitStruct.CAN_TTCM = DISABLE; CAN_InitStruct.CAN_ABOM = DISABLE; CAN_InitStruct.CAN_AWUM = DISABLE; CAN_InitStruct.CAN_NART = DISABLE; CAN_InitStruct.CAN_RFLM = DISABLE; CAN_InitStruct.CAN_TXFP = DISABLE; CAN_InitStruct.CAN_Mode = CAN_Mode_Normal; CAN_InitStruct.CAN_SJW = CAN_SJW_1tq; CAN_InitStruct.CAN_BS1 = CAN_BS1_3tq; CAN_InitStruct.CAN_BS2 = CAN_BS2_2tq; CAN_InitStruct.CAN_Prescaler = 9; // 假设系统时钟为72 MHz,则此预分频器对应500 kbps CAN_Init(CAN1, &CAN_InitStruct); } ``` #### 3. **中断使能与优先级设置** 验证是否启用了相应的中断源以及设置了合理的中断优先级。未启用特定类型的中断或不当的优先级安排都可能是造成中断丢失的因素之一。 ```c // 启用 CAN 中断并调整优先级 void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } // 开启接收 FIFO 的消息通知中断 void EnableCANInterrupts(void){ CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE); } ``` #### 4. **软件调试技巧** 当怀疑存在异常情况时,可以通过打印日志来追踪状态变化;另外也可以借助逻辑分析仪观察实际信号波形以排除物理层干扰的可能性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值