TA的每日心情 | 开心 昨天 08:20 |
---|
签到天数: 303 天 连续签到: 34 天 [LV.8]以坛为家I
|
【实验目的】
1、在freertos上移植lwip
2、创建tcpclient客户端。
3、实现对服务器返回的报文进行解析,如果符合指定的命令,测对开发板上的LED灯进开与关。
【实验环境】
1、win11+stm32cubeIDE
2、网络调试助手。
【实现步骤】
1、在前面搭建好的lwip的工程下面继续开展调试。【STM32H735-DK 测评】手工配置LWIP - 板卡试用 - 与非网 (eefocus.com)
2、打开stm32CubeMAX,打开freertos,选择CMSIS v2版(因为要与以后的TouchGFX一至),修改
MINIMAL_STACK_SIZE为256words。
3、将freertos的stack设置为1024。
4、生成代码后,删除原来的在main.c的主循环的MX_LWIP_Process();,编译代码并下载到开发板,ping一下开发板,可以顺利的拼通,说明我们在freertos上面移植lwip成功了。
5、在Core/inc目录下面新建tcpclien.h文件,内容如下:
- /*
- * tcpclient.h
- *
- * Created on: Mar 17, 2024
- * Author: liujianhua
- */
- #ifndef INC_TCPCLIENT_H_
- #define INC_TCPCLIENT_H_
- #define TCP_CLIENT_PORT 5001
- void TCP_Client_Init(void);
- #endif /* INC_TCPCLIENT_H_ */
复制代码 内容主要是定义一下服务器的监听端口为5001,同时声明一下TCP_Client_Init函数。
6、在Core/src下面新建tcpclient.c文件。代码如下:
- /*
- * tcpclinet.c
- *
- * Created on: Mar 17, 2024
- * Author: liujianhua
- */
- #include "lwip/netif.h"
- #include "lwip/ip.h"
- #include "lwip/tcp.h"
- #include "lwip/init.h"
- #include "netif/etharp.h"
- #include "lwip/udp.h"
- #include "lwip/pbuf.h"
- #include <stdio.h>
- #include <string.h>
- #include "main.h"
- uint8_t send_buf_led1on[] = "led1on\n";
- uint8_t send_buf_led2on[] = "led2on\n";
- uint8_t send_buf_led1off[] = "led1off\n";
- uint8_t send_buf_led2off[] = "led2off\n";
- uint8_t send_buf_err[] = "errcmd\n";
- static void client_err(void *arg, err_t err) //出现错误时调用这个函数,打印错误信息,并尝试重新连接
- {
- printf("连接错误!!\n");
- printf("尝试重连!!\n");
- //连接失败的时候释放TCP控制块的内存
- printf("关闭连接,释放TCP控制块内存\n");
- //tcp_close(client_pcb);
- //重新连接
- printf("重新初始化客户端\n");
- TCP_Client_Init();
- }
- static err_t client_send(void *arg, struct tcp_pcb *tpcb) //发送函数,调用了tcp_write函数
- {
- uint8_t send1_buf[]= "我是客户端,这里是与非网STM32H735DK测试\n";
- //发送数据到服务器
- tcp_write(tpcb, send1_buf, sizeof(send1_buf), 1);
- return ERR_OK;
- }
- static err_t client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
- {
- if (p != NULL)
- {
- /* 接收数据*/
- tcp_recved(tpcb, p->tot_len);
- printf("收到:%s 长度为:%d\n",p->payload,p->tot_len);
- if((p->tot_len) == 7 )
- {
- if(strncmp("LED1OFF",p->payload,p->tot_len) == 0)
- {
- HAL_GPIO_WritePin(USER_LED1_GPIO_Port, USER_LED1_Pin, GPIO_PIN_SET);
- tcp_write(tpcb, send_buf_led1off, sizeof(send_buf_led1off), 1);
- }
- else if(strncmp("LED2OFF",p->payload,p->tot_len) == 0)
- {
- HAL_GPIO_WritePin(USER_LED2_GPIO_Port, USER_LED2_Pin, GPIO_PIN_SET);
- tcp_write(tpcb, send_buf_led2off, sizeof(send_buf_led2off), 1);
- }
- }
- else if((p->tot_len) == 6)
- {
- if(strncmp("LED1ON",p->payload,p->tot_len) == 0)
- {
- HAL_GPIO_WritePin(USER_LED1_GPIO_Port, USER_LED1_Pin, GPIO_PIN_RESET);
- tcp_write(tpcb, send_buf_led1on, sizeof(send_buf_led1on), 1);
- }
- else if(strncmp("LED2ON",p->payload,p->tot_len) == 0)
- {
- HAL_GPIO_WritePin(USER_LED1_GPIO_Port, USER_LED2_Pin, GPIO_PIN_RESET);
- tcp_write(tpcb, send_buf_led2on, sizeof(send_buf_led2on), 1);
- }
- }
- else
- {
- tcp_write(tpcb, send_buf_err, sizeof(send_buf_err), 1);
- }
- /* 返回接收到的数据*/
- memset(p->payload, 0 , p->tot_len);
- pbuf_free(p);
- }
- else if (err == ERR_OK)
- {
- //服务器断开连接
- printf("服务器断开连接!\n");
- tcp_close(tpcb);
- //重新连接
- TCP_Client_Init();
- }
- return ERR_OK;
- }
- static err_t client_connected(void *arg, struct tcp_pcb *pcb, err_t err)
- {
- printf("connected ok!\n");
- //注册一个周期性回调函数
- tcp_poll(pcb,client_send,2);
- //注册一个接收函数
- tcp_recv(pcb,client_recv);
- return ERR_OK;
- }
- void TCP_Client_Init(void)
- {
- struct tcp_pcb *client_pcb = NULL; //这一句一定要放在里面,否则会没用
- ip4_addr_t server_ip; //因为客户端要主动去连接服务器,所以要知道服务器的IP地址
- /* 创建一个TCP控制块 */
- client_pcb = tcp_new();
- IP4_ADDR(&server_ip, DEST_IP_ADDR0,DEST_IP_ADDR1,DEST_IP_ADDR2,DEST_IP_ADDR3);//合并IP地址
- printf("客户端开始连接!\n");
- //开始连接
- tcp_connect(client_pcb, &server_ip, TCP_CLIENT_PORT, client_connected);
- ip_set_option(client_pcb, SOF_KEEPALIVE);
- printf("已经调用了tcp_connect函数\n");
- //注册异常处理
- tcp_err(client_pcb, client_err);
- printf("已经注册异常处理函数\n");
- }
- <font size="4">
- </font>
复制代码 代码中我们主要我们第一是编写TCP_Client_Init函数,函数中我们第一是创建client_pcb的TCP控制块,然后将服务器的IP地址合并到serveip上面。然后使用tcp_connect连接到服务器的IP以及端口中。使用ip_set_option激活这个控制块。最后注册一个异常回调函数client_err。
接着我们在client_connected的函数中,注册周期回调函数client_send,以及一个接收回调函数client_rcv。
在周期回函数中,我们一直向服务端发送一串字符串。
在接收回调函数中,我们先判断是否是我们指定的命令,如果是,则接执对应的LED开关命令。
接着把tcpclient.h放到Main.h头文件中引用,并在main.h中填入服务器的IP地址:
- /* Private includes ----------------------------------------------------------*/
- /* USER CODE BEGIN Includes */
- #include "tcpclient.h"
- /* USER CODE END Includes */
- /* Exported types ------------------------------------------------------------*/
- /* USER CODE BEGIN ET */
- //服务器IP地址
- #define DEST_IP_ADDR0 192
- #define DEST_IP_ADDR1 168
- #define DEST_IP_ADDR2 3
- #define DEST_IP_ADDR3 156
- <font size="4">/* USER CODE END ET */</font>
复制代码 在freertos.c的任务中,添加tcpclient_init。
- /* USER CODE END Header_StartDefaultTask */
- void StartDefaultTask(void *argument)
- {
- /* init code for LWIP */
- MX_LWIP_Init();
- /* USER CODE BEGIN StartDefaultTask */
- TCP_Client_Init();
- /* Infinite loop */
- for(;;)
- {
- osDelay(1);
- }
- /* USER CODE END StartDefaultTask */
- }
- /* Private application code --------------------------------------------------*/
- /* USER CODE BEGIN Application */
复制代码 编译下载到开发板,然后打开TCP调试助手,开启一个端口为5001的监听服务器。我们在输入LED1ON、LED2ON、LED1OFF、LED2OFF时,开发板上的两个用户灯会按要求进行亮与灭:
到此,我们就完成了TCP远程对开发板的LED的控制。
【总结】
在stm32CubeMAX这个可视化的配置工具中,我们很轻易的就完成了所需要的功能,编写的代码也非常少。
|
|