• 方案介紹
    • 一、環(huán)境介紹
    • 二、D9000網(wǎng)卡
    • 三、LWIP(TCP/IP)網(wǎng)絡(luò)協(xié)議棧介紹
    • 四、LWIP協(xié)議棧移植
    • 五、LWIP函數(shù)使用(RAW編程接口)
  • 附件下載
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

STM32入門開發(fā): LWIP網(wǎng)絡(luò)協(xié)議棧移植(網(wǎng)卡采用DM9000)

02/22 08:19
3203
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

更多詳細(xì)資料請聯(lián)系.docx

共1個文件

一、環(huán)境介紹

MCU: STM32F103ZET6

代碼開發(fā)工具: Keil5

TCP/IP協(xié)議棧: LWIP

網(wǎng)卡: DM9000

本篇文章主要講解如何在STM32F103工程里添加移植LWIP協(xié)議,最終完成TCP服務(wù)器、TCP客戶端的通信測試。 網(wǎng)卡采用的是DM9000,工程代碼中,采用STM32的FSMC接口來驅(qū)動DM900網(wǎng)卡,DM9000是并口網(wǎng)卡,引腳多,但是速度快,也可以采用其他網(wǎng)卡,SPI協(xié)議的、UART協(xié)議的等。 比如:ENC28J60。 因為主要是講LWIP協(xié)議棧的移植,所以網(wǎng)卡相關(guān)的代碼就沒有細(xì)說(需要準(zhǔn)備一個網(wǎng)卡可以正常通信的工程,再移植)。

工程源碼、LWIP資料包下載地址:https://download.csdn.net/download/xiaolong1126626497/19907087

資料包里的內(nèi)容如下:

二、D9000網(wǎng)卡

2.1 DM9000簡介

DM9000 是一款完全集成的、性價比高、引腳數(shù)少、帶有通用處理器接口的單芯片快速以太網(wǎng)控制器。 自帶一個 10/100M PHY 和 4K 雙字的 SRAM ,DM9000A 為適應(yīng)各種處理器提供了8位、16 位數(shù)據(jù)接口訪問內(nèi)部存儲器,DM9000擁有自動協(xié)商功能,DM9000特性如下:

1、集成自適應(yīng)10/100M收發(fā)器。

2、內(nèi)置16k字節(jié)的SRAM。

3、支持硬件幀校驗。

4、兼容3.3V和5.0V輸入輸出電壓。

DM9000 有多種型號,有 100 引腳和 48 引腳的, 開發(fā)板選擇的是 48 引腳的 DM9000,型號為 DM9000CEP。

2.2 DM9000 中斷引腳電平設(shè)置

DM9000的34(INT)引腳為中斷輸出引腳,默認(rèn)情況下該引腳高電平有效??梢酝ㄟ^設(shè)置DM9000 的 20(EECK)引腳來改變 INT 的有效電平,當(dāng) EECK 拉高以后, INT 低電平有效,否則的話 INT 是高電平有效的。開發(fā)板上 R66 電阻為 EECK 的上拉電阻,因此開發(fā)板上 DM9000 的 INT 引腳是低電平有效的。

2.3 DM9000 數(shù)據(jù)位寬設(shè)置

前面我們提了一下 DM9000 支持 8 位和 16 位兩種數(shù)據(jù)位寬,可以通過 DM9000 的 21(EECS)引腳設(shè)置其數(shù)據(jù)位寬,當(dāng) EECS 上拉的時候 DM9000 選擇 8 位數(shù)據(jù)位寬,否則的話選擇 16 位數(shù)據(jù)位寬。開發(fā)板上的 R65 電阻為 EECS 的上拉電阻,但是此電阻并未焊接! DM9000 芯片的數(shù)據(jù)位寬為 16 位。

2.4 DM9000寄存器表

寄存器 描述 寄存器地址 默認(rèn)值
NCR 網(wǎng)絡(luò)控制寄存器。 00H 00H
NSR 網(wǎng)絡(luò)狀態(tài)寄存器。 01H 00H
TCR 發(fā)送控制寄存器。 02H 00H
TSR I 發(fā)送狀態(tài)寄存器 I。 03H 00H
TSR II 發(fā)送狀態(tài)寄存器 II。 04H 00H
RCR 接收控制寄存器。 05H 00H
RSR 接收狀態(tài)寄存器。 06H 00H
ROCR 接收溢出計數(shù)寄存器。 07H 00H
BPTR 背壓門限寄存器。 08H 37H
FCTR 溢出控制門限寄存器。 09H 38H
FCR TX/RX 流量控制寄存器。 0AH 00H
EPCR EEPROM/PHY 控制寄存器。 0BH 00H
EPAR EEPROM/PHY 地址寄存器。 0CH 40H
EPDRL EEPROM/PHY 數(shù)據(jù)寄存器低位。 0DH XXH
EPDRH EEPROM/PHY 數(shù)據(jù)寄存器高位。 0EH XXH
WCR 喚醒控制寄存器。 0FH 00H
PAR 物理地址寄存器。 10H~15H 由 EEPROM 決定
MAR 廣播地址寄存器。 16H~1DH XXH
GPCR 通用目的控制寄存器(8bit 模式)。 1EH 01H
GPR 通用目的寄存器。 1FH XXH
TRPAL TX SRAM 讀指針地址低字節(jié)。 22H 00H
TRPAH TX SRAM 讀指針地址高字節(jié)。 23H 00H
RWPAL RX SRAM 寫指針地址低字節(jié)。 24H 00H
RWRAH RX SRAM 寫指針地址高字節(jié)。 25H 0CH
VID 廠家 ID。 28H~29H 0A46H
PID 產(chǎn)品 ID。 2AH~2BH 9000H
CHIPR 芯片版本。 2CH 18H
TCR2 發(fā)送控制寄存器 2。 2DH 00H
OCR 操作控制寄存器。 2EH 00H
SMCR 特殊模式控制寄存器。 2FH 00H
ETXCSR 即將發(fā)送控制/狀態(tài)寄存器。 30H 00H
TCSCR 發(fā)送校驗和控制寄存器。 31H 00H
RCSCSR 接收校驗和控制狀態(tài)寄存器。 32H 00H
MRCMDX 內(nèi)存數(shù)據(jù)預(yù)取讀命令寄存器(地址不加 1)。 F0H XXH
MRCMDX1 內(nèi)存數(shù)據(jù)讀命令寄存器(地址不加 1)。 F1H XXH
MRCMD 內(nèi)存數(shù)據(jù)讀命令寄存器(地址加 1)。 F2H XXH
MRRL 內(nèi)存數(shù)據(jù)讀地址寄存器低字節(jié)。 F4H 00H
MRRH 內(nèi)存數(shù)據(jù)讀地址寄存器高字節(jié)。 F5H 00H
MWCMDX 內(nèi)存數(shù)據(jù)寫命令寄存器(地址不加 1) F6H XXH
MWCMD 內(nèi)存數(shù)據(jù)寫命令寄存器(地址加 1)。 F8H XXH
MWRL 內(nèi)存數(shù)據(jù)寫地址寄存器低字節(jié)。 FAH 00H
MWRH 內(nèi)存數(shù)據(jù)寫地址寄存器高字節(jié)。 FBH 00H
TXPLL TX 數(shù)據(jù)包長度低字節(jié)寄存器。 FCH XXH
TXPLH TX 數(shù)據(jù)包長度高字節(jié)寄存器。 FDH XXH
ISR 中斷狀態(tài)寄存器。 FEH 00H
IMR 中斷屏蔽寄存器。 FFH 00H

