Tastenerkennung mit ATMega

OP #4846315
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
Gast #4846344
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.
Gast #4846379
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.
OP #4846435
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
Angehängte Dateien:
Gast #4846488
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.
OP #4846509
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
Gast #4846532
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.
Gast #4846645
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.
Gast #4846651
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.
Gast #4846661
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...
OP #4846696
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;
}
OP #4846726
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.
#4846765
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?
Gast #4846786
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.
Gast #4847148
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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren