Cách chạy Máy chủ Web trên Arduino

Trong hướng dẫn này, tôi sẽ chỉ cho bạn cách khởi động Máy chủ Web trên thiết bị Arduino có WiFi, như của tôiArduino MKR WiFi 1010.

Chúng tôi sẽ kết nối với mạng WiFi hiện có và chúng tôi sẽ có thể tương tác với Arduino từ trình duyệt của mình thông quaHTTP.

Điều này rất thú vị đối với nhiều loại ứng dụng. Từ việc kiểm tra dữ liệu cảm biến đơn giản, đến thực hiện các hành động dựa trênYêu cầu HTTPđã thực hiện.

Chúng tôi sẽ bắt đầu từ chương trình này được xác định trongKết nối với mạng WiFi bằng Arduinohướng dẫn:

#include <SPI.h>
#include <WiFiNINA.h>

void setup() {
  char ssid[] = SECRET_SSID;
  char pass[] = SECRET_PASS;

Serial.begin(9600); while (!Serial);

int status = WL_IDLE_STATUS; while (status != WL_CONNECTED) { Serial.print("Connecting to "); Serial.println(ssid); status = WiFi.begin(ssid, pass); delay(5000); }

Serial.print("IP address: "); Serial.println(WiFi.localIP()); }

void loop() {

}

Trước khi thiết lập (), hãy thêm dòng này:

WiFiServer server(80);

để khởi tạo mộtTCPmáy chủ trên cổng 80 và ở cuốisetup()gọi

server.begin();

để khởi động máy chủ.

Bây giờ đây là một máy chủ TCP, không phải một máy chủ HTTP. Nhưng vì HTTP (một giao thức ứng dụng TCP / IP) được xây dựng trên TCP (lớp truyền tải), chúng ta có thể xây dựng máy chủ HTTP của riêng mình, khá dễ dàng.

Đầu tiên chúng ta cần lắng nghe các kết nối của máy khách. Chúng tôi làm như vậy trongloop():

void loop() {
  WiFiClient client = server.available();
  if (client) {

} }

Phương thức sẵn có () củaserverlắng nghe khách hàng đến.

Bên trongif (client) {}kiểm tra, chúng tôi có một ứng dụng khách HTTP được kết nối. Những gì chúng ta cần làm là:

  • gọiclient.connected()để kiểm tra xem dữ liệu đã được kết nối chưa và có dữ liệu để đọc
  • gọiclient.available()để lấy số byte có sẵn để đọc (điều này đảm bảo có dữ liệu để đọc)
  • gọiclient.read()để đọc một byte từ dữ liệu đến (yêu cầu HTTP do máy khách gửi)
  • gọiclient.println()hoặc làclient.print()để gửi dữ liệu đến máy khách, xây dựng phản hồi HTTP thích hợp
  • gọiclient.stop()kết thúc kết nối

Chúng tôi bắt đầu in ra giao diện nối tiếp từng ký tự do máy khách gửi và cuối cùng chúng tôi đóng kết nối:

void loop() {
  WiFiClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
      }
    }
client.stop();

} }

Hãy thử tải lên chương trình này trên Arduino. Trỏ trình duyệt của bạn đến địa chỉ IP. Bạn sẽ thấy một cái gì đó như thế này được in vào giao diện nối tiếp. Đây là những gì được gửi bởi trình duyệt:

GET / HTTP/1.1
Host: 192.168.1.40
Upgrade-Insecure-Requests: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.2 Safari/605.1.15
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: keep-alive

Note the ending empty line. This is the end of the HTTP request.

We need to intercept this empty line.

Each line in the HTTP request is terminated by a CR carriage return character (\r), and a LF line feed character (\n).

So the end of the request can be determined by 2 sets of those sequences: \r\n\r\n.

This simple algorithm will work, we just memorize 2 characters prior to the current one, and we check if we identify the sequence \n\r\n (the last 3 characters in that sequence are enough to determine the last line):

void loop() {
  WiFiClient client = server.available();
  if (client) {
<span style="color:#66d9ef">char</span> prevprev;
<span style="color:#66d9ef">char</span> prev;

<span style="color:#66d9ef">while</span> (client.connected()) {
  <span style="color:#66d9ef">if</span> (client.available()) {
    <span style="color:#66d9ef">char</span> c <span style="color:#f92672">=</span> client.read();
    Serial.write(c);

    <span style="color:#66d9ef">if</span> (prevprev <span style="color:#f92672">==</span> <span style="color:#e6db74">'\n'</span> <span style="color:#f92672">&amp;&amp;</span> prev <span style="color:#f92672">==</span> <span style="color:#e6db74">'\r'</span> <span style="color:#f92672">&amp;&amp;</span> c <span style="color:#f92672">==</span> <span style="color:#e6db74">'\n'</span>) {
      <span style="color:#75715e">//we can send the response!

}

    prevprev <span style="color:#f92672">=</span> prev;
    prev <span style="color:#f92672">=</span> c;
  }
}

client.stop();

} }

