Forum: Mikrocontroller und Digitale Elektronik Taster abfragen? STK500


von EinSteigÄr (Gast)


Lesenswert?

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!

von Karl H. (kbuchegg)


Lesenswert?

> #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 )
     ...

von EinSteigÄr (Gast)


Lesenswert?

Ah vielen Dank!

Habe ich wohl in der guten Tutorial-Hilfe übersehen ;)

von EinSteigÄr (Gast)


Lesenswert?

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 :(

von Karl H. (kbuchegg)


Lesenswert?

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.

von EinSteigÄr (Gast)


Lesenswert?

Ja stimmt, der Sprung ist eben zu schnell...

Danke

von EinSteigÄr (Gast)


Lesenswert?

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

von EinSteigÄr (Gast)


Lesenswert?

sorry, habe deinen Thread mit dem einrücken noch nicht gelesen ;) Werde 
ich aber künftig beachten (siehe for-Schleife ;-) )

danke

von EinSteigÄr (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von EinSteigÄr (Gast)


Lesenswert?

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

von EinSteigÄr (Gast)


Lesenswert?

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!
      {

von EinSteigÄr (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von EinSteigÄr (Gast)


Lesenswert?

ok vielen Dank! Es lag einzig und allein am Löschen dieses Bits. Jetzt 
klappt es astrein

Danke

von EinSteigÄr (Gast)


Lesenswert?

#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 :-)

von Peter D. (peda)


Lesenswert?

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

von EinSteigÄr (Gast)


Lesenswert?

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!

von Karl H. (kbuchegg)


Lesenswert?

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
Noch kein Account? Hier anmelden.