GD32VW553 v2芯片 Wi-Fi 功能开发实践:SoftAP 及oled屏幕与按钮交互实现
分享作者:kkun
作者昵称:玉书前.
评测品牌:萤火工场
评测型号:GD32VW553-IOT-V2
发布时间:2025-10-09 10:56:25
1
前言
基于《GD32VW553 Wi-Fi 开发指南.pdf》(以下简称 “开发指南”)的 API 规范,本文以 “SoftAP 模式 + TCP 服务器 + 硬件交互” 为核心,结合 PB2 指示灯、PB11 按键、OLED 显示的实战开发,完整呈现 GD32VW553 芯片 Wi-Fi 功能的开发流程,所有代码均遵循开发指南定义的接口,确保兼容性与规范性。
开源口碑分享内容

开启正文前先来一个关于怎么使用msdk做该文章相关内容(wifi)开发的小教程大佬可以跳过~~~

先在 https://www.iceasy.com/cloud/RISC-V?pid=1907770165638025244 下载:

解压后获得以下内容:

打开GD32EmbeddedBuilder软件,依次点击左上角的    file->>open projects from file system

接下来点击directory找到刚刚下载的文件中的路径GD32VW55x_RELEASE_V1.0.3a\GD32VW55x_RELEASE_V1.0.3a\MSDK\examples\wifi\softap_tcp_server\Eclipse_project

最后点击finish即可导入项目

相关的oled代码在我的另一个测评中有说明 https://www.iceasy.com/review/1944795609719500802

导入oled相关代码到前面操作导入的项目中编译即可适用下文的代码了

好的接下来才是正文

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

一、开发基础:核心 API 与硬件资源梳理

在开发前需明确开发指南中的关键 API 与硬件资源映射关系,这是功能实现的核心依据

这款开发板相比前代增加了pb2口连接的led灯和pb11口连接的按钮,在本文中也进行测试使用

1.1 核心 API 选型(源自开发指南)

功能模块关键 API(开发指南章节)作用描述
SoftAP 管理wifi_management_ap_start(4.4.8 节)启动 SoftAP,支持配置 SSID、密码、信道、加密模式
wifi_management_ap_stop(4.4.10 节)停止 SoftAP,断开所有客户端连接
wifi_vif_is_softap(4.2.16 节)检测指定 VIF(虚拟接口)是否为 SoftAP 模式,判断 AP 启停状态
TCP 服务器LwIP 套接字 API(3.1 节)socket/bind/listen/accept/recv/send,实现 TCP 数据收发
RTOS 任务管理sys_task_create_dynamic(2.2.2 节)动态创建独立任务,避免单任务阻塞(如 TCP 与按键检测拆分)
sys_task_delete(2.2.4 节)删除任务,释放资源
系统延时sys_ms_sleep(2.4.3 节)任务级延时,释放 CPU 资源,符合 RTOS 调度逻辑

1.2 硬件资源定义

硬件接口功能映射关键配置(开发指南隐含 GPIO 逻辑)
PB2(输出)测试灯推挽输出模式,这边是做了一个定时翻转电平功能
PB11(输入)AP 启停切换按键上拉输入模式,按下时电平为低
OLED(I2C/SPI)信息显示显示 SSID、连接设备数、AP 状态(ok/false)

二、实战开发:分模块实现与代码解析

2.1 硬件初始化:GPIO 与 OLED 配置

2.1.1 PB2 指示灯与 PB11 按键初始化

遵循开发指南 “Low level 层外设操作” 逻辑(1.1 节),先使能 GPIO 时钟,再配置引脚模式:

#include "gd32vw55x_gpio.h"

#include "gd32vw55x_rcu.h"


// PB2 指示灯初始化(推挽输出)

static void pb2_led_init(void) {

   rcu_periph_clock_enable(RCU_GPIOB);  // 使能 GPIOB 时钟

   gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_2);  // 推挽输出

   gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_2);

   gpio_bit_reset(GPIOB, GPIO_PIN_2);  // 初始灭灯

}


// PB11 按键初始化(上拉输入)

