Hey,
ich habe ein kleines Atmega8 Board von meinem Freund rausgekramt.
Die 4 LEDs funktionieren einwandfrei mit den Funktionen und dann hab ich
mich den Tastern gewipmet. Habe dann den Timer eingebaut der das dann
alle 10ms überprüfen soll, ob ein Taster gedrückt ist.
Taster1: PD5
Taster2: PB7
Nur passiert nichts wenn ich die Taste drücke und iwann springt der
switch doch in den default in der main-schleife.
Hoffe ihr könnt mir helfen.
Dankeschön
Hier der Code:
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
#include<util/delay.h>
4
#include<avr/signal.h>
5
6
intmode=0;
7
8
SIGNAL(SIG_OVERFLOW0)
9
{
10
cli();// Interrupts nicht zulassen
11
12
if((PIND&(1<<PIND5)))// Up-Taste gedr¸ckt
13
mode=mode+1;
14
15
if((PINB&(1<<PINB7))){// Down-Taste gedr¸ckt
16
if((mode-1)!=-1){
17
mode=mode-1;
18
}
19
}
20
21
sei();// Interrupts zulassen
22
}
23
24
25
intmain(void)
26
{
27
init();
28
29
for(;;){
30
31
switch(mode){
32
case0:
33
LED1(1);
34
LED2(1);
35
LED3(1);
36
LED4(1);
37
break;
38
39
case1:
40
LED1(0);
41
LED2(0);
42
LED3(0);
43
LED4(0);
44
break;
45
46
default:
47
LED1(1);
48
LED2(0);
49
LED3(1);
50
LED4(1);
51
}
52
53
}
54
return0;/* never reached */
55
}
56
57
58
59
intinit(void){
60
//LED Outputs setzen
61
DDRD=0x1C;//1 << 2 | 1 << 3 | 1 << 4;
62
DDRB=0x40;//1 << 6;
63
//LED Outputs setzen ENDE
64
65
// Timer f¸r Tastenabfrage
66
TCCR0|=(1<<CS22)|(1<<CS20);//8-Bit Timer, Timer clock = system clock/1024
In der Regel werden Taster nach GND geschaltet und die internen Pull-ups
aktiviert. Ich weiß nicht, welches Board du hast, aber wenn das so ist,
dann musst du so überprüfen, ob die Taster gedrückt sind:
if (!(PIND & (1 << PIND5))) ...
mode muss volatile Typ definiert werden, weil es in der SIGNAL() und
im Userprogramm main() parallel benutzt wird.
Wenn du in main() so wie oben keine besonderen Vorkehrungen für atomaren
Datenzugriff triffst (s. Artikel Interrupt und Doku avr-libc,
Interrupts), dann solltest du für Typ char statt int wählen. Der
Zugriff auf eine char Variable kann atomar sein.
cli() und sei() haben in SIGNAL() nichts zu suchen.
SIGNAL() ist veraltet. Man benutzt stattdessen ISR() (s. Doku avr-libc,
Interrupts)
> TCCR0 |= (1<<CS22) | (1<<CS20); //8-Bit Timer, Timer clock = system
clock/1024
In meinem Datenblatt sind in Tabelle 34 CS02 und CS00 für Prescaler 1024
angegeben.
Wenn dein AVR mit der Werkseinstellung 1 MHz läuft, wird die
Interruptroutine alle 1000000/1024/256 Hz = 3,8 Hz = 262 ms aufgerufen.
Genau nur so lange auf die Taster zu drücken bis mode = 1 (case 1) ist
und nicht weiter, wird nur Chuck Norris gelingen. Der hat so kurze
Reaktionszeiten. Normalos werden case 0 oder default bekommen.
> DDRD = 0x1C; //1 << 2 | 1 << 3 | 1 << 4;> DDRB = 0x40; //1 << 6;
Kann man gleich so schreiben:
DDRD = (1<<PD2) | (1<<PD3) | (1<<PD4);
DDRB = (1<<PB6);
Die Taster sind laut Quellcode active-high angeschlossen (s.
AVR-GCC-Tutorial. Passt die externe Beschaltung zu dem Softwarecode?
Gibt es Pulldown-Widerstände?
>holger schrieb:>> // gefährlich, weg damit>> // sei(); // Interrupts zulassen>Dann wird das mit den Timern aber nix, oder?
Wieso nicht?
Und wenn er die Taster mal entprellt und mode
nicht einfach rauf/runterzählt, dann wirds vieleicht auch
mal was mit dem switch.
Danke für eure schnellen Antworten. Ich kann euch leider nicht sagen wie
die Taster angeschlossen sind habe das so bekommen und kann das mit
meinem Wissen nicht erkennen. Hab euch deswegen mal 2 Bilder gemacht.
Außerdem habe ich den Quellcode nach euren Vorschlägen angepasst. Und
kann jetzt von mode = 0 bis zu mode = ieine hohe zahl schalten. Nur
genau 1 treff ich nicht wie mach ich das am besten das ich nur eine
Stufe weiter schalte?
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
#include<util/delay.h>
4
5
volatileintmode=0;
6
7
ISR(TIMER0_OVF_vect)
8
{
9
cli();// Interrupts nicht zulassen
10
11
if(!(PIND&(1<<PIND5)))// Up-Taste gedr¸ckt
12
mode=mode+1;
13
14
if(!(PINB&(1<<PINB7))){// Down-Taste gedr¸ckt
15
if((mode-1)!=-1){
16
mode=mode-1;
17
}
18
}
19
20
sei();// Interrupts zulassen
21
}
22
23
24
intmain(void)
25
{
26
init();
27
28
for(;;){
29
30
switch(mode){
31
case0:
32
LED1(1);
33
LED2(1);
34
LED3(1);
35
LED4(1);
36
break;
37
38
case1:
39
LED1(0);
40
LED2(0);
41
LED3(0);
42
LED4(0);
43
break;
44
45
default:
46
LED1(1);
47
LED2(0);
48
LED3(1);
49
LED4(1);
50
}
51
52
}
53
return0;/* never reached */
54
}
55
56
57
58
intinit(void){
59
//LED Outputs setzen
60
DDRD=0x1C;//1 << 2 | 1 << 3 | 1 << 4;
61
DDRB=0x40;//1 << 6;
62
//LED Outputs setzen ENDE
63
64
// Timer f¸r Tastenabfrage
65
TCCR0|=(1<<CS02)|(1<<CS00);//8-Bit Timer, Timer clock = system clock/1024
Christopher schrieb:
> Danke für eure schnellen Antworten. Ich kann euch leider nicht sagen wie> die Taster angeschlossen sind
Wie kannst du dann ein Programm, noch dazu ein so komplexes, schreiben?
Finde erst einmal heraus, ob deine Taster gegen Masse, oder gegen Vcc
schalten. Als erste Arbeitshypothese würde ich annehmen: Sie schalten
gegen Masse.
Wenn du ein Multimeter hast, kannst du zb so vorgehen:
Erst mal Spannung weg von der Schaltung. Dann das Multimeter auf Ohm
stellen und den Widerstand von allen Tasterpins zu Masse und Vcc messen.
Gibt es einen Pin, der praktisch 0 Ohm gegen Masse hat, dann schalten
die Taster auch gegen Masse. Du kannst dann einfach mal den Taster
drücken und gedrückt halten und wieder alle Pins durchmessen. Es werden
dann auch andere Pins eine Verbindung mit Masse haben.
Hast du kein Messgerät, dann würde ich die Arbeitshypothese benutzen und
mir ein einfaches(!) Testprogramm schreiben, welches:
Port auf Input
Pullup Widerstände für die Taster ein
In einer SChleife
If Tasterpin gleich 0
Led ein
else
Led aus
das dann laufen lassen und auf den taster drücken. Wenn die
Arbeitshypothese stimmt, dann leuchten die LED auf, wenn du auf dem
Taster drückst.
Und erst dann, gehts mit komplizierteren Dingen weiter.
> Außerdem habe ich den Quellcode nach euren Vorschlägen angepasst.> Und kann jetzt von mode = 0 bis zu mode = ieine hohe zahl schalten.> Nur genau 1 treff ich nicht wie mach ich das am besten das ich nur> eine Stufe weiter schalte?
Dein Code schaltet mode um 1 weiter solange die Taste gedrückt ist.
Was du brauchst, ist Code der feststellt wann der Taster seinen Zustand
wechselt und nur dann weiterschaltet. Dazu merkt man sich den momentanen
Zustand des Tasters in einer Variablen und vergleicht dann diesen
gemerkten Zustand beim nächsten ISR aufruf mit dem dann vorliegenden
Zustand. Ist er anders, dann wurde der Taster betätigt.
1
unsignedcharPrevious;
2
3
ISR(...)
4
{
5
unsignedcharNow;
6
7
if(!(PIND&(1<<...)))// Taste gedrückt?
8
Now=1;
9
else
10
Now=0;
11
12
if(Now!=Previous){// gab es eine Veränderung?
13
...machwas,TastehatZustandgewechselt
14
}
15
16
Previous=Now;// der jetzige Zustand wird gemerkt, damit er
17
// beim nächsten ISR Aufruf als alter Vergleichswert
18
// herhalten kann
19
}
Aber Achtung:
Das stellt eine Veränderung des Tastenzustands fest!
Eine Veränderung ist zb wenn du die Taste drückst. Aber es ist auch eine
Veränderung, wenn du eine gedrückte Taste wieder loslässt. Aber Gott sei
Dank hast du ja in 'Now' stehen, ob die Taste nun gedrückt ist oder
nicht. Aber das einzuflechten überlasse ich jetzt dir.
Aber stell erst mal fest, ob deine Tasten wirklich active-low sind oder
nicht.
Christopher:
> Außerdem habe ich den Quellcode nach euren Vorschlägen angepasst. Und> kann jetzt von mode = 0 bis zu mode = i eine hohe zahl schalten. Nur> genau 1 treff ich nicht wie mach ich das am besten das ich nur eine> Stufe weiter schalte?
Du könntest die Tasten sehr viel langsamer abfragen, also z.B. statt im
Abstand von Millisekunden im Abstand von Sekunden. darauf kann ein
Normalsterblicher reagieren und Loslassen, wenn mode = 1 ist bzw. die
LEDs entsprechend leuchten.
Solange du so schnell die Taste abfragst, darfst du nur einmal
Hochzählen, wenn die Taste gedrückt ist und nicht jedesmal, wenn die
Taste gedrückt bleibt und du die Abfrage wiederholst. Vor dem nächsten
Hochzählen muss die Taste wieder losgelassen werden. Das Loslassen musst
du abfragen, ähnlich wie du oben das Drücken abfragst.
Noch sicherer wird Drücken/Loslassen, wenn du das Prellen der Taste
berücksichtigst. Z.B. wenn du programmierst, dass die Taste mindestens
ca. 20 Millisekunden gedrückt oder losgelassen sein muss, damit eine
Aktion ausgelöst wird. Verfahren dazu stehen im Artikel Entprellung.
festgestellt, dass die Taster active-low sein müssen, da dieser code ja
funktioniert.
Ich versuch jetzt schnell noch die Zustandswechsel einzubauen wie es
Karl Heinz vorgeschlagen hat.
Danke
Wenn man dem Aufdruck auf der Platine in den Fotos nachgeht, kommt man
zu dem Schaltplan im Anhang.
Die Taster sind darin active-low (s. AVR-GCC-Tutorial) angeschlossen
und auf der Platine sind keine externen Pull-up-Widerstände vorgesehen.
Es fehlt in deinem Programm also die notwendige Initialisierung der
internen Pull-up-Widerstände, die den PIN im losgelassenen Zustand auf
log. HIGH ziehen.
Christopher schrieb:
> Habe jetzt mit diesem Code:>>
1
intmain(void)
2
>{
3
>LED1(1);
4
>/* insert your hardware initialization here */
5
>for(;;){
6
>if(!(PIND&(1<<PIND5)))// Up-Taste gedr¸ckt
7
>LED1(1);
8
>
9
>if(!(PINB&(1<<PINB7))){// Down-Taste gedr¸ckt
10
>LED1(0);
11
>}
12
>}
13
>return0;/* never reached */
14
>}
>> festgestellt, dass die Taster active-low sein müssen, da dieser code ja> funktioniert.
Füg da ganz schnell noch ein
PORTD |= ( 1 << PORTD5 );
PORTB |= ( 1 << PORTB7 );
ganz am Anfang ein, um die Pullup Widerstände für die Tasten
einzuschalten. Ansonsten hattest du einfach nur Glück mit deinen Tasten.
Christopher schrieb:
> Funktioniert jetzt alles bestens.
Für praktische Zwecke mag das schon ausreichen.
Aber willst du deinem Benutzer wirklich zumuten, dass er 300 mal auf
Down drücken muss, wenn er 300 mal auf Up gedrückt hat?
> if(Now_taster2 == 1 && Now_taster2 != Previous_taster2) {> mode += 1;> }
Da würde ich auch noch eine Sicherung einbauen, so dass mode nicht zu
gross werden kann.
Ja so einen Schutz sollte man dann vll noch einbauen. Aber das war jetzt
mein erstes mal Microcontrollerprogrammieren um einfach mal einen
Einstieg zu bekommen.
Ansonsten mach ich eig immer nur Java, C#, PHP,... und nicht so nah an
der Hardware.
Als nächstes werde ich mich mal um die RS232 Schnittstelle kümmern. Mal
sehen wo ich da anfangen kann.