Pages: [1] 2   Go Down
Author Topic: Kann man Datentabellen/Matrizen für mehrere Datensätze anlegen?  (Read 1345 times)
0 Members and 1 Guest are viewing this topic.
Tübingen, BW, Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Logged

Forum Moderator
BZ (I)
Offline Offline
Brattain Member
*****
Karma: 252
Posts: 21283
+39 349 2158303
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Tübingen, BW, Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

NRW
Offline Offline
Sr. Member
****
Karma: 2
Posts: 372
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Forum Moderator
BZ (I)
Offline Offline
Brattain Member
*****
Karma: 252
Posts: 21283
+39 349 2158303
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Tübingen, BW, Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, dann sag ich mal vielen Dank und schau mal ob ich das wie gewollt hinbekomme ;-)
Logged

Tübingen, BW, Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo nochmal,

natürlich bekomme ich es nicht hin.  smiley-kitty

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
Code:
  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

Code:
if (result==0x40)
digitalWrite (LED, HIGH)
erzeugte rein gar nichts.

Wo ist denn mein Knoten im Kopf?

Code:
/* 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");   
  }

}
Logged

Tübingen, BW, Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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


Code:
 
    if (clicks > 0 ) {
      x++};
     
      if (x=41) {
        x=1}
   
    if (clicks < 0) {
       x--1};
       
        if (x=0) {
        x=40};
    }


Code:
#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);
   
 
}
Logged

Offline Offline
Sr. Member
****
Karma: 2
Posts: 260
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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:
Code:
if(kondition)
{
anweisung;
anweisung;
}

Code:
x--1
hier nehme ich an, du möchtest das gegenteil von x++ benutzen, also um 1 von x abziehen?
Das geht entweder so
Code:
x = x - 1;
oder so
Code:
x--;
.

Bei if-Anweisungen wird geprüft ob eine Kondition Wahr oder Falsch ist.
Code:
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.
« Last Edit: March 05, 2012, 02:30:39 pm by kduin » Logged

Tübingen, BW, Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo kduin,

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

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*
Logged

Tübingen, BW, Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?

Logged

Offline Offline
Sr. Member
****
Karma: 2
Posts: 260
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

bitte poste mal deinen akutellen Code.
Logged

Tübingen, BW, Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
Code:
#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.

Code:
/* 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
Code:
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.
Logged

Tübingen, BW, Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 ;-) 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?
                    
    
« Last Edit: March 10, 2012, 02:31:42 pm by Chimaera » Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Also das Ganze schreit geradezu nach einer Funktion.
Code:
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.
Logged

Pages: [1] 2   Go Up
Jump to: