恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
STM32F2多串口扩展:WK2114驱动实现与避坑指南
首页
资讯中心
/
STM32F2多串口扩展:WK2114驱动实现与避坑指南
STM32F2多串口扩展:WK2114驱动实现与避坑指南
发布时间:2026/10/21 2:32:56
简介这份资源面向嵌入式开发工程师与STM32学习者提供WK2114串口扩展芯片的驱动实现用于解决STM32F2系列微控制器UART接口不足、难以同时与多个外设进行串行通信的问题适用于物联网设备、工业自动化等需要多路串口通信的场景。压缩包共2个文件包含1个c源文件与1个h头文件整体约4KB其中源文件负责WK2114的初始化、波特率与数据格式设置、控制信号及收发数据等函数实现头文件则定义函数原型、常量与结构体便于其他模块调用与编译。目前已有1263人学习下载。通过该驱动读者可掌握WK2114芯片与STM32F2 UART1的配合方式、HAL库或寄存器操作思路以及串口扩展的测试与调试方法为多串口嵌入式项目提供可直接复用的代码基础。1. 从一颗冷门串口芯片说起WK2114 到底能解决什么问题去年帮一个做工业网关的朋友调板子STM32F207 上已经挂了 4 路 UART结果项目临时要接 8 个 RS232 传感器主控的串口资源直接见底。换 MCU 不现实软件模拟串口又扛不住 115200 的稳定收发。最后选了一颗 WK2114 串口拓展芯片一颗 SPI 挂上去硬生生多出 4 路独立 UART问题当场解决。这份资源就是围绕 WK2114 在 STM32F2 平台上的驱动实现包含寄存器操作、SPI 通信封装、中断收发和环形缓冲区管理。适合正在做多串口扩展、工业采集、嵌入式网关的开发者尤其是主控串口不够用又不想换方案的人。它不是什么通用库而是一份能直接嵌进你工程里的驱动代码改改引脚和 SPI 句柄就能跑。2. 芯片与平台选型WK2114 凭什么挂在 STM32F2 上2.1 WK2114 的定位与关键特性WK2114 是一颗四通道 UART 扩展芯片通过 SPI 或并口与主控通信。它内部集成了 4 个独立的 UART 控制器每个通道都有独立的波特率发生器、收发 FIFO 和中断控制。对主控来说它就是一个 SPI 从设备你往对应寄存器写数据它帮你把串口时序全部搞定。关键特性直接决定驱动怎么写通信接口SPI 从模式最高时钟支持到 10MHz 左右STM32F2 的 SPI1 跑在 18MHz 以下都没问题通道数4 路独立 UART每路可单独配置波特率、数据位、停止位、校验位FIFO每通道收发各 16 字节减少主控中断频率中断输出一根 IRQ 引脚低电平有效主控通过读中断状态寄存器判断是哪个通道触发供电3.3V和 STM32F2 电平直接匹配不需要电平转换我一般会先确认板子上 WK2114 的片选接在哪个 GPIOIRQ 接在哪个 EXTI 线上这两根线定下来驱动框架就清晰了。2.2 为什么选 STM32F2 而不是 F1/F4STM32F2 系列在工业现场很常见Cortex-M3 内核主频 120MHzSPI 外设支持 8 位和 16 位数据帧DMA 通道也够用。相比 F1F2 的 SPI 时钟更高配合 WK2114 的 FIFO 可以做到更低的 CPU 占用相比 F4F2 的外设寄存器布局更简单驱动代码不需要处理太多缓存一致性问题。常见做法是 SPI1 跑在 9MHz 左右用 DMA 发送、中断接收。WK2114 的 SPI 时序是标准模式 0CPOL0CPHA0MSB 先行。STM32F2 的 SPI_CR1 寄存器里把 CPOL 和 CPHA 都清零就行。2.3 硬件连接与引脚分配以某工业采集板为例典型连接如下WK2114 引脚STM32F2 引脚说明SCLKPA5 (SPI1_SCK)SPI 时钟MOSIPA7 (SPI1_MOSI)主出从入MISOPA6 (SPI1_MISO)主入从出CSPA4 (GPIO)软件片选低有效IRQPB0 (EXTI0)中断输出低有效RSTPB1 (GPIO)复位低有效片选我习惯用软件控制因为 WK2114 的 SPI 事务之间需要拉高 CS 来锁存数据硬件 NSS 有时候时序不好控。IRQ 接 EXTI 下降沿触发进中断后先读 WK2114 的中断状态寄存器再决定处理哪个通道。3. 驱动架构拆解SPI 通信层与 UART 通道管理3.1 分层设计思路驱动分成三层最底层是 SPI 读写字节函数中间层是 WK2114 寄存器读写封装最上层是 4 个 UART 通道的收发管理。这样分层的好处是换主控平台只需要改 SPI 底层换芯片只需要改寄存器定义。目录结构大致如下wk2114_driver/ ├── inc/ │ ├── wk2114.h // 寄存器定义、结构体、API 声明 │ └── wk2114_port.h // 平台相关宏SPI 句柄、CS/IRQ 引脚 ├── src/ │ ├── wk2114.c // 寄存器读写、初始化、中断处理 │ └── wk2114_uart.c // 4 通道收发、环形缓冲区 └── example/ └── main.c // 初始化示例、收发测试3.2 SPI 读写与寄存器操作WK2114 的寄存器地址是 8 位数据也是 8 位。SPI 事务格式先发地址字节最高位表示读/写1 读 0 写然后跟数据字节。下面是我常用的两个基础函数// wk2114.c #include wk2114.h #include wk2114_port.h // 写一个寄存器 void WK2114_WriteReg(uint8_t addr, uint8_t data) { WK2114_CS_LOW(); // 片选拉低 SPI_TransferByte(addr 0x7F); // 最高位 0 表示写 SPI_TransferByte(data); // 写入数据 WK2114_CS_HIGH(); // 片选拉高锁存 } // 读一个寄存器 uint8_t WK2114_ReadReg(uint8_t addr) { uint8_t val; WK2114_CS_LOW(); SPI_TransferByte(addr | 0x80); // 最高位 1 表示读 val SPI_TransferByte(0xFF); // 发哑元收数据 WK2114_CS_HIGH(); return val; }逻辑说明addr 0x7F把地址最高位清零表示写操作addr | 0x80置一表示读操作。SPI_TransferByte是平台相关函数STM32F2 上可以用标准库的SPI_I2S_SendData加等待SPI_I2S_GetFlagStatus实现也可以用 HAL 的HAL_SPI_TransmitReceive。片选必须在每个事务结束后拉高否则 WK2114 不会锁存数据这是血泪经验早期调试时数据写不进去就是 CS 忘了拉高。参数说明addr范围 0x00~0x7Fdata是 8 位寄存器值。读操作时发 0xFF 是因为 SPI 全双工必须给时钟才能收到数据哑元值无所谓。3.3 通道初始化与波特率配置WK2114 每个通道有一组寄存器波特率分频低字节、高字节、线路控制寄存器、FIFO 控制寄存器。初始化时先软复位再逐通道配置。// 初始化 WK2114配置 4 个通道 void WK2114_Init(uint32_t baudrate) { WK2114_RST_LOW(); // 硬件复位 Delay_ms(10); WK2114_RST_HIGH(); Delay_ms(10); // 全局中断使能FIFO 使能 WK2114_WriteReg(WK2114_REG_GLOBAL_CTRL, 0x01); for (uint8_t ch 0; ch 4; ch) { uint16_t divisor WK2114_CLK_FREQ / (baudrate * 16); WK2114_WriteReg(WK2114_REG_BR_L(ch), divisor 0xFF); WK2114_WriteReg(WK2114_REG_BR_H(ch), (divisor 8) 0xFF); // 8 数据位1 停止位无校验使能收发 FIFO WK2114_WriteReg(WK2114_REG_LCR(ch), 0x03); WK2114_WriteReg(WK2114_REG_FCR(ch), 0x07); // 使能接收中断 WK2114_WriteReg(WK2114_REG_IER(ch), 0x01); } }逻辑说明WK2114_CLK_FREQ是芯片内部基准时钟常见为 14.7456MHz 或 7.3728MHz具体看板子晶振。分频公式是基准时钟 / (波特率 * 16)算出 16 位分频值。LCR寄存器 0x03 表示 8N1FCR寄存器 0x07 表示使能 FIFO 并清空收发缓冲。IER寄存器 0x01 表示接收数据可用中断。参数说明baudrate支持 9600、19200、38400、57600、115200 等标准值。如果波特率有偏差优先检查基准时钟频率是否和实际晶振一致这个坑我踩过板子焊的是 7.3728MHz 但代码里写 14.7456MHz结果所有通道波特率翻倍数据全是乱码。3.4 中断处理与环形缓冲区WK2114 的 IRQ 引脚是 4 个通道共享的进中断后必须读全局中断状态寄存器判断是哪个通道有数据然后读该通道的接收寄存器塞进对应的环形缓冲区。// 环形缓冲区结构 typedef struct { uint8_t buf[256]; volatile uint16_t head; volatile uint16_t tail; } RingBuf_t; static RingBuf_t rx_buf[4]; // EXTI 中断服务函数 void EXTI0_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line0) ! RESET) { uint8_t int_status WK2114_ReadReg(WK2114_REG_INT_STATUS); for (uint8_t ch 0; ch 4; ch) { if (int_status (1 ch)) { while (WK2114_ReadReg(WK2114_REG_LSR(ch)) 0x01) { uint8_t data WK2114_ReadReg(WK2114_REG_RBR(ch)); uint16_t next (rx_buf[ch].head 1) % 256; if (next ! rx_buf[ch].tail) { rx_buf[ch].buf[rx_buf[ch].head] data; rx_buf[ch].head next; } } } } EXTI_ClearITPendingBit(EXTI_Line0); } }逻辑说明INT_STATUS寄存器的 bit0~bit3 分别对应 4 个通道。LSR寄存器的 bit0 是数据就绪标志循环读到没有数据为止。环形缓冲区用 head 和 tail 两个索引head 由中断写tail 由主循环读不需要关中断因为单生产者单消费者模型下读写各自索引不会冲突。参数说明缓冲区大小 256 字节可以根据实际数据量调整。如果波特率 115200 且数据连续建议至少 512 字节否则主循环处理慢会丢数据。WK2114_REG_LSR的 bit0 是 DRData Readybit1 是 OEOverrun Error如果发现 OE 置位说明缓冲区满了需要加大缓冲区或提高主循环读取频率。4. 避坑与排查调 WK2114 时最容易翻车的几个点4.1 数据写进去读出来全是 0xFF现象初始化后读任何寄存器都返回 0xFF写进去的值也读不回来。原因SPI 模式不对或者 MISO 线没接好。WK2114 要求 SPI 模式 0如果 CPHA 设成 1采样边沿错了读出来全是高电平。另外如果 MISO 虚焊主控读到的就是浮空的高电平。解决用示波器看 SCLK 和 MOSI确认时钟空闲低、第一个边沿采样。检查 MISO 焊接。STM32F2 的 SPI_CR1 寄存器里 CPOL0、CPHA0BR 分频先设大一点比如 64 分频低速调通再提速。4.2 能读能写但串口发不出数据现象寄存器读写正常但外部串口工具收不到任何数据。原因通道的发送使能没开或者波特率分频算错。WK2114 的 LCR 寄存器里除了数据位停止位还有一位是发送使能有些型号需要单独置位。另外分频值算错会导致波特率偏差太大接收端识别不了。解决先确认 LCR 的值8N1 通常是 0x03如果芯片手册要求发送使能位就改成 0x43。然后用示波器测 TX 引脚看有没有波形有波形但数据错就是波特率问题重新算分频值。4.3 中断进不去或者进去出不来现象IRQ 引脚一直是低电平或者中断触发一次后再也不触发。原因中断状态寄存器没清或者 EXTI 触发边沿设成了双边沿。WK2114 的 IRQ 是电平方式低电平表示有中断读走数据后自动变高。如果 EXTI 设成下降沿触发但中断服务里没读数据IRQ 一直低就不会再有下降沿。解决EXTI 配置成下降沿触发中断服务里必须读到 LSR 的 DR 位为 0 才退出。另外确认 WK2114 的全局中断使能位已经打开有些批次芯片默认是关闭的。4.4 多通道同时收发时数据串扰现象通道 0 收到的数据跑到了通道 1 的缓冲区里。原因读接收寄存器时地址算错或者中断状态判断时通道索引搞混。WK2114 的通道寄存器地址是基址加通道偏移如果偏移量算错读的就是隔壁通道的数据。解决把通道基址定义成宏比如#define WK2114_REG_RBR(ch) (0x00 (ch) * 0x08)确保每个通道的寄存器块间隔正确。中断里用for循环遍历 4 个通道时索引和寄存器地址要对应上。4.5 高速收发时丢数据现象115200 波特率下连续发几百字节接收端偶尔少几个字节。原因环形缓冲区太小或者主循环读取太慢。WK2114 的 FIFO 只有 16 字节如果主循环不及时读FIFO 溢出就丢数据。解决加大环形缓冲区到 512 或 1024 字节主循环里用while循环把缓冲区数据全部读走再处理。如果还丢考虑用 DMA 把 SPI 接收也做成自动搬运减少中断延迟。5. 二次开发与验证从能跑到好用的改造思路5.1 把驱动移植到其他 STM32 系列这份驱动的平台相关部分集中在wk2114_port.h和 SPI 底层函数里。移植到 STM32F1 或 F4 时只需要改三个地方SPI 句柄初始化、CS/IRQ 引脚宏定义、延时函数。寄存器操作和环形缓冲区逻辑完全不用动。我一般会先把SPI_TransferByte换成目标平台的实现然后跑一个寄存器读写测试读 WK2114 的版本寄存器或者随便写一个测试寄存器再读回来确认 SPI 通路正常。这一步过了后面基本不会有大问题。5.2 增加 DMA 收发降低 CPU 占用如果 4 个通道都跑 115200 且数据量大中断方式会吃掉不少 CPU。改造思路是SPI 接收用 DMAWK2114 的 IRQ 触发后启动一次 DMA 传输把 FIFO 里的数据批量搬到内存。发送方向也可以做 DMA 队列主循环把数据塞进发送缓冲区DMA 自动搬运。关键点是 DMA 传输长度要动态计算根据 LSR 寄存器里的数据个数来决定搬多少字节。STM32F2 的 DMA 支持单次传输配置好外设地址和内存地址使能通道就行。5.3 用 shell 命令验证每个通道调通之后我习惯在工程里加一个简单的 shell通过主串口输入命令来测试 4 个扩展通道。比如// 测试命令wk2114 send ch string void Cmd_WK2114_Send(int ch, char *str) { while (*str) { while (!(WK2114_ReadReg(WK2114_REG_LSR(ch)) 0x20)); WK2114_WriteReg(WK2114_REG_THR(ch), *str); } }逻辑说明LSR的 bit5 是发送保持寄存器空标志等待它置位再写下一个字节。这样可以在不接外部设备的情况下用回环线把 TX 和 RX 短接自己发自己收验证通道是否正常。参数说明ch范围 0~3str是要发送的字符串。回环测试时把对应通道的 TX 和 RX 用杜邦线短接发什么就应该收到什么。5.4 一个我踩过的坑早期调试时我把 WK2114 的 IRQ 接在了 STM32F2 的 PB0 上但 EXTI0 的中断优先级设得比 SysTick 还低结果主循环里HAL_Delay一执行中断就被挂起数据丢了一大半。后来把 EXTI0 的抢占优先级调到比 SysTick 高问题消失。从那以后我每次配中断优先级都强制走一遍优先级分组检查确保串口中断不会被系统滴答打断。希望帮到你。本文还有配套的精品资源点击获取