news 2026/9/9 21:45:51

WK2114串口扩展芯片Linux驱动实战:一UART变四UART的完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WK2114串口扩展芯片Linux驱动实战:一UART变四UART的完整指南

简介:一套基于STM32F2系列微控制器的WK2114串口扩展芯片驱动源码,面向需要突破单UART端口数量限制的嵌入式开发人员,常用于物联网设备、工业自动化等多串口通信场景,也适合驱动开发入门与进阶者阅读。压缩包共有2个文件,体积仅4KB,包含一个C驱动实现文件与一个H头文件:前者实现芯片初始化、波特率/数据格式设置以及收发数据等核心函数,后者提供函数原型与常量的统一声明,方便工程直接集成调用。资源已有1259人学习浏览,虽体量小但结构完整,直击串口扩展驱动关键环节。开发者可获得一套可移植的串口扩展驱动范例:既能直接调用收发接口完成多路串口扩充,也能通过代码理解WK2114与STM32F2 UART1之间的交互机制,以及基于HAL库的底层驱动设计思路。该驱动还有助于开发者掌握扩展微控制器串行通信能力的方法,提高系统设计灵活性,可作为后续移植到其他型号控制器或自主编写外设驱动时的参考。 前阵子帮一个做工业网关的朋友调板子,卡在最尴尬的一个问题上:主控芯片的串口全用完了,可工程现场又需要同时接好几个传感器、一个串口屏、一台旧设备。项目里甚至还有LED闪灯驱动芯片、带数码管的风扇驱动芯片这类外围器件,IO和串口资源被占得满满当当。后来换上了WK2114串口拓展芯片,把所有串口外设挂到一路物理UART上,问题才算彻底解决。这篇就把我调WK2114芯片驱动的整个过程、踩过的坑和一些底层经验整理出来。

WK2114属于单UART转四UART的串口拓展芯片,主控只需要一个串口,经过它就能引出4个独立的子串口。网上关于这颗料的中文资料不算多,尤其是“怎么把它在Linux下变成4个tty设备”的驱动部分,基本靠翻手册硬啃。我用的是嵌入式Linux环境,MCU裸机场景也顺手验证过,下面尽量把两种模式都能覆盖到,让拿到这颗芯片的人少走点弯路。

1. 一块WK2114,怎么就让系统多出了4个串口

1.1 先搞明白WK2114到底在干什么

先不急着写代码,得先搞清楚这颗芯片的数据通路。WK2114内部有一个主串口接口,另一端挂4个子串口(一般叫SUB1到SUB4)。主控的UART TX、RX接到芯片的主串口,芯片内部通过寄存器配置把数据调度到对应子串口上。

从使用者的视角看,主控发出去的数据会按某种协议被芯片“拆包”,然后转投到指定子口;反过来,子口收到的数据会汇总到主口上,再由主控读走。芯片内部一般还带FIFO缓冲,能缓解瞬时高流量带来的丢数据问题。子串口的波特率、数据位、停止位、校验位,都可以通过寄存器独立配置,这也是它比普通“硬件跳线分时复用”方案灵活的原因。

很多朋友第一次拿到这颗芯片,会下意识以为“外扩了4个串口,主控驱动就多出4个中断、4个DMA”。实际上不是,WK2114对主控来说始终只有一个串口,真正复杂的调度在芯片内部和驱动里。

1.2 为什么不用USB转串口,而非要选WK2114

这问题我在选型阶段纠结了很久。USB转UART方案(比如常见的FT232、CH340、CP2102那类)确实更通用,插上就是4个独立串口,Linux下驱动也成熟,看起来美得很。但放到工业产品里,USB方案有几个麻烦:

  • 主控得额外提供USB Host资源,而很多工业级MCU或精简板卡的USB口本来就少;
  • USB协议栈占用CPU和内存,抗干扰性能也不如纯UART链路稳定;
  • 设备频繁上下电、USB枚举异常时,恢复逻辑写起来想砸键盘。

WK2114走的是纯串口链路,主控侧就是一组TX/RX,驱动逻辑简单,实时性也更可控。代价是这颗芯片本身的驱动程序需要自己写或者深度适配,不像USB方案插上就有现成节点。

相比之下,如果你只是想让主控多几个“低速、不定时收发小数据”的串口,WK2114这种单转多UART芯片非常合适。如果追求高速率、大批量并发,那老老实实上USB转串口方案更划算。

2. 驱动不是上来就写代码:先把数据流和寄存器理清楚

2.1 从主串口到4个子串口的数据流

我调试时习惯先画数据流图,避免写代码写到一半逻辑绕晕。WK2114的数据流大致是:

  • 主控发送:主控通过物理UART发送一帧数据,WK2114根据帧里的通道信息,把有效负载写入对应子串口的发送FIFO,然后从对应TX引脚发出去。
  • 子口发送到主控:任意子串口收到外部数据后,存入该子口的接收FIFO,芯片通过INT引脚或其他状态位告诉主控“快取数据”,主控再从主串口读回。

所以驱动要解决的核心问题只有两个:一是怎么让主控“选中”某个子口,二是怎么知道当前数据属于哪个子口。这两个问题都由芯片的寄存器机制解决。

2.2 寄存器读写模型

WK2114的寄存器大体分三类:全局控制寄存器、通道选择相关寄存器、数据收发寄存器。我在调试时习惯把寄存器表打印出来逐条核,防止手册版本差异带来的坑。

常见操作流程是这样的:

  1. 上电后先给芯片一个复位信号,等稳定后再配置全局模式;
  2. 写配置寄存器,设置子串口数量、FIFO开关、中断模式等;
  3. 对每个子通道,单独配置波特率、数据位、校验位;
  4. 收发时,先写通道号,再从数据寄存器读或写。

这里必须提醒:WK2114不同批次、不同厂家的寄存器地址定义可能有差异,网上很多人贴的寄存器表也不一定和你手上的手册一致。我踩过一次坑,照着网上代码配波特率,怎么都不对,最后翻手册才发现分频计算公式落后了一个版本。所以下面的寄存器地址我只给逻辑流程,真正的地址一定要以你手里那颗芯片的最新数据手册为准。

2.3 轮询还是中断,这是个取舍

驱动里最影响实时性的,就是主串口的数据读取方式。

如果子口设备只是定时上报温湿度、开关量这种低频数据,完全可以用轮询:主控定时去读状态寄存器,发现数据就取回来。好处是代码简单,不占用额外引脚,坏处是数据随机到来时延迟不可控。

如果需要即时响应,比如接串口屏、扫码枪,那就得用中断。WK2114一般会提供一个中断信号引脚,子口有数据时拉低或拉高,主控对应的GPIO触发中断,然后驱动在读状态寄存器确认。中断方式响应快,但需要占用一个GPIO,而且中断处理函数里不能做耗时操作,只是“唤醒工作队列”,实际搬数据放到线程里。

我这个项目里是4个子口都在用,波特率也不一样,最后选了“中断通知+内核工作队列”的组合,实测CPU占用最稳。

3. Linux下的驱动落地:把WK2114注册成4个tty端口

3.1 设备树节点怎么写

先在设备树里描述芯片和主串口的关系。WK2114本身不挂I2C/SPI,而是挂在某个UART控制器下面,所以我们在设备树里把它描述成一个简单的platform device,再关联上复位GPIO和中断GPIO。

&uart1 { status = "okay"; pinctrl-0 = <&uart1_pins>; pinctrl-names = "default"; }; &pio { wk2114_int_pin: wk2114_int_pin { pins = "PD11"; function = "gpio_in"; bias-pull-up; }; }; wk2114 { compatible = "wk,wk2114"; status = "okay"; /* 控制主串口,这里只是示例 */ main-uart = <&uart1>; reset-gpios = <&pio PD10 GPIO_ACTIVE_LOW>; int-gpios = <&pio PD11 GPIO_ACTIVE_HIGH>; sub-port-speed = <9600 9600 115200 115200>; };

sub-port-speed是给每个子通道设默认波特率,也可以全部在驱动里配置。复位GPIO和中断GPIO务必确认主控侧的电气特性,别接反,WK2114的INT引脚一般要求上拉。

3.2 驱动核心框架

Linux下把这颗芯片做成4个标准tty设备,有两种思路:

  • 方案A:直接改uart驱动框架,注册4个uart_port,把它们挂在同一个uart_driver上;
  • 方案B:写一个platform驱动,内部把那颗芯片抽象成一个“中转站”,再注册4个虚拟tty设备。

我推荐方案B,灵活度更高,而且不用改动内核原有串口驱动,风险小。核心框架很像下面这样:

static const struct uart_ops wk2114_ops = { .startup = wk2114_startup, .shutdown = wk2114_shutdown, .set_termios = wk2114_set_termios, .start_tx = wk2114_start_tx, .stop_tx = wk2114_stop_tx, .tx_empty = wk2114_tx_empty, }; static struct uart_driver wk2114_uart_driver = { .owner = THIS_MODULE, .driver_name = "wk2114", .dev_name = "ttyWK", .nr = 4, };

在probe函数里,需要完成这几件事:

  1. 获取复位GPIO,释放复位;
  2. 获取INT中断GPIO,注册中断处理函数;
  3. 初始化芯片子口参数(波特率、数据位等);
  4. 调用uart_register_driver和tty_port_register_device注册设备;
  5. 在中断处理里读取子口数据,写入对应tty_port的接收buffer。

