Ethernet W5100 + Buttons
- Войдите на сайт для отправки комментариев
Чт, 22/09/2016 - 12:32
Здравствуйте.
Пытаюсь написать скетч по управлению внешними нагрузками через Web-интерфейс + физический выколючатель (вместо реле подключен светодиод). На данный момент работает либо переключение через web, либо через кнопки. Как заставить ардуино включать светодиод и с кнопки, и через веб?
В гугле нашел то, что мне нужно https://startingelectronics.org/articles/arduino/switch-and-web-page-but... , но не понимаю, как оно работает у товарища.
Можете подсказать, почему код обработки кнопки не работает?
Спасибо.
#include <SPI.h>
#include <Ethernet.h>
#include <Bounce2.h>
#define BUTTON 6
#define LED 7
Bounce bouncer = Bounce();
int ledValue = LOW;
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 10, 20, 30, 199 };
EthernetServer server(80);
String readString;
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
pinMode(BUTTON, INPUT);
pinMode(LED, OUTPUT);
bouncer.attach(BUTTON);
bouncer.interval(5);
digitalWrite(LED, LOW);
}
// start the Ethernet connection and the server:
// Ethernet.begin(mac, ip, gateway, subnet);
Ethernet.begin(mac, ip);
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
}
void loop() {
// Create a client connection
EthernetClient client = server.available();
if (client) {
while (client.connected()) {
if (client.available()) {
char c = client.read();
//read char by char HTTP request
if (readString.length() < 100) {
//store characters to string
readString += c;
//Serial.print(c);
}
//if HTTP request has ended
if (c == '\n') {
Serial.println(readString); //print to serial monitor for debuging
client.println("HTTP/1.1 200 OK"); //send new page
client.println("Content-Type: text/html");
client.println();
client.println("<HTML>");
client.println("<HEAD>");
client.println("<meta name='apple-mobile-web-app-capable' content='yes' />");
client.println("<meta name='apple-mobile-web-app-status-bar-style' content='black-translucent' />");
client.println("<link rel='stylesheet' type='text/css' href='http://randomnerdtutorials.com/ethernetcss.css' />");
client.println("<TITLE>Random Nerd Tutorials Project</TITLE>");
client.println("</HEAD>");
client.println("<BODY>");
client.println("<H1>Random Nerd Tutorials Project</H1>");
client.println("<hr />");
client.println("<br />");
client.println("<H2>Arduino with Ethernet Shield</H2>");
client.println("<br />");
client.println("<a href=\"/?button1on\"\">Turn On LED</a>");
client.println("<a href=\"/?button1off\"\">Turn Off LED</a><br />");
client.println("<br />");
client.println("<br />");
client.println("<a href=\"/?button2on\"\">Rotate Left</a>");
client.println("<a href=\"/?button2off\"\">Rotate Right</a><br />");
client.println("<p>Created by Rui Santos. Visit http://randomnerdtutorials.com for more projects!</p>");
client.println("<br />");
client.println("</BODY>");
client.println("</HTML>");
delay(1);
//stopping client
client.stop();
//controls the Arduino if you press the buttons
if (readString.indexOf("?button1on") >0){
digitalWrite(LED, HIGH);
}
if (readString.indexOf("?button1off") >0){
digitalWrite(LED, LOW);
}
//clearing string for next read
readString="";
}
}
}
}
//----Код обработки кнопки----------------------
if ( bouncer.update() ) {
//если считано значение 1
if ( bouncer.read() == HIGH) {
//если свет был выключен, будем его включать
if ( ledValue == LOW ) {
ledValue = HIGH;
//если свет был включен, будем выключать
} else {
ledValue = LOW;
}
//записываем значение вкл/выкл на пин со светодиодом
digitalWrite(LED,ledValue);
}
}
//-------------------------
}
Ну, по уму она работать и не должна.
Первая ошибка (дальше не смотрел) состоит в том, что в сроках 86-91 Вы тупо манипулируете светодиодом не изменяя при этом переменную ledValue .
А в строках 100-113 Вы надеетесь, что ledValue адекватно отражает состояние светодиода.
Теперь проиграйте сценарий. Вот Вы включили светодиод из сети. ledValue при этом как была false, так и осталась. Теперь Вы давите на кнопку. Там проверяется значение ledValue и, поскольку она false, ещё раз включается уже итак включённый светодиод. На глаз этого не видно и Вам кажется, что кнопку проигнорировали.
1. Исправьте это
2. после строки 100 поставьте печать чего нибудь, чтобы видеть попадает ли программа туда
3. опишите поведение - будем думать
Спасибо за подсказку с дебагом! Только она и помогла разобраться, что и как работало.
На данный момент получилось сделать так:
#include <Bounce2.h> #include <SPI.h> #include <Ethernet.h> #define BUTTON 6 #define LED 7 byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address byte ip[] = { 10, 20, 30, 199 }; // ip in lan (that's what you need to use in your browser. ("192.168.1.178") EthernetServer server(80); //server port String readString; int ledValue = LOW; // Выключить светодиод при включении Arduino Bounce bouncer = Bounce(); void setup() { // Open serial communications and wait for port to open: Serial.begin(9600); // start the Ethernet connection and the server: //Ethernet.begin(mac, ip, gateway, subnet); Ethernet.begin(mac, ip); server.begin(); Serial.print("server is at "); Serial.println(Ethernet.localIP()); pinMode(LED, OUTPUT); pinMode(BUTTON, INPUT); bouncer.attach(BUTTON); bouncer.interval(5); } void loop(){ if (bouncer.update()) { if (bouncer.read() == HIGH) { if (ledValue == LOW) { ledValue = HIGH; } else { ledValue = LOW; } digitalWrite(LED, ledValue); } } // Create a client connection EthernetClient client = server.available(); if (client) { while (client.connected()) { if (client.available()) { char c = client.read(); //read char by char HTTP request if (readString.length() < 100) { //store characters to string readString += c; //Serial.print(c); } //if HTTP request has ended if (c == '\n') { Serial.print("readString = "); Serial.println(readString); //print to serial monitor for debuging client.println("HTTP/1.1 200 OK"); //send new page client.println("Content-Type: text/html"); client.println(); client.println("<HTML>"); client.println("<HEAD>"); client.println("<TITLE>Show me status led</TITLE>"); client.println("<meta http-equiv=\"refresh\" content=\"3; url=http://10.20.30.199/\">"); client.println("</HEAD>"); client.println("<BODY>"); client.println("<H1>Status LED1</H1>"); client.println("<hr />"); client.println("<br />"); client.println("<H2>Arduino with Ethernet Shield</H2>"); client.println("<br />"); client.println("<form method=\"get\">"); ShowMeStatus(client); client.println("<a href=\"/?button1on\"\">Turn On LED</a>"); client.println("<a href=\"/?button1off\"\">Turn Off LED</a><br />"); client.println("</form>"); client.println("<br />"); client.println("</BODY>"); client.println("</HTML>"); delay(1); //stopping client client.stop(); //clearing string for next read readString=""; } // end HTTP REQUEST } // end Client.Available } // end Client.Connected } // end if(client) } // end loop void ShowMeStatus(EthernetClient cl) { if (readString.indexOf("?button1on") >0){ ledValue = HIGH; digitalWrite(LED, ledValue); cl.println("LED is ON"); } else if (readString.indexOf("?button1off") >0){ ledValue = LOW; digitalWrite(LED, ledValue); cl.println("LED is off"); } else if(ledValue) { cl.print("LED is ON "); } else { cl.print("LED is off "); } }Остается только один вопрос с редиректом client.println("<meta http-equiv=\"refresh\" content=\"3; url=http://10.20.30.199/\">");
Проблема вот в чем: когда пользователь нажимает на кнопку включения/отключения светодиода (на веб-форме), в адресной строке добавляется ?button1on или ?button1off. Если сделать автоматический рефреш страницы (чтобы обновлять статус лайбла LED is On/ LED is Off), то в GET запросе автоматически подставляется последнее значение и светодиод принимает значение от значения в адресной строке. Соответственно светодиод примет то значение, которое указано в GET-запросе. Придумал костыль в виде редиректа на стартовую страницу формы, чтобы управлять светодиодм также можно было и через обычную кнопку.
Скажите, пожалуйста, насколько данное решение можно применять в реальном использовании микроконтроллера? Можно ли это чем-нибудь заменить более правильным? Читал про arduino+ajax https://startingelectronics.org/tutorials/arduino/ethernet-shield-web-se... , но, как я понял, там придется делать авторефреш и держать кнопку нажатой по значению таймера, чтобы значение на веб-форме изменилось.
Не совсем понял, Вам нужно, чтобы актульное состояние кнопки отображалось на странице, даже если кнопку нажали офф-лайн?
Ну, для этого не надо свежать страницу целиком.
Давайте разделим вопрос и обсудим по частям:
1. Если таки (в других случаях) надо обновить страницу, но надо чтобы она точно загрузилась с сервера, а не взялась из кэша браузера, то это делается путём добавления случайного параметра на который страница никак не реагирует. Т.е. например, есть страница kaka.htm . Ну добавьте параметр со случайным значением и запрашивайте kaka.htm?a=321 - где 321 - случайное число, каждый раз разное. Всё, URL отличается - никаких кэшей - бкдет перегружаться.
2. В вашем случае перегружать страницу не надо. Достаточно сделать совсем маленькую вставочку типа adjax. Техника там такая же, но ajax - гормадный монстр, а мы сделаем крохотный его кусочек. Как это делается я уже здесь писал - смотрите. Кстати, в этой статье и техника вставки случайного параметра показана.