查看: 47434|回复: 0

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

[复制链接]
  • TA的每日心情
    开心
    昨天 08:20
  • 签到天数: 303 天

    连续签到: 34 天

    [LV.8]以坛为家I

    发表于 2024-3-18 22:22:04 | 显示全部楼层 |阅读模式
    分享到:
    【实验目的】
    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。 微信截图_20240318214444.png
    3、将freertos的stack设置为1024。
    微信截图_20240318215436.png
    4、生成代码后,删除原来的在main.c的主循环的MX_LWIP_Process();,编译代码并下载到开发板,ping一下开发板,可以顺利的拼通,说明我们在freertos上面移植lwip成功了。
    微信截图_20240318215833.png
    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时,开发板上的两个用户灯会按要求进行亮与灭:
    微信截图_20240318221944.png 微信截图_20240318221923.png 微信截图_20240318221909.png
    到此,我们就完成了TCP远程对开发板的LED的控制。
    【总结】
    在stm32CubeMAX这个可视化的配置工具中,我们很轻易的就完成了所需要的功能,编写的代码也非常少。
    回复

    使用道具 举报

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

    本版积分规则

    关闭

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

    手机版|小黑屋|与非网

    GMT+8, 2024-11-24 08:16 , Processed in 0.118434 second(s), 16 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.