当前位置: 首页 > news >正文

嵌入式面试题:CAN 与 I2C 核心对比(含优缺点,实操视角)

核心结论:CAN 偏工业 / 车载 “远距离、抗干扰、多电机” 场景,I2C 偏板级 “近距离、多传感器、低成本” 场景,差异全在适配性,优缺点互为补充。

对比维度CAN(控制器局域网)I2C(内部集成电路)
核心定位工业 / 车载级多设备总线,主打可靠与实时性板级近距离总线,主打简洁与低成本
身份标识帧内 ID 字段(动态贴标签,收发均需手动设 ID)设备自带从机地址(固定地址 + 引脚可调,主机喊地址匹配)
总线结构2 根线(CAN_H/CAN_L,差分信号)+ 两端 120Ω 终端电阻2 根线(SDA 数据线 / SCL 时钟线),无需终端电阻
通信距离 & 速率距离远(最长 10km@5kbps),速率中等(最高 1Mbps)距离近(最长 10m@100kbps),速率中等(最高 400kbps 高速模式)
抗干扰能力强(差分信号,适配电机、车载等强电磁干扰环境)弱(单端信号,易受板内布线干扰,仅适合板级短距离)
多设备支持支持 110+ 节点,无地址冲突(ID 可灵活分配)支持 10+ 节点(受地址位限制,多设备需调地址防冲突)
实时性 & 容错高(优先级传输 + 自动错误重发,紧急数据先传)低(主机主导时钟,无优先级,冲突后需重新通信)
代码复杂度较高(需配置波特率、滤波、ID,处理帧结构)极低(仅需指定从机地址,API 简洁,无需复杂协议处理)
硬件成本中高(需 CAN 收发器如 TJA1050,终端电阻)极低(无需额外芯片,MCU 自带 I2C 外设直接接线)
典型场景电机控制、车载电子、工业机械臂、远距离传感器网络板载传感器(温湿度、陀螺仪)、OLED 屏、EEPROM、芯片间通信

一、CAN 优缺点

优点:

  1. 抗干扰极强:差分信号设计,能在电机、汽车等强电磁环境下稳定传输,几乎不会丢包;
  2. 远距离 + 多节点:支持千米级传输,可挂百个设备,适合多电机、分布式控制;
  3. 实时容错:支持数据优先级(比如电机过载报警比转速指令先传),自动检测错误并重发,避免失控;
  4. 无地址冲突:ID 可灵活分配,新增设备只需设新 ID,不用改现有设备配置。

缺点:

  1. 硬件复杂:需额外加 CAN 收发器和终端电阻,布线要注意差分线匹配;
  2. 代码繁琐:要配置帧头、滤波、ID,协议层处理比 I2C 多;
  3. 成本较高:收发器 + 电阻增加硬件成本,不适合低成本小项目。

二、I2C 优缺点

优点:

  1. 极简易用:仅 2 根线,无需额外硬件,MCU 直接接线,代码只需调用地址 + 收发 API;
  2. 低成本:无额外芯片成本,布线简单,适合板内多传感器密集布局;
  3. 地址灵活:部分设备可通过 ADDR 引脚调地址,解决多设备冲突问题;
  4. 适配小数据:单次传 1-8 字节,完美匹配传感器(温湿度、光照)等小数据场景。

缺点:

  1. 抗干扰差:单端信号,板内布线过长或靠近电机、电源会丢包;
  2. 距离受限:仅适合板级(比如一块 PCB 上的多个芯片),超过 10cm 信号就不稳定;
  3. 实时性弱:主机控制时钟,所有设备按时钟同步,无紧急数据优先级;
  4. 节点有限:7 位地址仅支持 127 个设备,实际中多设备易冲突,且无错误重发机制。

简单总结:

  • 若做「车载 / 工业多电机、远距离控制」:选 CAN,牺牲一点复杂度换可靠性;
  • 若做「电路板上多传感器(如温湿度、OLED)」:选 I2C,用极简方案省成本。