有个容易忽略的细节:子串口set_termios被上层调用时,driver需要把参数下发给WK2114。也就是说,应用层用stty设置/dev/ttyWK2的波特率时,驱动要能转换成芯片寄存器写操作,否则串口打开时是什么参数,实际跑起来还是什么参数。

3.3 编译、加载和生成设备节点

驱动写完编译,我习惯先用模块方式加载,调通了再考虑编进内核:

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- M=drivers/tty/serial wk2114.ko insmod wk2114.ko dmesg | tail -20

加载成功后,能看见类似“ttyWK0~ttyWK3”的提示。如果/dev下没自动生成节点,手动创建设备节点验证一下:

mknod /dev/ttyWK0 c 240 0

等确认逻辑没问题,再补udev规则,让设备节点稳定在固定名字:

KERNEL=="ttyWK[0-3]", NAME="wk2114-%n"

这一步实际生产环境很有用,不然后面写应用层程序时设备名一变,全部白搭。

4. 调试实录:我最常踩的5个坑

4.1 子口收不到数据

这问题排第一,几乎每个人都会遇到。我遇到的情况是:主串口配置好了,子串口接传感器,死活收不到数据。

排查顺序建议从硬到软:

  1. 先用示波器或逻辑分析仪看主串口TX有没有波形,排除主控没发数据;
  2. 看芯片复位引脚有没有正常释放,有些板子复位电容太大,上电后芯片还在复位,你就开始配置了;
  3. 看子串口对应设备是否共地,串口通信必须共地,不然参考电平飘了数据全丢;
  4. 检查驱动里波特率寄存器配置是否正确,先拿一个子口loopback测试。

我最后发现不是硬件问题,而是驱动在初始化时漏了切换通道,配置只写到了SUB1,其他子口等于没配置。所以建议写驱动时加一个“初始化完成后逐通道回读配置”的调试函数,能省很多时间。

4.2 频繁乱码和丢字节

乱码和丢字节通常是两个原因:电平不稳定,或者数据速率不匹配。

如果主串口波特率是115200,而子口被配置成115200,理论上没有问题。但WK2114内部还要做数据搬运,如果FIFO阈值设置太低,子口突发数据一来,芯片来不及汇总到主口,就会丢掉。

我的处理办法是:

  • 把FIFO中断阈值调到一半左右,别等满了再通知;
  • 降低子口数据突发频率,应用层做小包重发;
  • 主串口波特率比所有子串口波特率之和还要高一些,这样才有余量。

如果只开一个子口且子口速率等于主口速率,时延还能压到很低。一旦4个子口全部以115200持续收发,主口至少得跑到460800甚至更高,否则卡死只是时间问题。

4.3 中断一直触发,CPU占用快拉满

这个问题很隐蔽。WK2114的中断引脚一般是有数据就触发,驱动如果读完数据后没有正确“清状态”,芯片会认为数据还在,中断就一直拉高或持续发脉冲,GPIO中断处理函数被疯狂调用,系统直接卡成PPT。

处理办法:

  • 确认中断触发方式,边沿触发还是电平触发要严格按手册来;
  • 中断处理里先把状态寄存器全部读完,确认处理干净再退出;
  • 如果中断里要做耗时事情,不要直接在中断上下文做,改由工作队列或tasklet处理。

我实测过,中断处理里加一个寄存器读操作,CPU占用能从接近100%降到个位数。

4.4 波特率不准,通信时好时坏

如果WK2114子口和某台旧设备怎么都握手不上,先怀疑波特率误差。检查芯片外部晶振/时钟源的精度,如果晶振偏差太大,波特率误差就会累计,超过RS232允许的误差范围自然乱码。

在驱动里可以按公式重新计算分频系数,不要完全依赖默认值。我遇到的一块板子,外部晶振标称12MHz,实际偏差0.3%,9600波特率下直接出现偶发错位。后来改成按实测频率计算,问题消失。这种问题在普通测试板卡上很难复现,等到产线批量才暴露,所以驱动里能做校准就做校准。

4.5 设备节点不稳定,重启后名称乱跳

串口设备节点在Linux下如果没固定绑定,重启后可能从ttyWK0变成ttyWK2,应用层就会连错设备。除了udev规则,我还建议在驱动里给每个tty端口设置别名,或根据DT里的别名固定索引。这一步属于“不加的时候没事,加了之后永远省心”的典型操作。

现象常见原因排查/解决
子口完全收不到数据通道未切换、复位未释放回读寄存器,检查复位时序
乱码、偶发丢字节波特率误差、FIFO阈值不合理校准分频,调整FIFO阈值
中断风暴状态未清、触发方式错误正确清状态,改边沿触发
设备节点不稳udev绑定缺失写udev规则,固定设备名

5. 性能和选型参考

5.1 实测表现大概什么样

