Hilfe bei Erstellung eines "einfachen" Codes

Guten Abend zusammen!
Ein Kommilitone und ich stehen vor einer (für uns) riesigen Herausforderung, da wir wirklich keinerlei Arduino Erfahrung haben.
Anbei ist unser Standard-code.
Wenn man ihn ausführt, wird einfach dauerhaft die Zahl 3235 auf der 4-7 Segment-Anzeige angezeigt und wir wollen, dass es erst dauerhaft angezeigt wird, wenn der (noch nicht vorhandene) Taster gedrückt wurde. Bei zweitem Tastendruck soll eine andere definierte Zahl angezeigt werden und beim dritten Tastendruck soll das Display ausgehen.
Das wars an sich schon. Hier nun der bisherige Code:

int Stelle;
int Segment;
int ErstesSegment=6;
int ErsteStelle=2;

int SegmenteJeZiffer[][8]={{1,1,1,1,1,1,0,0},
{0,1,1,0,0,0,0,0},{1,1,0,1,1,0,1,0},{1,1,1,1,0,0,1,0},
{0,1,1,0,0,1,1,0},{1,0,1,1,0,1,1,0},{1,0,1,1,1,1,1,0},
{1,1,1,0,0,0,0,0},{1,1,1,1,1,1,1,0},{1,1,1,1,0,1,1,0}};

void setup() {
  for(Stelle=0;Stelle<4;Stelle++) {
    pinMode(ErsteStelle+Stelle,OUTPUT);
    digitalWrite(ErsteStelle+Stelle,HIGH);
  }
  for(Segment=0;Segment<8;Segment++) {
    pinMode(ErstesSegment+Segment,OUTPUT);
    digitalWrite(ErstesSegment+Segment,LOW);
  }
}

void RichtigeSegmenteAnschalten(byte Ziffer){
  for(Segment=0;Segment<8;Segment++){
    if(SegmenteJeZiffer[Ziffer][Segment]==1){
      digitalWrite(ErstesSegment+Segment,HIGH);

    }
  }
}
 void AlleSegmenteAusschalten (){
  for (Segment=0;Segment<8;Segment++){
    digitalWrite(ErstesSegment+Segment,LOW);
  }
 }

void ZifferAusgabe(byte Stelle,byte Ziffer) {
  RichtigeSegmenteAnschalten(Ziffer);
  digitalWrite(ErsteStelle+Stelle,LOW);
  delay(2);
  digitalWrite(ErsteStelle+Stelle,HIGH);
  AlleSegmenteAusschalten();
}

void loop(){
  ZifferAusgabe(0,3);
  ZifferAusgabe(1,2);
  ZifferAusgabe(2,3);
  ZifferAusgabe(3,5);
  
}

Ich hab Deine Aufgabenstellung nicht ganz verstanden.
Willst Du mit einem Tastendruck die Digits durchzählen oder eine komplett neue Zahl generieren?

So wie ich das bisher gesehen habe, fehlt Dir dazu mindestens der button.
Aber dazu gehe mal in Deinen Ausgangspost und markiere Deinen Code und drücke dann auf die Schaltfläche <code>
Evetl. erklärst Du auch noch etwas genauer und peicherst dann nochmal ab.

1 Like

Hallo my_xy_projekt,

ich habe alles noch einmal geändert, wäre super wenn ich dazu Hilfe bekomme!

Gibst Du noch die zwei Zahlen vor, oder sollen die random ermittelt werden?

1 Like

Die erste Zahl ist die 3235 und die zweite ist die 2146

Vielleicht so:

#include <digitalWriteFast.h>
#include <Button_SL.hpp>

//
// Konstanten
//
constexpr uint8_t MAX_DIGITS {4};
constexpr uint8_t MAX_SEGMENTS {8};
constexpr uint32_t INTERVAL_MS {2000};

constexpr uint8_t decPlacePin[MAX_DIGITS] {A0, A1, A2, A3};
constexpr uint8_t digitPin[MAX_SEGMENTS] {4, 5, 6, 7, 8, 9, 10, 11};
constexpr uint8_t pinBtn {12};

