news 2026/10/14 17:04:02

CAN总线通信原理与STM32 bxCAN外设开发实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CAN总线通信原理与STM32 bxCAN外设开发实战

以前一直觉得,搞懂 CAN 总线是个“早晚要做但不着急”的事。真正被逼着去弄明白,是某个项目里两块主控板之间需要用一根线传状态,板子距离两三米,线还从电机旁边走,UART 直接废掉,I2C 更是想都别想。换成 CAN 总线之后,问题一次解决,后面所有做过的多节点通信项目我都默认优先考虑它。这篇文章就把 CAN 总线从协议底层到 STM32 的 bxCAN 外设应用完整梳理一遍,适合刚接触 CAN、被各种帧结构和寄存器搞晕的人,也适合已经跑通 Demo 但没想清楚原理的开发者。全程按我自己项目里的实际操作讲,不绕弯子。

1. 为什么很多嵌入式项目最终选了 CAN 总线而不是串口

先说我自己的结论:选通信方案,本质是选“物理层+数据链路层”的组合是否匹配现场环境。UART 简单,但单点对单点、无仲裁、抗干扰靠运气。I2C/SPI 适合板内短距离,一根排线可以搞定,但超过半米就开始看人品。RS485 虽然也是差分,但它本质上还是主从结构,谁先发谁后发要软件说了算,一旦两个节点同时开口就是数据碰撞,没有总线层面的解决办法。

CAN 总线能把这些问题一次性收掉,原因在于它从设计之初就是为“多主、远距离、强干扰、高可靠”准备的。总线上任何一个节点都可以主动发起通信,多个节点同时发也不会冲突,因为控制器和协议栈会通过硬件仲裁决定谁先用总线。这个能力在分布式系统里太重要了,比串口加 Modbus 轮询的方式省心太多。

做个简单对比会更直观:

特性UARTI2CSPIRS485CAN
通信距离1-2米内板级板级可达1000米可达几千米
多节点点对点多主可仲裁但复杂一主多从主从轮询多主仲裁
抗干扰弱弱弱差分,较好差分+错误处理,强
芯片支持几乎所有MCU几乎所有MCU几乎所有MCU需收发器需控制器+收发器
是否需要软件轮询不需要简单仲裁由主机控制需要不需要,硬件仲裁

所以选型逻辑很清楚:如果你的系统里节点数量超过三个,节点之间距离超过一米,或者环境里电机、继电器、变频器这类干扰源多,直接考虑 CAN 总线。反过来,板内两个芯片通信,UART 或 I2C 更简单,没必要为了“高级”而上 CAN。

CAN 总线常见的技术参数也顺便列一下,方便做方案评估:经典 CAN 最高速率 1Mbps,高速 CAN(CAN FD)可以做到 5Mbps 以上;报文数据段最长 8 字节,CAN FD 扩展后可以到 64 字节;物理介质用双绞线,CAN_H 和 CAN_L 一组差分信号;一条主干线理论上可以挂 100 多个节点,实际受收发器驱动能力和线缆质量影响,几十个节点很轻松。

2. 物理层先看明白:差分信号、显性位与隐性位,还有那两颗120欧电阻

很多人学 CAN 卡在物理层,总觉得“电平”两个字抽象。其实 CAN 物理层的核心就一句话:它用一对导线上的电压差来传数据,而不是像 TTL 串口那样用单根线对地的绝对电压。这个设计带来的好处是,外界的共模干扰(比如电机启动时在两根线上同时感应的噪声)会被差分接收器直接抵消掉。

具体电平状态也很有特点。CAN 总线上的位只有两种:显性位和隐性位。显性位代表逻辑 0,隐性位代表逻辑 1。总线空闲时,CAN_H 和 CAN_L 都在 2.5V 附近,差分电压接近 0V,总线处于隐性状态。当某个节点发送显性位时,CAN_H 被拉到约 3.5V,CAN_L 被拉到约 1.5V,差分电压约 2V。这个“显性位电压差”足够让所有接收节点稳定识别。

从协议设计的角度理解一下为什么用“显性/隐性”而不是“高/低”。多节点共享一条总线,如果某个节点在发隐性位(1),另一个节点同时在发显性位(0),两者“开车”碰在一起,谁赢?物理层上显性位主动驱动差分电压,隐性位相当于“释放总线”,所以总线最终表现为显性,0 覆盖 1。这就是后面仲裁机制能成立的基础。

终端电阻这块是新手最容易忽略的。CAN 总线规范要求线缆两端各接一个 120Ω 电阻,而不是每个节点都接,也不是随便接一个。原因是 CAN 信号在总线上以很高的速率跳变,如果传输线末端阻抗不匹配,信号会产生反射,导致波形畸变,严重时直接误码。120Ω 是从双绞线的特性阻抗定出来的经典值,在两端并联两个 120Ω 后,电源关闭状态下从任一接入点量 CAN_H 到 CAN_L 之间,电阻应该在 60Ω 左右。我用这个办法快速排查过好几块板子,很灵。

收发器不能省。STM32 内部集成的只是 CAN 控制器,负责协议处理、滤波、错误状态这些逻辑工作,但它引脚出来的不是差分电平。控制器必须外接一个 CAN 收发器芯片,把控制器的 TX/RX 信号转换成 CAN_H/CAN_L 差分信号,市面上常见的型号比如高速收发器 TJA1050、SN65HVD230 都可以。5V 供电的收发器接 3.3V 的 STM32,需要留意逻辑电平兼容,很多收发器是 5V 供电但逻辑引脚兼容 3.3V,具体看数据手册的 VIO 或逻辑电平说明,布线前一定确认一遍,否则会出现“连上了但收不到数据”的邪门问题。

3. 数据链路层的几件大事:帧结构、仲裁机制、位填充与错误处理

物理层搞定了,下面才是 CAN 真正有魅力的地方:数据链路层。CAN 的报文叫“数据帧”,最常见的标准格式数据帧由这么几段组成:起始位 SOF、仲裁段、控制段、数据段、CRC 校验段、ACK 应答段和帧结束 EOF。

SOF 就是一个显性位,表示一帧开始。仲裁段里最关键的是标识符 ID,标准帧是 11 位 ID,扩展帧是 29 位 ID。控制段里有数据长度代码 DLC,表示后面数据段有几个字节,经典 CAN 一帧最多 8 字节。数据段就是业务数据。CRC 是 15 位校验码,由发送节点硬件算好,接收节点硬件核对。ACK 段是接收节点回给发送节点的“我收到了”信号,这有个隐藏知识点:发送节点在 ACK 段会释放总线,接收节点如果完整无误地收到这一帧,就会拉一个显性位来应答。如果总线上只有发送节点、没有任何节点在收,发送节点的控制器会在 ACK 段检测不到显性位,直接报 ACK 错误。

仲裁机制值得单独讲透一点。假设节点 A 和节点 B 同时开始发帧,它们先各发一个 SOF,然后在仲裁段逐位发送 ID。CAN 的规则是“显性位优先级高于隐性位”,也就是在某个位时刻,A 发的是隐性(1),B 发的是显性(0),总线电平变成显性,A 会发现自己发出的隐性位和总线实际电平不一致,判定自己仲裁失败,立刻停止发送,转为接收状态。B 则继续发送完整帧。整个过程由硬件完成,微秒级结束,软件根本不需要介入。这也解释了为什么 ID 小的节点优先权更高,因为 ID 数值越小,二进制里高位 0 越多,越容易在仲裁段压制其他节点。

优先级设计好之后,要理解位填充。CAN 总线不是通过独立时钟线同步的,接收方靠总线上的电平跳变来恢复位时序。如果一长串数据全是连续的隐性位或连续显性位,信号长期没有跳变,接收方的采样时钟就会逐渐漂移,最终采错采样点。所以 CAN 协议规定,发送端在连续发送 5 个相同电平的位之后,必须自动插入一个相反电平的位,这就是位填充。接收端收到数据后会按规则把这个填充位去掉。这个机制保证了总线上每隔最多 5 个位就至少有一次跳变,时钟同步就不会丢。

错误处理也说一下,因为这是 CAN 和普通串口在可靠性上拉开差距的关键。CAN 控制器内置五种错误检测机制:位错误、填充错误、CRC 错误、格式错误、ACK 错误。每个节点内部维护发送错误计数器和接收错误计数器。错误计数小于 128 时,节点处于“错误主动”状态,出错时可以主动发出错误帧通知全网;计数在 128 到 255 之间时进入“错误被动”状态,只能被动响应错误帧;计数超过 255 就变成“总线关闭”,直接隔离出总线。这个设计非常像现实里的“隔离病房”,个别节点哪怕彻底短路也不会把整条总线拖死。

