Forum: Mikrocontroller und Digitale Elektronik Tasterroutinen Problem in C


von Taser (Gast)


Lesenswert?

Hallo Leute versuche vergebens meine Taster am Avr zum laufen zu 
bringen. Es scheitert schon beim Compilieren.Könnte jemand da vielleicht 
netterweise mal drübergucken oder mir nen heissen Tipp geben?

Hier mein code:
Main Code
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
 
4
/* Wir haben 3 Taster, in taster.h wird also angepasst zu
5
#define NUM_TASTER 3
6
*/
7
#include "taster.h"
8
9
/* 
10
 * Die Taster-Ports sind hartcodiert:
11
 * #0 --> PortB.4
12
 * #1 --> PortC.1
13
 * #2 --> PortD.2
14
 */
15
16
/* Bei 1MHz Grundtakt läuft Timer0 alle 256µs über.
17
 * Um auf rund 10ms zu kommen, rufen wir get_taster nur
18
 * jedes 39. mal auf. */
19
SIGNAL (SIG_OVERFLOW0)
20
{
21
    static unsigned char count_ovl0;
22
    unsigned char ovl0 = count_ovl0+1;
23
24
    if (ovl0 >= 39)
25
    {
26
        get_taster (0, PINB & (1<<PB4));
27
        get_taster (1, PINC & (1<<PC1));
28
        get_taster (2, PIND & (1<<PD2));
29
        
30
        ovl0 = 0;
31
    }
32
33
    count_ovl0 = ovl0;
34
}
35
36
void ioinit()
37
{
38
    /* Taster sind Input (default nach RESET) */
39
    /* An den Tastern die PullUps aktivieren */
40
    PORTB |= 1 << PB4;
41
    PORTC |= 1 << PC1;
42
    PORTD |= 1 << PD2;
43
 
44
    /* Timer0 ohne Prescaler starten */
45
    TCCR0 = 1 << CS00;
46
 
47
    /* Timer0-Overflow-Interrupt aktivieren */
48
    TIMSK |= (1 << TOIE0);
49
}
50
51
int main()
52
{
53
    ioinit();
54
 
55
    /* Taster konfigurieren (#define NUM_TASTER 3 in taster.h) */
56
    tasten[0].mode = TM_SHORT;
57
    tasten[1].mode = TM_LONG;
58
    tasten[2].mode = TM_REPEAT;
59
 
60
    /* Interrupts global aktivieren */
61
    sei();
62
63
    /* Hauptschleife */
64
    while (1)
65
    {
66
        signed char tast = taster;
67
  
68
        switch (tast)
69
        {
70
            default:
71
            case NO_TASTER:
72
                break;
73
    
74
            case 0:
75
                /* Taster 0 */
76
                break;
77
    
78
            case 1:
79
                /* Taster 1 kurz gedrueckt */
80
                break;
81
    
82
            case 1+TASTER_LONG:
83
                /* Taster 1 lange gedrueckt */
84
                break;
85
    
86
            case 2:
87
                /* Taster 2 */
88
                break;
89
        }
90
  
91
        if (tast != NO_TASTER)
92
            taster = NO_TASTER;
93
94
        /* ********************************** */
95
        /* Weiterer Code in der Hauptschleife */
96
    }
97
}


Taster.h
1
#ifndef _TASTER_H_
2
#define _TASTER_H_
3
4
/* Wert fuer taster, wenn nichts gedrückt wurde */
5
#define NO_TASTER (-1)
6
7
/* Maximale Anzahl der Taster */
8
#define NUM_TASTER 4
9
10
/* 0 --> Taster sind low-aktiv */
11
/* 1 --> Taster sind high-aktiv */
12
#define TASTER_LEVEL 0
13
14
/* Dieser Offset wird zur Tasten-Nummer addiert, */
15
/* wenn eine Taste lange gedrückt wurde */
16
#define TASTER_LONG 16
17
18
/* Zeitverzögerung (in Ticks), bis zum Beginn von auto-repeat */
19
#define TASTER_REPEAT_DELAY (60)
20
21
/* Zeitverzögerung (in Ticks), bis zum nächsten auto-repeat */
22
#define TASTER_REPEAT       (15)
23
24
/* Ab dieser Dauer wird der Tastendruck 'lange' */
25
#define TASTER_DELAY_LONG   (80)
26
27
typedef struct 
28
{
29
    /* private */
30
    const unsigned char delay, old;
31
32
    /* Mode des Tasters aus: TM_SHORT, TM_LONG, TM_REPEAT */
33
    unsigned char mode;
34
} taste_t;
35
36
extern taste_t tasten[];
37
38
/* In dieser Variable kann abgefragt werden, welche Taste gedrückt wurde.
39
   --> NO_TASTER:
40
       es wurde nichts gedrückt
41
   --> 0..NUM_TASTER-1:
42
       Taster Numero 'taster' wurde (kurz) gedrückt
43
   --> TASTER_LONG ... TASTER_LONG + NUM_TASTER-1:
44
       Taster Numero 'taster-TASTER_LONG' wurde lange gedrückt
45
*/   
46
extern volatile signed char taster;
47
48
extern void get_taster (const unsigned char num, unsigned char tast);
49
50
enum
51
{
52
    TM_SHORT,
53
    TM_LONG,
54
    TM_REPEAT
55
};
56
57
#endif /* _TASTER_H_ */


Taster.c
1
#include "taster.h"
2
3
volatile signed char taster = NO_TASTER;
4
5
taste_t tasten[NUM_TASTER];
6
7
/*
8
 * Aktualisiert 'taster', falls taster==NO_TASTER
9
 * num:  Nummer des Tasters von 0...NUM_TASTER-1
10
 * TASTER_LEVEL=1:
11
 *    tast: ==0 falls der Taster gerade nicht gedrueckt wird
12
 *    tast: !=0 falls der Taster gerade gedrueckt wird
13
 * TASTER_LEVEL=0:
14
 *    tast: !=0 falls der Taster gerade nicht gedrueckt wird
15
 *    tast: ==0 falls der Taster gerade gedrueckt wird
16
 */
17
void get_taster (const unsigned char num, unsigned char tast) 
18
{
19
    const taste_t * const ptast = & tasten[num];
20
    const unsigned char taster_old = ptast->old;
21
    unsigned char pressed, press, release, mode, delay;
22
23
#if TASTER_LEVEL
24
    tast = !!tast;
25
#else
26
    tast = !tast;
27
#endif
28
 
29
    /* Was wurde gedrueckt/losgelassen...? */
30
 
31
    /* Taster bleibt gedrueckt */
32
    pressed =  taster_old &  tast;
33
    /* Taster neu gedrueckt */
34
    press   = ~taster_old &  tast;
35
    /* Taster losgelassen */
36
    release =  taster_old & ~tast;
37
38
    /* ptast->old = tast;
39
     * Der Cast dient zum Wegwerfen des 'const' Qualifiers. 
40
     * Die Komponente wurde als 'const' qualifiziert, 
41
     * damit es einen Fehler gibt, wenn versucht wird,
42
     * ihren Wert von aussen zu aendern (private). */
43
    *((unsigned char *) & ptast->old) = tast;
44
 
45
    tast = NO_TASTER;
46
 
47
    mode  = ptast->mode;
48
    delay = ptast->delay;
49
 
50
    if (press)
51
    {
52
        if (mode != TM_LONG)
53
            tast = num;
54
   
55
        delay = 0;
56
    }
57
    else if (pressed)
58
    {
59
        if (delay < 0xfe)
60
            delay++;
61
    }
62
    else if (release)
63
    {
64
        if (mode == TM_LONG && delay != 0xff)
65
            tast = num;
66
    }
67
 
68
    if (mode == TM_LONG)
69
    {
70
        if (delay == TASTER_DELAY_LONG)
71
        {
72
            tast = TASTER_LONG + num;
73
            delay = 0xff;
74
        }
75
    }
76
    else if (mode == TM_REPEAT)
77
    {
78
        if (delay == TASTER_REPEAT_DELAY)
79
        {
80
            tast = num;
81
            delay = TASTER_REPEAT_DELAY - TASTER_REPEAT;
82
        }
83
    }
84
85
    if (taster == NO_TASTER)
86
        taster = tast;
87
  
88
    /* siehe oben */
89
    *((unsigned char *) & ptast->delay) = delay;
90
}

Ich bekomme den Fehler beim Compilierent dass sowolh Taster,Tasten und 
get_taster nicht definiert sind? Habe ich jedoch gemacht?

von Karl H. (kbuchegg)


Lesenswert?

Taser schrieb:

> Ich bekomme den Fehler beim Compilierent dass sowolh Taster,Tasten und
> get_taster nicht definiert sind?

Das stellt aber nicht der Compiler fest, sondern der Linker.

> Habe ich jedoch gemacht?

Ja hast da.
Aber weiss deine Entwicklungsumgebung auch, dass Tester.c zum Projekt 
mit dazugehört und daher compiliert und ins EXE mit eingelinkt werden 
muss?

von Taser (Gast)


Lesenswert?

Ja ich hab das c.File sowie das .h File in den dazugehörigen Ordner im 
AVR studio drinnen.



Gruß

von Karl H. (kbuchegg)


Lesenswert?

Taser schrieb:
> Ja ich hab das c.File sowie das .h File in den dazugehörigen Ordner im
> AVR studio drinnen.

Beobachte mal das Output Fenster.
Welche Kommandos werden vor der Fehlermeldung ausgeführt?
Taucht da Tasten.c auf?

(mach am besten einen Screenshot, Output Fenster dabei so gross wie 
möglich machen)

von Taser (Gast)


Angehängte Dateien:

Lesenswert?

Jap das c. File taucht auf ist aber auch im Source Ordner.

von Karl H. (kbuchegg)


Lesenswert?

Ist furchtbar schlecht zu lesen. JPG ist bei Bilder, bei denen es in 
erster Linie auf den Text ankommt, keine gute Wahl.

Aber ich kann in der 2.ten mit einem grünen Punkt markierten Zeile die 
taster.o nicht finden. Die sollte aber dort sein.

Nimm tester.c noch mal aus dem Projekt raus und fügs neu ein.

von Taser (Gast)


Angehängte Dateien:

Lesenswert?

So hab nochmal ein SS gemacht und jetzt die taster.c nochmal eingefügt.

von Karl H. (kbuchegg)


Lesenswert?

Wieso hast du unter 'Other Files' ein makefile eingetragen?
Benutzt du ein externes makefile?

Wenn ja, dann muss taster.c dort auch eingetragen sein, was es offenbar 
nicht ist.
Wenn es keinen wirklichen Grund für ein externes makefile gibt, dann 
schalte zurück auf 'AVR-Studio generiert das makefile selber'.

von Taser (Gast)


Lesenswert?

Nein ich benutze kein externes Makefile- das hat sich wohl da drinnen 
verirrt.

Gruß

von Karl H. (kbuchegg)


Lesenswert?

Taser schrieb:
> Nein ich benutze kein externes Makefile- das hat sich wohl da drinnen
> verirrt.

Tja. Aber irgendwo muss es herkommen.
Fakt ist, dass dein taster.o nicht mit eingelinkt wird. Sieht man 
deutlich an der Commandline. taster.o taucht dort nirgends auf.

Wird taster.c neu compiliert, wenn du im Quellcode was veränderst?

von Karl H. (kbuchegg)


Lesenswert?

Wenn alle Stricke reissen und du nichts rausfindest, dann Plan B 
starten:

Neues AVR-Studio Projekt anlegen. Mega8 auswählen.
Die Source Code Dateien aufs Projektverzeichnis kopieren und mit 'Add 
Source Files' hinzufügen. Das Default-generierte File rauswerfen und 
Projekt builden lassen.

Plan B geht oft schneller als das Rausfinden, wie und wo du das alte 
Projekt verkonfiguriert hast.

von Taser (Gast)


Lesenswert?

Danke!
Funktioniert jetzt!!!

von Taser (Gast)


Lesenswert?

Ich hab gestern nochmals vergeblich probiert die Taster zum Laufen zu 
bringen:
Folgender Code wurde verwendet und die entsprechende lcd.h sowie lcd.c 
wurden im Source Ornder neu angeleget um etwaige Fehler wie zuvor zu 
vermeiden.
Der Code sieht nun so aus:
1
//  ATMega8 LCD Driver
2
//
3
//  (C) 2009 Radu Motisan , radu.motisan@gmail.com
4
//  www.pocketmagic.net
5
//  All rights reserved.
6
//
7
//  test.c: sample test for the HD44780 LCD functions
8
//  For more details visit the website.
9
10
11
#include <avr/io.h>
12
#include <avr/interrupt.h>
13
 
14
/* Wir haben 3 Taster, in taster.h wird also angepasst zu
15
#define NUM_TASTER 3
16
*/
17
#include "taster.h"
18
#include "lcd.h"
19
/* 
20
 * Die Taster-Ports sind hartcodiert:
21
 * #0 --> PortB.4
22
 * #1 --> PortC.1
23
 * #2 --> PortD.2
24
 */
25
26
/* Bei 1MHz Grundtakt läuft Timer0 alle 256µs über.
27
 * Um auf rund 10ms zu kommen, rufen wir get_taster nur
28
 * jedes 39. mal auf. */
29
SIGNAL (SIG_OVERFLOW0)
30
{
31
    static unsigned char count_ovl0;
32
    unsigned char ovl0 = count_ovl0+1;
33
34
    if (ovl0 >= 39)
35
    {
36
        get_taster (0, PINB & (1<<PB4));
37
        
38
        
39
        ovl0 = 0;
40
    }
41
42
    count_ovl0 = ovl0;
43
}
44
45
void ioinit()
46
{
47
    /* Taster sind Input (default nach RESET) */
48
    /* An den Tastern die PullUps aktivieren */
49
    PORTB |= 1 << PB4;
50
    
51
 
52
    /* Timer0 ohne Prescaler starten */
53
    TCCR0 = 1 << CS00;
54
 
55
    /* Timer0-Overflow-Interrupt aktivieren */
56
    TIMSK |= (1 << TOIE0);
57
}
58
59
int main()
60
{  
61
  lcd_init();
62
    ioinit();
63
 
64
    /* Taster konfigurieren (#define NUM_TASTER 3 in taster.h) */
65
    tasten[0].mode = TM_SHORT;
66
    tasten[1].mode = TM_LONG;
67
    tasten[2].mode = TM_REPEAT;
68
 
69
    /* Interrupts global aktivieren */
70
    sei();
71
72
    /* Hauptschleife */
73
    while (1)
74
    {
75
        signed char tast = taster;
76
  
77
        switch (tast)
78
        {
79
            default:
80
            case NO_TASTER:
81
                break;
82
    
83
            case 0:
84
                /* Taster 0 */
85
                break;
86
    
87
            case 1:
88
               lcd_string2("Hello World! ");
89
                break;
90
    
91
            case 1+TASTER_LONG:
92
                /* Taster 1 lange gedrueckt */
93
                break;
94
    
95
            case 2:
96
                /* Taster 2 */
97
                break;
98
        }
99
  
100
        if (tast != NO_TASTER)
101
            taster = NO_TASTER;
102
103
        /* ********************************** */
104
        /* Weiterer Code in der Hauptschleife */
105
return 0;
106
    }
107
}
Ich hab jetzt einfach mal einen Output für das Lcd in die Switch 
Anweisung geschrieben.
Angezeigt am Lcd bekomme ich nur Balken. Der Taster ist ein uTaster 
ausgelötet aus dem Bedienpanel einer alten Stereoanlage  und wurde auf 
Funktionialität mit dem Durchgangsprüfer geprüft. Ergebnis: Taster funzt
Ich habe den Taster so verschaltet wie im uC.net Tutorial, ich glaube 
das heisst low-active oder so.

