本文转载自iCEasy商城口碑评测作者:wx17604307949653
欢迎大家戳链接萤火工场 GD32VW553-IOT-V2使用TCP协议 + FreeRTOS控制IO与原贴作者互动交流哦~
视频链接
https://www.bilibili.com/video/BV1gyyoBREQB/?pop_share=1&vd_source=d1a538cfff71e9cd89ca0de1aeb0c0ff
前言
萤火工场 GD32VW553-IOT-V2开发板,160MHzRISCV核心,拥有WIFI6、蓝牙5.2等丰富外设的同时,还提供了各类RTOS的移植。本文用于记录SDK快速开发,实现TCP服务器的流程。
开源口碑分享内容
从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) {cshutdown(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" #改为你获取到开发板的IPSERVER_PORT = 4065# 创建TCP socketclient_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 当中打开如下窗口使能自动补全即可
|
|