CH341A这颗芯片,在硬件圈子里最出圈的用途就是刷BIOS。无论是老主板救砖、给路由器换固件,还是笔记本刷写,很多人手里都有那么一块蓝色小板子。但我发现一个特别普遍的现象:大家买完CH341A之后,除了插上25系列SPI Flash座子刷个BIOS,剩下的排针和24系列座子基本都在吃灰。其实CH341A本身就是一颗USB总线转接芯片,SPI和I2C功能是它自带的核心能力,刷BIOS只是SPI模式下的一个典型应用。这篇文章我就把它的I2C传感器读写和SPI Flash读写两条线完整走一遍,从原理、接线、软件到常见坑,保证你读完能直接上手。
先说明一下适用人群:手里已经有CH341A编程器但不知道还能干别的、想做传感器数据采集的嵌入式新手、需要批量读写EEPROM或SPI Flash的维修调试党,都合适。如果你完全不熟悉I2C和SPI,也不用担心,我会把这两个协议用大白话讲清楚。
1. 为什么CH341A能做的不止刷BIOS
1.1 它其实是一颗“万能转接器”
先搞清楚CH341A是什么。它是一颗USB总线转接芯片,通过USB连接电脑后,内部可以切换成三种工作模式:UART串口模式、并口模式(EPP/ECP)、以及SPI/I2C主机模式。市面上那些蓝色CH341A编程器小板,本质就是把芯片的引脚引出来,加上25系列SPI Flash座、24系列I2C EEPROM座、部分还有1.8V/3.3V/5V电压选择跳线,方便直接用。
I2C模式下,芯片会提供SCL时钟和SDA数据两根线,外加GND和VCC。SPI模式下,提供CS片选、SCK时钟、MOSI主出从入、MISO主入从出四根线。所以从硬件角度看,这小板子天生就是个I2C主机和SPI主机,可以接几乎所有低速I2C传感器(SHT30、MPU6050、BH1750等)和标准SPI NOR Flash(W25Q系列、MX25系列、GD25系列等)。
很多人没意识到的是,板子上的24系列座子其实就是I2C总线,虽然它名义上是给24C01/24C02这类EEPROM用的,但SDA和SCL两根线是完全标准的I2C信号。所以如果你要接一个I2C传感器,完全可以借用24座上的SDA/SCL/GND/VCC,用杜邦线飞出来,或者直接从排针上取信号。
1.2 为什么“刷BIOS”成了它的代名词
CH341A在中文互联网上被叫成“刷BIOS神器”,是因为绝大多数主板、显卡、路由器的固件芯片用的都是25系列SPI Flash,而CH341A恰好支持SPI主机模式,硬件上可以直接读写这类芯片。加上这块板子便宜、操作简单,软件生态成熟,于是“CH341A=刷BIOS”的印象就被牢牢焊死了。
但这也带来一个副作用:围绕CH341A的大多数教程都在讲怎么备份和写入BIOS文件,I2C功能很少有人系统性讲。我猜原因有两个,第一,I2C方向需要自己找工具和资料,不像刷BIOS那样有大批现成教程;第二,I2C读写需要理解设备地址、寄存器这些概念,门槛比SPI Flash高一点。结果就是一块功能很全的调试板,被大多数人用成了“只会刷BIOS的专用工具”。
其实只要把它的I2C功能用起来,你会发现它完全可以胜任传感器调试、EEPROM批量烧录、I2C设备故障排查这些日常工作,性价比非常高。
1.3 它和树莓派、逻辑分析仪、专业编程器的区别
有读者可能会问:我想调试传感器,为什么不用Arduino或者树莓派?我想抓协议,为什么不用逻辑分析仪?我想烧芯片,为什么不用专业的编程器?这几个工具确实存在功能重叠,但使用场景完全不同。
| 工具 | 核心功能 | 上手难度 | 适合场景 | 价格参考 |
|---|---|---|---|---|
| CH341A编程器 | SPI/I2C读写、低速逻辑分析、串口 | 低 | 维修、调试、小批量烧录 | 十几到几十元 |
| Arduino/ESP32 | 可编程控制、传感器采集 | 中 | 做产品原型、交互控制 | 几十元 |
| 树莓派 | 完整系统、GPIO扩展 | 中高 | 复杂系统、网络化项目 | 几百元 |
| 逻辑分析仪 | 高速协议抓取、时序分析 | 中 | 排查I2C/SPI/UART通信问题 | 几十到上千元 |
| 专业编程器 | 芯片全兼容、高速批量烧录 | 中高 | 工厂烧录、大规模维修 | 几百元起步 |
我的观点是,CH341A不是这些工具里最强的,而是“什么都带一点”的均衡型选手。它最大的优势是便宜、即插即用、软件生态成熟。对嵌入式入门、维修佬、实验室调试来说,它比树莓派简单,比专业编程器便宜,虽然逻辑分析功能比不过专用仪器,但胜在一个工具干多件事。
2. 环境准备:驱动、模式切换和软件工具
2.1 驱动安装:三个平台的差异和坑
Windows下,去WCH官网下载CH341驱动即可。安装完后在设备管理器里能看到CH341设备。有个容易踩的坑:如果你的电脑以前装过非常老的CH341驱动,又插了多个USB转串口设备,可能遇到设备号冲突或者驱动签名问题。这时候建议先把老驱动卸载干净,重启后再装新版。
Linux下就省心很多。内核自带ch341串口驱动,不过注意,flashrom这类工具走的是libusb直接访问方式,反而不依赖内核驱动。也就是说,Linux下一般不需要额外装驱动,插上板子后lsusb能看到设备,flashrom识别出芯片就能干活。如果发行版自带的flashrom没编入ch341a_spi支持,可能需要自己从源码编译一次,这个后面会细说。
macOS下也能用,官方有驱动,但I2C方向的软件支持不如Windows丰富。如果主力机是Mac,我的建议是装个虚拟机或者用一个旧Windows笔记本跑这些工具,省心很多。
2.2 工作模式切换:不用动硬件
CH341A的UART、并口、SPI/I2C模式之间切换,是由软件通过USB控制命令完成的,不需要拨开关、不需要跳线,这也是它方便的地方。比如你用AsProgrammer打开软件,它会自动把芯片切到SPI/I2C模式;你把它当串口用时,串口工具会自动切到UART模式。
但这里有个细节要提醒:CH341A和CH340不是一回事。CH340是单纯的USB转串口芯片,没有SPI/I2C功能;CH341A才是带SPI/I2C的那个。很多人买了CH340模块后问我为什么不能刷BIOS、不能读传感器,就是因为芯片型号不一样,别买错。
2.3 工具链:我平时用这几套
Windows下,我首选AsProgrammer。这软件图形化、体积小、支持CH341A的SPI和I2C,芯片数据库也很全,既能读25系列Flash也能扫I2C总线和读写EEPROM。另外一个老牌工具是ch341eeprom,专门用来读写24系列I2C EEPROM,操作极其简单,适合只想读个EEPROM的场景。
Linux下,SPI Flash读写用flashrom,这个是命令行工具,功能强、支持芯片多。I2C方向没有特别统一的命令行工具,我一般用libusb写Python脚本,或者临时用Windows虚拟机里的AsProgrammer。
如果你想抓I2C时序波形,PulseView(sigrok)支持把CH341A当逻辑分析仪用,采样率不高,但抓个100kHz/400kHz的I2C时序绰绰有余。这个功能特别适合排查“总线忙”“无ACK”这类疑难杂症。
3. 手把手实战:用CH341A读写I2C传感器
3.1 先搞懂I2C的两个底层问题:开漏输出和上拉电阻
I2C协议本身不复杂,SCL提供时钟,SDA传输数据,主设备发起通信,从设备通过地址应答。但有两个概念新手经常栽跟头,一个是开漏输出,一个是上拉电阻。
开漏这个词听着吓人,其实可以这么理解:I2C的SDA和SCL线,所有设备都不能主动输出高电平,只能选择“拉低”或者“释放”。释放之后总线电平由外部上拉电阻拉高。这样做的好处是多个设备可以共享同一根线,同时拉低也不会造成短路。如果改成推挽输出,两个设备一个输出高一个输出低,直接就把总线干废了。
上拉电阻的取值很关键。选太小,低电平时的灌电流太大,设备可能拉不低;选太大,总线电容充电慢,上升沿变缓,通信速率上不去,甚至信号畸变。热词里那个“i2c上拉电阻小了不通信”说的就是这个:上拉电阻过小导致低电平不够低,从设备无法正确识别。
电阻范围可以用两个公式估算。下限是保证低电平能拉到位:Rp_min = (VCC - VOL_max) / IOL_max。以3.3V总线为例,VOL_max按0.4V,IOL_max按3mA算,Rp_min约等于966Ω。上限是保证上升沿够快:Rp_max = t_r / (0.8473 × Cbus)。按100kHz的I2C、上升时间1μs、总线电容100pF算,Rp_max约等于11.8kΩ。所以常见模块上用4.7kΩ很合理,兼顾了速度和功耗。如果线比较长或者设备多,我会换成2.2kΩ;如果只是短距离调试,10kΩ也不是不能用。
3.2 接线:从24座飞线或排针接线
以最常见的SHT30温湿度传感器模块为例。模块一般有四个引脚:VCC、GND、SCL、SDA,板子上通常已经带了4.7kΩ上拉电阻。接线非常简单:
| CH341A板 | SHT30模块 |
|---|---|
| VCC(选3.3V) | VCC |
| GND | GND |
| SCL | SCL |
| SDA | SDA |
操作里有几个原则。第一,先接GND再接VCC,不要带电插拔,模块很便宜,但烧掉也影响排查思路。第二,CH341A板的3.3V是板载LDO转出来的,带一个低功耗传感器没问题,但如果你同时接好几个传感器,建议外部供电,并且把GND和CH341A共地。第三,SDA和SCL不要接反,很多传感器误接反不会马上坏,但会表现为扫描不到地址,浪费时间。
如果是MPU6050这类模块,接线完全一样,只是模块供电一般是3.3V,特别注意别接到VCC 5V档,否则可能直接损坏。
3.3 第一步:扫描I2C地址
I2C设备都有个7位地址,主设备发地址+读写位,从设备匹配后回一个ACK。所以拿到一个新传感器,第一件事就是扫描总线,看它在哪个地址。
在AsProgrammer里,切到I2C模式,选“扫描”或者“Bus Scan”,软件会依次对0x08到0x77之间的地址发探测请求,有ACK的设备会被列出来。如果你用ch341eeprom,界面里也有地址扫描功能。SHT30的默认地址常见是0x44或0x45(由ADDR引脚决定),MPU6050是0x68或0x69。
如果自己写脚本,核心逻辑就是逐个地址发一个字节,能收到ACK就记录。示意代码如下:
# 伪代码:扫描I2C总线上的设备地址 import ch341a_i2c bus = ch341a_i2c.CH341A() for addr in range(0x08, 0x78): try: bus.write_byte(addr, [0x00]) # 发一个字节,等待ACK print(f"找到设备: 0x{addr:02X}") except ch341a_i2c.NACKError: pass注意,不同库的接口不一样,这里展示的是思路。实际使用中,如果你用libusb封装,注意每次扫描前要把总线释放干净,避免上一次通信残留的SDA电平影响结果。
3.4 第二步:读取SHT30温湿度数据
扫描到地址后,就可以真正读数据了。SHT30的读取流程比较典型:先发送测量命令0x24 0x00(周期测量、高重复性),等待约20ms让芯片完成测量,然后连续读6个字节,分别是温度高字节、温度低字节、温度CRC、湿度高字节、湿度低字节、湿度CRC。
温度和湿度的换算公式是:
- 温度 = -45 + 175 × (原始值 / 65535),单位°C
- 湿度 = 100 × (原始值 / 65535),单位%RH
Python示例:
import time import ch341a_i2c bus = ch341a_i2c.CH341A() addr = 0x44 bus.write(addr, [0x24, 0x00]) # 发送测量命令 time.sleep(0.02) data = bus.read(addr, 6) # 读取6字节 raw_t = (data[0] << 8) | data[1] raw_h = (data[3] << 8) | data[4] temp = -45.0 + 175.0 * raw_t / 65535.0 hum = 100.0 * raw_h / 65535.0 print(f"温度: {temp:.2f}°C 湿度: {hum:.2f}%RH")这里有个小技巧:数据里的CRC可以拿来校验通信质量,但如果连续几次读出来的温湿度都合理,CRC偶尔不一致也不用太紧张,大概率是线太长或上拉电阻不合适,优先排查硬件。
MPU6050也是同样的套路。先读0x75寄存器拿WHO_AM_I值,确认地址没错,再读0x3B开始的加速度数据、0x43开始的陀螺仪数据。如果你在Arduino/ESP32上用过MPU6050的DMP库,底层操作的寄存器就是这些,CH341A读出来的原始值和ESP32读出来的一致,可以交叉验证。
3.5 I2C常见故障速查
| 现象 | 可能原因 | 解决思路 |
|---|---|---|
| 扫描不到任何设备 | SDA/SCL接反、上电顺序错、供电不足 | 重查接线,确认先GND后VCC,量模块供电电压 |
| 能扫描到地址但读数据全是0xFF | 传感器未初始化、测量命令没发对 | 确认命令寄存器和时序,等待时间加长 |
| 偶尔读错、CRC老不对 | 线太长、上拉电阻不合适、附近干扰 | 缩短接线,上拉改2.2kΩ,加粗地线 |
| 总线一直处于忙状态 | 设备没释放SDA、上拉电阻缺失 | 确认模块是否自带拉高,必要时外接4.7kΩ |
4. 手把手实战:用CH341A读写SPI Flash
4.1 从BIOS芯片说起:25系列SPI Flash的引脚和命令
SPI Flash的引脚比I2C多,但逻辑也更直白。以最常见的25系列8脚封装为例,标准引脚是:1脚CS#(片选)、2脚DO(数据输出/MISO)、3脚WP#(写保护)、4脚GND、5脚DI(数据输入/MOSI)、6脚CLK(时钟)、7脚HOLD#(保持)、8脚VCC。
CH341A要和Flash通信,本质就是发命令。常用命令有很多,但调试时你只需记住几个核心的:0x9F读JEDEC ID,0x03按地址读数据,0x06写使能,0x02页编程,0x20扇区擦除,0x05读状态寄存器。以W25Q64为例,发送0x9F后会返回三个字节:EF 40 17,EF表示Winbond,40是SPI类型,17表示容量是64Mbit。这就是识别芯片的原理。
为什么CH341A能刷BIOS?因为BIOS芯片就是SPI NOR Flash,CH341A以SPI主机身份发出读ID、擦除、编程命令,本质上和编程器做的事一模一样。只是BIOS刷写脚本把这些命令封装得更“傻瓜化”了。
4.2 离线烧录 vs 板载烧录怎么选
烧SPI Flash有两种方式,离线烧录和板载烧录。
离线烧录是把芯片拆下来放到编程器的25系列座子里,接触可靠、速度稳,适合需要反复擦写或者芯片已经被拆下来的场景。注意芯片1脚要对着座子上的1脚标记,插反轻则识别不到,重则烧芯片。
板载烧录是用SOP8测试夹夹住主板上焊着的Flash,不用拆焊,适合刷BIOS这种场景。但板载烧录有个硬性要求:目标板必须完全断电,最好连电池都拔掉,只留Flash芯片由CH341A供电。如果目标板上还有其他设备挂在SPI总线上,有可能抢总线或者影响电平,识别不到就先把夹子重新夹一遍。
我的建议是:能拆就拆,能不拆就不拆。维修场景下,如果只是读备份,板载夹子够用;但如果是反复调试固件,拆下来放座子里最稳,能少踩很多接触不良的坑。
4.3 用flashrom和AsProgrammer完整读写一遍
Linux下用flashrom比较顺手。先让软件识别芯片:
flashrom -p ch341a_spi如果支持,它会打印Found Winbond flash chip "W25Q64"等信息。然后读取整个芯片内容到文件:
flashrom -p ch341a_spi -r backup.bin备份完想写入新固件:
flashrom -p ch341a_spi -w new.bin注意flashrom的-w操作会自动完成擦除、写入、校验三步,不需要单独执行擦除命令。如果只想清空芯片,可以执行:
flashrom -p ch341a_spi -EWindows下用AsProgrammer的流程也差不多:选择CH341A设备,点“识别”确认芯片型号,然后“读取”保存成bin文件,再“擦除”,打开目标文件,“写入”,“校验”。和flashrom的区别是它把擦除、写入、校验拆成了独立按钮,对新手更直观,但也更容易漏步骤。我在实际使用中,写完后一定会点一次校验,校验不过就绝不认为烧录成功。
4.4 SPI Flash实战避坑清单
第一个坑是容量单位。W25Q64是64Mbit,换算成字节是8MB,不是64MB。新手经常把文件大小和芯片容量搞混,拷入文件时发现装不下,或者写入后校验失败。
第二个坑是WP#和HOLD#引脚。这两个引脚在芯片内部有上拉,但如果你用夹子板载操作,周围电路可能把这些引脚拉低,导致写保护生效或通信挂起。处理办法是:离线座子里一般不用管,默认处理好了;板载夹子操作时,如果写入不稳定,检查这两个引脚是否被板上电路影响。
第三个坑是接触不良。SOP8夹子用久了弹簧老化,夹在芯片上很容易虚接。一个经验是:夹好之后,用万用表通断档分别量夹子另一端的线与芯片对应引脚是否导通,全部通过再上电读取。别嫌麻烦,这能省掉一半的“读出来全是FF”问题。
第四个坑是擦除后写入失败。常见原因是供电不足。CH341A板载LDO电流有限,如果你用的是USB延长线加HUB,电压掉到3V以下,Flash擦写就容易出问题。换一根短线直插电脑USB口,大多数问题能解决。
还有一个必须养成的好习惯:任何写操作之前,先把原芯片完整读出来存成bin文件。一旦刷进去的固件有问题,随时可以用备份恢复。这个习惯救了我不下十次。
5. 把CH341A玩明白的几条硬件经验
5.1 电平选择:3.3V和5V别搞混
CH341A板上常见的电压选择是3.3V和5V两档,I2C传感器和SPI Flash绝大多数是3.3V器件,但也有一些老型号是5V的。接之前一定要查芯片手册,确认供电电压。如果3.3V的芯片接到5V档,轻则冒烟,重则串进下一级电路。反过来,5V的芯片接3.3V供电可能工作不正常,表现为读ID异常、写入后校验失败。
还有一个细节:逻辑电平也要匹配。如果你用CH341A给3.3V的Flash供电,但SPI信号的逻辑电平是跟随VCC的,那没问题;如果给5V芯片供电,但CH341A输出的信号是3.3V,有些5V芯片对高电平门槛要求比较高,可能读不到。碰到这种情况,加个电平转换板是最稳的。
5.2 供电能力有限,别指望它带大负载
CH341A板的3.3V是从USB 5V经过LDO线性稳压来的,电流输出能力有限。带一个SHT30、一个MPU6050这种低功耗模块没问题,但如果你要同时给多个传感器、无线模块、屏幕供电,就不太够用了。这时候的解法是外部电源单独供电,然后把CH341A和外部电源的GND接在一起,保持共地。
对传感器调试来说,供电不稳会导致数据跳变、随机错误。我遇到过一台CH341A接上MPU6050后读出的加速度一直有小幅跳动,排除接线问题后,换成外部3.3V供电立刻稳定了。所以别小看供电质量。
5.3 后续还能怎么玩:逻辑分析、数据采集和课程设计
等I2C和SPI都熟悉了,CH341A还能往几个方向扩展。
第一,当逻辑分析仪用。在PulseView里选择CH341A作为采集设备,可以把SCL/SDA直接接到逻辑分析通道上,实时抓取I2C波形。这对排查“时序到底对不对”“ACK到底回没回”特别有用。虽然采样率赶不上专业逻辑分析仪,但跑100kHz的I2C足够。
第二,配合Python做传感器数据采集。很多开源库实现了libusb直接访问CH341A的I2C/SPI接口,你可以把多个传感器挂到总线上,用一个脚本定时轮询,记录温湿度、加速度、光照等数据。这种玩法特别适合传感器课程设计,比如做一个多传感器环境监测站,CH341A负责数据采集和上传,完全可行。
第三,和一些控制场景联动。比如云台配合倾角传感器和编码器使摄像头随臂架俯仰自动调整角度,这种项目的第一步就是先确认传感器能不能读出正确数据。用CH341A把传感器端调通,再交给单片机做闭环控制,调试效率会高很多。
我自己折腾下来最大的体会是,CH341A的I2C和SPI功能就是一对双胞胎,刷BIOS只是SPI这个方向的冰山一角。很多人遇到I2C传感器读不出数据就急着换设备、换软件,其实问题往往出在上拉电阻、供电电平和接线顺序这些最基础的地方。最后分享一个伴随我很久的习惯:任何芯片,不管是传感器还是Flash,拿到的第一件事永远是先备份原始数据,再动手改。这个习惯能让你在踩坑之后全身而退。
如果这篇文章正好帮你把手头的CH341A盘活了,下次遇到陌生的传感器读不出数据,你还可以回来翻翻这套流程——先扫描地址,再读寄存器,最后分析数据,三步走完,八成问题都已经解决了。