Forum: Mikrocontroller und Digitale Elektronik Tastenerkennung mit ATMega


von Martin B. (nutnic)


Lesenswert?

Guten Tag,

ich habe mir das Buch AVR Mikrocontroller Programmieren in C gekauft.

Ich habe das Beispiel Programm zum erkennen einer Tastatur mit einem 
Interrupt sb getippt.

Leider bekomme ich diesen Fehler nicht weg.

EICRA was not declared in this scope.
EIMSK was not declared in this scope.

Hier mein Code.

#include "ADConverter.h"

volatile uint16_t ADC_Wert;

#define Taster_1  ((ADC_Wert >= 168)  && (ADC_Wert <= 174))
#define Taster_2  ((ADC_Wert >= 89)  && (ADC_Wert <= 95))
#define Taster_3  ((ADC_Wert >= 0)  && (ADC_Wert <= 3))
#define Taster_4  ((ADC_Wert >= 185)  && (ADC_Wert <= 191))
#define Taster_5  ((ADC_Wert >= 113)  && (ADC_Wert <= 119))
#define Taster_6  ((ADC_Wert >= 22)  && (ADC_Wert <= 28))
#define Taster_7  ((ADC_Wert >= 202)  && (ADC_Wert <= 208))
#define Taster_8  ((ADC_Wert >= 131)  && (ADC_Wert <= 137))
#define Taster_9  ((ADC_Wert >= 46)  && (ADC_Wert <= 52))
#define Taster_10  ((ADC_Wert >= 218)  && (ADC_Wert <= 224))
#define Taster_11  ((ADC_Wert >= 150)  && (ADC_Wert <= 156))
#define Taster_12  ((ADC_Wert >= 70)  && (ADC_Wert <= 76))

void Init_ADC()
{
  uint8_t x;
  DDRC &= ~(1<<PC0);
  ADCSRA |= (1<< ADEN);
  ADCSRA |= (1<<ADPS0) | (1<<ADPS1);
  ADMUX  |= (1<<REFS0) | (1<<REFS1);
  ADMUX  |= (1<<MUX2)  | (1<<MUX0); // Hier könnte ein Fehler  liegen. 
Laut AVR Buch "ADC5 (PIN PC5) = ADC Channel"

  ADMUX  |= (1<<ADLAR);
//  DIDR0  |= (1<<ADC5D);

  ADCSRA |= (1<< ADSC);
  while (ADCSRA & (1<<ADSC));
  x = ADC;
}
void Init_INT0 ()
{
  DDRC  &= ~(1<<PD2);
  EICRA  |= (1<<ISC01);
  EIMSK  |= (1<<INT0);
  sei();
}

void ADC_Main ()
{
  DDRB |= 0xFF;
  Init_ADC();
  Init_INT0();

  while (1)
  {
    if (Taster_1)
    {
      DOGM204_Clear_Display();

      DOGM204_Set_Cursor(1,2);
      sprintf(text,"Taster 1");
      DOGM204_Write_Text(text, true);
    }

    ADC_Wert = 0;
  }
}

ISR (INT0_vect)
{
  ADCSRA |= (1<< ADSC);
  while (ADCSRA & (1<<ADSC));
  ADC_Wert += ADCH;

  ADCSRA |= (1<< ADSC);
  while (ADCSRA & (1<<ADSC));
  ADC_Wert += ADCH;

  ADCSRA |= (1<< ADSC);
  while (ADCSRA & (1<<ADSC));
  ADC_Wert += ADCH;

  ADC_Wert = ADC_Wert / 3;
}

Hier die Header-Datei.

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "DOGM204.h"
#include <stdio.h> // wegen printf

// Funktionen
void Init_ADC ();
void Init_INT0 ();
void ADC_Main ();
ISR (INT0_vect);

//extern DOGM204_Clear_Display();

extern char text[20];


Kann mir jemand Helfen ?

Gruß Nutnic

von STK500-Besitzer (Gast)


Lesenswert?

fehlt:
#include <avr/io.h>

von Hubert G. (hubertg)


Lesenswert?

Schon man nachgeschaut ob der verwendete Kontroller? diese Register 
überhaupt hat.
Welchen du verwendest hast du ja verschwiegen.

von Martin B. (nutnic)


Lesenswert?

Hallo,

die Header Datei habe ich eigebuden.

Ich nutze den AtMega32.

Gruß Nutnic

von Hubert G. (hubertg)


Lesenswert?

Da wirst du im Datenblatt nachsehen müssen wie die Register heißen in 
denen du den INT0 usw. aktivierst.

von S. Landolt (Gast)


Lesenswert?

