网易首页 > 网易号 > 正文 申请入驻

CAN总线位定时与同步:深度解析与代码实现

0
分享至


一、位时间的基本概念 1.1 核心时间单位

如您所述,CAN位时间由多个时间份额(Time Quantum, TQ)构成。关键公式:

TQ = BRP × Tclk

其中:

  • Tclk:CAN控制器外设时钟周期(通常来自系统时钟分频)

  • BRP:波特率预分频器值(寄存器值,通常为5~10位宽)

关于BRP+1的说明:不同芯片厂商的实现有差异。例如: STM32的BTR寄存器中 BRP 字段值为0~1023,实际分频 = BRP+1 某些老式独立CAN控制器(如SJA1000)的 BRP 寄存器直接等于分频值 本文后续代码采用实际分频值 = BRP寄存器值 + 1的方式(最通用)。
1.2 位时间的四段结构

一个标准CAN位时间分为四个连续段:

段名称

长度(TQ)

作用

同步段(SS)

1

固定,用于检测边沿

传播段(PROP)

1~8

补偿物理延迟

相位缓冲段1(PBS1)

1~8

采样点前缓冲,可延长

相位缓冲段2(PBS2)

1~8

采样点后缓冲,可缩短

采样点位置 = (SS + PROP + PBS1) / 总TQ数。推荐范围为70%~80%。

总位时间TQ数= 1 + PROP + PBS1 + PBS2,典型值8~25。

二、同步机制深度解析 2.1 硬同步(Hard Synchronization)

  • 触发时机:仅在帧起始(SOF)的隐性→显性跳变沿

  • 动作:接收节点将自己的SS段对齐到这个边沿

  • 调整幅度:无限制(可以大幅移动)

2.2 重同步(Resynchronization)
  • 触发时机:SOF之后的任何隐性→显性跳变沿(需满足跳变沿在PBS1或PBS2内)

  • 动作:通过延长PBS1或缩短PBS2来补偿相位误差

  • 限制:调整量不超过SJW(同步跳转宽度)

重同步规则:

  • 若边沿发生在PBS1内→ 相位误差e > 0(接收端慢),延长PBS1

  • 若边沿发生在PBS2内→ 相位误差e < 0(接收端快),缩短PBS2

  • 调整量 = min(|e|, SJW)

2.3 为什么SJW取值范围通常为1~4 TQ?(解答您的疑惑)

这是CAN控制器硬件实现的限制,根源在于:

  1. 采样点稳定性要求:SJW过大(如≥5)会导致采样点在位时间内过度漂移,降低噪声容限。

  2. 振荡器容差计算:CAN协议标准(ISO 11898-1)根据最大允许振荡器误差推导出SJW上限为4。公式如下:

    振荡器容差 ≤ SJW / (20 × NBT)
    其中NBT为一个位时间的TQ总数。当SJW=4时,可支持±1.58%的晶振误差(常见晶振为±0.5%~±1.5%)。
  3. 主流控制器事实标准:Bosch CAN 2.0规范建议SJW为1~4,所有主流芯片(STM32、SJA1000、MCP2515)均遵循此范围。

如果您看到某些文献中SJW取值可到8,那通常是指CAN FD(可变速率模式)下的扩展配置,经典CAN仅支持1~4。
三、代码实现示例 3.1 位定时参数计算器(C语言)

以下代码根据目标波特率、时钟频率自动计算BRP和段长度。

#include  

#include
#include

typedef struct {
uint16_t brp; // 波特率分频器 (实际分频 = brp+1)
uint8_t prop_seg; // 传播段长度 (1~8 TQ)
uint8_t pbs1_seg; // 相位缓冲段1 (1~8 TQ)
uint8_t pbs2_seg; // 相位缓冲段2 (1~8 TQ)
uint8_t sjw; // 同步跳转宽度 (1~4 TQ)
uint8_t sample_point_percent; // 采样点百分比
} CAN_BitTiming_TypeDef;

