Go Down

Topic: Funktion erstellen (Read 477 times) previous topic - next topic

chubacca

Hallo zusammen,

Nachdem ich ja schon stundenlang Bücher über C programmieren und Arduino Bücher gelesen habe, will ich jetzt mein erstes Praxisbezogenes Projekt erstellen, um gelesenes auch zu verwenden.

Das Projekt soll:

Per Matrixtastatur einen Sollwert an den Frequenzumrichter weitergeben (0-10V).
Am Display die Benutzereingabe, Sollwert, Istwert anzeigen.

Die Hardware funtioniert soweit.

Was mein grosses Problem ist, ich würde gerne zwecks eigenem Verständnis selber Funktionen erstellen.
Der erste Sketch funktioniert so wie ich will.
Das geht es um den abschnitt im Sketch "Wert der Matrixtastatur einlesen".
Im zweiten Sketch versuche ich es in eine Funktion zu verpacken was mir leider nicht gelingt.

Meiner Meinung nach:
1. Ich habe keine Parameter zu übergeben
2. Ich habe den Rückgabewert valueInt

Erster Sketch:
Code: [Select]

#include <LCD5110_Graph.h>
#include <Keypad.h>
#include <string.h>
#include <TimerOne.h>
const byte ROWS = 4; //four rows
const byte COLS = 3; //four columns
//define the cymbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
byte rowPins[ROWS] = {8, 7, 6, 5}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {4, 3, A4}; //connect to the column pinouts of the keypad
Keypad keyp = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); //initialize an instance of class NewKeypad
LCD5110 LCD(13,9,10,11,12);
extern unsigned char SmallFont[];
extern unsigned char TinyFont[];
int ZaehlerTaste;
char WertTaste[4];
static int WertRPM=0;
unsigned int counter=0;
unsigned int rotation=0;
void docount()  // counts from the speed sensor
{
  counter++;  // increase +1 the counter value
}

void timerIsr()
{
  Timer1.detachInterrupt();  //stop the timer
  Serial.print("Motor Speed: ");
  int rotation = (counter / 2);  // divide by number of holes in Disc
  Serial.print(rotation,DEC); 
  LCD.printNumI(rotation,RIGHT,16);
  Serial.println(" Rotation per seconds");
  counter=0;  //  reset counter to zero
  Timer1.attachInterrupt( timerIsr );  //enable the timer
}

void setup(){
  pinMode(A0,INPUT);
  Serial.begin(9600);
  LCD.InitLCD();
  LCD.setFont(SmallFont);
  Timer1.initialize(1000000); // set timer for 1sec
  attachInterrupt(0, docount, RISING);  // increase counter when speed sensor pin goes High
  Timer1.attachInterrupt( timerIsr ); // enable the timer

}


void loop(){

LCD.print("Eingabe: ",LEFT,0);
LCD.print("SOLLWERT: ",LEFT,8);
LCD.print("ISTWERT: " ,LEFT,16);
LCD.update();

//Wert der Matrixtastatur einlesen
char keypressed= keyp.getKey();
 if(keypressed != NO_KEY)
 {
  WertTaste[ZaehlerTaste]=keypressed;
  ZaehlerTaste++;
  int Wertint=atoi(WertTaste);
  LCD.printNumI(Wertint,RIGHT,0);   //Eingabewert an Display
  LCD.update();

 
  switch (keypressed)
    {
    case '*':  //Löscht die Eingabe
    Wertint=0;
    memset(WertTaste, '\0', sizeof(WertTaste));
    ZaehlerTaste=0;
    LCD.clrScr();
    LCD.printNumI(WertRPM,RIGHT,8);
    LCD.update();
    break;
 
    case '#':      //Übernimmt die Eingabe
    LCD.clrScr();
    WertRPM=Wertint;
    LCD.printNumI(WertRPM,RIGHT,8);
    Wertint=0;
    memset(WertTaste, '\0', sizeof(WertTaste));
    ZaehlerTaste=0;
    LCD.update();
    //Serial.print(WertRPM);
    break;
  }
   
 
  }
}

 
   
 
 
 

 
   
 
 
 


Und hier im zweiten Sketch versuch ich die Eingabe der Tastatur in eine Funktion zu verpacken (keyInput)
Leider mach ich da was falsch, entweder bei der ersten Taste die ich drücke kommt irgendein Wert, oder das Display blinkt nur, und etliche seltsame Dinge. Ich hab schon die wildesten Konstellationen versucht,
komm aber nicht drauf was ich falsch mache.
Code: [Select]