2.5 DM9000常用寄存器介紹

NCR、 NSR、 TCR、 RCR、 FCTR、 BPTR、 TCR2、 ISR、 IMR。

NCR(網(wǎng)絡(luò)控制寄存器)寄存器

BIT 7 6 5 4 3 2 1 0
名稱 RESERVED WAKEEN RESERVED FCOL FDX LBK RST

FCOL:強制沖突模式,用于檢測。

FDX:內(nèi)部 PHY 全雙工模式。

LBK:回環(huán)模式(LoopBack)

00 正常;

01 MAC 內(nèi)部回環(huán);

10 內(nèi)部 PHY100M 模式數(shù)字回環(huán);

11 保留;

RST:置 1 軟件復(fù)位, 10us 后自動清零。

NSR 寄存器(網(wǎng)絡(luò)狀態(tài)寄存器)

BIT 7 6 5 4 3 2 1 0
名 稱 SPEED LINKST WAKEST RESERVED TX2END TX1END RXOV RESERVED

SPEED:網(wǎng)絡(luò)速度,在使用內(nèi)部 PHY 情況下,0 表示 100Mbps,1 表示 100Mbps,當(dāng) LINKST=0時,此位無意義。

LINKST:連接狀態(tài), 0 為連接失敗, 1 位已連接。

TX2END: TX(發(fā)送)數(shù)據(jù)包 2 完成標(biāo)志,讀取或?qū)?1 將清零該位。

TX1END: TX(發(fā)送)數(shù)據(jù)包 1 完成標(biāo)志,讀取或?qū)?1 將清零該位。

RXOV: RX(接收)FIFO 溢出標(biāo)志。

TCR 寄存器(發(fā)送控制寄存器)

BIT 7 6 5 4 3 2 1 0
名 稱 RESERVED TJDIS EXCECM PAD_DIS2 CRC_DIS2 PAD_DIS1 CRC_DIS1 TXREQ

TJDIS: Jabber 傳輸禁止。

1,禁止 Jabber 傳輸定時器(2048 字節(jié))。

0,使能。

EXCECM:嚴(yán)重沖突模式控制

0,當(dāng)沖突計數(shù)多于 15 則終止本次數(shù)據(jù)包。

1,始終嘗試發(fā)送本次數(shù)據(jù)包。

PAD_DIS2:禁止為數(shù)據(jù)包 II 添加填充。

CRC_DIS2:禁止為數(shù)據(jù)包 II 添加 CRC 校驗。

PAD_DIS1:禁止為數(shù)據(jù)包 I 添加填充。

CRC_DIS1:禁止為數(shù)據(jù)包 I 添加 CRC 校驗。

TXREQ: TX(發(fā)送)請求,發(fā)送完成后自動清零該位

RCR 寄存器(發(fā)送控制寄存器)

BIT 7 6 5 4 3 2 1 0
名稱 RESERVED WTDIS DIS_LONG DIS_CRC ALL RUNT PRMSC RXEN

WTDIS:看門狗定時器(2048 字節(jié))禁止。

1,進(jìn)制

0,使能

DIS_LONG:丟棄長數(shù)據(jù)包, 1,丟棄數(shù)據(jù)包長度超過 1522 字節(jié)的數(shù)據(jù)包。

DIS_CRC:丟棄 CRC 校驗錯誤數(shù)據(jù)包。

ALL:允許廣播。

RUNT:允許小于最小長度的數(shù)據(jù)包。

PRMSC:各種模式。

RXEN:接收使能。

FCTR 寄存器(流控制閾值寄存器)

BIT 7 6 5 4 3 2 1 0
名稱 HWOT HWOT HWOT HWOT LWOT LWOT LWOT LWOT

HWOT:RX FIFO 緩存高位溢出門限

當(dāng) RX SRAM 空閑空間小于該門限值時則發(fā)送一個暫停時間為 FFFFH 的暫停包,若該值為 0,則無接收控件。 1=1k 字節(jié),默認(rèn)值為 3H,即 3K 字節(jié)空閑空間,不要超過 S RAM 大小。

LWOT:RX FIFO 緩存低位溢出門限當(dāng) RX SRAM 空閑空間大于該門限值時則發(fā)送一個暫停時間為 0000H 的暫停包。

當(dāng)溢出門限最高值的暫停包發(fā)送之后,溢出門限最低值的暫停包才有效,默認(rèn)值為 8K,不要超過 SRAM 大小。

BPTR 寄存器(背壓閾值寄存器)

BIT 7 6 5 4 3 2 1 0
名稱 BPHW JPT

BPHW:背壓閾值最高值當(dāng)接收 SRAM 空閑空間低于該閾值,則 MAC 將產(chǎn)生一個擁擠狀態(tài), 1=1k 字節(jié)。默認(rèn)值為 3H,即 3K 字節(jié)空閑空間,不要超過 SRAM 大小。

JPT:擁擠狀態(tài)時間,模式為 200us, JPT 值與其對應(yīng)的擁擠狀態(tài)時間表

JPT 擁擠狀態(tài)時間(us) JPT 擁擠狀態(tài)時間(us)
0000 5 1000 250
0001 10 1001 300
0010 15 1010 350
0011 25 1011 400
0100 50 1100 450
0101 100 1101 500
0110 150 1110 550
0111 200 1111 600

TCR2 寄存器(發(fā)送控制寄存器 2)

BIT 7 6 5 4 3 2 1 0
名稱 LED RLCP DTU ONEPM IFGS

LED: LED 模式

1,設(shè)置 LED 引腳為模式 1

0,設(shè)置 LED 引腳為模式 0 或根據(jù) EEPROM 的設(shè)定。

RLCP:重試沖突延時數(shù)據(jù)包, 1 重新發(fā)送有沖突延遲的數(shù)據(jù)包。

DTU: 1 禁止重新發(fā)送“underruned”數(shù)據(jù)包。

ONEPM:單包模式。

1,發(fā)送完成前發(fā)送一個數(shù)據(jù)包的命令能被執(zhí)行。

0,發(fā)送完成前發(fā)送最多兩個數(shù)據(jù)包的命令能被執(zhí)行。

IFGS:幀間間隔設(shè)置。

0XXX 為 96bit, 1000 為 64bit, 1001 為 72bit

1010 為 80bit, 1011 為 88bit, 1100 為 96bit