CAN 总线必须用 120 欧终端电阻,核心是匹配 CAN 双绞线特征阻抗并适配协议特性,既符合国际标准,又能解决信号传输中的多个关键问题,具体原因如下:

  1. 匹配阻抗,消除信号反射:CAN 总线常用的双绞线特征阻抗恰好是 120 欧。高速传输时信号到总线两端会因阻抗突变反射,反射波与原信号叠加会产生振铃、过冲,导致信号失真。120 欧终端电阻能吸收这部分反射能量,让信号波形规整,这也是其最核心作用,且 ISO11898 国际标准也明确规定该阻值。
  2. 加速总线状态切换:CAN 总线有显性和隐性两种状态,显性状态下总线寄生电容会充电。若没有终端电阻,电容只能通过收发器内部高阻电路放电,放电慢会导致总线无法快速切换到隐性状态,影响通信速率。120 欧电阻能提供低阻放电通道,让电容快速释放能量,保障高低速通信时状态切换的及时性。
  3. 提升隐性状态抗干扰能力:隐性状态下 CAN 收发器处于高阻态,极小的干扰能量就可能让总线误触发为显性状态。120 欧终端电阻作为差分负载,可给干扰信号提供泄放路径,吸收高频噪声能量,避免干扰伪造显性信号,大幅降低外界干扰对总线通信的影响。


分别提供 CAN 通信(STM32 控制电机) 和 I2C 通信(STM32 读取温湿度传感器) 的极简示例代码,基于 STM32 HAL 库,可直接参考移植。

一、CAN 通信示例(控制带 CAN 接口的电机驱动器)

功能:STM32 通过 CAN 总线给电机发送转速指令,并接收电机反馈的实际转速
#include "stm32f1xx_hal.h"// CAN句柄及帧结构
CAN_HandleTypeDef hcan;
CAN_TxHeaderTypeDef tx_header;  // 发送帧头(含ID)
CAN_RxHeaderTypeDef rx_header;  // 接收帧头(含ID)
uint8_t tx_buf[8];              // 发送数据缓存
uint8_t rx_buf[8];              // 接收数据缓存
uint32_t tx_mailbox;            // 发送邮箱// 1. CAN初始化(波特率500Kbps,匹配工业常用标准)
void CAN_Init(void) {hcan.Instance = CAN1;hcan.Init.Prescaler = 6;                  // 波特率=36MHz/(6*(1+11+4))=500Kbpshcan.Init.Mode = CAN_MODE_NORMAL;         // 正常收发模式hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;hcan.Init.TimeSeg1 = CAN_BS1_11TQ;hcan.Init.TimeSeg2 = CAN_BS2_4TQ;hcan.Init.AutoBusOff = ENABLE;            // 自动恢复总线HAL_CAN_Init(&hcan);// 配置滤波器(只接收电机反馈ID=0x201的数据)CAN_FilterTypeDef filter;filter.FilterBank = 0;filter.FilterMode = CAN_FILTERMODE_IDMASK;filter.FilterScale = CAN_FILTERSCALE_32BIT;filter.FilterIdHigh = 0x201 << 5;         // 目标ID=0x201(左移5位适配32位格式)filter.FilterMaskIdHigh = 0x7FF << 5;     // 掩码:只匹配ID=0x201的帧filter.FilterFIFOAssignment = CAN_RX_FIFO0;filter.FilterActivation = ENABLE;HAL_CAN_ConfigFilter(&hcan, &filter);HAL_CAN_Start(&hcan);                     // 启动CANHAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);  // 使能接收中断
}// 2. 发送电机转速指令(目标ID=0x101,数据格式:前2字节为转速值)
void CAN_SendSpeedCmd(uint16_t speed) {tx_header.StdId = 0x101;       // 电机驱动器接收ID(收件人身份)tx_header.RTR = CAN_RTR_DATA;  // 数据帧tx_header.IDE = CAN_ID_STD;    // 标准11位IDtx_header.DLC = 2;             // 数据长度2字节tx_buf[0] = (speed >> 8) & 0xFF;  // 转速高8位tx_buf[1] = speed & 0xFF;         // 转速低8位HAL_CAN_AddTxMessage(&hcan, &tx_header, tx_buf, &tx_mailbox);  // 发送
}// 3. 接收中断:解析电机反馈的实际转速(ID=0x201)
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header, rx_buf);if (rx_header.StdId == 0x201) {  // 确认是电机反馈ID(发件人身份)uint16_t actual_speed = (rx_buf[0] << 8) | rx_buf[1];  // 解析转速// 可通过串口打印调试:printf("实际转速:%d RPM\r\n", actual_speed);}
}// 主函数调用
int main(void) {HAL_Init();SystemClock_Config();  // 系统时钟初始化(需自行实现)CAN_Init();            // 初始化CANwhile (1) {CAN_SendSpeedCmd(1500);  // 发送转速指令(1500 RPM)HAL_Delay(1000);         // 每秒发送一次}
}

二、I2C 通信示例(读取 AHT20 温湿度传感器)