4. STM32 的 bxCAN 外设:硬件已经帮你做掉一半

现在把视角切到 STM32。大部分常见型号内置的 CAN 控制器叫 bxCAN,它挂在 APB1 总线上,也就是说 CAN 外设的工作频率来自 APB1 时钟而不是系统主频。这个细节很重要,因为后面算波特率要用到 APB1 的准确值,很多人翻车就是因为拿 72MHz 去算,忘了 APB1 通常是 36MHz。

bxCAN 的资源可以这样概括:3 个发送邮箱、2 个接收 FIFO、若干筛选器组。发送邮箱相当于三个发送缓冲区,只要有一个邮箱空闲,就可以把待发帧丢进去,让控制器自己排队发送。接收 FIFO 是硬件做的接收队列,FIFO0 和 FIFO1 各能暂存 3 帧。帧进来会先经过筛选器,再进入 FIFO,然后触发中断或者被查询读到。

筛选器组是 STM32 的 CAN 外设里比较特色的硬件功能。每个筛选器可以工作在两种模式:掩码模式和列表模式。掩码模式下的逻辑是:硬件把接收帧的 ID 和筛选器寄存器里的 ID 做比较,比较结果再和掩码寄存器做与运算,如果结果为 0 就算匹配。说白了,掩码决定“哪些位必须严格相等,哪些位可以随便”。列表模式则更简单粗暴,硬件维护一个 ID 列表,只要帧的 ID 能和列表里任意一项匹配就放行。工程项目里如果只关心少数几个 ID 的报文,用列表模式最省心;如果希望接收一段连续 ID 的报文,用掩码模式。

bxCAN 还有四种工作模式:正常模式、环回模式、静默模式和环回静默模式。调试阶段强烈推荐先玩环回模式。环回模式下,控制器发送的报文不会真正跑到总线上去,而是被控制器内部直接回环到自己的接收路径上。换句话说,在没有外接任何收发器、没有接总线的情况下,你也能验证“我的 CAN 初始化对不对、我的发送和接收代码通不通”。这个模式我几乎每个项目调试都先用,等环回跑通了再接真实总线,能省出一大截排错时间。

说回协议无关的细节,bxCAN 会自动完成前面提到的仲裁、位填充、CRC 校验、错误处理,软件只需要做四件事:配置 GPIO 复用、配置 CAN 波特率和采样点、配置筛选器、然后按结构体收发报文。这部分我放下一章直接写代码。

5. 从零写一套 CAN 收发程序:初始化、筛选器与中断收发

这里给出一套我实际在用的 HAL 库示例代码,基于常见型号的 72MHz 主频配置,APB1 为 36MHz。第一步先配置引脚和使能时钟,以 PA11 为 RX、PA12 为 TX 为例:

void CAN_GPIO_Init(void) { GPIO_InitTypeDef gpio = {0}; __HAL_RCC_CAN1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); gpio.Pin = GPIO_PIN_11; /* CAN1_RX */ gpio.Mode = GPIO_MODE_AF_INPUT; gpio.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &gpio); gpio.Pin = GPIO_PIN_12; /* CAN1_TX */ gpio.Mode = GPIO_MODE_AF_PP; /* 推挽复用输出 */ gpio.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &gpio); }

注意 RX 引脚是浮空输入,TX 引脚是复用推挽输出。这个配置如果写反,常常出现总线波形一直在但就是收不到数据的情况。

接着配置 CAN 的工作参数。波特率的计算公式是:

波特率 = APB1时钟 / (预分频系数 × (1 + BS1 + BS2))

其中 BS1、BS2 的单位是 tq(时间量子),1 是固定的同步段。采样点位置为(1 + BS1) / (1 + BS1 + BS2),一般设计在 75%~80% 比较稳。以 APB1=36MHz 为例,我用得最多的一组参数是:预分频 4,BS1=13tq,BS2=4tq,得到位时间 18tq,波特率 500kbps,采样点约 77.8%。

