1. 程式人生 > >STM32407+LAN8720A+LWIP 實現LWIP 客戶端

STM32407+LAN8720A+LWIP 實現LWIP 客戶端

update light weak details b- 文件 main add ip協議

一、配置CubeMax工程

技術分享圖片

二、配置系統時鐘

因為LAN8720使用的是外部25MHz的晶振,所以不需要單片機輸出時鐘

技術分享圖片

三、配置ETH和LWIP參數

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

四、更改代碼

LAN8720A在初始化的時候需要復位,因此在ethernetif.c的 static void low_level_init(struct netif *netif) 函數中添加LAN8720A 的復位程序

技術分享圖片

再mian函數主循環中添加一下代碼,然後編譯運行,正常的話,再路由器中能看到程序中設置的MAC地址,以及分配的IP,此時能夠ping通

MX_LWIP_Process();

成功了?NoNoNO,如果你啟動的時候沒有接網線,等啟動之後,再插上網線,你會發現,板子死活都不會找dhcp服務器要IP, 結果就是失聯。。重大缺陷,不能忍!幸虧LWIP協議棧早就想到了這種情況,LWIP_NETIF_LINK_CALLBACK是幹嘛的?就是在連接狀態改變的時候,調用一個回調函數,來做相應的處理

在main函數的住循環中加入

extern struct netif *netif_default;
ethernetif_set_link(netif_default);

這個函數會查詢當前的連接狀態,當狀態改變的時候,調用回調函數,在ethernetif.c裏我們可以找到這個回調函數,

void ethernetif_update_config(struct netif *netif)

果然有很多處理,那為什麽還是不能打開dhcp呢?來看看這個函數的末尾,調用了這個函數

ethernetif_notify_conn_changed()

這個函數,而這個函數看看註釋就知道,是需要咱自己來實現的,所以我們加入以下的代碼

 1 /**
 2   * @brief  This function notify user about link status changement.
 3   * @param  netif: the network interface
 4   * @retval None
 5   */
 6 __weak void ethernetif_notify_conn_changed(struct netif *netif)
 7 {
 8   /* NOTE : This is function could be implemented in user file 
 9
when the callback is needed, 10 */ 11 if(netif_is_link_up(netif) && !netif_is_up(netif)) 12 { 13 netif_set_up(netif); 14 extern err_t dhcp_start(struct netif *netif); 15 dhcp_start(netif); 16 } 17 }

重編譯下載,拔掉網線,開機,再插上網線,獲得了IP, 大功告成!

五、添加API文件

從庫中示例代碼中把LwIP/LwIP_TCP_Echo_Client/Src/tcp_echoclient.c 和 tcp_echoclient.h 拷貝到工程中,然後添加發送函數

 1 err_t tcp_client_usersent(struct tcp_pcb *tpcb, uint8_t *buff,uint16_t size)
 2 {
 3     err_t ret_err;
 4     struct echoclient *es; 
 5     es=tpcb->callback_arg;
 6     if(es!=NULL)  //連接處於空閑時可以發送數據
 7     {
 8         es->p_tx=pbuf_alloc(PBUF_TRANSPORT, size,PBUF_POOL);    //申請內存
 9         pbuf_take(es->p_tx,(char*)buff,size);    //將tcp_client_sentbuf[]中的數據拷貝到es->p_tx中
10         tcp_echoclient_send(tpcb,es);  //將tcp_client_sentbu[]裏面復制給pbuf的數據發送出去
11         if(es->p_tx)pbuf_free(es->p_tx);    //釋放內存
12         ret_err=ERR_OK;
13     }else
14     { 
15         tcp_abort(tpcb);  //終止連接,刪除pcb控制塊
16         ret_err=ERR_ABRT;
17     }
18     return ret_err;
19 }

在 tcp_echoclient.h中需要添加連接到的服務器的IP地址和端口

 1 #include "err.h"
 2 #include "tcp.h"
 3 /* Includes ------------------------------------------------------------------*/
 4 /* Exported types ------------------------------------------------------------*/
 5 /* Exported constants --------------------------------------------------------*/
 6 /* Exported macro ------------------------------------------------------------*/
 7 /* Exported functions ------------------------------------------------------- */
 8 void tcp_echoclient_connect(void);
 9 err_t tcp_client_usersent(struct tcp_pcb *tpcb, uint8_t *buff,uint16_t size);
10 
11 #define DEST_IP_ADDR0    192
12 #define DEST_IP_ADDR1    168    
13 #define DEST_IP_ADDR2    000
14 #define DEST_IP_ADDR3    108
15 
16 
17 #define DEST_PORT        9001

通過以上更改,就可以使用 tcp_client_usersent()函數進行發送數據了

1 /**
2 * @brief        發送數據包
3  * @retval     None
4  */
5 void UCP_DataAnswer(void)
6 {
7     tcp_client_usersent(echoclient_pcb, ToSendBuf, 23);
8     tcp_client_usersent(echoclient_pcb, DeSendBuf, 23);
9 }

上面已經能正常發送數據了,如果我把網線拔下來,在插上去又怎麽樣呢,試試?所有在main函數的主循環中增加斷線重連的代碼

 1   /* USER CODE BEGIN WHILE */
 2   while (1)
 3   {    
 4         HAL_GPIO_TogglePin(ALARM_GPIO_Port, ALARM_Pin);
 5         MX_LWIP_Process();                                                // LwIP Initialization
 6         ethernetif_set_link(netif_default);                // This function sets the netif link status.
 7         
 8         // 拔掉網線後,由於服務端單向斷開連接,客戶端會進入FIN_WAIT_2等待狀態
 9         if(echoclient_pcb->state == CLOSED || echoclient_pcb->state == FIN_WAIT_2)
10         {   
11             tcp_abort(echoclient_pcb);
12             tcp_echoclient_connect();                                // 斷線重連
13         }
14         

參考博客:https://blog.csdn.net/hustwf/article/details/80040578

STM32407+LAN8720A+LWIP 實現LWIP 客戶端