功能:STM32 通过 I2C 读取 AHT20 的温度和湿度数据(传感器从机地址固定为 0x38)
#include "stm32f1xx_hal.h"// I2C句柄
I2C_HandleTypeDef hi2c1;// 1. I2C初始化(速率100Kbps,标准模式)
void I2C_Init(void) {hi2c1.Instance = I2C1;hi2c1.Init.ClockSpeed = 100000;         // 100Kbpshi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;hi2c1.Init.OwnAddress1 = 0;             // 主机模式,无需自身地址hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;  // 7位地址hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;HAL_I2C_Init(&hi2c1);
}// 2. 读取AHT20温湿度数据(从机地址0x38)
void AHT20_ReadData(float *temp, float *humi) {uint8_t cmd[3] = {0xAC, 0x33, 0x00};  // 读取数据指令uint8_t data[6];                      // 接收传感器返回的6字节数据// 步骤1:发送读取指令(地址0x38,写操作)HAL_I2C_Master_Transmit(&hi2c1, 0x38 << 1, cmd, 3, 100);HAL_Delay(80);  // 等待传感器采样完成// 步骤2:接收返回数据(地址0x38,读操作:0x38<<1 | 0x01)HAL_I2C_Master_Receive(&hi2c1, (0x38 << 1) | 0x01, data, 6, 100);// 步骤3:解析数据(按AHT20手册公式计算)uint32_t humi_raw = ((uint32_t)data[1] << 12) | ((uint32_t)data[2] << 4) | (data[3] >> 4);uint32_t temp_raw = ((uint32_t)(data[3] & 0x0F) << 16) | ((uint32_t)data[4] << 8) | data[5];*humi = (humi_raw * 100.0f) / (1 << 20);  // 湿度:0~100%*temp = (temp_raw * 200.0f) / (1 << 20) - 50;  // 温度:-50~150℃
}// 主函数调用
int main(void) {HAL_Init();SystemClock_Config();  // 系统时钟初始化(需自行实现)I2C_Init();            // 初始化I2Cfloat temperature, humidity;while (1) {AHT20_ReadData(&temperature, &humidity);// 可通过串口打印:printf("温度:%.1f℃  湿度:%.1f%%\r\n", temperature, humidity);HAL_Delay(2000);  // 每2秒读一次}
}

核心差异对比(代码层面)

特性CAN 代码特点I2C 代码特点
身份配置需手动设置StdId(收发均需指定 ID)只需指定从机地址(如0x38 << 1
硬件依赖需初始化 CAN 收发器(TJA1050)和终端电阻直接用 MCU 的 I2C 引脚,无需额外硬件
数据处理需解析帧头 ID,支持多设备区分地址匹配后直接收发,无需处理帧结构
典型 APIHAL_CAN_AddTxMessage/ 中断回调HAL_I2C_Master_Transmit/Receive
http://www.dtcms.com/a/618989.html

相关文章:

  • 商河县做网站公司网络营销师资格证有什么用
  • 揭阳市住房和城乡建设局官方网站一天必赚100元的游戏
  • Python 常用库
  • 【 Java八股文面试 | Java集合 】
  • 青岛网站优化公司哪家好建网站 找个人
  • 网站建设售后服务网站推广排名
  • 线程控制块 (TCB) 与线程内核栈的内存布局关系
  • 现在最常用网站开发工具建设公司网站开发方案
  • 长春专业做网站公司排名discuz集成wordpress
  • 独立开发者的本质
  • 从“高密度占有”到“点状渗透”:论“开源AI智能名片链动2+1模式”在S2B2C商城小程序中的渠道革新
  • Goer-Docker系列-1-容器编排实操
  • 4.1 Agent开发热潮!基于LLM构建智能代理系统,未来人机交互的新范式
  • 设计模式实战篇(七):适配器模式 —— 让“不兼容的接口”优雅合作的万能转换器
  • 【Java 基础】5 面向对象 - 实体类
  • 波哥昆明网站建设平面设计的素材网站
  • 外贸网站推广收费自己做个网站好还是做别人会员好
  • MySQL---C/C++链接
  • 怎么进入微信官方网站汉字logo标志设计
  • 深入理解 Java Stream 流:函数式编程的优雅实践(全面进阶版)
  • 高端网站制作报价网站怎么做搜索
  • CSS Fonts(字体)
  • 莱芜手机网站设计公司网站上传到空间
  • skywalking整合logback.xml日志,日志文件出现乱码问题解决
  • 网站建设栏目添加收费电影网站怎么做
  • 【LwIP源码学习8】netbuf源码分析
  • 蓝牙EIR数据
  • 外企网站建设中国庆阳网
  • nfs共享服务
  • vue2[webpack]中接入vue3[vite]的qiankun微前端服务