1101 為 104bit, 1110 位 112bit, 1111 為 120bit

ISR 寄存器(中斷狀態(tài)寄存器)

BIT 7 6 5 4 3 2 1 0
名稱 IOMODE RESERVED LNKCHG UDRUN ROO ROS PT PR

IOMODE: 0,16 位模式; 1,8 位模式。

LNKCHG:連接狀態(tài)改變。

UDRUN:發(fā)送“Underrun”

ROO:接收溢出計數(shù)器溢出

ROS:接收溢出。

PT:數(shù)據(jù)包發(fā)送。

PR:數(shù)據(jù)包接收。

IMR 寄存器(中斷狀態(tài)寄存器)

BIT 7 6 5 4 3 2 1 0
名稱 PAR RESERVED LNKCHGI UDRUNI ROOI ROSI PTI PRI

PAR:使能 SRAM 的讀/寫指針在指針地址超過 SRAM 的大小時自動跳回起始位置。需要驅(qū)動程序設(shè)置該位,若設(shè)置該位, REG_F5 將自動置為 0XH。

LNKCHGI:使能連接狀態(tài)改變中斷。

UDRUNI:使能發(fā)送“Underrun”中斷。

ROOI:使能接收溢出計數(shù)器溢出中斷。

ROI:使能接收溢出中斷。

PTI:使能數(shù)據(jù)包發(fā)送中斷。

PRI:使能數(shù)據(jù)包接收中斷。

2.6 DM9000 直接內(nèi)存訪問控制(DMAC)

DM9000 直接內(nèi)存訪問控制(DMAC)

DM9000 支持 DMA 方式簡化對內(nèi)部存儲器的訪問。在我們編程寫好內(nèi)部存儲器地址后,就可以用一個讀/寫命令偽指令把當(dāng)前數(shù)據(jù)加載到內(nèi)部數(shù)據(jù)緩沖區(qū),這樣,內(nèi)部存儲器指定位置就可以被讀/寫命令寄存器訪問。存儲器地址將會自動增加,增加的大小與當(dāng)前總線操作模式相同(比如:8-bit、 16-bit 或 32-bit),接著下一個地址數(shù)據(jù)將會自動加載到內(nèi)部數(shù)據(jù)緩沖區(qū)。要注意的是在連續(xù)突發(fā)式第一次訪問的數(shù)據(jù)應(yīng)該被忽略,因為,這個數(shù)據(jù)是最后一次讀寫命令的內(nèi)容。內(nèi)部存儲器空間大小 16K 字節(jié)。前 3K 字節(jié)單元用作發(fā)送包的緩沖區(qū),其他 13K 字節(jié)用作接收包的緩沖區(qū)。所以在寫存儲器操作時,如果地址越界(即超出 3K 空間),在 IMR 寄存器 bit7 置位的情況下,地址指針將會返回到存儲器 0 地址處。同樣,在讀存儲器操作時,如果地址越界(即超出 16K 空間),在 IMR 寄存器 bit7 置位的情況下,地址指針將會返回到存儲器 0x0C00 地址處。

DM9000 數(shù)據(jù)包發(fā)送

DM9000 有兩個發(fā)送數(shù)據(jù)包: index1 和 index2,同時存儲在 TX SRAM 中。發(fā)送控制寄存器(02h)控制循環(huán)冗余校驗碼(CRC)和填充(pads)的插入,其狀態(tài)分別記錄在發(fā)送狀態(tài)寄存器I(03H)和發(fā)送狀態(tài)寄存器 II(04H)中。發(fā)送器的起始地址為 0x00H,在軟件或硬件復(fù)位后,默認(rèn)的數(shù)據(jù)發(fā)送包為 index1。首先,使用 DMA 端口將數(shù)據(jù)寫 TX SRAM 中,然后,在發(fā)送數(shù)據(jù)包長度寄存器中把數(shù)據(jù)字節(jié)數(shù)寫入字節(jié)計數(shù)寄存器。置位發(fā)送控制寄存器的 bit0 位,則 DM9000 開始發(fā)送 index1 數(shù)據(jù)包。在 index1數(shù)據(jù)包發(fā)送結(jié)束之前,數(shù)據(jù)發(fā)送包 index2 被移入 TX SRAM 中。在 index1 數(shù)據(jù)包發(fā)送結(jié)束后,將 index2 數(shù)據(jù)字節(jié)數(shù)寫入字節(jié)計數(shù)寄存器中,然后,置位發(fā)送控制寄存器的 bit0 位,則 index2數(shù)據(jù)包開始發(fā)送。以此類推,后面的數(shù)據(jù)包都以此方式進(jìn)行發(fā)送。

DM9000 數(shù)據(jù)包接收

RX SRAM 是一個環(huán)形數(shù)據(jù)結(jié)構(gòu)。在軟件或硬件復(fù)位后, RX SRAM 的起始地址為 0X0C00。每個接收數(shù)據(jù)包都包含有 CRC 校驗域,數(shù)據(jù)域,以及緊跟其后的 4 字節(jié)包頭域。 4 字節(jié)包頭格式為: 01h、狀態(tài)、 BYTE_COUNT 低、 BYTE_COUNT 高。請注意:每個接收包的起始地址處在適當(dāng)?shù)牡刂愤吔?,這取決于當(dāng)前總線操作模式(8bit 或者 16bit)

2.7 DM9000原理圖介紹

各信號線描述如下:

PWRST: DM9000 復(fù)位信號。

CS: DM9000 的片選信號。

WR(IOW): 處理器寫命令。

RD(IOR): 處理器讀命令。

CMD: 命令/數(shù)據(jù)標(biāo)志, 0,讀寫命令; 1,讀寫數(shù)據(jù)。

SD0~SD15: 16 位雙向數(shù)據(jù)線。

信號線對應(yīng)的GPIO口對應(yīng)關(guān)系

引腳名稱 GPIO口 功能說明
PWRST-->DM9000_RST PD7 復(fù)位信號
CS-->FSMC_NE2 PG9 片選信號
WR(IOW)-->FSMC_NWE PD5 處理器寫命令
RD(IOR) --->FSMC_NOE PD4 處理器讀命令
CMD—>FSMC-A7 PF13 命令/數(shù)據(jù)標(biāo)志, 0,讀寫命令; 1,讀寫數(shù)據(jù)
INT--->DM9000_INT PG6 中斷引腳
FSMC_D0 PD14 數(shù)據(jù)線0
FSMC_D1 PD15 數(shù)據(jù)線1
FSMC_D2 PD0 數(shù)據(jù)線2
FSMC_D3 PD1 數(shù)據(jù)線3
FSMC_D4 PE7 數(shù)據(jù)線4
FSMC_D5 PE8 數(shù)據(jù)線5
FSMC_D6 PE9 數(shù)據(jù)線6
FSMC_D7 PE10 數(shù)據(jù)線7
FSMC_D8 PE11 數(shù)據(jù)線8
FSMC_D9 PE12 數(shù)據(jù)線9
FSMC_D10 PE13 數(shù)據(jù)線10
FSMC_D11 PE14 數(shù)據(jù)線11
FSMC_D12 PE15 數(shù)據(jù)線12
FSMC_D13 PD8 數(shù)據(jù)線13
FSMC_D14 PD9 數(shù)據(jù)線14
FSMC_D15 PD10 數(shù)據(jù)線15

