www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Taster abfragen? STK500


Autor: EinSteigÄr (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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 )
     ...

Autor: EinSteigÄr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ah vielen Dank!

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

Autor: EinSteigÄr (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :(

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
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;
    _delay_ms(200);
  }
}

Und gewöhn dir gleich von anfang an, deinen Code
korrekt einzurücken.

Autor: EinSteigÄr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja stimmt, der Sprung ist eben zu schnell...

Danke

Autor: EinSteigÄr (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: EinSteigÄr (Gast)
Datum:

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

danke

Autor: EinSteigÄr (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: EinSteigÄr (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: EinSteigÄr (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!
      {

Autor: EinSteigÄr (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.
#include <avr/io.h>
#include <avr/interrupt.h>

unsigned int ueberlauf;

ISR( TIMER0_OVF_vect)    // Diese Funktion wird ausgeführt, wenn der
                         // Timer einen Überlauf produziert hat.
{
  ueberlauf++;
}

int main()
{
  unsigned char y;

  DDRD = 0xFF;
  DDRB = 0x00;
 
  TCCR0 |= (1<<CS00);     // irgendein Presc., wegen Simul. dass es
                          // nicht so lange dauert, bis ein Durchlauf 
                          // fertig ist

  TIMSK |= (1<<TOIE0);    // Für den Timer 0 den Interrupt bei Overflow erlauben

  sei();                  // Interrupts global freigeben

  for(;;)
  {
    if (PINB == 0x01)     // wenn Taster1 gedrückt wird, dann....
    {
      TCCR0 = 0x00;       // Timer stoppen
      y = TCNT0;          // Inhalt des TCNT0 in die Var. y schreiben
      PORTD = ueberlauf;  // LED-Anzeige des Inhalts von "ueberlauf"
    }
  }
}

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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: EinSteigÄr (Gast)
Datum:

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

Danke

Autor: EinSteigÄr (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :-)

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
EinSteigÄr wrote:

>   TIFR |= (1<<TOV0);

scheint richtig, ist es aber nicht.

Es macht genau das gleiche wie
TIFR = TIFR;
oder
TIFR = 0xFF;

d.h. es löscht sämtliche anderen Timerinterruptquellen mit.

Richtig ist allein:
TIFR = 1<<TOV0;


Peter

Autor: EinSteigÄr (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.