/**
* @brief 计算CAN位定时参数
* @param clk_khz CAN控制器时钟频率 (kHz)
* @param baud_kbps 目标波特率 (kbps)
* @param target_sp 目标采样点百分比 (例如 75 表示75%)
* @param timing 输出参数结构体
* @return 1:成功, 0:失败
*/
uint8_t CAN_ComputeBitTiming(uint32_t clk_khz, uint32_t baud_kbps,
uint8_t target_sp, CAN_BitTiming_TypeDef *timing)
{
uint32_t best_error = 0xFFFFFFFF;
uint8_t best_brp = 0, best_prop = 1, best_pbs1 = 2, best_pbs2 = 1;
uint32_t actual_baud;
int32_t error;
// 总TQ数范围: 8~25
for (uint8_t tq_num = 8; tq_num <= 25; tq_num++)
{
// 计算理论TQ时间 (us)
double tq_us = 1000.0 / (baud_kbps * tq_num);
double clk_t_us = 1.0 / clk_khz;
// 计算所需BRP (取整)
uint16_t brp_calc = (uint16_t)(tq_us / clk_t_us + 0.5) - 1;
if (brp_calc < 0 || brp_calc > 1023) continue;
// 实际波特率
actual_baud = clk_khz * 1000 / ((brp_calc+1) * tq_num);
error = (int32_t)actual_baud - (int32_t)(baud_kbps * 1000);
if (error < 0) error = -error;
// 误差小于0.5%才考虑
if (error * 1000 <= (int32_t)(baud_kbps * 1000 * 5))
{
// 分配段长度: SS=1固定, PROP=1~8, PBS1=1~8, PBS2=1~8
for (uint8_t prop = 1; prop <= 8 && (1+prop+2+1) <= tq_num; prop++)
{
for (uint8_t pbs1 = 1; pbs1 <= 8; pbs1++)
{
uint8_t pbs2 = tq_num - 1 - prop - pbs1;
if (pbs2 < 1 || pbs2 > 8) continue;
if (pbs1 < pbs2) continue; // 要求PBS1 >= PBS2
uint8_t sp = (1 + prop + pbs1) * 100 / tq_num;
if (abs(sp - target_sp) > 5) continue; // 采样点偏差±5%
// 选择最优组合 (优先采样点准确,次选误差小)
uint32_t current_error = abs(sp - target_sp) * 1000 + error;
if (current_error < best_error) {
best_error = current_error;
best_brp = brp_calc;
best_prop = prop;
best_pbs1 = pbs1;
best_pbs2 = pbs2;
}
}
}
}
}
if (best_error == 0xFFFFFFFF) return 0;
timing->brp = best_brp;
timing->prop_seg = best_prop;
timing->pbs1_seg = best_pbs1;
timing->pbs2_seg = best_pbs2;
timing->sjw = (best_pbs1 < 4) ? best_pbs1 : 4; // SJW不超过PBS1和4
timing->sample_point_percent = (1 + best_prop + best_pbs1) * 100 /
(1 + best_prop + best_pbs1 + best_pbs2);
return 1;
}

// 使用示例
int main(void)
{
CAN_BitTiming_TypeDef timing;
// 假设CAN外设时钟40MHz,目标波特率500kbps,采样点75%
if (CAN_ComputeBitTiming(40000, 500, 75, &timing)) {
printf("BRP = %d (实际分频 %d)\n", timing.brp, timing.brp+1);
printf("PROP_SEG = %d TQ\n", timing.prop_seg);
printf("PBS1 = %d TQ\n", timing.pbs1_seg);
printf("PBS2 = %d TQ\n", timing.pbs2_seg);
printf("SJW = %d TQ\n", timing.sjw);
printf("采样点 = %d%%\n", timing.sample_point_percent);
printf("总TQ数 = %d\n", 1+timing.prop_seg+timing.pbs1_seg+timing.pbs2_seg);
} else {
printf("未找到合适的位定时参数\n");
}
return 0;
}
3.2 STM32 HAL库配置示例

#include "stm32f4xx_hal.h"

CAN_HandleTypeDef hcan1;

void CAN1_Config(void)
{
hcan1.Instance = CAN1;
hcan1.Init.Mode = CAN_MODE_NORMAL;
// 手动计算好的参数 (假设APB1=42MHz, 波特率500k, 采样点75%)
// 总TQ=16, BRP=5 (实际分频6), 则TQ=6/42M≈142.86ns, 位时间=16*142.86ns≈2.2857us -> 437.5kbps
// 调整为BRP=4 (分频5), TQ=5/42M≈119ns, 位时间=16*119ns=1.904us -> 525kbps
// 实际更精确的配置:BRP=3(分频4), TQ=4/42M≈95.24ns, 位时间=20*95.24ns=1.9048us -> 525kbps
// 为了500kbps,需要位时间=2us,TQ=100ns,BRP分频=42M*100ns=4.2->取4,BRP=3
// 总TQ=20,SS=1,PROP=7,PBS1=6,PBS2=6,采样点=(1+7+6)/20=70%
hcan1.Init.TimeTriggeredMode = DISABLE;
hcan1.Init.AutoBusOff = DISABLE;
hcan1.Init.AutoWakeUp = DISABLE;
hcan1.Init.AutoRetransmission = ENABLE;
hcan1.Init.ReceiveFifoLocked = DISABLE;
hcan1.Init.TransmitFifoPriority = DISABLE;
// 位定时寄存器 BTR 配置
// STM32的BS1 = PROP + PBS1, BS2 = PBS2, 且BS1/BS2长度=位长-3
// 这里需要根据芯片手册转换
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ; // SJW=1
hcan1.Init.TimeSeg1 = CAN_BS1_13TQ; // 13TQ (包含SS)
hcan1.Init.TimeSeg2 = CAN_BS2_6TQ; // 6TQ
hcan1.Init.Prescaler = 4; // BRP=4 (实际分频=4+1=5)
if (HAL_CAN_Init(&hcan1) != HAL_OK) {
Error_Handler();
}
}
3.3 同步过程模拟(伪代码)