FSMC接口框圖

DM9000網(wǎng)卡接在FSMC的第2塊上,數(shù)據(jù)線地址: 0x64000000

PA7地址線作為命令與數(shù)據(jù)線切換引腳。

外接16位寬度存儲器:HADDR[25:1] ? FSMC_A[24:0]

外接8位寬度存儲器: HADDR[25:0] ? FSMC_A[25:0]

0x64000000基地址:01100100000000000000000000000000

0x64000000寫數(shù)據(jù):01100100000000000000000000000000

0x64000100寫命令:01100100000000000000000100000000

2.8 DM9000時序圖介紹

IOR和IOW是DM9000的讀寫選擇引腳,低電平有效,即低電平時進(jìn)行讀(IOR)寫(IOW)操作;AEN是芯片選通引腳,低電平有效,該引腳為低時才能進(jìn)行讀寫操作;CMD的命令/數(shù)據(jù)切換引腳,低電平時讀寫命令操作,高電平時讀寫數(shù)據(jù)操作。

讀時序:

寫時序:

三、LWIP(TCP/IP)網(wǎng)絡(luò)協(xié)議棧介紹

根據(jù)以太網(wǎng)幀頭攜帶的上層協(xié)議類型值傳遞數(shù)據(jù)。

以太網(wǎng)幀格式定義:

目的MAC地址 源MAC地址?????????? 類型/長度????????????????? 數(shù)據(jù)???????????????????? 校驗

6字節(jié)???????? ?6字節(jié)???? ??????????2字節(jié)?????????????????? 46-1500字節(jié)????????????? 4字節(jié)

ip:0x0800

ARP:0x0806

最大幀長1518字節(jié) 最小字節(jié)64字節(jié)

3.1 LWIP介紹

lwip是瑞典計算機科學(xué)院網(wǎng)絡(luò)嵌入式系統(tǒng)小組(SICS)的Adam Dunkels(亞當(dāng)·鄧克爾) 開發(fā)的一個小型開源的TCP/IP協(xié)議棧。實現(xiàn)的重點是在保持TCP協(xié)議主要功能的基礎(chǔ)上減少對RAM 的占用。

LwIP是Light Weight (輕型)IP協(xié)議,有無操作系統(tǒng)的支持都可以運行。LwIP實現(xiàn)的重點是在保持TCP協(xié)議主要功能的基礎(chǔ)上減少對RAM 的占用,它只需十幾KB的RAM和40K左右的ROM就可以運行,這使LwIP協(xié)議棧適合在低端的嵌入式系統(tǒng)中使用。lwip提供三種API:1)RAW API ?2)(NETCONN)lwip API ?3)BSD API。

RAW 編程接口使得程序效率高,但是需要對 LWIP 有深入的了解,而且不適合大數(shù)據(jù)量等場合。 NETCONN 編程接口,使用 NETCONN API 時需要有操作系統(tǒng)的支持。

RAW API把協(xié)議棧和應(yīng)用程序放到一個進(jìn)程里邊,該接口基于函數(shù)回調(diào)技術(shù),使用該接口的應(yīng)用程序可以不用進(jìn)行連續(xù)操作。不過,這會使應(yīng)用程序編寫難度加大且代 碼不易被理解。為了接收數(shù)據(jù),應(yīng)用程序會向協(xié)議棧注冊一個回調(diào)函數(shù)。該回調(diào)函數(shù)與特定的連接相關(guān)聯(lián),當(dāng)該關(guān)聯(lián)的連接到達(dá)一個信息包,該回調(diào)函數(shù)就會被協(xié)議 棧調(diào)用。這既有優(yōu)點也有缺點。優(yōu)點是既然應(yīng)用程序和TCP/IP協(xié)議棧駐留在同一個進(jìn)程中,那么發(fā)送和接收數(shù)據(jù)就不再產(chǎn)生進(jìn)程切換。主要缺點是應(yīng)用程序不 能使自己陷入長期的連續(xù)運算中,這樣會導(dǎo)致通訊性能下降,原因是TCP/IP處理與連續(xù)運算是不能并行發(fā)生的。這個缺點可以通過把應(yīng)用程序分為兩部分來克 服,一部分處理通訊,一部分處理運算。

lwip API把接收與處理放在一個線程里面。這樣只要處理流程稍微被延遲,接收就會被阻塞,直接造成頻繁丟包、響應(yīng)不及時等嚴(yán)重問題。因此,接收與協(xié)議處理必須 分開。LwIP的作者顯然已經(jīng)考慮到了這一點,他為我們提供了 tcpip_input() 函數(shù)來處理這個問題, 雖然他并沒有在 rawapi 一文中說明。 講到這里,讀者應(yīng)該知道tcpip_input()函數(shù)投遞的消息從哪里來的答案了吧,沒錯,它們來自于由底層網(wǎng)絡(luò)驅(qū)動組成的接收線程。我們在編寫網(wǎng)絡(luò)驅(qū)動時, 其接收部分以任務(wù)的形式創(chuàng)建。 數(shù)據(jù)包到達(dá)后, 去掉以太網(wǎng)包頭得到IP包, 然后直接調(diào)用tcpip_input()函數(shù)將其 投遞到mbox郵箱。投遞結(jié)束,接收任務(wù)繼續(xù)下一個數(shù)據(jù)包的接收,而被投遞得IP包將由TCPIP線程繼續(xù)處理。這樣,即使某個IP包的處理時間過長也不 會造成頻繁丟包現(xiàn)象的發(fā)生。這就是lwip API。

BSD API提供了基于open-read-write-close模型的UNIX標(biāo)準(zhǔn)API,它的最大特點是使應(yīng)用程序移植到其它系統(tǒng)時比較容易,但用在嵌入式系統(tǒng)中效率比較低,占用資源多。這對于我們的嵌入式應(yīng)用有時是不能容忍的

lwIP協(xié)議棧主要關(guān)注的是怎么樣減少內(nèi)存的使用和代碼的大小,這樣就可以讓lwIP適用于資源有限的小型平臺例如嵌入式系統(tǒng)。為了簡化處理過程和內(nèi)存要求,lwIP對API進(jìn)行了裁減,可以不需要復(fù)制一些數(shù)據(jù)。

其主要特性如下:

(1)支持多網(wǎng)絡(luò)接口下的IP轉(zhuǎn)發(fā);

(2)支持ICMP協(xié)議;

(3)包括實驗性擴展的UDP(用戶數(shù)據(jù)報協(xié)議);

