7-Segment Library - ShiftDisplay-3 flakernde 7Seg, 1 "scheint" statisch

Hallo zusammen,
habe nun mal wieder ein kleines Problem. Ich denke ich bin zu doof die Library korrekt zu benutzen, aber mal sehen was Ihr meint. Ich nutze dabei eine 4stellige 7Segment Anzeige. Common Anode mit 220Ohm Widerständen bei a-bis-g. Wie halt im Schemtic Beispiel zur Library.

Ich nutze die ShiftDisplay Library GitHub

Habe eigentlich alle Arbeitsschritte in separate Funktionen gebetten. So ist es imho am übersichtlichsten. Das fitzelchen Code in der loop-Schleife sollte nun eigentlich die Solltemperatur plus ein “S” für Solltemperatur anzeigen. Deswegen das “+5000” beim Wert, so steht einfach im 1ten der 4 Digits ein “S”.

Das Problem ist nun folgendes. Die Zahl z.B. 5395 wird angezeigt, jedoch flakern Digit 1,2,3 im gleichtakt mit ca. 4mal An/Aus pro Sekunde. Und der 4te flakert nur sehr sehr leicht auf.
Das ganze ändert sich nicht wenn ich ALLES andere im Code auskommentiere und die Zahl manuell eintrage. Genau das gleich, somit bremst mein Code nicht das “multiplexing” des Displays.

Wisst ihr was ich da falsch gemacht habe? Danke schobmal

Der ganze Code soll sich mal um meinen Lötkolben kümmer, hier zu Ende nun noch meinen Code.

#include <PID_v1.h>
#include <ShiftDisplay.h>
//ACPhaseControl;
#include <avr/io.h>
#include <avr/interrupt.h>

//Pins am NANO mit notwendiger Funktion festlegen;
#define LoadIndicator 5             //OC0B;

#define IstwertThermoelement A6     //ADC6;
#define SollwertPoti A7             //ADC7:

#define zeroCross 3                 //INT1;
#define MOCZuendung 9               //OC1A;   
          
#define SRData 4
#define SRLatch 8
#define SRClock 7

//Konstanten zur Thermoelement Berechnung;
const int thAmplification = 166;              //Verstärkung Thermoelement Messverstärker 6k/1M=166,667
const float thmVperDigitTypeJ = 0.054423333;  //Temperaturkonstante - °C/mV
const int thCalibrationOffset = 0;                  //0°C-100°C Kalibrierung/Abgleichsfaktor

//15VAC 0,8A Steckernetzteil; Risetime 340µs,Falltime 340µs, pos-Width 940µs, neg-Width 9080µs => max. Peridode= 10,04ms;
//eine Halbwelle a 100Hz(50Hz AC grid) signal is 16Mhz/Prescaler(256)=62500 => 1count des Timers = 16µs; eine Halbwelle 10ms = 625counts;
//delayZeit die zum Zünden verstreicht, max. delay-Schleifenlänge 603counts = 9648µs;
const int delayMAX = 603;
//Sicherheitsspalt Falltime 340µs = 22counts; 10ms = 625counts sind max. Periodendauer; ==> Gesamtschleife =603+22=625counts =>10ms;
const int delayMIN = 22;

//globale Variablen für delayMicroseconds Ersatzfunktion;
volatile unsigned long triacONdelay = 0;
const byte ZuendflankeON = 4;       // Zündimpulsdauer: 4counts des Timers ist der Triac-Ausgang HIGH => 64µs (16µs each count);
volatile unsigned long zeroCrossCounter = 0;
int i = 0; //Zündpunkt - triacONdelay Ersatzvariable für Phasenschnitt-Testansteuerung;

int PIDOutputINT = 0;
int StellgroesseINT = 0;

//PID globale Übergabevariablen für PID Aufruf in der Interrrupt-Schleife;
double PIDthTempJformel = 0;        //Übergabe in loop-Schleife aus IST-Wert Thermoelement-Messung;
double PIDOutput = 0;
double PIDtemperaturSoll = 0;       //Übergabe in loop-Schleife aus SOLL-Wert Poti-Abfrage;
//Regelparameter PID;
double PIDKp = 2.0;
double PIDKi = 8.0;
double PIDKd = 0.1;
//PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, POn (P_ON_E (error) or P_ON_M(measurement)), Direction);
//PID myPID(Lötkolben-IST-Temperatur, "PWM 0-255" PID-Regelgröße, Poti-Sollwert, Kp, Ki, Kd, POn (P_ON_E (error) or P_ON_M(measurement)), Direction);
PID myPID(&PIDthTempJformel, &PIDOutput, &PIDtemperaturSoll, PIDKp, PIDKi, PIDKd, P_ON_E, DIRECT);

//7Segment Anzeige;
unsigned long millisPreviousDisplay = 0;
const long millisIntervalDisplay = 2500; // refresh Rate Display
double oldPIDtemperaturSoll = 0;

