回答

收藏

[评测分享] 【STM32H735-DK 测评】基于LWIP的TCP远程控制LED

#板卡评测 #板卡评测 246702 人阅读 | 0 人回复 | 2024-03-18

【实验目的】
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文件,内容如下:
  1. /*
  2. * tcpclient.h
  3. *
  4. *  Created on: Mar 17, 2024
  5. *      Author: liujianhua
  6. */

  7. #ifndef INC_TCPCLIENT_H_
  8. #define INC_TCPCLIENT_H_

  9. #define TCP_CLIENT_PORT 5001

  10. void TCP_Client_Init(void);

  11. #endif /* INC_TCPCLIENT_H_ */
复制代码
内容主要是定义一下服务器的监听端口为5001,同时声明一下TCP_Client_Init函数。
6、在Core/src下面新建tcpclient.c文件。代码如下:
  1. /*
  2. * tcpclinet.c
  3. *
  4. *  Created on: Mar 17, 2024
  5. *      Author: liujianhua
  6. */

  7. #include "lwip/netif.h"
  8. #include "lwip/ip.h"
  9. #include "lwip/tcp.h"
  10. #include "lwip/init.h"
  11. #include "netif/etharp.h"
  12. #include "lwip/udp.h"
  13. #include "lwip/pbuf.h"
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include "main.h"

  17. uint8_t send_buf_led1on[] = "led1on\n";
  18. uint8_t send_buf_led2on[] = "led2on\n";

  19. uint8_t send_buf_led1off[] = "led1off\n";
  20. uint8_t send_buf_led2off[] = "led2off\n";
  21. uint8_t send_buf_err[] = "errcmd\n";

  22. static void client_err(void *arg, err_t err)       //出现错误时调用这个函数,打印错误信息,并尝试重新连接
  23. {
  24.   printf("连接错误!!\n");
  25.         printf("尝试重连!!\n");

  26.   //连接失败的时候释放TCP控制块的内存
  27.         printf("关闭连接,释放TCP控制块内存\n");
  28.   //tcp_close(client_pcb);


  29.   //重新连接
  30.         printf("重新初始化客户端\n");
  31.         TCP_Client_Init();

  32. }


  33. static err_t client_send(void *arg, struct tcp_pcb *tpcb)   //发送函数,调用了tcp_write函数
  34. {
  35.   uint8_t send1_buf[]= "我是客户端,这里是与非网STM32H735DK测试\n";

  36.   //发送数据到服务器
  37.   tcp_write(tpcb, send1_buf, sizeof(send1_buf), 1);

  38.   return ERR_OK;
  39. }

  40. static err_t client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
  41. {

  42.   if (p != NULL)
  43.   {
  44.     /* 接收数据*/
  45.     tcp_recved(tpcb, p->tot_len);
  46.     printf("收到:%s 长度为:%d\n",p->payload,p->tot_len);
  47.     if((p->tot_len) == 7 )
  48.     {
  49.             if(strncmp("LED1OFF",p->payload,p->tot_len) == 0)
  50.             {
  51.                     HAL_GPIO_WritePin(USER_LED1_GPIO_Port, USER_LED1_Pin, GPIO_PIN_SET);
  52.                     tcp_write(tpcb, send_buf_led1off, sizeof(send_buf_led1off), 1);
  53.             }
  54.             else if(strncmp("LED2OFF",p->payload,p->tot_len) == 0)
  55.             {
  56.                     HAL_GPIO_WritePin(USER_LED2_GPIO_Port, USER_LED2_Pin, GPIO_PIN_SET);
  57.                     tcp_write(tpcb, send_buf_led2off, sizeof(send_buf_led2off), 1);
  58.             }
  59.     }
  60.     else if((p->tot_len) == 6)
  61.     {
  62.             if(strncmp("LED1ON",p->payload,p->tot_len) == 0)
  63.             {
  64.                     HAL_GPIO_WritePin(USER_LED1_GPIO_Port, USER_LED1_Pin, GPIO_PIN_RESET);
  65.                     tcp_write(tpcb, send_buf_led1on, sizeof(send_buf_led1on), 1);
  66.             }
  67.             else if(strncmp("LED2ON",p->payload,p->tot_len) == 0)
  68.             {
  69.                     HAL_GPIO_WritePin(USER_LED1_GPIO_Port, USER_LED2_Pin, GPIO_PIN_RESET);
  70.                     tcp_write(tpcb, send_buf_led2on, sizeof(send_buf_led2on), 1);
  71.             }
  72.     }
  73.     else
  74.     {
  75.             tcp_write(tpcb, send_buf_err, sizeof(send_buf_err), 1);
  76.     }
  77.     /* 返回接收到的数据*/
  78.     memset(p->payload, 0 , p->tot_len);
  79.     pbuf_free(p);
  80.   }
  81.   else if (err == ERR_OK)
  82.   {
  83.     //服务器断开连接
  84.     printf("服务器断开连接!\n");
  85.     tcp_close(tpcb);

  86.     //重新连接
  87.     TCP_Client_Init();
  88.   }
  89.   return ERR_OK;
  90. }

  91. static err_t client_connected(void *arg, struct tcp_pcb *pcb, err_t err)
  92. {
  93.   printf("connected ok!\n");

  94.   //注册一个周期性回调函数
  95.   tcp_poll(pcb,client_send,2);

  96.   //注册一个接收函数
  97.   tcp_recv(pcb,client_recv);

  98.   return ERR_OK;
  99. }


  100. void TCP_Client_Init(void)
  101. {
  102.         struct tcp_pcb *client_pcb = NULL;   //这一句一定要放在里面,否则会没用
  103.   ip4_addr_t server_ip;     //因为客户端要主动去连接服务器,所以要知道服务器的IP地址
  104.   /* 创建一个TCP控制块  */
  105.   client_pcb = tcp_new();

  106.   IP4_ADDR(&server_ip, DEST_IP_ADDR0,DEST_IP_ADDR1,DEST_IP_ADDR2,DEST_IP_ADDR3);//合并IP地址

  107.   printf("客户端开始连接!\n");

  108.   //开始连接
  109.   tcp_connect(client_pcb, &server_ip, TCP_CLIENT_PORT, client_connected);
  110.         ip_set_option(client_pcb, SOF_KEEPALIVE);

  111.         printf("已经调用了tcp_connect函数\n");

  112.   //注册异常处理
  113.   tcp_err(client_pcb, client_err);
  114.         printf("已经注册异常处理函数\n");
  115. }
  116. <font size="4">
  117. </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地址:
  1. /* Private includes ----------------------------------------------------------*/
  2. /* USER CODE BEGIN Includes */
  3. #include "tcpclient.h"
  4. /* USER CODE END Includes */

  5. /* Exported types ------------------------------------------------------------*/
  6. /* USER CODE BEGIN ET */
  7. //服务器IP地址
  8. #define DEST_IP_ADDR0    192
  9. #define DEST_IP_ADDR1    168
  10. #define DEST_IP_ADDR2      3
  11. #define DEST_IP_ADDR3    156
  12. <font size="4">/* USER CODE END ET */</font>
复制代码
在freertos.c的任务中,添加tcpclient_init。
  1. /* USER CODE END Header_StartDefaultTask */
  2. void StartDefaultTask(void *argument)
  3. {
  4.   /* init code for LWIP */
  5.   MX_LWIP_Init();
  6.   /* USER CODE BEGIN StartDefaultTask */
  7.   TCP_Client_Init();
  8.   /* Infinite loop */
  9.   for(;;)
  10.   {
  11.     osDelay(1);
  12.   }
  13.   /* USER CODE END StartDefaultTask */
  14. }

  15. /* Private application code --------------------------------------------------*/
  16. /* USER CODE BEGIN Application */
复制代码
编译下载到开发板,然后打开TCP调试助手,开启一个端口为5001的监听服务器。我们在输入LED1ON、LED2ON、LED1OFF、LED2OFF时,开发板上的两个用户灯会按要求进行亮与灭:

到此,我们就完成了TCP远程对开发板的LED的控制。
【总结】
在stm32CubeMAX这个可视化的配置工具中,我们很轻易的就完成了所需要的功能,编写的代码也非常少。
分享到:
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条