Taster abfragen? STK500

Gast #544330
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!
#544335
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 )
     ...
Gast #544356
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 :(
#544364
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.
Gast #544435
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
#544474
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.
Gast #544485
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
Gast #544764
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!
      {
Gast #544788
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.
#545055
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.
#545056
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.
Gast #545858
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 :-)
Gast #545936
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!
#545962
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren