單芯片解決方案,開(kāi)啟全新體驗(yàn)——W55MH32 高性能以太網(wǎng)單片機(jī)
W55MH32是WIZnet重磅推出的高性能以太網(wǎng)單片機(jī),它為用戶帶來(lái)前所未有的集成化體驗(yàn)。這顆芯片將強(qiáng)大的組件集于一身,具體來(lái)說(shuō),一顆W55MH32內(nèi)置高性能Arm? Cortex-M3核心,其主頻最高可達(dá)216MHz;配備1024KB FLASH與96KB SRAM,滿足存儲(chǔ)與數(shù)據(jù)處理需求;集成TOE引擎,包含WIZnet全硬件TCP/IP協(xié)議棧、內(nèi)置MAC以及PHY,擁有獨(dú)立的32KB以太網(wǎng)收發(fā)緩存,可供8個(gè)獨(dú)立硬件socket使用。如此配置,真正實(shí)現(xiàn)了All-in-One解決方案,為開(kāi)發(fā)者提供極大便利。
在封裝規(guī)格上,W55MH32提供了兩種選擇:QFN100和QFN68。
W55MH32L采用QFN100封裝版本,尺寸為12x12mm,其資源豐富,專(zhuān)為各種復(fù)雜工控場(chǎng)景設(shè)計(jì)。它擁有66個(gè)GPIO、3個(gè)ADC、12通道DMA、17個(gè)定時(shí)器、2個(gè)I2C、5個(gè)串口、2個(gè)SPI接口(其中1個(gè)帶I2S接口復(fù)用)、1個(gè)CAN、1個(gè)USB2.0以及1個(gè)SDIO接口。如此豐富的外設(shè)資源,能夠輕松應(yīng)對(duì)工業(yè)控制中多樣化的連接需求,無(wú)論是與各類(lèi)傳感器、執(zhí)行器的通信,還是對(duì)復(fù)雜工業(yè)協(xié)議的支持,都能游刃有余,成為復(fù)雜工控領(lǐng)域的理想選擇。同系列還有QFN68封裝的W55MH32Q版本,該版本體積更小,僅為8x8mm,成本低,適合集成度高的網(wǎng)關(guān)模組等場(chǎng)景,軟件使用方法一致。更多信息和資料請(qǐng)進(jìn)入http://www.w5500.com/網(wǎng)站或者私信獲取。
此外,本W(wǎng)55MH32支持硬件加密算法單元,WIZnet還推出TOE+SSL應(yīng)用,涵蓋TCP SSL、HTTP SSL以及 MQTT SSL等,為網(wǎng)絡(luò)通信安全再添保障。
為助力開(kāi)發(fā)者快速上手與深入開(kāi)發(fā),基于W55MH32L這顆芯片,WIZnet精心打造了配套開(kāi)發(fā)板。開(kāi)發(fā)板集成WIZ-Link芯片,借助一根USB C口數(shù)據(jù)線,就能輕松實(shí)現(xiàn)調(diào)試、下載以及串口打印日志等功能。開(kāi)發(fā)板將所有外設(shè)全部引出,拓展功能也大幅提升,便于開(kāi)發(fā)者全面評(píng)估芯片性能。
若您想獲取芯片和開(kāi)發(fā)板的更多詳細(xì)信息,包括產(chǎn)品特性、技術(shù)參數(shù)以及價(jià)格等,歡迎訪問(wèn)官方網(wǎng)頁(yè):http://www.w5500.com/,我們期待與您共同探索W55MH32的無(wú)限可能。
第九章 W55MH32 HTTP Server示例
本篇文章我們將詳細(xì)介紹如何在W55MH32芯片上面實(shí)現(xiàn)HTTP Server功能,并通過(guò)實(shí)戰(zhàn)例程,為大家講解如何通過(guò)瀏覽器修改W55MH32的網(wǎng)絡(luò)地址信息。
該例程用到的其他網(wǎng)絡(luò)協(xié)議,例如DHCP,請(qǐng)參考相關(guān)章節(jié)。有關(guān)W55MH32的初始化過(guò)程,也請(qǐng)參考相關(guān)章節(jié),這里將不再贅述。
1 HTTP協(xié)議簡(jiǎn)介
HTTP(超文本傳輸協(xié)議,HyperText Transfer Protocol)是一種用于分布式、協(xié)作式、超媒體信息系統(tǒng)的應(yīng)用層協(xié)議,基于 TCP/IP通信協(xié)議來(lái)傳遞數(shù)據(jù),是萬(wàn)維網(wǎng)(WWW)的數(shù)據(jù)通信的基礎(chǔ)。設(shè)計(jì) HTTP最初的目的是為了提供一種發(fā)布和接收 HTML頁(yè)面的方法,通過(guò) HTTP或者 HTTPS協(xié)議請(qǐng)求的資源由統(tǒng)一資源標(biāo)識(shí)符(Uniform Resource Identifiers,URI)來(lái)標(biāo)識(shí)。
以上是HTTP協(xié)議的簡(jiǎn)介,如想深入了解該協(xié)議,請(qǐng)參考mozilla網(wǎng)站上的介紹: HTTP 概述 - HTTP | MDN
2 HTTP協(xié)議特點(diǎn)
基于請(qǐng)求-響應(yīng)模型:客戶端發(fā)起請(qǐng)求,服務(wù)器處理后返回響應(yīng)。例如,用戶在瀏覽器輸入網(wǎng)址時(shí),瀏覽器會(huì)向?qū)?yīng)服務(wù)器發(fā)送HTTP請(qǐng)求,服務(wù)器返回網(wǎng)頁(yè)內(nèi)容。
無(wú)狀態(tài)性:HTTP本身不保存請(qǐng)求之間的狀態(tài),每次請(qǐng)求獨(dú)立。但可以通過(guò)Cookie、Session等機(jī)制實(shí)現(xiàn)狀態(tài)保持。
無(wú)連接:無(wú)連接的含義是限制每次連接只處理一個(gè)請(qǐng)求。服務(wù)器處理完客戶的請(qǐng)求并收到客戶的應(yīng)答后,便立即斷開(kāi)連接。
3 HTTP Server應(yīng)用場(chǎng)景
W55MH32使用HTTP Server模式可以進(jìn)行以下幾種應(yīng)用:
設(shè)備配置和管理:通過(guò)瀏覽器訪問(wèn)W55MH32提供的WEB界面,實(shí)現(xiàn)網(wǎng)絡(luò)配置,系統(tǒng)參數(shù)調(diào)整,固件升級(jí)等操作。
實(shí)時(shí)監(jiān)控和數(shù)據(jù)展示:通過(guò)瀏覽器訪問(wèn)W55MH32提供的WEB頁(yè)面,實(shí)時(shí)監(jiān)控傳感器數(shù)據(jù),狀態(tài)信息,以及查看工作日志等。
遠(yuǎn)程控制:通過(guò)瀏覽器訪問(wèn)W55MH32提供的WEB頁(yè)面進(jìn)行遠(yuǎn)程控制設(shè)備,如開(kāi)關(guān)等。
4 HTTP協(xié)議的基本工作流程
HTTP的請(qǐng)求-響應(yīng)模型通常由以下幾個(gè)步驟組成
建立連接:客戶端與服務(wù)器之間基于TCP/IP協(xié)議建立連接。
發(fā)送請(qǐng)求:客戶端向服務(wù)器發(fā)送請(qǐng)求,請(qǐng)求中包含要訪問(wèn)的資源的 URL、請(qǐng)求方法(GET、POST、PUT、DELETE等)、請(qǐng)求頭(例如,Accept、User-Agent)以及可選的請(qǐng)求體(對(duì)于 POST 或 PUT請(qǐng)求)。
處理請(qǐng)求:服務(wù)器接收到請(qǐng)求后,根據(jù)請(qǐng)求中的信息找到相應(yīng)的資源,執(zhí)行對(duì)應(yīng)的處理操作。這可能涉及從數(shù)據(jù)庫(kù)中檢索數(shù)據(jù)、生成動(dòng)態(tài)內(nèi)容或者簡(jiǎn)單地返回靜態(tài)文件。
發(fā)送響應(yīng):服務(wù)器將處理后的結(jié)果封裝在響應(yīng)中,并將其發(fā)送回客戶端。響應(yīng)包含狀態(tài)碼(用于指示請(qǐng)求的成功或失?。㈨憫?yīng)頭(例如,Content-Type、Content-Length)以及可選的響應(yīng)體(例如,HTML頁(yè)面、圖像數(shù)據(jù))。
關(guān)閉連接:在完成請(qǐng)求-響應(yīng)周期后,客戶端和服務(wù)器之間的連接將被關(guān)閉,除非使用了持久連接(如 HTTP/1.1中的 keep-alive)。
5 HTTP請(qǐng)求方法
在HTTP協(xié)議中,GET和POST是兩種常用的請(qǐng)求方法,用于客戶端向服務(wù)器發(fā)送數(shù)據(jù)和獲取資源。
GET方法
GET方法通常用于從服務(wù)器獲取資源。它有以下特點(diǎn):
參數(shù)傳遞:請(qǐng)求參數(shù)通過(guò)URL中的查詢字符串傳遞,形如?key1=value1&key2=value2。
數(shù)據(jù)大小限制:由于參數(shù)附加在URL后,長(zhǎng)度可能受URL長(zhǎng)度限制(取決于瀏覽器和服務(wù)器設(shè)置)。
安全性:數(shù)據(jù)在URL中明文顯示,不適合傳遞敏感信息。
請(qǐng)求格式:
GET HTTP/
Request-URI:表示目標(biāo)資源的路徑,可能包含參數(shù)。
Version:HTTP協(xié)議版本。
Headers:包含元信息,例如客戶端的屬性、支持的格式等。
Blank Line:空行。
POST方法
POST方法通常用于向服務(wù)器提交數(shù)據(jù)。它有以下特點(diǎn):
參數(shù)傳遞:數(shù)據(jù)放在請(qǐng)求體中,而不是URL中。
數(shù)據(jù)大小限制:POST請(qǐng)求的體積沒(méi)有明顯限制,可以傳遞大量數(shù)據(jù)。
安全性:數(shù)據(jù)在請(qǐng)求體中傳輸,相對(duì)來(lái)說(shuō)更安全。
請(qǐng)求格式:
POST HTTP/
Request-URI:目標(biāo)資源的路徑,通常是API的端點(diǎn)。
Headers:元信息,例如內(nèi)容類(lèi)型和長(zhǎng)度。
Blank Line:空行,區(qū)分頭和主體。
Body:數(shù)據(jù)的主體,包含客戶端發(fā)送到服務(wù)器的長(zhǎng)度。
6 HTTP協(xié)議響應(yīng)內(nèi)容
HTTP協(xié)議響應(yīng)內(nèi)容包含狀態(tài)行、響應(yīng)頭以及響應(yīng)體三個(gè)部分。
狀態(tài)行
HTTP狀態(tài)行包含HTTP協(xié)議版本、狀態(tài)碼以及狀態(tài)描述。
狀態(tài)碼由三個(gè)十進(jìn)制數(shù)字組成,第一個(gè)十進(jìn)制數(shù)字定義了狀態(tài)碼的類(lèi)型。
狀態(tài)碼分為五類(lèi):
1xx(信息性狀態(tài)碼):表示接收的請(qǐng)求正在處理。
2xx(成功狀態(tài)碼):表示請(qǐng)求正常處理完畢。
3xx(重定向狀態(tài)碼):需要后續(xù)操作才能完成這一請(qǐng)求。
4xx(客戶端錯(cuò)誤狀態(tài)碼):表示請(qǐng)求包含語(yǔ)法錯(cuò)誤或無(wú)法完成。
5xx(服務(wù)器錯(cuò)誤狀態(tài)碼):服務(wù)器在處理請(qǐng)求的過(guò)程中發(fā)生了錯(cuò)誤。
示例:
HTTP/1.1 200 OK
響應(yīng)頭
響應(yīng)頭則會(huì)包含內(nèi)容類(lèi)型、長(zhǎng)度、編碼等信息。
常見(jiàn)的響應(yīng)頭字段有:
Content-Type:響應(yīng)內(nèi)容的MIME類(lèi)型,例如 text/html、application/json。
Content-Length:響應(yīng)內(nèi)容的字節(jié)長(zhǎng)度。
Server:服務(wù)器信息。
Set-Cookie:設(shè)置客戶端的Cookie。
示例:
Content-Type: text/html; charset=UTF-8 Content-Length: 3495 Server: Apache/2.4.41 (Ubuntu)
響應(yīng)體
響應(yīng)體包含實(shí)際的數(shù)據(jù)內(nèi)容,具體形式取決于響應(yīng)的類(lèi)型和請(qǐng)求內(nèi)容。例如:HTML頁(yè)面內(nèi)容,JSON數(shù)據(jù),文件的二進(jìn)制數(shù)據(jù)等。
如果是狀態(tài)碼為204 No Content或 304 Not Modified的響應(yīng),則通常沒(méi)有正文。
注意:響應(yīng)體和響應(yīng)頭之間會(huì)添加一個(gè)空行來(lái)分隔內(nèi)容。
7 Web頁(yè)面的基本構(gòu)成
HTML(超文本標(biāo)記語(yǔ)言)
、、。
作用:定義網(wǎng)頁(yè)的結(jié)構(gòu)和內(nèi)容。
內(nèi)容:
結(jié)構(gòu)標(biāo)簽:如
內(nèi)容標(biāo)簽:如
、
、、。
表單標(biāo)簽:如 、、。
CSS(層疊樣式表)
作用:控制網(wǎng)頁(yè)的樣式和布局。
內(nèi)容:
字體設(shè)置:如 font-family、font-size。
顏色設(shè)置:如 color、background-color。
布局設(shè)計(jì):如 margin、padding、display、flex。
響應(yīng)式設(shè)計(jì):如媒體查詢(@media)。
JavaScript(腳本語(yǔ)言)
作用:增加網(wǎng)頁(yè)的交互性和動(dòng)態(tài)功能。
應(yīng)用:
表單驗(yàn)證。
動(dòng)畫(huà)效果。
與服務(wù)器交互(如通過(guò) AJAX請(qǐng)求)。
處理用戶事件(如點(diǎn)擊、懸停)。
Meta信息
中。
作用:提供頁(yè)面的元數(shù)據(jù),通常包含在
內(nèi)容:
網(wǎng)頁(yè)標(biāo)題:
字符集:。
SEO信息:如 。
設(shè)備適配:如 。
示例:
!DOCTYPE html?> Simple Page/title?> body { font-family: Arial, sans-serif; text-align: center; padding: 20px; } button { padding: 10px 20px; cursor: pointer; } /style?> /head?>Hello, Web!/h1?> Click the button for a surprise./p?> Click Me/button?> /body?> /html?>
8 Web頁(yè)面交互
Web頁(yè)面實(shí)現(xiàn)HTTP請(qǐng)求的方式:
HTTP請(qǐng)求頁(yè)面
描述:客戶端通過(guò) HTTP協(xié)議向服務(wù)器發(fā)送請(qǐng)求,服務(wù)器處理后返回響應(yīng)。
特點(diǎn):
最基礎(chǔ)的交互方式。
包括常見(jiàn)的 HTTP方法:GET、POST、PUT、DELETE等。
示例:
GET請(qǐng)求:瀏覽器訪問(wèn)網(wǎng)頁(yè),獲取靜態(tài)資源(HTML、CSS、JavaScript等)。
POST請(qǐng)求:提交表單數(shù)據(jù)。
表單提交
描述:通過(guò) HTML表單向服務(wù)器提交數(shù)據(jù)。
特點(diǎn):
表單數(shù)據(jù)會(huì)被編碼后隨請(qǐng)求發(fā)送。
可使用 GET或 POST方法。
示例:
Submit/button?> /form?>
AJAX(Asynchronous JavaScript and XML)
描述:使用 JavaScript在后臺(tái)與服務(wù)器通信,更新部分頁(yè)面內(nèi)容而無(wú)需刷新整個(gè)頁(yè)面。
特點(diǎn):
提高用戶體驗(yàn),減少頁(yè)面加載時(shí)間。
現(xiàn)代開(kāi)發(fā)中多用 JSON代替 XML。
示例:
fetch('/api/data', { method: 'GET' }) .then(response => response.json()) .then(data => console.log(data));
Web服務(wù)器響應(yīng)處理
直接響應(yīng)
定義:服務(wù)器直接處理請(qǐng)求,返回靜態(tài)資源或簡(jiǎn)單的動(dòng)態(tài)內(nèi)容,而不調(diào)用外部腳本或程序。
特點(diǎn)
高效:直接處理請(qǐng)求,無(wú)需額外調(diào)用外部程序,適合靜態(tài)內(nèi)容。
適用場(chǎng)景:
靜態(tài)資源(HTML、CSS、JavaScript、圖像等)的分發(fā)。
輕量級(jí)動(dòng)態(tài)內(nèi)容生成。
工作流程
客戶端發(fā)送 HTTP請(qǐng)求。
服務(wù)器解析請(qǐng)求 URL,查找相應(yīng)的資源(如文件路徑)。
直接讀取資源內(nèi)容并返回給客戶端,附加適當(dāng)?shù)?HTTP響應(yīng)頭。
CGI響應(yīng)
定義:服務(wù)器通過(guò) CGI(Common Gateway Interface)調(diào)用外部程序或腳本,處理客戶端請(qǐng)求并生成動(dòng)態(tài)響應(yīng)內(nèi)容。
特點(diǎn)
靈活性:可以動(dòng)態(tài)生成內(nèi)容,支持復(fù)雜邏輯。
適用場(chǎng)景:
動(dòng)態(tài)內(nèi)容生成(如用戶登錄、數(shù)據(jù)查詢)。
與數(shù)據(jù)庫(kù)交互或其他后臺(tái)服務(wù)的復(fù)雜邏輯處理。
工作流程
客戶端發(fā)送 HTTP請(qǐng)求。
服務(wù)器解析請(qǐng)求并將請(qǐng)求數(shù)據(jù)(如 URL參數(shù)或表單數(shù)據(jù))傳遞給 CGI程序。
CGI程序處理請(qǐng)求,生成響應(yīng)內(nèi)容并返回給服務(wù)器。
服務(wù)器將 CGI程序生成的內(nèi)容包裝為 HTTP響應(yīng)發(fā)送給客戶端。
9實(shí)現(xiàn)過(guò)程
接下來(lái),我們看看如何通過(guò)瀏覽器修改W55MH32的網(wǎng)絡(luò)配置。
注意:測(cè)試實(shí)例需要PC端和W55MH32處于同一網(wǎng)段。
首先需要編寫(xiě)網(wǎng)頁(yè)內(nèi)容,這里我們寫(xiě)了一個(gè)網(wǎng)頁(yè)配置頁(yè)面的內(nèi)容以及提交后等待重啟頁(yè)面的內(nèi)容,如下所示:
#define index_page "n" "n" " W55MH32 Configuration Page/title?>n" " n" " body { font-family: Arial, sans-serif; margin: 20px; padding: 20px; background-color: #f4f4f9; }n" " h1 { text-align: center; color: #333; }n" " form { max-width: 400px; margin: auto; background: #ffffff; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); }n" " label { display: block; margin-bottom: 8px; font-weight: bold; }n" " input[type=text], input[type=submit] { width: 400px; padding: 8px; margin-bottom: 12px; border: 1px solid #ccc; border-radius: 4px; }n" " input[type=submit] { background-color: #4CAF50; color: white; border: none; cursor: pointer; }n" " input[type=submit]:hover { background-color: #45a049; }n" " input[readonly] { background-color: #e9ecef; color: #6c757d; border: 1px solid #ced4da; cursor: not-allowed; }n" " .error { color: red; font-size: 12px; margin-top: -10px; margin-bottom: 10px; }n" " input::placeholder { color: #aaa; font-style: italic; }n" " /style?>n" " n" " function validateForm(event) {n" " const ipPattern = /^(\d{1,3}\.){3}\d{1,3}$/;n" " let isValid = true;n" " document.querySelectorAll('.error').forEach(e => e.textContent = '');n" " const fields = ['ip', 'subnet', 'gateway', 'dns'];n" " fields.forEach(field => {n" " const input = document.forms[0][field];n" " if (input.value.trim() === '') {n" " input.placeholder = 'e.g., 192.168.1.1';n" " document.getElementById(field + '-error').textContent = 'This field is required.';n" " isValid = false;n" " } else if (!ipPattern.test(input.value)) {n" " document.getElementById(field + '-error').textContent = 'Invalid IP address format.';n" " isValid = false;n" " }n" " });n" " if (!isValid) {n" " event.preventDefault();n" " }n" " }n" " /script?>n" "/head?>n" "n" " W55MH32 Configuration Page/h1?>n" " n" " MAC Address: /label?> n" " IP Address: /label?>
n" " Subnet Mask: /label?>
n" " Default Gateway: /label?>
n" " DNS Server: /label?>
n" " n" " /form?>n" "/body?>n" "/html?>n"
這里,我們提交網(wǎng)絡(luò)地址信息的方式為POST,提交的地址為config.cgi:
#define CONFIG_SUCCESS_PAGE "!DOCTYPE html?>n" "n" "n" " n" " n" " Configuration Modification Succeeded/title?>n" " n" " body {n" " font-family: Arial, sans-serif;n" " text-align: center;n" " padding-top: 100px;n" " background-color: #f0f0f0; n" " }n" " h1 {n" " color: green;n" " animation: fadeInOut 2s infinite;n" " }n" " #countdown {n" " font-size: 24px;n" " margin-top: 20px;n" " opacity: 0; n" " animation: fadeIn 1s forwards;n" " animation-delay: 1s; n" " }n" " @keyframes fadeIn {n" " from {n" " opacity: 0;n" " }n" " to {n" " opacity: 1;n" " }n" " }n" " /style?>n" "/head?>n" "n" " Configuration Modification Succeeded!/h1?>n" " Will redirect in 10 seconds. Please wait.../p?>n" "n" " let seconds = 10;n" " const countdownElement = document.getElementById('countdown');n" " const countdownInterval = setInterval(() => {n" " seconds--;n" " countdownElement.textContent = `Will redirect in ${seconds} seconds. Please wait...`;n" " if (seconds === 0) {n" " clearInterval(countdownInterval);n" " window.location.href = 'http://%d.%d.%d.%d/';n" " }n" " }, 1000);n" "/script?>n" "/body?>n" "/html?>"
步驟一:從EEPROM中讀取網(wǎng)絡(luò)地址信息并配置
check_eeprom_network_info(&default_net_info); network_init(ethernet_buf, &default_net_info);
check_eeprom_network_info()函數(shù)的作用是檢查EEPROM中是否有網(wǎng)絡(luò)地址信息,如果有則賦值給default_net_info結(jié)構(gòu)體。函數(shù)內(nèi)容如下:
uint8_t check_eeprom_network_info(wiz_NetInfo *net_info) { wiz_NetInfo eeprom_net_info = {0}; /*-----------------------------------------------------------------------------------*/ if (ee_CheckDevice(EEPROM_DEV_ADDR) == 1) { /* No EEPROM detected */ printf("No serial EEPROM detected!rn"); return 0; } ee_ReadBytes((uint8_t *)&eeprom_net_info, 0, sizeof(eeprom_net_info)); if (eeprom_net_info.mac[0] == 0x00 && eeprom_net_info.mac[1] == 0x08 && eeprom_net_info.mac[2] == 0xdc) { memcpy(net_info, &eeprom_net_info, sizeof(wiz_NetInfo)); return 1; } return 0; }
步驟二:注冊(cè)網(wǎng)頁(yè)內(nèi)容及HTTP Server初始化
printf("Please enter% d.% d.% d.% d in your browser to access the %s HTTP serverrn", net_info.ip[0], net_info.ip[1], net_info.ip[2], net_info.ip[3], _WIZCHIP_ID_); sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X", net_info.mac[0], net_info.mac[1], net_info.mac[2], net_info.mac[3], net_info.mac[4], net_info.mac[5]); sprintf(ip, "%d.%d.%d.%d", net_info.ip[0], net_info.ip[1], net_info.ip[2], net_info.ip[3]); sprintf(sn, "%d.%d.%d.%d", net_info.sn[0], net_info.sn[1], net_info.sn[2], net_info.sn[3]); sprintf(gw, "%d.%d.%d.%d", net_info.gw[0], net_info.gw[1], net_info.gw[2], net_info.gw[3]); sprintf(dns, "%d.%d.%d.%d", net_info.dns[0], net_info.dns[1], net_info.dns[2], net_info.dns[3]); sprintf(page, (char *)index_page, mac, ip, sn, gw, dns); reg_httpServer_webContent((uint8_t *)"index.html", (uint8_t *)page); // Build HTTP server web pages httpServer_init(http_tx_ethernet_buf, http_rx_ethernet_buf, 1, socknumlist); // Initializing the HTTP server
reg_httpServer_webContent()函數(shù)的作用是注冊(cè)web內(nèi)容,這里可以是頁(yè)面,也可以是JavaScript代碼。
httpServer_init的作用是初始化HTTP Server參數(shù),四個(gè)參數(shù)分別是HTTP發(fā)送緩存、HTTP接收緩存、使用的SOCKET數(shù)量以及對(duì)應(yīng)的SOCKET列表。
步驟三:注冊(cè)HTTP超時(shí)中斷程序
/** * @brief 1ms timer IRQ Handler * @param none * @return none */ void TIM3_IRQHandler(void) { static uint32_t tim3_1ms_count = 0; if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) { tim3_1ms_count++; if (tim3_1ms_count >= 1000) { DHCP_time_handler(); httpServer_time_handler(); tim3_1ms_count = 0; } TIM_ClearITPendingBit(TIM3, TIM_IT_Update); } }
步驟四:運(yùn)行HTTP Server程序
while (1) { httpServer_run(SOCKET_ID); }
httpServer_run()函數(shù)的邏輯跟TCP Server基本一致,也是運(yùn)行了一個(gè)狀態(tài)機(jī),根據(jù)SOCKET不同狀態(tài),執(zhí)行相應(yīng)的HTTP Server部分的處理,內(nèi)容如下:
void httpServer_run(uint8_t seqnum) { uint8_t s; // socket number uint16_t len; uint32_t gettime = 0; #ifdef _HTTPSERVER_DEBUG_ uint8_t destip[4] = { 0, }; uint16_t destport = 0; #endif http_request = (st_http_request *)pHTTP_RX; // Structure of HTTP Request parsed_http_request = (st_http_request *)pHTTP_TX; // Get the H/W socket number s = getHTTPSocketNum(seqnum); /* HTTP Service Start */ switch (getSn_SR(s)) { case SOCK_ESTABLISHED: // Interrupt clear if (getSn_IR(s) & Sn_IR_CON) { setSn_IR(s, Sn_IR_CON); } // HTTP Process states switch (HTTPSock_Status[seqnum].sock_status) { case STATE_HTTP_IDLE: if ((len = getSn_RX_RSR(s)) > 0) { if (len > DATA_BUF_SIZE) len = DATA_BUF_SIZE; len = recv(s, (uint8_t *)http_request, len); *(((uint8_t *)http_request) + len) = ''; parse_http_request(parsed_http_request, (uint8_t *)http_request); #ifdef _HTTPSERVER_DEBUG_ getSn_DIPR(s, destip); destport = getSn_DPORT(s); printf("rn"); printf("> HTTPSocket[%d] : HTTP Request received ", s); printf("from %d.%d.%d.%d : %drn", destip[0], destip[1], destip[2], destip[3], destport); #endif #ifdef _HTTPSERVER_DEBUG_ printf("> HTTPSocket[%d] : [State] STATE_HTTP_REQ_DONErn", s); #endif // HTTP 'response' handler; includes send_http_response_header / body function http_process_handler(s, parsed_http_request); gettime = get_httpServer_timecount(); // Check the TX socket buffer for End of HTTP response sends while (getSn_TX_FSR(s) != (getSn_TxMAX(s))) { if ((get_httpServer_timecount() - gettime) > 3) { #ifdef _HTTPSERVER_DEBUG_ printf("> HTTPSocket[%d] : [State] STATE_HTTP_REQ_DONE: TX Buffer clear timeoutrn", s); #endif break; } } if (HTTPSock_Status[seqnum].file_len > 0) HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_INPROC; else HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_DONE; // Send the 'HTTP response' end } break; case STATE_HTTP_RES_INPROC: /* Repeat: Send the remain parts of HTTP responses */ #ifdef _HTTPSERVER_DEBUG_ printf("> HTTPSocket[%d] : [State] STATE_HTTP_RES_INPROCrn", s); #endif // Repeatedly send remaining data to client send_http_response_body(s, 0, http_response, 0, 0); if (HTTPSock_Status[seqnum].file_len == 0) HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_DONE; break; case STATE_HTTP_RES_DONE: #ifdef _HTTPSERVER_DEBUG_ printf("> HTTPSocket[%d] : [State] STATE_HTTP_RES_DONErn", s); #endif // Socket file info structure re-initialize HTTPSock_Status[seqnum].file_len = 0; HTTPSock_Status[seqnum].file_offset = 0; HTTPSock_Status[seqnum].file_start = 0; HTTPSock_Status[seqnum].sock_status = STATE_HTTP_IDLE; //#ifdef _USE_SDCARD_ // f_close(&fs); //#endif #ifdef _USE_WATCHDOG_ HTTPServer_WDT_Reset(); #endif http_disconnect(s); break; default: break; } break; case SOCK_CLOSE_WAIT: #ifdef _HTTPSERVER_DEBUG_ printf("> HTTPSocket[%d] : ClOSE_WAITrn", s); // if a peer requests to close the current connection #endif disconnect(s); break; case SOCK_CLOSED: if (reboot_flag) { NVIC_SystemReset(); } #ifdef _HTTPSERVER_DEBUG_ printf("> HTTPSocket[%d] : CLOSEDrn", s); #endif if (socket(s, Sn_MR_TCP, HTTP_SERVER_PORT, 0x00) == s) /* Reinitialize the socket */ { #ifdef _HTTPSERVER_DEBUG_ printf("> HTTPSocket[%d] : OPENrn", s); #endif } break; case SOCK_INIT: listen(s); break; case SOCK_LISTEN: break; default: break; } // end of switch #ifdef _USE_WATCHDOG_ HTTPServer_WDT_Reset(); #endif }
步驟五:請(qǐng)求內(nèi)容處理
POST方式的CGI請(qǐng)求處理,在httpUtil.c文件的predefined_set_cgi_processor()函數(shù)中處理。
GET方式的CGI請(qǐng)求處理,在httpUtil.c文件的predefined_get_cgi_processor()函數(shù)中處理。
uint8_t predefined_set_cgi_processor(uint8_t *uri_name, uint8_t *uri, uint8_t *buf, uint16_t *len) { if (strcmp((const char *)uri_name, "config.cgi") == 0) { uint8_t *param; wiz_NetInfo new_net_info = {0}; wizchip_getnetinfo(&new_net_info); param = get_http_param_value((char *)uri, "ip"); //獲取IP地址 parse_ip((char *)param, new_net_info.ip); //更新IP地址 param = get_http_param_value((char *)uri, "subnet"); //獲取子網(wǎng)掩碼 parse_ip((char *)param, new_net_info.sn); //更新子網(wǎng)掩碼 param = get_http_param_value((char *)uri, "gateway"); //獲取默認(rèn)網(wǎng)關(guān) parse_ip((char *)param, new_net_info.gw); //更新默認(rèn)網(wǎng)關(guān) param = get_http_param_value((char *)uri, "dns"); //獲取DNS地址 parse_ip((char *)param, new_net_info.dns); //更新DNS地址
步驟六:重啟設(shè)備
在httpServer_run()函數(shù)中,當(dāng)SOCKET處于SOCK_CLOSED狀態(tài)時(shí)(即上次請(qǐng)求已經(jīng)處理完畢),再進(jìn)行復(fù)位操作,避免出現(xiàn)客戶端請(qǐng)求后,W55MH32未響應(yīng)就重啟導(dǎo)致客戶端請(qǐng)求超時(shí)的情況。
case SOCK_CLOSED: if (reboot_flag) { NVIC_SystemReset(); }
10運(yùn)行結(jié)果
燒錄例程運(yùn)行后,首先進(jìn)行了PHY鏈路檢測(cè),然后是通過(guò)DHCP獲取網(wǎng)絡(luò)地址并打印網(wǎng)絡(luò)地址信息,最后HTTP Server程序開(kāi)始監(jiān)聽(tīng)客戶端的請(qǐng)求并處理響應(yīng),如下圖所示:
接著我們打開(kāi)瀏覽器,輸入W55MH32的IP地址進(jìn)行訪問(wèn)。
然后我們將IP地址改為192.168.1.33,DNS服務(wù)器地址改為114.114.114.114,并點(diǎn)擊Submit按鈕。
等待W55MH32重啟后,瀏覽器會(huì)自動(dòng)跳轉(zhuǎn)至新地址。
11總結(jié)
本文介紹了在 W55MH32芯片上實(shí)現(xiàn) HTTP Server功能,并通過(guò)瀏覽器修改其網(wǎng)絡(luò)地址信息的方法。闡述了 HTTP協(xié)議的概念、特點(diǎn)、應(yīng)用場(chǎng)景、工作流程、請(qǐng)求方法、響應(yīng)內(nèi)容,以及 Web頁(yè)面構(gòu)成和交互方式。展示了在W55MH32上實(shí)現(xiàn)的過(guò)程。
下一篇將講解在該芯片上實(shí)現(xiàn) SNTP授時(shí)功能,介紹從 SNTP服務(wù)器獲取準(zhǔn)確時(shí)間的原理和實(shí)現(xiàn)步驟。敬請(qǐng)期待!
WIZnet是一家無(wú)晶圓廠半導(dǎo)體公司,成立于 1998年。產(chǎn)品包括互聯(lián)網(wǎng)處理器 iMCU?,它采用 TOE(TCP/IP卸載引擎)技術(shù),基于獨(dú)特的專(zhuān)利全硬連線 TCP/IP。iMCU?面向各種應(yīng)用中的嵌入式互聯(lián)網(wǎng)設(shè)備。
WIZnet在全球擁有 70多家分銷(xiāo)商,在香港、韓國(guó)、美國(guó)設(shè)有辦事處,提供技術(shù)支持和產(chǎn)品營(yíng)銷(xiāo)。
香港辦事處管理的區(qū)域包括:澳大利亞、印度、土耳其、亞洲(韓國(guó)和日本除外)。
審核編輯 黃宇
-
嵌入式
+關(guān)注
關(guān)注
5175文章
19974瀏覽量
324404
發(fā)布評(píng)論請(qǐng)先 登錄
第三十章 W55MH32 HTTP_Server&NetBIOS示例

第二十九章 W55MH32 Modbus_TCP_Server示例

第二十六章 W55MH32?上位機(jī)搜索和配置示例

第十八章 W55MH32 FTP_Server示例

第十七章 W55MH32 ARP示例

第十六章 W55MH32 PING示例

第十五章 W55MH32 SNMP示例

第十四章 W55MH32 TFTP示例

第十二章 W55MH32 NetBIOS示例

第十章 W55MH32 SNTP示例

第六章 W55MH32 UDP?Multicast示例

第五章 W55MH32 UDP示例

第三章 W55MH32 TCP Client示例

第二章 W55MH32 DHCP示例

W55MH32高性能以太網(wǎng)單片機(jī)教程 第九章 窗口看門(mén)狗(WWDG)

評(píng)論