static void pb11_key_init(void) {

   rcu_periph_clock_enable(RCU_GPIOB);

   gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_PIN_11);  // 上拉输入

}


// 按键扫描(可带消抖)

uint8_t key_scan(void) {

static uint8_t key_up = 1; // 按键松开标志

if(key_up && (gpio_input_bit_get(GPIOB, GPIO_PIN_11) == 0)) {

// delay_1ms(1); // 消抖

if(gpio_input_bit_get(GPIOB, GPIO_PIN_11) == 0) {

key_up = 0;

return 1; // 按键按下

}

} else if(gpio_input_bit_get(GPIOB, GPIO_PIN_11) == 1) {

key_up = 1; // 按键松开

}

return 0;

}

2.1.2 OLED 初始化与显示函数

OLED 初始化需确保 I2C/SPI 引脚配置正确,显示逻辑需适配开发指南中 “任务内周期性刷新” 的要求使用rtos实现oled显示的任务调度:

static void oled_display_task(void *param) {

OLED_Init();

char *state_str;

char count_str[16];

uint8_t connected_sta_num;

gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_2);

gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_2);

while (1) {

state_str = (g_softap_enabled== 0) ? "false" : "ok";

connected_sta_num = get_ap_connected_sta_num();

sprintf(count_str, "%d", connected_sta_num);


OLED_Clear();

OLED_ShowString(10, 5, "AP:", OLED_8X16);

OLED_ShowString(40, 5, SSID, OLED_8X16);

OLED_ShowString(10, 25, "STA COUNT:", OLED_8X16);

OLED_ShowString(90, 25, count_str, OLED_8X16);

OLED_ShowString(10, 45, "STATE:", OLED_8X16);

OLED_ShowString(65, 45, state_str, OLED_8X16);

OLED_Update();

gpio_bit_toggle(GPIOB, GPIO_PIN_2);

vTaskDelay(pdMS_TO_TICKS(1000)); // 依赖FreeRTOS,需确保包含task.h

}

}

2.2 Wi-Fi 功能实现:SoftAP 与连接设备检测

2.2.1 SoftAP 启动与停止

严格使用开发指南 4.4 节 API,配置 SSID 为 “GD32VW553_AP”,密码为 “12345678”,信道 11,用rtos实现ap的任务调度:

static void softap_tcp_server_task(void *param) {

int ret = 0;

char *ssid = SSID;

char *password = PASSWORD;

uint8_t channel = 11, is_hidden = 0;

wifi_ap_auth_mode_t auth_mode = AUTH_MODE_WPA2_WPA3;


// -------------------------- 初始化 PB11 按键--------------------------

rcu_periph_clock_enable(RCU_GPIOB); // 使能 GPIOB 时钟

gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_PIN_11); // 上拉输入


// -------------------------- 初始启动 SoftAP --------------------------

if (ssid == NULL) {

printf("ssid can not be NULL!\r\n");

goto exit;

}

if (password && (strlen(password) == 0)) {

password = NULL;

auth_mode = AUTH_MODE_OPEN; // 无密码时为开放模式

}


// 初始启动 SoftAP(文档 API:wifi_management_ap_start)

printf("Start Wi-Fi softap.\r\n");

ret = wifi_management_ap_start(ssid, password, channel, auth_mode, is_hidden);

if (ret != 0) {

printf("Wi-Fi softap start failed.\r\n");

g_softap_enabled = 0; // 启动失败,标记 AP 关闭

goto exit;

} else {

printf("SoftAP:%s successfully started!\r\n", ssid);

g_softap_enabled = 1; // 启动成功,标记 AP 开启

}


// -------------------------- 按键检测与 AP 开关切换 --------------------------

