从ICEasy获取开发套件
需要下载的内容有
- GD32embededbulider (基于eclipse的IDE)
- GD32AllInOneProgrammer (串口下载软件)
- GD32VW55x_RELEASE_V1.0.3a (SDK)

导入TCP模板
打开IDE,在左上角菜单中依次找到
File -> Open Projects From System
随后按照如下所示导入模板内容

本文作者存储的文件路径为"H:\GD32\GD32VW55x_RELEASE_V1.0.3a\MSDK\examples\wifi\softap_tcp_server\Eclipse_project"
导入成功后,左侧菜单出现项目内容,选择当前项目后编译,确保环境正确。

编译产物位于"H:\GD32\GD32VW55x_RELEASE_V1.0.3a\MSDK\examples\wifi\softap_tcp_server\Eclipse_project\softap_tcp_server\softap_tcp_server.bin"
添加LED翻转代码逻辑
在main.c开头添加IO初始化(PB2、推挽)
/* enable GPIOB clock */
rcu_periph_clock_enable(RCU_GPIOB);
/* configure PB2 as output */
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_2);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_2);
/* set PB2 low (optional, similar to LED off) */
gpio_bit_reset(GPIOB, GPIO_PIN_2);定义二值信号量、创建RTOS线程函数
// 模板代码
// 定义信号量
os_sema_t TCP_Bin;
// 模板代码
static void tcp_recv_task(void *param) // 获取信号量,当信号量被give,触发IO电平翻转
{
while (1) {
if (sys_sema_down(&TCP_Bin, -1) == OS_OK) { // 无限等待信号量
printf("Received Toggle signal, toggle LED\r\n");
gpio_bit_toggle(GPIOB, GPIO_PIN_2);
}
}
}
//模板代码
int main(void)
{
/* enable GPIOB clock */
rcu_periph_clock_enable(RCU_GPIOB);
/* configure PB2 as output */
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_2);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_2);
/* set PB2 low (optional, similar to LED off) */
gpio_bit_reset(GPIOB, GPIO_PIN_2);
int32_t ret = sys_sema_init(&TCP_Bin, 0); // 创建二值信号量
if (ret != OS_OK) {
printf("Semaphore init failed.\r\n");
return -1;
}
platform_init();
if (wifi_init()) {
printf("wifi init failed.\r\n");
return -1;
}
sys_task_create_dynamic((const uint8_t *)"softap tcp server", 4096, OS_TASK_PRIORITY(0), softap_tcp_server_task, NULL);
sys_task_create_dynamic((const uint8_t *)"tcp_recv", 1024, OS_TASK_PRIORITY(1), tcp_recv_task, NULL);
sys_os_start();
for (;;) ;
}
修改TCP业务逻辑
如下修改tcp_server_test函数使得TCP服务器接收到"Toggle"的时候give一个信号量
在这里freertos底层API被宏封装了,得用官方API进行任务和信号量创建,以及信号量的give和take也改变了,详情请看代码内容
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]);
// 信号处理逻辑
if (strcmp(recv_buf, "Toggle") == 0) {
sys_sema_up(&TCP_Bin); // 给信号量
}
} 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) {c
shutdown(listen_fd, SHUT_RD);
close(listen_fd);
}
}设置log输出串口
文件和宏如下图修改,将CONFIG_BOARD 改为 PLATFORM_BOARD_32VW55XF527
并且将log端口改为USART0 (即连接CH340的串口)

编译并烧录到开发板当中
- 开发板boot1设置为on
- 开发板通电
- 使用GD32AllInOneProgrammer 选择编译出的.bin文件进行烧录
- 开发板boot1拨回
- 按下K1进行reset
网络连接
烧录成功后,打开电脑wifi网卡,可见以“test_ap"为默认名称的ap信号。

SSID和PSWD由代码内容的宏定义

功能测试
将开发板typec口连接计算机,打开对应com口,波特率默认115200,查看输出日志
输出内容包含文件描述符、IP地址、设备连接等信息

随后编写如下程序,在电脑运行python程序,向网关(即开发板)发送数据包
import socket
# 服务器IP和端口
SERVER_IP = "192.168.237.1" #改为你获取到开发板的IP
SERVER_PORT = 4065
# 创建TCP socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器
try:
client_socket.connect((SERVER_IP, SERVER_PORT))
print("Connected to server")
# 发送数据
message = "Toggle"
client_socket.send(message.encode())
# 接收回显数据
response = client_socket.recv(1024).decode()
print(f"Received: {response}")
except Exception as e:
print(f"Error: {e}")
finally:
client_socket.close()实验结果表明 每次运行python程序都会使得LED亮灭
自动补全插件分享
研究了好久IDE的自动补全,发现GD32的IDE和stm32的cubeIDE一样都是基于eclipse,试了一下当时给后者配补全插件的方法,下载对应.jar文件放入"H:\GD32\GD32EmbeddedBuilder_v1.5.4_Rel\GD32EmbeddedBuilder\plugins"后,在IDE上方菜单的window -> preferences 当中打开如下窗口使能自动补全即可
通过网盘分享的文件:org.eclipse.cdt.ui_8.1.200.202310201538.jar 链接: https://pan.baidu.com/s/1PP9if9vBKtNLpVz6i2Vfrg?pwd=1145 提取码: 1145
链接失效请移步 : https://blog.csdn.net/wyn3514/article/details/139274725

碎碎念
楼主第一次发测评,如果有什么没讲明白和不妥的地方,请各位指出,感激不尽,本人小菜鸡一个,轻喷,谢谢喵
最后感谢ICEasy商城的大力支持,希望咱们的国产芯片越做越好!

