Show Posts
|
|
Pages: [1] 2 3 ... 53
|
|
1
|
International / Deutsch / Re: Handlinger Arm - Arduino
|
on: Today at 08:42:44 am
|
Habe komischerweise nichts im Netz gefunden, dass jemand sowas mit dem Arduino gebaut hat. Kann ich mir ja kaum vorstellen...
Die Entwicklung feinfühliger Roboter-"Hände" mit taktiler Rückmeldung und 10 oder mehr Fingergelenken ist ein Themengiebiet, das zum Bereich der Spitzenforschung gehört, da sitzen ganze Universitätsinstitute mit Mannjahren an Entwicklung feinmechanischer und elektronischer Systeme dran, mit millionenschweren Etats hinter der Entwicklung. Für das Handling mit Arduino und zu Preisen für Hobbyisten sind "Klauen-Greiferhände" derzeitig der Stand der Technik. Z.B. eBay Artikelnummer 280943189486 für knappe 50 EUR.
|
|
|
|
|
2
|
International / Deutsch / Re: Zahl mit Punkt versehen .. ??? <gelöst>
|
on: Today at 06:07:12 am
|
Das hatte ich auch schon --> Serial.println( 4635/1000, 3 ); Aber leider kam da nie das raus, auf die 1000.0 wäre ich nicht gekommen!  4635/1000 ist rechnen mit ganzen Zahlen. das geht vier ganze male, also Ergebnis 4. Der Kompiler hat bestimmte Rechenregeln, was beim Rechnen mit Zahlen herauskommt, wenn die Zahlentypen unterschiedlich sind. Integer geteilt durch Integer = reine Integer-Rechnung, Ergebnis Integer Integer geteilt durch Float = rechnen mit Gleitkommazahl, Ergebnis Float Du kannst die Umwandlung in float auch ausdrücklich angeben. Die Schreibweise: 4635/1000.0 ist daher dasselbe wie 4635/float(1000)
|
|
|
|
|
3
|
International / Deutsch / Re: Zahl mit Punkt versehen .. ???
|
on: Today at 05:10:06 am
|
Also, ich habe eine Zahl (4635), was den Millivolt des Arduino entspricht, wie bekomme ich da einen Punkt vor die zweite stelle ? --> 4.635
Du wandelst die Zahl in eine Gleitkommazahl um, indem Du die Integerzahl durch eine Gleitkommazahl dividiert (also in dem Fall 1000.0 statt 1000 als Teiler) und gibst die so erhaltene Gleitkommazahl dann mit drei Nachkommastellen aus: Serial.println( 4635/1000.0, 3 );
|
|
|
|
|
4
|
International / Deutsch / Re: 2 Pumpen zu gewissen Zeiten ansteuern
|
on: May 23, 2013, 09:45:25 am
|
Bei Deinen geringen Programmierkenntnissen halte ich das für eine suboptimale Entscheidung. Soweit ich das sehe, willst Du den Arduino quasi als Zeitschaltuhr verwenden, und eine/zwei Zeitschaltuhr/en verwendest Du nur deshalb nicht, weil bei Schaltuhren die kleinste programmierbare Schaltzeit 15 Minuten (mechanische Schaltuhr) oder 1 Minute (elektronische Schaltuhr) ist, Du aber eine Schaltzeit von 1 Sekunde für Deine Dosierpumpen benötigst. Mein Gegenvorschlag für Material: 1. Arduino Uno ( http://www.ozhobbies.eu/?module=product_info&products_id=1322) 2. Relaisplatine ( http://www.ozhobbies.eu/?module=product_info&products_id=1480) (warum das vierfach und nicht das zweifach http://www.ozhobbies.eu/bauelemente/relais-interface-shield-2x-10a/ ) 3. USB-Netzteil für den Arduino (hast Du keine Stromversorgung vorgesehen oder hast Du ein Netzteil?) 4. Zeitschaltuhr (billigste mechanische, die Du kriegen kannst) Ausführung: Als erstes nimmst Du die Zeitschaltuhr und programmierst sie so, dass sie alle 12 Stunden das Arduino-Netzteil mit Strom versorgt, z.B. eine viertel Stunde lang, und dann abschaltet. Wie lange genau, ist dabei egal. Und auf den Arduino kommt ein ganz simples Programm, ohne Uhr, ohne Display, sondern einfach nur mit dieser Programmlogik: a) Beim ersten Einschalten schalte Pumpe 1 für 1 Sek. ein, danach mache bei zum Ausschalten nichts mehr b) Beim zweiten Einschalten schalte Pumpe 2 für 1 Sek. ein, danach mache bei zum Ausschalten nichts mehr c) Und dann wieder bei a) anfangen Die Schaltvorgänge (Uhrzeit verwalten, Einschalten des Arduino, Ausschalten des Arduino) übernimmt nun die stinknormale Zeitschaltuhr. Und jedesmal wenn der Arduino eingeschaltet wird, schaltet er bei einem Einschalten die eine Pumpe für eine Sekunde ein. Beim nächsten mal die andere Pumpe. Und dann wieder von vorne. Ob der Arduino zum 1., 3., 5., 7. mal eingeschaltet wird (1. Pumpe schalten) oder zum 2., 4., 6., 8. mal (2. Pumpe schalten) kann sich der Arduino jedesmal im EEPROM-Speicher merken. Die komplette Programmlogik in Pseudocode sieht dann so aus: 1. Lies Eeprom-Speicherstelle, 2. Wenn eine "1" gelesen wurde, dann Relais für Pumpe 1 einschalten, sonst Relais für Pumpe 2 einschalten 3. Warte 1 Sekunde 4. Relais wieder abschalten 5. Wenn 1 gelesen wurde, schreibe 2 in die Eeprom-Speicherstelle, sonst schreibe 1 6. Programmende (warten aufs Ausschalten durch die Zeitschaltuhr) Und fertig ist die Laube.
|
|
|
|
|
5
|
International / Deutsch / Re: PWM - Signal übertragen mit XBee
|
on: May 23, 2013, 08:07:06 am
|
Ja, leider sind wir an die PIC16F688 gebunden, Du bist komplett im falschen Forum. Ich hoffe ihr könnt mir trotzdem helfen  Unabhängig davon, ob Du es mit einem Atmega oder Pic Controller machst, überträgt man in einem solchen Fall nicht das hochfrequente Signal an sich, sondern die Information, wie das Signal erzeugt wird. D.h. immer wenn sich der PWM-Wert ändert, sendet der eine Controller den PWM-Wert an den anderen Controller, und jeder Controller für sich macht aus dem PWM-Wert ein PWM-Signal an einem Pin.
|
|
|
|
|
6
|
International / Deutsch / Re: Fragen zum Prescaler
|
on: May 23, 2013, 04:54:27 am
|
In wie fern macht sich das bemerkbar bzw wie kann ich mir das vorstellen? Wieviel Genauigkeit geht verloren?
Ich habe das selbst nicht getestet und kann nur http://www.atmel.com/Images/doc8444.pdf zitieren: If ADC resolution of less than 10 bits required, then the ADC clock frequency can be higher than 200kHz. At 1MHz it is possible to achieve eight bits of resolution maximum.
Ob es bei der geringeren Auflösung so ist, dass bestimmte Messwerte überhaupt nicht mehr gemessen werden, so dass es nicht jeden Wert zwischen 0 und 1023 auch als Messwert gibt, oder ob die Messwerte bei gleichbleibender Messspannung schwanken und bei direkt nacheinander ausgeführten Messungen leicht springende Werte zurückgeliefert werden, kann ich Dir nicht sagen. Aber wenn Du es aufgebaut und programmiert hast, kannst Du das natürlich selbst mal austesten, indem Du mal ein feinfühlig einstellbares 10-Gang Poti verbaust und verschiedene nebeneinander liegende Einstellungen ausmißt, einmal mit normalem Prescaler und einmal mit gedoptem Prescaler.
|
|
|
|
|
7
|
International / Deutsch / Re: Fragen zum Prescaler
|
on: May 23, 2013, 03:29:03 am
|
Mich würde interessieren warum das so ist. Wenn ich den Takt von 16MHz mit den Prescaler Bits auf 62500Hz runterbreche müsste das System doch langsamer reagieren und nicht schneller?
Die ADC clock tickt immer mit "Systemtakt durch Prescaler", und der normale Prescaler-Wert ist 128. 16 MHz Systemtakt / 128 = 125 kHz ADC clock Wenn Du den Prescaler auf 16 verkleinerst, dann gilt: 16 MHz Systemtakt / 16 = 1 MHz = 1000 kHz ADC clock Mit Prescaler 16 statt 128 taktet die ADC clock achtmal schneller. Aber mit mehr als 200 kHz ADC clock liefert der ADC keine 10 bit Auflösung mehr, sondern es geht Genauigkeit verloren. In jedem Fall benötigt eine ADC-Wandlung 13 ADC clock Takte.
|
|
|
|
|
8
|
International / Deutsch / Re: Ethernet und SD Karte gleichzeitig nutzen - mit dem Ethernetshield
|
on: May 23, 2013, 12:43:29 am
|
Wie Bitklopfer schon sagte, erst die Daten von der SD im wertvollem Ram des AVR's speichern und dann vom dort aus zum Ethernet.
Ja, diese Sendeschleife mit der Logik "ein Byte lesen - ein Byte senden" ist natürlich furchtbar ineffektiv und langsam: while ((c = file.read()) >= 0) { // uncomment the serial to debug (slow!) //Serial.print((char)c); client.print((char)c); }
Da macht man besser eine Logik "100 Bytes lesen - 100 Bytes senden" oder sowas in der Art draus, um größere Dateien zu senden und dabei eine deutliche Geschwindigkeitssteigerung zu erzielen, wenn gleich ein ganzer Datenblock an den Ethernet-Chip übergeben wird.
|
|
|
|
|
9
|
International / Deutsch / Re: Arduino als Hyperterminal Master
|
on: May 23, 2013, 12:36:08 am
|
Die CNC funktioniert schon seit Jahren über die USB wie RS232 Schnittstelle. Über das alte Hyperterminal eines 486 DX 100 PC der vor einiger Zeit das Zeitliche gesegnet hat, bis her habe ich die Programme Übertragen und die CNC im Direkt Modus gefahren. Der neue Rechner mit WIN 98 braucht zu lange zum Booten 1/2 Stunde bis er alles geladen hat.
"Neu" ist WIN98 ja nun nicht gerade. Für ein modernes Windows-Betriebssystem auf einem modernen Windows-PC würde man ein Windows-Terminalprogramm mit YModem installieren und es über ein USB-Seriell Kabel an Dein RS232-Gerät anschließen und gut. Lasse mich bitte verstehen, weshalb Du jetzt mit Arduino bastelst und selbst ein Programm mit YModem für den Arduino programmieren möchtest: Du möchtest irgendwas automatisieren (YModem Dateitransfers), das in Zukunft automatisch ablaufen soll, was Du bisher mit einem Terminalprogramm von Hand interaktiv gemacht hast, oder? Also Du möchtest eine höhere Automatisierungsstufe erreichen, gegenüber der Verwendung eines Terminalprogramms? Der Ardunio ist mit dem Max232 über TDX RXD also PIN 0 und PIN 1 verbunden die Stromversorgung ist auch vom Bord dann über ein Kabel (Cross / Normal). Pin-0 und -1 sind die Hardware-Serial des Arduino, an diesen beiden Pins ist bereits ein USB-Seriell Wandlerchip angeschlossen, über den der Arduino eine virtuelle serielle Schnittstelle an seinem USB-Anschluß zur Verfügung stellt. Bist Du sicher, dass sich der USB-Seriell-Wandlerchip auf dem Arduino-Board nicht mit dem MAX232 Chip beißt, den Du an denselben Pins angeschlossen hast? Müßtest Du nicht den MAX232 an zwei andere Pins anschließen, die Du dann per Programmierung als Software-Serial ansprichst? Ich teste jetzt erst mal ein andere RS232 Schnittstelle (DigiVoltMeter).
Also ich würde ja jetzt erstmal nur mit dem Arduino und dem RS232 Adapter testen. Also alle Hardware (LCD, Taster) weglassen, nur das Arduino-Board und den MAX232-Adapter verwenden. Das Arduino-Board über USB mit einem PC verbinden. Den MAX232 Adapter an beispielsweise Pin-10 und Pin-11 anschließen. Und dann mal einen einfachen Test-Sketch laufen lassen wie z.B.: #include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX
#define CR '\r'
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 Serial.println("Programm ist gestartet!"); // set the data rate for the SoftwareSerial port mySerial.begin(9600); mySerial.print("A"); mySerial.print(CR); }
void loop() // run over and over { if (mySerial.available()) Serial.write(mySerial.read()); if (Serial.available()) mySerial.write(Serial.read()); }
Und dann hast Du an der Hardware-Serial Deine Arduino-Software mit dem seriellen Monitor von Arduino laufen. Und mit dem Sketch leitest Du Dir die Daten von der Software-Serial, an der Dein RS232-Gerät hängt, auf den seriellen Arduino-Monitor um. So dass Du gleichzeitig den PC mit Deiner Programmiersoftware angeschlossen hast, damit Du schnell mal einen anderen Sketch hochladen kannst. Senden an Dein angeschlossenes Gerät mit mySerial.write oder mySerial.print. Und was vom Gerät kommt, erscheint im seriellen Monitor der Arduino-Software. Du bist doch nicht mal ansatzweise so weit, ein Standalone-Gerät mit getesteter Firmware betreiben zu können. Du hast ja noch nichtmal erfolgreich getestet, dass Dein selbstgelöteter MAX232-Adapter einwandfrei funktioniert. Daher würde ich mir erstmal immer ein Entwicklungssystem aufbauen, das an einen PC mit Arduino-Software angeschlossen ist und gleichzeitig an das RS232-Gerät, um jederzeit mal schnell was neues Ausprobieren zu können und ruckzuck neue/geänderte Sketche hochzuladen und zu testen.
|
|
|
|
|
10
|
International / Deutsch / Re: Ethernet und SD Karte gleichzeitig nutzen - mit dem Ethernetshield
|
on: May 22, 2013, 04:50:45 am
|
Hast ja recht, ich komme aus der Delphi (Pascal) Richtung, und wollte bei den Strings nicht mit Char Arrays arbeiten. Der Ressouren auf dem Atmels sind nicht so groß, deshalb macht das Sinn.
Nicht nur deshalb. String-Objekte sind unter Arduino fehlerhaft implementiert. Wenn Du es selbst mal testen möchtest: In http://forum.arduino.cc/index.php?topic=138383.25 habe ich als Reply #28 mal einen kurzen Testcode gepostet, der innerhalb einer Schleife von nur 100 Schleifendurchläufen mit Verwendung von String-Objekten abstürzt (getestet mit Arduino Versionen bis 1.0.3), d.h. das Schleifenende nicht erreicht. Solche Dinge kannst Du nicht für Programme verbrauchen, die stunden-, tage-, wochen- und monatelang durchlaufen sollen. Deshalb willst Du keine String-Objekte, wenn Du zuverlässig funktionierende Programme möchtest. Darüber hinaus arbeiten sämtliche Funktionen der C-Standardlibrary mit C-Strings (char Arrays) und nicht mit String-Objekten. WEIL du kannst nicht beide Teile GLEICHzeitig aktivieren...das gibt Totsicher einen Crahs auf dem SPI Bus. DAS ist nunmal SO !
Ja. Trotzdem mußt Du den Code dafür nicht unbedingt in den Sketch reinschreiben, weil der Code dafür teilweise schon in den Libraries drinsteht. Dass ich oben in Reply #7 einen völlig einwandfrei funktionierenden "Arduino SD-Karten Webserver" gepostet habe, hast Du gesehen? Am Beispiel der Ethernet-Library z.B. steht der notwendige Code innerhalb der Quellcodedatei w5100.cpp, wo die Funktionen dann z.B. so aussehen: uint8_t W5100Class::write(uint16_t _addr, uint8_t _data) { setSS(); SPI.transfer(0xF0); SPI.transfer(_addr >> 8); SPI.transfer(_addr & 0xFF); SPI.transfer(_data); resetSS(); return 1; }
D.h. beim Aufrufen von "write" wird zu Anfang mit "setSS();" der Ethernet-Chip aktiviert, am Ende der Funktion wird er mit "resetSS();" wieder deaktiviert, zwischendurch wird der Transfer über den SPI Bus durchgeführt. D.h. Du rufst im Sketch nur "client.write" auf und automatisch wird von der Library das angesprochene Gerät aktiviert.
|
|
|
|
|
11
|
International / Deutsch / Re: Morse programm von mir geht nicht =(
|
on: May 21, 2013, 10:32:41 am
|
Kann mir jemand helfen?  Irgendwie scheinen Dir noch ein paar Grundlagen zu fehlen. Erstens mal darfst Du einen und denselben Bezeichner nicht für zwei ganz verschiedene Dinge verwenden. int morse = 3; ... class morse {... Ja was denn nun: Soll "morse" einen Integer-Wert oder eine Klasse bezeichnen? Wenigstens die Groß- und Kleinschreibung der Bezeichner sollte sich unterscheiden. Beispielsweise: int MORSE = 3; class Morse {... Für C sind "MORSE" und "Morse" unterschiedliche Bezeichner. Aber "morse" und "morse" sind identische Bezeichner. Merke: Unterschiedliche Bezeichner für unterschiedliche Dinge verwenden, identische Bezeichner für identische Dinge! Darüber hinaus hast Du zwar die Klassen definiert, aber Du hast keine Klassenvariablen erzeugt. Ich habe Deinen Code mal geringfügig verändert, dass er fehlerfrei kompiliert. Also unterschiedliche Bezeichner verwendet, wo Bezeichner unterschiedlich sein müssen und fehlende Klassenvariablen nach bestem Wissen und Gewissen ergänzt (ich programmiere üblicherweise in Sketchen nur prozedural und nicht objektorientiert, so ganz sattelfest bin ich darin auch nicht). Dass der Code nicht nur kompiliert werden kann, sondern auch wie gewünscht funktioniert, ist bei Deinen Programmierkenntnissen allerdings eher unwahrscheinlich. Aber Du kannst dran arbeiten: int MORSE = 3; int button1 = 2; int button2 = 4; int button3 = 5; int pin = 0;
class Ton { public: void kurz() { long zaehler = 0; boolean ver = 0; while (zaehler != 250000) { digitalWrite(MORSE, ver); if (ver == HIGH) { ver = LOW; } else { ver = HIGH; } zaehler = zaehler + 1; } } void lang() { long zaehler2 = 0; boolean ver2 = 0; while (zaehler2 != 250000) { digitalWrite(MORSE, ver2); if (ver2 == HIGH) { ver2 = LOW; } else { ver2 = HIGH; } zaehler2 = zaehler2 + 1; } } };
class Morse { public: Ton ton; void cq() { ton.lang(); ton.kurz(); ton.lang(); ton.kurz(); delay(800); } void name() { ton.kurz(); ton.lang(); ton.kurz(); ton.kurz(); delay(500); ton.lang(); ton.kurz(); ton.kurz(); delay(500); ton.kurz(); delay(500); ton.lang(); ton.lang(); ton.lang(); ton.lang(); ton.lang(); delay(500); ton.kurz(); ton.lang(); ton.lang(); ton.lang(); ton.lang(); delay(800); } void sos() { ton.kurz(); ton.kurz(); ton.kurz(); delay(500); ton.lang(); ton.lang(); ton.lang(); delay(500); ton.kurz(); ton.kurz(); ton.kurz(); delay(800); } };
Morse morse;
void setup() { pinMode(MORSE, OUTPUT); pinMode(button1, INPUT); pinMode(button2, INPUT); pinMode(button3, INPUT); Serial.begin(9600); }
void loop() { if (digitalRead(button1) == HIGH && digitalRead(button2) == LOW && digitalRead(button3) == LOW) { // [i] morse.cq(); // [/i] } else if (digitalRead(button2) == HIGH && digitalRead(button1) == LOW && digitalRead(button3) == LOW) { morse.name(); } else if (digitalRead(button3) == HIGH && digitalRead(button1) == LOW && digitalRead(button2) == LOW) { morse.sos(); } else { Serial.println("..."); } delay(10); }
[Edit] Ich habe außerdem noch ein int zaehler = 0; ausgetauscht gegen ein long zaehler = 0; Weil int-Zähler zählen nur bis max. 32767 hoch und laufen dann über. Der int-Zähler würde also nie den Wert erreichen, auf den Du prüfst: while (zaehler != 250000) Merke: Wenn Zahlen den int-Wertebereich überschreiten, dann stattdessen long-Werte verwenden!
|
|
|
|
|
12
|
International / Deutsch / Re: Arduino als Hyperterminal Master
|
on: May 20, 2013, 04:03:27 pm
|
Kann mir Jemand Helfen?
Hast Du einen RS232-TTL Wandler, den Du auf einer Seite an Deine RS232-Steuerung anschließen kannst und an der anderen Seite mit Drähten an Deinen Arduino? Wenn ja, hast Du den Adapter am Arduino angeschlossen? Welcher ist es? Und wie angeschlossen? Wenn ja, welchen Sketch hast Du zum Testen auf dem Arduino laufen? Und falls Du deine RS232-Steuerung noch überhaupt nicht am Arduino angeschlossen und mit einem Sketch getestet hast: Hast Du denn Deine Steuerung wenigstens mal an einem PC mit serieller Schnittstelle (oder mittels USB-Seriell Adapterkabel) angeschlossen und hast mit einem Terminalprogramm auf dem PC die Funktion getestet (z.B. ob ein Prompt kommt)?
|
|
|
|
|
13
|
International / Deutsch / Re: Ethernet und SD Karte gleichzeitig nutzen - mit dem Ethernetshield
|
on: May 20, 2013, 12:09:31 pm
|
Den Code habe ich nicht 1:1 aus dem Link übernommen, arbeite aber auch mit der String Class.
Wenn Du das brauchst. Ich brauche unter Arduino NIEMALS String-Objekte. Was ich auch noch erwähnen muß, ich verwende kein Orginal Arduino Ethernetshield, meines kommt vom Chinamann. Habe da auch schon gelesen, das dies nicht 100% kompatibel sein.
Meine Ethernet-Shields sind auch alles billigste China-Ware. Teste mal beiliegenden "Arduino SD-Karten Webserver", der läuft bei mir auf einem UNO mit China-Ethernet-Shield, anpassen der IP-Adresse an Dein Netzwerk nicht vergessen: /* * This sketch uses the microSD card slot on the Arduino Ethernet shield * to serve up files over a very minimal browsing interface * * Some code is from Bill Greiman's SdFatLib examples, * some is from the Arduino Ethernet WebServer example, * some is from Limor Fried (Adafruit), * some is from "jurs" for German Arduino forum, * so its probably under GPL */
#include <SD.h> #include <SPI.h> #include <Ethernet.h>
/************ ETHERNET STUFF ************/ byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; byte ip[] = { 192, 168, 2, 111 }; EthernetServer server(80);
/************ SDCARD STUFF ************/ Sd2Card card; SdVolume volume; SdFile root; SdFile file;
// store error strings in flash to save RAM #define error(s) error_P(PSTR(s))
void error_P(const char* str) { PgmPrint("error: "); SerialPrintln_P(str); if (card.errorCode()) { PgmPrint("SD error: "); Serial.print(card.errorCode(), HEX); Serial.print(','); Serial.println(card.errorData(), HEX); } while(1); }
char* strupper( char* s ) // helper function char array to uppercase letters { for (char* p = s; *p; ++p) *p = toupper( *p ); return s; }
char* strlower( char* s ) // helper function char array to lowercase letters { for (char* p = s; *p; ++p) *p = tolower( *p ); return s; }
void setup() { Serial.begin(9600); PgmPrint("Free RAM: "); Serial.println(FreeRam()); // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with // breadboards. use SPI_FULL_SPEED for better performance. pinMode(10, OUTPUT); // set the SS pin as an output (necessary!) digitalWrite(10, HIGH); // but turn off the W5100 chip!
if (!card.init(SPI_HALF_SPEED, 4)) error("card.init failed!"); // initialize a FAT volume if (!volume.init(&card)) error("vol.init failed!");
PgmPrint("Volume is FAT"); Serial.println(volume.fatType(),DEC); Serial.println(); if (!root.openRoot(&volume)) error("openRoot failed");
// list file in root with date and size PgmPrintln("Files found in root:"); root.ls(LS_DATE | LS_SIZE); Serial.println(); // Recursive list of all directories PgmPrintln("Files found in all dirs:"); root.ls(LS_R); Serial.println(); PgmPrintln("Done"); // Debugging complete, we start the server! Ethernet.begin(mac, ip); server.begin(); }
void ListFiles(EthernetClient client, uint8_t flags) { // This code is just copied from SdFile.cpp in the SDFat library // and tweaked to print to the client output in html! dir_t p; root.rewind(); client.println("<ul>"); while (root.readDir(p) > 0) { // done if past last used entry if (p.name[0] == DIR_NAME_FREE) break;
// skip deleted entry and entries for . and .. if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue;
// only list subdirectories and files if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;
// print any indent spaces client.print("<li><a href=\""); for (uint8_t i = 0; i < 11; i++) { if (p.name[i] == ' ') continue; if (i == 8) { client.print('.'); } client.print((char)p.name[i]); } client.print("\">"); // print file name with possible blank fill for (uint8_t i = 0; i < 11; i++) { if (p.name[i] == ' ') continue; if (i == 8) { client.print('.'); } client.print((char)p.name[i]); } client.print("</a>"); if (DIR_IS_SUBDIR(&p)) { client.print('/'); }
// print modify date/time if requested if (flags & LS_DATE) { root.printFatDate(p.lastWriteDate); client.print(' '); root.printFatTime(p.lastWriteTime); } // print size if requested if (!DIR_IS_SUBDIR(&p) && (flags & LS_SIZE)) { client.print(' '); client.print(p.fileSize); } client.println("</li>"); } client.println("</ul>"); }
// How big our line buffer should be. 100 is plenty! #define BUFSIZ 100
void loop() { char clientline[BUFSIZ]; int index = 0; EthernetClient client = server.available(); if (client) { // an http request ends with a blank line boolean current_line_is_blank = true; // reset the input buffer index = 0; while (client.connected()) { if (client.available()) { char c = client.read(); // If it isn't a new line, add the character to the buffer if (c != '\n' && c != '\r') { clientline[index] = c; index++; // are we too big for the buffer? start tossing out data if (index >= BUFSIZ) index = BUFSIZ -1; // continue to read more data! continue; } // got a \n or \r new line, which means the string is done clientline[index] = 0; // Print it out for debugging Serial.println(clientline); // Look for substring such as a request to get the root file if (strstr(clientline, "GET / ") != 0) { // send a standard http response header client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println(); // print all the files, use a helper to keep it clean client.println("<h2>Files:</h2>"); ListFiles(client, LS_SIZE); } else if (strstr(clientline, "GET /") != 0) { // this time no space after the /, so a sub-file! char *filename; filename = clientline + 5; // look after the "GET /" (5 chars) // a little trick, look for the " HTTP/1.1" string and // turn the first character of the substring into a 0 to clear it out. (strstr(clientline, " HTTP"))[0] = 0; // print the file we want Serial.println(filename);
if (! file.open(&root, filename, O_READ)) { client.println("HTTP/1.1 404 Not Found"); client.println("Content-Type: text/html"); client.println(); client.println("<h2>File Not Found!</h2>"); break; } Serial.println("Opened!"); strlower(filename); client.println("HTTP/1.1 200 OK"); if (strstr(filename,".htm")!=NULL) client.println("Content-Type: text/html"); else if (strstr(filename,".jpg")!=NULL) client.println("Content-Type: image/jpg"); else client.println("Content-Type: text/plain"); client.println(); int16_t c; while ((c = file.read()) >= 0) { // uncomment the serial to debug (slow!) //Serial.print((char)c); client.print((char)c); } file.close(); } else { // everything else is a 404 client.println("HTTP/1.1 404 Not Found"); client.println("Content-Type: text/html"); client.println(); client.println("<h2>File Not Found!</h2>"); } break; } } // give the web browser time to receive the data delay(1); client.stop(); } }
Wenn Du keine Datei aufrufst, zeigt der Server ein Dateilisting mit anklickbaren Dateinamen an. Dateinamen mit der Endung .htm werden als HTML gesendet, Dateinamen mit der Endung .jpg als Bild und Dateinamen mit der Endung .txt als einfacher Text. Unbekannte Dateiendungen werden ebenfalls als einfacher Text gesendet, aber zumindest unter Windows werden die Browser die Datei dann wohl trotzdem downloaden statt anzeigen. Probier's mal aus, ob das bei Dir läuft!
|
|
|
|
|
14
|
International / Deutsch / Re: Ethernet und SD Karte gleichzeitig nutzen - mit dem Ethernetshield
|
on: May 20, 2013, 07:23:18 am
|
In diesem Fall wird der Inhalt einer Datei auf die HTML Seite kopiert, man braucht also beide Devices quasi gleichzeitig. Klar kann das nicht gehen, aber in dem Beispielcode aus meiner erstem Posting wird es so gemacht.
Ohne Pin 10 oder 4 anzufassen. Dies wird wohl in der SD oder Ethernet Lib geregelt.
Ja, "ohne Pin 10 oder 4 anzufassen" scheint wohl tatsächlich zu funktionieren, wenigstens mit manchen Funktionen der SD- und Ethernet-Library und wenn man sich an bestimmte Reihenfolgen und Funktionen hält, scheinen es die Libraries selbst zu managen, darauf deuten auch von mir durchgeführte Tests hin. Aber: Das von Dir verlinkte Programm ist doch irgendwie ein Fake, denn es läuft auf einem UNO plus Ethernet-Shield plus den verwendeten Beispieldateien plus einem Standard-Desktop-Webbrowser (hier verwendet: Google-Chrome) trotzdem nicht. Und zwar aus dem Grund: RAM-Speichermangel. Bei meinen Tests mit dem von Dir verlinkten Programm ist es so, daß die von einem Standard-Webbrowser gesendeten HTTP-Header so lang sind, dass String HTTP_req = ""; // stores the received HTTP request ... HTTP_req += c; // save HTTP request character zum vollständigen Verbrauch des RAM-Speichers beim Einlesen des HTTP-Requests auf einem UNO führt, so dass der Controller bei HTTP-Anfragen wahlweise hängenbleibt oder neu startet, jedenfalls nicht das macht, was er machen soll. Sprich: Ein UNO hat zu wenig RAM-Speicher! Der Code könnte ggf. mit kleinen Anpassungen im Quellcode auf einem Controller mit mehr RAM-Speicher laufen, etwa einem MEGA. Oder bei einer komplett anderen speicherplatzsparenden Programmierung ohne "String" Objekte bei der Auswertung der HTTP-Header zu verwenden. Oder zusammen mit einem WEB-Browser, der sehr kurze HTTP-Header sendet. Manche Browser kann man z.B, so konfigurieren, dass Sie keinen "User-Agent" String im HTTP-Header mitsenden oder einen "User-Agent" String nach eigenem Wunsch. Jedenfalls: Das gezeigte Youtube-Video vom Funktionieren des Sketches mag unter bestimmten Umständen zutreffen, aber bei Verwendung eines UNO-Boards mit einem Standard-Webbrowsers zum Datenabruf hat das Gesamtsystem zu wenig RAM-Speicher. Und das vor allem, weil im Sketch mit einem String-Objekt der Speicher für nichts und wieder nichts vergeudet wird.
|
|
|
|
|
15
|
International / Deutsch / Re: Navigation im Dateiverzeichnis der SD-Karte und Anzeige auf LCD
|
on: May 19, 2013, 04:43:55 pm
|
Effektiv könntest du vielleicht 10 Ordner mit 10 Dateien darstellen, anschließend hast du zu wenig Speicher.
Man muss nicht alles im RAM-Speicher halten, wenn man für ein System mit extrem wenig RAM-Speicher programmiert! Eine SD-Karte hat genug Speicher für einige sortierte Dateilisten, genauer gesagt eine Dateiliste pro Verzeichnis. So geht's: Ein 8.3 Dateiname belegt 12 Bytes. Bevor das Programm einen Dateinamen aus einem Verzeichnis anzeigt, läßt man eine Initialisierungsroutine laufen. Pro Verzeichnis wird zunächst eine "versteckte Datei" mit einer Dateiliste angelegt, in der alle Dateien des Verzeichnisses drinstehen. Dateiname z.B. sdidx.txt (diese versteckte Datei wird aber NICHT mit in die Dateiliste geschrieben). Die Dateiliste in sdidx.txt wird an Ort und Stelle sortiert, durch Tauschen von je 12 und 12 Bytes mit Dateinamen. Und zum Anzeigen der nun sortierten Dateiliste wird jetzt einfach die Datei sdidx.txt geöffnet und immer ein Dateiname angezeigt. Erster Dateiname steht in den ersten 12 Bytes, zweiter Dateiname in den zweiten 12 Bytes, dritter Dateiname ... Wenn ein ausgewählter Name ein Verzeichnisname ist, wird ins entsprechende Unterverzeichnis gewechselt und dort die versteckte Datei initialisiert/geöffnet. Wenn ein ausgewählter Name kein Verzeichnis- sondern ein Dateiname ist, ist dieser Name ausgewählt. An RAM-Speicher werden im wesentlichen dreimal 12 Bytes benötigt, weil man nie mehr als drei Dateinamen gleichzeitig im Speicher halten muß, egal wieviele Dateien auf der SD-Karte sind, also auch nicht bei 100 Dateien in 1000 verschiedenen Ordnern. Plus die Bytes, die der maximalen Dateipfadlänge entsprechen, um auch den kompletten Dateipfad zu verwalten. Plus vielleicht ein abschließendes Nullzeichen an jedem der vier char-Arrays, um bequem die C-Stringfunktionen verwenden zu können (z.B. zum Vergleichen von Dateinamen beim Sortieren). Speichermangel gibt es dabei nicht, sofern nicht der Speicher auf der SD-Karte ausgeht. BTW: Auch ein "Tree (Nested-Set-Model)" kann man im wesentlichen auf Massenspeicher anlegen, so dass man sich durch eine sehr große Datenstruktur hangeln kann, ohne dabei viel RAM-Speicher zu benötigen.
|
|
|
|
|