while (1) {

// 检测 PB11 按键按下(调用 key_scan 函数)

if (key_scan() == 1) {

printf("PB11 key pressed, toggle AP state...\r\n");


// 获取当前 AP 状态(基于文档 API:wifi_vif_is_softap)

//g_softap_enabled = get_softap_state();

if (g_softap_enabled == 1) {

// 情况1:AP 已开启 → 关闭 AP

ret = wifi_management_ap_stop();

if (ret == 0) {

printf("SoftAP stopped successfully!\r\n");

g_softap_enabled = 0; // 标记 AP 关闭

// 关闭 AP 后,停止 TCP 服务器

// (若需重新开启 AP 时重启 TCP,可在此处清理 TCP 资源)

} else {

printf("SoftAP stop failed! Error code: %d\r\n", ret);

}

} else {

// 情况2:AP 已关闭 → 重新开启 AP(文档 API:wifi_management_ap_start)

ret = wifi_management_ap_start(ssid, password, channel, auth_mode, is_hidden);

if (ret == 0) {

printf("SoftAP restarted successfully!\r\n");

g_softap_enabled = 1; // 标记 AP 开启

// 重新开启 AP 后,重启 TCP 服务器

//tcp_server_test();//这个是tcp服务器程序启动代码,这边和按钮开关ap功能冲突了所以注释掉,有大佬可以解决的话可以删掉最左侧的注释符

} else {

printf("SoftAP restart failed! Error code: %d\r\n", ret);

}

}

}


// 延时 50ms,避免频繁检测占用 CPU(文档 RTOS 任务调度推荐)

vTaskDelay(pdMS_TO_TICKS(50));

}


// -------------------------- 清理逻辑 --------------------------

exit:

printf("the test has ended.\r\n");

// 退出前关闭 AP(文档推荐:资源需手动释放)

if (g_softap_enabled == 1) {

wifi_management_ap_stop();

}

sys_task_delete(NULL);

}

2.2.2 连接设备数检测

基于开发指南 5.3 节 “启动 SoftAP” 示例,使用 macif_vif_ap_assoc_info_get 获取客户端 MAC 地址,统计设备数:

// 获取 SoftAP 已连接的客户端数量

static uint8_t get_ap_connected_sta_num(void) {

// 存储客户端MAC地址:CFG_STA_NUM个客户端,每个MAC占6字节

uint8_t cli_mac[CFG_STA_NUM][6] = {0};

int vif_idx = 0; // SoftAP默认VIF序号为0(文档隐含)

int cli_count = 0; // 实际连接的客户端数量


// 调用函数:仅传2个参数(VIF序号 + MAC缓冲区指针)

cli_count = macif_vif_ap_assoc_info_get(

vif_idx, // 参数1:SoftAP的VIF序号

(uint16_t *)cli_mac // 参数2:MAC缓冲区(强制转换为uint16_t*匹配声明)

);


// (可选)打印客户端MAC和IP(修正指针类型)

for (int i = 0; i < cli_count; i++) {

// 参数改为 uint8_t* 类型,匹配 dhcpd_find_ipaddr_by_macaddr 要求

uint32_t client_ip = dhcpd_find_ipaddr_by_macaddr(cli_mac[i]);

printf("Client[%d]: MAC=%02X:%02X:%02X:%02X:%02X:%02X, IP=%d.%d.%d.%d\r\n",

i,

cli_mac[i][0], cli_mac[i][1], cli_mac[i][2],

cli_mac[i][3], cli_mac[i][4], cli_mac[i][5],

(client_ip >> 0) & 0xFF, (client_ip >> 8) & 0xFF,

(client_ip >> 16) & 0xFF, (client_ip >> 24) & 0xFF);

}


// 确保返回值为uint8_t(客户端数量不会超过CFG_STA_NUM,通常≤8)

return (cli_count > CFG_STA_NUM) ? CFG_STA_NUM : (uint8_t)cli_count;

}

2.3 TCP 服务器实现:独立任务设计

遵循开发指南 2.2 节 “任务功能拆分” 原则,将 TCP 服务器封装为独立任务,避免阻塞按键检测与 OLED 刷新:

static void tcp_server_test(void)

{

int listen_fd = -1, ret, reuse, idx;

struct sockaddr_in server_addr;

int cli_fd[TCP_SERVER_LISTEN_NUM];

struct sockaddr_in client_addr;

uint8_t cli_count = 0;

char recv_buf[128];

socklen_t len;

struct timeval timeout;

fd_set read_set;

int max_fd_num = 0;


listen_fd = socket(AF_INET, SOCK_STREAM, 0);

if (listen_fd < 0) {

printf("Create tcp server socket fd error!\r\n");

goto exit;

}

printf("Create tcp server, fd: %d, port: %u.\r\n", listen_fd, TCP_SERVER_LISTEN_PORT);


reuse = 1;

setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse, sizeof(reuse));

sys_memset(&server_addr, 0, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_len = sizeof(server_addr);

server_addr.sin_port = htons(TCP_SERVER_LISTEN_PORT);

server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

ret = bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));

if(ret < 0) {

printf("Bind tcp server socket fd error!\r\n");

goto exit;

}


ret = listen(listen_fd, TCP_SERVER_LISTEN_NUM);

if(ret != 0) {

printf("Listen tcp server socket fd error!\r\n");

goto exit;

}


for (idx = 0; idx < TCP_SERVER_LISTEN_NUM; idx++)

cli_fd[idx] = -1;


timeout.tv_sec = 1;

timeout.tv_usec = 0;

len = sizeof(struct sockaddr);

while (1) {

FD_ZERO(&read_set);

for (idx = 0; idx < TCP_SERVER_LISTEN_NUM; idx++) {

if (cli_fd[idx] > 0) {

FD_SET(cli_fd[idx], &read_set);

if (cli_fd[idx] > max_fd_num)

max_fd_num = cli_fd[idx];

}

}

if (cli_count < TCP_SERVER_LISTEN_NUM) {

FD_SET(listen_fd, &read_set);

if (listen_fd > max_fd_num)

max_fd_num = listen_fd;

}


select(max_fd_num + 1, &read_set, NULL, NULL, &timeout);


if (FD_ISSET(listen_fd, &read_set)) {

for (idx = 0; idx < TCP_SERVER_LISTEN_NUM; idx++) {

if (cli_fd[idx] == -1) {

break;

}

}

if (idx == TCP_SERVER_LISTEN_NUM) {

printf("cli count error!\r\n");

goto exit;

}

cli_fd[idx] = accept(listen_fd, (struct sockaddr *)&client_addr, (socklen_t *)&len);

if (cli_fd[idx] < 0) {

if (errno != EAGAIN)

printf("accept error. %d\r\n", errno);

if (errno == EBADF) {

goto exit;

}

for (idx = 0; idx < TCP_SERVER_LISTEN_NUM; idx++) {

if (cli_fd[idx] != -1 && FD_ISSET(cli_fd[idx], &read_set))

break;

}

if (idx == TCP_SERVER_LISTEN_NUM) {

continue;

}

} else {

printf("Add tcp client, fd: %d.\r\n", cli_fd[idx]);

cli_count++;

FD_SET(cli_fd[idx], &read_set);

if (cli_fd[idx] > max_fd_num)

max_fd_num = cli_fd[idx];

}

}


for (idx = 0; idx < TCP_SERVER_LISTEN_NUM; idx++) {

sys_memset(recv_buf, 0, 128);

if (cli_fd[idx] == -1)

continue;

if (FD_ISSET(cli_fd[idx], &read_set)) {

ret = recv(cli_fd[idx], recv_buf, 128, 0);

if (ret == 0) {

printf("remote close, from client, fd: %d.\r\n", cli_fd[idx]);

goto remove_client;

} else if (ret > 0) {

printf("recv:[%s], from client, fd: %d.\r\n", recv_buf, cli_fd[idx]);

} else {

if (errno == EAGAIN) {

continue;

} else if (errno == EBADF) {

printf("rev error: %d, from client, fd: %d.\r\n", errno, cli_fd[idx]);

goto exit;

} else {

printf("rev error: %d, from client, fd: %d.\r\n", errno, cli_fd[idx]);

goto remove_client;

}

}


ret = send(cli_fd[idx], recv_buf, strlen(recv_buf), 0);

if (ret <= 0) {

printf("send error: %d, send to client, fd: %d.\r\n", errno, cli_fd[idx]);

goto remove_client;

}

}

continue;

remove_client:

printf("Remove tcp client, fd: %d.\r\n", cli_fd[idx]);

shutdown(cli_fd[idx], SHUT_RD);

close(cli_fd[idx]);

cli_fd[idx] = -1;

cli_count--;

}

}


