www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ATTiny2313 Analog Komparator als "Capture Pin" für Timer?


Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Fachmänner ;-)

Zuerst:   Compiler AVR-GCC
          Controller: ATTiny2313

Folgendes Problem habe ich.

Ich habe mir eine Schaltung für meinen CarPC gebaut welche das 
Powermanagement
übernehmen soll. Unter anderen habe ich mit dem Analog Komparator einen 
Schutz eingerichtet, welcher mir den Rechner automatisch runterfährt 
sobald die Akkuspannung unter 11,6V sinkt.

Nun das Problem:
Angenommen das Fahrzeug ist aus, Rechner ist an und die Akkuspannung ist 
über 11,6V.

Wenn ich jetzt den Motor starte, bricht kurzzeitig die Spannung an der 
Batterie ein. Bei diesem Einbruch fährt mir meine Schaltung aber sofort 
den Rechner runter, was ja beim Motorstart nicht sein soll weil der Akku 
eigentlich nicht leer ist.

Also dachte ich mir, ich lasse den Rechner nur dann runterfahren wenn 
der gemessene Akkuzustand von 11,6V mindestens zwei Sekunden lang wahr 
ist.

Müsste ich mit dem Timer machen. Laut Datasheet kann ich den Komparator 
mit dem Timer verbinden.

Zweites wäre: Ich möchte den 8-Bit Timer benutzen.
Bei einem Systemtakt von 8MHz und einem Prescaler von 1024 würde der 
Timer Overflow Interrupt pro Sekunde 30 mal ausgelöst werden (8Mhz / 
1024 / 255; richtig gerechnet?). Wie kann ich denn den Timer auswerten 
dass er mir erst nach 2 Sekunden in meine PC-Shutdown routine reinläuft? 
Das Ergebnis des Timers nach 2 Sekunden müsste 15625 sein (richtig?)

Mein gedanke wäre jetzt, in der Timer Overflow routine die 
Timerergebnisse so lange zu addieren bis ich einen wert von 15625 habe 
und dann erst in die Shutdown Routine reinspringen. Würde das so 
funktionieren oder wird das Ergebnis (TCNT-Register) vor dem Auslösen 
des Overflow Interrupts auf 0 zurückgesetzt?

Hoffe ich habe gut genau erklärt was ich vorhabe.
Danke schonmal an alle im Voraus.


MfG Konrad

Autor: Michael U. (amiga)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich kenne ja Dein Konzept nicht, aber bei mir läuft eigentlich immer ein 
10ms Timer für alles mögliche von Uhr über Tastenentprellung usw.

Ich würde nur in jedem Timer-IRQ nach den Comparator schauen, ist 
Spannung kleiner als Sollwert -> Variable erhöhen -> Testen, ob größer 
als 2s (200 bei 10ms IRQ). Ist die Spannung im Sollbereich -> Variable 
auf 0 setzen.

Gruß aus Berlin
Michael

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok hört sich auch nett an :)

Wie stelle ich denn den Timer ein damit die ISR jede 10ms aufgerufen 
wird?
Damit hab ich noch so meine Probleme.
Dann schreibst du: Testen ob größer als 2s.
Also wenn der Komparator kippt meinst du soll ich die Variable erhöhen, 
wenn beim nächsten Vergleich immer noch gekippt wieder um eins erhöhen, 
und wenn mein Variablenwert 200 erreicht, erst dann runterfahren?!
Wenn der Komparator zwischendurch bei auslesen nicht gekippt ist einfach 
meine Zählervariable wieder auf 0 setzen. Verstehe ich dich richtig?

Autor: Michael U. (amiga)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ja, genau so. Damit werden dann kurze Einbrüche sicher ignoriert.

Die Zeit selbst sollte ja nicht sonderlich kritisch sein.

Timer 0 auf CTC-Mode, Vorteiler auf 1024 und Compare auf 77 sollten
8000000/1024 = 7812,5 / (77+1) = 100,16 Hz
1000/100,16= 9,984ms wenn ich jetzt auf die Schnelle richtig gerechnet 
habe.
Damit kommst Du bei einem 8-Bit Zähler in der IRQ auf maximal 2,55s.
Wenn Du IRQ nur dafür nimmst, kannst Du natürlich auch mit grüßerem 
Compare-Wert arbeiten, mit 144 wären dann maximal rund 5s Wartezeit drin 
usw.

Zum Code kann ich jetzt nichts sagen, benutze ASM, kein C...

Gruß aus Berlin
Michael

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja korrekt, erstmal dankeschön. werds heute nachmittag gleich mal 
testen, hoffentlich stell ich mich nicht doof an ;-)

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bin zu blöd für diese ganzen vielen Register hier...
Dieser CTC-Mode schaltet die OCnB Pins durch, da ist an meiner Schaltung 
aber nichts angeschlossen...
Kann mir denn nicht jemand mal nen Tritt verpassen wie ich den Timer 
initialisieren muss ?! Also welche Bits ich setzen muss und welche 
nicht.  Ich blicke da nicht durch, sorry.

Autor: Michael U. (amiga)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

er kann das machen, wie auch einige andere Modi, er muß aber nicht und 
Du brauchst das ja auch nicht.

Von vorn:
wir brauchen einen Interrupt in festem Zeitabstand, dafür bietet sich 
CTC an, weil der alles alleine macht.
Der zählt aufwärts bis der Wert in TCCR0A erreicht ist, setzt das 
Compare-IEQ-Flag und setzt den Zähler auf 0 und der zählt wieder bis 
TCCR0A usw. usw.

CTC ist WGM01 in TCCR0A auf 1, WGN00 auf 0, die COM0A und COM0B-Bits 
bleiben auch alle 0, weil keine Ausganbe des Taktes nütig ist.

Dazu in TCCR0B noch CS00 und CS02 auf 1 für Prescaler 1024, Rest bleibt 
auf 0.

Nun noch OCR0A miz 77 (oder eben anderen Top-Wert) geladen.
In TIMSK noch OCIE0A setzen für Interrupt bei Comparematch Register 
TCCR0A und fertig.

Interrupt-Routine schreiben für den CompareMatchA-IRQ (OC0Aaddr) von 
Timer0 und globale IRQ mit SEI freigeben.

IRQ-Routine dann etwa so:

if comparator = 1 (ok, sonst eben andersrum...)
  zaehler = 0
else              (zu niedrig...)
  zaaehler = zaehler+1 ; erhöhen
  if zaehler > max
    flag = du_sollst_runterfahren ;)
  endif
endif

Gruß aus Berlin
Michael

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rush wrote:
> Ich bin zu blöd für diese ganzen vielen Register hier...
> Dieser CTC-Mode schaltet die OCnB Pins durch, da ist an meiner Schaltung
> aber nichts angeschlossen...

Nö, tut er nicht.
Die Pins werden erst mit dem Timer verbunden, wenn Du das explizit mit 
den COM0B0 und COM0B1 Bits so einstellst.

Wenn ich ne Timerfunktion einstellen will, gehe ich einfach ins 
Datenblatt unter Register Description (T0: Seite 77).
Jedes Bit ist da schön erklärt.
Und dann arbeite ich die Register der Reihe nach ab, also TCCR0A, TCCR0B 
usw.


Peter

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab jetzt folgenden Code zusammengetippt:
#include <avr/io.h>
#include <avr/interrupt.h>
#define _SEI()      asm("sei")
#define _CLI()      asm("cli")
char var = 0;

void init()
{
  TCCR0A |= (1<<WGM01) | (0<<WGM00);
  TCCR0B |= (1<<CS00 ) | (1<<CS02);
  OCR0A = 78;
  TIMSK |= (1<<OCIE0A);

  DDRD &=~ (0<<PB0);
  DDRD |= (1<<PD0);
  PORTD |= (1<<PD0);

}

ISR(TIMER0_COMPA_vect)
{

  if(PORTB==0x01)
    {
    var = 0;
      PORTD |= (1<<PD1);
    }
  else
    {
    var = var+1;
    if (var >= 5)
      { PORTD &=~ (1<<PD1);}
    }


}

void main(void)
{
init();
  while(1)
  {
  _SEI();
  }
}


Im Simulator scheint es einwanfrei zu funktionieren.
wenn ich es aber in meinen Tiny schiebe leuchtet PD0 kontinuierlich. 
Auch wenn ich den Taster PB0 am STK500 drücke tut sich garnichts, LED 
leuchtet immer noch durch. Was habe ich denn falsch gemacht? Oder hab 
ich hier einfach nur irgendwo einen Denkfehler drin?

Danke schonmal.

MfG Konrad

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, die LED bleibt komplett aus, hatte das noch mit in die 
Initialisierung reingenommen.

Autor: Rush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mal so auf die schnelle einen Code zusammenfriemeln ist wohl doch nicht 
so prickelnd habe ich festgestellt. Hier mein Code für alle die nach 
einer Lösung suchen der funzt.

@Michael U.
Danke für die Idee, klappt wunderbar. Nur noch ein mein Progg einbinden 
und fertig.
#include <avr/io.h>
#include <avr/interrupt.h>
#define _SEI()      asm("sei")
#define _CLI()      asm("cli")
char var = 0;

void init()
{
  TCCR0A |= (1<<WGM01) | (0<<WGM00);
  TCCR0B |= (1<<CS00 ) | (1<<CS02);
  OCR0A = 78;  //geladen mit 10ms
  TIMSK |= (1<<OCIE0A);

  DDRB &=~ (1<<PB0);
  DDRD |= (1<<PD0);
  PORTD |= (1<<PD0);

}

ISR(TIMER0_COMPA_vect)
{

  if(PINB==0xFE)
    {
    var= var + 1;
    if (var >= 200)    //wenn Zustand mindestens 200x10ms = 2sec. andauert
      { PORTD |= (1<<PD0);}
    }
  else
    {
      PORTD &=~ (1<<PD0);
    var = 0;
    }


}

void main(void)
{
init();
  while(1)
  {
  _SEI();
  }
}

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.