#include <LCD5110_Graph.h>
#include <Keypad.h>
#include <string.h>
#include <TimerOne.h>
const byte ROWS = 4; //four rows
const byte COLS = 3; //four columns
//define the cymbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
byte rowPins[ROWS] = {8, 7, 6, 5}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {4, 3, A4}; //connect to the column pinouts of the keypad
Keypad keyp = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); //initialize an instance of class NewKeypad
LCD5110 LCD(13,9,10,11,12);
extern unsigned char SmallFont[];
extern unsigned char TinyFont[];
int ZaehlerTaste =0;
int Wertint =0;
int valueInt =0;
char WertTaste[4];
static int WertRPM =0;
unsigned int counter =0;
unsigned int rotation =0;


//Funktionen
void docount()  // counts from the speed sensor
{
  counter++;  // increase +1 the counter value
}

void timerIsr()  //Drehzahlmesser
{
  Timer1.detachInterrupt();  //stop the timer
  Serial.print("Motor Speed: ");
  int rotation = (counter / 2);  // divide by number of holes in Disc
  Serial.print(rotation,DEC); 
  LCD.printNumI(rotation,RIGHT,16);
  Serial.println(" Rotation per seconds");
  counter=0;  //  reset counter to zero
  Timer1.attachInterrupt( timerIsr );  //enable the timer
}


int keyInput () // Funktion sollte den Wert  der Matrixtastatur als INT übergeben
{
 
  char keypressed=keyp.getKey();
  WertTaste[ZaehlerTaste]=keypressed;
  ZaehlerTaste++;
  valueInt=atoi(WertTaste);
  return valueInt;
}
 

void setup(){
  pinMode(A0,INPUT);
  Serial.begin(9600);
  LCD.InitLCD();
  LCD.setFont(SmallFont);
  Timer1.initialize(1000000); // set timer for 1sec
  attachInterrupt(0, docount, RISING);  // increase counter when speed sensor pin goes High
  Timer1.attachInterrupt( timerIsr ); // enable the timer

}


void loop(){

LCD.print("Eingabe: ",LEFT,0);
LCD.print("SOLLWERT: ",LEFT,8);
LCD.print("ISTWERT: " ,LEFT,16);

LCD.update();

char keypressed= keyp.getKey();
 if(keypressed != NO_KEY)
 {
  keyInput(); //Aufruf der Funktion
  Wertint=valueInt;
  LCD.printNumI(Wertint,RIGHT,0); //Ausgabe am Display
  LCD.update();
 
  switch (keypressed)
   {
    case '*':  //Löscht die Eingabe
    Wertint=0;
    memset(WertTaste, '\0', sizeof(WertTaste));
    ZaehlerTaste=0;
    LCD.clrScr();
    LCD.printNumI(WertRPM,RIGHT,8);
    LCD.update();
    break;
 
    case '#':      //Übernimmt die Eingabe
    LCD.clrScr();
    WertRPM=Wertint;
    LCD.printNumI(WertRPM,RIGHT,8);
    Wertint=0;
    memset(WertTaste, '\0', sizeof(WertTaste));
    ZaehlerTaste=0;
    LCD.update();
    //Serial.print(WertRPM);
    break;
  }
   
 
  }
}

 
   
 
 
 

 
   
 
 
 

Kann mir da wer helfen bitte, ist sicher eine Kleinigkeit für einen erfahrenen Arduinonutzer.
Gruss
Chubacca

combie

#1
Sep 17, 2018, 01:14 pm Last Edit: Sep 17, 2018, 02:04 pm by combie
Quote
ist sicher eine Kleinigkeit für einen erfahrenen Arduinonutzer.
Is klar....
Keine Fragen ...
Alles klar...



Quote
Nachdem ich ja schon stundenlang Bücher über C programmieren ...
Da steckt schon mal ein Irrtum!
Arduino ist C++, nicht C.
Und ja, das macht einen Unterschied.


------------


Deine ISRs nutzen Funktionen/Methoden, welche ihrerseits ISRs benötigen/nutzen.
Das geht ins Auge, da Interrupts in ISRs grundsätzlich erst mal gesperrt sind.

Zusätzliche Stichworte: volatile und atomic


------

Zu deinem Array "WertTaste"
Ich sehe keinen Schutz, welcher das Schreiben über das Arrayende hinweg, verhindern würde.
Auch erwartet atoi() einen C- String, mit einem Null Byte als Begrenzer.
Ein Frosch, der im Brunnen lebt, beurteilt das Ausmaß des Himmels nach dem Brunnenrand.

chubacca

