Hallo Mikrocontroller-Freaks. Ich habe mir gestern ein STK500 gekauft, und wollte gerade mal ein kleines Programm zum abfragen von den Tastern schreiben. Das heißt, sobald eine bestimmte Taste gedrückt wird, sollen die LEDs ein bestimmtes Muster leuchten. Hier mal mein bisheriges Programm: _______ #include <avr/io.h> int main (void) { DDRA = 0xFF; //DataDirRegister auf Ausgang von PORTA DDRB = 0x00; //DataDirRegister auf Eingang von PORTB for(;;) { if (PORTB==0x7F) //wenn der "linke"Taster gedrückt wird, dann.. { PORTA=0xA5; } } } ________ es leuchet aber leider nüx. Ich habe mir schon überlegt, ob es denn daran liegt, dass die Taste möglicherweise prellt (mech. Schalter prellen immer) oder evtl. die Abfrage vom µC so schnell ist, dass er 1000x oder öfter ein 0x7F am PORTB bekommt. Obwohl das wiederum durch die Endlos-Schleife doch kein Problem darstellen sollte :-/ Bitte um Hilfee!
> #include <avr/io.h> > > int main (void) > { > DDRA = 0xFF; //DataDirRegister auf Ausgang von PORTA > DDRB = 0x00; //DataDirRegister auf Eingang von PORTB > for(;;) > { > if (PORTB==0x7F) //wenn der "linke"Taster gedrückt wird, > dann.. > { > PORTA=0xA5; > } > } > } > __________ > > es leuchet aber leider nüx. Auf einen Port gibt man aus indem man in das PORT Register schreibt Von einem Port wird eingelesen, indem man vom PIN Register liest if( PINB == 0x7F ) ...
Und so müsste die LED doch eigentlich Blinken oder? #include <avr/io.h> #include <util/delay.h> int main (void) { DDRA = 0xFF; //DataDirRegister auf Ausgang von PORTA DDRB = 0x00; //DataDirRegister auf Eingang von PORTB for(;;) { PORTA = 0x7F; _delay_ms(200); PORTA = 0x00; } } macht sie leider nich :(
Geh das mal in Gedanken durch:
for(;;)
{
PORTA = 0x7F;
_delay_ms(200);
PORTA = 0x00;
}
PORTA = 0x7F
damit wird eine Lampe eingeschaltet (oder aus?, weiss nicht,
ist auch egal).
_delay_ms(200)
danach wartet ddas Programm
PORTA = 0x00
dann die Lampe wieder aus. Als nächstes beginnt
die Schleife wieder von vorne
PORTA = 0x7F
die Lampe wird wieder eingeschaltet.
Oha. Was denkst du wieviel Zeit vergeht vom Ausschalten
der Lampe mittels PORTA = 0x00 bis zum Wiedereinschalten
mittels PORTA = 0x7F?
In Summe
> macht sie leider nich :(
Doch das tut sie. Nur ist die Dunkelphase so kurz, dass du
sie unmöglich sehen kannst :-)
Mit einem Oszilloskop würdest du es sehen können.
Du musst natürlich, nachdem die Led dunkel geworden ist,
ebenfalls eine zeitlang warten
1 | int main (void) |
2 | {
|
3 | DDRA = 0xFF; //DataDirRegister auf Ausgang von PORTA |
4 | DDRB = 0x00; //DataDirRegister auf Eingang von PORTB |
5 | |
6 | for(;;) |
7 | {
|
8 | PORTA = 0x7F; |
9 | _delay_ms(200); |
10 | |
11 | PORTA = 0x00; |
12 | _delay_ms(200); |
13 | }
|
14 | }
|
Und gewöhn dir gleich von anfang an, deinen Code korrekt einzurücken.
So. Jetzt mache ich gerade etwas mit Timern: und zwar möchte ich hintereinander folgend 3 Taster am STK500 abfragen, während ein Timer läuft und dann die momentanen Werte in einem Register (hier PORTA -> Leuchtdioden) speichern. Habe es nun mit einem Taster probiert: include <avr/io.h> #include <util/delay.h> int main (void) { DDRA = 0xFF; //PORTA = Ausgang DDRB = 0x00; //PORTB = Eingang DDRD = 0x00; TCCR0 |= (1<<CS02) | (1<<CS00); //1024 Prescaler for(;;) { if (TIFR &(1<<TOV0)) //wenn Overflow, dann PORTA incrementieren { PORTA=TCNT0+1; } if (PINB==0x7F) //wenn Taster1 gedrückt wird, Timer stoppen { TCCR0 |= (1<<CS02) | (1<<CS01) | (1<<CS00); } } } Und das funktioniert auch soweit. Nur in welches Register kann ich es noch speichern? Hat man nicht so "Universal-Register", in die man Werte schreiben kann? Außerdem möchte ich, dass ich den Timer noch langsamer laufen lasse. Wie kann ich das mit einer Schleife bewerkstelligen? Etwa so: for (i=0;i<100;i++) { if (TCNT0==0xFF) { i++; } } Würde auch das so funktionieren? Danke
sorry, habe deinen Thread mit dem einrücken noch nicht gelesen ;) Werde ich aber künftig beachten (siehe for-Schleife ;-) ) danke
Hmm da ist auch noch der Wurm drin, in meinem Quellcode. Er sollte nämlich immer um eins hochzählen (Binäre Darstellung durch LEDs), wenn ein Overflow kommt.
EinSteigÄr wrote: > include <avr/io.h> > #include <util/delay.h> > > int main (void) > { > DDRA = 0xFF; //PORTA = Ausgang > DDRB = 0x00; //PORTB = Eingang > DDRD = 0x00; > TCCR0 |= (1<<CS02) | (1<<CS00); //1024 Prescaler > > > for(;;) > { > if (TIFR &(1<<TOV0)) //wenn Overflow, dann PORTA incrementieren > { > PORTA=TCNT0+1; > } > > if (PINB==0x7F) //wenn Taster1 gedrückt wird, Timer stoppen > { > TCCR0 |= (1<<CS02) | (1<<CS01) | (1<<CS00); > } > } > } > > Und das funktioniert auch soweit. Das glaub ich nicht so ganz. Zumindest den Timer wieder stoppen funktioniert so sicher nicht. > Nur in welches Register kann ich es > noch speichern? Hat man nicht so "Universal-Register", in die man Werte > schreiben kann? Ja. Nennt sich Variable int main() { int Wert; int Wert2; Wert = 5; Wert2 = 2 * Wert + 8; Wert = PINA; } > Außerdem möchte ich, dass ich den Timer noch langsamer > laufen lasse. Wie kann ich das mit einer Schleife bewerkstelligen? gar nicht. Da musst du auf Interrupts ausweichen und den Overflow Interrupt auswerten. Tu dir einen Gefallen und besorg dir erstmal ein normales Buch über C. Wenn du mit dem Begriff "Variable" noch nichts anfangen kannst, dann fehlt es an elementaren Grundlagen in C. Bevor du dich da nicht weiter eingarbeitet hast, ist der Frust an der µC Programmierung vorprogrammiert.
Doch, der Begriff Variable ist mir natürlich geläufig. War eben ein Denkfehler in Bezug auf Mikrocontroller. Habe auch mal eine kurze Zeit Assembler Programmiert und da war es eben ein wenig anders (Register/Variablen) Danke
Bitte helft mir: ich bin der Verzweiflung nahe :-( Ich möchte nun folgendes machen: Sobald der Taster1 gedrückt wird (und zwar jetzt NICHT auf dem STK500, drum 0x01 und nicht 0x7F), soll der momentane Inhalt des Zählregisters vom Timer in die Variable y geschrieben werden. Sofern es bis dahin Überläufe gegeben hat, sollen diese in die Variable "uberlauf" geschrieben werden. Nachdem der Taster 1 Gedrückt wurde, sollen die Anzahl der bisherigen Überläufe mit binärer LED-Anzeige (über PORTD) erfolgen. Wenn ich es im AVR Studio simuliere, dann bekommt die Variable "uberlauf" irgendwann einen wert von 24, mal 28, mal irgendeine Andere Zahl, obwohl bisher z.b. nur ein einziger Überlauf stattgefunden hat :-( Warum?? #include <avr/io.h> int main(void) { int ubergabe=0,y=0; DDRD=0xFF; DDRB=0x00; TCCR0 |= (1<<CSO0); //irgendein Presc., wegen Simul. dass es nicht so lange dauert, bis ein Durchlauf fertig ist for(;;) { if (TIFR &(1<<TOV0)) //wenn Überlauf stattfand,dann.... { ubergabe++; } if (PINB==0x01) //wenn Taster1 gedrückt wird, dann.... { TCCR0=0x00; //Timer stoppen y=TCNT0; //Inhalt des TCNT0 in die Var. y schreiben PORTD=ubergabe; //LED-Anzeige des Inhalts von "ubergabe" } } } Vieelen Dank! {
Bitte bitte helft mir, sonst kann ich deswegen heute Nacht nicht schlafen kaffeemaschine auf dauerlauf :-) Vielen Dank für euere Geduld ;-) Aber ich denke, es wird jedem so gehen, der mit mikrocontrollern noch nicht allzuviel am Hut hatte.
EinSteigÄr wrote: > Bitte helft mir: ich bin der Verzweiflung nahe :-( > > Ich möchte nun folgendes machen: Sobald der Taster1 gedrückt wird (und > zwar jetzt NICHT auf dem STK500, drum 0x01 und nicht 0x7F), soll der > momentane Inhalt des Zählregisters vom Timer in die Variable y > geschrieben werden. Sofern es bis dahin Überläufe gegeben hat, sollen > diese in die Variable "uberlauf" geschrieben werden. Nachdem der Taster > 1 Gedrückt wurde, sollen die Anzahl der bisherigen Überläufe mit binärer > LED-Anzeige (über PORTD) erfolgen. > Wenn ich es im AVR Studio simuliere, dann bekommt die Variable > "uberlauf" irgendwann einen wert von 24, mal 28, mal irgendeine Andere > Zahl, obwohl bisher z.b. nur ein einziger Überlauf stattgefunden hat :-( > Warum?? Das wird so nichts. Ich sagte schon, du musst auf Interrupts ausweichen. Jeder Timer ist in der Lage einen Interrupt auszulösen, wenn bestimmte Ereignisse eintreten: zb. ein Überlauf stattfindet. Dazu muss man * Eine Interrupt Funktion schreiben * Dem Timer sagen, dass er einen Interrupt generieren darf * Da globale Interrupt Flag freigeben, damit Interrupts generell zu gelassen sind.
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | |
4 | unsigned int ueberlauf; |
5 | |
6 | ISR( TIMER0_OVF_vect) // Diese Funktion wird ausgeführt, wenn der |
7 | // Timer einen Überlauf produziert hat.
|
8 | {
|
9 | ueberlauf++; |
10 | }
|
11 | |
12 | int main() |
13 | {
|
14 | unsigned char y; |
15 | |
16 | DDRD = 0xFF; |
17 | DDRB = 0x00; |
18 | |
19 | TCCR0 |= (1<<CS00); // irgendein Presc., wegen Simul. dass es |
20 | // nicht so lange dauert, bis ein Durchlauf
|
21 | // fertig ist
|
22 | |
23 | TIMSK |= (1<<TOIE0); // Für den Timer 0 den Interrupt bei Overflow erlauben |
24 | |
25 | sei(); // Interrupts global freigeben |
26 | |
27 | for(;;) |
28 | {
|
29 | if (PINB == 0x01) // wenn Taster1 gedrückt wird, dann.... |
30 | {
|
31 | TCCR0 = 0x00; // Timer stoppen |
32 | y = TCNT0; // Inhalt des TCNT0 in die Var. y schreiben |
33 | PORTD = ueberlauf; // LED-Anzeige des Inhalts von "ueberlauf" |
34 | }
|
35 | }
|
36 | }
|
Wegen der Taster: Bist du dir ganz sicher, dass deine Taster high-aktiv sind? Normalerweise ist es so, dass ein nicht gedrückter Taster ein 1 Bit am PIN produziert und wenn er gedrückt wird, geht dieses Bit auf 0. Auch ist es meist so, dass man für einen Taster den Pullup Widerstand aktivieren muss.
EinSteigÄr wrote: > Wenn ich es im AVR Studio simuliere, dann bekommt die Variable > "uberlauf" irgendwann einen wert von 24, mal 28, mal irgendeine Andere > Zahl, obwohl bisher z.b. nur ein einziger Überlauf stattgefunden hat :-( > Warum?? Beobachte mal im Debugger das TOV0 Flag im TIFR Register. Wenn ein Überlauf auftritt wird es gesetzt. Dein Code reagiert auch darauf. Aber dann: Nur weil du das Register im Code abfragst wird es nicht zurückgesetzt. Auch beim nächsten Schleifendurchlauf ist das Flag gesetzt und du erhöhst deine Variable gleich nochmal, obwohl in der Zwischenzeit kein Überlauf stattgefunden hat. Und im nächsten Schleifendurchlauf ist es immer noch gesetzt woraufhin du schon wieder eine Erhöhung machst, etc. etc. Du müsstest daher das Überlaufflag selbst löschen, nachdem du den Überlauf gezählt hast. Aber die Interrupt Lösung ist besser und letztendlich hat man so einen Timer mit Overflow Interrupt in den meisten Programmen als Zeitbasis drinn.
ok vielen Dank! Es lag einzig und allein am Löschen dieses Bits. Jetzt klappt es astrein Danke
#include <avr/io.h> int main(void) { int ubergabe=0,y=0; DDRD =0xFF; DDRB =0x00; TCCR0 |= (1<<CS00); for(;;) { if (TIFR &(1<<TOV0)) { ubergabe++; TIFR |= (1<<TOV0); } if (PINB==0x01) { TCCR0=0x00; y=TCNT0; PORTD=ubergabe; } } } soo klappts, das mit den interrupts mach ich dann bald :-)
EinSteigÄr wrote:
> TIFR |= (1<<TOV0);
scheint richtig, ist es aber nicht.
Es macht genau das gleiche wie
1 | TIFR = TIFR; |
oder
1 | TIFR = 0xFF; |
d.h. es löscht sämtliche anderen Timerinterruptquellen mit. Richtig ist allein:
1 | TIFR = 1<<TOV0; |
Peter
aahhja, das verwirrt mich nun ... Aber solange ich ohne Interrupts arbeite, ist das doch eigentl. egal?! ich benötige das Bit ja lediglich, um festzustellen, ob ein Überlauf stattgefunden hat. Aber vielen Dank, ich ändere es auf deine Lösugn ab!
EinSteigÄr wrote: > aahhja, das verwirrt mich nun ... > > Aber solange ich ohne Interrupts arbeite, ist das doch eigentl. egal?! Nein. Etwas falsch zu machen ist nie egal, selbst wenn es anscheinend das richtige tut. > ich benötige das Bit ja lediglich, um festzustellen, ob ein Überlauf > stattgefunden hat. Es geht nicht ums feststellen. Es geht ums rücksetzen. EIn Interrupt Flag wird zurückgesetzt, indem man das entsprechende Bit händisch auf 1 setzt. Mittels TIFR |= (1<<TOV0); beschreibst du TIFR auch an jenen Stellen mit einer 1, bei denen im TIFR Register eine 1 war. Nicht nur an der Stelle TOV0
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.