前阵子做一个小工具,要用HC05蓝牙模块和电脑串口通信,结果在PyCharm里第一步就栽在了装pyserial上。这个库看着简单,网上一搜教程满天飞,可真照着操作下来,各种报错照样能把人绕晕:“pip不是内部或外部命令”“Permission denied”“No module named 'serial'”……我索性把整个安装过程重新捋了一遍,把踩过的坑和验证过的方法都记录下来,写成了这篇东西。
pyserial是Python操作串口的事实标准库,包名叫pyserial,可代码里导入时却写import serial。一个名字搞两套,很多人第一次就懵了。这篇文章适合刚学Python串口通信、准备接HC05蓝牙模块、L298N电机驱动这些硬件的外包开发者,也适合在PyCharm里装第三方包经常莫名其妙报错的人。看完你不仅能装好pyserial,还能学会一套排查Python包安装问题的通用思路。
1. 先把pyserial这件事看明白再动手
1.1 pyserial到底是个啥:包名和模块名为何不一样
pyserial是一个第三方Python库,专门用来和电脑上的串口(Windows里叫COM口,Linux里叫tty设备)交流数据。几乎所有用Python做嵌入式开发、硬件调试的人都绕不开它。它的功能说白了就是三件事:打开串口、往串口发数据、从串口读数据。
但这里有个特别容易让人犯迷糊的点:PyPI上的安装包名字是pyserial,写代码时导入的模块名却是serial。所以你看网上的教程,安装命令是pip install pyserial,可代码第一行永远都是import serial。如果你哪天看到有文章写“import pyserial”,那基本可以断定作者没真正跑过代码。还有一些老资料会提到serial这个包名,其实PyPI上也有一个叫serial的第三方包,但它和pyserial完全是两回事,千万别搞混,否则你装了一堆依赖,代码照样跑不起来。
pyserial本身的优点是跨平台,Windows、Linux、macOS都能用,而且同时支持Python 2和Python 3,依赖极少,整个安装包也就几百KB。按道理说这种轻量级库不应该装出问题,但实际操作里大家还是经常翻车,原因绝大多数都不在pyserial本身,而是环境配置有问题。所以我一直觉得,解决安装报错的第一步不是反复重装库,而是先把自己的Python环境看清楚。
1.2 安装前必须确认的三样东西
无论你打算用哪种方法安装,动手前都建议先确认下面三件事,能省掉后面一大堆排查时间。
第一,当前项目用的Python解释器是谁。打开PyCharm,看右下角状态栏,那里会显示当前解释器的名字和路径。如果你有多个Python版本,比如系统里同时装了Python 3.9、3.11,还装了Anaconda,那就必须搞清楚PyCharm现在用的到底是哪一个。因为pip install装到的是当前终端激活的那个Python,不一定就是你代码运行用的那个Python。
第二,项目有没有创建虚拟环境。PyCharm新建项目时默认会创建venv虚拟环境,如果你一路点“Next”没注意,项目就会带着一个venv目录。打开PyCharm底部的Terminal,如果命令行前面有(venv)几个字,说明终端已经自动激活了虚拟环境,此时pip安装的所有包都会进入这个虚拟环境,不会污染系统Python。这是最理想的状态。如果命令行前面啥都没有,说明终端使用的是全局Python,包会装到系统目录。
第三,pip版本和网络源是否正常。执行python -m pip --version可以查看pip版本和它对应的Python路径,如果这条命令能正常打印出版本号,说明Python和pip基本没问题。至于网络源,国内默认源是pypi.org,经常抽风,下文会细说怎么换镜像源。
1.3 为什么明明是“装库”,却经常要查环境
很多人在网上搜“pycharm安装教程”,跟着做了半天,最后还是装不上pyserial,就开始怀疑是不是PyCharm这个软件有问题。其实真不怪PyCharm,PyCharm只是一个编辑器加项目管理工具,它本身不负责管理Python包,包管理是pip和Python解释器的事。
问题往往出在解释器配置不一致上。举个例子,你在PyCharm的Settings里看到Python Interpreter指向A环境的Python,但打开Terminal时,命令行实际用的却是B环境的Python。这俩如果不一致,你就可能遇到“图形界面里看包已经装上了,代码一运行照样No module found”的诡异现象。另外,PyCharm新版界面和旧版不一样,2020年之后的版本Settings入口和Package对话框都改过,网上搜到的教程如果截图很老,对不上号也很正常,不影响本质思路。
所以在进入安装环节之前,我建议大家先把“当前解释器是谁”“有没有虚拟环境”“pip归谁管”这三个问题搞清楚。这三句话搞明白,后面无论装什么包,成功率都会高一大截。
2. PyCharm中安装pyserial的3种高效方法
2.1 方法一:用PyCharm的Terminal跑pip命令
这是我最推荐的方式,也适合绝大多数场景,因为你能看到完整日志,遇到错误可以直接看到原因。
操作步骤很简单:
- 打开PyCharm,在当前项目里点击底部Tool Windows里的Terminal,或者通过菜单View切换出来。
- 确认命令行前面有(venv)前缀。如果没有,用cd命令进入项目根目录,然后手动激活虚拟环境。Windows下执行venv\Scripts\activate,macOS或Linux下执行source venv/bin/activate。
- 执行安装命令:
pip install pyserial- 如果网络很慢,或者反复超时,就加上国内镜像源:
pip install pyserial -i https://pypi.tuna.tsinghua.edu.cn/simple安装成功后,最后几行会显示Successfully installed pyserial-3.5,看到这个就说明已经装好了。
这里我想多说一句关于python -m pip install和pip install的区别。当系统里存在多个Python版本时,直接用pip这个命令,调用的可能是你最先装的那个Python的pip,这不一定是你需要的。而python -m pip install pyserial会强制使用当前命令行里Python对应的pip,更稳妥。在PyCharm的Terminal里,只要虚拟环境激活正确,python和pip就都是虚拟环境里的,用哪个都行;但出了PyCharm自己开终端的时候,这个细节特别重要。
另外,如果你发现pip版本太老,可以先升级pip再装库:
python -m pip install --upgrade pip老版本pip在解析一些新包的元数据时会出问题,偶尔会出现明明包存在,但它说找不到版本的情况。
2.2 方法二:在Python Interpreter里图形化安装
不习惯命令行的朋友,可以用PyCharm自带的图形化安装界面,这种方式的好处是能直观看到当前解释器路径,不容易装错环境。
具体步骤:
- 打开PyCharm,点击菜单File,下拉里选择Settings(macOS上是在PyCharm菜单里找Preferences)。
- 左侧栏展开Project:你的项目名,找到Python Interpreter。
- 右侧顶部会显示当前解释器的完整路径,先确认这里选中的是你项目实际使用的解释器。
- 点击路径右侧的+号按钮,弹出Available Packages搜索窗口。
- 在搜索框输入pyserial,下方列表过滤出这个包。
- 点击左下角Install Package按钮。
安装过程中左下角有进度条,如果一直停在进度条,通常是网络问题,等一会儿或者换成国内源。换源的方法是点击左下角Manage Repositories,先把默认的官方源地址解绑,再添加清华源或阿里源,保存后重新搜索安装即可。
这个方法对新手特别友好,因为它把解释器路径明明白白写在了界面上,你能确认包到底装到了哪个环境里。不过它的缺点是,一旦安装失败,提示往往比较笼统,只弹出一个Install failed,具体原因还得去日志里翻。所以如果图形化安装失败,我还是建议回到Terminal里执行pip install,看看完整报错。
2.3 方法三:离线whl文件安装
如果你所在的电脑完全不联网,或者处于内网办公环境,那离线安装就是救命方案。提前在一台联网电脑上把whl文件下载好,拷贝过去就能装。
步骤:
- 在一台能联网的电脑上,打开浏览器访问pypi.org,搜索pyserial,找到Files列表,下载这个文件:pyserial-3.5-py2.py3-none-any.whl。
- 把这个whl文件用U盘或者内部传输工具拷贝到目标电脑。
- 在PyCharm的Terminal里,执行本地安装命令:
pip install D:\downloads\pyserial-3.5-py2.py3-none-any.whlLinux或macOS就把路径换成对应的绝对路径或相对路径。
这里有个通用知识点值得记一下:whl文件名里的py2.py3-none-any是平台标签,意思是对Python 2和Python 3都兼容,且不依赖特定操作系统,任何平台都能装,所以pyserial的whl文件去哪里都通用。但以后如果你要离线安装pandas、numpy这类带C扩展的库,文件名里会有类似cp39-cp39-win_amd64这样的标记,必须和目标机器的Python版本、操作系统版本严格匹配,不能随手拿一个就能装。pyserial是纯Python包,才敢这么随便。
离线安装完同样会提示Successfully installed,之后想卸载也很简单,pip uninstall pyserial即可。
2.4 三种方法怎么选:一张表看懂
| 安装方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Terminal + pip | 日常开发,网络正常 | 日志清晰,容易排查问题,推荐首选 | 需要稍微懂一点命令行 |
| Python Interpreter图形界面 | 新手,或者想确认解释器路径 | 界面直观,不容易装错环境 | 失败提示笼统,排错能力弱 |
| 离线whl | 断网、内网隔离环境 | 不受网络影响,稳定可控 | 需要提前下载文件,复杂包还要匹配平台 |
我个人建议是,网络条件允许就优先用第一种方法,因为你以后装任何包都会遇到报错,熟悉命令行pip的报错逻辑,对排查问题非常有帮助。图形化安装适合第一次接触PyCharm的新手,先把东西装成功建立起信心再说。离线安装属于特殊场景,掌握思路就好。
3. 常见报错与排查方法
3.1 pip命令提示“不是内部或外部命令”
这是Windows用户最容易撞上的报错,完整提示是“pip不是内部或外部命令,也不是可运行的程序或批处理文件”。这个报错的本质是系统在PATH环境变量里找不到pip,也就是说Python可能没装好,或者装的时候没勾选Add Python to PATH。
最简单的规避方法,就是在PyCharm的Terminal里操作,不要自己另外开一个cmd窗口。因为PyCharm已经配置好了解释器,Terminal会继承这个环境,一般不会出现找不到pip的情况。如果PyCharm的Terminal里也提示找不到pip,那要检查Python解释器本身是否正常。
更稳妥的命令是:
python -m pip install pyserial这条命令会先去找python,再让python自己去找pip模块。如果python本身能运行,pip一般是没问题的。如果连python都不认识,那就得重新安装Python,安装时务必勾选Add Python to PATH,装完再重启PyCharm。
还有一种情况,提示的不是pip找不到,而是pip后面报一堆traceback,说No module named pip。这大概率是Python环境被弄坏了,或者用的是某些精简版Python。遇到这种情况,可以试一下python -m ensurepip --upgrade把pip重新安装回来。
3.2 网络错误、超时和“No matching distribution”,换源解决
这种报错的长相五花八门,常见的有:
- Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None))...
- Could not find a version that satisfies the requirement pyserial (from versions: none)
- ERROR: No matching distribution found for pyserial
前两种多半是网络或者源的问题,最后一种除了网络问题,也可能是pip版本太旧。很多人一看到“No matching distribution”就开始怀疑是不是包名错了,其实包名没错,就是下载通道不顺畅。
解决办法是换国内镜像源。一次性命令:
pip install pyserial -i https://pypi.tuna.tsinghua.edu.cn/simple如果想永久生效,以后懒得每次加参数,可以在用户目录下创建一个pip配置文件。Windows用户在C:\Users\你的用户名\AppData\Roaming\pip下创建pip.ini,或者直接在用户目录下新建pip文件夹再建pip.ini;Linux和macOS用户在~/.pip或者~/.config/pip下创建pip.conf。文件内容如下:
[global] index-url = https://pypi.tuna.tsinghua.edu.cn/simple trusted-host = pypi.tuna.tsinghua.edu.cn保存后再执行pip install pyserial,之后的所有pip安装都会走清华源。注意trusted-host这行不能省,否则有些网络环境下会报SSL证书问题。
另外,如果确认网络没问题,但就是提示找不到版本,先把pip升级到最新版再试。老版本pip对某些新包的元数据解析会有问题,升级方法上文已经写过。
3.3 PermissionError权限不足,别一味给管理员权限
这类报错也很常见,尤其在macOS或Linux上,提示通常长这样:
Could not install packages due to an EnvironmentError: [Errno 13] Permission denied: '/usr/local/lib/python3.11/site-packages/...本质上是当前用户没有权限往系统级Python目录里写入文件。很多人遇到这个第一反应是加sudo或者以管理员身份运行,其实这是最不推荐的做法。因为系统Python环境是很多工具共享的,你不小心污染了,后面其他项目全都会遭殃。
正确的做法是给项目创建虚拟环境,然后在虚拟环境里安装,这就不会存在权限问题。PyCharm项目的venv目录就是干这个用的。如果你实在不想建虚拟环境,又只想给当前用户安装,可以执行:
pip install --user pyserial这个命令会把包安装到当前用户目录下,避免写系统目录。但“user安装”会增加环境复杂度,不太建议长期依赖。
顺便说一句,Windows下如果提示Permission denied,可以右键PyCharm图标选择“以管理员身份运行”来临时解决,但这同样是治标不治本的办法。真正稳妥的还是用虚拟环境,隔离干净。
3.4 明明安装成功,import serial还是No module found
这是所有人最崩溃的情况:屏幕明明显示Successfully installed pyserial,代码里import serial却报ModuleNotFoundError: No module named 'serial'。
排查顺序我建议按下面几步来:
第一步,确认当前终端环境。在PyCharm的Terminal里,看命令行有没有(venv)前缀。如果没有,说明pip把包装到了全局环境,而PyCharm运行代码时用的可能是虚拟环境,两边对不上。解决办法是激活虚拟环境后重新安装。
第二步,查看Python解释器路径。在Terminal里执行:
python -c "import sys; print(sys.executable)"看输出的路径是否和PyCharm右下角显示的解释器路径一致。如果不一致,说明终端和PyCharm用的根本不是同一个Python,这需要你在Settings里把解释器路径统一起来。
第三步,直接测试导入。执行:
python -c "import serial; print(serial.__version__)"如果这一步成功,说明装到哪里都没问题,那问题就出在PyCharm的索引或者运行配置上,试试File菜单里的Invalidate Caches / Restart,把缓存清掉再重开项目。
还有一个不起眼但真实存在的坑:你装的是pyserial,结果代码里import的也是serial,但系统里恰好有个不相关的serial包抢占了模块名。用pip show serial和pip show pyserial分别查看,如果发现serial不是pyserial提供的,那就卸载掉不相关的那个。我自己就遇到过这种情况,装的包和模块名刚好撞车,排查了半天。
3.5 新系统上的PEP 668和conda环境报错
这两年随着Linux发行版更新,不少用户会遇到一个看起来莫名其妙的报错:
error: externally-managed-environment This environment is externally managed这是PEP 668引入的保护机制,目的很朴素:某些Linux发行版对Python系统环境进行了严格管理,不允许pip直接往里装第三方包,避免把系统包管理器维护的Python弄乱。如果你确认不需要动系统环境,正解还是创建虚拟环境,在venv里装。如果你确实无所谓,想强行装,可以用:
pip install --break-system-packages pyserial但这属于破坏性操作,风险自负,我一般不推荐。
另外,用Anaconda作为解释器的用户也要留心。你在PyCharm里打开了Terminal,默认可能激活的是conda的base环境,pip install会装到base里。如果你的项目用的是另一个conda环境,就得先执行conda activate环境名,再执行pip install pyserial。这类问题看终端提示符就能判断,命令行前面出现的是(base)还是(venv),一眼就能看懂。
为了方便大家对照排查,我做了一个速查表:
| 报错信息 | 最常见原因 | 推荐解法 |
|---|---|---|
| pip不是内部或外部命令 | Python未加入PATH或未安装 | 用python -m pip,重装Python |
| Retrying / timeout | 官方源网络不稳定 | 换清华、阿里等镜像源 |
| Could not find a version | 网络或pip版本太旧 | 换源,先升级pip |
| PermissionError: [Errno 13] | 无权限写系统目录 | 创建venv虚拟环境 |
| ModuleNotFoundError | 解释器或环境不一致 | 统一解释器路径 |
| externally-managed-environment | 新版Linux系统保护 | 用虚拟环境 |
| No module named pip | Python环境损坏 | python -m ensurepip |
4. 装好后的验收和实际联调经验
4.1 三步快速验证:版本号、解释器路径、导入测试
装完pyserial,先别急着写一大段业务代码,用三步确认环境没问题,再往下走。
第一步,在PyCharm的Terminal里执行:
python -c "import serial; print(serial.__version__)"正常会输出3.5之类的版本号。如果没报错,说明模块导入没问题。
第二步,执行:
python -c "import sys; print(sys.executable)"把输出路径和PyCharm右下角的解释器路径对一下,确认代码运行用的就是刚装包的那个环境。这两条命令加起来用不了十秒钟,但能避免绝大多数“装完还是跑不了”的尴尬。
第三步,在PyCharm的Python Console里执行import serial,如果也没报错,那环境基本就稳了。之后再去写连接硬件的代码,心里才有底。
4.2 用pyserial列出电脑上所有可用串口
写串口程序的第一步,通常不是直接打开某个端口,而是先看看电脑有哪些串口可用。pyserial自带的list_ports工具就能做这件事,代码非常简单:
import serial.tools.list_ports ports = serial.tools.list_ports.comports() for port in ports: print(port.device, port.description)这段代码在Windows上会输出类似COM3 USB-SERIAL CH340这样的信息,在Linux上会输出/dev/ttyUSB0之类的路径。强烈建议把这段逻辑封装成一个小函数,每次启动程序时先枚举一遍串口,再把结果打印给用户选择。很多嵌入式调试工具都是这么设计的,避免用户手动填端口号填错。
如果你插上了USB转TTL模块,但这段代码根本看不到新端口,那基本可以断定是驱动问题,比如CH340芯片的驱动没装好,或者线材本身有问题。这时候Python代码再对也白搭,得先把系统层面的设备识别搞定。
4.3 接HC05蓝牙等硬件时,连接不上的四个原因
装好pyserial、也看到了串口,不代表就能立刻和HC05蓝牙模块正常通信。网上搜“hc05蓝牙模块连接不上”,能搜出一堆求助帖,结合我的经验,最常见的其实是这四个原因。
第一个是USB转TTL驱动问题。HC05模块自己不带USB接口,必须通过USB转TTL小板连接电脑,小板上的主控芯片通常是CH340或者CP2102。如果Windows设备管理器里根本看不到COM口,或者显示黄色感叹号,那就先装对应芯片的驱动,再回来讨论Python程序。
第二个是COM口号认错。系统分配的COM号可能会因为插拔顺序发生变化,比如上一次是COM3,下一次变成COM5。不要图省事把COM3硬编码在代码里,用上文说的list_ports枚举设备才是正经做法。
第三个是波特率不匹配。HC05模块有命令响应模式和透传模式,不同模式下默认波特率不一样,常见的有9600、38400、115200。pyserial打开串口时设置的波特率必须和蓝牙模块一致,否则你往串口发出一堆数据,对面收不到或者收到的全是乱码。这种问题光看代码是看不出来的,得先确认模块那边的参数。
第四个是TX和RX接反,或者模块供电不足。串口通信的接线原则是交叉相连:设备的TX接USB转TTL的RX,设备的RX接USB转TTL的TX。第一次接硬件的人特别容易把这两根线按“同名相连”来接,然后发现数据死活不通。电源方面,有些HC05模块需要3.3V或5V供电,电流不够时会表现为搜索不到蓝牙或者连接后频繁断开。
pyserial打开串口的标准代码是:
import serial try: ser = serial.Serial('COM3', 9600, timeout=1) print('打开串口成功:', ser.name) except serial.SerialException as e: print('打开串口失败:', e)注意timeout参数一定要写,不然执行ser.read()时如果对端一直不发数据,代码就会一直卡在阻塞状态,看起来像程序死机。
4.4 和L298N电机驱动、ESP32等设备联调的代码思路
很多人装pyserial之后,第一个项目就是控制小车,用L298N电机驱动模块接电机,再用单片机接收电脑指令。在这种场景里,Python端一般不是直接操作L298N,而是通过pyserial往下位机(比如Arduino或STM32)发指令,由下位机解析后控制电机。
往串口发数据的代码很简单:
ser.write(b'forward\n')注意write方法接收的是字节类型,不是普通字符串。如果你手头是字符串,需要先编码:
data = 'forward' ser.write(data.encode('utf-8'))读取数据时,readline可以按行读取,适合下位机按行返回状态信息的场景:
line = ser.readline() print(line.decode('utf-8', errors='ignore'))如果收到的数据是乱码,除了前面说的波特率问题,还要检查通信双方的串口参数(数据位、停止位、校验位)是否一致。pyserial默认是8位数据位、1位停止位、无校验,这个参数和大多数单片机默认配置一致,但如果下位机改了配置,Python这边也要跟着改。
至于ESP32这类板子,很多人会顺手扩展以太网功能,比如LAN8720模块。这种以太网扩展严格来说已经不走串口通信了,而是走SPI或者RMII接口,和pyserial关系不大。但你在串口调试阶段,还是需要pyserial从ESP32的日志串口读取打印信息,所以把它装好、理解串口基本用法,依然有价值。
4.5 几个容易看懵的pyserial接口细节
最后补充几个我实际使用中经常见人搞混的接口细节,省得你们踩同样的坑。
第一,程序的串口对象用完一定要关闭:
ser.close()程序退出时不会自动释放串口资源,如果你反复运行调试,就会遇到serial.SerialException打开失败,原因是串口被上个进程占用,尤其是Windows上特别明显。
第二,in_waiting属性可以帮你判断缓冲区里有没有数据:
if ser.in_waiting > 0: data = ser.read(ser.in_waiting)这个比直接sleep然后read更高效,能减少CPU空转。
第三,flush和reset_input_buffer这类方法,在实际联调时很有用。比如下位机复位后,串口缓冲区里可能残留上一次的数据,不清理的话,程序会读到一堆过期的旧数据。
ser.reset_input_buffer()第四,pyserial的Serial类还支持with语句上下文管理:
with serial.Serial('COM3', 9600, timeout=1) as ser: ser.write(b'ping\n')这样无论程序中途怎么出错退出,串口都会被自动关闭,省心很多。
说实话,我在实际项目里装pyserial的次数已经数不过来了,但每次帮同事排查,发现大半问题都出在环境选择上,而不是安装命令本身。装这个库最核心的经验就一句话:先确认终端里的Python和PyCharm运行代码用的Python是同一个,再谈安装。只要这个前提成立,pip install pyserial一次就能过,剩下的所谓疑难杂症,基本上都是网络源和解释器路径的问题。希望这篇梳理能帮你少走点弯路,尤其是第一次用HC05蓝牙模块或者倒腾串口设备的时候,回头再看这篇,应该能省下不少折腾时间。