Was hat der Interrupt mit meiner Funktion keyInput zu tun?
Arrayende,ist das nicht durch [4] gegeben?
Und sehr eigenartig finde ich das der ganze Sketch in der ersten Version ohne meiner keyInput wie gewünscht funktioniert.Danke trotzdem für deinen Denkanstoss combie,werde das weiter verfolgen sobald ich die Sache mit der Funktion gelöst habe.
Hat vielleicht jemand einen Tipp der sich auf keyInput bezieht?
Gruss

combie

Quote
Arrayende,ist das nicht durch [4] gegeben?
Wie kommst du darauf...?

Du reservierst 4 Speicherplätze, mehr nicht.
Im Programm ignorierst du die sich daraus ergebene und auch notwendige Grenze.
Dein C++ kennt da keine Gnade, das schreibt gerne über das Ziel hinaus, wenn du ihm das befielst.


Beispiel:
Ist der Autofahrer für das lesen der Schilder zuständig, oder das Auto?
Ein Frosch, der im Brunnen lebt, beurteilt das Ausmaß des Himmels nach dem Brunnenrand.

chubacca

Und das ist der Grund das die Funktion nicht funktioniert?  Na das muss mal wer verstehen.Hut ab vor den c++ Programmierern..
Danke sehr.
Dann bleib ich wohl lieber bei der Version ohne Funktion,die funktioniert wenigstens.
Gruss

combie

Quote
Und das ist der Grund das die Funktion nicht funktioniert?
Das habe ich nicht gesagt.
Ist aber durchaus möglich.

Quote
Na das muss mal wer verstehen.Hut ab vor den c++ Programmierern..
Naja...
Ich würde dazu neigen, solche Situationen zu vermeiden.
Im Vorfeld schon.

Aber sowas fällt einem nicht von selber zu.
Dazu muss man diese Falle schon mal gespürt haben.

Wer einmal stundenlang einen solchen Fehler gesucht hat, investiert die 2 Minuten im Vorfeld gerne.


Quote
Dann bleib ich wohl lieber bei der Version ohne Funktion,die funktioniert wenigstens.
Kannst du natürlich tun...

Aber ob das die beste Idee ist? Naja....


Mein Rat:
Eliminiere alle Interrupts, es sei denn, sie sind unbedingt nötig.


Und wenn du Interrupts nutzt, dann denke an volatile und atomic. (sachte ich aber doch schon)
Auch eine der Fallen, die man mal gespürt haben muss.
Möglich, dass dir das auch hier ins Essen spuckt.



Teile den Code sinnvoll in Zuständigkeiten auf.
Jede Zuständigkeit gehört in eine Funktion oder Klasse gekapselt.
Das erlaubt die Dinge einzeln zu testen.

Ich kann vielleicht 3 Zuständigkeiten gleichzeitig im Fokus halten.
Bei 5 komme ich in Schwierigkeiten, es bildet sich ein Widerwille.

Das gilt auch für Schachtelungstiefen, von Schleifen und If Konstrukten.

Anfängern traue ich da noch weniger zu.


Ein Frosch, der im Brunnen lebt, beurteilt das Ausmaß des Himmels nach dem Brunnenrand.

gregorss

Ich habe Deine Sketches nicht gelesen. Mir ist nur aufgefallen:

Combie sondert wieder einmal Müll ab.

C++ ist eine Obermenge (quasi Erweiterung) von C. Du kannst also problemlos pures C programmieren.

