Kann man Datentabellen/Matrizen für mehrere Datensätze anlegen?

Hallo,

ich habe gerade ganz frisch mit Arduino angefangen und plane gerade ein Projekt. Im Programm selbst müssen dabei mehrere Dinge verbunden werden.

Konkret sollen dabei zwei 7-Segment-Anzeigen mit einem Rotary-Encoder von 1-40 durchgekurbelt werden, gleichzeitig muss aber jeder Zahl auf dem Display ein bestimmter Binärcode an mehreren Output-Pins des Arduinos zugeordnet werden.

Die Zahlen für das 7-Segment-Dingens würde ich über 2 75HCT595 Schieberegister outshiften - das geht eigentlich auch ganz gut, wie ich festgestellt habe.

Nur frage ich mich jetzt gerade wie ich die Datentabellen am blödesten anlege:

Mit einem normalen Array kann ich ja nur zwei Werte speichern, einmal die Position und einmal den Wert. Gibt es irgendwie eine Tabellen-Matrizenfunktion? So dass ich meinetwegen dem Wert "Nummer 01" (auf der Anzeige) einmal den Wert für die 0 (Zehner-Anzeige) dann den Wert für die 1 (Einer-Anzeige) und dann den Binärcode für die Output-Pins zuweisen kann?
Oder kombiniere ich da am besten mehrere Array miteinander? Hat mir jemand einen Tip?

Wie gesagt, mein erstes Projekt. Mir fehlt gerade noch so ein wenig die Herangehensweise.

mach einfach 3 arravs;
Als Index den Wert des Rotary-Encoder.
Eine für die Einerstelle, eine für die Zehnerstelle und die dritte für die Ausgabe.
Grüße Uwe

Hallo Uwe,

hui, das ging ja schnell.

Ok, das klingt schon mal logisch. Kann ich denn dem Rotary Encoder einen Wert zuweisen? Ich dachte der zählt immer nur + oder - ?

Oder meinst du, dass man das so definieren kann, dass er nach dem einschalten z.B. den Wert x=1 zugewiesen bekommt, der sich dann durch das drehen hoch und runter verändert? Das wäre ja dann eigentlich einleuchtend.

Nach dem einschalten hat er einen festen Wert den du vor gibst.
Der Encoder macht nur + oder -
Den Wert kannst du dann beim drehen mit
encoder++
oder
encoder--
Zählen lassen.
Eventuell mit abfragen auf maximal und minimal Wert.
Diese Variable nutzt du dann für dein Array Index

Chimaera:
Ok, das klingt schon mal logisch. Kann ich denn dem Rotary Encoder einen Wert zuweisen? Ich dachte der zählt immer nur + oder - ?

Oder meinst du, dass man das so definieren kann, dass er nach dem einschalten z.B. den Wert x=1 zugewiesen bekommt, der sich dann durch das drehen hoch und runter verändert? Das wäre ja dann eigentlich einleuchtend.

Genau so.
Grüße Uwe.

Ok, dann sag ich mal vielen Dank und schau mal ob ich das wie gewollt hinbekomme :wink:

Hallo nochmal,

natürlich bekomme ich es nicht hin. :slight_smile:

Als Rotary Code verwende ich das unten angegebene Programm. Irgendwie scheitere ich aber schon daran mir aus diesem die Werte für den Encoder zu ziehen. Kann mir damit eventuell nochmals jemand helfen?