Ich bin echt ratlos was dieses Problem betrifft und ich hoffe erneut , 
dass ein Netter "Mituser" sich meiner erbarmt und mir ein bisschen auf 
die Sprünge hilft.
Vielen Dank

von Taser (Gast)


Lesenswert?

keiner eine Idee?

von rfr (Gast)


Lesenswert?

Nur balken heisst oftt, dass das LCD falsch angeschlossen ist, oder dass 
die Kontrastspannung falsch ist.

Gruss

Robert

von Taser (Gast)


Lesenswert?

Nein das Lcd funktioniert normal - nur mit diesem code nicht...

von Jochen S. (schiffner)


Lesenswert?

Hallo,
ein Balken im LCD bedeutet entweder falsche Kontrastspannung oder nicht 
richtig initialisiert. was passiert denn bei deinem lcd_init()? Du hast 
nirgends deine Ports fürs LCD definiert, is das in lcd_init() mit 
drinnen.

von Taser (Gast)


Lesenswert?

doch die sind wie oben geschrieben in der lcd.h bzw lcd.c drinnen .
Es ist kein schwarze Balken sondern Ein Balken der kurz blinkt und dan 
ein strich wird und das ganze geht halt ewig.

Gruß

von Jochen S. (schiffner)


Lesenswert?

wenn der balken weg geht und ein Strich an der ersten Stelle kommt, 
scheint das Initialisieren zu funktionieren. das Blinken macht der 
ständig oder nur wenn der taster gedrückt wird?

von Taser (Gast)


Lesenswert?

der macht das ständig :(

von kalle (Gast)


Lesenswert?

wenn ich das richtig sehe, beendest du die schleife nach dem ersten 
durchlauf, wodurch ja eigentlich das prog immer wieder neu gestartet und 
alles neu initialisiert wird. also das return 0; an der stelle sollte 
fehl am platz sein.

von Taser (Gast)


Lesenswert?

Ok beim weglassen des return 0; ist auch nichts passiert.
Kann es sein dass AVR Studio Probleme macht und dass der Quelltext bis 
auf das return 0; i.0 ist?


Gruß

von Taser (Gast)


Lesenswert?

Gehören die Taster vielleicht entprellt?

Gruß

von Jochen S. (schiffner)


Lesenswert?

da du deine Taster über nen Timer abfragst und der Balken immer kommt 
und geht auch ohne gedrückten Taster, wird das nicht an prellenden 
Tastern liegen. Sieht wirklich so aus als würde dein LCD ständig neu 
initialisiert (return 0, is ja jetzt weg, oder?). Schreib mal in einen 
case eine Endlosschleife, wenn das Programm da rein kommt sollte der 
Blaken dauerhaft wegbleiben.

von Taser (Gast)


Lesenswert?

Es funktioniert auch mit einer Endlosschleife nicht...:(
Mit leds klappts auch nicht? Schön langsam bin ich mit meinem Latein am 
Ende ...

Gruß

von Peter D. (peda)


Lesenswert?

Taser schrieb:
> Es funktioniert auch mit einer Endlosschleife nicht...:(
> Mit leds klappts auch nicht? Schön langsam bin ich mit meinem Latein am
> Ende ...


Tastenentprellung:

http://www.mikrocontroller.net/articles/Entprellung#Komfortroutine_.28C_f.C3.BCr_AVR.29


LCD-Ansteuerung:

http://www.mikrocontroller.net/attachment/30300/lcd_drv.zip


Dann funktionierts auch.


Peter

von Taser (Gast)


Lesenswert?

wobei ich hier   i = key_state ^ ~KEY_PIN;  z.B: PB4 statt KEY_PIN 
einsetzte oder?
Bin Anfänger darum :)

Danke für den Link!!!!

Gruß

von Peter D. (peda)


Lesenswert?

Taser schrieb:
> wobei ich hier   i = key_state ^ ~KEY_PIN;  z.B: PB4 statt KEY_PIN
> einsetzte oder?

Da steht doch:
1
#define KEY_PIN         PINB

> Bin Anfänger darum :)

Was ein #define ist, solltest Du aber erstmal lernen.


Peter

von Taser (Gast)


Lesenswert?

Soweit ich jetzt begriffen habe werden in Ihrem Programm PB0-PB2 als 
Eingang für die Taster verwendet Richtig?


Gruß

von Karl H. (kbuchegg)


Lesenswert?

Für dich sind diese #define interessant
1
#define KEY_DDR         DDRB
2
#define KEY_PORT        PORTB
3
#define KEY_PIN         PINB
4
#define KEY0            0
5
#define KEY1            1
6
#define KEY2            2
7
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2)
8
 
9
#define REPEAT_MASK     (1<<KEY1 | 1<<KEY2)       // repeat: key1, key2

KEY_DDR, KEY_PORT, KEY_PIN  legen fast an welchem Port sich die Tasten 
befinden.
KEY0, KEY1, KEY2 (und wenn du brauchst KEY3, KEY4, KEY5, KEY6 und KEY7) 
legen fest welche Pins an diesem Port benutzt werden, um Tasten 
auszulesen.

ALL_KEYS ist die Zusammenfassung aller definierten KEYx. Wenn du also 
noch ein zusätzliches KEY3 hast, dann nimmst du das dort mit auf
1
#define KEY2            2
2
#define KEY3            5    // der vierte Taster liegt an Pin 5
3
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2 | 1<<KEY3)

und die REPEAT_MASK schlussendlich legt fest, auf welche der Taster ein 
automatischer Autorepeat gelegt werden soll.

Für die Tastenmakros kann man auch schöne, anwendungsbezogene Namen 
nehmen. Die entsprechenden #define werden nur in der Auswertung benutzt. 
Die eigentliche Entprellerei ist davon unbeeindruckt.
1
#define KEY_DDR         DDRB
2
#define KEY_PORT        PORTB
3
#define KEY_PIN         PINB
4
5
#define KEY_LEFT        2    // Taster an PB2 ist 'Links'
6
#define KEY_RIGHT       1    // Tastre an PB1 ist 'Rechts'
7
#define KEY_ENTER       5    // Taster an PB5 ist 'Enter'
8
#define ALL_KEYS        (1<<KEY_LEFT | 1<<KEY_RIGHT | 1<<KEY_ENTER)
9
 
10
#define REPEAT_MASK     (1<<KEY_LEFT | 1<<KEY_RIGHT)

Dann sieht eine Auswertung zb so aus
1
  while(1){
2
    if( get_key_press( 1<<KEY_LEFT ) || get_key_rpt( 1<<KEY_LEFT ))
3
    {
4
       // Cursor nach links bewegen
5
    }
6
7
    else if( get_key_press( 1<<KEY_RIGHT ) || get_key_rpt( 1<<KEY_RIGHT ))
8
    {
9
       // Cursor nach rechts bewegen
10
    }
11
 
12
    else if( get_key_press( 1<<KEY_RIGHT ))
13
    {
14
       // Benutzer hat Eingabe bestätigt
15
    }
16
  }

und das hat dann schon eine eigene selbstdokumentierende Code-Qualität, 
die zusätzliche Kommentare überflüssig macht.

von Taser (Gast)


Lesenswert?

Vielen Dank!
Jetzt ist mir einiges klar geworden.
Sind doch einige kompetente und hilfbereite Leute hier im Forum!

Vielen Dank nochmal!

Gruß

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.