以下演示接收节点如何根据边沿误差调整PBS1/PBS2:

// 接收节点位流处理状态机
typedef enum {
IDLE,
WAITING_SOF,
RECEIVING_BITS
} CAN_RxState;

CAN_RxState rx_state = WAITING_SOF;
int16_t tq_counter = 0; // 当前位内的TQ计数
int16_t phase_error = 0; // 相位误差 (TQ单位)

void CAN_Rx_Tick(void) // 每个TQ调用一次
{
if (detect_falling_edge()) { // 隐性->显性跳变
if (rx_state == WAITING_SOF) {
// 硬同步:直接对齐到SS起点
tq_counter = 0;
rx_state = RECEIVING_BITS;
}
else if (rx_state == RECEIVING_BITS && tq_counter > 0) {
// 重同步:计算相位误差
if (tq_counter < (ss_len + prop_len + pbs1_len)) {
// 边沿在PBS1内 -> 节点慢,需要延长PBS1
phase_error = tq_counter - (ss_len + prop_len);
if (phase_error > sjw) phase_error = sjw;
pbs1_extend = phase_error;
pbs2_shorten = 0;
}
else if (tq_counter < total_tq) {
// 边沿在PBS2内 -> 节点快,需要缩短PBS2
phase_error = (total_tq - tq_counter);
if (phase_error > sjw) phase_error = sjw;
pbs2_shorten = phase_error;
pbs1_extend = 0;
}
}
}
// 采样点判断 (位于PBS1结束时刻)
if (tq_counter == (ss_len + prop_len + pbs1_len - 1 + pbs1_extend)) {
sample_bit(); // 读取总线电平
}
// 位结束,准备下一个位
if (tq_counter >= (total_tq + pbs1_extend - pbs2_shorten - 1)) {
tq_counter = 0;
pbs1_extend = 0;
pbs2_shorten = 0;
} else {
tq_counter++;
}
}
四、总结与最佳实践

参数

推荐值/范围

总TQ数

16~20

平衡同步精度与开销

采样点

70%~80%

经典CAN常用75%

SJW

1~3

晶振精度高时可取1~2

PROP

根据总线长度

每米总线约需5~10ns,转换为TQ

BRP

尽可能小

提高采样分辨率,但注意寄存器范围

同步设计要点:

  • 整个网络应采用相同的位定时参数

  • 长总线(>40m)需增加PROP段

  • 高波特率(>500k)应减少总TQ数,提高采样点精度

希望这篇补充了代码实例和SJW深度解析的文章能对您有所帮助。如果您需要特定MCU(如NXP S32K、Infineon AURIX)的寄存器级配置代码,我可以进一步提供。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
中国为什么总说要扩大消费,却迟迟没有进行大规模收入分配改革?

中国为什么总说要扩大消费,却迟迟没有进行大规模收入分配改革?

素衣读史
2026-06-25 22:12:10
昔日国乒名将陈龙灿发声!张本宇留日另有原因,当年选择不简单

昔日国乒名将陈龙灿发声!张本宇留日另有原因,当年选择不简单

潋滟晴方DAY
2026-08-13 13:06:45
反转!中国男篮被爆出内幕,郭士强这次可能被冤枉,真错怪他了

反转!中国男篮被爆出内幕,郭士强这次可能被冤枉,真错怪他了

宗介说体育
2026-09-27 07:59:37
贷款中介,这几天集体变安静了

贷款中介,这几天集体变安静了

21世纪经济报道
2026-09-27 22:07:57
王曼昱头号贵人,不是刘国梁也不是王励勤,竟是已离开国家队的他

王曼昱头号贵人,不是刘国梁也不是王励勤,竟是已离开国家队的他

完善法
2026-09-09 04:59:50
国产显卡撞上性能墙!砺算LX 7G100号称对标RTX 4060:实测勉强赢过AMD九年前的RX 580

国产显卡撞上性能墙!砺算LX 7G100号称对标RTX 4060:实测勉强赢过AMD九年前的RX 580

