PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem beim ersten Projekt



Spaniokel
21.10.2013, 16:51
Hallo zusammen,

ein Kumpel und ich sitzen gerade an unserem ersten Arduino-Projekt und bräuchten etwas Hilfe. Wir sind keine Profis was das programmieren angeht und das erkennt man wahrscheinlich auch an unserem Programmcode^^.

Für eine kleine Windkraftanlage, die bei unserer Uni auf dem Dach steht, möchten wir die Drehzahl des Rotors, die Umfangsgeschwindigkeit des Rotors, die Windrichtung sowie die Windgeschwindigkeit messen. Die Messergebnisse sollen auf eine SD-Karte geschrieben und auf einem LCD-Display angezeigt werden. Die ganze Einheit soll später direkt an der Windkraftanlage in einer Plastikbox angebracht und mit einer Batterie betrieben werden. Bei Bedarf soll die SD-Karte samt der aufgezeichneten Daten entnommen und am PC ausgewertet werden können. Hierfür haben wir folgende Komponenten vorgesehen:

- 1 Arduino Uno
- 1 Data Logger Shield Kit v1.0 (http://www.adafruit.com/products/243)
- 1 16x2 LCD Shield Kit (http://www.adafruit.com/products/715)
- 1 Power Predictor (http://www.bettergeneration.co.uk/power-predictor/introducing-the-power-predictor-anemometer.html), zur Messung der Windrichtung und der Windgeschwindigkeit
- 1 Reed Sensor + Magnet (zum erfassen der Drehzahl des Rotors)

Soweit so gut....
Wir haben alles angeschlossen und programmiert. Allerdings stoßen wir auf das Problem, dass der Data Logger nicht richtig funktioniert. Das heißt er erstellt zwar eine Datei auf der SD-Karte, schreibt aber nichts in diese Datei. Des Weiteren funktioniert das LCD-Shield nur dann, wenn der Data-Logger nicht angeschlossen wird.

Wir haben die Vermutung das es daran liegt, dass sowohl das LCD Shield als auch der Data Logger auf die ANALOG IN Pin 4 und Pin 5 zugreifen... Da diese beiden Pins aber von den mitgelieferten Libraries des LCD-Shields und des SD-Shields definiert werden, konnten wir diese nicht neu definieren. Dazu fehlt uns einfach das Know how, um in der Libray die P...

Wie gesagt, wir vermuten das es daran liegt, wissen es aber nicht genau. Für jede Art von Vorschlag/Hilfe sind wir dankbar.

Hier einmal unser Code (bitte nicht erschrecken, wir sind Anfänger ;) ):







//-------------------------------------------------------------Libraries*einbinden-----------------------------------------------------------

//LED*LIBRARIES
#include*<Wire.h>
#include*<Adafruit_MCP23017.h>
#include*<Adafruit_RGBLCDShield.h>

//Data*Logger*Libraries
#include*<SD.h>
#include*<Wire.h>
#include*"RTClib.h"

//Sonstige*Libraries
#include*<EEPROM.h> // EEPROM Byte Speicherung Library

//---------------------------------------------------------------Definition*LCD---------------------------------------------------------------

//*Das*LCD*Shield*verwendet*standardmäßig*die*Analog ausgänge*4*und*5*des*Arduino*für*die*Datenübermitt lung

Adafruit_RGBLCDShield*lcd*=*Adafruit_RGBLCDShield( );***//Bennunung des LCD Shields in "lcd"


#define*OFF*0x0*********************************** *****//#define Definiert die Farben des LCD
#define*RED*0x1
#define*YELLOW*0x3
#define*GREEN*0x2
#define*TEAL*0x6
#define*BLUE*0x4
#define*VIOLET*0x5
#define*WHITE*0x7

//---------------------------------------------------Definition*Data*Logger-------------------------------------------------------------------
const int chipSelect = 10;

File dataFile;
long zeitAnfang = 0;
long zeitEnde = 0;
long drehzahlZwischenspeicher = 0;
boolean timerMittelwert = 0;
int zaehlerIst = 0;

RTC_DS1307*rtc;

//-------------------------------------------------------------Implementierung*der*Zähler*&*Variablen------------------------------------------

int lcd_count = 0; // Implementierung der Zähler für die LCD Menüsteuerung
int color_count = 0;
int horizontal_count = 0;
int vertical_count = 0;

int avg1_count = 0; //Anzahl Messwerte im Puffer für die Drehzahl der Windkraftanlage
int avg2_count = 0; //Anzahl Messwerte im Puffer für die Drehzahl der Windgeschwindigkeitsanzeige

const int AVG1 = 4; // Einstellung der Glättungsvariablen über mindestens 4 Messwerte

//---------------------------------------------------Definition*DREHZAHLSENSOR*(Eingangspin*2)--------------------------------------------

//*Definition*der*Drehzahlsensorvariablen

volatile*unsigned long dauer=0; // microsekunden seit dem letzten Interrupt
volatile*unsigned long last=0; // Zählerwert beim letzten Interrup
volatile*unsigned long average_rpm=1;

long drehzahl; // Definition der Variablen "Drehzahl"
int durchmesser_windrad = 2200;
long umfangsgeschwindigkeit;
long interruptDauer = 0;
long interruptStop = 0;

char buf[17]; // RPM (Umdrehungen) Pufferstring für sprintf
char buf3[17]; // Umfangsgeschwindigkeit

const int EingangDrehzahlmesser = 2; // Pin 2 ist Eingang für Drehzahlschalter (Reed Kontakt)

int drehzahlMittelwert; //Mittelwerte Drehzahlsensor für Datalogger

//--------------------------------------------------Definition*WINDGESCHWINDIGKEITSENSOR*(Eingangspin* A1)**---------------------------------

//Definition*der*Windgeschwindigkeitsvariablen

volatile*unsigned long dauer1=0;
volatile*unsigned long last1=0;

long drehzahl1;
long windgeschwindigkeit; // Definition der Variablen "Windgeschwindigkeit"
long interrupt1Dauer = 0;
long interrupt1Stop = 0;

char buf1[17]; // Windgeschwindigkeit Pufferstring für sprintf
const int EingangWindgeschwindigkeit = 3; // Pin 3 ist Eingang für Reed Kontakt des Anemometers

int windgeschwindigkeitMittelwert; //Erstellung der Mittelwerte für die Windgeschwindigkeit

//--------------------------------------------------Definition*Windrichtungssensor*--------------------------------------------------------

#define*EingangPotentiometer*(A0)*

String windrichtung;
int Richtung;
int KorrRichtung = 0; //Korrekturwert für Richtungswert (-360 bis +360) für die Kalibrierung der Windfahne
int WertPotentiometer = 0; //Zwischenspeicher der Werte des Poti
String buf2; //Ausgabewert der Windgrichtung

const int CalPin = 8; //Definition Kalibrierungsknopf
byte DirCorrB1 = 0; //Korrekturwerte bei der Kalibrierung
byte DirCorrB2 = 0;

//-------------------------------------------------------------------SETUP------------------------------------------------------------------

void setup() { // Setup des Gesamtsystems initialisieren
**Serial.begin(9600);

**//LCD initialisieren---------------------------------
**// Ausgänge für das LCD debuggen - Gibt die Übertragungsgeschwindigkeit des LCD Shield und des Arduino in [bit/s] an
**lcd.begin(16, 2); // Setup des LCD in Anzahl der Zeichen und Anzahl der Reihen:
**lcd.print("STARTE..."); // Standard Überschrift "Drehzahlmesser" ausgeben
**lcd.setCursor(0, 1);
**lcd.print("Halten f. KAL");

**lcd.setCursor(15, 1);
**lcd.print("5");
**delay(1000);
**lcd.setCursor(15, 1);
**lcd.print("4");
**delay(1000);
**lcd.setCursor(15, 1);
**lcd.print("3");
**delay(1000);
**lcd.setCursor(15, 1);
**lcd.print("2");
**delay(1000);
**lcd.setCursor(15, 1);
**lcd.print("1");
**delay(1000);

**lcd.clear();

**//DataLogger initialisieren--------------------------
#ifdef*AVR
**Wire.begin();
#else
**Wire1.begin(); // Initialisierung des Dataloggers
#endif
**rtc.begin();

**Serial.println("Datum,Uhrtzeit,RPM [1/min],Umfangsgeschw.[m/s],Windgeschw.[m/s],Windrichtung");
**dataFile.println("Datum,Uhrtzeit,RPM [1/min],Umfangsgeschw.[m/s],Windgeschw.[m/s],Windrichtung");

**zeitAnfang*=*millis();

**//Drehzahlsensor-------------------------------------
**pinMode(EingangDrehzahlmesser, INPUT); // Definition EingangDrehzahlmesser (pin 2) als Eingangspin
**digitalWrite(EingangDrehzahlmesser, HIGH); // Arduinointernen Pullup-Widerstand einschalten (20kOhm), somit wird kein Hardwarewiderstand benötigt

**attachInterrupt(0, readmicros , RISING ); // Interrupt 0 (pin2 auf ArduinoUno) auf Routine "readmicros" (Zeit zwischen Umdrehungen) reagiert auf steigende Flanken an Pin 2

**//Windgeschwindigkeit
**pinMode(EingangWindgeschwindigkeit, INPUT); // Definition EingangDrehzahlmesser (pin 3) als Eingangspin
**digitalWrite(EingangWindgeschwindigkeit, HIGH); // Arduinointernen Pullup-Widerstand einschalten (20kOhm), somit wird kein Hardwarewiderstand benötigt

**attachInterrupt(1, readmicros1 , RISING ); // Interrupt 1 (pin3 auf ArduinoUno) für den Windgeschwindigkeitssensor

**//Windrichtung
**pinMode(CalPin, INPUT); // Kalibrierung, wenn der Kalibrierungsknopf gedrückt ist
**digitalWrite(CalPin, HIGH);
**delay(1000);
**if ((digitalRead(CalPin) == LOW)){
****calibrate*();
**}
**else lcd.print("1.Drehzahlmesser");

**DirCorrB1*=*EEPROM.read(1); // Wenn keine Kalibrierung gestartet wird, Werte aus Zwischenspeicher übernehmen
**DirCorrB2*=*EEPROM.read(2);

**KorrRichtung*=*(DirCorrB1)*+*(DirCorrB2);*

}


//-------------------------------------*Hauptprogramm------------------------------------------------------------------------------------

void loop() { // Hauptprogramm als Schleife

**//Drehzahl---------------------------------------------------------------
**if ( dauer == 0 || (((interruptDauer = millis()) - interruptStop) > 20000)){ //Drehzahl startet bei Null und springt bei Fehlen von Signalen nach 20s auf Null zurück
****drehzahl*=*0;
****umfangsgeschwindigkeit*=*0;
****avg1_count*=*0;
**}
**else {
****drehzahl*=*myround*(60000000*/*average_rpm);************************************ *****// Drehzahl ausrechnen
****umfangsgeschwindigkeit*=*((drehzahl**3.1415926 5359**durchmesser_windrad)/60000);*****//Aus Drehzahl Umfangsgeschwindigkeit ausrechnen
**}

**//Windgeschwindigkeit----------------------------------------------------
**if ( dauer1 == 0 || (((interrupt1Dauer = millis()) - interrupt1Stop) > 20000)){ // Bei Start des Programmes und bei Stillstand (20s) auf Wert Null setzen
****windgeschwindigkeit*=*0;
**}
**else {
****drehzahl1*=*60000000*/*dauer1;****************************************** **************// Drehzahl ausrechnen
****windgeschwindigkeit*=*((((drehzahl1**3.1415926 5359**0.13)*/*60)**3)**3.6);************//Aus Drehzahl Umfangsgeschwindigkeit ---> Windgeschwindigkeit = Vu*3
**}

*

**//Anzeige der Puffervariablen----------------------

**sprintf(buf,*"RPM %4lu ", drehzahl); // Drehzahl als 4stellig formatierte Zahl in den Puffer schreiben
**sprintf(buf3,*"%2lu m/s", umfangsgeschwindigkeit); // Geschwindigkeit als 2stellig formatierte Zahl in den Puffer schreiben
**sprintf(buf1,*"%2lu km/h", windgeschwindigkeit); // Geschwindigkeit als 2stellig formatierte Zahl in den Puffer schreiben
**buf2*=*(windrichtung);************************** ********//Windrichtung als Himmelsrichtung ausgeben

**//Daten der zweiten Reihe anzeigen-----------------

**lcd.setCursor(0, 1); // cursor an den Anfang der 2. Zeile (fängt mit 0 an)

**if ((horizontal_count == 0) && (vertical_count == 0)){
****lcd.print(buf); // Puffer (RPM) ausgeben
**}
**if ((horizontal_count == 0) && (vertical_count == 1)){
****lcd.print(buf3); // Puffer3 (Umfangsgeschwindigkeit) ausgeben
**}

**if (horizontal_count == 1){
****lcd.print(buf1); // Puffer1 (Windgeschwindigkeit) ausgeben
**}

**if (horizontal_count == 2){
****lcd.print(buf2); // Puffer2 (Windrichtung) ausgeben
**}


**//DataLogger------------------------------------------------------------

**//Mittelwert Drehzahlsensor
**if (timerMittelwert == 0){ //Ist der Timer auf "0", springt das Programm in Mittelwert berechnen.
****MittelwertBerechnen();*
**}

**//Schreiben des Datums und Uhrzeit alle 5 Sekunden-------------------------

**if (timerMittelwert == 1){ //Wurde der Timer des Mittelwertes von Mittelwert Berechnen von 0 auf 1 gesetztz, wird eine Datenreihe auf die SD Karte geschrieben

****DateTime*now*=*rtc.now();

****Serial.print(now.year(), DEC);
****Serial.print('/');
****Serial.print(now.month(), DEC);
****Serial.print('/');
****Serial.print(now.day(), DEC);
****Serial.print(',');
****Serial.print(now.hour(), DEC);
****Serial.print(':');
****Serial.print(now.minute(), DEC);
****Serial.print(':');
****Serial.print(now.second(), DEC);
****Serial.print(',');

****dataFile.print(now.year(), DEC);
****dataFile.print('/');
****dataFile.print(now.month(), DEC);
****dataFile.print('/');
****dataFile.print(now.day(), DEC);
****dataFile.print(',');
****dataFile.print(now.hour(), DEC);
****dataFile.print(':');
****dataFile.print(now.minute(), DEC);
****dataFile.print(':');
****dataFile.print(now.second(), DEC);
****dataFile.print(',');

****Serial.println(drehzahlMittelwert);
****dataFile.println(drehzahlMittelwert);
****Serial.print(',');
****dataFile.print(',');
****Serial.print(windgeschwindigkeitMittelwert);
****dataFile.print(windgeschwindigkeitMittelwert);

****dataFile.flush();
****timerMittelwert*=*0;
****zeitAnfang*=*millis();
**}

}
//-------------------------------------INTERRUPT*1*für*Drehzahlmesser*(Pin*2)---------------------------------------

void readmicros() { // Interrupt-Routine 1

**detachInterrupt(1); // Interrupt 2 ausschalten
**detachInterrupt(0); // Interrupt 1 ausschalten

**int avgmax;

**unsigned long us = micros(); // Microsekundenzähler auslesen
**if (last == 0) { // erster Messwert
****last*=*us;******************************// merken und nicht weiter bearbeiten
**}****
**else {
****if ( us < last ) { // Zählerüberlauf
******dauer*=*4294967295*-*last*+*us;*********// erzeugt einen Fehler von 1µS - vernachlässigbar
****}
****else {
******dauer*=*us*-*last;**********************// Differenz zum letzten Durchlauf berechnen
****}

****if (dauer > 5000) { // ignorieren wenn <= 5ms (Kontaktpreller)
******average_rpm*=*dauer*+*average_rpm***avg1_cou nt++;********// Wert in buffer und mit Faktor avgcnt glätten

******average_rpm*/=*avg1_count;*******************************// und zurückrechnen
******avgmax*=*1000000*/*dauer;********************************// dynamische Größe des Integrationspuffers

******if (avgmax < AVG1) avgmax = AVG1; // Trägheit mindestens 1 Sekunde

******if (avg1_count >= avgmax) avg1_count--;

******last*=*us;********************************** ************// und wieder den letzten Wert merken
****}

**}

**interruptStop*=*millis();
**attachInterrupt(0, readmicros, RISING ); // Interrupt 1 wieder einschalten.
**attachInterrupt(1, readmicros1, RISING ); // Interrupt 2 wieder einschalten.

}

//-------------------------------------INTERRUPT*2*für*Windgeschwindigkeitssensor*(Pin*3)---------------------------------------

void readmicros1() { // Interrupt-Routine 2

**detachInterrupt(0); // Interrupt 1 ausschalten während Interrupt 2 läuft
**detachInterrupt(1); // Interrupt 2 ausschalten während er läuft

**unsigned long t = micros(); // Microsekundenzähler auslesen
**unsigned long dt = t - last1; // Differenz zum letzten Durchlauf berechnen

**if (dt > 100000) { // ignorieren wenn <= 100ms (Kontaktpreller)
****dauer1*=*dt;**********************************// Wert in dauer übernehmen
****last1*=*t;************************************// und wieder den letzten Wert merken
**}

**interrupt1Stop*=*millis();
**attachInterrupt(1, readmicros1, RISING ); // Interrupt wieder einschalten.
**attachInterrupt(0, readmicros, RISING ); // Interrupt wieder einschalten.

}


//-------------------Gewichtete*Rundung*für*Drehzahlmesser*einstellen--------------------------------

unsigned long myround(unsigned long value) { // Gewichtete Rundung für den Drehzahlsensor erstelleb
**int rto;

**if (value > 3000) { // Rundungswert bestimmen
****rto*=*100;****
**}

**else if (value > 1500) {
****rto*=*50;
**}

**else if (value > 500) {
****rto*=*10;
**}

**else if (value > 100) {
****rto*=*5;
**}
**else {
****return (value);
**}

**return (_myround(value, rto));

}

unsigned long _myround(unsigned long value, int roundto) {

**value*+=*(roundto*>>*1);**************************************// Halben roundto Wert addieren

**value*/=*roundto;**************************************** *****// Integer division

**value**=*roundto;******************************* **************// Integer multiplikation

**return (value);
}
//Kalibrierung*der*Windrichtung------------------------------------------------------------------------

void calibrate () { //Routine wird aufgerufen, wenn der Kalibrierungsknopf beim Start des Systemes gedrückt wird

**lcd.clear();
**lcd.setCursor(0, 1);
**lcd.print("Kalibriert... ");
**delay (1000); //Eine Sekunde warten

**WertPotentiometer*=*analogRead(EingangPotentiome ter); //Wert des Poti auslesen
**KorrRichtung*=*map(WertPotentiometer, 0, 1023, 359, 0); //Korrekturwert ins Array schreiben

**lcd.setCursor(0, 1);
**lcd.print("KAL Wert = "); //Korrekturwert ausgeben
**lcd.print(KorrRichtung, DEC);
**lcd.print(" ");
**delay (2000); //2 Sekunden warten

**//Korrekturwerte in beide Richtungen speichern
**DirCorrB1*=*KorrRichtung*/*255;
**if (DirCorrB1 == 1){
****DirCorrB1*=*255;**
****DirCorrB2*=*KorrRichtung*-*255*;
**}
**else {
****DirCorrB1*=*KorrRichtung;**
****DirCorrB2*=*0;
**}***

**EEPROM.write (1, DirCorrB1); //Und in den EEPROM Speicher schreiben
**EEPROM.write (2, DirCorrB2);

**lcd.clear();

**lcd.setCursor(0, 1);
**lcd.print("KAL OK!");
**delay(1000);

**lcd.clear(); //Kalibierung abgeschlossen. System startet mit neuer Kalibierung neu...
**lcd.print("Kalibrierung OK");
**lcd.setCursor(0, 1);
**lcd.print("Neustart... ");
**delay (2000);

**lcd.clear();
**setup ();
}*

//Mittelwerte*berechnen-----------------------------------

void MittelwertBerechnen(){ //Mittelwerte der Drehzahl und Windgeschwindigkeit erstellen und alle 5 min auf die SD schreiben

****if (((zeitEnde = millis()) - zeitAnfang) < 5000){ //Wärend die Gesamtzeit von 5 min wird alle 300ms ein Wert genommen.
****zaehlerIst*++;******************************** **********************//Die Anzahl der Werte wird zwecks Mittelwertbestimmung fortgeschrieben.
****drehzahlZwischenspeicher*=*drehzahlZwischenspe icher*+*drehzahl;
****drehzahlMittelwert*=*0;
****timerMittelwert*=*0;
****delay(300);
**}

**if (((zeitEnde = millis()) - zeitAnfang) >= 5000){ //Ist die Gesamtzeit erreicht, wird der Mittelwert berechnet und die Zähler wieder genullt

****drehzahlMittelwert*=*(drehzahlZwischenspeicher */*zaehlerIst);
****zaehlerIst*=*0;
****drehzahlZwischenspeicher*=*0;
****timerMittelwert*=*1;
**}
}




Ich hoffe der Code wird richtig angezeigt ;) Wenn die Beschreibung noch zu ungenau ist, dann führe ich die Problemstellung gerne noch weiter aus. Wir hoffen auf schnelle Hilfe.

Danke und beste Grüße

Arkon
22.10.2013, 07:02
Ich hab mir den Code jetzt nicht genauer angesehen. Die ganzen Sternchen machen mich wahnsinnig XD

Wenn zwei Shields auf die gleichen Pins zugreifen wird es Probleme geben. Die entsprechenden Stellen in den Libs zu ändern ist doch aber nicht schwer, wenn ihr die Stellen schon gefunden habt. Ihr müsst nur auch die Pins auf den Platinen entsprechend anpassen. Dazu entweder die Leiterbahnen auftrennen und fliegend neu verdrahten oder per Go-Between-Shield die Pins entsprechend umrouten.

Spaniokel
22.10.2013, 11:19
Hey Arkon,

danke für deine Antwort. Die Pins in den Libs zu ändern ist nicht so einfach (auf jeden Fall für uns nicht), da die Pins dort ja nicht mit Pin 4 bzw. Pin 5 bezeichnet werden... Da wir keine klassischen Programmierer sind, wissen wir nicht wie die beiden Pins dort bezeichnet werden bzw. wie man diese ändert oder ob man sie ohne weiteres überhaupt ändern kann. Vielleicht könntest du ja mal einen Blick in die Libraries werfen. Wie gesagt wir stoßen da an unsere Grenzen ;)

LCD-Shield Library: http://learn.adafruit.com/rgb-lcd-shield/downloads

SD-Shield Library: http://learn.adafruit.com/adafruit-data-logger-shield/downloads

Ansonsten hätten wir noch die Möglichkeit auf einen Arduino Leonardo oder auf einen Due umzusatteln. Allerdings glaube ich, dass das unser Problem auch nicht löst.
Vielen Dank für deine Bemerkungen/Hilfe. Wäre gut wenn wir weitere Hilfestellung bekommen könnten =)

Viele Grüße

Arkon
22.10.2013, 12:18
Bin noch auf der Arbeit. Werde heute Abend mal in die Libs gucken. Denn beide hatte ich selbst noch nicht in Gebrauch.

Normalerweise werden die Pins aber zu Beginn der Lib mit einer Deklaration "umbenannt" um nachfolgend aussagekräftige Namen verwenden zu können. Als Beispiel kannst du in eurem Code ja die Farben für das LCD heranziehen. Ist halt einfacher zu schreiben lcd.backgroundColor(GREEN) als sich merken zu müssen, dass lcd.backgroundColor(0x2) das gleiche macht.

Arkon
22.10.2013, 19:26
Soooo.....

Habe nen kurzen Blick in die beiden Libs geworfen. Die SD-Master nutzt Pin4 ebenso wie die LCD-Lib. In der SD-Master kannst du den Pin mit der Zeile

const int chipSelect = 4;

Das habt ihr auch gemacht, allerdings auf Pin10 welcher eh schon von der SD-Master genutzt wird.