Arduino en een ENC28J60 Ethernet Shield
In dit artikel gebruiken we een Arduino ENC28J60 Ethernet shield, zoals besproken in het “Hoe web-enable je een Arduino“, welke we zullen combineren met èèn of meer DS18B20 digitale temperatuur sensoren (je kunt natuurlijk ook andere sensoren gebruiken). Het doel: Data LEZEN van de Arduino over het netwerk.
We gebruiken hier precies dezelfde opstelling als in ons Data Push artikel!
Hiervoor gebruiken we de “UIPEthernet” Library die je van Github kun downloaden of van Tweaking4All. Zoals gebruikelijk het advies om de Github versie te gebruiken aangezien deze meer recent kan zijn dan de versie op Tweaking4All.
Omdat we in ons voorbeeld de DS18B20 sensoren gaan gebruiken, hebben we ook de “OneWire” library nodig, welke te vinden is op de OneWire Project Website (aanbevolen) of natuurlijk van Tweaking4All.
Gebruik maken van de standard Arduino Ethernet Shield
Omdat “UIPEthernet” volledig compatible met de standaard “Ethernet” library is die bij de Arduino IDE zit, zou je de voorbeelden op deze pagina ook voor de Standaard Arduino Ethernet Shield (W5100 gebaseerd) kunnen gebruiken. Om dit te doen, vervang de include regel (#include <UIPEthernet.h>
) met deze twee regels:
1 2
| #include <SPI.h>
#include <Ethernet.h> |
Aansluiten van het Ethernet Shield
Aansluiten van het Ethernet shield is eenvoudig, voor meer details zie ook het “Hoe web-enable je een Arduino” artikel.
Een Ethernet module gebruikt altijd GND (aarde) en +3.3V of +5V, omdat we stroom nodig hebben.
Voor mijn eBay module moest ik +5V gebruiken (het heeft een voltage regulator aan boord).
Hieronder een tabel voor Arduino Uno, Arduino Nano en de module die ik op eBay had gekocht, met de pin aansluitingen die we nodig hebben.
ENC28J60 Pins
Pin naam |
UIPEthernet |
Mijn eBay Module |
SS |
10 |
10 |
MOSI (SI) |
11 |
11 |
MISO (SO) |
12 |
12 |
SCK |
13 |
13 |
Mijn ENC28J60 test opstelling
Aansluiten van de Temperatuur sensor
De temperatuur sensor is ook eenvoudig aan te sluiten, en we gebruiken pin 2 als de data pin voor onze sensor(en). In mijn opstelling heb ik er 2 gebruikt, maar dit werkt ongewijzigd ook voor slechts èèn of meerdere sensoren.
Lees het artikel “Hoe temperaturen meten met een Arduino en een DS18B20” voor meer details.
Arduino, ENC28J60 en 2x DS18B20 test opstelling
Alle aansluitingen gecombineerd
Afhankelijk van het Arduino board en ENC28J60 Ethernet shield model dat je gebruikt, zouden de aansluitingen er als volgt uit kunnen zien. Bedenk dat ik hierbij een “Deek Robot – Nano Ethernet Shield” (van eBay) en een Arduino Uno heb gebruikt. De meegeleverde Arduino Nano is hierbij niet gebruikt en voor de pinnen D10 … D13 op de ethernet shield kun je bovenstaande tabel volgen.
Arduino, ENC28J60 en DS18B20 diagram
Ad Blocking Gedetecteerd Vriendelijk verzoek om te overwegen Ad Blocking uit te zetten voor onze website.
We zijn afhankelijk van inkomen uit Advertenties om de website te kunnen draaien.
Je kunt ons ook op andere manieren ondersteunen (zie Ondersteun ons links bovenin).
Hoe gaan we de Data ophalen?
In dit voorbeeld gebruiken we dus de temperatuur sensor van het DS18B20 artikel en willen we de temperatuur waarneming van de sensor(en) in onze computer inlezen via het computer netwerk. Als ik zeg “computer” denk dan ook aan b.v. een smartphone of tablet, zolang ze maar in hetzelfde netwerk zitten.
Data Pull of Push
We hebben bij het uitwisselen van data twee opties, en de beste optie hangt af van jouw toepassing:
– Pull: Een applicatie op onze computer (of server) bepaalt wanneer data van de Arduino opgehaald gaat worden.
– Push: De Arduino bepaalt wanneer data naar onze computer (of server) gestuurd wordt.
In dit artikel kijken we naar DATA PULL van de Arduino, door onze computer.
Dit is de eerste aanpak die ik probeerde vanwege zijn eenvoud. We hebben aan de computer kan alleen maar een web-browser nodig (die je later door jouw eigen programma kunt vervangen). In principe wordt de data opgehaald van de Arduino alsof het een “web pagina” is. De computer bepaalt dus wanneer we data gaan ophalen.
In dit voorbeeld heb ik gekozen voor het XML formaat voor de data, maar is absoluut niets mis met andere formaten zoals CSV (Comma Separated Values), HTML, of jouw eiegn formaat. Uiteindelijk is het jouw programma die straks de data gaat ophalen en dus aan jouw om te bepalen welke formaat het meest geschikt is.
Als je naar het “Hello World!” voorbeeld kijkt die we voor “UIPEthernet” hadden gebruikt (zie “Hoe web-enable je een Arduino“), dan zie je in de loop dat we eigenlijk steeds wachten op een verbinding (regel 23). Als een verbinding wordt gevonden en blijft bestaan (regel 23 en regel 30), dan sturen we data (regel 41) naar de computer die de verbinding maakt en vervolgens sluiten we de verbinding (regel 61).
Makkelijk, niet dan? We gaan nu dit voorbeeld gebruiken en regel 41 vervangen met onze data.
Lezen van de DS18B20 Temperatuur Sensor(en)
In dit deel had ik UIPEthernet echt nodig omdat het de print functie volledig ondersteund en op dezelfde manier werkt als de Serial.print
of Serial.println
functie.
Mijn voorbeeld code mag dan wel niet de meest efficiente of beste code zijn die je zou kunnen schrijven: werken doet het wel! Ik heb het getest met 1 en 2 temperatuur sensoren (ik had er maar 2).
De functie “TemperaturesToXML“, in onderstaan de Sketch, bevat in principe alles wat we gebruikt hebben in de Sketch van het DS18B20 Temperatuur Sensor artikel waarbij we pin 2 voor de data van de temperatuur sensoren gebruiken. Voor wie dat artikel werkelijk gelezen heeft: nu weet je wat ik bedoel met “andere plannen voor pin 10”.
De rest van de code is een aangepaste versie van het Ethernet “Hello World!” voorbeeld.
Je kunt de Sketch kopiëren en plakken of je kunt het .ino bestand downloaden.
Download - T4A TemperatureDrone
Bestandsnaam: |
T4A-TemperatureDrone.ino |
Platform: |
Undefined |
Versie: |
1.0 |
Omvang: |
6.3 kB |
Datum: |
2014-03-23 |
Download Nu
Stuur me Koffie
|
Nog een paar opmerkingen voor het gebruik van de client.print
en client.println
functies (dito voor Serial.print
varianten):
- Vermijd combineren van verschillende data typen – het kan onverwachte resultaten leveren.
- Je kunt “\n” in een string gebruiken om een nieuwe regel te starten.
- Lees de Arduino Referentie voor “Serial.print” voor meer trucs en tips.
Output Voorbeelden
In mijn test opstelling heb ik twee sensoren gebruikt en de output in mijn web-browser bekeken. Je kunt de output in jouw web-browser bekijken door het adres als volgt in te voeren in het adres van van jouw browser: http://192.168.1.179 (natuurlijk wel het IP adres gebruiken dat je in de Sketch hebt gebruikt).
Voorbeeld output in een web-browser:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?xml version='1.0'?>
<sensordata>
<sensor>
<serial>28 88 84 82 05 00 00 6a </serial>
<status>OK</status>
<chip>DS18B20</chip>
<celsius>20.44</celsius>
<fahrenheit>68.79</fahrenheit>
</sensor>
<sensor>
<serial>28 da ca 27 05 00 00 49 </serial>
<status>OK</status>
<chip>DS18B20</chip>
<celsius>20.31</celsius>
<fahrenheit>68.56</fahrenheit>
</sensor>
</sensordata> |
Ik heb in de Sketch ook output naar de “Serial Monitor” gestuurd van de Arduino IDE en dat ziet er ongeveer zo uit:
Tweaking4All.com - Temperature Drone - v1.0
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
IP Address: 192.168.1.179
-> New Connection
Collecting Sensor Data:
Sensor : 28 88 84 82 05 00 00 6a
Temperature: 20.44 C (68.79 F)
Sensor : 28 da ca 27 05 00 00 49
Temperature: 20.31 C (68.56 F)
Done Collecting Sensor Data
Disconnected
Even door de code lopen …
Basis voor we starten:
Regel 1 en 2 zijn de twee Library includes die we nodig hebben voor de Arduino ENC28J60 Ethernet module, en de DS18B20 1-wire temperatuur sensor(en).
In regel lines 5 – 11 stellen we IP en MAC adres in en definiëren we define poort 80 voor data requests (HTTP).
Regel 13 maakt een globale variabele aan die onze Ethernet Client verbinding vast houdt, zodat we met de client kunnen praten.
Voor de sensoren definiëren we pin 2 als de data pin, in regel 19.
Setup()
In de “setup()” functie openen we de seriële poort voor debug data die we met de “Serial Monitor” van de Arduino IDE kunnen bekijken (menu “Tools” “Serial Monitor” en vergeet net te controleren dat de snelheid op “9600 baud” staat). Het lijkt erop dat Arduino Leonardo gebruikers een stukje code moeten toevoegen na regel 25 om te wachten op de seriële poort – maar ik heb geen Leonardo dus ik kan dat niet bevestigen (zoiets als while (!Serial) { }
). In regel 28 starten we dan de Ethernet shield met gegeven IP en MAC adres en een eerste teken van leven wordt door de seriële poort gestuurd.
Alle regels met “Serial.begin”, “Serial.print” en “Serial.println” mogen verwijderd worden als je geen seriële output nodig hebt.
Loop()
De “loop()” functie is waar we op een verbinding gaan wachten. Als een verbinding opgezet is, gaan we vervolgens de sensoren uitlezen, de data naar de client sturen en uiteindelijk verbreken we de verbinding. Zoals Arduino gebruikelijk blijft deze loop oneindig rond gaan zolang de Arduino stroom heeft.
TemperatureToXML()
Zoals eerder gezegd, de functie “TemperaturesToXML()” is in principe de code die we voor onze DS18B20 temperatuur sensor demo hebben gebruikt. Ik heb het wat opgeruimd en aangepast zodat het niet alleen seriële data uitstuurt maar ook data over de netwerkverbinding stuurt. Voor meer details zie ook het DS18B20 artikel.
Demo Sketch
Hieronder vindt je de besproken demo code (download link zie eerder vermelde link) – zodra de Arduino draait, open een web-browser op jouw computer en voer het volgende in (IP adres aanpassen indien nodig): http://192.168.1.79
Na een seconde of zo zie je de output in jouw browser verschijnen.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
| #include <UIPEthernet.h> // Gebruikt voor Ethernet
#include <OneWire.h> // Gebruikt voor de temperatuur sensor(en)
// **** ETHERNET SETTING ****
// Ethernet MAC adres - moet uniek zijn in jouw netwerk
byte mac[] = { 0x54, 0x34, 0x41, 0x30, 0x30, 0x31 };
// ethernet interface IP adres (moet ook uniek zijn in jouw netwerk)
IPAddress ip(192, 168, 1, 179);
// ethernet interface IP poort (80 = http)
EthernetServer server(80);
EthernetClient client;
// **** TEMPERATUUR INSTELLINGEN ****
// Sensor(en) data pin worden met Arduino pin 2 verbonden in non-parasite mode!
OneWire ds(2);
void setup() {
// Open serieel poort:
Serial.begin(9600);
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server.begin();
Serial.println("Tweaking4All.com - Temperature Drone - v1.0");
Serial.println("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
Serial.print("IP Adres: ");
Serial.println(Ethernet.localIP());
Serial.println();
}
void loop() {
// listen for incoming clients
client = server.available();
if (client)
{
Serial.println("-> Nieuwe verbinding\n");
// http requests starten met een lege regel
boolean currentLineIsBlank = true;
while (client.connected())
{
if (client.available()) {
char c = client.read();
// einde regel bereikt en de regel was leeg?
// dan is de http request klaar,
// stuur nu de data
if (c == '\n' && currentLineIsBlank)
{
client.println("<?xml version='1.0'?>\n<sensordata>");
Serial.println(" Ophalen Sensor Data:");
TemperaturesToXML();
client.println("</sensordata>");
Serial.println("\n Klaar met ophalen Sensor Data");
break;
}
if (c == '\n') {
// we beginnen weer met een lege regel
currentLineIsBlank = true;
}
else if (c != '\r') {
// je hebt een character ontvangen, dus niet een lege regel
currentLineIsBlank = false;
}
}
}
// geef web browser tijd om de data te ontvangen
delay(10);
// sluit de verbinding:
client.stop();
Serial.println(" Einde verbinding\n");
}
}
void TemperaturesToXML(void) {
byte counter;
byte present = 0;
byte sensor_type;
byte data[12];
byte addr[8];
float celsius, fahrenheit;
ds.reset_search();
while ( ds.search(addr)) {
client.println("<sensor>");
// Ophalen Serial nummer
client.print(" <serial>");
Serial.print("\n Sensor : ");
for( counter = 0; counter < 8; counter++)
{
if (addr[counter]<0x10) client.print("0");
client.print(String(addr[counter], HEX));
client.print(" ");
if (addr[counter]<0x10) Serial.print("0");
Serial.print(String(addr[counter], HEX));
Serial.print(" ");
}
Serial.println();
client.println("</serial>");
// Check CRC
if (OneWire::crc8(addr, 7) != addr[7])
{
client.println(" <status>Invalid CRC</status>\n</sensor>");
Serial.println(" ERROR\n");
return;
}
client.println(" <status>OK</status>");
// Ophalen Chip type (de eerste ROM byte geven chip model aan)
client.print(" <chip>");
switch (addr[0])
{
case 0x10:
client.println("DS18S20</chip>");
sensor_type = 1;
break;
case 0x28:
client.println("DS18B20</chip>");
sensor_type = 0;
break;
case 0x22:
client.println("DS1822</chip>");
sensor_type = 0;
break;
default:
client.println("onbekend</chip>");
return;
}
ds.reset();
ds.select(addr);
ds.write(0x44); // start conversie, met normale (non-parasite!) voeding
delay(1000); // misschien is 750ms, misschien ook niet
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
// Get Raw Temp Data, we need 9 bytes
for ( counter = 0; counter < 9; counter++)
{
data[counter] = ds.read();
}
// Converteer data naar temperatuur
// Dit is een 16 bit signed integer, dus opslaan
// in een "int16_t" type
int16_t raw = (data[1] << 8) | data[0];
if (sensor_type)
{
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
// "count remain" gives full 12 bit resolution
raw = (raw & 0xFFF0) + 12 - data[6];
}
}
else
{
// at lower res, the low bits are undefined, so let's zero them
byte cfg = (data[4] & 0x60);
//// default is 12 bit resolution, 750 ms conversion time
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
}
celsius = (float)raw / 16.0;
fahrenheit = celsius * 1.8 + 32.0;
client.print(" <celsius>");
client.print(celsius);
client.print("</celsius>\n <fahrenheit>");
client.print(fahrenheit);
client.println("</fahrenheit>");
Serial.print(" Temperature: ");
Serial.print(celsius);
Serial.print(" C (");
Serial.print(fahrenheit);
Serial.println(" F)");
client.println("</sensor>");
}
return;
} |
Reacties
Er zijn 2 reacties welke je hieronder kunt lezen.
Je kunt jouw eigen opmerkingen plaatsen m.b.v. dit formulier, of een reactie op een bestaande opmerking plaatsen door op de "Beantwoorden" knop te klikken.
[…] een voorgaand artikel beschreef ik hoe je m.b.v. “Data Pull” Arduino sensor data kon lezen via een […]
UPDATE:
Bug in de code (bij het toevoegen van een “0” by ieder adres nummer gebruikte ik <10, maar dit moet <0x10 zijn) en XML output een beetje opgeruimd (</chip> staat nu op dezelfde regel als <chip>).
hans