CAN_HandleTypeDef hcan1; void CAN_Init_500k(void) { hcan1.Instance = CAN1; hcan1.Init.Prescaler = 4; /* 36MHz / 4 = 9MHz,每tq为1/9MHz */ hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ; hcan1.Init.TimeSeg1 = CAN_BS1_13TQ; hcan1.Init.TimeSeg2 = CAN_BS2_4TQ; hcan1.Init.TimeTriggeredMode = DISABLE; hcan1.Init.AutoBusOff = ENABLE; /* 总线关闭后自动恢复,省得手动复位 */ hcan1.Init.AutoWakeUp = DISABLE; hcan1.Init.AutoRetransmission = ENABLE; /* 发送失败自动重发,适合可靠性场景 */ hcan1.Init.ReceiveFifoLocked = DISABLE; hcan1.Init.TransmitFifoPriority = ENABLE; HAL_CAN_Init(&hcan1); }

这里两个参数多说一句。AutoRetransmission开启后,如果一帧数据因为仲裁失败或者错误没能发出去,控制器会自动重传。对大多数应用这是好事,但也要知道它会占住邮箱,极端情况下会影响新数据的发送。AutoBusOff开启以后,总线关闭状态会自动恢复连接,免去手动调用软件复位流程。

接下来是筛选器。刚调试时最简单的是把所有报文全部放进来,掩码全部写成 0 即可:

void CAN_Filter_AllPass(void) { CAN_FilterTypeDef filter = {0}; filter.FilterBank = 0; /* 用筛选器组0 */ filter.FilterMode = CAN_FILTERMODE_IDMASK; filter.FilterScale = CAN_FILTERSCALE_32BIT; filter.FilterIdHigh = 0x0000; filter.FilterIdLow = 0x0000; filter.FilterMaskIdHigh = 0x0000; /* 掩码为0,不校验任何位 */ filter.FilterMaskIdLow = 0x0000; filter.FilterFIFOAssignment = CAN_RX_FIFO0; filter.FilterActivation = ENABLE; HAL_CAN_ConfigFilter(&hcan1, &filter); HAL_CAN_Start(&hcan1); HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING); }

筛选器配置有个容易犯错的地方:掩码是 0 代表“所有位都忽略”,而不是“所有位都要匹配”。很多人第一次写都反了,导致一条消息也收不到。

发送一帧数据,步骤是先看有没有空闲邮箱,再填报文头结构体,最后呼叫发送接口:

uint8_t CAN_Send_Std(uint32_t id, uint8_t *data, uint8_t len) { CAN_TxHeaderTypeDef txHeader; uint32_t mailbox = 0; if (len > 8) len = 8; txHeader.StdId = id; txHeader.IDE = CAN_ID_STD; txHeader.RTR = CAN_RTR_DATA; txHeader.DLC = len; txHeader.TransmitGlobalTime = DISABLE; if (HAL_CAN_GetTxMailboxesFreeLevel(&hcan1) == 0) { return 0; /* 三个邮箱全满,发送失败 */ } if (HAL_CAN_AddTxMessage(&hcan1, &txHeader, data, &mailbox) != HAL_OK) { return 0; } return 1; }

接收则推荐用中断,代码在回调函数里处理。这比在 while 循环里轮询 FIFO 干净得多,也不容易丢帧:

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) { CAN_RxHeaderTypeDef rxHeader; uint8_t rxData[8]; HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rxHeader, rxData); if (rxHeader.StdId == 0x123) { /* 这里处理你的业务数据 */ } }

FIFO0 收到帧时硬件自动触发这个回调,记得在主程序里已经打开了 CAN_IT_RX_FIFO0_MSG_PENDING 中断,并且正确设置了 CAN 中断优先级。如果不走中断,也可以在主循环里先查询HAL_CAN_GetRxFifoFillLevel,有数据再读。

另外一个常见疑问是:为什么我发了标准帧,接收端收到的 StdId 和我发的不一样?因为接收结构体里的 StdId 是经过逻辑右移处理的,而发送结构体里的 StdId 是原始 11 位数值。两边都走 HAL 库接口,这个问题通常不太会遇到。一旦你直接操作寄存器或者混用标准库寄存器写法,就很容易被这个位段偏移折腾一番。建议收发两端代码风格保持一致,别混用。

