一、模块介绍
本项目是自选通信应用综合系统模块。设计一个 USB 无线网卡(Wi-Fi Dongle):USB-A 公头插到主机(PC/开发板)上,由 STM32C071 通过 USB 枚举并与 ST67 Wi-Fi 模组通信,把主机的数据经 Wi-Fi 收发,实现“USB 转 Wi-Fi”的无线连接功能(也可作为各类主机的无线扩展开发板)。
二、项目介绍
2.1 主要芯片选项
ST67芯片资源框图

ST657是意法半导体联合高通推出的协处理器,通过了Wi-Fi® 6和Bluetooth® LE认证,可无缝集成到STM32MCU或MPU,深度融合ST的cube包,集成在Cubemx中,可快速构建MCU驱动ST67的项目。
在项目主控方面,选取的是STM32C071GBU6,C0系列是ST超值系列的当家花旦,C071有原生的USB2.0接口,片上集成PHY,无需外部添加UBS PHY,其中UFQFPN封装可极大程度降低PCB空间。
方案框图

2.2 硬件选型
无线模组 | ST67W611M1A6BTR(U1,邮票孔模组) | Wi-Fi 收发,SPI + UART 主机接口 |
主控 MCU | STM32C071G8U6(U6,UFQFPN-28) | USB 设备、SPI/UART 协议转换、按键与 LED 管理 |
电源 | AMS1117-3.3(U7,SOT-89) | USB 5V → 3.3V 供电 |
接口 | USB-A 公头(TH)、TYPE-C 16Pin 母座 | 双 USB 接口,共享 D+/D− 总线 |
防护 | 2× USBLC4-2SC6(U2、U5,SOT-23-6) | 两个端口的 USB 差分对 ESD 静电防护 |
时钟 | 48MHz 有源晶振(X1) | 为 MCU 提供精确时钟(USB 通信要求) |
人机交互 | 3× LED(LD1~LD3)、2× 轻触按键 + NRST/BOOT 按键 | 状态指示与控制 |
调测接口 | H1(调试串口 D_TX/D_RX)、H2(SWD)、H3(5V/3V3/PB6/PB7 扩展排针) | 烧录、调试、功能扩展 |
其他 | 10kΩ NTC + 23.7kΩ 分压电阻(NTC1 网络) | 温度检测,监视模组温升 |
2.3 原理图介绍

ST67外围电路简介:
- VDD33引脚旁布置3个0603尺寸的MLCC焊盘,预留充足的电容空间,避免发射时的峰值电流。
- VDDIO通过3个0603尺寸的焊盘,完成1V8和3V3的全电压兼容
- ST67的SPI引脚引出至排针,可脱离C071单独使用
C071电路简介:
- PC14、PC15引脚连接到48M的无源晶振,以备在高温时内部晶振偏移较大导致的USB数据失真。选取48M晶振可直接引入USB PHY所需时钟,无需分频等操作
- 引出原生的USART2串口的PA2 PA3引脚,以便出厂空程序时烧录C071
- 考虑到STM32C0系列独特设计,不连接BOOT0至按钮上进行BOOT模式的选择。
USB电路简介:
- USB使用一个C口和一个A口公头,兼容,CC引脚通过5.1K电阻下拉到GND,防止过压。
- USB输入电源经过保险丝和ESD后才连接到ST67和C071上,具备过压过流保护。
- C071靠近USB接口,USB D+和USB D-网络差分等长走线。
2.3 PCB介绍


PCB设计特点
- 4层板设计,超小PCB
- 天线区域下方禁止走线禁止铺铜
- 33-36散热GND焊盘放置过孔
- ST67芯片区域防止一个NTC电阻,使用C071的ADC采集温度,根据温度自适应发射功率
- USB线路附近增加GND过孔
- C口和A口呈对称式布局,单侧超宽,以便降低dogle对其他USB设备的干扰
2.3 改版介绍
相较于阶段1的理论设计 ST67-dogle 阶段1
优化了USB接口设定,C071和ST67的连接方式,优化了PCB的布局和尺寸。
三、模块性能
模块性能
性能指标 | 参数值 |
|---|---|
主控芯片型号 | STM32C071 |
主控内核与主频 | Cortex-M0+ @ 48MHz |
主控存储 | 128KB Flash + 24KB RAM |
无线模组型号 | ST67W611M1(Wi-Fi 6 + BLE 5.4) |
无线发射功率 | Wi-Fi +21dBm / BLE +10dBm |
无线接收灵敏度 | Wi-Fi -67dBm(MCS9)/ BLE -99dBm(1Mbps) |
无线传输速率 | Wi-Fi 最高17Mbps(TCP) |
电源输入 | Type-C 5V(兼容4.5~15V) |
电源输出(LDO) | AMS1117 降压 3.3V / 最大1A |
工作温度范围 | 主控 -40~125℃ / 模组 -40~85℃ |
引脚定义
H1排针序号 | 网络名称 |
|---|---|
1 | SUART_RX |
2 | SUART_TX |
3 | GND |
4 | VDD_IN |
5 | SPI_MOSI |
6 | SPI_NSS |
7 | SPI_SCK |
8 | SPI_MISO |
9 | CHIP_EN |
四、调试
4.1 焊接调试
PCB采用4层沉金打烊,正反面均部满了元器件。




