Forum: Compiler & IDEs Taster abfragen UND dann.


von Björn (Gast)


Lesenswert?

Hallo!

Ich habe folgende Frage, auf deren Lösung ich einfach nicht komme:

Ich habe einen Taster an PORTC angeschlossen. Nun soll auf dem Display 
die Anzahl der Tastendrücke (Zählvariable: iMessung) angezeigt werden.

z.B. 1x Drücken = "Messung-1", 3x Drücken = "Messung-3" bis Messung-5.

Zur Displayansteuerung verwendete ich Peter Fleury's Library.
Mein Display zeigt einfach nicht den Wert der Variablen iMessung an. 
Woran liegt das?


Hier der Code:
1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/pgmspace.h>
4
#include "lcd.h"
5
#include <inttypes.h>
6
7
8
static const PROGMEM unsigned char copyRightChar[] =
9
{
10
  0x07, 0x08, 0x13, 0x14, 0x14, 0x13, 0x08, 0x07,
11
  0x00, 0x10, 0x08, 0x08, 0x08, 0x08, 0x10, 0x00
12
};
13
14
15
/*
16
*
17
* function prototypes
18
*/ 
19
void wait_until_key_pressed(void);
20
21
22
void wait_until_key_pressed(void)
23
{
24
    unsigned char temp1, temp2;
25
    unsigned int i;
26
    
27
    do {
28
        temp1 = PIND;                  // read input
29
        for(i=0;i<65535;i++);
30
        temp2 = PIND;                  // read input
31
        temp1 = (temp1 & temp2);       // debounce input
32
    } while ( temp1 & _BV(PIND2) );
33
    
34
              
35
}
36
37
Disp_Messung(short Anzahl)
38
{
39
  switch(Anzahl)
40
  {
41
    case 1:  lcd_puts("Messung-1");
42
    break;
43
    case 2: lcd_puts("Messung-2");
44
    break;
45
    case 3: lcd_puts("Messung-3");
46
    break;
47
    case 4: lcd_puts("Messung-4");
48
    break;
49
    case 5: lcd_puts("Messung-5");
50
    break;
51
  }
52
}
53
54
void Disp_Ctrl(void)
55
{
56
wait_until_key_pressed();
57
58
   
59
       lcd_command(LCD_DISP_ON);
60
        
61
       
62
        
63
       lcd_command(_BV(LCD_CGRAM));  /* set CG RAM start address 0 */
64
}
65
66
67
68
69
int main(void)
70
{
71
  DDRC =0x00;
72
    char buffer[7];
73
    int  num=134;
74
    unsigned char i;
75
    short iMessung =1;
76
    
77
    DDRD &=~ (1 << PD2);        /* Pin PD2 input              */
78
    PORTD |= (1 << PD2);        /* Pin PD2 pull-up enabled    */
79
80
81
    /* initialize display, cursor off */
82
    lcd_init(LCD_DISP_ON);
83
84
    for(;;)
85
  {
86
  if (PINC == 0xFE)
87
    {
88
      iMessung++;
89
    }
90
                              /* loop forever */
91
        
92
       
93
        lcd_clrscr();
94
        
95
        
96
        Disp_Messung(iMessung);
97
98
       
99
         Disp_Ctrl();
100
              
101
  }    
102
}
Vielen Dank!

von Johannes M. (johnny-m)


Lesenswert?