exit:

printf("tcp server has closed.\r\n");

for (idx = 0; idx < TCP_SERVER_LISTEN_NUM; idx++) {

if (cli_fd[idx] != -1) {

shutdown(cli_fd[idx], SHUT_RD);

close(cli_fd[idx]);

}

}

if (listen_fd > -1) {

shutdown(listen_fd, SHUT_RD);

close(listen_fd);

}

}

2.4 主任务:硬件交互与功能协同

主任务负责整合所有模块,实现 “按键控制 AP 启停 + 指示灯闪烁 + OLED 实时显示” 的完整逻辑:

int main(void)

{

platform_init();

if (wifi_init()) {

printf("wifi init failed.\r\n");

}

// 创建 TCP 服务器任务

sys_task_create_dynamic(

(const uint8_t *)"softap tcp server",

4096,

OS_TASK_PRIORITY(0),

softap_tcp_server_task,

NULL

);

// 创建 OLED 显示任务

sys_task_create_dynamic(

(const uint8_t *)"oled display",

2048, // 栈空间

OS_TASK_PRIORITY(1), // 优先级可与 TCP 任务相同或略低

oled_display_task,

NULL

);

// 启动操作系统

sys_os_start();

}

三、功能验证:预期效果与 API 合规性

3.1 硬件交互效果

PB2 指示灯:

上电后 AP 启动,PB2 灯开始闪烁;按下 PB11 按键,AP 关闭;再次按下,AP开启

PB11 按键:

短按(<1s)切换 AP 状态,可以自定义消抖,无误触发;长按不影响逻辑,仅识别一次按下。

OLED 显示:

固定显示 SSID “test_ap”;

“AP STATE” 栏显示 “ok”(开启)或 “false”(关闭);

“STA COUNT” 栏实时显示连接设备数(0~8),设备连接 / 断开时立即更新。

3.2 Wi-Fi 与 TCP 功能效果

SoftAP 功能:

手机 / 电脑可搜索到 “test_ap”,输入密码 “12345678” 成功连接;

连接设备数超过 8 时,新设备无法接入(符合开发指南 SoftAP 最大容量)。

TCP 功能:

使用 TCP 调试工具连接 192.168.4.1:4065(AP 默认网关),发送数据后可收到回显;

AP 关闭时 TCP 服务器停止,调试工具提示 “连接断开”;AP 重启后需重新连接。

3.3 API 合规性验证

所有功能实现均基于开发指南定义的 API,无文档外私有接口:

Wi-Fi 操作:wifi_management_ap_start/wifi_management_ap_stop(4.4 节);

任务管理:sys_task_create_dynamic/sys_task_delete(2.2 节);

网络操作:LwIP 套接字 API(3.1 节);

系统延时:sys_ms_sleep(2.4.3 节)。

四、开发总结:关键经验与注意事项

任务拆分原则:

遵循开发指南 2.2 节,将 TCP 服务器、按键检测、OLED 刷新拆分为独立逻辑(或任务),避免单任务阻塞,这是解决 “按键无响应” 的核心(如前期调试中 TCP 阻塞按键检测的问题)。

资源清理规范:

停止 AP 时需同步删除 TCP 任务、关闭套接字(开发指南 3.1 节),避免端口占用导致后续启动失败。

通过以上开发流程,可基于 GD32VW553 芯片快速实现 “SoftAP + TCP + 硬件交互” 的 Wi-Fi 应用,所有代码均遵循《GD32VW553 Wi-Fi 开发指南.pdf》规范,具备良好的可移植性与稳定性。


因为稿子上传日期是2025/10/6 在这里祝大家中秋国庆节快乐!!!

全部评论
暂无评论
0/144