I have a "technical computer science" background but I am new to the arduino world and need your help. I have an arduino uno and an 28J60 Ethernet module attached to it. I am working on a Mac with IDE 1.0.6
I already reduced my "project" to a very basic test but still there I dont understand what happens. THe code below works fine, I have a blinking LED. Once I initialize the Ether28J60 (Line 19; the bold comment) the LED stops blinking. Can someone explain that behaviour? I also tried using the EtherCard library to do the same and also there the same issue. once I initialize the Ethernet the LED doesn't blink anymore.
Many thanks in advance
#include "etherShield.h" #include "ETHER_28J60.h"
const int ledPin = 13; // the number of the LED pin
int ledState = LOW; // ledState used to set the LED
OK I am back at the point where the (for me) "curious" things happen.
Does anyone know how much data I can "respond" via that ethernet library?
I start writing to the ethernet-library like this
e.print("\r\n");
and once I finished "printing" the html I like; I write the response to the client like this
e.respond();
but if I am writing to much the server reacts completely weird. The example below works but if I just add one character e.g. in column 35 the server hangs up.
if(sensorValue > nBoundaryHigh)
sHTMLLevelValue1 += " the soil is too humid you should";//" the soil is too humid you shouldn't water it!";
// else if(sensorValue < nBoundaryLow)
// sHTMLLevelValue1 += " the soil is too dry you should water it!\r\n";
// else
// sHTMLLevelValue1 += " that seems to be good!\r\n";
sHTMLLevelValue1 += "";
char output[sHTMLLevelValue1.length()+1];
sHTMLLevelValue1.toCharArray(output,sHTMLLevelValue1.length()+1);
You are unnecessarily wasting memory by allowing all those string literals to be copied into SRAM. Stop that by using the F() macro:
e.print(F(" start watering"));
Below is an example of a web page bundled in a single F() macro. Bundling like this can be broken into parts if variables need to be printed in the page.
//example of web page bundled in single F() macro
//get submit box code
//for use with IDE 1.0
//open serial monitor to see what the arduino receives
//use the \ slash to escape the " in the html or use a '
//address will look like http://192.168.1.102:84 when submitted
//for use with W5100 based ethernet shields
//note that the below bug fix may be required
// http://code.google.com/p/arduino/issues/detail?id=605
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 102 }; // ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(84); //server port
String readString;
//////////////////////
void setup(){
pinMode(5, OUTPUT); //pin selected to control
pinMode(6, OUTPUT); //pin selected to control
pinMode(7, OUTPUT); //pin selected to control
pinMode(8, OUTPUT); //pin selected to control
//start Ethernet
Ethernet.begin(mac, ip, gateway, gateway, subnet);
server.begin();
//enable serial data print
Serial.begin(9600);
Serial.println(F("server text box test1")); // so I can keep track of what is loaded
}
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); //see what was captured
//now output HTML data header
client.print(F( //start F() macro
"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"
"<HTML>"
"<HEAD>"
"<meta name='apple-mobile-web-app-capable' content='yes' />"
"<meta name='apple-mobile-web-app-status-bar-style' content='black-translucent' />"
"<TITLE>JAVA Page</TITLE>"
"</HEAD>"
"<BODY>"
"<H1>JAVA</H1>"
"<hr />"
"
"
"<FORM ACTION='/' method=get >"
"Enter Code: <INPUT TYPE=TEXT NAME='LED' VALUE='' SIZE='25' MAXLENGTH='50'>
"
"
"
"<input type=submit value='5 ON' style=width:100px;height:45px onClick=location.href='/?on8;'><input type=submit value='5 OFF' style=width:100px;height:45px onClick=location.href='/?off9;'>
"
"<input type=submit value='6 ON' style=width:100px;height:45px onClick=location.href='/?on8;'><input type=submit value='6 OFF' style=width:100px;height:45px onClick=location.href='/?off9;'>
"
"<input type=submit value='7 ON' style=width:100px;height:45px onClick=location.href='/?on8;'><input type=submit value='7 OFF' style=width:100px;height:45px onClick=location.href='/?off9;'>
"
"<input type=submit value='8 ON' style=width:100px;height:45px onClick=location.href='/?on8;'><input type=submit value='8 OFF' style=width:100px;height:45px onClick=location.href='/?off9;'>
"
"</FORM>"
"</BODY>"
"</HTML>"
)); //end F() macro
delay(1);
//stopping client
client.stop();
/////////////////////
if(readString.indexOf("5") >0)//checks for on
{
digitalWrite(5, HIGH); // set pin 5 high
Serial.println(F("Led On"));
}
if(readString.indexOf("50") >0)//checks for off
{
digitalWrite(5, LOW); // set pin 5 low
Serial.println(F("Led Off"));
}
if(readString.indexOf("6") >0)//checks for on
{
digitalWrite(6, HIGH); // set pin 6 high
Serial.println(F("Led 6 On"));
}
if(readString.indexOf("60") >0)//checks for off
{
digitalWrite(6, LOW); // set pin 6 low
Serial.println(F("Led 6 Off"));
}
if(readString.indexOf("7") >0)//checks for on
{
digitalWrite(7, HIGH); // set pin 7 high
Serial.println(F("Led On"));
}
if(readString.indexOf("70") >0)//checks for off
{
digitalWrite(7, LOW); // set pin 7 low
Serial.println(F("Led Off"));
}
if(readString.indexOf("8") >0)//checks for on
{
digitalWrite(8, HIGH); // set pin 8 high
Serial.println(F("Led On"));
}
if(readString.indexOf("80") >0)//checks for off
{
digitalWrite(8, LOW); // set pin 8 low
Serial.println(F("Led Off"));
}
//clearing string for next read
readString="";
}
}
}
}
}
Happy New Year! I am back with much more understanding for the whole topic but the same problem. As mentioned, I am having an 28J60 Ethernet module and the following code, where I try to write one line to the flash memory to avoid SRAM overflows. What I got working on a W5100 Shield (the F() macro) is not working with my 28J60 Library.
Is there another method bringing the variables to the flash? If not does anyone know a better library supporting the F() macro?
Many thanks in advance
Benni
#include "etherShield.h"
#include "ETHER_28J60.h"
int outputPin = 6;
static uint8_t mac[6] = {0x54, 0x55, 0x58, 0x10, 0x00, 0x24};
static uint8_t ip[4] = {192, 168, 178, 179};
static uint16_t port = 80;
ETHER_28J60 e;
void setup()
{
e.setup(mac, ip, port);
pinMode(outputPin, OUTPUT);
Serial.begin(57600);
}
void loop()
{
char* params;
int sensorValue = analogRead(A0);
float humidityPerCent = 100-(sensorValue /10.23);
int nLevelValue1 = int(humidityPerCent);
int nBoundaryLow = 40;
int nBoundaryHigh = 60;
String sHTMLLevelValue1 = "<div class=\"level ";
if (nLevelValue1 < nBoundaryLow or nLevelValue1 > nBoundaryHigh)
{sHTMLLevelValue1 += "bad";}
sHTMLLevelValue1 += "\" style=\"width:" + String(nLevelValue1) + "%;\">" + String(nLevelValue1) +"% <span style=\"color:#888;\"> =>";
if(sensorValue > nBoundaryHigh)
sHTMLLevelValue1 += " the soil is too humid you should";//" the soil is too humid you shouldn't water it!";
// else if(sensorValue < nBoundaryLow)
// sHTMLLevelValue1 += " the soil is too dry you should water it!\r\n";
// else
// sHTMLLevelValue1 += " that seems to be good!\r\n";
sHTMLLevelValue1 += "</span></div>";
char output[sHTMLLevelValue1.length()+1];
sHTMLLevelValue1.toCharArray(output,sHTMLLevelValue1.length()+1);
//Serial.println(output);
if (params = e.serviceRequest())
{
e.print(F("<!DOCTYPE HTML>\r\n"));
e.print("<html>\r\n");
e.print(" <head>\r\n");
e.print(" <title>The Garduino</title>\r\n");
e.print(" <style>\r\n");
e.print(" body, input, select, textarea\r\n");
e.print(" {color: #888;font: 16pt \"Source Sans Pro\", sans-serif; width: 75%; margin:0 auto;}\r\n");
e.print(" .level{}\r\n");
e.print(" .level.bad{color: red}\r\n");
e.print("</style>\r\n");
e.print("</head>\r\n<body>\r\n");
e.print( output );
// e.print(sensorValue);
if (strcmp(params, "?cmd=on") == 0)
{
digitalWrite(outputPin, HIGH);
e.print("actually watering: <A HREF='?cmd=off'>stop watering</A>");
}
else if (strcmp(params, "?cmd=off") == 0) // Modified -- 2011 12 15 # Ben Schueler
{
digitalWrite(outputPin, LOW);
e.print(" <A HREF='?cmd=on'>start watering</A>");
}
e.print(" </body>\r\n");
e.print("</html>\r\n");
e.respond();
}
}
compiler:
Webserver.ino: In function 'void loop()':
Webserver.ino:47: error: invalid conversion from 'const __FlashStringHelper*' to 'int'
Webserver.ino:47: error: initializing argument 1 of 'void ETHER_28J60::print(int)'
As you suspected, the problem in line 47 is caused by e.print() not being able to access data in flash memory. However, it's interesting that the next 10 lines, as well as any of the other constant strings, do not use the F() macro.
Since none of the other strings use the F() macro, the easy fix is to simply take the F() macro off of line 47. In the grand scheme of things the difference in the amount of memory used will be minimal.
Now, if you took the F() macro off the other strings for testing, and only added it back to this one line to show the error, the problem becomes how to get e.print() to recognize these flash strings so you can put F() back in all of these other lines?
<avr/pgmspace.h>: Program Space Utilities
The issue is that the processor treats the data and program memory spaces differently. Special instructions are required to be able to access data from program memory. Some functions that process strings have special versions that are automatically selected when a F() style string is encountered. e.print() apparently does not have such a version.
If you look at the example at the bottom of the Arduino Reference page linked above, you will see how they are creating an array of strings in program memory space. Then, they have a loop that copies one at a time into a buffer, and then prints the string from that buffer. Of course, Serial.println() has a special version that can access program memory data directly, so it's not an immediately useful example. But the key is the copying into a RAM buffer. A solution for you might be to put all of those strings in a string array like in the buffer, then where you have the series of e.print() calls replace that with a loop that copies one string at a time into a buffer, and then calls e.print with that buffer.