Das ganze versteckt sich ja wohl in

  if (result) {
    Serial.println(result == 0x40 ? "LEFT" : "RIGHT");

Aber wie überführe ich das ganze jetzt genau in eine auf- und absteigende Variable? Irgendwie doof wenn man den Code nicht so ganz kapiert.

Ich dachte ursprünglich ich könnte mir - zumindest nur zum Testen ob ich das Signal auch im Programm weiterverarbeiten kann, es an eine LED (genauer die LED an Pin 13) koppeln. So hatte sie ja zumindest schon mal permanent angehen sollen, wenn ich den Encoder in eine Richtung drehe.

Ich hatte dementsprechend alles definiert, aber eine Code-Zeile

if (result==0x40) 
digitalWrite (LED, HIGH)

erzeugte rein gar nichts.

Wo ist denn mein Knoten im Kopf?

/* Rotary encoder handler for arduino.
 *
 * Copyright 2011 Ben Buxton. Licenced under the GNU GPL Version 3.
 * Contact: bb@cactii.net
 *
 * Quick implementation of rotary encoder routine.
 *
 * More info: http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html
 *
 */

// Half-step mode?
#define HALF_STEP
// Arduino pins the encoder is attached to. Attach the center to ground.
#define ROTARY_PIN1 2
#define ROTARY_PIN2 3
// define to enable weak pullups.
#define ENABLE_PULLUPS


#ifdef HALF_STEP
// Use the half-step state table (emits a code at 00 and 11)
const char ttable[6][4] = {
  {0x3 , 0x2, 0x1,  0x0}, {0x83, 0x0, 0x1,  0x0},
  {0x43, 0x2, 0x0,  0x0}, {0x3 , 0x5, 0x4,  0x0},
  {0x3 , 0x3, 0x4, 0x40}, {0x3 , 0x5, 0x3, 0x80}
};
#else
// Use the full-step state table (emits a code at 00 only)
const char ttable[7][4] = {
  {0x0, 0x2, 0x4,  0x0}, {0x3, 0x0, 0x1, 0x40},
  {0x3, 0x2, 0x0,  0x0}, {0x3, 0x2, 0x1,  0x0},
  {0x6, 0x0, 0x4,  0x0}, {0x6, 0x5, 0x0, 0x80},
  {0x6, 0x5, 0x4,  0x0},
};
#endif
volatile char state = 0;

/* Call this once in setup(). */
void rotary_init() {
  pinMode(ROTARY_PIN1, INPUT);
  pinMode(ROTARY_PIN2, INPUT);
#ifdef ENABLE_PULLUPS
  digitalWrite(ROTARY_PIN1, HIGH);
  digitalWrite(ROTARY_PIN2, HIGH);
#endif
}

/* Read input pins and process for events. Call this either from a
 * loop or an interrupt (eg pin change or timer).
 *
 * Returns 0 on no event, otherwise 0x80 or 0x40 depending on the direction.
 */
char rotary_process() {
  char pinstate = (digitalRead(ROTARY_PIN2) << 1) | digitalRead(ROTARY_PIN1);
  state = ttable[state & 0xf][pinstate];
  return (state & 0xc0);
}

void setup() {
  Serial.begin(9600);
  rotary_init();
}

void loop() {
  char result = rotary_process();
  if (result) {
    Serial.println(result == 0x40 ? "LEFT" : "RIGHT");   
  }

}

OK, neuer Versuch.

Ich hab ne andere Rotary-Encoder-Bibliothek gefunden, die ich einbinden konnte.

Nur habe ich noch nen Fehler drin, finde ihn aber nicht. Ich bin leider noch nicht ganz so firm in der Struktur - wo habe ich welche Zeichen zu wenig oder zuviel?

Projekt.cpp: In function ‘void loop()’:
Projekt.cpp:38:10: error: expected ‘;’ before ‘}’ token
Projekt.cpp:41:12: error: expected ‘;’ before ‘}’ token
Projekt.cpp:44:11: error: expected ‘;’ before numeric constant
Projekt.cpp:47:13: error: expected ‘;’ before ‘}’ token

    if (clicks > 0 ) {
      x++};
      
      if (x=41) {
        x=1}
    
    if (clicks < 0) {
       x--1};
       
        if (x=0) {
        x=40};
    }
#include <PinChangeInt.h> // necessary otherwise we get undefined reference errors.
#include <AdaEncoder.h>

#define a_PINA 5
#define a_PINB 7

const int latch = 8;
const int data = 11;
const int clock = 12;

int kanaele_einer[] =  {6,91,79,102,109,125,7,127,103,63,6,91,79,102,109,125,7,127,103,63,6,91,79,102,109,125,7,127,103,63,6,91,79,102,109,125,7,127,103,63};
int kanaele_zehner[] = {63,63,63,63,63,63,63,63,63,6,6,6,6,6,6,6,6,6,6,91,91,91,91,91,91,91,91,91,91,79,79,79,79,79,79,79,79,79,79,102};
int x = 1;
int8_t clicks=0;
char id=0;

void setup()
{
  AdaEncoder::addEncoder('a', a_PINA, a_PINB);
  pinMode(clock, OUTPUT); // make the clock pin an output
  pinMode(data, OUTPUT); // make the data pin an output
  pinMode(latch, OUTPUT); // make the latch pin an output

}

void loop()
{
  encoder *thisEncoder;
  thisEncoder=AdaEncoder::genie(&clicks, &id);
  if (thisEncoder != NULL) {
    thisEncoder=AdaEncoder::getFirstEncoder();
    
    
    if (clicks > 0 ) {
      x++};
      
      if (x=41) {
        x=1}
    
    if (clicks < 0) {
       x--1};
       
        if (x=0) {
        x=40};
    }
       
   // Anzeigenausgabe   
      digitalWrite(latch, 0);
      shiftOut(data, clock, MSBFIRST, kanaele_einer[x]);
      shiftOut(data, clock, MSBFIRST, kanaele_zehner[x]);
      digitalWrite(latch, 1);
    
  
}

