Forum: Mikrocontroller und Digitale Elektronik AVR 4x3 Keypad mit ADC auslesen


von Daniel (Gast)


Lesenswert?

Hallo,
ich versuche gerade die Eingabe auf ein 3x4 Keypad mit einem ADC-Eingang 
vom Arduino Uno zu erfassen und später auf einem Display auszugeben.

Die Schaltung ist soweit fertig und folgende ADC-Werte konnte ich für 
die jeweiligen Tasten ermitteln:

1: 7-14
2: 296-330
3: 452-463
4: 101-118
5: 339-353
6: 482-492
7: 177-226
8: 384-417
9: 509-522
0: 421-447
*: 243-258
#: 531-542

Da ich leider noch nicht lange in C Programmiere stoße ich gerade etwas 
an meine Grenzen. Wichtig ist, dass der uC später nicht nur diese 
Messungen tätigt, sondern diese sind nur ein kleiner Teil des 
Gesamtsystems.
Aus diesem Grund will ich mich an folgedem Beispiel orientieren, da die 
Messungen mit ISR erfolgen sollen und auch wie er in dem Beispiel 
beschreibt schneller geht als mit dem von Arduino mitgelieferten 
möglichkeiten ala "AnalogRead(int pin)". Zusätzlich soll der Taster noch 
entprellt werden. Wie dies funktioniert habe ich verstanden, allerdings 
nicht wie man dies in C umsetzt.

Es sollte nur gemessen werden wenn ein Taster gedrückt wird, d.h 
analogVal < 1000 in meinem Fall.

Die for-Schleifen für die Taster könnten ja dann so aussehen:
Beispielsweise für die "1"
1
if (analogVal > 7 && analogVal < 14)


Kann mir jemand einen Ansatz geben wie ich vorgehe?

Gruß
Daniel

http://www.glennsweeney.com/tutorials/interrupt-driven-analog-conversion-with-an-atmega328p
1
// Testing interrupt-based analog reading
2
// ATMega328p
3
4
// Note, many macro values are defined in <avr/io.h> and
5
// <avr/interrupts.h>, which are included automatically by
6
// the Arduino interface
7
8
// High when a value is ready to be read
9
volatile int readFlag;
10
11
// Value to store analog result
12
volatile int analogVal;
13
14
15
// Initialization
16
void setup(){
17
 
18
  // clear ADLAR in ADMUX (0x7C) to right-adjust the result
19
  // ADCL will contain lower 8 bits, ADCH upper 2 (in last two bits)
20
  ADMUX &= B11011111;
21
 
22
  // Set REFS1..0 in ADMUX (0x7C) to change reference voltage to the
23
  // proper source (01)
24
  ADMUX |= B01000000;
25
 
26
  // Clear MUX3..0 in ADMUX (0x7C) in preparation for setting the analog
27
  // input
28
  ADMUX &= B11110000;
29
 
30
  // Set MUX3..0 in ADMUX (0x7C) to read from AD8 (Internal temp)
31
  // Do not set above 15! You will overrun other parts of ADMUX. A full
32
  // list of possible inputs is available in Table 24-4 of the ATMega328
33
  // datasheet
34
  ADMUX |= 8;
35
  // ADMUX |= B00001000; // Binary equivalent
36
 
37
  // Set ADEN in ADCSRA (0x7A) to enable the ADC.
38
  // Note, this instruction takes 12 ADC clocks to execute
39
  ADCSRA |= B10000000;
40
 
41
  // Set ADATE in ADCSRA (0x7A) to enable auto-triggering.
42
  ADCSRA |= B00100000;
43
 
44
  // Clear ADTS2..0 in ADCSRB (0x7B) to set trigger mode to free running.
45
  // This means that as soon as an ADC has finished, the next will be
46
  // immediately started.
47
  ADCSRB &= B11111000;
48
 
49
  // Set the Prescaler to 128 (16000KHz/128 = 125KHz)
50
  // Above 200KHz 10-bit results are not reliable.
51
  ADCSRA |= B00000111;
52
 
53
  // Set ADIE in ADCSRA (0x7A) to enable the ADC interrupt.
54
  // Without this, the internal interrupt will not trigger.
55
  ADCSRA |= B00001000;
56
 
57
  // Enable global interrupts
58
  // AVR macro included in <avr/interrupts.h>, which the Arduino IDE
59
  // supplies by default.
60
  sei();
61
 
62
  // Kick off the first ADC
63
  readFlag = 0;
64
  // Set ADSC in ADCSRA (0x7A) to start the ADC conversion
65
  ADCSRA |=B01000000;
66
}
67
68
69
// Processor loop
70
void loop(){
71
72
  // Check to see if the value has been updated
73
  if (readFlag == 1){
74
   
75
    // Perform whatever updating needed
76
   
77
    readFlag = 0;
78
  }
79
 
80
  // Whatever else you would normally have running in loop().
81
 
82
}
83
84
85
// Interrupt service routine for the ADC completion
86
ISR(ADC_vect){
87
88
  // Done reading
89
  readFlag = 1;
90
 
91
  // Must read low first
92
  analogVal = ADCL | (ADCH << 8);
93
 
94
  // Not needed because free-running mode is enabled.
95
  // Set ADSC in ADCSRA (0x7A) to start another ADC conversion
96
  // ADCSRA |= B01000000;
97
}

von Hubert G. (hubertg)


Lesenswert?

Daniel schrieb:
> ADMUX &= B11011111;

Das kannst du dir sparen beim initialisieren.

Übersichtlicher ist es wenn du schreibst
ADCSRA =(1<<ADEN)|(1<<ADATE)|  usw.

Daniel schrieb:
> analogVal = ADCL | (ADCH << 8);

Hier genügt ein analogVal=ADC;  Den Rest macht der Compiler

von Daniel (Gast)


Lesenswert?

Hubert G. schrieb:
> Daniel schrieb:
>> ADMUX &= B11011111;
>
> Das kannst du dir sparen beim initialisieren.
>
> Übersichtlicher ist es wenn du schreibst
> ADCSRA =(1<<ADEN)|(1<<ADATE)|  usw.
>
> Daniel schrieb:
>> analogVal = ADCL | (ADCH << 8);
>
> Hier genügt ein analogVal=ADC;  Den Rest macht der Compiler

Warum genau kann ich mir das sparen?


Hast du noch einen Tipp bzw. Ansatz was das Auslesen des ADC-Wertes 
angeht mit einem Interrupt?

von Peter D. (peda)


Lesenswert?


von Hubert G. (hubertg)


Lesenswert?

Daniel schrieb:
>> Hier genügt ein analogVal=ADC;  Den Rest macht der Compiler
>
> Warum genau kann ich mir das sparen?

Weil es der Compiler sicher nicht schlechter macht als du.

Daniel schrieb:
> volatile int readFlag;

Hier würde es ein char als Flag auch tun.

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.