返回列表 发新帖我要提问本帖赏金: 30.00元(功能说明)

[APM32F4] 【极海APM32F407IG Tiny Board开发板测评】TCP_client点灯

[复制链接]
 楼主| xiaoqi976633690 发表于 2023-7-12 12:41 | 显示全部楼层 |阅读模式
本帖最后由 xiaoqi976633690 于 2023-7-12 12:37 编辑

声明:本例程基于极海官方APM32F4xx_SDK_v1.3内的ETH_TCP_client例程修改,目标路径\**\APM32F4xx_SDK_v1.3\Examples\ETH\ETH_TCP_client

一、准备硬件:APM32F407IG Tiny Board,RJ45网线,路由或笔记本电脑或交换机,usb串口线
软件:APM32F4xx_SDK_v1.3,lwip基础,mdk,网络调试助手。

二、实验目的
tiny开发板通过网络连接到server端,server端发送指令控制开发板LED3点亮和熄灭。


二、实验过程
由于官方已经将底层的驱动实现,这里不细讲lwip移植和lwip内核实现原理,感兴趣的可以看下正点原子或野火的lwip专题教程。
LWIP有三种API,在本例程中,使用Raw API(无操作系统)
a. mdk安装apm32f407的pack,打开官方例程
1.png

b.主要实现函数


2.png


c. min.c 主要函数说明


  LwIP协议栈初始化函数

LwIP_Init函数用于初始化LwIP协议栈,一般在main函数中调用。首先是内存相关初始化,mem_init函数是动态内存堆初始化,memp_init函数是存储池初始化, LwIP是实现内存的高效利用,内部需要不同形式的内存管理模式。

接下来为ipaddr、netmask和gw结构体变量赋值,设置本地IP地址、子网掩码和网关,如果使用DHCP功能直接赋值为0即可。netif_add是以太网设备添加函数, 即向LwIP协议栈申请添加一个网卡设备,函数有7个形参,第一个为netif结构体类型变量指针,这里赋值为gnetif地址,该网卡设备属性就存放在gnetif变量中; 第二个为ip_addr结构体类型变量指针,用于设置网卡IP地址;第三个ip_addr结构体类型变量指针,用于设置子网掩码;第四个为ip_addr结构体类型变量指针, 用于设置网关;第五个为void变量,用户自定义字段,一般不用直接赋值NULL;第六个为netif_init_fn类型函数指针,用于指向网卡设备初始化函数, 这里赋值为指向ethernetif_init函数,该函数在ethernetif.c文件定义,初始化LwIP与ETH外设连接函数;最后一个参数为netif_input_fn类型函数指针, 用于指向以太网帧接收函数,这里赋值为指向ethernet_input函数,该函数定义在etharp.c文件中。


  1. /*!
  2. * [url=home.php?mod=space&uid=247401]@brief[/url]       This function initializes the lwIP stack
  3. *
  4. * @param       None
  5. *
  6. * @retval      None
  7. */
  8. void LwIP_Init(void) //lwip初始化函数
  9. {
  10.     struct ip_addr ipaddr;
  11.     struct ip_addr netmask;
  12.     struct ip_addr gw;

  13.     /** Initializes the dynamic memory heap */
  14.     mem_init();

  15.     /** Initializes the memory pools */
  16.     memp_init();

  17.     IP4_ADDR(&ipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
  18.     IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1 , NETMASK_ADDR2, NETMASK_ADDR3);
  19.     IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);

  20.     /** Config MAC Address */
  21.     ETH_ConfigMACAddress(ETH_MAC_ADDRESS0, SetMACaddr);

  22.     /** Add a network interface to the list of lwIP netifs */
  23.     netif_add(&UserNetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);

  24.     /** Registers the default network interface */
  25.     netif_set_default(&UserNetif);

  26.     /** When the netif is fully configured this function must be called */
  27.     netif_set_up(&UserNetif);
  28. }


LwIP_Pkt_Handle函数用于从以太网存储器读取一个以太网帧并将其发送给LwIP,它在接收到以太网帧时被调用, 它是直接调用ethernetif_input函数实现的,该函数定义在ethernetif.c文件中。
  1. /*!
  2. * [url=home.php?mod=space&uid=247401]@brief[/url]       This function received ethernet packet
  3. *
  4. * @param       None
  5. *
  6. * @retval      None
  7. */
  8. void LwIP_Pkt_Handle(void)
  9. {
  10.     /** Read a received packet from the Ethernet buffers and send it to the lwIP for handling */
  11.     ethernetif_input(&UserNetif);
  12. }




LwIP_Periodic_Handle函数是一个必须被无限循环调用的LwIP支持函数,一般在main函数的无限循环中调用,主要功能是为LwIP各个模块提供时间并查询链路状态, 该函数有一个形参,用于指示当前时间,单位为ms。
  1. /*!
  2. * @brief       This function LwIP periodic tasks
  3. *
  4. * @param       ETHTimer the current Ethernet Timer value
  5. *
  6. * @retval      None
  7. */
  8. void LwIP_Periodic_Handle(__IO uint32_t ETHTimer)
  9. {
  10.     static uint8_t flagToggle = 0;

  11. #if LWIP_TCP
  12.     /** TCP periodic process every 250 ms */
  13.     if (ETHTimer - TCPTimer >= TCP_TMR_INTERVAL)
  14.     {
  15.         TCPTimer =  ETHTimer;
  16.         tcp_tmr();
  17.     }
  18. #endif

  19.     /** ARP periodic process every 5s */
  20.     if ((ETHTimer - ARPTimer) >= ARP_TMR_INTERVAL)
  21.     {
  22.         ARPTimer =  ETHTimer;
  23.         etharp_tmr();
  24.     }

  25.     /** Check link status */
  26.     if ((ETHTimer - LinkTimer) >= 1000)
  27.     {
  28.         if ((ETH_GET_LINK_STATUS != 0) && (flagToggle == 0))
  29.         {
  30.             /** link goes up */
  31.             netif_set_link_up(&UserNetif);
  32.             flagToggle = 1;
  33.         }

  34.         if ((ETH_GET_LINK_STATUS == 0) && (flagToggle == 1))
  35.         {
  36.             EthLinkStatus = 1;
  37.             /** link goes down */
  38.             netif_set_link_down(&UserNetif);
  39.             flagToggle = 0;
  40.         }
  41.     }
  42. }


d. echo_cc.c函数讲解
该文件主要实现tcp—client
LWIP 中 RAW API 编程接口中与 TCP 相关的函数:

3.png
TCP 的 RAW API 编程函数

4.png


tcp连接初始化函数
  1. /*!
  2. * @brief       tcp client init
  3. *
  4. * @param       tcpc_port: client port
  5. *
  6. * @param       ipaddr: point to the client ip address
  7. *
  8. * @retval      None
  9. */
  10. void tcpc_echo_init(ip_addr_t *ipaddr, uint16_t tcpc_port)//tcp连接初始化函数
  11. {
  12.   tcpc_echo_pcb = tcp_new();
  13.   if (tcpc_echo_pcb != NULL)
  14.   {
  15.     /* connect to server address:port */
  16.     tcp_connect(tcpc_echo_pcb, ipaddr, tcpc_port, tcpc_echo_accept);///* 连接服务器 */
  17.   }
  18.   else
  19.   {
  20.     /* abort? output diagnostic? */
  21.   }
  22. }
pbuf接收处理函数指令处理主要在该函数内实现
  1. /*!
  2. * @brief       Printf TCP Receive Data
  3. *
  4. * @param       p: pointer on the tcp pcb received pbuf
  5. *
  6. * @retval      None
  7. */
  8. void PrintfRecData(struct pbuf *p)//pbuf接收处理函数
  9. {
  10.   char recbuf[100] = {0};
  11.         char LED_ON[]={"LED3ON"};
  12.         char LED_OFF[]={"LED3OFF"};
  13.   memcpy(recbuf, p->payload, p->len);
  14.   printf("received message:%s\n\r", recbuf);
  15.         if(strcmp(recbuf,LED_ON)==0)
  16.         {
  17.                 printf("LED3 on\n\r");
  18.                 APM_TINY_LEDOn(LED3);//打开LED
  19.         }
  20.                 if(strcmp(recbuf,LED_OFF)==0)
  21.         {
  22.                 printf("LED3 off\n\r");
  23.                 APM_TINY_LEDOff(LED3);//关闭LED
  24.         }
  25. }

接收到数据时的回调函数



  1. /*!
  2. * @brief       LwIP tcp_recv callback function
  3. *
  4. * @param       None
  5. *
  6. * @retval      None
  7. */
  8. err_t tcpc_echo_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
  9. {
  10.   struct tcpc_echo_state *es;
  11.   err_t ret_err;

  12.   LWIP_ASSERT("arg != NULL", arg != NULL);
  13.   es = (struct tcpc_echo_state *)arg;
  14.   if (p == NULL)
  15.   {
  16.     /* remote host closed connection */
  17.     es->state = ES_CLOSING;
  18.     if (es->p == NULL)
  19.     {
  20.       /* we're done sending, close it */
  21.       tcpc_echo_close(tpcb, es);
  22.     }
  23.     else
  24.     {
  25.       /* we're not done yet */
  26.       tcp_sent(tpcb, tcpc_echo_sent);
  27.       tcpc_echo_send(tpcb, es);
  28.     }
  29.     ret_err = ERR_OK;
  30.   }
  31.   else if (err != ERR_OK)
  32.   {
  33.     /* cleanup, for unkown reason */
  34.     if (p != NULL)
  35.     {
  36.       es->p = NULL;
  37.       pbuf_free(p);
  38.     }
  39.     ret_err = err;
  40.   }

  41.   else if (es->state == ES_ACCEPTED)//接收缓存处理
  42.   {
  43.     tcp_recved(tpcb, p->tot_len);

  44.     /** Printf TCP Receive Data */
  45.     PrintfRecData(p);

  46.     es->p = NULL;
  47.     pbuf_free(p);
  48.     ret_err = ERR_OK;
  49.   }
  50.   else
  51.   {
  52.     /* unkown es->state, trash data  */
  53.     tcp_recved(tpcb, p->tot_len);
  54.     es->p = NULL;
  55.     pbuf_free(p);
  56.     ret_err = ERR_OK;
  57.   }
  58.   return ret_err;
  59. }

  60. /*!
  61. * @brief       LwIP tcp_err callback function
  62. *
  63. * @param       None
  64. *
  65. * @retval      None
  66. */
  67. void tcpc_echo_error(void *arg, err_t err)
  68. {
  69.   struct tcpc_echo_state *es;

  70.   LWIP_UNUSED_ARG(err);

  71.   es = (struct tcpc_echo_state *)arg;
  72.   if (es != NULL)
  73.   {
  74.     mem_free(es);
  75.   }
  76. }