Das Beispielprogramm ist für einen anderen Controller, vielleicht den 
ATmega328. Also muss z.B. EICRA durch MCUCR sowie EIMSK durch 
GICR ersetzt werden. Um sicher zu sein, müsste man aber alle 
verwendeten SFRs kontrollieren bzw. abgleichen.

von S. Landolt (Gast)


Lesenswert?

> ADMUX  |= (1<<MUX2)  | (1<<MUX0);
> // Hier könnte ein Fehler  liegen.
> Laut AVR Buch "ADC5 (PIN PC5) = ADC Channel"

Eben. Beim ATmega32 ist das PA5.


> ADMUX  |= (1<<REFS0) | (1<<REFS1);

"Internal 2.56V Voltage Reference" beim ATmega32, aber z.B. bei einem 
ATmega328 1.1 V, welche der 32er aber gar nicht hat, d.h. man müsste 
alle ADC-Intervalle in diesen define Taster... neu berechnen.

von S. Landolt (Gast)


Lesenswert?

Na, Letzteres nicht unbedingt, es hängt davon ab, wie die Taster 
verschaltet sind; ich kenne dieses Buch nicht.

von Martin B. (nutnic)


Angehängte Dateien:

Lesenswert?

Hallo Landolt,

die Register habe ich gefunden.
Jrtzt bekomme ich schon mal werte von den Tastern.

Die Tastrer sind über eine Matrix angeschlossen.

Anbei der Schaltplan.

Kannst du mir sagen wie ich die Taster neu berechne ?
Ich hatte nicht die Richtigen Widerstände da.

Gruß Nutnic

von S. Landolt (Gast)


Lesenswert?

Das hängt davon ab, von welcher Referenzspannung das Beispielprogramm 
ausgeht, also für welchen Controller es ursprünglich gedacht war. Ist es 
z.B. der ATmega328, dann müssten die Werte mit 1.1/2.56, d.h. 
Vref(ATmega328) / Vref(ATmega32), multipliziert werden.
  Alternativ könnte man auch eine Vref von 1.1 V extern anlegen.

von Martin B. (nutnic)


Lesenswert?

Hsllo Landolt,

das Beispiel ist für dem ATmega88 @ 1 Mhz ausgelegt.

ich habe momentan 3,3 Volt anliegen.
Kann ich das Problem auch mit nur 3,3 Volt lösen ?
Sonst muss ich extra einen Festspannungsregler verbauen für die 5 Volt.
Das will ich echt nicht machen.

Gruß Nutnic

von STK500-Besitzer (Gast)


Lesenswert?

wenn ich deinen Schaltplan richtig gedeutet habe, ergeben sich diese 
Formeln bei gedrückten Tastern:
U(S2C)= 0,0 / 39,9 * Vcc
U(S1B)= 3,7 / 39,9 * Vcc
U(S1A)= 7,4 / 39,9 * Vcc
U(S3D)= 4,7 / 39,9 * Vcc
U(S4E)= 1,0 / 39,9 * Vcc

Die ADC-Vergleichswerte darfst du selber ausrechnen.

von Peter D. (peda)


Lesenswert?

Martin B. schrieb:
> Kannst du mir sagen wie ich die Taster neu berechne ?

Man kann Konstanten den Compiler ausrechnen lassen, der macht das gerne 
und fehlerfrei.
Man muß nur die Formel (Spannungsteiler) hinschreiben:

Beitrag "Tastenmatrix auslesen über nur 2 Leitungen"

von S. Landolt (Gast)


Lesenswert?

(Entschuldigung, da war eben ein 'Familieninterrupt')

Ich hab's noch nicht verstanden, sind das fünf Einzeltasten, also keine 
Matrix?

von Martin B. (nutnic)


Lesenswert?

Hallo,

es sind 5 Einzeltaster.


Bekomme ich das mit der 3,3 Volt Spannung so hin ?

Gruß Nutnic

von HildeK (Gast)


Lesenswert?

S. Landolt schrieb:
> Ich hab's noch nicht verstanden, sind das fünf Einzeltasten, also keine
> Matrix?

Es ist keine Matrix.
Drücke in Gedanken einfach jede Taste und berechne aus R1...R4 die 
heruntergeteilte Spannung - das hat ja STK500-Besitzer schon fast 
gemacht.
Das geht auch mit 3.3V.
Je nach Referenzspannung kannst dann den passenden Schwellwert dazu 
ausrechnen.

von S. Landolt (Gast)


Lesenswert?

Ja eben, die Formeln von STK500-Besitzer kommen mir falsch vor, ich 
hätte gedacht:

