查看: 92875|回复: 110

Arduino教程——使用Ethernet构建简易的Web Server

  [复制链接]
  • TA的每日心情
    郁闷
    2018-12-6 22:21
  • 签到天数: 48 天

    [LV.5]常住居民I

    发表于 2014-12-24 01:15 | 显示全部楼层 |阅读模式
    本教程适用于使用WIZnet w5100/w5500的arduino控制器
    完整版见《Arduino程序设计基础》第二版

    程序一

    这里我们使用Arduino Ethernet建立一个简单网页服务器,当Arduino服务器接收到浏览器访问请求时,即会发送响应消息,浏览器接收到响应消息,会将其中包含的HTML文本转换为网页显示出来。
    这样就可以将传感器获取到的信息显示到网页上,每个在该网络范围内的计算机或其他移动设备,无论什么平台都可以通过网页浏览器了解到各传感器的数据。


    kittenblock中小学创客名师推荐的图形化编程软件

    /*
    OpenJumper WebServer Example
    建立一个显示传感器信息的Arduino服务器
    http://www.openjumper.com/
    http://x.openjumper.com/ethernet/
    */
    
    #include <SPI.h>
    #include <Ethernet.h>
    
    // 设定MAC地址、IP地址
    // IP地址需要参考你的本地网络设置
    byte mac[] = { 
      0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
    IPAddress ip(192,168,1,177);
    
    // 初始化Ethernet库
    // HTTP默认端口为80
    EthernetServer server(80);
    
    void setup() {
    // 初始化串口通信
      Serial.begin(9600);
    
      // 开始ethernet连接,并作为服务器初始化
      Ethernet.begin(mac, ip);
      server.begin();
      Serial.print("server is at ");
      Serial.println(Ethernet.localIP());
    }
    
    void loop() {
      // 监听客户端传来的数据
      EthernetClient client = server.available();
      if (client) {
        Serial.println("new client");
        // 一个Http请求结尾必须带有回车换行
        boolean currentLineIsBlank = true;
        while (client.connected()) {
          if (client.available()) {
            char c = client.read();
            Serial.write(c);
            // 如果收到空白行,说明http请求结束,并发送响应消息
            if (c == '\n' && currentLineIsBlank) {
              // 发送标准的HTTP响应
              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>");
              // 添加一个meta刷新标签, 浏览器会每5秒刷新一次
              // 如果此处刷新频率设置过高,可能会出现网页的卡死的状况
              client.println("<meta http-equiv=\"refresh\" content=\"5\">");
              // 输出每个模拟口读到的值
              for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
                int sensorReading = analogRead(analogChannel);
                client.print("analog input ");
                client.print(analogChannel);
                client.print(" is ");
                client.print(sensorReading);
                client.println("<br />");       
              }
              client.println("</html>");
              break;
            }
            if (c == '\n') {
              // 已经开始一个新行
              currentLineIsBlank = true;
            } 
            else if (c != '\r') {
              // 在当前行已经得到一个字符
              currentLineIsBlank = false;
            }
          }
        }
        // 等待浏览器接收数据
        delay(1);
        // 断开连接
        client.stop();
        Serial.println("client disonnected");
      }
    }
    



    下载程序后,通过浏览器,访问Arduino Ethernet所在的IP地址(如程序中设定的IP地址为192.168.1.177),即可看到如图10-11对应的网页了。
    webserver0.jpg
    在网页中显示了A0至A5所读出的模拟值,你也可以通过修改以上程序,显示其他类型的数据。

    以上程序修改自Arduino IDE自带的Web Server例程,它是通过不断刷新网页来获取Arduino反馈来完成的。实际上,在当今web开发上,我们几乎都是通过ajax不刷新网页,来与服务器通信的。这里我写了一个ajax+arduino web server的示例。


    程序二

    要制作这个项目,首先我们需要准备一个
    webserver.jpg

    该网页HTML部分如下:

    kittenblock中小学创客名师推荐的图形化编程软件

    <!--例程网页控制Arduino -->
    <!--奈何col  2014.12.24 v3.0 -->
    <!--学了半小时js,求别吐槽 -->
    <html>
    <head>
    <meta charset="UTF-8">
    <title>OpenJumper!Arduino Web Server</title>
    <script type="text/javascript">
    function send2arduino(){
            var xmlhttp;
            if (window.XMLHttpRequest)
            {// code for IE7+, Firefox, Chrome, Opera, Safari
                    xmlhttp=new XMLHttpRequest();
            }
            else
            {// code for IE6, IE5
                    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
            }
    
            element=document.getElementById("light");
            if (element.innerHTML.match("Turn on"))
              { 
                      element.innerHTML="Turn off"; 
                      xmlhttp.open("GET","?on",true);
              }
            else
              { 
                      element.innerHTML="Turn on";
                      xmlhttp.open("GET","?off",true); 
              }
            xmlhttp.send();        
    }
    function getBrightness(){
            var xmlhttp;
            if (window.XMLHttpRequest)
            {// code for IE7+, Firefox, Chrome, Opera, Safari
                    xmlhttp=new XMLHttpRequest();
            }
            else
            {// code for IE6, IE5
                    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
            }
            xmlhttp.onreadystatechange=function()
        {
                if (xmlhttp.readyState==4 && xmlhttp.status==200)
                {
                        document.getElementById("brightness").innerHTML=xmlhttp.responseText;
                }
        }
            xmlhttp.open("GET","?getBrightness",true); 
            xmlhttp.send();        
    }
    window.setInterval(getBrightness,5000); 
    </script>
    </head>
    <body>
    <div align="center">
    <h1>Arduino Web Server</h1>
    <div>brightness:</div>
    <div id="brightness">??</div>
    <button id="light" type="button">Turn on</button>
    <button type="button">About</button>
    </div>
    </body>
    </html>


    在该网页中,第一个id为light的button标签,用于控制开关灯。点击后,会调用send2arduino()函数,浏览器会以AJAX的方式向Arduino服务器发送含有"?on"或"?off"的GET请求。Arduino服务器通过判断请求中的内容,做出开关灯动作。
    而getBrightness()函数通过一个定时操作,每秒钟运行一次,每次都以AJAX的方式向Arduino服务器发送含有"?getBrightness"的GET请求,Arduino接收到该请求后,就会读取传感器数据并返回给浏览器。同时getBrightness()函数会将id为brightness的div标签中的内容更新为返回的数据。

    此外我们将A0引脚连接光敏模块,用于采集室内光线;D2引脚连接LED模块。
    示例程序代码如下:

    kittenblock中小学创客名师推荐的图形化编程软件

    
    /*
    OpenJumper WebServer Example
    http://www.openjumper.com/ethernet/
    
    显示室内照度+开关灯控制
    通过手机、平板、计算机等设备访问
    Arduino Server,就看到当前室内光线照度
    在A0引脚连接光敏模块,用于采集室内光线;在2号引脚连接LED模块。
    
    奈何col 2014.12.25
    */
    
    #include <SPI.h>
    #include <Ethernet.h>
    
    byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
    IPAddress ip(192,168,1,177);
    EthernetServer server(80);
    EthernetClient client;
    String readString=""; 
    int Light=2;
    int Sensor=A0;
    
    void setup() {
      Serial.begin(9600);
      //初始化Ethernet通信
      Ethernet.begin(mac, ip);
      server.begin();
      pinMode(Light,OUTPUT);
      Serial.print("Server is at ");
      Serial.println(Ethernet.localIP());
    }
    
    void loop() {
      // 监听连入的客户端
      client = server.available();
      if (client) {
        Serial.println("new client");
        boolean currentLineIsBlank = false;
        while (client.connected()) {
          if (client.available()) {
            char c = client.read();
            readString += c;
            if (c == '\n') {
              Serial.println(readString);
              //检查收到的信息中是否有”on”,有则开灯
              if(readString.indexOf("?on") >0) {
                digitalWrite(Light, HIGH);
                Serial.println("Led On");
                break;
              }
              //检查收到的信息中是否有”off”,有则关灯
              if(readString.indexOf("?off") >0) {
                digitalWrite(Light, LOW);
                Serial.println("Led Off");
                break;
              }
              //检查收到的信息中是否有”getBrightness”,有则读取光敏模拟值,并返回给浏览器
              if(readString.indexOf("?getBrightness") >0) {
                client.println(analogRead(Sensor));
                break;
              }
              //发送HTML文本
              SendHTML();
              break;
            }        
          }
        }
        delay(1);
        client.stop();
        Serial.println("client disonnected");
        readString=""; 
      }
    }
    
    // 用于输出HTML文本的函数
    void SendHTML()
    {
      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><head><meta charset=\"UTF-8\"><title>OpenJumper!Arduino Web Server</title><script type=\"text/javascript\">");
      client.println("function send2arduino(){var xmlhttp;if (window.XMLHttpRequest)xmlhttp=new XMLHttpRequest();else xmlhttp=new ActiveXObject(\"Microsoft.XMLHTTP\");element=document.getElementById(\"light\");if (element.innerHTML.match(\"Turn on\")){element.innerHTML=\"Turn off\"; xmlhttp.open(\"GET\",\"?on\",true);}else{ element.innerHTML=\"Turn on\";xmlhttp.open(\"GET\",\"?off\",true); }xmlhttp.send();}");
      client.println("function getBrightness(){var xmlhttp;if (window.XMLHttpRequest)xmlhttp=new XMLHttpRequest();else xmlhttp=new ActiveXObject(\"Microsoft.XMLHTTP\");xmlhttp.onreadystatechange=function(){if (xmlhttp.readyState==4 && xmlhttp.status==200)document.getElementById(\"brightness\").innerHTML=xmlhttp.responseText;};xmlhttp.open(\"GET\",\"?getBrightness\",true); xmlhttp.send();}window.setInterval(getBrightness,1000);</script>");
      client.println("</head><body><div align=\"center\"><h1>Arduino Web Server</h1><div>brightness:</div><div id=\"brightness\">");  
      client.println(analogRead(Sensor));
      client.println("</div><button id=\"light\" type=\"button\" onclick=\"send2arduino()\">Turn on</button><button type=\"button\" onclick=\"alert('OpenJumper Web Server')\">About</button></div></body></html>");
    }
    
    



    下载程序,并将你的Arduino接入到局域网中。现在你就可以通过浏览器访问你的Arduino了。页面的中的亮度数据,每秒回更新一次,还可以通过“Turn on”、“Turn off”按钮控制LED的开关。

    需要注意的是Arduino本身的存储空间有限,存放和输出网页信息会消耗掉很多空间,因此在以上示例程序中,尽量将client.println()输出的文本行数减少,可以节省一定的存储空间。
    在Arduino Ethernet控制器及扩展板上通常都带有SD卡槽,也可以尝试将网页数据放置在SD卡上,然后分段读取,并通过Ethernet输出,从而达到节省存储空间的目的。








    如果以上内容对你有帮助,你可以通过打赏支持作者
  • TA的每日心情
    郁闷
    2018-12-6 22:21
  • 签到天数: 48 天

    [LV.5]常住居民I

     楼主| 发表于 2016-10-13 15:09 | 显示全部楼层
    正在途中 发表于 2016-10-13 14:37
    昨天把这两个例程都跑了一遍,都成功了。试图给第二程序增加一个开关,结果报错:没有足够的内存。当前以例 ...

    可能你输出的字符太多了,可以把字符串,存在flash中,以节省RAM空间,详见:Arduino进阶教程——使用PROGMEM在flash中存储数据   http://www.arduino.cn/thread-7781-1-1.html     
    如果以上内容对你有帮助,你可以通过打赏支持作者

    该用户从未签到

    发表于 2014-12-30 11:12 | 显示全部楼层
    网页做得漂亮一点,就可以PK Yeelink了

    点评

    arduino本身的空间不够,实现不了复杂的web页面,硬要实现也有办法,不过比较复杂,最好的方法就是单独再做个app来连接这个web server,arduino只负责接收网络命令,做出动作~~~  详情 回复 发表于 2014-12-30 23:57
  • TA的每日心情
    郁闷
    2018-12-6 22:21
  • 签到天数: 48 天

    [LV.5]常住居民I

     楼主| 发表于 2014-12-30 23:57 | 显示全部楼层
    My_skity 发表于 2014-12-30 11:12
    网页做得漂亮一点,就可以PK Yeelink了

    arduino本身的空间不够,实现不了复杂的web页面,硬要实现也有办法,不过比较复杂,最好的方法就是单独再做个app来连接这个web server,arduino只负责接收网络命令,做出动作~~~
    如果以上内容对你有帮助,你可以通过打赏支持作者
  • TA的每日心情
    郁闷
    2015-1-30 16:06
  • 签到天数: 5 天

    [LV.2]偶尔看看I

    发表于 2015-1-11 15:35 | 显示全部楼层
    请问硬件模块需要用到哪些,求介绍哦

    点评

    我用的 Zduino ethernet,你也可以在UNO上接个W5100/W5500扩展板,实现网络功能  详情 回复 发表于 2015-1-12 09:31
  • TA的每日心情
    郁闷
    2018-12-6 22:21
  • 签到天数: 48 天

    [LV.5]常住居民I

     楼主| 发表于 2015-1-12 09:31 | 显示全部楼层
    简单侣图 发表于 2015-1-11 15:35
    请问硬件模块需要用到哪些,求介绍哦

    我用的 Zduino ethernet,你也可以在UNO上接个W5100/W5500扩展板,实现网络功能
    如果以上内容对你有帮助,你可以通过打赏支持作者
  • TA的每日心情
    慵懒
    2019-2-13 16:55
  • 签到天数: 506 天

    [LV.9]以坛为家II

    发表于 2015-1-12 11:04 | 显示全部楼层
    奈何col 发表于 2014-12-30 23:57
    arduino本身的空间不够,实现不了复杂的web页面,硬要实现也有办法,不过比较复杂,最好的方法就是单独再 ...

    还是这样各司其职比较好,不能将W5100真的拿来当服务器用。
  • TA的每日心情
    郁闷
    2015-1-30 16:06
  • 签到天数: 5 天

    [LV.2]偶尔看看I

    发表于 2015-1-17 22:28 | 显示全部楼层
    为啥我的网页是打不开的呢,我改好IP了啊
  • TA的每日心情
    郁闷
    2015-1-30 16:06
  • 签到天数: 5 天

    [LV.2]偶尔看看I

    发表于 2015-1-17 22:48 | 显示全部楼层
    [img][/img]为啥这样的
  • TA的每日心情
    慵懒
    2019-2-13 16:55
  • 签到天数: 506 天

    [LV.9]以坛为家II

    发表于 2015-1-18 06:19 | 显示全部楼层
    图呢?{:soso_e197:}
    您需要登录后才可以回帖 登录 | 立即注册  

    本版积分规则

    热门推荐

    KittenBot杯第六届开源硬件开发大赛启动啦
    KittenBot杯第六届开源硬
    大赛简介: 第六届开源硬件开发大赛由Arduino中文社区发起 由KittenBot冠名赞助
    求助,Due使用问题。
    求助,Due使用问题。
    如图,Due没有SPI库和Wire库。
    arduino+onenet+edp协议
    arduino+onenet+edp协议
    每次在edp.c这里报错,请问这是什么问题?(这一句本身应该没有问题的)
    一文教你选择Arduino开发板,小白进
    一文教你选择Arduino开发
    笔者在2016年接触了Arduino,跳了万条坑,行了千里弯,到今天也算是Arduino的一
    能够与arduino结合的嵌入式视觉识别模块
    能够与arduino结合的嵌入
    该视觉识别模块是我司于2018年新推出的产品,处理器采用双核MCU,面向创客以及steam
    Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   ( 蜀ICP备14017632号-3 )
    快速回复 返回顶部 返回列表