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
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
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?
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
Ja korrekt, erstmal dankeschön. werds heute nachmittag gleich mal testen, hoffentlich stell ich mich nicht doof an ;-)
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.
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
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
Ich hab jetzt folgenden Code zusammengetippt:
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | #define _SEI() asm("sei")
|
4 | #define _CLI() asm("cli")
|
5 | char var = 0; |
6 | |
7 | void init() |
8 | {
|
9 | TCCR0A |= (1<<WGM01) | (0<<WGM00); |
10 | TCCR0B |= (1<<CS00 ) | (1<<CS02); |
11 | OCR0A = 78; |
12 | TIMSK |= (1<<OCIE0A); |
13 | |
14 | DDRD &=~ (0<<PB0); |
15 | DDRD |= (1<<PD0); |
16 | PORTD |= (1<<PD0); |
17 | |
18 | }
|
19 | |
20 | ISR(TIMER0_COMPA_vect) |
21 | {
|
22 | |
23 | if(PORTB==0x01) |
24 | {
|
25 | var = 0; |
26 | PORTD |= (1<<PD1); |
27 | }
|
28 | else
|
29 | {
|
30 | var = var+1; |
31 | if (var >= 5) |
32 | { PORTD &=~ (1<<PD1);} |
33 | }
|
34 | |
35 | |
36 | }
|
37 | |
38 | void main(void) |
39 | {
|
40 | init(); |
41 | while(1) |
42 | {
|
43 | _SEI(); |
44 | }
|
45 | }
|
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
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.
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | #define _SEI() asm("sei")
|
4 | #define _CLI() asm("cli")
|
5 | char var = 0; |
6 | |
7 | void init() |
8 | {
|
9 | TCCR0A |= (1<<WGM01) | (0<<WGM00); |
10 | TCCR0B |= (1<<CS00 ) | (1<<CS02); |
11 | OCR0A = 78; //geladen mit 10ms |
12 | TIMSK |= (1<<OCIE0A); |
13 | |
14 | DDRB &=~ (1<<PB0); |
15 | DDRD |= (1<<PD0); |
16 | PORTD |= (1<<PD0); |
17 | |
18 | }
|
19 | |
20 | ISR(TIMER0_COMPA_vect) |
21 | {
|
22 | |
23 | if(PINB==0xFE) |
24 | {
|
25 | var= var + 1; |
26 | if (var >= 200) //wenn Zustand mindestens 200x10ms = 2sec. andauert |
27 | { PORTD |= (1<<PD0);} |
28 | }
|
29 | else
|
30 | {
|
31 | PORTD &=~ (1<<PD0); |
32 | var = 0; |
33 | }
|
34 | |
35 | |
36 | }
|
37 | |
38 | void main(void) |
39 | {
|
40 | init(); |
41 | while(1) |
42 | {
|
43 | _SEI(); |
44 | }
|
45 | }
|
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.