Arduino Forum

International => Deutsch => Topic started by: chubacca on Sep 17, 2018, 12:44 pm

Title: Funktion erstellen
Post by: chubacca on Sep 17, 2018, 12:44 pm
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
Title: Re: Funktion erstellen
Post by: combie on Sep 17, 2018, 01:14 pm
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.
Title: Re: Funktion erstellen
Post by: chubacca on Sep 17, 2018, 03:27 pm
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
Title: Re: Funktion erstellen
Post by: combie on Sep 17, 2018, 03:45 pm
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?
Title: Re: Funktion erstellen
Post by: chubacca on Sep 17, 2018, 04:34 pm
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
Title: Re: Funktion erstellen
Post by: combie on Sep 17, 2018, 05:40 pm
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.


Title: Re: Funktion erstellen
Post by: gregorss on Sep 17, 2018, 06:42 pm
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
Title: Re: Funktion erstellen
Post by: Serenifly on Sep 17, 2018, 06:49 pm
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
Title: Re: Funktion erstellen
Post by: gregorss on Sep 17, 2018, 06:58 pm
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
Title: Re: Funktion erstellen
Post by: combie on Sep 17, 2018, 07:20 pm
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.

Title: Re: Funktion erstellen
Post by: chubacca on Sep 17, 2018, 07:38 pm
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

Title: Re: Funktion erstellen
Post by: combie on Sep 17, 2018, 07:51 pm
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.
Title: Re: Funktion erstellen
Post by: wno158 on Sep 17, 2018, 07:55 pm
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
Title: Re: Funktion erstellen
Post by: Serenifly on Sep 17, 2018, 08:05 pm
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
Title: Re: Funktion erstellen
Post by: chubacca on Sep 17, 2018, 08:09 pm
Was ist jetzt falsch?das man es begrenzen muss oder keine Begrenzung notwendig?
Title: Re: Funktion erstellen
Post by: Serenifly on Sep 17, 2018, 08:18 pm
Es ist falsch egal wo es steht. Ob Funktion oder nicht spielt keine Rolle
Erstens musst du schon beim Tastendrücken aufpassen dass du nicht über die Array-Grenze schreibst. Zweitens erwartet atoi() ein Null-terminiertes char Array
Title: Re: Funktion erstellen
Post by: combie on Sep 17, 2018, 08:29 pm
Arrays sind anderes als in manchen anderen Sprachen kein eigenständiger Datentyp.
Deine Aussage hat mich gerade stutzig gemacht.

Immerhin:
C++ trägt sehr wohl die Größe eines Arrays mit sich rum.


Das kann man auch schön nutzen, um Bereichsüberschreitungen zu vermeiden.
Man muss es allerdings zufuß machen. Automatisch erkannt werden Bereichsüberschreitungen nur bei der Initialisierung.

Ein echter Fortschritt, gegenüber C.



Testprogramm:
Code: [Select]


using EinEigenerType = char[5];


char testA[] = "9999";
char testB[5] = "9";
EinEigenerType testC = "9";
EinEigenerType testD = "999999"; // hier wirft der Compiler eine Warnung


void setup()
{
  Serial.begin(9600);     
  Serial.println("Start");
  Serial.println(sizeof(testA));
  Serial.println(sizeof(testB));
  Serial.println(sizeof(testC));
  Serial.println(sizeof(testD));
}

void loop()
{
   
}


Title: Re: Funktion erstellen
Post by: postmaster-ino on Sep 17, 2018, 08:35 pm
Hi

So oder so verhindert der Kompiler (zumindest hier beim Arduino) aber nicht, daß man auf das x-te Element des Array zugreift, egal, wie hoch X ist, egal ob lesend, oder schreibend.
Wie's bei einem Speicherüberlauf aussieht - kA (also wohin testA[15000] dann schaut) und oder ob die Größe des Index reglementiert ist wobei uint16_t schon recht weit hinter die Speichergrenze reichen wird.

MfG
Title: Re: Funktion erstellen
Post by: combie on Sep 17, 2018, 10:02 pm
So oder so verhindert der Kompiler (zumindest hier beim Arduino) aber nicht, daß man auf das x-te Element des Array zugreift, egal, wie hoch X ist, egal ob lesend, oder schreibend.
Da hast du Wahr!

Und das hat auch seinen Grund!

Würde C++ diese Laufzeitprüfungen machen, dann wären die erzeugten Kompilate erheblich größer, und langsamer. Das würde der "Maschinennähe" gar nicht gut tun.
Es sind ja nicht nur die Arrays, sondern eher die Zeiger, welche in die Wiese zeigen(können)
Und auf Zeiger will man nicht verzichten.

Ein C/C++ Programmierer ist halt nicht auf Rosen gebetet, ihm wird nicht bei jeder Gelegenheit der Hintern abgeputzt.
Er ist selber verantwortlich, für das, was er/sie/es tut.

:smiley-twist:  Eine gute Gelegenheit, etwas Verantwortung, Disziplin und Sorgfalt zu lernen. :smiley-twist:


Hier mal ein Progrämmchen, welches die Äquivalenz von Zeigern und Arrays vorführt:
(und ja, der Code ist Standardkonform)
Code: [Select]


unsigned long test[] {30,40,50};


void setup()
{
  Serial.begin(9600);     
  Serial.println("Start");

  int i = 1;
  Serial.println( test[i] );
  Serial.println( i[test] );
  Serial.println( 1[test] );
  Serial.println( *(test+i) );
  Serial.println( *(1+test) );
}

void loop()
{

}
Title: Re: Funktion erstellen
Post by: postmaster-ino on Sep 17, 2018, 10:21 pm
Hi

... kommt mir bekannt vor ... in Assembler hat man nicht Mal Das :o
(und auch, wenn ich Assembler schon irgendwie geil finde, hat man's in C++ doch erheblich einfacher)

MfG
Title: Re: Funktion erstellen
Post by: gregorss on Sep 18, 2018, 12:03 am
... und auch, wenn ich Assembler schon irgendwie geil finde, hat man's in C++ doch erheblich einfacher ...
Nicht ohne Grund ist C/C++ so beliebt: Es ermöglicht eine sehr maschinennahe Programmierung, bei der einem viel Assembler-Gehampel abgenommen wird.

Gruß

Gregor