(4)包括阻塞控制、RTT 估算、快速恢復(fù)和快速轉(zhuǎn)發(fā)的TCP(傳輸控制協(xié)議);

(5)提供專門的內(nèi)部回調(diào)接口(Raw API),用于提高應(yīng)用程序性能;

(6)可選擇的Berkeley接口API (在多線程情況下使用) 。

(7)在最新的版本中支持ppp

(8) 新版本中增加了的IP fragment(IP分片)的支持.

(9) 支持DHCP協(xié)議,動態(tài)分配ip地址.

3.2 幾種開源TCPIP協(xié)議概述

1、BSD TCP/IP協(xié)議棧

BSD棧歷史上是商業(yè)棧的起點,大多數(shù)專業(yè)TCP/IP棧(VxWorks內(nèi)嵌的TCP/IP棧)是BSD棧派生的。這是因為BSD棧在BSD許可協(xié)議下提供了這些專業(yè)棧的雛形,BSD許用證允許BSD棧以修改或未修改的形式結(jié)合這些專業(yè)棧的代碼而無須向創(chuàng)建者付版稅。同時,BSD也是許多TCP/IP協(xié)議中的創(chuàng)新(如廣域網(wǎng)中餓擁塞控制和避免)的點。

2、uC/IP

uC/IP是由Guy Lancaster編寫的一套基于uC/OS且開放源碼的TCP/IP協(xié)議棧,亦可移植到操作系統(tǒng),是一套完全免費的、可供研究的TCP/IP協(xié)議棧,uC/IP大部分源碼是從公開源碼BSD發(fā)布站點和KA9Q(一個基于DOS單任務(wù)環(huán)境運行的TCP/IP協(xié)議棧)移植過來。uC/IP具有如下一些特點:帶身份驗證和報頭壓縮支持的PPP協(xié)議,優(yōu)化的單一請求/回復(fù)交互過程,支持IP/TCP/UDP協(xié)議,可實現(xiàn)的網(wǎng)絡(luò)功能較為強大,并可裁減。UCIP協(xié)議棧被為一個帶最小化用戶接口及可應(yīng)用串行鏈路網(wǎng)絡(luò)模塊。根據(jù)采用CPU編譯器和系統(tǒng)所需實現(xiàn)協(xié)議的多少,協(xié)議棧需要的代碼容量空間在30-60KB之間。http://ucip.sourceforge.net

3、LwIP

LwIP是瑞士計算機科學(xué)院(Swedish Institute of Computer Science)的Adam Dunkels等開發(fā)的一套用于嵌入式系統(tǒng)的開放源代碼TCP/IP協(xié)議棧。LwIP的含義是Light Weight(輕型)IP協(xié)議,相對于uip。LwIP可以移植到操作系統(tǒng)上,也可以在無操作系統(tǒng)的情況下獨立運行。LwIP TCP/IP實現(xiàn)的重點是在保持TCP協(xié)議主要功能的基礎(chǔ)上減少對RAM的占用,一般它只需要幾十K的RAM和40K左右的ROM就可以運行,這使LwIP協(xié)議棧適合在低端嵌入式系統(tǒng)中使用。LwIP的特性如下:支持多網(wǎng)絡(luò)接口下的IP轉(zhuǎn)發(fā),支持ICMP協(xié)議 ,包括實驗性擴展的的UDP(用戶數(shù)據(jù)報協(xié)議),包括阻塞控制,RTT估算和快速恢復(fù)和快速轉(zhuǎn)發(fā)的TCP(傳輸控制協(xié)議),提供專門的內(nèi)部回調(diào)接口(Raw API)用于提高應(yīng)用程序性能,并提供了可選擇的Berkeley接口API。http://www.sics.se/~adam/lwip/或http://savannah.nongnu.org/projects/lwip/

4、uIP

uIP是專門為8位和16位控制器設(shè)計的一個非常小的TCP/IP棧。完全用C編寫,因此可移植到各種不同的結(jié)構(gòu)和操作系統(tǒng)上,一個編譯過的棧可以在幾KB ROM或幾百字節(jié)RAM中運行。uIP中還包括一個HTTP服務(wù)器作為服務(wù)內(nèi)容。許可:BSD許用證http://www.sics.se/~adam/uip/

uIP是一個完全由C語言編寫的開源軟件, 它的文檔和源代碼可用于商業(yè)和非商業(yè)用途, 它已經(jīng)移植到了大部分的8微控制器, 而且已在很多的嵌入式產(chǎn)品和項目中使用.

5、TinyTcp

TinyTcp 棧是TCP/IP的一個非常小和簡單的實現(xiàn),它包括一個FTP客戶。TinyTcp是為了燒入ROM設(shè)計的并且現(xiàn)在開始對大端結(jié)構(gòu)似乎是有用的(初始目標(biāo)是68000芯片)。TinyTcp也包括一個簡單的以太網(wǎng)驅(qū)動器用于3COM多總線卡http://ftp.ecs.soton.ac.uk/pub/elks/utils/tiny-tcp.txt

選擇一個開源協(xié)議??梢詮乃膫€方面來考慮:

是否提供易用的底層硬件API,即與硬件平臺的無關(guān)性;

協(xié)議棧需要調(diào)用的系統(tǒng)函數(shù)接口是否容易構(gòu)造,另一個對于應(yīng)用支持程度。

最關(guān)鍵的是占用的系統(tǒng)資源是否在可接受范圍內(nèi),有裁減優(yōu)化的空間否? 其中,

BSD ??赏暾麑崿F(xiàn)TCP/IP協(xié)議,但代碼龐大,70KB-150KB之間,裁減優(yōu)化有難度,

uIP和TinyTcp代碼容量小巧,實現(xiàn)功能精簡,限制了在一些較高要求場合下的應(yīng)用,如可靠性與大容量數(shù)據(jù)傳輸

LwIP和uC/IP是同量級別的兩個開源協(xié)議棧,兩者代碼容量和實現(xiàn)功能相似,LwIP沒有操作系統(tǒng)針對性,它將協(xié)議棧與平臺相關(guān)的代碼抽象出來,用戶如果要移植到自己的系統(tǒng),需要完成該部分代碼的封裝,并為網(wǎng)絡(luò)應(yīng)用支持提供了API接口的可選性。

uC/IP協(xié)議最初是針對uC/OS設(shè)計,為方便用戶移植實現(xiàn),同樣也抽象了協(xié)議棧與平臺相關(guān)代碼,但是協(xié)議棧所需調(diào)用的系統(tǒng)函數(shù)大多參照uC/OS內(nèi)核函數(shù)原型設(shè)計,并提供了協(xié)議棧的函數(shù),方便用戶參考,其不足在于該協(xié)議棧對網(wǎng)絡(luò)應(yīng)用支持不足。