Projekt.cpp:38:10: error: expected ‘;’ before ‘}’ token

... zeigt dir in welcher Zeile und bei welchem Zeichen er meckert.

Die gültige Struktur ist im Grunde immer:

if(kondition)
{
anweisung;
anweisung;
}
 x--1

hier nehme ich an, du möchtest das gegenteil von x++ benutzen, also um 1 von x abziehen?
Das geht entweder so

x = x - 1;

oder so
x--;.

Bei if-Anweisungen wird geprüft ob eine Kondition Wahr oder Falsch ist.
if (x=41)
x=41 ist keine Kondition, sondern eine Anweisung. Die Anweisung wird korrekt ausgeführt, also ist die Kondition immer wahr.
x == 41 prüft, ob x den wert 41 hat.
Das doppelte == ist ein sogenannter Vergleichsoperator.

Das ganze wird dich jetzt sicher verwirren, aber nach ein paar C++ Tutorials (das Arduino verwendet eine vereinfachte Form der Programmiersprache C++) sollte mehr Klarheit bei dir herrschen.

Hallo kduin,

ich danke dir. Jetzt kompiliert er zumindest schonmal - wen das Programm auch noch ncht tut was ich will :wink:

Ich seh schon. Auch beim Proggen heisst es üben, üben und nochmals üben. Solange bis die Strukturen im Kopf sind. Das mit dem Vergleichen/Setzen = und == ist schon gemein. Theoretisch wusste ich es so gar. Aber dann praktisch sowas auch erkennen. hust

Also, das Programm verhält sich noch etwas komisch.
Einerseits prellt der Encoder, was aber nicht das Hauptproblem darstellt.

Die wirkliche Crux liegt in der Darstellung der Einer der 7-Segmentanzeige:

Irgendwas verträgt sich da nicht. Steure ich die Anzeige manuell ohne Encoder ganz normal mit einer For-Schleife an, funktioniert alles bestens und er zählt ohne zu Mucken von 01-40 durch.
Sobald die Dinger aber mit dem Encoder dran betrieben werden, leuchten bei der Einer-Anzeige alle 7-Segmente gleichzeitig, wenn auch mehr oder weniger intensiv. Man kann dann zwar beim Drehen erkennen, das es Veränderungen gibt, aber leider nicht so genau welche. Von der Anzahl der Schritte her passt es eigentlich, nach 10 Schritten geht die Zehneranzeige eine Stufe nach oben.

Hat irgendjemand eine Idee?

Hi,

bitte poste mal deinen akutellen Code.

Ich hab das Problem mittlerweile gefunden. Es lag daran, dass das 7-Segment ständig überschrieben wurde. Eine richtige Klammer später, wurde der Output nur noch dann geschrieben, wenn es eine Veränderung in der Indexzahl gab. Dann war es aber ok.

Der nun funktionierende Code lautet:

#include <PinChangeInt.h> // necessary otherwise we get undefined reference errors.
#include <AdaEncoder.h>

#define a_PINA 2
#define a_PINB 3

const int latch = 8;
const int data = 11;
const int clock = 12;

int kanaele_einer[] =  {6,91,79,102,109,125,7,127,103,63,6,91,79,102,109,125,7,127,103,63,6,91,79,102,109,125,7,127,103,63,6,91,79,102,109,125,7,127,103,63}; // right segment, one-spot? 
int kanaele_zehner[] = {63,63,63,63,63,63,63,63,63,6,6,6,6,6,6,6,6,6,6,91,91,91,91,91,91,91,91,91,91,79,79,79,79,79,79,79,79,79,79,102}; // left segment, ten-spot?
int x = 0;
int8_t clicks=0;
char id=0;

void setup()
{
  AdaEncoder::addEncoder('a', a_PINA, a_PINB);
  pinMode(clock, OUTPUT); // make the clock pin an output
  pinMode(data, OUTPUT); // make the data pin an output
  pinMode(latch, OUTPUT); // make the latch pin an output
  Serial.begin(115200);
  
  digitalWrite(latch, 0);
  shiftOut(data, clock, MSBFIRST, kanaele_einer[x]);
  Serial.println(kanaele_einer[x]);
  shiftOut(data, clock, MSBFIRST, kanaele_zehner[x]);
  Serial.println(kanaele_zehner[x]);
  digitalWrite(latch, 1);

}

