最終更新日:2023/2/3
RP2040でI/O制御するWebserverの構築ソースを移植してみました。普通に動くのですが、クライアントブラズザでラジオボタンによる8者択一という仕組みを組み込もうとしたら、ブラウザ側は択一なのにサーバ側は自分で戻さないといけないことが判りました。これはこれで実際に構築したことで気づいたことであり意味がありました。
/* * 2023年2月3日T.Wanibe * 過去に作成したMEGA+WIZ5100で動作するAJAXWebserverをPicp+W5500で動作する様に移植作業を実施する * 浅井さん案件では8chの切替をブラウザで行うことを期待しています。このデモンストレーション版です * 基本的に動作します。 * 20180914 T.Wanibe * オリジナルのコードは反応が良い事を確認した。このコードを元に幾つかレタッチしてゆく事にする * まずはHTML部分をページ毎に関数化したい。インデントが深くなりすぎるのを解決したい。 *- * Ajax Web Server * * A simple web server that shows the value of the analog input pins. * using an Arduino Wiznet Ethernet shield. * * Circuit: * Ethernet shield attached to pins 10, 11, 12, 13 * Analog inputs attached to pins A0 through A5 (optional) * * created 18 Dec 2009 * by David A. Mellis * modified 4 Sep 2010 * by Tom Igoe * * - - - - - - - - - - - - - - - - - - - - - - - - * modified 16 Sep 2011 // Ajax version. * by TETRASTYLE * for Arduino IDE 0022 * * get Digital & Analog port status ( JSON(P) formatted data) * <-- http://192.168.1.177/?= * * return value * --> cb({"D":[D0,D1,D2,D3,D4,D5,D6,D7],"A":[A0,A1,A2,A3,A4,A5]}); * * toggle Digital Port (D0 - D7) * <-- http://192.168.1.177/?btn=0 * <-- http://192.168.1.177/?btn=1 * ... * <-- http://192.168.1.177/?btn=7 *- * * オリジナルコードのコンパイルを実行したところRAM使用量が2Kを超えた。UNOでは使えない。 * 最大253952バイトのフラッシュメモリのうち、スケッチが14006バイト(5%)を使っています。 * 最大8192バイトのRAMのうち、グローバル変数が2265バイト(27%)を使っていて、ローカル変数で5927バイト使うことができます * F()でFlashメモリ(プログラム領域)にデータを格納し、読み込む手続きを実施した * 最大253952バイトのフラッシュメモリのうち、スケッチが13912バイト(5%)を使っています。 * 最大8192バイトのRAMのうち、グローバル変数が495バイト(6%)を使っていて、ローカル変数で7697バイト使うことができます。 * RAMの使用量が500Byteまで落ちており意味がある。実行速度の違いは体感は出来ないと思う。 * IDE1.8.7に更新 * 最大253952バイトのフラッシュメモリのうち、スケッチが15020バイト(5%)を使っています。 * 最大8192バイトのRAMのうち、グローバル変数が500バイト(6%)を使っていて、ローカル変数で7692バイト使うことができます。 * Pico環境での状況 * 最大1044480バイトのフラッシュメモリのうち、スケッチが68140バイト(6%)を使っています。 * 最大262144バイトのRAMのうち、グローバル変数が8064バイト(3%)を使っていて、ローカル変数で254080バイト使うことができます。 */ #define TIMER_INTERRUPT_DEBUG 1 #define _TIMERINTERRUPT_LOGLEVEL_ 4 #include <TimeLib.h> #include "RPi_Pico_TimerInterrupt.h" #include <SPI.h> #include <Ethernet3.h> #define HttpPort 80 #define BAUDRATE 115200 #define NICReset 18 #define NICInit 19 #define SPI_SCK 2 #define SPI_TX 3 #define SPI_RX 4 #define SPI_CS 5 #define TIMER0_INTERVAL_MS 1000 #define vers "Pico_AjaxWebserver_1_01" uint32_t delay_ms = 8000; //8秒 最大8.3秒 boolean gflag =false; String parm; // 1 で消灯 0で点灯 int dout[8] = {1,1,1,1,1,1,1,1}; //物理接続要素 int dOsPins[] = {16,17,20,21,22,26,27,28}; // byte mac[] = {0x00,0x08,0xDC,0x54,0x4D,0xDD}; //WIZNET byte ip[] = {192, 168, 0, 208}; byte subnet[] = {255,255,255,0}; byte gateway[] = {192,168,0,1}; byte fTogle1 = LOW; unsigned long OperatingTime = 0; //稼働時間 Count2で1秒 long gPreTime,gNowTime; // EthernetServer webServer(HttpPort); RPI_PICO_Timer ITimer0(0); //-------------------------------------------------------------------------------------------------------- //normal HTTP access void normalHttpAccess(EthernetClient client){ sendHttpResponseOk; // client.print(("<html><head><title>")); client.print(vers); client.print(("</title>\n<META HTTP-EQUIV='Content-Type' CONTENT='text/html;CHARSET=x-sjis'>\n")); // client.print(("<meta name='viewport' content='width=240px' />\n<script type='text/javascript'>\n")); client.print(("function createXMLHttpRequest(cbFunc){\n\tvar XObj = new XMLHttpRequest();\n\tif(XObj) XObj.onreadystatechange = cbFunc;return XObj;}\n")); client.print(("function setData(val){htObj = createXMLHttpRequest(displayData);\n\tif(htObj){htObj.open('GET','/?btn='+val,true);htObj.send(null);}}\n")); client.print(("function getData(){htObj = createXMLHttpRequest(displayData);\n\tif(htObj){htObj.open('GET','/?=',true);htObj.send(null);}}\n")); client.print(("function displayData(){ if((htObj.readyState == 4) && (htObj.status == 200)){\n\tdocument.getElementById('result').innerHTML = htObj.responseText;}}\n")); client.print(("function strT(){ getData(); timerID=setTimeout('strT()', document.getElementById('tf1').value);}\n")); client.print(("function clrT(){clearTimeout(timerID);}\n</script>\n")); client.print(("<style>\ninput[type=radio] {\ndisplay: none;\n}\n")); client.print(("\tinput[type=radio]:checked + label {\n\tbackground: #31A9EE;\n\tcolor: #ffffff;\n}\n")); client.print((".label{\n\tdisplay: block;\n")); client.print(("\tfloat: left;\n")); client.print(("\tmargin: 5px;\n")); client.print(("\twidth: 100px;\n")); client.print(("\theight: 45px;\n")); client.print(("\tpadding-left: 5px;\n")); client.print(("\tpadding-right: 5px;\n")); client.print(("\tcolor: #b20000;\n")); client.print(("\ttext-align: center;\n")); client.print(("\tline-height: 45px;\n")); client.print(("\tcursor: pointer;\n")); client.print(("\tborder: 2px solid #006DD9;\n")); client.print(("\tborder-radius: 5px;\n}\n")); client.print(("</style>\n</head>\n<body onLoad='getData()'><form action='/' method='GET'><br /><P>\n")); client.println(("\t<input id='btn0' type='radio' name='button' value=' A ' onClick='setData(0)'><label for='btn0' class='label'>A</label>")); client.println(("\t<input id='btn1' type='radio' name='button' value=' B ' onClick='setData(1)'><label for='btn1' class='label'>B</label>")); client.println(("\t<input id='btn2' type='radio' name='button' value=' C ' onClick='setData(2)'><label for='btn2' class='label'>C</label>")); client.println(("\t<input id='btn3' type='radio' name='button' value=' D ' onClick='setData(3)'><label for='btn3' class='label'>D</label><br><br></P><P>")); client.println(("\t<input id='btn4' type='radio' name='button' value=' E ' onClick='setData(4)'><label for='btn4' class='label'>E</label>")); client.println(("\t<input id='btn5' type='radio' name='button' value=' F ' onClick='setData(5)'><label for='btn5' class='label'>F</label>")); client.println(("\t<input id='btn6' type='radio' name='button' value=' G ' onClick='setData(6)'><label for='btn6' class='label'>G</label>")); client.println(("\t<input id='btn7' type='radio' name='button' value=' H ' onClick='setData(7)'><label for='btn7' class='label'>H</label><br><br></P>")); client.println(("</form><br /><div id='result'></div>")); client.println(("<br /></body></html>")); } //-------------------------------------------------------------------------------------------------------- //using XMLhttpObject access void XMLhttpObjectAccess(EthernetClient client,String parm){ } //-------------------------------------------------------------------------------------------------------- // 200 OK means the resource was located on the server and the browser (or service consumer) should expect a happy response void sendHttpResponseOk(EthernetClient client){ Serial.println(("200 OK")); Serial.println(); // send a standard http response header client.println(("HTTP/1.1 200 OK")); client.println(("Content-Type: text/html")); client.println(("Connnection: close")); // do not reuse connection client.println(); } //-------------------------------------------------------------------------------------------------------- // 404 means it ain't here. quit asking. void sendHttp404(EthernetClient client){ Serial.println(("404 Not Found")); Serial.println(); client.println(("HTTP/1.1 404 Not Found")); client.println(("Content-Type: text/html")); client.println(("Connnection: close")); // do not reuse connection client.println(); } //-------------タイマ割込で呼ばれるルーチン クロック表示 500msec毎 bool TimerHandler0(struct repeating_timer *t){ OperatingTime++; /* currentTime = now(); if(Serial) Serial.println(currentTime); currentTime %= 86400; currentHour = currentTime / 3600; currentMin = (currentTime % 3600)/60; TimeDisp[0] = currentHour/ 10; TimeDisp[1] = currentHour % 10; TimeDisp[2] = currentMin / 10; TimeDisp[3] = currentMin % 10; if(fTogle1) tm1637.point(POINT_OFF); else tm1637.point(POINT_ON); tm1637.display(TimeDisp); */ digitalWrite(LED_BUILTIN,fTogle1); fTogle1 = !fTogle1; return true; } //-------------------------------------------------------------- void setup(){ Serial.begin(BAUDRATE); Serial.println(("Start")); for (int i=0;i<8;i++){ //Picoの GP16..23を使用する pinMode(dOsPins[i] ,OUTPUT); digitalWrite(dOsPins[i],dout[i]); } pinMode(LED_BUILTIN, OUTPUT); SPI.setSCK(SPI_SCK); SPI.setRX(SPI_RX); SPI.setTX(SPI_TX); SPI.setCS(SPI_CS); SPI.begin(); //Ethernet3で使用可能なAPI pinMode(SPI_CS, OUTPUT); //NIC_CS出力設定 Ethernet.setCsPin(SPI_CS); //NIC_CSアサイン Ethernet.setRstPin(NICReset); //NIC_RSTアサイン //NICリセット処理 pinMode(NICReset, OUTPUT); digitalWrite(NICReset, LOW); delay(10); //10msecパルス幅で初期化 digitalWrite(NICReset, HIGH); // start the Ethernet connection and the server: Ethernet.begin(mac, ip); Serial.print(("Server is at ")); Serial.println(Ethernet.localIP()); webServer.begin(); //マイクロ秒単位の間隔 if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 500, TimerHandler0)){ if(Serial){ Serial.print(("Starting ITimer0 OK, millis() = ")); Serial.println(millis()); } }else{ if(Serial){ Serial.println(("Can't set ITimer0. Select another freq. or timer")); } } watchdog_reboot(0,0,delay_ms); gPreTime = millis(); if(Serial) Serial.println(("EndSetup")); } //-------------------------------------------------------------- void loop(){ //1秒のループ WDT8秒 if (watchdog_caused_reboot()){ if(Serial) Serial.print("Rebooted by Watchdog!\n"); }else{ if(Serial) Serial.print("Clean boot\n"); } watchdog_update(); // listen for incoming clients EthernetClient client = webServer.available(); if (client) { // an http request ends with a blank line boolean currentLineIsBlank = true; while (client.connected()) { if (client.available()) { char c = client.read(); // serch parameter from "HTTP GET" if(gflag){ if(c != ' '){ parm += c; }else{ gflag = false; } } if(c == '?' && parm == ""){ gflag = true; } //Serial.print(c); // 改行コードか空行を受けたら返信 if (c == '\n' && currentLineIsBlank) { // 標準のhttp応答ヘッダーを送信する if(parm == ""){ // normal HTTP access normalHttpAccess(client); }else{ // using XMLhttpObject access int check = parm.indexOf('='); if(check != -1){ //Set Digital Port int check2 = parm.indexOf('btn'); if(check2 != -1){ int port = (parm.substring(check+1)).toInt(); dout[port] = !dout[port]; digitalWrite(dOsPins[port] , dout[port]); } //Write JSONP Data (Digital & Analog Ports Status, Callback function name is 'cb') client.print(("cb({\"D\":[")); for(int i=0; i<8; i++ ){ client.print(dout[i]); if(i<7){ client.print(","); } } client.print("]});"); } parm = ""; } break; } if (c == '\n') { // you're starting a new line currentLineIsBlank = true; } else if (c != '\r') { // you've gotten a character on the current line currentLineIsBlank = false; } } } // give the web browser time to receive the data delay(1); // close the connection: client.stop(); } }
免責事項
本ソフトウエアは、あなたに対して何も保証しません。本ソフトウエアの関係者(他の利用者も含む)は、あなたに対して一切責任を負いません。
あなたが、本ソフトウエアを利用(コンパイル後の再利用など全てを含む)する場合は、自己責任で行う必要があります。本ソフトウエアの著作権はToolsBoxに帰属します。
本ソフトウエアをご利用の結果生じた損害について、ToolsBoxは一切責任を負いません。
ToolsBoxはコンテンツとして提供する全ての文章、画像等について、内容の合法性・正確性・安全性等、において最善の注意をし、作成していますが、保証するものではありません。
ToolsBoxはリンクをしている外部サイトについては、何ら保証しません。
ToolsBoxは事前の予告無く、本ソフトウエアの開発・提供を中止する可能性があります。
商標・登録商標
Microsoft、Windows、WindowsNTは米国Microsoft Corporationの米国およびその他の国における登録商標です。
Windows Vista、Windows XPは、米国Microsoft Corporation.の商品名称です。
LabVIEW、National Instruments、NI、ni.comはNational Instrumentsの登録商標です。
I2Cは、NXP Semiconductors社の登録商標です。
その他の企業名ならびに製品名は、それぞれの会社の商標もしくは登録商標です。
すべての商標および登録商標は、それぞれの所有者に帰属します。