www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVR Helligkeitsregulierung per Interrupt


Autor: Philipp F. (nerdture)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich bin noch immer an meinem Wecker-Projekt (ATMEGA8, intern 4MHz RC, 
LED-7Seg) und wollte jetzt ein feature einbauen, sodass man die 
Helligkeit vom Display regulieren kann.
Das soll sozusagen wie PWM funktionieren.

Da ich nicht soviele Pins zur verfuegung habe und auch keine weiteren 
ICs verwenden wollte wird das Display momentan gepulst. Es ist immer nur 
eine der 4 Ziffern an, und die werden bisher einfach im Kreis 
durchlaufen, bei jedem Interrupt gehts eins weiter. Der Interrupt ist 
der OutputCompareMatch vom 16-bit Timer 1.

Zur Helligkeitsregulierung habe ich es jetzt so gemacht, dass er bei 
jedem Interrupt den "status" wechselt (0/1). Und jedes mal das 
OutputCompareMatch Register aendert. Im Status 0 waere das Display dann 
komplett an, im Status 1 wuerde er eine Ziffer weiter gehen und diese 
anschalten.
Man soll dann das Verhaeltnis der Dauer von An und Aus umstellen 
koennen.

Prinzipiell funktioniert das auch, aber ich vermute stark, dass hier 
irgendwelche Interrupts verschluckt werden, wenn das Verhaeltnis zu 
stark von 1 abweicht, weil dann das Display teilweise kurz flackert.
Ich koennte natuerlich das Verhaeltnis einfach strenger begrenzen, aber 
dann bringt die Helligkeitseinstellung nicht mehr soviel, wie loest man 
sowas also professionell?

Ich hoffe ihr koennt mir helfen. Wenn ich was wichtiges vergessen habe 
einfach fragen.
Philipp

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde den zweiten Compare-Interrupt des Timers nehmen, um das Licht 
auszuschalten. Also der eine Compare-Int macht das Multiplexing 
(Datenquelle umschalten, Digit umschalten, nächsten Multiplex-Termin 
festlegen und jetzt zusätzlich den Ausschalt-Termin des anderen 
Interrupts festlegen). Der andere Compare-Int erfolgt nun mit 
(einstellbarer) Verzögerung dem ersten Comp-Int und macht das Licht 
wieder aus. Somit kann man die Einschaltdauer feinstufig einstellen.

...

Autor: Philipp F. (nerdture)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja stimmt, gar nicht gesehen, dass es zwei CompareRegister gibt. Aber 
mein Problem bleibt dann immer noch.
Das Problem ist naemlich der Grenzfall, wo Aus- und Einschalten zeitlich 
ganz nah zusammenrücken,wenn ich das Display sehr hell oder dunkel 
stelle. Also sehr dicht hintereinander die Interrupts kommen. Und in der 
einen Interruptroutine zum setzen der Segmente brauche ich schon ein 
paar kleine Rechnungen die kurz dauern.
An sich kein problem, das interrupt flag bleibt ja gesetzt, bis die 
routine fertig ist, aber evtl. wird dann mein wichtigster Interrupt 
verschluckt, der naemlich die Zeit zaehlt...

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Philipp F. wrote:
> Ja stimmt, gar nicht gesehen, dass es zwei CompareRegister gibt. Aber
> mein Problem bleibt dann immer noch.

Dann machst Du was Grundlegendes falsch...

> Das Problem ist naemlich der Grenzfall, wo Aus- und Einschalten zeitlich
> ganz nah zusammenrücken,wenn ich das Display sehr hell oder dunkel
> stelle. Also sehr dicht hintereinander die Interrupts kommen. Und in der
> einen Interruptroutine zum setzen der Segmente brauche ich schon ein
> paar kleine Rechnungen die kurz dauern.

Aha... Du rechnest in der ISR? Du solltest lieber in der Mainloop 
rechnen und in der ISR die bereitstehenden Werte nur kopieren. Dies 
verkürzt die ISRs dermaßen, dass es keine Konflikte mehr gibt.

> An sich kein problem, das interrupt flag bleibt ja gesetzt,

gesetzt?? Während der ISR ist es meiner Meinung nach gelöscht...

> bis die
> routine fertig ist, aber evtl. wird dann mein wichtigster Interrupt
> verschluckt, der naemlich die Zeit zaehlt...

Das lässt sich alles durch das Befolgen von drei wichtigen Regeln 
verhindern:

1. ISRs möglichst kurz halten
2. ISRs möglichst kurz halten
3. ISRs möglichst kurz halten

...

Autor: Philipp F. (nerdture)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich weiss ja nicht was du mit kurz meinst. Also ich habe keine Schleifen 
o.ae. drin:

SIGNAL(SIG_OUTPUT_COMPARE1A)
{
  TCCR1B = 0; //stop (no new interrupts please)
  
  disp_state ^= 0b1;
  
  if(!disp_state) {
    PORTD = 0b1111111 | cur_playl; //Turn off all segments
    PORTC = (0b100<<cur_digit); //Switch to next digit (no dots)
    
    OCR1A = 1000-(clk_settings[SET_BRIGHTNESS]*150);
  } else {
    PORTC ^= dispdots; //Set dots to state wanted
    
    blink_cnt++;
    if(blink_cnt >= BLINKINTERVAL) {
      cur_blinkstate = cur_blinkstate?0:1;
      blink_cnt = 0;
    }
    
    if(!blink_mask[cur_digit] || cur_blinkstate)
      PORTD = transtbl[dispcont[cur_digit]] | cur_playl; //Set the new segments
    else
      PORTD = 0b1111111 | cur_playl; //We are Blinking and digit is currently off
    
    cur_digit = (cur_digit+1)%4;

    OCR1A = 63+(clk_settings[SET_BRIGHTNESS]*150);
  }
  
  TCNT1 = 0;
  TCCR1B = 0b1010; //prescaler = 8 //TOP = OCR1A, update immediatly
}


clk_settings[SET_BRIGHTNESS] kann man von 0 bis 5 einstellen

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, für C bin ich nicht zuständig, ich werkele in Assembler.

...

Autor: Philipp F. (nerdture)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also,
ich habe jetzt den Fehler gefunden. Das leichte Flackern lag naemlich 
gar nicht an diesem Interrupt sondern an einem anderen, der wirklich zu 
lang war, den ich aber leider auch nicht so einfach auslagern konnte.
Also habe ich den langen jetzt mit sei() "nestable" gemacht und es 
klappt wunderbar.

Ich habe es aber trotzdem noch mit zwei Compares (A und B) geloest. Ist 
einfach schoener

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man kann in der ISR ein Flag (Semaphore) setzen und dieses in der 
Mainloop abfragen und bei Bedarf den (angemeldeten) Job erledigen. Damit 
bekommt man die ISRs schön klein und schnell. Das Freigeben des 
Interruptes in der ISR sollte man nur in Ausnahmefällen anwenden, da es 
recht störanfällig ist und zu Stackfehlern führen kann. Meist gibt es 
eine bessere Lösung, nämlich kurze schnelle ISRs.

...

Autor: Ulrich P. (uprinz)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also das geht eigentlich auch ohne Software ganz gut. Da Du ja eine 
Matrix verwendest, hast Du alle Segmente auf einem Treiber und alle 
Spalten auf einem Anderen. Nun müsstest Du also nur die Spalten Treiber 
noch mal über einen gemeinsamen FET schalten, der von einem der PWM 
Generatoren geschaltet wird. Wenn Du für die PWM ein vielfaches Deiner 
Spaltenfortschaltung verwendest kannst Du ohne Software Aufwand das 
ganze Display in vielen Stufen dimmen. Du musst nur das PWM Verhältnis 
durch das setzen des PWM Registers verändern.
Du müsstest lediglich einen LDR oder eine Photodiode an einen der ADC 
Eingänge klemmen.
Da gehen dann auch komplexere Dinge, wie z.B. eine verzögerte 
Nachführung der Helligkeit oder eine Änderung der Helligkeit bei Alarm 
oder was auch immer.

Gruß, Ulrich

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.