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
intmain(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
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
unsignedintueberlauf;
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
intmain()
13
{
14
unsignedchary;
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.
#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 :-)
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