6. 实测中踩过的 CAN 坑,一次讲清楚

代码能跑起来只是开始,真正让 CAN 项目“稳”的是调试阶段排除掉的那堆坑。下面这几个都是我实际遇到过的,按出现频率排个序。

第一个坑是终端电阻位置不对或数量不对。曾经有一块板子,单板测试时收发都正常,接到总线网络上就偶发超时。排查到最后,原因就是总线上只有两块板子,但板子上的终端电阻被设计成了默认开启,导致两端各有两只 120Ω 并联,总线负载明显偏重。后来改成用跳线手动插拔终端电阻,只保留总线物理两端各一只 120Ω,问题消失。快速判断方法:断电后在总线任意接入点量 CAN_H 和 CAN_L 之间的电阻,如果在 60Ω 左右,说明终端电阻工作正常;如果量到 120Ω,说明只有一端有;如果量到接近 0Ω,说明有短路。

第二个坑是正常模式下单节点自发自收失败。这是新手最容易懵的地方:我明明发了,也没有任何报错,但就是自己收不到。原因在于正常模式下,发送节点在 ACK 段等待接收节点回显性应答,如果总线上没有任何其他节点,发送节点检测不到 ACK,于是报 ACK 错误,同时因为AutoRetransmission开着,帧会被反复重发,看起来就像“卡死在发送里”。解决办法很简单:自测阶段用环回模式,或者外接一个 USB-CAN 分析工具当接收端,别让发送节点一个人唱独角戏。

第三个坑是波特率误差和采样点设置不合理。两个控制器通讯,一方的晶体频率有偏差,或者 APB1 分频算出的 tq 组合导致实际波特率和目标值差了 1%,短期内可能没事,但总线越长、节点越多,出错概率越高。我的习惯是给自己定一条省钱原则:目标波特率和实际波特率的误差控制在 1% 以内,采样点放在 75% 到 80% 之间。如果项目里波特率不太常规,比如要用 125kbps,就先算出 APB1 时钟和波特率之间的整除关系,优先保证预分频系数和位时间组合是整数结果。

第四个坑是筛选器把报文“吃掉”了,软件层面没有任何感觉。这个坑隐蔽在:筛选器里写的东西本身没错,但你用错了 ID 布局。CAN 的 ID 在 32 位寄存器里不是从 bit0 开始的,标准 ID 占了高 11 位,所以直接把收到的StdId当成筛选器里的 ID 结果是错的。用 HAL 库HAL_CAN_ConfigFilter时,填写 FilterIdHigh/FilterIdLow 要按 ID 布局换算。初学阶段我强烈建议先做“全通”筛选器,确认数据链路通了,再去算掩码过滤,否则误把自己坑了找不到原因。

第五个坑是错误状态没有恢复机制。常见场景是总线上某个节点反复出错,错误计数器越过 255,节点进入 Bus-Off 状态。如果没有开AutoBusOff,节点就彻底脱离总线,你要在调试器里看 CAN 外设状态才发现它“消极怠工”了。更稳妥的做法是:初始化里开自动恢复,同时在应用层做周期性的健康检查,比如每 500ms 读一次错误计数,超过阈值就主动复位 CAN 外设,让系统自愈。

第六个坑,也是最基础的一个:CAN_H 和 CAN_L 接反。很多收发器带反接保护,不会立刻烧掉,但差分信号极性反了,通信必然失败。我吃过一次亏,是在转接板线序上,板子丝印写的是 H,结果杜邦线插到了另一排,示波器一看波形是反的才反应过来。接线之前先用万用表确认收发器的 CANH、CANL 引脚定义,再对接线颜色做统一约定,比如 CANH 用橙线,CANL 用蓝线,所有节点统一标准。

调试工具方面,做 CAN 项目有条件的话备一个 USB-CAN 分析工具,几百块的够用,配合电脑软件能直接看 ACK 错误、帧 ID、总线负载率。没有工具的话,用示波器也能诊断:隐性状态时 CAN_H 和 CAN_L 都在 2.5V 附近,显性位 CAN_H 抬到 3.5V、CAN_L 压到 1.5V,差分约 2V。如果波形上沿明显过冲或者方波边沿有振铃,基本都是终端电阻和布线的问题,不是芯片的问题。

还有一个容易被忽略的系统级坑:不同节点的地电位不一致。CAN 虽然是差分通信,但收发器本身需要参考地,如果两块板子用两个不同的开关电源供电,地之间压差过大,共模电压超出收发器的允许范围,会导致持续错误。解决方法是总线两端或中间用一根地线把各个节点的工作地连起来,尤其是远距离节点之间,地线不能省。这个点是我做分布式项目踩过最深的一个坑,换了很多代码逻辑都没用,最后发现是两个电源模块的地没有共接。

整套跑通之后,建议再按这个路径进阶试试:先自己焊两块板子,用双绞线互联,分别写上“节点 A 每 100ms 发一帧、节点 B 收到后回一帧”的循环测试;然后把环回模式切换成正常模式,确认 ACK 逻辑;接着加第三块板子,故意让两个节点同时发帧,观察仲裁是否正常;最后再接入网络和电机负载,用 USB-CAN 工具长时间抓包,统计错误帧。整套操作走下来,CAN 总线在你的项目里基本就不会再给你惊喜了。

我的体会是,CAN 总线相比串口真正贵重的不是协议本身,而是它把可靠性内建在了控制器硬件里:自动仲裁、自动重发、自动错误计数、自动故障隔离。你要做的只是配置好外设,再把业务逻辑按帧收发去组织。这个特性让它在工业现场和车载环境里经久不衰,也让 STM32 这类集成 bxCAN 的芯片成了嵌入式项目里最省心的通信方案之一。下一步如果想深入,可以试试加一个 CAN 应用层协议,比如开源的 CANopen 协议栈,让总线上的节点具备参数配置和状态上报能力,那又是另外一层天地了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 17:03:57

前缀和+同余+哈希表:破解“连续子数组和可被k整除”的2024题22

1. 题面只有三行,但它如何骗过了我的第一反应1.1 原题描述与数据范围在整理2024年热题清单的时候,我注意到一道被很多人称为“2024年题22”的题。它出现的频率高得离谱,但绝大多数人只记得“这题很简单”,却说不出到底考了什么。题…

作者头像 李华
网站建设 2026/10/14 17:03:46

QSpinBox箭头位置换到左侧:QSS子控件定位与图片替换全解析

前阵子接了个界面改造的需求,设计稿上数字输入框的箭头位置跟默认控件完全不一样:向上的箭头要放到输入框左侧,向下的按钮要缩小藏起来,整个控件看起来像一个小巧的计数器。当时我理所当然地认为,既然是Qt的QSpinBox&a…

作者头像 李华
网站建设 2026/10/14 17:03:43

Godot Transform2D 完全指南:2D 变换矩阵原理、完整 API 与实战应用

文档教程游戏开发 【免费下载链接】godot-docs Godot Engine official documentation 项目地址: https://gitcode.com/GitHub_Trending/go/godot-docs 点击查看 免费下载 Transform2D 是 Godot 引擎内置的 23 变换矩阵 Variant 类型,由 x、y 两个基向量…

作者头像 李华
网站建设 2026/10/14 17:03:28

端到端图像水印嵌入与提取:深度学习实战指南

简介:这是一套基于PyTorch构建的端到端图像水印嵌入与提取系统,利用深度卷积网络实现鲁棒水印的联合优化,覆盖COCO、ImageNet、Cifar10与QRCode四类主流数据集,可满足深度学习课程设计、毕业设计、科研复现及工程原型验证等场景需…

作者头像 李华
网站建设 2026/10/14 17:03:26

AI前沿速递|AI学会“装傻“了!

2026年10月14日 三篇最新arXiv论文深度解读 导读: 2026年10月中旬,AI领域接连出现三个令人深思的突破。一篇被NeurIPS 2026接收的论文证明,AI模型可以利用密码学方法可证明地隐藏任意危险能力,让所有安全审计手段失效&#xff1b…

作者头像 李华
网站建设 2026/10/14 17:03:18

NPU数据流设计:从HBM到Shared Memory的带宽优化实战

做NPU开发这几年,我越来越觉得一个朴素的道理:计算引擎永远在等数据。主频、MAC阵列规模决定了理论算力,但实际跑一个卷积层,吞吐多少往往由数据能不能按时喂到位决定。这个“喂数据”的链路,就是本系列第三章要聊的核…

作者头像 李华