U(S2C)= 0.0
U(S1B)= 3.7 / (39.9+3.7)  * Ucc
U(S1A)= 7.4 / (39.9+7.4)  * Ucc
U(S3D)= 1.0 / (39.9+1.0)  * Ucc
U(S4E)= 4.7 / (39.9+4.7)  * Ucc

S2C und S3D liegen dann etwas dicht beieinander, aber es sollte 
eigentlich reichen.

von Hubert G. (hubertg)


Lesenswert?

HildeK schrieb:
> Drücke in Gedanken einfach jede Taste und berechne aus R1...R4 die
> heruntergeteilte Spannung - das hat ja STK500-Besitzer schon fast
> gemacht.

Für die Spannungsteilerberechnung würde ich aber für diese Formel 
plädieren:
http://www.elektronik-kompendium.de/sites/slt/0201111.htm

von STK500-Besitzer (Gast)


Lesenswert?

S. Landolt schrieb:
> Ja eben, die Formeln von STK500-Besitzer kommen mir falsch vor, ich
> hätte gedacht:

Wenigstens hast du den Fehler gefunden.
Ich würde einfach ein Programm schreiben, das mir die gemessenen 
ADC-Werte ans Terminal schickt.

von S. Landolt (Gast)


Lesenswert?

Also, mit Ucc= 3.3 V, Uref= 2.56 V (Datenblatt: 2.3 .. 2.7 V) sowie 
ADLAR=1 komme ich auf die ADC-Werte:
U(S2C)=  0
U(S1B)= 28
U(S1A)= 52
U(S3D)=  8
U(S4E)= 35
Jetzt noch passende Intervallgrenzen auswählen, dann sollte das klappen.
Ohne den anderen Vorschlägen vorgreifen zu wollen...

von Martin B. (nutnic)


Lesenswert?

Hallo,

ksnn man mir noch mal Helfen ?

Ich glAub ich habe dar einen Fetten Fehler drin:

#include "ADConverter.h"

volatile uint16_t ADC_Wert;

#define Taster_1  ((ADC_Wert >= 49)  && (ADC_Wert <= 55))
#define Taster_2  ((ADC_Wert >= 25)  && (ADC_Wert <= 31))
#define Taster_3  ((ADC_Wert >= 0)  && (ADC_Wert <= 3))
#define Taster_4  ((ADC_Wert >= 32)  && (ADC_Wert <= 38))
#define Taster_5  ((ADC_Wert >= 5)  && (ADC_Wert <= 11))

void Init_ADC()
{
  uint8_t x;
  DDRC &= ~(1<<PC0);
  ADCSRA |= (1<< ADEN);
  ADCSRA |= (1<<ADPS0) | (1<<ADPS1);
  ADMUX  |= (1<<REFS0) | (1<<REFS1);
  ADMUX  |= 1<<MUX0;
  ADMUX  |= (1<<ADLAR);
//  DIDR0  |= (1<<ADC5D);

  ADCSRA |= (1<< ADSC);
  while (ADCSRA & (1<<ADSC));
  x = ADC;
}
void Init_INT0 ()
{
  DDRC  &= ~(1<<PD2);
  MCUCR  |= (1<<ISC01);
  GICR  |= (1<<INT0);
  sei();
}

void ADC_Main ()
{
  DDRB |= 0xFF;
  Init_ADC();
  Init_INT0();

  while (1)
  {
    if (Taster_1)
    {
      DOGM204_Clear_Display();

      DOGM204_Set_Cursor(1,2);
      sprintf(text,"Taster 1");
      DOGM204_Write_Text(text, true);
    }

    else if (Taster_2)

    {
      DOGM204_Clear_Display();

      DOGM204_Set_Cursor(1,2);
      sprintf(text,"Taster 2");
      DOGM204_Write_Text(text, true);
    }

    else if (Taster_3)
    {
      DOGM204_Clear_Display();

      DOGM204_Set_Cursor(1,2);
      sprintf(text,"Taster 3");
      DOGM204_Write_Text(text, true);
      _delay_ms(1000);
    }

    else if (Taster_4)
    {
      DOGM204_Clear_Display();

      DOGM204_Set_Cursor(1,2);
      sprintf(text,"Taster 4");
      DOGM204_Write_Text(text, true);
    }

    else if (Taster_5)
    {
      DOGM204_Clear_Display();

      DOGM204_Set_Cursor(1,2);
      sprintf(text,"Taster 5");
      DOGM204_Write_Text(text, true);
    }




    ADC_Wert = 0;
  }
}

ISR (INT0_vect)
{
  ADCSRA |= (1<< ADSC);
  while (ADCSRA & (1<<ADSC));
  ADC_Wert += ADCH;

  ADCSRA |= (1<< ADSC);
  while (ADCSRA & (1<<ADSC));
  ADC_Wert += ADCH;

  ADCSRA |= (1<< ADSC);
  while (ADCSRA & (1<<ADSC));
  ADC_Wert += ADCH;

  ADC_Wert = ADC_Wert / 3;
}

von S. Landolt (Gast)


Lesenswert?

Wie äußert sich der Fehler?

ADC-Eingang ist PA1, okay?

von S. Landolt (Gast)


Lesenswert?

Es ruft das Vergnügen, ich möchte mich verabschieden -

wünsche allerseits einen

   guten Rutsch und ein gutes Neues Jahr.

von Martin B. (nutnic)


Lesenswert?

Hallo,

Nein Nein, PA0 ist nur noch frei.

Wenn alle Tasten angeschlossen sin.
Erkennt er Taste 3 ohne das ich etwas drücke.

Wenn ich Taster3 raus nehme, dann erkennt er zwar einzelne Tasten, aber 
sehr mühsam. Ich muss mehr mals drauf drücken damit er reagiert und dann 
erkennt er immer mal eine andere Taste ob wohl ich die selbe drücke.

Gruß

Sollen wir mal telefonieren ?
Ich würde ich gerne an rufen das ist das vielleicht nicht so mühsam.
Schreib mir einfach.

von Hubert G. (hubertg)


Lesenswert?

Martin B. schrieb:
> ADMUX  |= 1<<MUX0;

Hier hast du ADC1, also PA1 eingestellt.

von Hubert G. (hubertg)


Lesenswert?

Martin B. schrieb:
> Ich glAub ich habe dar einen Fetten Fehler drin:


Zum ersten prellen die Tasten, das heißt, der Interrupt wird mehrmals 
aufgerufen. Dafür gibt es Entprellroutinen.
Dann kannst du mal die Spannung am ADC Eingang messen und mit deinen 
theoretischen Werten vergleichen.
Wie sieht deine Hardware aus. Kondensator am AREF und Kondensator an VCC 
nach GND?
AVCC mit L/C von VCC entkoppelt? WAs ist mit den anderen Pin von PortA. 
Geben die Ruhe wenn auf PA0 gemessen wird?

von Hubert G. (hubertg)


Lesenswert?

Martin B. schrieb:
> DDRC  &= ~(1<<PD2);

Das passt auch nicht.

von MaWin (Gast)


Lesenswert?

Martin B. schrieb:
> ((ADC_Wert >= 49)  && (ADC_Wert <= 55))

Wenn dein Interrupt dazwischen reinkommt, sind deine Vergleiche falsch.
Auch ist ADC_Wert 16 Bit breit und somit nicht atomisch. Somit kann ein 
Interrupt auch während des Lesens eines ADC_Wert dazwischenkommen.

-> IRQs müssen in der Hauptschleife gesperrt werden.

von Hubert G. (hubertg)


Lesenswert?

Martin B. schrieb:
> volatile uint16_t ADC_Wert;

uint8_t  genügt für ADC_Wert, da ohnehin nur ADCH abgefragt wird. Damit 
entfällt auch das Problem mit der ISR.

von MaWin (Gast)


Lesenswert?

Hubert G. schrieb:
> Damit
> entfällt auch das Problem mit der ISR.

Nein tut es nicht, weil ADC_Wert mehrfach für eine Bedingung abgefragt 
wird.

von S. Landolt (Gast)


Lesenswert?

> Nein Nein, PA0 ist nur noch frei.
Dass der ADC-Eingang auf PA1 programmiert ist, wurde ja bereits gesagt, 
auch dass das Ganze wegen des Tasterprellens eigentlich gar nicht stabil 
zu bekommen ist. Und mit dem
> ADC_Wert = 0;
in der Hauptschleife ist die Bedingung
> #define Taster_3  ((ADC_Wert >= 0)  && (ADC_Wert <= 3))
doch immer erfüllt.
Insgesamt eine recht eigenwillige Konstruktion. Wie kommt es zu den 
ungebräuchlichen Widerstandswerten?

von Peter D. (peda)


Lesenswert?

Martin B. schrieb:
> ksnn man mir noch mal Helfen ?

Warum folgst Du nicht einfach meinem Link?
Da steht alles drin, mit Entprellung.

von Peter D. (peda)


Lesenswert?

Man muß auch bedenken, daß die Wandlung asynchron zum Drücken erfolgt 
und sich die Spannung nicht unendlich schnell ändert, d.h. es werden 
Zwischenwerte anderer Tasten durchlaufen. Diese kurzzeitigen 
Fehlerkennungen filtert die Entprellung.

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.