1. 为什么macOS上的串口调试值得单独聊一聊
做嵌入式固件调试的人,手里大概率都备着一根USB转TTL线。插上板子,打开串口工具,看日志、敲命令,这套动作在Windows上大家都很熟。但换到macOS,情况就有点微妙了——系统自带的screen命令能用但难用,minicom配置繁琐,而很多图形化串口工具要么收费、要么在macOS上水土不服。CoolTerm算是这个圈子里口碑比较稳的一个选择,免费、跨平台、功能不花哨但该有的都有。
这篇内容想聊的,就是怎么在macOS上把CoolTerm用明白,尤其是串口日志捕获和日志管理这两件事。很多人用CoolTerm只停留在"能连上、能看到输出"的阶段,但真正做固件调试的时候,你需要的是:长时间抓取不丢数据、日志能自动落盘、关键信息能快速定位、多设备切换不混乱。这些需求,CoolTerm其实都能满足,只是默认配置下不会帮你做到。
适合谁看?如果你正在macOS上调试ESP32、STM32、树莓派、路由器固件,或者任何需要串口输出的嵌入式设备,这篇内容应该能帮你省下不少折腾时间。如果你只是偶尔用串口看一眼启动日志,那前半部分的基础配置也够用了。
我自己的场景比较典型:手头同时挂着两三块开发板,有的在跑RTOS输出任务调度日志,有的在调试Bootloader阶段的启动信息,还有一块路由器板子需要抓完整的启动过程。最开始我也是用screen凑合,后来发现日志没法保存、滚动缓冲区一满就丢数据,才认真把CoolTerm的配置研究了一遍。下面把这些经验整理出来,尽量说清楚每一步为什么这么做。
2. CoolTerm在macOS上的安装与串口识别
2.1 安装方式的选择与理由
CoolTerm的官方发布形式是一个独立的.app包,直接下载dmg拖进Applications就行。它没有上架Mac App Store,也不通过Homebrew Cask分发(至少目前没有官方维护的cask),所以别指望brew install coolterm能搞定。
为什么推荐直接下载官方包而不是找第三方渠道?因为串口工具涉及驱动层面的操作,来源不明的包有被篡改的风险。官方包虽然更新频率不高,但胜在干净。下载地址在Roger Meier的官网上,搜"CoolTerm download"就能找到。
安装本身没什么好说的,拖进去就行。但有一个细节值得注意:首次打开时macOS会拦截,因为它是从互联网下载的未签名应用。你需要在"系统设置→隐私与安全性"里手动允许一次。这个操作只需要做一次,之后就不会再拦了。
2.2 macOS下串口设备的命名规律
这是很多人第一次在macOS上用串口时最容易懵的地方。Windows下你看到的是COM3、COM4,macOS下看到的是一串类似这样的东西:
/dev/tty.usbserial-1420 /dev/tty.usbmodem14101 /dev/cu.usbserial-0001这里有几个关键点需要搞清楚:
tty和cu的区别。tty.开头的设备是"呼叫进入"(call-in)模式,cu.开头的是"呼叫发出"(call-out)模式。对于串口调试这种主动发起的连接,优先用cu.开头的设备。原因是tty.设备在连接时会等待DCD(数据载波检测)信号,某些USB转串口芯片不会拉高这个信号,导致你打开设备后一直卡住。cu.设备则不会等待,打开就能用。
芯片型号决定后缀。常见的USB转串口芯片有几种:
| 芯片型号 | macOS设备名典型格式 | 驱动情况 |
|---|---|---|
| FTDI FT232 | /dev/cu.usbserial-XXXXXXXX | 系统自带驱动,即插即用 |
| Silicon Labs CP2102 | /dev/cu.usbserial-XXXX | 需要安装CP210x驱动 |
| Prolific PL2303 | /dev/cu.usbserial | 老芯片,新macOS可能不兼容 |
| CH340/CH341 | /dev/cu.wchusbserialXXXX | 需要安装WCH驱动 |
| 原生USB CDC | /dev/cu.usbmodemXXXX | 系统自带,常见于ESP32-S2/S3 |
如果你插上板子后在/dev/下找不到对应的设备,八成是驱动没装。CH340和CP2102在Apple Silicon的Mac上需要专门找支持ARM架构的驱动版本,老版本的x86驱动在M系列芯片上跑不起来。
2.3 快速确认设备是否被识别
不用打开CoolTerm,直接在终端里敲:
ls /dev/cu.*插拔板子前后各执行一次,对比多出来的那个设备名,就是你的目标串口。这个方法比在CoolTerm的列表里翻要快得多,尤其是在设备多的时候。
还有一个更直观的办法:
ls /dev/cu.* | xargs -I{} sh -c 'echo "{}";'配合ioreg可以进一步确认设备信息:
ioreg -p IOUSB -l | grep -i "USB Serial"这条命令能看到USB转串口芯片的厂商和产品ID,帮你确认驱动是否正常加载。
注意:如果你用的是USB Hub,某些廉价Hub会导致串口设备识别不稳定,表现为设备时有时无。调试固件时尽量直插Mac的USB口,或者用带独立供电的Hub。
3. CoolTerm连接配置:那些默认值需要改
3.1 波特率不是唯一要设的参数
打开CoolTerm,点"Options",第一页就是串口参数。大多数人只改波特率,但下面这几个参数同样关键:
Data Bits:默认8位,绝大多数固件都是8位,不用改。
Parity:默认None,一般不用改。但如果你调试的是工业设备或者老式通信协议,可能会遇到Even/Odd校验。
Stop Bits:默认1位,偶尔会遇到2位的情况。
Flow Control:这个要重点说。默认是None,但如果你调试的设备支持硬件流控(RTS/CTS),而你又没开,高速传输时可能丢数据。反过来,如果设备不支持流控但你开了,连接可能直接失败。判断方法:先试None,如果大数据量传输时出现乱码或丢包,再试RTS/CTS。
DTR/RTS初始状态:这个藏在Options的"Terminal"或者"Serial"页里。某些开发板(尤其是ESP8266/ESP32系列)会用DTR和RTS信号来控制复位和进入Bootloader模式。如果CoolTerm默认拉高了这两个信号,板子可能一直处于复位状态或者进不了正常运行模式。遇到"连上了但没输出"的情况,先检查这里。
3.2 连接前的自检清单
在点"Connect"之前,我习惯按这个顺序过一遍:
- 设备名选的是
cu.开头而不是tty.开头 - 波特率和目标固件一致(常见:115200、921600、460800)
- Flow Control先设为None
- DTR/RTS如果板子有特殊要求,提前设好
- 终端模式选"Raw"而不是"Line"(Raw模式下每个字符实时传输,Line模式下要等回车才发送)
第5点特别容易忽略。如果你在CoolTerm里敲命令发现没反应,但按了回车之后一下子全出来了,那就是终端模式设成了Line。改成Raw就正常了。
3.3 连接成功后的第一件事
连上之后别急着看日志,先确认通信是双向的。最简单的办法:敲一个回车,看设备有没有回显或者输出提示符。如果设备固件支持命令行,敲个help或者?试试。
如果只有输出没有输入响应,检查两个地方:一是终端模式是不是Raw,二是本地回显(Local Echo)有没有开。CoolTerm的本地回显在"Connection→Terminal"里,开了之后你敲的字符会显示在屏幕上,方便确认输入是否被接收。
4. 日志捕获的核心配置:让每一行输出都落盘
4.1 为什么默认的日志保存不够用
CoolTerm有一个"Capture to Textfile"功能,在Connection菜单里。点一下就开始把收到的数据写入文件,再点一下停止。听起来很简单对吧?但默认配置有几个坑:
坑一:文件覆盖而非追加。默认情况下,每次开始捕获会覆盖同名文件。如果你调试一个需要反复重启的设备,每次重启都重新捕获,之前的日志就没了。
坑二:没有时间戳。默认捕获的是纯数据,没有时间信息。调试时序相关的问题时,你不知道两条日志之间隔了多久。
坑三:缓冲区溢出丢数据。CoolTerm的显示缓冲区是有限的,如果你只看屏幕不落盘,高速输出时超出缓冲区的内容就丢了。捕获到文件可以避免这个问题,但前提是捕获功能得配对。
4.2 正确的日志捕获配置步骤
在Options里找到"Capture"或者"Logging"相关的设置页(不同版本位置略有差异),按以下配置:
文件名模板:CoolTerm支持在文件名里插入时间变量。比如设成log_%Y%m%d_%H%M%S.txt,每次捕获都会生成一个带时间戳的新文件,不会互相覆盖。
追加模式:如果希望同一个会话的多次捕获写到同一个文件,开启"Append"选项。但更推荐用时间戳文件名,每次都是新文件,管理起来更清晰。
时间戳前缀:开启"Add timestamp"选项,CoolTerm会在每行数据前面加上接收时间。格式可以自定义,我一般用[HH:mm:ss.zzz],精确到毫秒。调试通信协议时序问题时,这个精度够用了。
自动开始捕获:在"Startup"设置里,可以配置连接建立后自动开始捕获。这样你就不用每次手动点一下,尤其适合需要反复重启设备的调试场景。
配置好之后,每次连接CoolTerm就会自动把串口数据写入带时间戳的日志文件。文件默认保存在CoolTerm的应用支持目录下,你也可以指定一个固定的日志目录,比如~/Documents/serial_logs/。
4.3 高速输出场景下的参数调优
调试某些固件时,串口输出速度非常快,比如ESP32在启动阶段会以921600的波特率吐出大量信息。这种情况下,默认配置可能跟不上。
提高接收缓冲区:CoolTerm的串口接收缓冲区大小可以在Options里调整。默认值偏保守,高速场景下建议调到最大。
关闭屏幕显示:如果只是抓日志不需要实时看,可以关闭终端显示(或者把窗口最小化)。屏幕渲染会消耗CPU时间,关闭后CoolTerm能把更多资源用于接收和写文件。
降低波特率:如果固件允许,把波特率从921600降到460800甚至115200。虽然传输慢了,但丢数据的概率大大降低。调试阶段稳定性比速度重要。
使用硬件流控:如果设备和线缆都支持RTS/CTS,开启流控能有效防止缓冲区溢出。这是最可靠的防丢数据手段。
实操心得:我曾经调试一块STM32板子,Bootloader阶段输出特别快,用默认配置抓十次有三次会丢开头几行。后来把波特率从921600降到115200,同时开启RTS/CTS流控,连续抓了二十次都没再丢过。调试阶段,稳定压倒一切。
5. 日志文件的管理与快速定位技巧
5.1 目录结构设计
日志文件一多,找起来就头疼。我建议按项目分目录:
~/Documents/serial_logs/ ├── project_a_esp32/ │ ├── 20250115_093012_boot.txt │ ├── 20250115_094530_runtime.txt │ └── 20250115_101200_crash.txt ├── project_b_stm32/ │ └── ... └── project_c_router/ └── ...CoolTerm的文件名模板里可以包含路径,所以你可以为每个项目单独配置一个日志目录。切换项目时改一下Options里的路径就行。
5.2 用命令行快速筛选日志
日志文件是纯文本,这意味着你可以用macOS自带的命令行工具做各种筛选。以下是我常用的几个:
查找关键字:
grep -n "ERROR\|WARN\|assert" 20250115_093012_boot.txt-n显示行号,方便定位。
查看某个时间段:
awk '/09:30:15/,/09:30:20/' 20250115_093012_boot.txt如果日志带了时间戳前缀,这条命令能提取出指定时间段的输出。
统计错误出现次数:
grep -c "ERROR" 20250115_093012_boot.txt实时监控最新日志:
tail -f ~/Documents/serial_logs/project_a_esp32/$(ls -t ~/Documents/serial_logs/project_a_esp32/ | head -1)这条命令会自动打开最新生成的日志文件并实时跟踪,相当于在终端里看串口输出,但数据同时也在落盘。
5.3 日志轮转与清理
调试频繁的时候,一天能产生几十个日志文件。如果不清理,磁盘空间很快就被占满。我一般用两种方式管理:
按时间清理:每周清理一次超过两周的日志。
find ~/Documents/serial_logs -name "*.txt" -mtime +14 -delete按大小清理:单个文件超过一定大小就归档或删除。不过串口日志一般不会太大,除非你连续抓了好几天。
归档重要日志:调试出关键问题的那次日志,单独复制出来放到一个important/目录里,加上备注。比如20250115_crash_after_30min_runtime.txt,文件名本身就说明了问题。
6. 多设备切换与自动化连接
6.1 保存多个连接配置
CoolTerm支持保存连接配置。在Options里配置好一组参数后,点"File→Save As"保存成一个.cts文件。下次要用的时候直接打开这个文件,所有参数都恢复。
我的做法是给每个常用设备存一个.cts文件,命名清晰:
esp32_devkit_115200.ctsstm32_bootloader_921600.ctsrouter_console_57600.cts
放在一个固定目录里,需要连哪个设备就双击对应的.cts文件。CoolTerm会自动打开并加载配置,你只需要点一下Connect。
6.2 用脚本实现一键连接
如果你经常需要在命令行和CoolTerm之间切换,可以写一个简单的shell脚本来启动CoolTerm并加载指定配置:
#!/bin/bash # open_serial.sh CONFIG_DIR="$HOME/Documents/coolterm_configs" open -a CoolTerm "$CONFIG_DIR/$1.cts"用法:./open_serial.sh esp32_devkit_115200
这个脚本用open -a命令启动CoolTerm并传入配置文件路径。CoolTerm会自动加载配置,你只需要点Connect。
6.3 多窗口同时监控
CoolTerm支持同时打开多个窗口,每个窗口连接不同的串口。这在调试多设备通信时特别有用,比如一块板子发数据、另一块收数据,两个窗口并排看,时序关系一目了然。
窗口布局可以用macOS的分屏功能来管理。我一般左边放发送端的日志,右边放接收端的日志,两边都开了时间戳,对比起来很方便。
注意:同时开多个CoolTerm窗口时,每个窗口的日志捕获要配置不同的文件名模板,否则会互相覆盖。建议在文件名里加上设备标识,比如
esp32_%Y%m%d_%H%M%S.txt和stm32_%Y%m%d_%H%M%S.txt。
7. 常见问题排查与踩坑记录
7.1 连上了但没有任何输出
这是最常见的问题,可能的原因按概率排序:
波特率不对。这是头号原因。固件用的是115200,你设了9600,看到的全是乱码或者什么都没有。确认固件实际的波特率,或者挨个试常见的几个值。
DTR/RTS信号导致板子复位。某些板子的串口电路设计使得DTR/RTS拉低会触发复位。CoolTerm默认可能拉高了这两个信号,导致板子一直处于复位状态。在Options里把DTR和RTS都设为"Low"或者"Disable"试试。
TX/RX接反了。USB转TTL线的TX要接板子的RX,RX接板子的TX。接反了就是没输出。这个错误新手常犯,检查一下杜邦线的连接。
板子没供电。有些USB转TTL线只提供数据不提供电源,板子需要单独供电。确认板子的电源指示灯亮了。
串口被其他程序占用。macOS下同一个串口设备不能被两个程序同时打开。如果你之前用screen连过没退出,CoolTerm就连不上。用lsof | grep cu.usbserial查一下有没有进程占用。
7.2 日志中出现乱码
乱码通常有三种情况:
波特率不匹配:乱码是持续性的,从头到尾都乱。调对波特率就好。
数据位/校验位不匹配:乱码可能间歇性出现,或者只在特定字符上出现。检查Data Bits和Parity设置。
流控问题:如果乱码出现在大量数据传输时,而小数据量时正常,很可能是流控没配对导致缓冲区溢出。开启RTS/CTS试试。
还有一种特殊情况:某些固件在启动阶段会临时切换波特率。比如Bootloader阶段用9600,进入应用后切到115200。这种情况下你需要在CoolTerm里手动切换波特率,或者用两个窗口分别抓两个阶段。
7.3 长时间捕获导致CoolTerm卡顿
连续捕获几个小时甚至几天后,CoolTerm的界面可能变得很卡。原因是显示缓冲区积累了太多数据。
解决方法:定期清空显示缓冲区(View→Clear Buffer),或者干脆关闭显示只保留文件捕获。CoolTerm的"Capture"功能是独立于显示的,关掉显示不影响文件写入。
如果捕获的文件特别大(几百MB),打开和搜索都会很慢。建议按时间段分割日志文件,比如每小时自动换一个文件。CoolTerm的文件名模板支持时间变量,配合自动捕获功能可以实现按时间分文件。
7.4 Apple Silicon Mac上的兼容性问题
M系列芯片的Mac在运行某些串口驱动时可能遇到问题。主要表现为设备识别不稳定或者传输过程中断连。
CH340驱动:需要找支持ARM64的版本。WCH官网有提供,但更新不太及时。如果官方驱动有问题,可以试试社区维护的版本。
CP210x驱动:Silicon Labs的驱动对Apple Silicon支持较好,但需要macOS 11以上。如果你还在用Big Sur之前的系统,可能需要升级。
FTDI芯片:系统自带驱动,Apple Silicon上表现最稳定。如果经常遇到驱动问题,建议优先选用FTDI芯片的USB转TTL线。
Rosetta模式:CoolTerm本身是Universal Binary,原生支持Apple Silicon,不需要Rosetta。但如果你用的某些串口驱动是x86的,可能需要通过Rosetta运行,稳定性和性能都会打折扣。
8. 把CoolTerm融入日常调试工作流
8.1 与版本控制配合
日志文件一般不建议提交到Git仓库,但关键的崩溃日志和异常日志值得保存下来,作为问题追踪的依据。我的做法是在项目仓库里建一个debug_logs/目录,把重要的日志文件复制进去,文件名加上简短的描述,比如20250115_esp32_wifi_init_timeout.txt。然后在提交信息里引用这个文件名,方便回溯。
8.2 与固件版本关联
每次烧录新固件后,第一次串口输出的日志建议单独保存,并在文件名里标注固件版本。比如fw_v1.2.3_boot_log.txt。这样当出现问题时,你可以快速对比不同固件版本的启动日志差异。
8.3 建立自己的日志分析命令集
调试久了,你会发现某些筛选命令反复用到。把它们写成shell函数或者alias,放在.zshrc里:
# 查找日志中的错误和警告 alias logerr='grep -n "ERROR\|WARN\|FAULT\|assert"' # 查看最新日志文件 alias latestlog='ls -t ~/Documents/serial_logs/**/*.txt | head -1' # 实时跟踪最新日志 alias taillog='tail -f $(latestlog)'这样在终端里敲logerr somefile.txt就能快速筛选错误信息,敲taillog就能实时看最新日志。
8.4 一个实际调试案例的完整流程
最后分享一个我最近调试ESP32 WiFi连接问题的完整流程,把上面说的这些串起来:
- 板子通过USB转TTL连接Mac,
ls /dev/cu.*确认设备名为cu.usbserial-1420 - 打开CoolTerm,加载之前保存的
esp32_devkit_115200.cts配置 - 确认波特率115200、Flow Control为None、DTR/RTS为默认
- 点击Connect,看到启动日志正常输出
- 在Options里开启自动捕获,文件名模板设为
esp32_wifi_%Y%m%d_%H%M%S.txt,开启毫秒级时间戳 - 复位板子,观察WiFi连接过程,发现连接超时后反复重试
- 断开连接,在终端里用
grep -n "wifi\|WiFi\|connect" esp32_wifi_20250115_143022.txt筛选相关日志 - 发现每次重试间隔约5秒,超时时间设置为10秒,但实际连接在8秒左右成功,只是判断逻辑有问题
- 修改固件中的超时判断逻辑,重新烧录
- 再次捕获日志,确认连接稳定,保存这次成功的日志作为参考
整个过程从发现问题到定位根因,大概花了二十分钟,其中大部分时间是在看日志和改代码。CoolTerm的自动捕获和时间戳功能让日志分析变得很高效,不用手动记录时间点,直接按时间戳筛选就行。
这套流程跑顺了之后,串口调试就不再是"看一眼输出"这么粗糙的操作,而是有一套完整的记录、筛选、对比、归档的方法。固件调试本身就是个细致活,工具用顺手了,能把更多精力放在真正的问题上。