我用自己的板子做过一轮压力测试,主控是一颗常见的四核ARM处理器,4个子口全部使用115200波特率,开了流控,驱动采用中断+工作队列模式。持续对发数据时,CPU占用大约在15%到20%,单次转发延迟在毫秒级。如果只开1个子口,CPU占用可以压到5%以内。

我整理的参考数据如下(实际数值和你板子的中断频率、主串口波特率强相关,只做趋势参考):

场景主串口波特率子口配置有效吞吐CPU占用
单子口低速1152009600 x1稳定很低
两子口中速230400115200 x2基本稳定中等
四子口同时满载921600115200 x4有压力较高

这里的瓶颈不在WK2114本身,而在主控串口的中断处理能力和驱动的数据搬运效率。主串口速率越高,单字节中断时间越短,CPU压力越大,必要时得优化驱动,改成DMA方式搬运数据。

5.2 什么时候不该用WK2114

不是所有“串口不够”都应该用WK2114。它适合低速、多路、数据量可控的场景,比如传感器采集、串口屏控制、旧设备对接。但如果你要做以下事情,它可能不是最优解:

  • 单个子口持续高速大数据量收发,比如每秒几十KB的日志输出,主口很容易成为瓶颈;
  • 需要频繁热插拔子设备并且要求系统自动识别,那是USB转串口的强项;
  • 仅仅是控制LED闪灯、驱动数码管风扇这类,没必要占用串口,直接用GPIO或专用驱动芯片更省事。

我个人做下来的最大感受是:WK2114这类芯片,驱动本身不难,难的是一开始要把它当成“一个带多路分发的串口控制器”来理解,而不是当成“4个独立串口”。把数据流和寄存器机制想透,后面Linux驱动也只是一层包装。踩过几次坑之后,我现在拿到这类单转多UART芯片,第一件事永远是拿示波器查上电时序,第二件事是逐条验证寄存器回读,这两步做扎实,后面基本不会翻车。

本文还有配套的精品资源,点击获取

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

AI测试助手实战:系统工程师如何用AI提升效率与质量

这两年做系统工程师和测试相关的活儿&#xff0c;一个非常明显的感受是&#xff1a; AI 测试 已经从“能用但鸡肋”进化到“真能帮你省两三个小时”的阶段了。不管是写自动化脚本、排查 Linux 环境问题&#xff0c;还是解析一堆让人头大的日志&#xff0c;AI 这个“超级助手”…

作者头像 李华
网站建设 2026/9/9 21:45:16

PyCharm 2026安装配置指南:从解释器到虚拟环境一次搞定

如果你翻到这篇文章&#xff0c;多半是刚下载完PyCharm&#xff0c;正卡在安装包解压后的那个蓝色向导界面&#xff0c;或者装完之后打开白屏、新建项目时不知道该选哪一行解释器。这个工具我这些年给团队新手配了不知道多少次环境&#xff0c;说实话&#xff0c;PyCharm安装本…

作者头像 李华
网站建设 2026/9/9 21:44:45

XDMA驱动底层读写DLL封装:接口设计、缓冲区管理与踩坑实录

简介&#xff1a;面向PCIE开发者的Xilinx XDMA底层读写DLL封装工程&#xff0c;其专注于解决FPGA与主机之间高速数据传输时驱动调用繁琐的问题。工程将xdma驱动的硬件访问接口封装为动态链接库&#xff0c;使开发人员可以在C或C#环境中直接调用读写函数&#xff0c;无需深入驱动…

作者头像 李华
网站建设 2026/9/9 21:44:30

十大经典机器学习算法Python手写实现与避坑指南

简介&#xff1a;面向数据挖掘初学者、相关课程学生及准备算法面试的开发者&#xff0c;这份源代码包精准覆盖了关联规则Apriori、决策树C4.5/CART、EM聚类、K-means、KNN、PageRank共7种经典算法的Python实现&#xff0c;每个算法均可独立运行并对照教材理解。压缩包共15个文件…

作者头像 李华
网站建设 2026/9/9 21:41:42

GPUPixel:移动端实时美颜滤镜的跨平台C++引擎解析

最近好几个做音视频和直播的朋友都在问我&#xff0c;移动端的实时美颜、滤镜到底怎么选型才靠谱。既要效果好、性能跑得动&#xff0c;又要能跨平台复用&#xff0c;iOS、Android一套代码搞定。我研究了一圈开源方案&#xff0c;发现GPUPixel这个项目值得好好聊聊。它是个用C1…

作者头像 李华
网站建设 2026/9/9 21:39:23

如何用 Langflow 的 Guardrails 组件为 Agent 添加行为约束?

如何用 Langflow 的 Guardrails 组件为 Agent 添加行为约束&#xff1f; 【免费下载链接】langflow Langflow is a powerful tool for building and deploying AI-powered agents and workflows. 项目地址: https://gitcode.com/GitHub_Trending/la/langflow 在 Langflo…

作者头像 李华