Was das mit dem Index des Arrays angeht: In der Deklaration gibst Du die Zahl der Elemente im Array an (z. B. 5), der Index beginnt jedoch bei 0, woraus folgt, dass Du bei 5 Elementen maximal den Index 4 benutzen kannst. Wenn Du den Index 5 verwendest, erhältst Du eine Fehlermeldung („out of range" oder so, das hängt evtl. auch davon ab, ob Du lesen oder schreiben möchtest).

Mehr ist mir auf die Schnelle nicht aufgefallen.

Allgemeiner Tipp: Strukturiere Dein Programm durch passende Einrückungen und setze die Klammern einheitlich. Das entlastet beim Lesen und ist bei der Fehlersuche Gold wert.

Soviel für jetzt, ich bin erstmal wieder AFK.

Gruß

Gregor
Wenn man keine Probleme hat, kann man sich welche machen („Großes Lötauge", Medizinmann der M3-Hopi)
Nicht lange fackeln, lass' Backen wackeln! (Seeed)

Serenifly

Wenn Du den Index 5 verwendest, erhältst Du eine Fehlermeldung („out of range" oder so, das hängt evtl. auch davon ab, ob Du lesen oder schreiben möchtest).
Das ist in C/C++ eben nicht der Fall. Arrays sind anderes als in manchen anderen Sprachen kein eigenständiger Datentyp. Eine Überprüfung auf Array Grenzen findet nicht statt

gregorss

Das ist in C/C++ eben nicht der Fall. Arrays sind anderes als in manchen anderen Sprachen kein eigenständiger Datentyp. Eine Überprüfung auf Array Grenzen findet nicht statt
Eieiei ... da bin ich mal wieder auf die Schnauze gefallen. Was soll's, C bzw. C++ ist wohl die zehnte Programmiersprache, mit der ich mich herumschlage.

Gruß

Gregor
Wenn man keine Probleme hat, kann man sich welche machen („Großes Lötauge", Medizinmann der M3-Hopi)
Nicht lange fackeln, lass' Backen wackeln! (Seeed)

combie

Quote
C++ ist eine Obermenge (quasi Erweiterung) von C. Du kannst also problemlos pures C programmieren.
Auch das ist falsch.
Es gibt genügend C Code, welcher sich nicht durch einen C++ Compiler jagen lässt.

Vor ca 30 Jahren haben sich die beiden Sprachen getrennt und sind seit dem, trotz aller Ähnlichkeit unterschiedliche Sprachen.

Und ja, Arduino mit seiner AVR Tool Chain, kann auch C Dateien kompilieren.
Aber dann sollte man sie auch *.c nennen, damit der C Compiler sie zu schlucken bekommt, und nicht der C++ Compiler.
Alles andere wäre schlampige Arbeit, und das wollen wir doch nicht, oder?


Quote
Combie sondert wieder einmal Müll ab.
Tja...
Wenn es dir damit besser geht, dann haue und steche...

Aber dann, ein Tipp:
Recherchiere besser, sonst blamierst du nicht mich, sondern nur dich selber.

Ein Frosch, der im Brunnen lebt, beurteilt das Ausmaß des Himmels nach dem Brunnenrand.

chubacca

Sorry,wollt hier keinen Streit auslösen.
Aber mein Gefühl sagt mir,ich habe charArray[4] weil keypad.getKey  char zurück gibt,UND dadurch  kann ich maximal 9999 eingeben.
Und so funktioniert mein Programm auch.Aber nur DAS wo ich keine Funktion versuche zu erstellen.
Also sieht es für mich nicht danach aus als müsste ich es begrenzen.

Aber ich werde mich auf jeden Fall an euren Tipps orientieren.(und vielleicht mal die c++ Bücher die hier rum liegen lesen).
Sonst vielleicht jemand eine Idee die mit meiner Funktion keyInput zu tun hat? Muss ich da vielleicht doch einen Parameter übergeben oder ein Denkfehler im Gültigkeitsbereich einer Variable?
Gruss


combie

#11
Sep 17, 2018, 07:51 pm Last Edit: Sep 17, 2018, 07:51 pm by combie
Quote
Sorry,wollt hier keinen Streit auslösen.
Da mache dir mal keine Sorgen drum...
Mit der Baustelle, hast du nichts zu tun.

Quote
Aber mein Gefühl sagt mir,
Programmieren basiert auf Logik.
Gefühle sind da oft hinderlich, ins besondere, wenn sie Wissen ersetzen.


4 mal '9' in einer Zeichenkette benötigt ein Array von der Größe 5
Dein Array ist zu klein.

Begründung:
Quote
Auch erwartet atoi() einen C- String, mit einem Null Byte als Begrenzer.
Ein Frosch, der im Brunnen lebt, beurteilt das Ausmaß des Himmels nach dem Brunnenrand.

wno158

#12
Sep 17, 2018, 07:55 pm Last Edit: Sep 17, 2018, 08:00 pm by wno158
Warum holst Du vor dem Aufruf von der Funktion schon einmal die Taste mit getKey ab?
Das macht doch die Funktion dann - und die könnte auch NO_KEY zurückgeben.
Also vor der Abfrage die Funktion aufrufen; nicht hinter der Abfrage.

Gruß Walter

Serenifly

#13
Sep 17, 2018, 08:05 pm Last Edit: Sep 17, 2018, 08:07 pm by Serenifly
Und so funktioniert mein Programm auch.Aber nur DAS wo ich keine Funktion versuche zu erstellen.
Also sieht es für mich nicht danach aus als müsste ich es begrenzen.
Es ist so oder so falsch. Egal wo es steht. Dass das manchmal funktioniert ist reiner Zufall. Und das meine ich wörtlich. Es hängt davon was in der Speicherzelle nach dem Array steht. Also wahrscheinlich von dem Wert von WertRPM

chubacca

Was ist jetzt falsch?das man es begrenzen muss oder keine Begrenzung notwendig?

Go Up