void loop()
{
  

  encoder *thisEncoder;
  thisEncoder=AdaEncoder::genie(&clicks, &id);
  if (thisEncoder != NULL) {
    thisEncoder=AdaEncoder::getFirstEncoder();
    
    
    if (clicks > 0 ) {
      x++;};
      
      if (x==40) {
        x=0;};
    
    if (clicks < 0) {
       x--;};
       
        if (x==-1) {
        x=39;};
    
       
   // Anzeigenausgabe   
      digitalWrite(latch, 0);
      shiftOut(data, clock, MSBFIRST, kanaele_einer[x]);
      Serial.println(kanaele_einer[x]);
      shiftOut(data, clock, MSBFIRST, kanaele_zehner[x]);
      Serial.println(kanaele_zehner[x]);
      digitalWrite(latch, 1);
   } 
  
}

Leider muss ich sagen, bounct das Ding noch gewaltig. Ich würde eigentlich gerne den Rotary Code von Buxter verwenden, bekomme ihn aber nicht richtig konfiguriert.

/* Rotary encoder handler for arduino.
 *
 * Copyright 2011 Ben Buxton. Licenced under the GNU GPL Version 3.
 * Contact: bb@cactii.net
 *
 * Quick implementation of rotary encoder routine.
 *
 * More info: http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html
 *
 */

// Half-step mode?
#define HALF_STEP
// Arduino pins the encoder is attached to. Attach the center to ground.
#define ROTARY_PIN1 2
#define ROTARY_PIN2 3
// define to enable weak pullups.
#define ENABLE_PULLUPS


#ifdef HALF_STEP
// Use the half-step state table (emits a code at 00 and 11)
const char ttable[6][4] = {
  {0x3 , 0x2, 0x1,  0x0}, {0x83, 0x0, 0x1,  0x0},
  {0x43, 0x2, 0x0,  0x0}, {0x3 , 0x5, 0x4,  0x0},
  {0x3 , 0x3, 0x4, 0x40}, {0x3 , 0x5, 0x3, 0x80}
};
#else
// Use the full-step state table (emits a code at 00 only)
const char ttable[7][4] = {
  {0x0, 0x2, 0x4,  0x0}, {0x3, 0x0, 0x1, 0x40},
  {0x3, 0x2, 0x0,  0x0}, {0x3, 0x2, 0x1,  0x0},
  {0x6, 0x0, 0x4,  0x0}, {0x6, 0x5, 0x0, 0x80},
  {0x6, 0x5, 0x4,  0x0},
};
#endif
volatile char state = 0;

/* Call this once in setup(). */
void rotary_init() {
  pinMode(ROTARY_PIN1, INPUT);
  pinMode(ROTARY_PIN2, INPUT);
#ifdef ENABLE_PULLUPS
  digitalWrite(ROTARY_PIN1, HIGH);
  digitalWrite(ROTARY_PIN2, HIGH);
#endif
}

/* Read input pins and process for events. Call this either from a
 * loop or an interrupt (eg pin change or timer).
 *
 * Returns 0 on no event, otherwise 0x80 or 0x40 depending on the direction.
 */
char rotary_process() {
  char pinstate = (digitalRead(ROTARY_PIN2) << 1) | digitalRead(ROTARY_PIN1);
  state = ttable[state & 0xf][pinstate];
  return (state & 0xc0);
}

void setup() {
  Serial.begin(9600);
  rotary_init();
}

void loop() {
  char result = rotary_process();
  if (result) {
    Serial.println(result == 0x40 ? "LEFT" : "RIGHT");   
  }

}

Ich muss dann ja das Ergebnis von result also aus diesem Block Serial.println(result == 0x40 ? "LEFT" : "RIGHT");  in eine Variable überführen. Mit if result == 0x40 geht das ja noch, dann gab ich eine Drehrichtung. Aber die andere bekomme ich irgendwie nicht hin.

So, der Rotary Encoder funzt jetzt auch anstandslos. Habe das ganze hinbekommen.

Nächster Schritt, die Binär-Ausgabe.

Wie mache ich das denn am Schlechtesten. Klar, ich könnte das auch wieder über eine Schieberegister zuweisen :wink: Aber eigentlich habe ich ja die Ports. Gibt es eine einfache Variante um die Ports zusammenzufassen?

Wenn ich jedem der 40 Kanäle je einen Block
if (x == 0) {
digitalWrite (Port1, HIGH);
digitalWrite (Port2, LOW);
....
digitalWrite (Port7, HIGH)};
zuweise, benötige ich ja Code ohne Ende - zudem wird es schnell unübersichtlich.

