第33课 ENC28J60联网 Web 服务器

我是潘,曾经是个工程师。这是为 Ardui.Co 制作的 “Arduino 公开课” 系列的入门教程。上节课介绍了如何访问服务器,反过来,本课要让 Arduino 作为一个可以随时随地访问 Web 服务器,在交互控制中更有现实意义。有任何疑问请在评论区提出,我会逐一回答。

Arduino 更适合作为控制节点,而不适合当服务器,在复杂的中央控制系统上,Raspberry Pi 是我的首选。不过,在需要快速、简单、可靠的应用环境中,将一块 Arduino 作为节点的网络界面也未尝不可。但是区区的 32KB ROM 十分考验我们对 HTML 代码的优化能力。

其实,这节课的意义在于理解 Arduino 是如何相应来自网络的请求,作为系统中的节点,这点相当重要。

HTTP 可能是世界上使用最广的通信协议了。访问一个网站,服务器和浏览器之间就是通过 HTTP 协议来互通信息。HTTP 协议的应用层是由 HTML 语言构成的,由于 HTML 属于文本类型的解析性语言,所以即使是主频只有 16MHz 的 Arduino 单片机,也可以轻松驾驭它。

利用 HTTP 通信,不仅通过一般的 PC 浏览器去访问、控制 Arduino,而且可以让它利用局域网,构成一个更大的节点网络。相比 I2C、SPI 的通信连接方式,HTTP 理论上,只要找到路由,是可以无线拓展的。当然,HTTP 更适合人机、节点之间、或者中央与节点间的长距离通信,毕竟在硬件通信层面,串口、I2C、SPI 等协议的延时要低得多。 (HTTP 的总体延时在毫秒级别,而 I2C 在高速模式下 4MHz,延时在微秒级)

Web 服务器完整代码如下:

设置MAC、IP地址等都属于基础部分,核心内容在 loop() 中:

首先,我们将 packetLoop() 的返回值保存在一个变量里 pos。

缓存中,pos 是浏览器请求开始的位置,如果 pos 有效(大于0),则把请求打印出来(方便学习理解,但不是必须的)。

难点在这里,BufferFiller 是一个构造函数(Constructor,参考官方文档),它的对象 bfill,用于存储服务器对浏览器的响应内容。tcpOffset() 指针,指向响应内容的位置。

用 emit_p() 方法将响应内容保存在缓冲区,并用PSTR() 将网页内容(字符串存)储在 Flash 空间中,以节省 SRAM。

position() 方法以获得 bfill 包含的内容长度,然后,httpServerReply() 获取缓冲区的内容,响应浏览器的请求。

为何一次访问会产生两次请求?因为浏览器除了网页内容外,还会请求 favicon.ico 网站的角标:

 

Leave a Reply

Your email address will not be published. Required fields are marked *