> for(i=0;i<65535;i++);
Das ist schon mal ein klasse Kandidat für den Optimizer. Mach sowas 
nicht. Leere Zählschleifen werden gerne wegoptimiert. Entweder schreib 
was in die Schleife rein (z.B. ein "asm(nop::);) oder (besser) nimm für 
kurze Wartezeiten die fertigen Funktionen aus der delay.h.

> if (PINC == 0xFE)
Wie soll PINC denn in Deinem Programm jemals 0xFE werden? Hast Du 
externe Pull-Ups da dran? Abgesehen davon: Du wartest am Ende der 
Endlosschleife darauf, dass ein Taster an PIND2 gedrückt wird. Wenn das 
der Fall ist, müsste gleichzeitig der an PINC0 befindliche Taster 
gedrückt sein, damit überhaupt eine Änderung erfasst wird. Und dabei 
müssen auch noch alle anderen Pins von Port C High-Pegel haben.

Ich denke, da ist einiges verkehrt...

von Karl H. (kbuchegg)


Lesenswert?

Das liegt daran, dass dein Programm zwar jede Menge Code
beinhaltet, dieser Code aber völlig für die Katz ist.

Du überwachst hier:

    for(;;)
  {
  if (PINC == 0xFE)
    {
      iMessung++;
    }

den Eingang. Und solange dieser Eingang auf 0xFE
steht, wird die Variable hochgezählt.
Dieser Eingang steht aber lange auf 0xFE. Wenn du
da einen Taster dran hast, und die Taste auch nur
100 ms lang gedrückt hältst, dann kann dein µC die
konmplette Schleife wahrscheinlich ein paar Hundert
mal ausführen. Dementsprechend wurde die Variable
iMessung auch 100 mal erhöht.

Dein Code macht: Solange eine Taste gedrückt ist,
zähle die Variable hoch

Dein Code soll machen: Nur in dem Moment, in dem sich
der Zustand der Taste ändert, und zwar von nicht
gedrückt auf gedrückt, soll die Variable erhöht
werden.

PS: Deine debounce Funktion kannst du in der Pfeife
rauchen. Die funktioniert nicht richtig.
Hol dir aus dem Wiki die PeDa-Entprell Routinen und
benutze sie.

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

von Björn (Gast)


Lesenswert?

also, ich habe das STK500 und da habe ich mir einen PORT (nämlich den 
PORT-C) über ein Flachkabel nach außen gelegt, wo ich einfach einen 
Taster von Masse nach PIN0 schalte. Also ich habe da keinen Pullup dran.


diese "wait until keypressed" funktion kommt von Peter Fleurys Lib. Ich 
habe keine Ahnung was sie macht, ich weiß nur, wenn ich sie 
auskommentiere, flimmert mein Display eigenartig, drum hab ich es drin 
gelassen. Ich wäre gerne bereit, eine Alternative (auch zwecks 
Zählschleife) von euch anzunehmen, da ihr ja wirklich die Profis seid.

Ich möchte eigentlich erstmal nur diesen einen PIN (portC -> PIN0) 
abfragen, und dann sofort per Tastendruck die dadurch inkrementierte 
Variable "iMessung" auf dem Display ausgeben.


Vielen Dank

von Karl H. (kbuchegg)


Lesenswert?

Wie gesagt:
geh auf die Web Seite auf der der Entprellcode liegt und
hol dir diesen Code. Der ist zwar für den Anfang wahrlich
nicht einfach zu durchschauen, die Details wie er funktioniert
musst du aber fürs erste nicht wissen.
Auf der Seite ist auch ein  main() angegeben, welches den
Code benutzt und in Aktion zeigt. Damit sollte es dann
ein leichtes sein, dein Vorhaben umzusetzen.

> Ich möchte eigentlich erstmal nur diesen einen PIN (portC -> PIN0)
> abfragen, und dann sofort per Tastendruck die dadurch inkrementierte
> Variable "iMessung" auf dem Display ausgeben.
>

Das ist dann fast so einfach wie einem Baby den Schnuller klauen.
1
....
2
Hier kommt der Rest aus der Seite rein. Also die ISR und die
3
paar Hilfsfunktionen. Achte darauf, dass du die defines so
4
anpasst, dass sie zu deiner Hardware passen. Alles was mit LED
5
zu tun hat, brauchst du klarerweise nicht. Das betrifft die Makros
6
LED_DDR, LED_PORT, LED0, LED1 und LED2
7
8
9
int main( void )
10
{
11
  DDRC = 0x00;   // den Port an dem die Taster hängen vorbereiten
12
  PORTC = 0xFF;
13
 
14
                // die Tastenroutinen basieren auf einem Timer
15
                // diesen mal anwerfen
16
  TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
17
  TIMSK = 1<<TOIE0;        // enable timer interrupt
18
19
  lcd_init( LCD_DISP_ON );
20
 
21
  sei();
22
 
23
  for(;;) {                                       // main loop
24
                                                  // single press
25
    if( get_key_press( 1<<KEY0 ) ) {
26
      iMessung++;
27
      lcd_clrscr();
28
      Disp_Messung(iMessung);
29
    }
30
  }
31
}

von Björn (Gast)


Lesenswert?

Funktioniert der Timer_interrupt auch, obwohl ich schon einen Timer in 
Verwendung habe?

von Björn (Gast)


Lesenswert?

noch jemand da??

von Johannes M. (johnny-m)


Lesenswert?

Björn wrote:
> noch jemand da??
RTFM!
AVR-GCC-Tutorial...

von Stefan B. (stefan) Benutzerseite


Lesenswert?

> noch jemand da??

Logisch.

> Funktioniert der Timer_interrupt auch, obwohl ich schon einen Timer
> in Verwendung habe?

Warum sollte es nicht funktionieren? Du brauchst getrennte Timer, wenn 
du den Code direkt übernehmen willst.

Aber wenn du im eigenen Programmteil schon einen Timer am laufen hast 
(ich sehe das in deinem Sourcecode nicht), könntest du überlegen, wie du 
das Entprellen dort mit erledigst. Dort wäre das Entprellen 
wahrscheinlich Kleinkram für nebenher.

von Björn (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Also ich schicke nun mal meine main.c, damit ihr seht um was es 
geht....Ich brauche unbedingt eine Routine in meinem Code, die die 
Tastendrücke verarbeitet und daraufhin am Display einen entsprechenden 
Code ausgibt.
Habe einfach mal eine Endlosschleife um eine Tastenabfrage gemacht, aber 
es rührt sich NULL!

Vielen Dank!

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Sowas geht mit dem neuen GCC nicht mehr, diese for-schleife wird 
gnadenlos wegoptimiert:
1
void wait_until_key_pressed(void)
2
{
3
    unsigned char temp1, temp2;
4
    unsigned int i;
5
    
6
    do {
7
        temp1 = PIND;                  // read input
8
        for(i=0;i<65535;i++);
9
        temp2 = PIND;                  // read input
10
        temp1 = (temp1 & temp2);       // debounce input
11
    } while ( temp1 & _BV(PIND2) );
12
    
13
    loop_until_bit_is_set(PIND,PIND2); /* wait until key is released */
14
}

mach das stattdessen mit _delay_ms(). 20-30ms reichen. Den Maximalwert 
bei _delay_ms() beachten, siehe Abschnitt Warteschleifen im 
AVR-GCC-Tutorial
1
void wait_until_key_pressed(void)
2
{
3
    unsigned char temp1, temp2;
4
    unsigned int i;
5
    
6
    do {
7
        temp1 = PIND;                  // read input
8
        _delay_ms(10);
9
        _delay_ms(10);
10
        _delay_ms(5);
11
        temp2 = PIND;                  // read input
12
        temp1 = (temp1 & temp2);       // debounce input
13
    } while ( temp1 & _BV(PIND2) );
14
    
15
    loop_until_bit_is_set(PIND,PIND2); /* wait until key is released */
16
}

Jetzt kontrolliere die Sourcen, ob noch mehr solcher Daumendrehschleifen 
drin sind.

_delay_ms() erfordert ein #include <util/delay.h> und ein Übersetzen mit 
Optimierung (-Os zum Beispiel).

von Björn (Gast)


Lesenswert?

ok habe ich gemacht....

aber das problem mit den schaltern ist immer noch das gleiche ;)

könntest mir da vll auch noch helfen??


danke!

von Stefan B. (stefan) Benutzerseite


Lesenswert?

2. Teil der Fehlersuche
(da die obige Funktion in deinem Code überhaupt nicht benutzt wird)
1
int main(void)
2
{
3
  unsigned char tastenzaehler;
4
  unsigned char taste_gedrueckt;
5
    
6
  DDRD &=~ (1 << PD2);        /* Pin PD2 input              */
7
  PORTD |= (1 << PD2);        /* Pin PD2 pull-up enabled    */
8
9
  /* initialize display, cursor off */
10
  lcd_init(LCD_DISP_ON);
11
12
  DDRD =0xFF;   //UART
13
  DDRB =0x00;   //Lichtschranken
14
  DDRA =0xFF;   //Port f�r LCD
15
  DDRC =0x00;   //Port f�r div. Steuer-Taster
16
17
  PORTA = 0x00;
18
19
  UCSRB |= (1<<TXEN);                            //Senden aktivieren
20
  UCSRC |= (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1);  
21
22
  UBRRH = 00;   //Baudrate einstellen 9600 bei 8 MHz
23
  UBRRL = 51;
24
25
  for(;;)
26
  {
27
    taste_gedrueckt = 0;
28
    
29
    //
30
    // Solange die Taste an Pin0 von PORTC nicht losgelassen 
31
    // wurde: warten
32
    //
33
    while(PINC == 0xFE)
34
    {
35
      // Entprellen: Taste ist mindestens 25ms lang gedrückt
36
      _delay_ms(10);
37
      _delay_ms(10);
38
      _delay_ms(5);
39
      if (PINC == 0xFE)
40
        taste_gedrueckt = 1;
41
    }
42
43
    if (taste_gedrueckt)
44
    {
45
      taste_gedrueckt = 0;
46
      tastenzaehler++;
47
48
      // ADD: hier ggf. auch noch das Loslassen entprellen
49
      _delay_ms(10);
50
      _delay_ms(10);
51
      _delay_ms(5);
52
    }
53
54
    switch (tastenzaehler)
55
    {
56
      case 0:
57
        //Ausgangstext auf dem Display
58
        lcd_clrscr();    //Display l�schen
59
        lcd_puts("Mit SCROLLtaster\nDurchlauf wahlen");
60
        break;
61
      case 1:
62
        lcd_clrscr();
63
        lcd_puts("Messung 1");
64
        break;
65
      case 2:
66
        lcd_clrscr();
67
        lcd_puts("Messung 2");
68
        break;
69
      case 3:
70
        lcd_clrscr();
71
        lcd_puts("Messung 3");
72
        break;
73
      default:
74
        tastenzaehler = 0;
75
        break;
76
    }
77
  }
78
}

von Björn (Gast)


Lesenswert?

ok danke:


Nächstes Problem:    Object file not found.... habe avr-studio 
geschlossen und wieder geöffnet, jetzt geht das kompilieren plötzlich 
mit oben genanntem fehler nicht!! :(

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Schon Rebuild All im Menü Build probiert?

Kommen beim Kompilieren Fehler? Kannst du die Ausgabe im Message-Fenster 
komplett per Copy&Paste hier angeben? Alles dort mit Gelben oder Roten 
Punkten ist fischig und muss kontrolliert werden.

von Björn (Gast)


Lesenswert?

ja bringt auch nix, kompilieren hat es sich ja vorher gelassen.


jetzt kommt dauernd dieser GCC-plugin-error wegen dem *.elf

von Björn (Gast)


Lesenswert?

nicht mal ein neues Projekt völlig unabhängig von all dem vorherigen 
funktioniert mehr. HILFE!

von Björn (Gast)


Lesenswert?

wo soll denn diese komische .elf-Datei sein?? ich finde die in keinem 
Ordner!

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Björn wrote:
> wo soll denn diese komische .elf-Datei sein?? ich finde die in keinem
> Ordner!

Genau das meldet dir das GCC-Plugin auch als Fehler.

*.elf ist das kompilierte und gelinkte fertige Programm.

DIese Datei fehlt, wenn das Kompilieren fehlgeschlagen ist.

Warum das Fehlgeschlagen ist, kann zwei Ursachen haben.

1/ Der Quelltext enthält Fehler.

2/ Es gibt Probleme mit dem Projekt- bzw. Speicherpfad. Ist da bei dir 
ein Leerzeichen oder ein Sonderzeichen drin?

von Björn (Gast)


Lesenswert?

ok funktioniert wieder, war an einem Pfadnamen gelegen und an einem 
syntax-fehler im Code.



Ähm zu deinem Codebeispiel, erstmal vielen lieben Dank :)

also nach dem Einschalten des Board erscheint mal garnix auf dem 
Display, dann wenn ich eine Taste drücke flaggert die Zahl nach 
"Messung" zwischen 2 und 3 und nach etwa 1 sec. bleibt sie dann auf 
einer von beiden stehen.

Danke!

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Das das flackert liegt an den vielen Löschaktionen mit lcd_clrscr();

Mein Beispiel ist ja kein fertiges Programm, sondern etwas mit dem du 
selber ein Stück weitermachen kannst. Versuche es zu verstehen und passe 
es dir an.

Zwei Sachen noch:

1/ Tastenzaehler initialisieren. Der Compiler meldet korrekterweise eine 
Warnung bei obigem Code ohne die Zuweisung. Wegen der zufälligen 
Initialisierung kommt bei obigem Code auch keine Anfangsmeldung.

  unsigned char tastenzaehler = 0;    // <==


2/ Die Abfrage auf den Tastendruck besser nur auf genau das eine 
interessante Bit vergleichen:

//  while(PINC == 0xFE)
    while(!(PINC & (1<<PC0)))
    {
      // Entprellen: Taste ist mindestens 25ms lang gedrückt
      _delay_ms(10);
      _delay_ms(10);
      _delay_ms(5);
//    if (PINC == 0xFE)
      if (!(PINC & (1<<PC0)))
        taste_gedrueckt = 1;
    }

von Björn (Gast)


Lesenswert?

also ich füge mal meinen Code-Schnipsel ein, habe jetzt selber irgendwie 
ohne Entprellung erstmal hinbekommen:

Es gibt aber noch ein Problem.: Ich schalte das Board ein. Es kommt die 
Meldung "Mit Scrolltaster Durchlauf wählen". Sobald ich nun die 
Scrolltaste drücke DAUERT ES etwa 1 sec, bis das Display reagiert (Die 
Anzeige ändert). Wenn ich schließlich bei "Messung 3 ?" angelangt bin, 
bleibt es nur 1 sec. im Display und danach ist das ganze display 
"gelöscht".

Woran liegt das?
1
void Disp_Messung(short i)
2
{
3
  switch (i)
4
  {
5
    case 1:   lcd_puts("Messung - 1 ?");
6
    case 2:    lcd_puts("Messung - 2 ?");
7
    case 3:    lcd_puts("Messung - 3 ?");
8
  }
9
}
10
                            
11
        lcd_clrscr();                        //Display l?schen
12
        lcd_puts("Mit SCROLLtaster\nDurchlauf wahlen");
13
    //lcd_puts("Mit SCROLLtaster\nDurchlauf wahlen");    //Ausgangstext auf dem Display
14
                                                                 //Steuerbefehl an das Display senden
15
     for(;;)
16
    {
17
      
18
    
19
    
20
      if(PINC == 0xFE)
21
      {
22
    lcd_clrscr();
23
        tastenzaehler++;
24
    Disp_Messung(tastenzaehler);
25
        }


Danke!

von Stefan B. (stefan) Benutzerseite


Lesenswert?

1/ C-Grundlagen switch case
Es fehlt ein break; in den case Abfragen. dadurch bekommt das Programm 
Durchfall. Ein auftretender case 1 fällt durch case 2 und case 3...

2/  for(;;)
    {
      if (PINC == 0xFE)

Wie oft schätzt du kommt dein Programm an dieser Stelle pro Sekunde 
vorbei? Zig tausend Male! Auch wenn du die Taste drückst. Der AVR ist 
sauschnell!

Wenn du die Taste drückst, wird jedesmal das LCD gelöscht (das dauert), 
der tastenzsehler erhöht (bis er überläuft und von 0 anfängt) und dann 
dreimal hintereinander kurz was anderes angezeigt und gleich 
weitergestolpert in die nächste Runde.

Ich empfehle dir stark, dein Programm mal im Einzelschritt im Simulator 
durchzusteppen.  Dir werden Sachen auffallen, die du so nie gewollt hast 
;-)

von Björn (Gast)


Lesenswert?

ok Danke, wird wohl das problem sein, bin nun in der Arbeit....

Werde es abends noch mal ausprobieren ;)


naja, ich bin eben kein Profi, drum bin ich ja teilweise auf euere gute 
Hilfe angewiesen.


Ich werde euch abend noch berichten!

von Björn (Gast)


Lesenswert?

Hallo!


Ich habe nun noch eine Idee: Ich möchte desweiteren in der 
switch-Anweisung die Zeit in einer Array speichern, die verstreicht, 
solange ein Taster gedrückt ist.

Könntet ihr mir dabei helfen?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Sollte gehen.

Im Grunde ist das eine Anwendung der Timer so wie es im AVR-Tutorial 
bzw. im AVR-GCC-Tutorial ausführlich erklärt ist. Timer mit diesen 
Anleitungen so einrichten, dass er im Interrupt die Zeit hochzählt. Im 
Hauptprogramm Startzeit merken, Endzeit abfragen, Differenz bilden, 
Ergebnis formatieren und ausgeben. Pronto.

Hast du den Rest des Programms schon fertig geschrieben und entwanzt und 
nach Wunsch lauffähig auf'm µC, so dass man den die Zeitbehandlung nur 
noch einbauen muss, oder hapert es noch an allem?

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.