e.main.c
main函数实现
  1. int main(void)
  2. {
  3.     char LCDDisplayBuf[100] = {0};

  4.     struct ip_addr DestIPaddr;

  5.     uint8_t flag = 0;

  6.     USART_Config_T usartConfig;

  7.     /** User config the different system Clock */
  8.     UserRCMClockConfig();

  9.     /** Configure SysTick */
  10.     ConfigSysTick();
  11.                
  12.     /** Configure USART */
  13.     usartConfig.baudRate = 115200;
  14.     usartConfig.wordLength = USART_WORD_LEN_8B;
  15.     usartConfig.stopBits = USART_STOP_BIT_1;
  16.     usartConfig.parity = USART_PARITY_NONE ;
  17.     usartConfig.mode = USART_MODE_TX_RX;
  18.     usartConfig.hardwareFlow = USART_HARDWARE_FLOW_NONE;

  19.     APM_BOARD_COMInit(COM1,&usartConfig);

  20.     /** Configures LED2 and LED3 */
  21.     APM_BOARD_LEDInit(LED2);
  22.     APM_BOARD_LEDInit(LED3);

  23.     /** KEY init*/
  24.     APM_BOARD_PBInit(BUTTON_KEY1, BUTTON_MODE_GPIO);
  25.     APM_BOARD_PBInit(BUTTON_KEY2, BUTTON_MODE_GPIO);

  26.     printf("This is a ETH TCP Client Demo! \r\n请稍侯,正在启动lwip\n\r");
  27.                 APM_TINY_LEDOn(LED3);
  28.     /** Configure ethernet (GPIOs, clocks, MAC, DMA) */
  29.     ConfigEthernet();

  30.     /** Initilaize the LwIP stack */
  31.     LwIP_Init();
  32.                 APM_TINY_LEDOff(LED3);
  33.     /** Use Com printf static IP address*/
  34.     sprintf(LCDDisplayBuf,"TINY board Static IP address \r\n");
  35.     printf("%s",LCDDisplayBuf);

  36.     sprintf(LCDDisplayBuf,"IP: %d.%d.%d.%d \r\n",
  37.     IP_ADDR0,
  38.     IP_ADDR1,
  39.     IP_ADDR2,
  40.     IP_ADDR3);
  41.     printf("%s",LCDDisplayBuf);

  42.     sprintf(LCDDisplayBuf,"NETMASK: %d.%d.%d.%d \r\n",
  43.     NETMASK_ADDR0,
  44.     NETMASK_ADDR1,
  45.     NETMASK_ADDR2,
  46.     NETMASK_ADDR3);
  47.     printf("%s",LCDDisplayBuf);

  48.     sprintf(LCDDisplayBuf,"Gateway: %d.%d.%d.%d \r\n",
  49.     GW_ADDR0,
  50.     GW_ADDR1,
  51.     GW_ADDR2,
  52.     GW_ADDR3);
  53.     printf("%s",LCDDisplayBuf);

  54.     sprintf(LCDDisplayBuf,"TCP Server IP: %d.%d.%d.%d:%d \r\n",
  55.     COMP_IP_ADDR0,
  56.     COMP_IP_ADDR1,
  57.     COMP_IP_ADDR2,
  58.     COMP_IP_ADDR3,
  59.     COMP_PORT);
  60.     printf("%s",LCDDisplayBuf);

  61.     printf("\n\rKEY1: Connect TCP server \r\n");
  62.     printf("KEY2: Disconnect TCP server \r\n");

  63.     while(1)
  64.     {

  65.         if ((APM_TINY_PBGetState(BUTTON_KEY1)==0)&&(flag==0))
  66.         {
  67.             APM_TINY_LEDOn(LED2);
  68.             if (EthLinkStatus == 0)
  69.             {
  70.                 /** connect to tcp server */
  71.                 printf("\n\rConnect TCP server \r\n");
  72.                 IP4_ADDR( &DestIPaddr, COMP_IP_ADDR0, COMP_IP_ADDR1, COMP_IP_ADDR2, COMP_IP_ADDR3 );
  73.                 tcpc_echo_init(&DestIPaddr,COMP_PORT);
  74.                 flag=1;
  75.             }
  76.         }
  77.         if ((APM_TINY_PBGetState(BUTTON_KEY2)==0)&&(flag==1))
  78.         {
  79.             APM_TINY_LEDOff(LED2);
  80.             printf("\n\rDisconnect TCP server \r\n");
  81.             tcpc_echo_disable();
  82.             flag=0;
  83.         }

  84.         /** check if any packet received */
  85.         if (ETH_CheckReceivedFrame())
  86.         {
  87.             /** process received ethernet packet */
  88.             LwIP_Pkt_Handle();
  89.         }
  90.         /** handle periodic timers for LwIP */
  91.         LwIP_Periodic_Handle(ETHTimer);
  92.     }
  93. }


f.烧录-实验现象
将开发板连接和server端同网段到网络。
6.png
等待串口出现ip提示信息,按key1连接到server端
5.png
发送对应指令实现了led的点亮和熄灭
7.png

程序源码附件
ETH_TCP_client.zip (7.72 MB, 下载次数: 5)

打赏榜单

Gfan 打赏了 30.00 元 2023-08-17
理由:APM32F407 TINY测评精选文章

 楼主| xiaoqi976633690 发表于 2023-7-12 16:42 | 显示全部楼层
演示视频哔哩哔哩https://www.bilibili.com/video/BV1XM4y1j7FE/
tpgf 发表于 2023-8-7 13:18 | 显示全部楼层
client是指的客户端还是服务器端啊

评论

客户端  发表于 2023-8-7 15:01
nawu 发表于 2023-8-7 13:40 | 显示全部楼层
以太网的连接必须要有心跳信号吗
aoyi 发表于 2023-8-7 14:03 | 显示全部楼层
tcp好像是应该有心跳信号的  但是udp好像是不需要的
zljiu 发表于 2023-8-7 16:06 | 显示全部楼层
楼主有没有实测连接是否稳定呀
gwsan 发表于 2023-8-7 16:35 | 显示全部楼层
实测通讯速率最大能达到多少了吗?
tfqi 发表于 2023-8-7 17:12 | 显示全部楼层
以太网这边可以通过软件更改客户端或者是服务器端吗
您需要登录后才可以回帖 登录 | 注册

本版积分规则

35

主题

204

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部

35

主题

204

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部