根據(jù)以上分析,從應(yīng)用和開發(fā)的角度看,似乎LWIP更得到了網(wǎng)上很多朋友使用的青睞;uC/IP在文檔支持與軟件升級管理上有很多不足,但是它最初是針對UC/OS而設(shè)計,如果選用UC/OS作為軟件基礎(chǔ)的話,在系統(tǒng)函數(shù)構(gòu)造方面有優(yōu)勢。當(dāng)然你選擇其他操作系統(tǒng)的話,可參照OS_NULL文件夾下的文件修改。 以上的這些開源協(xié)議棧也并非免費,拿來就可以用,據(jù)我所知,UC/OS的母公司推出UC/OS-TCP/IP花了6人*2年的工作量,國內(nèi)某公司使用LWIP作為移植的參照,花了4-5人*2年的工作量來測試與優(yōu)化協(xié)議,使用商用TCP/IP棧的高費用就不足為奇了。 作為廣大的愛好者學(xué)習(xí)而言,如果只是跑跑原型,實驗一下效果,以上的幾種開源協(xié)議棧都提供了測試的例子,應(yīng)該是不錯的選擇。

終上所述:LWIP可優(yōu)先考慮,參考的資料較多

四、LWIP協(xié)議棧移植

4.1? LWIP源碼下載

源碼下載地址: http://ftp.yzu.edu.tw/nongnu/lwip/

下載LWIP1.4.1版本、并下載contrib-1.4.1版本。

4.2 將LWIP源碼加入到工程目錄

?

?

4.3 配置lwipopts.h文件

4.4 修改ethernetif.c文件

ethernetif.c文件默認(rèn)是不編譯的,該文件是網(wǎng)卡底層接口的模板文件,需要根據(jù)修改網(wǎng)卡發(fā)送接口和接收接口。

4.5 修改sys_arch.c文件

修改sys_arch.c只是留下sys_now()函數(shù),其他代碼全部刪除掉。刪除windows.h頭文件。

sys_now()函數(shù)用于返回一個32位的系統(tǒng)時鐘,單位是ms。沒有操作系統(tǒng)的情況下,使用定時器提供時間即可。

4.6 新建lwip_config.c文件

在LWIP/app目錄下新建一個lwip_config.c/lwip_config.h文件。用于編寫動態(tài)IP地址分配處理代碼,和LWIP事物輪詢、初始化代碼。

編寫一個LWIP初始化配置函數(shù),向LWIP協(xié)議棧添加一個新的網(wǎng)卡設(shè)備

/*
函數(shù)功能: LWIP協(xié)議棧初始化
*/
void lwip_config_init(void)
{
	ip_addr_t ipaddr;   //IP地址
	ip_addr_t netmask;  //子網(wǎng)掩碼
	ip_addr_t gw;       //網(wǎng)關(guān)
	
	//全部初始化為0  -因為使用了動態(tài)IP地址分配
	ipaddr.addr=0;
	netmask.addr=0;
	gw.addr=0;
	
	/*1. 初始化LWIP內(nèi)核*/
	lwip_init();
	/*2. 向網(wǎng)卡列表中添加一個網(wǎng)絡(luò)設(shè)備*/
	netif_add(&lwip_netif,&ipaddr,&netmask,&gw,NULL,&ethernetif_init,&ethernet_input);
	/*3. 開啟DHCP服務(wù) */
	dhcp_start(&lwip_netif);
	/*4. 設(shè)置netif為默認(rèn)網(wǎng)口*/
	netif_set_default(&lwip_netif);
	/*5. 打開netif網(wǎng)口*/
	netif_set_up(&lwip_netif);	
}

編寫LWIP事物輪詢函數(shù)與DHCP處理函數(shù)

u32 TCPTimer=0;				//TCP查詢計時器
u32 ARPTimer=0;				//ARP查詢計時器
u32 DHCPfineTimer=0;	 	//DHCP精細(xì)處理計時器
u32 DHCPcoarseTimer=0; 		//DHCP粗糙處理計時器
u32 DHCP_State=1;          //保存DHCP狀態(tài) 1表示沒有分配成功 0表示分配成功

/*
函數(shù)功能:  LWIP輪詢?nèi)蝿?wù)
*/
void lwip_periodic_handle()
{
	//每250ms調(diào)用一次tcp_tmr()函數(shù)
	if(TCPTimer >= TCP_TMR_INTERVAL)
	{
		TCPTimer=0;
		tcp_tmr();  //處理TCP協(xié)議請求
	}
	
	//ARP每5s周期性調(diào)用一次
	if(ARPTimer >= ARP_TMR_INTERVAL)
	{
		ARPTimer=0;
		etharp_tmr();
	}
	//每500ms調(diào)用一次dhcp_fine_tmr()
	if(DHCPfineTimer >= DHCP_FINE_TIMER_MSECS)
	{
		DHCPfineTimer=0;
		dhcp_fine_tmr(); //動態(tài)IP地址分配的事物處理
		if(DHCP_State)lwip_dhcp_process_handle();  //DHCP處理
	}

	//每60s執(zhí)行一次DHCP粗糙處理
	if(DHCPcoarseTimer >= DHCP_COARSE_TIMER_MSECS)
	{
		DHCPcoarseTimer=0;
		dhcp_coarse_tmr();
	}  
}

//lwip控制結(jié)構(gòu)體
typedef struct  
{
	u8 remoteip[4];	//服務(wù)器主機IP地址 
	u8 ip[4];        //本機IP地址
	u8 netmask[4]; 	//子網(wǎng)掩碼
	u8 gateway[4]; 	//默認(rèn)網(wǎng)關(guān)的IP地址
}__lwip_dev;

extern __lwip_dev lwipdev;	//lwip信息結(jié)構(gòu)體

__lwip_dev lwipdev;	//lwip信息結(jié)構(gòu)體