快科技
2026-09-26 14:11:07
太瘆人了!日本男子潜入单身女子家100多次,打扫卫生、补充饮料,甚至偷走内衣后再买新的换回去。

太瘆人了!日本男子潜入单身女子家100多次,打扫卫生、补充饮料,甚至偷走内衣后再买新的换回去。

日本物语
2026-09-27 20:34:09
一座1亿瓦的核反应堆,只有洗衣机大小,运行63年却没发一度电,专门生产一些造出来就快速消失的东西,已帮助了数亿生命

一座1亿瓦的核反应堆,只有洗衣机大小,运行63年却没发一度电,专门生产一些造出来就快速消失的东西,已帮助了数亿生命

徐德文科学频道
2026-09-27 14:20:48
刘欢离世爆出真实家底,不拍戏不代言,不靠综艺为何坐拥上亿身家

刘欢离世爆出真实家底,不拍戏不代言,不靠综艺为何坐拥上亿身家

东方不败然多多
2026-09-27 16:17:04
刘欢临终细节:妻子卢璐和女儿刘一丝守在床边,母女俩哭到站不住

刘欢临终细节:妻子卢璐和女儿刘一丝守在床边,母女俩哭到站不住

情感大头说说
2026-09-28 05:34:17
刚拿冠军就退役,当晚直接打包行李走人,这姑娘的操作把全网看傻

刚拿冠军就退役,当晚直接打包行李走人,这姑娘的操作把全网看傻

静若梨花
2026-08-29 10:42:55
嫁错人太可怕!被前夫公开骂“性欲太强”的她,活成张柏芝对照组

嫁错人太可怕!被前夫公开骂“性欲太强”的她,活成张柏芝对照组

阿讯说天下
2026-08-02 04:31:47
19岁松岛辉空,正式公布退役计划

19岁松岛辉空,正式公布退役计划

乒乓乐园
2026-08-13 12:18:37
索尼低价区试水?《战神劳菲》能成为PS首个试金石吗

索尼低价区试水?《战神劳菲》能成为PS首个试金石吗

游民星空
2026-09-27 19:13:07
港媒:大陆高铁已被“粪便淹没”!再不解决后果严重,真的假的?

港媒:大陆高铁已被“粪便淹没”!再不解决后果严重,真的假的?

铭记历史呀
2026-09-02 02:21:33
电影院的至暗时刻:174亿票房、场均不到6人、五大公司全亏

电影院的至暗时刻:174亿票房、场均不到6人、五大公司全亏

草莓解说体育
2026-09-27 17:07:15
人活多久,看起夜就知道?寿命短的人,起夜一般有这3个特征

人活多久,看起夜就知道?寿命短的人,起夜一般有这3个特征

芹姐说生活
2026-09-10 23:50:29
20岁德国天才后卫闪耀德甲,开价3500万欧,良心价,皇马情有独钟

20岁德国天才后卫闪耀德甲,开价3500万欧,良心价,皇马情有独钟

零度眼看球
2026-09-28 07:36:21
日本人怒斥高市,非要硬刚中国,这下全世界都知道敌国条款了

日本人怒斥高市,非要硬刚中国,这下全世界都知道敌国条款了

爱看剧的阿峰
2026-09-27 13:15:55
人大代表建议机关事业单位双休调整为“大周休3天,小周休2天”

人大代表建议机关事业单位双休调整为“大周休3天,小周休2天”

职场资深秘书
2026-09-27 19:40:23
2026-09-28 07:52:49
新能源自动驾驶 incentive-icons
新能源自动驾驶
专注于半导体行业资讯
1015文章数 348关注度
往期回顾 全部

科技要闻

星舰第14飞,为什么准备绕地球六圈?

头条要闻

小伙汽车电瓶被偷刚报完案车又被砸 强忍蚊虫蹲守一宿

头条要闻

小伙汽车电瓶被偷刚报完案车又被砸 强忍蚊虫蹲守一宿

体育要闻

114项指控成立,曼城已经完蛋了吗?

娱乐要闻

刘欢去世后谣言四起,韩磊被翻旧账

财经要闻

“为了看短剧,我妈两年花了22万 ”

汽车要闻

MAZDA EZ-60激光版上市 焕新全系11.39万元起

态度原创

家居
本地
手机
游戏
公开课

家居要闻

2026建博会(广州) 公装联探展交流活动

本地新闻

中秋逛白塔寺,体验国医妙荟雅集

手机要闻

苹果A20 Pro运行《GTA 5》性能表现达到GTX 1650水平 能效高出近12倍

《神鬼寓言4》伦敦首次开放试玩 战斗配音获玩家称赞

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版