4.2 调试软件
调试软件采用
stm32cubemx v6.17.1
stm32cubeide v2.2.0
rycom串口助手
dap-link调试器
4.3 软件代码
上电时序(st67w61.c)
void ST67_PowerOn(void)
{
/* BOOT 拉低 = 正常启动模式 */
HAL_GPIO_WritePin(ST67_BOOT_GPIO_Port, ST67_BOOT_Pin, GPIO_PIN_RESET);
/* 电源复位脉冲: CHIP_EN 低 20ms → 高 */
ST67_PowerOff(); /* CHIP_EN = 0 */
HAL_Delay(20);
HAL_GPIO_WritePin(ST67_CHIP_EN_GPIO_Port, ST67_CHIP_EN_Pin, GPIO_PIN_SET);
HAL_Delay(ST67_BOOT_DELAY_MS); /* 500ms 等待模组启动 */
ST67_WakePulse(); /* PA15 高电平 5ms 唤醒脉冲 */
}
SPI 帧事务(st67w61.c 核心)
static int st67_spi_xfer(const uint8_t *tx_payload, uint16_t tx_len,
uint8_t type, uint16_t *rx_len)
{
uint8_t htx[8], hrx[8] = {0};
uint16_t slave_len = 0, n;
/* 组帧 */
htx[0] = 0x55; htx[1] = 0xAA; /* Magic */
htx[2] = tx_len & 0xFF; /* 长度低字节 */
htx[3] = tx_len >> 8; /* 长度高字节 */
htx[4] = 0x00; /* ver/flags */
htx[5] = type; /* 0=AT通道 */
cs_select();
/* 阶段1: 全双工交换帧头 */
HAL_SPI_TransmitReceive(&hspi1, htx, hrx, 8, ST67_XFER_TIMEOUT_MS);
/* 解析从机帧头: 校验Magic + 取从机payload长度 */
if (hrx[0] == 0x55 && hrx[1] == 0xAA)
slave_len = hrx[2] | (hrx[3] << 8);
else
/* 帧头错误 → 限流打印原始字节, 便于定位接线/极性问题 */
/* 阶段2: 按两侧长度较大值交换 payload */
n = (tx_len > slave_len) ? tx_len : slave_len;
if (n > 0)
HAL_SPI_TransmitReceive(&hspi1,
(tx_len > 0) ? (uint8_t*)tx_payload : s_dummy, /* 无发送时填0 */
s_rx, n, ST67_XFER_TIMEOUT_MS);
cs_release();
*rx_len = slave_len; /* 实际读到的从机数据长度 */
return 0;
}
AT 命令接口(st67w61.c)
int ST67_AT(const char *cmd, char *resp, uint16_t resp_size, uint32_t timeout_ms)
{
/* 1. 命令+CRLF 打包为 payload */
memcpy(s_tx, cmd, cmdlen);
s_tx[cmdlen++] = '\r'; s_tx[cmdlen++] = '\n';
/* 2. 保持唤醒并发送 */
ST67_WakeSet(1);
st67_spi_xfer(s_tx, cmdlen, ST67_TRAFFIC_AT, &rlen);
/* 3. 10ms 周期轮询, 收到的payload追加到resp并原样打印 */
while (未超时) {
got = append_text(resp, ...); /* 内部: 零长发送帧轮询读 */
if (strstr(resp, "OK")) return 1; /* 成功 */
if (strstr(resp, "ERROR")) return 0; /* 模组报错 */
HAL_Delay(10);
}
return -1; /* 超时 */
}
Wi-Fi 连接流程(main.c)c
static int app_wifi_join(void)
{
/* 1. AT 握手 (最多10次, 500ms超时) */
for (i = 0; i < 10; i++)
if (ST67_AT("AT", resp, sizeof(resp), 500) == 1) break;
/* 2. 模组信息 */
ST67_AT("AT+SDKINFO?", resp, sizeof(resp), 2000);
ST67_AT("AT+MACADDR?", resp, sizeof(resp), 2000);
/* 3. 连接 AP: SSID=Xiaomi 15, PWD=88888888 */
snprintf(cmd, sizeof(cmd), "AT+WJAP=\"%s\",\"%s\"", WIFI_SSID, WIFI_PASSWORD);
ret = ST67_AT(cmd, resp, sizeof(resp), 20000); /* 20s 超时 */
if (ret == 1) { /* 已连接 */ ST67_AT("AT+WJAP?", ...); return 0; }
return -1; /* 失败 → 主循环15s后重试 */
}
主循环(main.c)
while (1) {
/* 系统灯: 未连模组100ms快闪 / 连接中250ms / WiFi已连1s慢闪 */
if (now - led_next >= period) { toggle PB5; }
/* 200ms 轮询模组异步上报 (网络事件等) */
if (now - async_poll >= 200) ST67_PollAsync(...);
/* 断线 15s 自动重连 */
if (state == NO_LINK && now >= join_retry) app_wifi_join();
/* 5s 打印一次运行状态 */
app_print_status(); /* [APP] uptime=Xs state=CONNECTED */
}
日志输出(main.c)
/* printf 重定向到 USART2 (PA2=TX, 115200) */
int __io_putchar(int ch)
{
uint8_t c = (uint8_t)ch;
HAL_UART_Transmit(&huart2, &c, 1U, 100U);
return ch;
}
4.4 关键配置宏(st67w61.h)
宏 | 默认值 | 说明 |
|---|---|---|
| 1 | CS 高电平选中(按协议文档),异常时改 0 |
| 512 | 单帧最大 payload |
| 500 | 上电等待模组启动时间 |
| 200 | 单次 SPI 传输超时 |
| 0x00 | AT 命令流量类型 |
五、和ST67通讯


感谢得捷和电子森林的活动,这次尝试一个USB和无线射频在一个板子上的项目。