/*
函數(shù)功能: DHCP處理任務(wù)
*/
void lwip_dhcp_process_handle(void)
{
	u32 ip=0,netmask=0,gw=0;
	ip=lwip_netif.ip_addr.addr;			//讀取新IP地址
	netmask=lwip_netif.netmask.addr;   //讀取子網(wǎng)掩碼
	gw=lwip_netif.gw.addr;           //讀取默認(rèn)網(wǎng)關(guān)
	
	if(ip!=0)			//正確獲取到IP地址的時候
	{
		DHCP_State=0; //表示分配成功
	  //解析出通過DHCP獲取到的IP地址
		lwipdev.ip[3]=(uint8_t)(ip>>24); 
		lwipdev.ip[2]=(uint8_t)(ip>>16);
		lwipdev.ip[1]=(uint8_t)(ip>>8);
		lwipdev.ip[0]=(uint8_t)(ip);
		printf("動態(tài)分配
IP:..............%d.%d.%d.%drn",lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);
		//解析通過DHCP獲取到的子網(wǎng)掩碼地址
		lwipdev.netmask[3]=(uint8_t)(netmask>>24);
		lwipdev.netmask[2]=(uint8_t)(netmask>>16);
		lwipdev.netmask[1]=(uint8_t)(netmask>>8);
		lwipdev.netmask[0]=(uint8_t)(netmask);
		printf("子網(wǎng)掩
碼............%d.%d.%d.%drn",lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]);
		//解析出通過DHCP獲取到的默認(rèn)網(wǎng)關(guān)
		lwipdev.gateway[3]=(uint8_t)(gw>>24);
		lwipdev.gateway[2]=(uint8_t)(gw>>16);
		lwipdev.gateway[1]=(uint8_t)(gw>>8);
		lwipdev.gateway[0]=(uint8_t)(gw);
		printf("網(wǎng)
關(guān).........%d.%d.%d.%drn",lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]);
	}
}

4.7 配置一個定時器提供時間基準(zhǔn)

4.8 初始化lwip動態(tài)獲取IP地址

4.9 LWIP內(nèi)存配置選擇

LWIP可以選擇使用系統(tǒng)庫自帶的函數(shù)malloc/free進(jìn)行管理空間,也可以使用lwip自己的內(nèi)存管理函數(shù)進(jìn)行管理,源碼默認(rèn)就是使用lwip自己的內(nèi)存管理方法,就是在初始化內(nèi)存的時候定義一個數(shù)組,數(shù)組的大小在lwipopts.h文件MEM_SIZE宏定義的。

五、LWIP函數(shù)使用(RAW編程接口)

5.1 ?LWIP初始化配置

ip_addr_t ipaddr;   //IP地址
ip_addr_t netmask;  //子網(wǎng)掩碼
ip_addr_t gw;       //網(wǎng)關(guān)

//全部初始化為0  -因為使用了動態(tài)IP地址分配
ipaddr.addr=0;
netmask.addr=0;
gw.addr=0;

/*1. 初始化LWIP內(nèi)核*/
lwip_init();
/*2. 向網(wǎng)卡列表中添加一個網(wǎng)絡(luò)設(shè)備*/
netif_add(&lwip_netif,&ipaddr,&netmask,&gw,NULL,&ethernetif_init,&ethernet_input);
/*3. 開啟DHCP服務(wù) */
dhcp_start(&lwip_netif);
/*4. 設(shè)置netif為默認(rèn)網(wǎng)口*/
netif_set_default(&lwip_netif);
/*5. 打開netif網(wǎng)口*/
netif_set_up(&lwip_netif);	

5.2 LWIP輪詢函數(shù)處理

LWIP輪詢期間:

1. 推薦每250ms周期性調(diào)用一次tcp_tmr()函數(shù),處理TCP協(xié)議請求。

超時時間LWIP使用TCP_TMR_INTERVAL宏進(jìn)行了定義。

2. 推薦每5s周期性調(diào)用一次etharp_tmr()函數(shù),清除ARP表中過期的數(shù)據(jù)。

超時時間LWIP使用ARP_TMR_INTERVAL宏進(jìn)行了定義。

3. (如果開啟了動態(tài)IP分配功能)推薦每500ms周期性調(diào)用一次dhcp_fine_tmr()函數(shù),處理DHCP動態(tài)IP地址分配請求。 ?如果IP地址獲取成功,將會放在初始化時注冊的網(wǎng)絡(luò)設(shè)備結(jié)構(gòu)體里(struct netif)。

超時時間LWIP使用DHCP_FINE_TIMER_MSECS宏進(jìn)行了定義。

4. (如果開啟了動態(tài)IP分配功能)推薦每60s調(diào)用一次dhcp_coarse_tmr()函數(shù),用于檢查DHCP租約時間,并進(jìn)行重新綁定。

超時時間LWIP使用DHCP_COARSE_TIMER_MSECS宏進(jìn)行了定義。

5. 在LWIP運行期間,當(dāng)網(wǎng)卡收到數(shù)據(jù)時,還需要調(diào)用ethernetif_input函數(shù)讀取網(wǎng)卡數(shù)據(jù)。

在函數(shù)ethernetif_input()主要完成兩個工作

1、調(diào)low_level_input(); 讀取網(wǎng)卡實際數(shù)據(jù)。

2、調(diào)用netif->input();

所以,為了能夠?qū)崟r的讀取數(shù)據(jù),需要最快的速度輪詢調(diào)用ethernetif_input函數(shù)。

5.3 ?LWIP編程RAW接口函數(shù)

tcp_new() 創(chuàng)建一個 TCP 的 PCB 控制塊
tcp_bind() 為 TCP 的 PCB 控制塊綁定一個本地 IP 地址和端口號
tcp_listen() 開始 TCP 的 PCB 監(jiān)聽
tcp_accept() 控制塊 accept字段注冊的回調(diào)函數(shù),偵聽到連接時被調(diào)用
tcp_accepted() 通知 LWIP 協(xié)議棧一個 TCP 連接被接受了
tcp_conect() 連接遠(yuǎn)端主機
tcp_write() 構(gòu)造一個報文并放到控制塊的發(fā)送緩沖隊列中
tcp_sent() 控制塊 sent 字段注冊的回調(diào)函數(shù),數(shù)據(jù)發(fā)送成功后被回調(diào)
tcp_output() 將發(fā)送緩沖隊列中的數(shù)據(jù)發(fā)送出去
tcp_recv()控制塊 recv 字段注冊的回調(diào)函數(shù),當(dāng)接收到新數(shù)據(jù)時被調(diào)用
tcp_recved()當(dāng)程序處理完數(shù)據(jù)后一定要調(diào)用這個函數(shù),通知內(nèi)核更新接收窗口
tcp_poll() 控制塊 poll 字段注冊的回調(diào)函數(shù),該函數(shù)周期性調(diào)用
tcp_close() 關(guān)閉一個 TCP 連接
tcp_err() 控制塊 err 字段注冊的回調(diào)函數(shù),遇到錯誤時被調(diào)用
tcp_abort() 中斷 TCP 連接

5.4 創(chuàng)建TCP服務(wù)器示例

下面演示了TCP服務(wù)器創(chuàng)建步驟,測試服務(wù)器是否正常。

u8 TCP_Create(u16_t port)
{
	struct tcp_pcb *pcb=NULL;
	pcb=tcp_new(); //創(chuàng)建套接字
	if(pcb==NULL)return 1;
	if(tcp_bind(pcb,IP_ADDR_ANY,port)!=ERR_OK)return 2; //綁定端口號
	pcb=tcp_listen(pcb); //開始監(jiān)聽
	tcp_accept(pcb,TCP_accept);//等待連接
	return 0;
}

err_t TCP_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
	u8 addr[4];
	//tcp_setprio(newpcb, TCP_PRIO_MIN);  設(shè)置優(yōu)先級
	printf("有新的客戶端連接!n");
	addr[3]=(newpcb->remote_ip.addr>>24)&0xFF;
	addr[2]=(newpcb->remote_ip.addr>>16)&0xFF;
	addr[1]=(newpcb->remote_ip.addr>>8)&0xFF;
	addr[0]=(newpcb->remote_ip.addr>>0)&0xFF;
	printf("ip地址:%d.%d.%d.%dn",addr[0],addr[1],addr[2],addr[3]);
	printf("端口號:%dn",newpcb->remote_port);
	printf("當(dāng)前隊列剩余字節(jié):%dn",tcp_sndbuf(newpcb));
	tcp_write(newpcb,"1234567890",10,1); //將要發(fā)送的數(shù)據(jù)提交到發(fā)送隊列(不會立即發(fā)送)
	tcp_output(newpcb); 								 //提示系統(tǒng)現(xiàn)在,發(fā)送數(shù)據(jù)
	tcp_sent(newpcb,TCP_sent); 					 //發(fā)送成功的回調(diào)函數(shù)
	tcp_recv(newpcb,TCP_recv);
	return ERR_OK;
}

err_t TCP_sent(void *arg, struct tcp_pcb *tpcb,u16_t len)
{
	printf("成功發(fā)送:%d字節(jié)n",len);
	//tcp_close(tpcb); //關(guān)閉客戶端連接
	return ERR_OK;
}

u8 rx_buff[1024];
err_t TCP_recv(void *arg, struct tcp_pcb *tpcb,struct pbuf *p, err_t err)
{
	u32 rx_cnt=0;
	struct pbuf *q;
	memset(rx_buff,0,sizeof(rx_buff));
	if(p==NULL)
	{
	  printf("客戶端已經(jīng)斷開連接!n");
	}
	else
	{
	  for(q=p;q!=NULL;q=q->next)
	  {
			memcpy(rx_buff+rx_cnt,q->payload,q->len);
			rx_cnt+=q->len;
	  }
       pbuf_free(p); //釋放PUFF
		printf("成功接收:%d字節(jié)n",rx_cnt);
		printf("收到的數(shù)據(jù)=%sn",rx_buff);
	}
	return ERR_OK;
}

5.5 創(chuàng)建TCP客戶端示例

u8 TCP_Create(u16_t port)
{
	struct tcp_pcb *pcb=NULL;
	pcb=tcp_new(); //創(chuàng)建套接字
	ip_addr_t ipaddr;
	if(pcb==NULL)return 1;
	IP4_ADDR(&ipaddr,192,168,31,54); //在ip_addr.h里定義
	tcp_connect(pcb,&ipaddr,port,TCP_connected);
	return 0;
}


err_t TCP_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
{
	u8 addr[4];
	//tcp_setprio(newpcb, TCP_PRIO_MIN);  設(shè)置優(yōu)先級
	printf("服務(wù)器連接成功!n");
	addr[3]=(tpcb->remote_ip.addr>>24)&0xFF;
	addr[2]=(tpcb->remote_ip.addr>>16)&0xFF;
	addr[1]=(tpcb->remote_ip.addr>>8)&0xFF;
	addr[0]=(tpcb->remote_ip.addr>>0)&0xFF;
	printf("服務(wù)器ip地址:%d.%d.%d.%dn",addr[0],addr[1],addr[2],addr[3]);
	printf("服務(wù)器端口號:%dn",tpcb->remote_port);
	printf("當(dāng)前隊列剩余字節(jié):%dn",tcp_sndbuf(tpcb));
	tcp_write(tpcb,"1234567890",10,1); //將要發(fā)送的數(shù)據(jù)提交到發(fā)送隊列(不會立即發(fā)送)
	tcp_output(tpcb); //提示系統(tǒng)現(xiàn)在,發(fā)送數(shù)據(jù)
	tcp_sent(tpcb,TCP_sent); //發(fā)送成功的回調(diào)函數(shù)
	tcp_recv(tpcb,TCP_recv);
	return ERR_OK;
}


err_t TCP_sent(void *arg, struct tcp_pcb *tpcb,u16_t len)
{
	printf("成功發(fā)送:%d字節(jié)n",len);
	//tcp_close(tpcb); //關(guān)閉客戶端連接
	return ERR_OK;
}


u8 rx_buff[1024];
err_t TCP_recv(void *arg, struct tcp_pcb *tpcb,struct pbuf *p, err_t err)
{
	u32 rx_cnt=0;
	struct pbuf *q;
	memset(rx_buff,0,sizeof(rx_buff));
	if(p==NULL)
	{
		printf("服務(wù)器已經(jīng)斷開連接!n");
	}
	else
	{
		for(q=p;q!=NULL;q=q->next)
		{
			  memcpy(rx_buff+rx_cnt,q->payload,q->len);
			  rx_cnt+=q->len;
		}
		printf("成功接收:%d字節(jié)n",rx_cnt);
		printf("收到的數(shù)據(jù)=%sn",rx_buff);
	}
	return ERR_OK;
}

 

  • 更多詳細(xì)資料請聯(lián)系.docx
    下載
意法半導(dǎo)體

意法半導(dǎo)體

意法半導(dǎo)體(ST)集團于1987年6月成立,是由意大利的SGS微電子公司和法國Thomson半導(dǎo)體公司合并而成。1998年5月,SGS-THOMSON Microelectronics將公司名稱改為意法半導(dǎo)體有限公司。意法半導(dǎo)體是世界最大的半導(dǎo)體公司之一,公司銷售收入在半導(dǎo)體工業(yè)五大高速增長市場之間分布均衡(五大市場占2007年銷售收入的百分比):通信(35%),消費(17%),計算機(16%),汽車(16%),工業(yè)(16%)。 據(jù)最新的工業(yè)統(tǒng)計數(shù)據(jù),意法半導(dǎo)體是全球第五大半導(dǎo)體廠商,在很多市場居世界領(lǐng)先水平。例如,意法半導(dǎo)體是世界第一大專用模擬芯片和電源轉(zhuǎn)換芯片制造商,世界第一大工業(yè)半導(dǎo)體和機頂盒芯片供應(yīng)商,而且在分立器件、手機相機模塊和車用集成電路領(lǐng)域居世界前列.

意法半導(dǎo)體(ST)集團于1987年6月成立,是由意大利的SGS微電子公司和法國Thomson半導(dǎo)體公司合并而成。1998年5月,SGS-THOMSON Microelectronics將公司名稱改為意法半導(dǎo)體有限公司。意法半導(dǎo)體是世界最大的半導(dǎo)體公司之一,公司銷售收入在半導(dǎo)體工業(yè)五大高速增長市場之間分布均衡(五大市場占2007年銷售收入的百分比):通信(35%),消費(17%),計算機(16%),汽車(16%),工業(yè)(16%)。 據(jù)最新的工業(yè)統(tǒng)計數(shù)據(jù),意法半導(dǎo)體是全球第五大半導(dǎo)體廠商,在很多市場居世界領(lǐng)先水平。例如,意法半導(dǎo)體是世界第一大專用模擬芯片和電源轉(zhuǎn)換芯片制造商,世界第一大工業(yè)半導(dǎo)體和機頂盒芯片供應(yīng)商,而且在分立器件、手機相機模塊和車用集成電路領(lǐng)域居世界前列.收起

查看更多

相關(guān)推薦