CAN波特率/CAN总线采样点/CAN位时间(Bit Time)
采样点(Sample Point)是指在一个CAN位时间内,控制器实际读取总线电平状态的时间点。正确的采样点设置对可靠通信至关重要。
CAN总线波特率计算方法
CAN总线波特率的计算基于以下几个关键参数:
1. 波特率计算公式
波特率 = CAN时钟频率 / (Prescaler × (1 + BS1 + BS2))
其中:
-
CAN时钟频率:代码中为54MHz
-
Prescaler:预分频值(代码中的PreScale)
-
BS1:时间段1的时间量子数
-
BS2:时间段2的时间量子数
2. 代码中的波特率配置示例
以代码中的1Mbps配置为例:
{CAN_BT_SJW_1TQ, CAN_BT_BS1_6TQ, CAN_BT_BS2_2TQ, 6}, // 1M
计算过程:
-
预分频值(Prescaler) = 6
-
BS1 = 6TQ (时间量子)
-
BS2 = 2TQ (时间量子)
-
总时间量子数 = 1(Sync_Seg) + BS1 + BS2 = 1 + 6 + 2 = 9TQ
波特率 = 54MHz / (6 × 9) = 54,000,000 / 54 = 1,000,000 bps (1Mbps)
3. 各波特率配置验证
|
波特率 |
Prescaler |
BS1 |
BS2 |
计算式 |
结果 |
|---|---|---|---|---|---|
|
1M |
6 |
6 |
2 |
54MHz/(6×9)=1M |
正确 |
|
500K |
12 |
7 |
1 |
54MHz/(12×9)=500K |
正确 |
|
250K |
27 |
6 |
1 |
54MHz/(27×8)=250K |
正确 |
|
200K |
15 |
15 |
2 |
54MHz/(15×18)=200K |
正确 |
|
125K |
54 |
6 |
1 |
54MHz/(54×8)=125K |
正确 |
|
100K |
60 |
7 |
1 |
54MHz/(60×9)=100K |
正确 |
代码
/**
CAN初始化
CAN0->与电池模组BMS通信
CAN1->与UPS或其他外部设备通信
CAN使用APB1时钟=54MHz
尽可能地把采样点设置为CiA推荐的值
CiA 波特率
75% >800K
80% >500K
87.5% <=500K
CiA计算方式:(1+CAN_BS1)/(1+CAN_BS1+CAN_BS2)
使用CAN波特率计算工具得来
*/
#include "can.h"
#include "main.h"
CAN0_QUEUE Can0_Rcv_Msg; //接收BUF
CAN0_QUEUE Can0_Snd_Msg; //发送BUF
CAN1_QUEUE Can1_Rcv_Msg; //接收BUF
CAN1_QUEUE Can1_Snd_Msg; //发送BUF
//波特率函数列表
typedef struct{
uint8_t SJW;
uint8_t BS1;
uint8_t BS2;
uint16_t PreScale;
}TCAN_BaudRate;
TCAN_BaudRate CAN_BaudRateInitTab[]= { // CLK=54MHz
{CAN_BT_SJW_1TQ, CAN_BT_BS1_6TQ, CAN_BT_BS2_2TQ, 6}, // 1M
{CAN_BT_SJW_1TQ, CAN_BT_BS1_7TQ, CAN_BT_BS2_1TQ, 12}, // 500K
{CAN_BT_SJW_1TQ, CAN_BT_BS1_6TQ, CAN_BT_BS2_1TQ, 27}, // 250K
{CAN_BT_SJW_1TQ, CAN_BT_BS1_15TQ, CAN_BT_BS2_2TQ, 15}, // 200K
{CAN_BT_SJW_1TQ, CAN_BT_BS1_6TQ, CAN_BT_BS2_1TQ, 54}, // 125K
{CAN_BT_SJW_1TQ, CAN_BT_BS1_7TQ, CAN_BT_BS2_1TQ, 60}, // 100K
};
//单位K
uint32_t CAN_GetBaudRateNum(uint32_t BaudRate)
{
switch(BaudRate){
case 1000:return 0;
case 500 :return 1;
case 250 :return 2;
case 200 :return 3;
case 125 :return 4;
case 100 :return 5;
default :return 0;
}
}
void CAN0_Init(uint16_t Baud)
{
can_parameter_struct can_parameter;
can_filter_parameter_struct can_filter;
//端口设置
/* enable can clock */
rcu_periph_clock_enable(RCU_CAN0);
rcu_periph_clock_enable(RCU_GPIOD);
rcu_periph_clock_enable(RCU_AF);
gpio_pin_remap_config(GPIO_CAN0_FULL_REMAP, ENABLE);
/* configure CAN0 GPIO, CAN0_TX(PD1) and CAN0_RX(PD0) */
gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
gpio_init(GPIOD, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
//功能配置
/* initialize CAN register */
can_deinit(CAN0);
/* initialize CAN */
can_parameter.working_mode = CAN_NORMAL_MODE; //正常模式
can_parameter.resync_jump_width = CAN_BaudRateInitTab[CAN_GetBaudRateNum(Baud)].SJW;
can_parameter.time_segment_1 = CAN_BaudRateInitTab[CAN_GetBaudRateNum(Baud)].BS1;
can_parameter.time_segment_2 = CAN_BaudRateInitTab[CAN_GetBaudRateNum(Baud)].BS2;
can_parameter.prescaler = CAN_BaudRateInitTab[CAN_GetBaudRateNum(Baud)].PreScale; //波特率预分频器
can_parameter.time_triggered = DISABLE; //时间触发通信模式
can_parameter.auto_bus_off_recovery = ENABLE; //自动总线关闭恢复
can_parameter.auto_wake_up = DISABLE; //自动唤醒模式
can_parameter.no_auto_retrans = DISABLE; //自动重传模式禁用
can_parameter.rec_fifo_overwrite = DISABLE; //接收 FIFO 覆盖模式
can_parameter.trans_fifo_order = DISABLE; //发送先进先出顺序
can_init(CAN0, &can_parameter);
// 滤波器配置
/* initialize filter */
/* CAN0 filter number */
can_filter.filter_number = 0; //过滤器号
/* initialize filter */
can_filter.filter_mode = CAN_FILTERMODE_MASK; //过滤模式、列表或掩码
can_filter.filter_bits = CAN_FILTERBITS_32BIT; //过滤器位宽
can_filter.filter_list_high = 0x0000; //过滤列表编号高位
can_filter.filter_list_low = 0x0000; //过滤列表编号低位
can_filter.filter_mask_high = 0x0000; //过滤器掩码数高位
can_filter.filter_mask_low = 0x0000; //过滤器掩码数低位
can_filter.filter_fifo_number = CAN_FIFO0; //接收与过滤器关联的 FIFO
can_filter.filter_enable = ENABLE; //过滤工作与否
can_filter_init(&can_filter);
nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);
nvic_irq_enable(CAN0_RX0_IRQn,0,0);
//中断使能
/* enable CAN receive FIFO0 not empty interrupt */
can_interrupt_enable(CAN0, CAN_INT_RFNE0);
}
//CAN0接收中断
void CAN0_RX0_IRQHandler(void)
{
can_receive_message_struct Can0_Rcv_Msg_Struct;
uint8_t CanRxLen, *DestBufPtr, *SourBufPtr;
/* check the receive message */
can_message_receive(CAN0, CAN_FIFO0, &Can0_Rcv_Msg_Struct);
if((Can0_Rcv_Msg_Struct.rx_ff == CAN_FF_EXTENDED) //扩展帧
&& (Can0_Rcv_Msg_Struct.rx_ft == CAN_FT_DATA)) //数据帧
{
Can0_Rcv_Msg.CanMsg[Can0_Rcv_Msg.Rin].Id.All = Can0_Rcv_Msg_Struct.rx_efid; //取标示符
Can0_Rcv_Msg.CanMsg[Can0_Rcv_Msg.Rin].DLC = Can0_Rcv_Msg_Struct.rx_dlen; //数据长度
CanRxLen = Can0_Rcv_Msg.CanMsg[Can0_Rcv_Msg.Rin].DLC;
DestBufPtr = (uint8_t *)&Can0_Rcv_Msg.CanMsg[Can0_Rcv_Msg.Rin].Data.Bytes.Byte1;
SourBufPtr = (uint8_t *)&Can0_Rcv_Msg_Struct.rx_data[0];
while (CanRxLen--) //取数据
{
*DestBufPtr++ = *SourBufPtr++;
}
Can0_Rcv_Msg.Rin++;
Can0_Rcv_Msg.Rin = Can0_Rcv_Msg.Rin % CAN_MSGS;
if(Can0_Rcv_Msg.Nums < CAN_MSGS)
{
Can0_Rcv_Msg.Nums++;
}
}
}
void CAN1_Init(uint16_t Baud)
{
can_parameter_struct can_parameter;
can_filter_parameter_struct can_filter;
/* enable can clock */
rcu_periph_clock_enable(RCU_CAN0);
rcu_periph_clock_enable(RCU_CAN1);
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_AF);
gpio_pin_remap_config(GPIO_CAN1_REMAP, ENABLE); //重映射PB5,PB6
//端口设置
/* configure CAN1 GPIO, CAN1_TX(PB6) and CAN1_RX(PB5) */
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_5);
//功能配置
/* initialize CAN register */
can_deinit(CAN1);
/* initialize CAN */
can_parameter.working_mode = CAN_NORMAL_MODE; //正常模式
can_parameter.resync_jump_width = CAN_BaudRateInitTab[CAN_GetBaudRateNum(Baud)].SJW;
can_parameter.time_segment_1 = CAN_BaudRateInitTab[CAN_GetBaudRateNum(Baud)].BS1;
can_parameter.time_segment_2 = CAN_BaudRateInitTab[CAN_GetBaudRateNum(Baud)].BS2;
can_parameter.prescaler = CAN_BaudRateInitTab[CAN_GetBaudRateNum(Baud)].PreScale; //波特率预分频器
can_parameter.time_triggered = DISABLE; //时间触发通信模式
can_parameter.auto_bus_off_recovery = ENABLE; //自动总线关闭恢复
can_parameter.auto_wake_up = DISABLE; //自动唤醒模式
can_parameter.no_auto_retrans = DISABLE; //自动重传模式禁用
can_parameter.rec_fifo_overwrite = DISABLE; //接收 FIFO 覆盖模式
can_parameter.trans_fifo_order = DISABLE; //发送先进先出顺序
can_init(CAN1, &can_parameter);
// 滤波器配置
/* initialize filter */
/* CAN1 filter number */
can_filter.filter_number = 14; //过滤器号
/* initialize filter */
can_filter.filter_mode = CAN_FILTERMODE_MASK; //过滤模式、列表或掩码
can_filter.filter_bits = CAN_FILTERBITS_32BIT; //过滤器位宽
can_filter.filter_list_high = 0x0000; //过滤列表编号高位
can_filter.filter_list_low = 0x0000; //过滤列表编号低位
can_filter.filter_mask_high = 0x0000; //过滤器掩码数高位
can_filter.filter_mask_low = 0x0000; //过滤器掩码数低位
can_filter.filter_fifo_number = CAN_FIFO1; //接收与过滤器关联的 FIFO
can_filter.filter_enable = ENABLE; //过滤工作与否
can_filter_init(&can_filter);
nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);
nvic_irq_enable(CAN1_RX1_IRQn,0,0);
//中断使能
/* enable CAN receive FIFO1 not empty interrupt */
can_interrupt_enable(CAN1, CAN_INT_RFNE1);
}
//CAN1接收中断
//void CAN1_RX0_IRQHandler(void)
void CAN1_RX1_IRQHandler(void)
{
can_receive_message_struct Can1_Rcv_Msg_Struct;
uint8_t CanRxLen, *DestBufPtr, *SourBufPtr;
/* check the receive message */
can_message_receive(CAN1, CAN_FIFO1, &Can1_Rcv_Msg_Struct);
if((Can1_Rcv_Msg_Struct.rx_ff == CAN_FF_EXTENDED) //扩展帧
&& (Can1_Rcv_Msg_Struct.rx_ft == CAN_FT_DATA)) //数据帧
{
Can1_Rcv_Msg.CanMsg[Can1_Rcv_Msg.Rin].Id.All = Can1_Rcv_Msg_Struct.rx_efid; //取标示符
Can1_Rcv_Msg.CanMsg[Can1_Rcv_Msg.Rin].DLC = Can1_Rcv_Msg_Struct.rx_dlen; //数据长度
CanRxLen = Can1_Rcv_Msg.CanMsg[Can1_Rcv_Msg.Rin].DLC;
DestBufPtr = (uint8_t *)&Can1_Rcv_Msg.CanMsg[Can1_Rcv_Msg.Rin].Data.Bytes.Byte1;
SourBufPtr = (uint8_t *)&Can1_Rcv_Msg_Struct.rx_data[0];
while (CanRxLen--) //取数据
{
*DestBufPtr++ = *SourBufPtr++;
}
Can1_Rcv_Msg.Rin++;
Can1_Rcv_Msg.Rin = Can1_Rcv_Msg.Rin % CAN_MSGS;
if(Can1_Rcv_Msg.Nums < CAN_MSGS)
{
Can1_Rcv_Msg.Nums++;
}
}
}
4. 波特率配置要点
-
同步段(Sync_Seg):固定为1TQ,用于同步
-
时间段1(BS1):包括传播时间段和相位缓冲段1
-
时间段2(BS2):相位缓冲段2
-
同步跳转宽度(SJW):限制重新同步时相位缓冲段的调整量
5. 实际应用中的考虑
-
采样点选择:通常建议采样点在75%-85%之间
-
采样点位置 = (1 + BS1) / (1 + BS1 + BS2)
以1Mbps配置为例:
(1 + 6) / (1 + 6 + 2) = 7/9 ≈ 77.8%
-
-
时钟精度要求:CAN总线对时钟精度要求较高,通常需要±0.5%以内的精度
-
总线长度限制:更高的波特率意味着更短的最大总线长度
这种波特率配置方法通过预定义表格简化了配置过程,开发者只需选择所需的波特率,代码会自动查找对应的参数组合。
CAN总线采样点详解
采样点是CAN总线通信中一个非常重要的概念,它决定了在哪个时间点读取总线上的电平状态。我来详细解释你提到的这段内容:
1. 采样点的定义
采样点(Sample Point)是指在一个CAN位时间内,控制器实际读取总线电平状态的时间点。正确的采样点设置对可靠通信至关重要。
2. 采样点计算公式
采样点位置 = (1 + BS1) / (1 + BS1 + BS2)
其中:
-
1 代表同步段(Sync_Seg),固定为1个时间量子(TQ)
-
BS1 是时间段1的时间量子数
-
BS2 是时间段2的时间量子数
3. 1Mbps配置示例分析
代码中的1Mbps配置:
{CAN_BT_SJW_1TQ, CAN_BT_BS1_6TQ, CAN_BT_BS2_2TQ, 6}, // 1M
计算过程:
-
同步段 = 1TQ
-
BS1 = 6TQ
-
BS2 = 2TQ
-
总位时间 = 1 + 6 + 2 = 9TQ
采样点位置 = (1 + 6) / (1 + 6 + 2) = 7/9 ≈ 77.8%
这意味着在这个配置下,控制器会在位时间的77.8%处采样总线电平。
4. 为什么建议75%-85%
这个范围是基于以下考虑:
-
信号稳定:确保信号已经稳定(经过传播延迟和上升/下降时间)
-
噪声容限:避开信号边沿可能不稳定的区域
-
行业经验:大多数CAN设备和控制器在这个范围内工作最佳
5. 采样点与总线质量的关系
-
采样点过早:信号可能未稳定,容易受到噪声干扰
-
采样点过晚:可能错过有效信号窗口,特别是在长距离传输时
-
理想采样点:应在信号最稳定的中点稍后位置
6. 实际应用中的调整
当遇到通信问题时,可以尝试:
-
增加BS1 - 将采样点后移
-
减少BS1 - 将采样点前移
-
保持总位时间不变的情况下调整BS1/BS2比例
例如,要调整1Mbps配置的采样点到80%:
-
总位时间保持9TQ
-
解方程 (1 + BS1)/9 = 0.8 ⇒ BS1 = 6.2 ⇒ 取整6
-
实际上保持77.8%也是可以接受的,因为已经很接近80%
理解采样点的概念对于CAN总线调试非常重要,特别是在高波特率或长距离通信场景下。
CAN位时间(Bit Time)详解
CAN位时间是指CAN总线传输一个数据位所需要的时间长度,它是CAN总线通信的基本时间单位。理解位时间对于正确配置CAN总线参数至关重要。
1. 位时间的组成
一个完整的CAN位时间由4个段组成(按时间顺序):
-
同步段(Sync_Seg)
-
固定为1个时间量子(1 TQ)
-
用于总线节点间的硬同步
-
边沿跳变应该发生在这个段内
-
-
传播时间段(Prop_Seg)
-
包含在BS1中
-
补偿总线上的物理延迟
-
-
相位缓冲段1(Phase_Seg1)
-
BS1的剩余部分
-
用于补偿正向的相位误差
-
-
相位缓冲段2(Phase_Seg2)
-
即BS2
-
用于补偿负向的相位误差
-
2. 位时间的计算
位时间 = (Sync_Seg + BS1 + BS2) × TQ
= (1 + BS1 + BS2) × TQ
其中:
-
TQ(Time Quantum):时间量子,由CAN时钟分频得到
-
总TQ数:通常选择在8-25个TQ之间
3. 位时间与波特率的关系
波特率 = 1 / 位时间
例如:
-
1Mbps波特率 → 位时间 = 1μs
-
500Kbps波特率 → 位时间 = 2μs
4. 位时间的实际意义
-
通信可靠性:合适的位时间设置确保在采样点时信号已稳定
-
同步机制:CAN总线通过调整相位缓冲段来实现位同步
-
错误检测:位时间定义了判断位错误的时间窗口
5. 代码中的位时间示例
以代码中的1Mbps配置为例:
{CAN_BT_SJW_1TQ, CAN_BT_BS1_6TQ, CAN_BT_BS2_2TQ, 6}, // 1M
计算:
-
预分频值 = 6
-
时间量子(TQ) = (1/54MHz)×6 ≈ 111.1ns
-
位时间 = (1+6+2)×111.1ns ≈ 1μs
-
波特率 = 1/1μs = 1Mbps
6. 位时间调整原则
-
总TQ数:通常8-25个TQ,高速率用较少TQ,低速率用较多TQ
-
采样点:保持在75%-85%之间
-
同步跳转宽度(SJW):通常设为BS1和BS2中较小的那个
理解位时间是CAN总线配置的基础,它直接影响到通信的可靠性和稳定性。
更多推荐



所有评论(0)