Hallo Leute,
ich habe mein Keypad mit Widerständen zusammengefasst und lese das
Keypad dann mit einem ADC aus. Es klappt auch gut schon.
Hier der Code:
/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
13
also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
14
ADCSRA|=(1<<ADSC);// eine ADC-Wandlung
15
while(ADCSRA&(1<<ADSC)){
16
;// auf Abschluss der Konvertierung warten
17
}
18
result=ADCW;// ADCW muss einmal gelesen werden,
19
// sonst wird Ergebnis der nächsten Wandlung
20
// nicht übernommen.
21
22
/* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */
23
result=0;
24
for(i=0;i<4;i++)
25
{
26
ADCSRA|=(1<<ADSC);// eine Wandlung "single conversion"
27
while(ADCSRA&(1<<ADSC)){
28
;// auf Abschluss der Konvertierung warten
29
}
30
result+=ADCW;// Wandlungsergebnisse aufaddieren
31
}
32
ADCSRA&=~(1<<ADEN);// ADC deaktivieren (2)
33
34
result/=4;// Summe durch vier teilen = arithm. Mittelwert
35
36
returnresult;
37
}
38
39
40
41
voidlong_delay(uint16_tms){
42
for(;ms>0;ms--)_delay_ms(1);
43
}
44
45
intmain(void)
46
{
47
DDRC=0x00;
48
PORTC=0xFF;
49
50
DDRD=0x00;
51
PORTD=0xFF;
52
53
54
/*DDRB = 0xFF;
55
PORTB = 0x00; */
56
57
uint16_tadcval;
58
59
60
sei();
61
uart_puts_P("Sender laeuft !\n");
62
63
while(1)
64
{
65
adcval=ReadChannel(0);/* MUX-Bits auf 0b0000 -> Channel 0 */
66
67
68
if(adcval>228&&adcval<232)
69
{
70
uart_puts("Taster 1\n");
71
}
72
73
if(adcval>245&&adcval<250)
74
{
75
uart_puts("Taster 4\n");
76
}
77
if(adcval>261&&adcval<266)
78
{
79
uart_puts("Taster 7\n");
80
}
81
if(adcval>134&&adcval<139)
82
{
83
uart_puts("Taster 2\n");
84
}
85
if(adcval>155&&adcval<160)
86
{
87
uart_puts("Taster 5\n");
88
}
89
if(adcval>175&&adcval<184)
90
{
91
uart_puts("Taster 8\n");
92
}
93
if(adcval>195&&adcval<205)
94
{
95
uart_puts("Taster 0\n");
96
}
97
if(adcval>10&&adcval<20)
98
{
99
uart_puts("Taster 3\n");
100
}
101
if(adcval>40&&adcval<50)
102
{
103
uart_puts("Taster 6\n");
104
}
105
if(adcval>60&&adcval<80)
106
{
107
uart_puts("Taster 9\n");
108
}
109
110
//receive();
111
long_delay(100);
112
}
113
114
return1;
115
}
Das heißt er wird genau erkannt welche Taster gedrückt wurde.
Das Problem ist aber ... das wenn ich die Taster etwas zu lange halte er
ja es paar mal ausführt.
Wie mache ich das wenn eine Taster gedrückt wird, sie nur einmal
gedrückt werden kann .. .bis Sie losgelassen worden ist und nochmal
gedrückt?
Und zweite Frage: Es soll eine Fernbedingung werden, ist das OK wenn der
ADC so oft Messen tut? Wird der ADC nicht müde? ;-) Der muss ja ganze
Zeit Messen weil er sonst den Tasterdruck nicht merken würde ... oder
macht man das anders?
Vielen Dank schon mal für eure Ideen und Meinungen.
>Wie mache ich das wenn eine Taster gedrückt wird, sie nur einmal>gedrückt werden kann .. .bis Sie losgelassen worden ist und nochmal>gedrückt?
Merk dir in einer Variable, ob ein Taster schon gedrückt wurde und
vergleich das auch noch.
Beispielsweise so:
uint8 Taste = 0;
while(1)
{
adcval = ReadChannel(0); /* MUX-Bits auf 0b0000 -> Channel 0 */
if(adcval > 228 && adcval < 232)
{
if (Taste != 1)
{
uart_puts("Taster 1\n");
Taste = 1;
}
}
if(adcval > 245 && adcval < 250)
{
if (Taste != 4)
{
uart_puts("Taster 4\n");
Taste = 4;
}
}
//usw...
}
Die Version sorgt dafür, dass man erst eine andere Taste drücken muß,
bevor man diese erneut drücken darf.
Man muß also noch erkennen, ob keine Taste gedrückt wird. Dann muß Taste
= 0 gesetzt werden.
>Und zweite Frage: Es soll eine Fernbedingung werden, ist das OK wenn der>ADC so oft Messen tut? Wird der ADC nicht müde? ;-) Der muss ja ganze>Zeit Messen weil er sonst den Tasterdruck nicht merken würde ... oder>macht man das anders?
Die Arbeitszeit von ADC regelt die ADC-Gewerkschaft...
Wenn dein ADC nicht in der Gewerkschaft ist (ein Trittbrettfahrer
also...), dann muß er so lange arbeiten, wie der Arbeitsgeber es
wünscht.
Chinesische ADC darf man bei Arbeitsverweigerung auch erschiessen...
Richard B. wrote:
> Wie mache ich das wenn eine Taster gedrückt wird, sie nur einmal> gedrückt werden kann .. .bis Sie losgelassen worden ist und nochmal> gedrückt?Beitrag "Tastenmatrix auslesen über nur 2 Leitungen"> Und zweite Frage: Es soll eine Fernbedingung werden, ist das OK wenn der> ADC so oft Messen tut?
Nen hochohmigen Widerstand an die Tastatur legen und dann mit dem
Pinchangeinterrupt den MC aufwecken, sonst ist schnell die Batterie
leer.
Peter
Hallo Peter,
das ist eine gute Idee. Aber wie meinst du es genau? Ich benutze die
Schaltung hier von dir(Im Anhang).
Wo soll ich den die Leitung Abzapfen für den Int Eingang?
Also im worst case sind es 11k, wenn eine Taste gedrückt wird. Nun
schaltest Du 100k gegen VCC und bei ner gedrückten Taste erkennt der PCI
low. dann aktivierst Du den 10k und mißt genau nach, welche Taste es
ist.
Du brauchst also noch nen extra Pin für denn 10k, der im Ruhezustand
Tristate ist.
Peter
Richard B. wrote:
> Wie soll ich den 10K Widerstand aktivieren? Soll ich den per Relaise> schalten?
Nein, der kommt an einen Pin.
Zum Abfragen wird er Ausgang high gesetzt, sonst Eingang low (also
tristate).
Peter
Hallo,
etwa so?
Das heißt, der Pin ist dann immer High geschaltet im AVR und wenn er
lowgeschaltet wird durch Drücken einer Taste ... dann Schalte ich in Low
und Messe mit dem ADC den Wert. Richtig?
Es funktioniert nicht so. Kann es mir jemand genauer erklären?
Vielleicht mit einer Zeichnung? Wäre sehr dankbar. Komme leider nicht
weiter ... hab schon ganzen Mittag & Nachmittag probiert :-(
Richard B. wrote:
> Hallo,>> etwa so?> Das heißt, der Pin ist dann immer High geschaltet im AVR und wenn er> lowgeschaltet wird durch Drücken einer Taste ... dann Schalte ich in Low> und Messe mit dem ADC den Wert. Richtig?
Nein, der R6 kommt gegen nen IO-Pin, der im Sleep Eingang ist und von
dort ein 100k Pullup. Zum Messen setzt man den Pin auf High.
Der ADC-Eingang ist im Sleep auf Pin-change gesetzt zum Aufwachen.
Peter
Hallo Peter,
R6 in deiner Zeichnung (PDF) oder in der kyxpad.jpg?
"Sleep Eingang" heist low?
> Der ADC-Eingang ist im Sleep auf Pin-change gesetzt zum Aufwachen.
Was meinst du mit "Sleep"? Das war mit bei Pins noch nicht wirklich
bekannt.
So, irgendwie komme ich hier nicht wirklich weiter. Wieso tun wir uns so
schwer es bisschen einfacher zu erklären damit es auch ein Anfänger
verstehen kann?
Ich habe hier mal eine Zeichnung gemacht mit der ich hoffe wir jetzt
schneller zum Zeil kommen.
Pin PD0 ist an 10K angeschlossen. PD0 ist low. Wenn einer Taste gedrückt
wird ... wird PD0 High und ich weiss das eine Taste gerückt ist ... dann
Schalte ich PD0 High und Messe mit PB4 per ADC den Wert.
Ist es so richtig?
Mhh irgendwie scheint es nicht richtig zu sein. ist PD0 so nicht immer
HIGH?
Oder muss PB4 auch low sein ... damit PD0 High wird?
Richard B. wrote:
> Pin PD0 ist an 10K angeschlossen. PD0 ist low.
PD0 ist niemals low, es ist entweder hochohmig (Eingang) oder high
(Ausgang)
> Wenn einer Taste gedrückt> wird ... wird PD0 High und ich weiss das eine Taste gerückt ist
Nö, dann ist PB4 low.
> ... dann> Schalte ich PD0 High und Messe mit PB4 per ADC den Wert.> Ist es so richtig?
Ja.
Peter
Guten Nabend Peter,
also ist meine Schaltung so richtig? Du hast es nicht beantwortet :-(
Wie lese ich beim Eingang(PD0) den Zustand?
Das heißt wenn der Eingang(PD0)(High geschaltet ist 5V) und eine Taste
gedrückt wird ... dann ist PB4 low und beim Eingang(PD0) kann ich ein
welchsel von High auf Low messen, dann weiss ich das eine Taste gedrückt
wird. Richtig?
Du willst doch Strom sparen (Batteriebetrieb)?
Dann setzt Du die CPU in sleep, wenn ne Weile lang keine Taste gedrückt
erkannt wurde.
Vorher aber den ADC abschalten, Pinchange Interrupt auf PB4 einschalten
und PD0 auf Eingang.
Und sobald ne Taste gedrückt wird, wacht die CPU auf (Interrupthandler
nicht vergessen!).
Peter
P.S.:
PD0 läßt vermuten, Du nimmst keinen ATtiny13 sondern nen dicken AVR.
Warum dann das Auslesen der Matrix per ADC?
Ich verwende einen ATMega8. Hab eine 3x4 Tastatur dran, einen RFM12 und
3x7 Segment Anzeige. Und 2 einfache Taster.
Langsam bin ich auch der Meinung die Tastatur komplett an AVR
anschliessen.
Wenn ich die Tastatur komplett anschliesse kann ich einfach im Timer
jede 10ms testen ob Taste gedrückt oder mache ich das auch per
Pinchange?
MMhh jetzt habe ich das kapiert!! danke.
Das Problem ist, das bei Tastendruck 4,7,8,*,0 wird nicht erkannt das es
gedrückt wurde. Warscheinlicht ist die Spannung zu hoch um es noch als
low zu registrieren.
Also geht die Methode nicht wirklich ... oder man hofft auch glück das
die anderen Tasten zuerst gedrück werden :-)
AChja R5 und R6 sind bei mir 4.7K
@ Richard B. (rbrose)
>AChja R5 und R6 sind bei mir 4.7K
Ist nicht wirklich clever. Die ganze Sache ist schon etwas empfindlich
was die Widerstände angeht. Das sollte man 1% Metallschicht nehmen, mit
den angegebenen Werten.
MfG
Falk
Richard B. wrote:
> Also geht die Methode nicht wirklich ... oder man hofft auch glück das> die anderen Tasten zuerst gedrück werden :-)
Hat überhaupt nichts mit Glück zu tun.
110k zu 12,4k reicht dicke aus, um sicher low zu erkennen.
Warscheinlich hast Du die internen Pullups mit angeschaltet.
> AChja R5 und R6 sind bei mir 4.7K
Kein Problem, wenn Du wie ich die Schwellen vom Präprozessor automatisch
berechnen läßt.
In Deinem Codeschnipsel hast Du allerdings feste Werte eingetragen. Ob
die stimmmen, weiß ich nicht.
Peter
@Peter
Habe eben nach gelesen das der AtMega8 keine Pin Change
Interrupts(PCINT) hat.
Somit kann ich das mit dem PCINT vergessen :-( Da ich dafür nur INT0 und
INT1 benutzen kann, die aber nicht ADC können.
Hab aber einen AtMega168-20DIP hier noch liegen. Der soll auch weniger
Strom verbrauchen im Gegensatz zum AtMega8.
Ich werde den mal ausprobieren.
Kann ich das Programm von Atmega8 1zu1 übernehmen ... oder gibt es da
gravierende unterschiede zwischen atmega8 und atmega168?
Zum Keyboard Scannen:
Hab mal für eine Tastatur, die zur Abfrage gescannt wurde, alle zeilen
per DiodenODER auf High gelegt (hatte noch einen Ausgangspin am MUX
frei).
In Verbindung mit dem Auslesen der Datenleitung kann man so einen
kbhit() realisieren, und startet erst bei positiver Rückmeldung die
KeyScan funktion. Spart Rechenleistung, wenn man eine einfache Lösung
ohne Interrupt sucht.
Wobei ... etwas weiter gedacht könnte man die Datenleitungen ver-odern
und mit dem Signal nen INT eingang speisen :-)
VG,
/r.
Hallo zusammen,
Benutze jetzt einen AtMega168 und der Pin Change Interrupt funktioniert
super.
HIer der COde:
1
ISR(SIG_PIN_CHANGE1)
2
{
3
PORTB^=(1<<PB0);
4
DDRD|=(1<<PD2);
5
PORTD&=~(1<<PD2);
6
adcval=ReadChannel(0);
7
8
charbuffer[7];
9
itoa(adcval,buffer,10);
10
uart_puts(buffer);
11
12
DDRD&=~(1<<PD2);
13
PORTD&=~(1<<PD2);
14
}
15
16
17
intmain(void)
18
{
19
20
...
21
PCICR|=(1<<PCIE1);
22
PCMSK1|=(1<<PCINT8);
23
...
24
}
Nur wird er bei steigernder und fallender Flanke ausgeführt.
Wie kann ich in nur bei steigernder Flanke ausführen?
Ich weiss es geht nicht Hardware mässig, also muss ich in dem Interrupt
eine if abfrage einbauen ... aber auf was kann ich zugreifen um zu
überprüfen ob der Auslöser jetzt eine steigernde oder fallende Flanke
war?
Danke
@ Richard B. (rbrose)
>eine if abfrage einbauen ... aber auf was kann ich zugreifen um zu>überprüfen ob der Auslöser jetzt eine steigernde oder fallende Flanke>war?
Die Bits in PINx. Sind sie 1 wars ne steigende Flanke . . .
MFG
Falk