Forum: Compiler & IDEs timer durch pinabfrage steuern


von Gastulus (Gast)


Lesenswert?

Hallo allerseits,

ich würde gerne durch drücken eines Tasters an PD2 die Variable "teiler" 
jeweils um 1 erhöhen (entprellen hab ich erstmal weggelassen) um damit 
den Teiler für meine ausgegebene Frequenz zu vergrößern. An den 
Ausgängen PD5 und PD6 habe ich zwei Led`s angeschlossen die gegenläufig 
negiert werden. Wenn ich den Taster nun drücke, ändert sich allerdings 
meine ausgegeben Frequenz nicht. Der Fehler ist für euch warscheinlich 
nicht so schwer zu sehen, für mich allerdings schon. Danke für jeden Tip


#include <avr\io.h>
#include <avr\interrupt.h>
#include <stdint.h>

int count;
int teiler;

ISR( TIMER0_OVF_vect )    //Interrupt der durch den Timer Overflow 
ausgelöst wird
{
  count++;
  if (count >= teiler)
  {
  PORTD ^= (1<<PD5) | (1<<PD6);   //pin 5 und 6 von Port D Toggeln
  }
}


int main(void)
{
DDRD  &= ~(1<<DDD2);      /* Pin PD2 als Eingang */
PORTD |= (1<<PD2);    /* internen Pull-Up an PD2 aktivieren */

DDRD = (1 << DDD5) | (1 << DDD6); //Pin D5 und D6 als Ausgang definieren
PORTD |= (1<<PD5) | (0<<PD6);     //Pin D5 auf logisch 1 und D6 auf 0

TCCR0 = ( 1 << CS02 ) | ( 1 << CS00 );  //Prescaler auf CPUClock/1024
TIMSK = ( 1 << TOIE0 );      //TIMSK: Timer Interrupt Mask
  sei();

  while( 1 )
  {
if ( PIND & (1<<PIND2) )
  {
    teiler++;
  }

  }
}

von Johannes M. (johnny-m)


Lesenswert?

1.: Du müsstest count auch wieder auf Null setzen, wenn die LEDs 
umgeschaltet wurden.

2.: Variablen, die sowohl im Hauptprogramm als auch in 
Interrupt-Handlern verwendet werden (also in Deinem Programm die 
Variable teiler), müssen volatile deklariert werden, da es sonst 
passieren kann, dass Zugriffe wegoptimiert werden und das ganze nicht 
mehr funktioniert.

von Gastulus (Gast)


Lesenswert?

Habe die Beiden Mängel behoben, jetz blinken die Leds komischerweise mit 
etwa 1Hz und auf den Taster wollen sie auch nicht so richtig hören. 
Trotzdem danke, werds mir nochmal durch den Kopf gehen lassen.

von Johannes M. (johnny-m)


Lesenswert?

Gastulus wrote:
> Habe die Beiden Mängel behoben, jetz blinken die Leds komischerweise mit
> etwa 1Hz und auf den Taster wollen sie auch nicht so richtig hören.
Ich hoffe, Du hast das Rücksetzen von count in die Klammer vom if mit 
reingeschrieben...

> Trotzdem danke, werds mir nochmal durch den Kopf gehen lassen.
Tu das. Und schick vielleicht noch mal den neuen Code mit den 
"Verbesserungen".

von Gastulus (Gast)


Lesenswert?

Ja, hab ich in die Klammer mit rein geschrieben, so sieht er jetzt aus.



#include <avr\io.h>
#include <avr\interrupt.h>
#include <stdint.h>

volatile uint8_t count;
volatile uint8_t teiler;

ISR( TIMER0_OVF_vect )    //Interrupt der durch den Timer Overflow 
ausgelöst wird
{
count++;
if (count >= teiler)
{
PORTD ^= (1<<PD5) | (1<<PD6);   //pin 5 und 6 von Port D Toggeln
count = 0;
}
}

int main(void)
{
DDRD  &= ~(1<<DDD2);    /* Pin PD2 als Eingang */
PORTD |= (1<<PD2);      /* internen Pull-Up an PD2 aktivieren */

DDRD = (1 << DDD5) | (1 << DDD6);//Pin D5 und D6 als Ausgang
PORTD |= (1<<PD5) | (0<<PD6);   //Pin D5 auf logisch 1 und D6 auf 0

TCCR0 = ( 1 << CS02 ) | ( 1 << CS00 );  //Prescaler auf CPUClock/1024
TIMSK = ( 1 << TOIE0 );  //TIMSK: Timer Interrupt Mask
sei();

  while( 1 )
  {

          //Fuehre Aktion aus, wenn Bit Nr. 3 in PINC gesetzt (1) ist //
  if ( PIND & (1<<PIND2) )
  {
    teiler++;
  }

  }
}

von Johannes M. (johnny-m)


Lesenswert?

> //Fuehre Aktion aus, wenn Bit Nr. 3 in PINC gesetzt (1) ist //
>  if ( PIND & (1<<PIND2) )
Das widerspricht sich! Wo hängt der Taster dran? Port D oder C? Und noch 
was: Ist der Taster High- oder Low-side angeschlossen? Im zweiten Fall 
(der aber in den meisten Fällen vorliegt) muss die Abfrage invertiert 
sein (Taster gedrückt -> Low-Pegel am Pin). Also
1
if (!(PIND & (1<<PIND2)))
2
{}

von Johannes M. (johnny-m)


Lesenswert?

BTW: count muss nicht volatile sein, da es nur in der ISR verwendet 
wird.

> PORTD |= (1<<PD5) | (0<<PD6);   //Pin D5 auf logisch 1 und D6 auf 0
Das (0 << PD6) bringt an der Stelle überhaupt nichts. Wenn PD6 vorher 
gesetzt war (was es nach einem Reset natürlich nicht ist, weshalb das an 
dieser Stelle zumindest nicht zu einer Fehlfunktion führt), bleibt es 
das auch. Merke:
X | 0 = X
Und eine Null kannst Du schieben wie Du willst, es bleibt immer eine 
Null.
0        = 0b00000000
0 << PD6 = 0b00000000
Merkst Du was?

Bei einer 1 hingegen macht es Sinn:
1        = 0b00000001
1 << PD5 = 0b00100000

von Gastulus (Gast)


Lesenswert?

Hast recht das hat sich wiedersprochen, aber der Taster ist tatsächlich 
an Port D. Der Taster ist auf Masse gezogen wenn er nicht betätigt wird, 
bei Betätigung liegen +5V am Pin. Werde morgen nochmal drüber 
nachdenken. Danke

von Johannes M. (johnny-m)


Lesenswert?

Gastulus wrote:
> Hast recht das hat sich wiedersprochen, aber der Taster ist tatsächlich
> an Port D. Der Taster ist auf Masse gezogen wenn er nicht betätigt wird,
> bei Betätigung liegen +5V am Pin. Werde morgen nochmal drüber
> nachdenken. Danke
Sicher? Und warum hast Du dann den Pull-Up aktiviert? Was ist das für 
ein Taster?

von Gastulus (Gast)


Lesenswert?

Ich habe gedacht das das so gemacht wird, das ist so ein MiniTaster auf 
meinem Pollin EvalBoard. Der Taster liegt im ungetasteten Zustand mit 
der einen Seite über einen 33K-Widerstand auf Masse, die andere Seite 
wird beim drücken mit +5V verbunden.

von Johannes M. (johnny-m)


Lesenswert?

Autsch ja, das Pollin-Board... Stimmt, da haben die aus irgendwelchen 
unerfindlichen Gründen High-Side-Taster mit externen Pull-Downs dran, 
und das obwohl die AVRs integrierte Pull-Ups haben... Dann musst Du 
allerdings den internen Pull-Up deaktivieren, weil Du sonst im Zustand 
"Taster nicht gedrückt" einen Pegel irgendwo zwischen gut und böse hast, 
der möglicherweise vom µC weder definiert als High noch als Low erkannt 
werden kann.

von Gastulus (Gast)


Lesenswert?

Habe den Pullup deaktiviert, und siehe da, die Frequenz reagiert 
zumindest schon mal auf den Taster. Aber, manchmal blinken die Leds 
schneller wenn ich drücke und dann wieder ganz langsam... die Frequenz 
sinkt also nicht kontinuierlich mit zunehmender Tastanzahl ab. Dafür 
hätten wir das mit den Pullups aber schonmal geklärt.

von Johannes M. (johnny-m)


Lesenswert?

Gastulus wrote:
> Habe den Pullup deaktiviert, und siehe da, die Frequenz reagiert
> zumindest schon mal auf den Taster. Aber, manchmal blinken die Leds
> schneller wenn ich drücke und dann wieder ganz langsam... die Frequenz
> sinkt also nicht kontinuierlich mit zunehmender Tastanzahl ab. Dafür
> hätten wir das mit den Pullups aber schonmal geklärt.
Doch, ich vermute schon, dass die Frequenz sich kontinuierlich ändert, 
allerdings so schnell, dass Du das überhaupt nicht mitbekommst. Der 
Taster wird schließlich ohne jegliche Wartezeit zyklisch abgefragt. Je 
nach Taktfrequenz des µC gehe ich mal davon aus, dass bei gedrücktem 
Taster die Erhöhung von teiler alle paar µs geschieht. teiler ist aber 
eine 8-Bit-Variable, die schon nach 256 Erhöhungen (also nach höchstens 
ein paar ms) überläuft und wieder bei Null anfängt. Deshalb siehst Du 
nur zufällige Reaktionen des Controllers. Du musst entweder eine 
vernünftige Taster-Auswertung einbauen, damit jeder Tastendruck nur 
einmal erkannt wird und teiler beim Drücken der Taste nur einmal erhöht 
wird, oder füge nach der Tasterabfrage eine Wartezeit ein.

von Gastulus (Gast)


Lesenswert?

AAAAAAHHHH, jetzt habe ich verstanden, danke langsam kommt Licht in das 
Dunkel. Werde einfach mal mit einer einfachen Wartezeit beginnen.

Wäre es aber allgemein nicht besser wenn man den Timer im CTC-Modus 
laufen lässt und mit dem Tastendruck immer diesen Vergleichswert hoch 
oder auch runter Zählt?
Egal, erstmal die Sache mit der Wartezeit ausprobieren. Vielen Dank 
nochmal

von Johannes M. (johnny-m)


Lesenswert?

Gastulus wrote:
> AAAAAAHHHH, jetzt habe ich verstanden, danke langsam kommt Licht in das
> Dunkel. Werde einfach mal mit einer einfachen Wartezeit beginnen.
Das ist zum Ausprobieren für den Anfang sicher die einfachste Methode. 
Bedenke aber, wenn Du die Funktionen aus der util/delay.h benutzen 
wollen solltest, dass die _delay_ms- und _delay_us-Funktion limitiert 
sind in Abhängigkeit von der CPU-Frequenz (Details siehe AVR-libc-Doku).

> Wäre es aber allgemein nicht besser wenn man den Timer im CTC-Modus
> laufen lässt und mit dem Tastendruck immer diesen Vergleichswert hoch
> oder auch runter Zählt?
Das wäre eine elegantere Methode.

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.