constexpr uint8_t segmentBits[10] = {
    //  afbgcDde
    0b11101011,   // 0
    0b00101000,   // 1
    0b10110011,   // 2
    0b10111010,   // 3
    0b01111000,   // 4
    0b11011010,   // 5
    0b11011011,   // 6
    0b10101000,   // 7
    0b11111011,   // 8
    0b11111010,   // 9
};

//
// globale Variablen/Objkte
//
Btn::ButtonSL btn {pinBtn};

//
// Funktionen
//
void digitsOff() {
  // Clear Digits
  for (auto dPP : decPlacePin) { digitalWriteFast(dPP, HIGH); }
}

void digit(uint8_t nbr, uint8_t dpPin) {
  digitsOff();
  for (uint8_t i = 0; i < MAX_SEGMENTS; ++i) { digitalWriteFast(digitPin[i], ((segmentBits[nbr] >> i) & 0x01)); }
  digitalWriteFast(decPlacePin[dpPin], LOW);
}

void setDot(uint8_t pos) {
  if (pos > 0 && pos < MAX_DIGITS) {
    digitsOff();
    for (uint8_t i = 0; i < MAX_SEGMENTS; ++i) { digitalWriteFast(digitPin[i], ((0b00000100 >> i) & 0x01)); }
    digitalWriteFast(decPlacePin[pos], LOW);
  }
}

void numberToDisplay(uint8_t dgt[], uint8_t dot) {
  static uint8_t activeDigit {0};
  switch (activeDigit) {
    case 0: digit(dgt[0], 0);
    case 1: digit(dgt[1], 1);
    case 2: digit(dgt[2], 2);
    case 3: digit(dgt[3], 3);
    case 4: setDot(dot);
  }
  if (++activeDigit == (MAX_DIGITS + 1)) { activeDigit = 0; }
}

void breakNumberDown(uint8_t dgt[], uint16_t nbr) {
  dgt[3] = nbr / 1000;
  nbr %= 1000;
  dgt[2] = nbr / 100;
  nbr %= 100;
  dgt[1] = nbr / 10;
  nbr %= 10;
  dgt[0] = nbr;
}

//
// Hauptprogramm
//
void setup() {
  for (auto dP : digitPin) { pinMode(dP, OUTPUT); }
  for (auto dPP : decPlacePin) { pinMode(dPP, OUTPUT); }
  btn.begin();
  randomSeed(638462874);
}

void loop() {
  static uint8_t digits[MAX_DIGITS];
  static uint16_t dotPos;
  uint16_t number;

  if (btn.tick() == Btn::ButtonState::shortPressed) {
    number = random(1, 10000);
    dotPos = random(0, 4);
    breakNumberDown(digits, number);
  }
  numberToDisplay(digits, dotPos);
}
int Stelle;
int Segment;
const byte ErstesSegment = 6;
const byte ErsteStelle = 2;
const byte TastePin = A0;

const byte SegmenteJeZiffer[11] = {
  11111100,
  01100000,
  11011010,
  11110010,
  01100110,
  10110110,
  10111110,
  11100000,
  11111110,
  11110110,
  00000000 // leer
};

void setup() {
  for (Stelle = 0; Stelle < 4; Stelle++) {
    pinMode(ErsteStelle + Stelle, OUTPUT);
    digitalWrite(ErsteStelle + Stelle, HIGH);
  }
  pinMode(TastePin, INPUT_PULLUP);
}

void ZifferAusgabe(byte Pos, byte Ziffer) {
  for (Stelle = 0; Stelle < 4; Stelle++)digitalWrite(ErsteStelle + Stelle, HIGH);

  for (Segment = 0; Segment < 8; Segment++) {
    digitalWrite(ErstesSegment + Segment, SegmenteJeZiffer[Ziffer]&(1<<Segment) );
  }
  digitalWrite(ErsteStelle + Pos, LOW);
  delay(10);
}

void loop() {
  static byte Mode = 0;
  static uint32_t Time = millis();
  switch (Mode) {
    case 0:
      ZifferAusgabe(0, 10);
      ZifferAusgabe(1, 10);
      ZifferAusgabe(2, 10);
      ZifferAusgabe(3, 10);
      break;
    case 1:
      ZifferAusgabe(0, 3);
      ZifferAusgabe(1, 2);
      ZifferAusgabe(2, 3);
      ZifferAusgabe(3, 5);
      break;
    case 2:
      ZifferAusgabe(0, 2);
      ZifferAusgabe(1, 1);
      ZifferAusgabe(2, 4);
      ZifferAusgabe(3, 6);
      break;
  }
  if (millis() - Time > 150) {
    if (!digitalRead(TastePin)) {
      Mode = (++Mode) % 3;
      Time = millis();
    }
  }
}

Du möchtest also quasi 2 Dingen gleichzeitig machen:

  • Eine Anzeige auf dem Display
  • Auf Taster reagieren

Hier ist die anzuzeigende Zahl fest kodiert. Das würde ich erstmal rausziehen in ein Array.

byte displaydata[4];

void setup(){
displaydata[0] = 3;
...
}

void loop(){
ZifferAusgabe(0,displaydata[0]);
...
}

Danach ein Umbau auf non-blocking. Da kannst du dir auch das Beispiel "Blink without delay" anschauen.

void ZifferAusgabe(byte Stelle,byte Ziffer) {
  <Alle Stellen aus>
  <Setze Segmente für Stelle>
  <Stelle ein>
}

void updateDisplay(){
  <wenn 10 ms vergangen>{
    <wähle nächste Stelle>
    ZifferAusgabe(stelle, displaydata[stelle]);
  }
}

void loop(){
  updateDisplay();
}

Wenn das läuft, kümmern wir uns um die Tasterlogik.

Dann gebe ich jetzt mal meinen Ansatz zum Besten.
Ohne die vorherigen gesehen zu haben. (Ich bin immer lange Zeit offline...)
Mal sehen, ob ich es getroffen habe:

constexpr byte digitPin[] {2, 3, 4, 5};
constexpr byte maxDigit {sizeof(digitPin) / sizeof(digitPin[0])};

constexpr byte segmentPin[] {6, 7, 8, 9, 10, 11, 12,}; // seg: A, B, C, D, E, F, G,
constexpr byte maxSegment {sizeof(segmentPin) / sizeof(segmentPin[0])};

constexpr bool digitOn {HIGH};                 // Das ist die einzige Stelle die geändert werden könnte
constexpr bool segmentOn {!digitOn};

constexpr byte ziffer[][maxSegment] =
{
  {1, 1, 1, 1, 1, 1, 0, }, // 0
  {0, 1, 1, 0, 0, 0, 0, },
  {1, 1, 0, 1, 1, 0, 1, },
  {1, 1, 1, 1, 0, 0, 1, },
  {0, 1, 1, 0, 0, 1, 1, },
  {1, 0, 1, 1, 0, 1, 1, },
  {1, 0, 1, 1, 1, 1, 1, },
  {1, 1, 1, 0, 0, 0, 0, },
  {1, 1, 1, 1, 1, 1, 1, },
  {1, 1, 1, 1, 0, 1, 1, }, // 9
};

constexpr byte maxZahl {2};
constexpr byte ziffern[maxZahl][maxDigit] {{3, 2, 3, 5,}, {2, 1, 4, 6,}};

constexpr byte btnPin {A0};
constexpr uint32_t debounce {50};
bool isPress;
uint32_t lastPress;

byte auswahl;

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  // BTN-Init
  pinMode(btnPin, INPUT_PULLUP);
  // Digit-Init
  for (byte b = 0; b < maxDigit; b++)
  {
    pinMode(digitPin[b], OUTPUT);
    digitalWrite(digitPin[b], LOW);
  }
  // segment-Init
  for (byte b = 0; b < sizeof(segmentPin); b++)
  {
    pinMode(segmentPin[b], OUTPUT);
    digitalWrite(segmentPin[b], LOW);
  }
  // SegmentTest
  for (byte d = 0; d < maxDigit; d++)
  {
    digitalWrite(digitPin[d], digitOn);
    for (byte s = 0; s < maxSegment; s++)
    {
      digitalWrite(segmentPin[s], segmentOn);
      delay(150);
      digitalWrite(segmentPin[s], !segmentOn);
    }
    digitalWrite(digitPin[d], !digitOn);
  }
}
//
void loop()
{
  if (chkBtn())
  { auswahl++; }
  switch (auswahl)
  {
    case 0 ... maxZahl-1:
      for (byte b = 0; b < maxDigit; b++)
      { printDigit(b, ziffern[auswahl][b]); }
      break;
    default:
      for (byte b = 0; b < maxDigit; b++)
      { digitalWrite(digitPin[b], !digitOn); }
      if (auswahl > maxZahl)
      { auswahl = 0; }
      break;
  }
}
//
bool chkBtn()
{
  bool rtn = false;
  if (!digitalRead(btnPin))
  {
    if (isPress == false)
    {
      rtn = true;
      isPress = true;
      lastPress = millis();
    }
  }
  else if (millis() - lastPress > debounce)
  { isPress = false; }
  return rtn;
}
//
void printDigit(const byte digit, const byte zahl)
{
  digitalWrite(digitPin[digit], !digitOn);
  for (byte s = 0; s < maxSegment; s++)
  { digitalWrite(segmentPin[s], ziffer[zahl][s]); }
  digitalWrite(digitPin[digit], digitOn);
}

Hinweis 1:
Ich war mir nicht sicher, ob der DIGIT-Pin HIGH- oder LOW-aktiv ist.
Im setup laufen die Digits einmal alle durch. Sollte das nicht passieren, musst Du in an der Stelle, wo ich das kommentiert habe LOW anstelle von HIGH eintragen.

Hinweis 2:
Das Spielerchen im setup kannst auch ausklammern :wink:

Hinweis 3:
Das switch / case - Konstrukt ist Absicht. Es wäre auch ein if / else gegangen, würde dann aber endgültig sein. Sollte Dir irgendwas anderes einfallen, kannst Du anhand der auswahl weitere Funktionen unterbringen ohne den ganzen Code umschreiben zu müssen...

Ich danke euch allen einmal und probier es morgen gleich mal aus! Ich lasse von mir hören :slight_smile:

hat jemand schon erwähnt dass 7-Seg Display sollte man nicht direkt an Arduino anschließen? in meinem Sketch nutze ich interne Pullups, aber das ist immernoch nicht vernunftig

Klar kann man einen HT16K33 oder MAX7219 benutzen... aber bei einer gegebenen Aufgabe könnte das dann "Out of scope" sein.

Hmm... wie meinst du das mit den internen Pullups?

pinMode(segments, INPUT_PULLUP);

Erzähl mal bitte mehr.

Was soll das bringen?
Wo ist segments definiert?

#define segments 8
pinMode(segments, INPUT_PULLUP);

Ok. Damit bekommt Pin 8 einmalig den Typ INPUT_PULLUP zugewiesen und sobald Du auch nur einmal auf den Pin schreibst, passiert genau was?
Ich hab Deinen Code oben schon absichtlich nicht kommentiert, aber Du musst ganz dringend GRUNDLAGEN lernen!

(Würdest Du anstatt dieser #define Krücke richtige Definitionen benutzen, würdest Du hoffentlich selbst drauf kommen...)

funzt mein Sketch nicht?

wieso würde jemand auf ein Input schreiben wollen? ich nicht. du?

war für TO gezeigt.

Erklär mal bitte, was seǵment ist!
Dein Sketch enthält kein segment.

Oder hab ich was übersehen?

Und der Sketch setzt voraus, dass Du nur alle 150ms die Taste abfragst, aber wenn Du nicht schaffst früh genug los zu lassen...

Darüber hinaus hast Du den schnurz des TO übernommen und zählst die Pins mit magischen Zahlen....

wahr. so ne brutale Pin-Aufzählung, funzt aber.