mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Tasterroutinen Problem in C


Autor: Taser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
#include <avr/io.h>
#include <avr/interrupt.h>
 
/* Wir haben 3 Taster, in taster.h wird also angepasst zu
#define NUM_TASTER 3
*/
#include "taster.h"

/* 
 * Die Taster-Ports sind hartcodiert:
 * #0 --> PortB.4
 * #1 --> PortC.1
 * #2 --> PortD.2
 */

/* Bei 1MHz Grundtakt läuft Timer0 alle 256µs über.
 * Um auf rund 10ms zu kommen, rufen wir get_taster nur
 * jedes 39. mal auf. */
SIGNAL (SIG_OVERFLOW0)
{
    static unsigned char count_ovl0;
    unsigned char ovl0 = count_ovl0+1;

    if (ovl0 >= 39)
    {
        get_taster (0, PINB & (1<<PB4));
        get_taster (1, PINC & (1<<PC1));
        get_taster (2, PIND & (1<<PD2));
        
        ovl0 = 0;
    }

    count_ovl0 = ovl0;
}

void ioinit()
{
    /* Taster sind Input (default nach RESET) */
    /* An den Tastern die PullUps aktivieren */
    PORTB |= 1 << PB4;
    PORTC |= 1 << PC1;
    PORTD |= 1 << PD2;
 
    /* Timer0 ohne Prescaler starten */
    TCCR0 = 1 << CS00;
 
    /* Timer0-Overflow-Interrupt aktivieren */
    TIMSK |= (1 << TOIE0);
}

int main()
{
    ioinit();
 
    /* Taster konfigurieren (#define NUM_TASTER 3 in taster.h) */
    tasten[0].mode = TM_SHORT;
    tasten[1].mode = TM_LONG;
    tasten[2].mode = TM_REPEAT;
 
    /* Interrupts global aktivieren */
    sei();

    /* Hauptschleife */
    while (1)
    {
        signed char tast = taster;
  
        switch (tast)
        {
            default:
            case NO_TASTER:
                break;
    
            case 0:
                /* Taster 0 */
                break;
    
            case 1:
                /* Taster 1 kurz gedrueckt */
                break;
    
            case 1+TASTER_LONG:
                /* Taster 1 lange gedrueckt */
                break;
    
            case 2:
                /* Taster 2 */
                break;
        }
  
        if (tast != NO_TASTER)
            taster = NO_TASTER;

        /* ********************************** */
        /* Weiterer Code in der Hauptschleife */
    }
}


Taster.h
#ifndef _TASTER_H_
#define _TASTER_H_

/* Wert fuer taster, wenn nichts gedrückt wurde */
#define NO_TASTER (-1)

/* Maximale Anzahl der Taster */
#define NUM_TASTER 4

/* 0 --> Taster sind low-aktiv */
/* 1 --> Taster sind high-aktiv */
#define TASTER_LEVEL 0

/* Dieser Offset wird zur Tasten-Nummer addiert, */
/* wenn eine Taste lange gedrückt wurde */
#define TASTER_LONG 16

/* Zeitverzögerung (in Ticks), bis zum Beginn von auto-repeat */
#define TASTER_REPEAT_DELAY (60)

/* Zeitverzögerung (in Ticks), bis zum nächsten auto-repeat */
#define TASTER_REPEAT       (15)

/* Ab dieser Dauer wird der Tastendruck 'lange' */
#define TASTER_DELAY_LONG   (80)

typedef struct 
{
    /* private */
    const unsigned char delay, old;

    /* Mode des Tasters aus: TM_SHORT, TM_LONG, TM_REPEAT */
    unsigned char mode;
} taste_t;

extern taste_t tasten[];

/* In dieser Variable kann abgefragt werden, welche Taste gedrückt wurde.
   --> NO_TASTER:
       es wurde nichts gedrückt
   --> 0..NUM_TASTER-1:
       Taster Numero 'taster' wurde (kurz) gedrückt
   --> TASTER_LONG ... TASTER_LONG + NUM_TASTER-1:
       Taster Numero 'taster-TASTER_LONG' wurde lange gedrückt
*/   
extern volatile signed char taster;

extern void get_taster (const unsigned char num, unsigned char tast);

enum
{
    TM_SHORT,
    TM_LONG,
    TM_REPEAT
};