const DisplayType DISPLAY_TYPE = COMMON_ANODE; // COMMON_CATHODE or COMMON_ANODE
const int DISPLAY_SIZE = 4; // number of digits on display
ShiftDisplay display(SRLatch, SRClock, SRData, DISPLAY_TYPE, DISPLAY_SIZE);


void setup() {
  Serial.begin(115200);

  //PID-Regler initialisieren;
  myPID.SetMode(AUTOMATIC);                                       //Aktivierung PID-Regelung;
  pinMode(LoadIndicator, OUTPUT);

  //7-SegmentConfig;
  pinMode(SRData, OUTPUT);
  pinMode(SRLatch, OUTPUT);
  pinMode(SRClock, OUTPUT);


  //Eingänge konfigurieren;
  analogReference(DEFAULT);
  pinMode(IstwertThermoelement, INPUT);
  pinMode(SollwertPoti, INPUT);

  //Interrupt für Nulldurchgangserkennen;
  pinMode(zeroCross, INPUT);
  attachInterrupt(digitalPinToInterrupt(zeroCross), zeroCrossDetected, RISING);
  pinMode(MOCZuendung, OUTPUT);

  //Timer1 Configuration: ref.page 134-ATMEGA328;
  OCR1A = 100;      //initialize the comparator
  TIMSK1 = 0x03;    //enable comparator A and overflow interrupts
  TCCR1A = 0x00;    //timer control registers set for
  TCCR1B = 0x00;    //normal operation, timer disabled

  //Anschlusserkennung Lötkolben/Fehlerausgabe - notConnected;
  /*
    if(21 <= analogRead(IstwertThermoelement) <= 58){         //Thermoelement Temp 10-30°C => angeschlossen und i.O.;
      lcd.print("Lötkolben   i.O.");
    }
    else{
      lcd.print("Check CON  ERROR");
    }
  */

}

//ermittle Solltemperatur;
double getSolltemperatur() {
  //Sollwert Messung Potentiometer + Mittelwertbildung;
  int interationMW = 1000;
  unsigned long potiSolladd = 0;
  for (int count = 0; count < interationMW; count++) {
    int potiSollMomentan = analogRead(SollwertPoti);
    potiSolladd = potiSolladd + potiSollMomentan;
  }
  potiSolladd = potiSolladd / interationMW;
  potiSolladd = map(potiSolladd, 0, 1023, 0, 60);
  //Staffelung des Potis in 5°C Schritte:
  potiSolladd = (potiSolladd * 5) + 150;
  //übertragen in PID-Regelparameter;
  PIDtemperaturSoll = double(potiSolladd);
  return PIDtemperaturSoll;  
}

//ermittle Isttemperatur;
double getIsttemperatur() {
  // Erstellen des ADC-Mittelwerts zur Anzeige-Temperatur-Stabilisierung;
  long interationMW = 1000;
  unsigned long thAmpMWadd = 0;
  for (int count = 0; count < interationMW; count++) {
    int thAmpMomentan = analogRead(IstwertThermoelement);
    thAmpMWadd = thAmpMWadd + thAmpMomentan;
  }
  thAmpMWadd = thAmpMWadd / interationMW;
  double thTempJformel = ((((thAmpMWadd * (5.0 / 1023.0)) / thAmplification) * 1000) / thmVperDigitTypeJ) + thCalibrationOffset;
  //übertragen in PID-Regelparameter;
  PIDthTempJformel = thTempJformel;
  return PIDthTempJformel;
}

//Serielle Werteausgabe;
void callSerialPrint() {
}

//PID- und Triac Ansteuerung;
void computePIDtriac() {
  //Regelstrecke;
  myPID.Compute();
  //Anzeige auf LastIndicatorLED;
  PIDOutputINT = int(PIDOutput);
  analogWrite(LoadIndicator, PIDOutputINT);

  //mappen des PIDOutput auf den Invertierten Zündimpuls der Phasenanschnitts-Steuerung;
  triacONdelay = map(PIDOutput, 0, 255, delayMAX, delayMIN);
  
  //Stellgrößenhilfswerte anstatt triacONdelay verwenden für Testzwecke;
  StellgroesseINT = analogRead(SollwertPoti);
  i = map(StellgroesseINT, 0, 1023, delayMAX, delayMIN);
  //i ins Timerregister schreiben, ist Ersatzvariable für triacONdelay wenn im Regelbetrieb i=triacONdelay;
  OCR1A = i;  
}

void loop() {
  
  getSolltemperatur();
  getIsttemperatur();  
  computePIDtriac();   
  callSerialPrint();

  Ausgabe7Segment(); 


  if(oldPIDtemperaturSoll != PIDtemperaturSoll) {
  display.set(PIDtemperaturSoll + 5000, 0, false, ALIGN_RIGHT);        
  }
  oldPIDtemperaturSoll = PIDtemperaturSoll;
  display.update();
}

//Anzeige der Übergabewerte auf 7Segment Anzeige;
void Ausgabe7Segment() {

}



//Interrupt-Funktion an INT0 mit Optokoppler-Doppel-Nulldurchgangserkennung, Signal alle 50Hz => 10-ms peak-peak --- RISING Signal HIGH if 0-Cross;
void zeroCrossDetected() {
  TCCR1B = 0x04;                    //start timer with divide by 256 input
  TCNT1 = 0;                        //reset timer - count from zero
  zeroCrossCounter++;
}

//Timer1 erreichen Schwellenpunkt und Triac zünden;
ISR(TIMER1_COMPA_vect) {           //comparator match
  digitalWrite(MOCZuendung, HIGH); //set TRIAC gate to high
  TCNT1 = 65536 - ZuendflankeON;     //trigger pulse width
}

//gemessene 64µs Zündflanke = 4counts;
//Timer1 Überlauf - Triac Freigabe löschen;
ISR(TIMER1_OVF_vect) {             //timer1 overflow
  digitalWrite(MOCZuendung, LOW);  //turn off TRIAC gate
  TCCR1B = 0x00;                   //disable timer stopd unintended triggers
}

Wenn ich das Beispiel aus der Library "SerialMonitor" verwende, werden alle 4Digits mit gleicher Helligkeit ohne flakern angezeigt.

Beim oben beschriebenen Fall sind die ersten 3 Digit nur so ca. 1/3 so hell wie das voll erleuchtete 4te Digit.

(kein Edit weil die 9k-Zeichen zuende waren, sorry)

Der Autor ist inkompetent auf Elektronik bezogen. Die Bibliothek hab ich mir nicht angesehen und kann über seine Programmierkenntnisse nichts sagen.

Ein Segment (nehmen wir den schlimmsten Fall mit roten Segmenten) bei 5V bekommt 15mA. Wenn man eine 8 darstellt dann sind das zusammen 108mA; mit den Dezimalpunkt dazu 123mA.

Der SN74HC595 von Texas Instrument kann pro Ausgang 35mA bringen. Der Strom der Spannungsversorgung/Masse darf max 70mA sein. Da sind wir uaußerhalb der spezifikation mit der vorgeschlagenen Schaltung. Das IC von anderen Herstellern wird ca die gleichen Maximalwerte haben.

Der TPIC6B595 verträgt bis zu 150mA pro Ausgang, Die Schaltung funktioniert mit 2 TPIC6B595 aber nicht da die Ausgänge open Drain sind und darum den Ausgang nur auf Masse schalten können. Sie konnen die Anoden nicht mit Spannung versorgen also bleibt das display dunkel.

Lösungen:

  • größere Widerstände an den Display, mindestens 560 Ohm und
  • Zusätzliche Transistoren oder Treiber: je nachdem ob das Display Common Anode oder Common Kathode ist PNP Transistoren oder A2983 bzw NPN Transistoren oder UDN2803.

Gleich was ordentliches nehmen: einen MAX7219; der übernimmt auch selbstständig das Multiplexing.

Grüße Uwe

Also Uwe du hast in allen deinen Punkten recht. Gesamtstrom eines Digits beim Anzeigen der "maximalen" -8- liegt bei ca.90mA.

Mein eigentliches Problem liegt im Verständnis warum mein Code flackert aber der Beispielcode scheinbar statisch ist. So sollte es ja rein theoretisch Hardwaremäßig möglich sein, das ganze korrekt in meinem Code anzeigbar zu machen.

Habe mal vom Verhalten im Beispiel Code "SerialMonitor" gemacht. Dabei gibt es scheinbar keine Probleme beim Multiplexen. Habe dazu mal einige Zahlen eingebenen. Die Digits wirken auch alle ungefähr gleich hell, wenngleich die Digits 1+2 ein wenig dunkler wirken im Video.
Danach habe ich dann meinen Code hochgeladen und mit dem Poti einfach den Temperatur Sollwert geändert.
Dabei sieht man eben deutlich das das 4.te Digit nicht flakert und relativ hell ist und die Digits 1-2-3 im gleichtakt gedimmt flackern.

Anbei ein Video vom dem ganzen

noch eine weitere Frage bezüglich eventuellem Wechsel der Library. Welche könnt ihr da empfehlen, bzw. wisst ihr das gut/brauchbar funktioniert?

Ich hätte gerne beibehalten die Segmente (a-b-c-d-e-f-g, kein Dezimalpunkt) mit einen Schieberegister (74HC595) zu treiben. Da ich CommonAnode Displays habe ist es für mich kein Problem eine externe Digit-Treiberstufe mit diskretem PNP-Transitoren aufzubauen. Auch habe ich noch 4 "übrige" DigitalPins des Arduino ungenutzt. Somit wäre eine direkt Ansteurung der Digit-Auswahl des Multiplex Betriebs möglich.

Danke schonmal wenn mir dabei jemand helfen könnte.