Ich habe zwar gelesen, dass es auch eine Code-Variante gibt, mit der man alle Ports gleichzeitig setzen kann, da stand aber dabei, dass man diese besser nicht nutzen soll, wenn es sich vermeiden läßt.

Ich würde ja gerne eine Subfunktion nutzen, habe aber keine Ahnung, ob das so geht wie ich es mir vorstelle:

Also, dass man jedem x am Anfang wieder per Array einen Code zuweist (10101111) und diesen dann von mehreren digitalWrite ausführen lässt. Das Problem ist also: Geht es, dass ich jedem digitalWrite eine andere Dezimalstelle in diesem Code zuweise?
Also, dass der erste mit Port1 die erste Stelle, der zweite Mit Port2 die zweite Stelle .... ausführt?

Also das Ganze schreit geradezu nach einer Funktion.

void loop() {
...
    byte binvalue = B10010;
    binout(binvalue);
...
}

void binout(byte value) {
    digitalWrite(PORT0,bitRead(value,0);
    digitalWrite(PORT1,bitRead(value,1);
    digitalWrite(PORT2,bitRead(value,2);
    digitalWrite(PORT3,bitRead(value,3);
    digitalWrite(PORT4,bitRead(value,4);
    digitalWrite(PORT5,bitRead(value,5);
    digitalWrite(PORT6,bitRead(value,6);
    digitalWrite(PORT7,bitRead(value,7);
}

Wenn Du die Werte für PORT0 bis PORT7 (#define für die IO-Ports) in ein Array packst, kannst Du das auch in einer Schleife noch kürzer machen.
Der Trick ist eigentlich, das Du nicht ein "if(x==wert)" für alle Binärwerte die Du ausgeben willst programmierst, sondern eine Funktion hast, der Du einfach einen beliebigen Wert übergibst und die dann die Ausgabe ganz allgemein löst. Somit kannst Du später auch mehr als 40 Werte ausgeben, ohne die Funktion nochmal anfassen zu müssen.

Vielen Dank. Ich habe das gerade jetzt mal umgesetzt und es funktioniert so, wie es soll.

Ich bekomme es allerdings irgendwie nicht hin, dass ich eine Array direkt an eine Funktion übergeben kann. Momentan löse ich das so, dass ich zuerst eine Hilfsvariable deklariere, dieser dann den aktuellen Wert aus dem Array übergebe und danach die Hilfsvariable an die Funktion übergebe.

// Kanal-Code für Binär-Ausgabe

byte bincode [] = { B000000,B000001,B000010,B000100,B000101,  B000110,B000111,B001001,B001010,B001011, B001100,B001110,B001111,B010000,B010001, B010011,B010100,B010101,B010110,B011000,
                    B011001,B011010,B011101,B011011,B011100,  B011110,B011111,B100000,B100001,B100010, B100011,B100100,B100101,B100110,B100111, B101000,B101001,B101010,B101011,B101100};
//Startkanal
int x = 0;
byte aktuellKanal= B000000;
void binausgabe (byte ak) {
  digitalWrite (APort0, bitRead(ak,0));
  digitalWrite (APort1, bitRead(ak,1));
  digitalWrite (APort2, bitRead(ak,2));
  digitalWrite (APort3, bitRead(ak,3));
  digitalWrite (APort4, bitRead(ak,4));
  digitalWrite (APort5, bitRead(ak,5));
}


void loop() {

}
 [.........]
       

   // Anzeigenausgabe   
      digitalWrite(latch, 0);
      shiftOut(data, clock, MSBFIRST, kanaele_einer[x]);
      Serial.println(kanaele_einer[x]);
      shiftOut(data, clock, MSBFIRST, kanaele_zehner[x]);
      Serial.println(kanaele_zehner[x]);
      digitalWrite(latch, 1);  
      
    //Binausgabe  
      byte aktuellKanal= bincode[x];
      binausgabe (aktuellKanal);                       
               }

Beherrsche ich die Syntax nicht richtig oder warum funktioniert "binausgabe (bincode[x]);" nicht?

Und noch eine weitere Frage: Ist es eigentlich möglich an den Pins nicht nur HIGH oder LOW sondern auch sowas wie "mach nix" bzw "spiel mit den teilnahmslosen Isolator" zu schalten?

Und zwar geht es darum, dass ich eben bemerkt habe, dass ich im Endeffekt meine PLL an den Pins nur nach Ground ziehen muss und eigentlich keine Spannung draufgeben darf. So hab ich es jetzt zumindest verstanden. Gibts da ne Möglichkeit? Oder gibt es da dann nur die Hardware-Lösung mit vorgeschalteten Dioden?