#endif /* _TASTER_H_ */


Taster.c
#include "taster.h"

volatile signed char taster = NO_TASTER;

taste_t tasten[NUM_TASTER];

/*
 * Aktualisiert 'taster', falls taster==NO_TASTER
 * num:  Nummer des Tasters von 0...NUM_TASTER-1
 * TASTER_LEVEL=1:
 *    tast: ==0 falls der Taster gerade nicht gedrueckt wird
 *    tast: !=0 falls der Taster gerade gedrueckt wird
 * TASTER_LEVEL=0:
 *    tast: !=0 falls der Taster gerade nicht gedrueckt wird
 *    tast: ==0 falls der Taster gerade gedrueckt wird
 */
void get_taster (const unsigned char num, unsigned char tast) 
{
    const taste_t * const ptast = & tasten[num];
    const unsigned char taster_old = ptast->old;
    unsigned char pressed, press, release, mode, delay;

#if TASTER_LEVEL
    tast = !!tast;
#else
    tast = !tast;
#endif
 
    /* Was wurde gedrueckt/losgelassen...? */
 
    /* Taster bleibt gedrueckt */
    pressed =  taster_old &  tast;
    /* Taster neu gedrueckt */
    press   = ~taster_old &  tast;
    /* Taster losgelassen */
    release =  taster_old & ~tast;

    /* ptast->old = tast;
     * Der Cast dient zum Wegwerfen des 'const' Qualifiers. 
     * Die Komponente wurde als 'const' qualifiziert, 
     * damit es einen Fehler gibt, wenn versucht wird,
     * ihren Wert von aussen zu aendern (private). */
    *((unsigned char *) & ptast->old) = tast;
 
    tast = NO_TASTER;
 
    mode  = ptast->mode;
    delay = ptast->delay;
 
    if (press)
    {
        if (mode != TM_LONG)
            tast = num;
   
        delay = 0;
    }
    else if (pressed)
    {
        if (delay < 0xfe)
            delay++;
    }
    else if (release)
    {
        if (mode == TM_LONG && delay != 0xff)
            tast = num;
    }
 
    if (mode == TM_LONG)
    {
        if (delay == TASTER_DELAY_LONG)
        {
            tast = TASTER_LONG + num;
            delay = 0xff;
        }
    }
    else if (mode == TM_REPEAT)
    {
        if (delay == TASTER_REPEAT_DELAY)
        {
            tast = num;
            delay = TASTER_REPEAT_DELAY - TASTER_REPEAT;
        }
    }

    if (taster == NO_TASTER)
        taster = tast;
  
    /* siehe oben */
    *((unsigned char *) & ptast->delay) = delay;
}

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

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

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

Autor: Taser (Gast)
Datum:

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



Gruß

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

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

Autor: Taser (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Jap das c. File taucht auf ist aber auch im Source Ordner.

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

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

Autor: Taser (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
So hab nochmal ein SS gemacht und jetzt die taster.c nochmal eingefügt.

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

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

Autor: Taser (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein ich benutze kein externes Makefile- das hat sich wohl da drinnen 
verirrt.

Gruß

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

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

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

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

Autor: Taser (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke!
Funktioniert jetzt!!!

Autor: Taser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
//  ATMega8 LCD Driver
//
//  (C) 2009 Radu Motisan , radu.motisan@gmail.com
//  www.pocketmagic.net
//  All rights reserved.
//
//  test.c: sample test for the HD44780 LCD functions
//  For more details visit the website.


#include <avr/io.h>
#include <avr/interrupt.h>
 
/* Wir haben 3 Taster, in taster.h wird also angepasst zu
#define NUM_TASTER 3
*/
#include "taster.h"
#include "lcd.h"
/* 
 * Die Taster-Ports sind hartcodiert:
 * #0 --> PortB.4
 * #1 --> PortC.1
 * #2 --> PortD.2
 */

/* Bei 1MHz Grundtakt läuft Timer0 alle 256µs über.
 * Um auf rund 10ms zu kommen, rufen wir get_taster nur
 * jedes 39. mal auf. */
SIGNAL (SIG_OVERFLOW0)
{
    static unsigned char count_ovl0;
    unsigned char ovl0 = count_ovl0+1;

    if (ovl0 >= 39)
    {
        get_taster (0, PINB & (1<<PB4));
        
        
        ovl0 = 0;
    }

    count_ovl0 = ovl0;
}

void ioinit()
{
    /* Taster sind Input (default nach RESET) */
    /* An den Tastern die PullUps aktivieren */
    PORTB |= 1 << PB4;
    
 
    /* Timer0 ohne Prescaler starten */
    TCCR0 = 1 << CS00;
 
    /* Timer0-Overflow-Interrupt aktivieren */
    TIMSK |= (1 << TOIE0);
}

int main()
{  
  lcd_init();
    ioinit();
 
    /* Taster konfigurieren (#define NUM_TASTER 3 in taster.h) */
    tasten[0].mode = TM_SHORT;
    tasten[1].mode = TM_LONG;
    tasten[2].mode = TM_REPEAT;
 
    /* Interrupts global aktivieren */
    sei();

    /* Hauptschleife */
    while (1)
    {
        signed char tast = taster;
  
        switch (tast)
        {
            default:
            case NO_TASTER:
                break;
    
            case 0:
                /* Taster 0 */
                break;
    
            case 1:
               lcd_string2("Hello World! ");
                break;
    
            case 1+TASTER_LONG:
                /* Taster 1 lange gedrueckt */
                break;
    
            case 2:
                /* Taster 2 */
                break;
        }
  
        if (tast != NO_TASTER)
            taster = NO_TASTER;

        /* ********************************** */
        /* Weiterer Code in der Hauptschleife */
return 0;
    }
}

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

Autor: Taser (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
keiner eine Idee?

Autor: rfr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nur balken heisst oftt, dass das LCD falsch angeschlossen ist, oder dass 
die Kontrastspannung falsch ist.

Gruss

Robert

Autor: Taser (Gast)
Datum:

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

Autor: Jochen S. (schiffner)
Datum:

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

Autor: Taser (Gast)
Datum:

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

Autor: Jochen S. (schiffner)
Datum:

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

Autor: Taser (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
der macht das ständig :(

Autor: kalle (Gast)
Datum:

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

Autor: Taser (Gast)
Datum:

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

Autor: Taser (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gehören die Taster vielleicht entprellt?

Gruß

Autor: Jochen S. (schiffner)
Datum:

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

Autor: Taser (Gast)
Datum:

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

Gruß

Autor: Peter Dannegger (peda)
Datum:

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


LCD-Ansteuerung:

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


Dann funktionierts auch.


Peter

Autor: Taser (Gast)
Datum:

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

Autor: Peter Dannegger (peda)
Datum:

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

Da steht doch:
#define KEY_PIN         PINB

> Bin Anfänger darum :)

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


Peter

Autor: Taser (Gast)
Datum:

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


Gruß

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

Bewertung
0 lesenswert
nicht lesenswert
Für dich sind diese #define interessant
#define KEY_DDR         DDRB
#define KEY_PORT        PORTB
#define KEY_PIN         PINB
#define KEY0            0
#define KEY1            1
#define KEY2            2
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2)
 
#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
#define KEY2            2
#define KEY3            5    // der vierte Taster liegt an Pin 5
#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.
#define KEY_DDR         DDRB
#define KEY_PORT        PORTB
#define KEY_PIN         PINB

#define KEY_LEFT        2    // Taster an PB2 ist 'Links'
#define KEY_RIGHT       1    // Tastre an PB1 ist 'Rechts'
#define KEY_ENTER       5    // Taster an PB5 ist 'Enter'
#define ALL_KEYS        (1<<KEY_LEFT | 1<<KEY_RIGHT | 1<<KEY_ENTER)
 
#define REPEAT_MASK     (1<<KEY_LEFT | 1<<KEY_RIGHT)

Dann sieht eine Auswertung zb so aus
  while(1){
    if( get_key_press( 1<<KEY_LEFT ) || get_key_rpt( 1<<KEY_LEFT ))
    {
       // Cursor nach links bewegen
    }

    else if( get_key_press( 1<<KEY_RIGHT ) || get_key_rpt( 1<<KEY_RIGHT ))
    {
       // Cursor nach rechts bewegen
    }
 
    else if( get_key_press( 1<<KEY_RIGHT ))
    {
       // Benutzer hat Eingabe bestätigt
    }
  }

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

Autor: Taser (Gast)
Datum:

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

Vielen Dank nochmal!

Gruß

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.