So now we can send the response inside the if, we can use client.println() for this, and we add a simple response like this:

HTTP/1.1 200 OK
Content-Type: text/html
Connection: close

<!DOCTYPE HTML> <html> test </html>

In this way:

client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("test");
client.println("</html>");
break;

The break; statement ends the while (client.connected()) {} block.

Here is the full program:

#include <SPI.h>
#include <WiFiNINA.h>

WiFiServer server(80);

void setup() { char ssid[] = SECRET_SSID; char pass[] = SECRET_PASS;

Serial.begin(9600); while (!Serial);

int status = WL_IDLE_STATUS; while (status != WL_CONNECTED) { Serial.print("Connecting to "); Serial.println(ssid); status = WiFi.begin(ssid, pass); delay(5000); }

Serial.print("IP address: "); Serial.println(WiFi.localIP());

server.begin(); }

void loop() { WiFiClient client = server.available(); if (client) {

<span style="color:#66d9ef">char</span> prevprev;
<span style="color:#66d9ef">char</span> prev;
<span style="color:#66d9ef">while</span> (client.connected()) {
  <span style="color:#66d9ef">if</span> (client.available()) {
    <span style="color:#66d9ef">char</span> c <span style="color:#f92672">=</span> client.read();
    Serial.write(c);

    <span style="color:#66d9ef">if</span> (prevprev <span style="color:#f92672">==</span> <span style="color:#e6db74">'\n'</span> <span style="color:#f92672">&amp;&amp;</span> prev <span style="color:#f92672">==</span> <span style="color:#e6db74">'\r'</span> <span style="color:#f92672">&amp;&amp;</span> c <span style="color:#f92672">==</span> <span style="color:#e6db74">'\n'</span>) {
      client.println(<span style="color:#e6db74">"HTTP/1.1 200 OK"</span>);
      client.println(<span style="color:#e6db74">"Content-Type: text/html"</span>);
      client.println(<span style="color:#e6db74">"Connection: close"</span>);
      client.println();
      client.println(<span style="color:#e6db74">"&lt;!DOCTYPE HTML&gt;"</span>);
      client.println(<span style="color:#e6db74">"&lt;html&gt;"</span>);
      client.println(<span style="color:#e6db74">"test"</span>);
      client.println(<span style="color:#e6db74">"&lt;/html&gt;"</span>);
      <span style="color:#66d9ef">break</span>;
    }

    prevprev <span style="color:#f92672">=</span> prev;
    prev <span style="color:#f92672">=</span> c;
  }
}

client.stop();

} }

Try it, you should see test showing up in the browser:

The approach works until you need to figure out how what the client asked us.

In that case you want to read each line, so this alternative approach works better:

void loop() {
  WiFiClient client = server.available();
  if (client) {
    String line = "";
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
    <span style="color:#66d9ef">if</span> (c <span style="color:#f92672">!=</span> <span style="color:#e6db74">'\n'</span> <span style="color:#f92672">&amp;&amp;</span> c <span style="color:#f92672">!=</span> <span style="color:#e6db74">'\r'</span>) {
      line <span style="color:#f92672">+=</span> c;
    }

    <span style="color:#66d9ef">if</span> (c <span style="color:#f92672">==</span> <span style="color:#e6db74">'\n'</span>) {
      <span style="color:#66d9ef">if</span> (line.length() <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>) {
        client.println(<span style="color:#e6db74">"HTTP/1.1 200 OK"</span>);
        client.println(<span style="color:#e6db74">"Content-Type: text/html"</span>);
        client.println(<span style="color:#e6db74">"Connection: close"</span>);
        client.println();
        client.println(<span style="color:#e6db74">"&lt;!DOCTYPE HTML&gt;"</span>);
        client.println(<span style="color:#e6db74">"&lt;html&gt;"</span>);
        client.println(<span style="color:#e6db74">"test"</span>);
        client.println(<span style="color:#e6db74">"&lt;/html&gt;"</span>);
        <span style="color:#66d9ef">break</span>;
      } <span style="color:#66d9ef">else</span> {
        line <span style="color:#f92672">=</span> <span style="color:#e6db74">""</span>;
      }
    }
  }
}

client.stop();

} }

In the last else we can inspect the line because the line is terminated, and act accordingly to our needs.


More electronics tutorials: