Hallo zusammen,
hab ein kommisches Problem.
Ich benutze die Schaltung (Siehe Attachemend) für eine Auswertung des
Keypads.
PC0 ist als PCINT definiert.
Der Interrupt wird auch super ausgefürht. Doch leider friert mir der AVR
ein wenn ich die Taste "*" drücke oder manchmal auch die Taste "2" und
"0" drücke.
Hat einer eine Idee was das Problem sein könnte?
Hier der Gesammte Code:
1
/*
2
# Autor: Richard Brose
3
# Title: Keypad 3x4 Matrix V0.1
4
# Class: main
5
*/
6
7
8
#ifndef F_CPU
9
#warning "F_CPU war noch nicht definiert, wird nun mit 8000000 definiert"
10
#define F_CPU 8000000UL /* Quarz mit 8.0000 Mhz */
11
#endif
12
#include<util/delay.h> /* in älteren avr-libc Versionen <avr/delay.h> */
13
14
#include<avr/io.h>
15
#include<stdlib.h>
16
#include<avr/pgmspace.h>
17
#include<avr/interrupt.h>
18
#include"uart.h"
19
20
21
volatileuint8_teiner=0;
22
volatileuint8_tzweier=0;
23
volatileuint8_tdreier=0;
24
25
volatileuint16_tadcval;
26
27
28
voidlong_delay(uint16_tms){
29
for(;ms>0;ms--)_delay_ms(1);
30
}
31
32
33
/* Einfache Funktion zum Entprellen eines Tasters */
@ Richard B. (rbrose)
>Ich benutze die Schaltung (Siehe Attachemend) für eine Auswertung des>Keypads.
Hatten wir das nciht in einem anderen thread ausreichend geklärt?
Ausserdem solltest du cich über Netiquette informieren. Lange
Quelltexte gehören in den Anhang.
>Der Interrupt wird auch super ausgefürht. Doch leider friert mir der AVR>ein wenn ich die Taste "*" drücke oder manchmal auch die Taste "2" und>"0" drücke.
Du greifst sowohl im Main als auch im Interrupt auf die Ports zu,
das geht schief. Siehe Link, Atomarer Zugriff.
MfG
Falk
Falk Brunner wrote:
> @ Richard B. (rbrose)>>>Ich benutze die Schaltung (Siehe Attachemend) für eine Auswertung des>>Keypads.>> Hatten wir das nciht in einem anderen thread ausreichend geklärt?
Das Problem hatte ich noch nicht. Es ging nicht um das Problem.
> Ausserdem solltest du cich über Netiquette informieren. Lange> Quelltexte gehören in den Anhang.>
Hatte eine JPG-Datei schon als Anhang. Wollte nicht 2 Post drauf machen.
Werde das in Zukunft beherzigen.
>>Der Interrupt wird auch super ausgefürht. Doch leider friert mir der AVR>>ein wenn ich die Taste "*" drücke oder manchmal auch die Taste "2" und>>"0" drücke.>> Du greifst sowohl im Main als auch im Interrupt auf die Ports zu,> das geht schief. Siehe Link, Atomarer Zugriff.>
Leider war es nicht das Problem :-(
Habe die Main in folgendes geändert:
1
intmain(void)
2
{
3
uart_init(UART_BAUD_SELECT(19200,F_CPU));
4
5
6
PCICR|=(1<<PCIE1);
7
PCMSK1|=(1<<PCINT8);
8
9
DDRB=0xFF;
10
PORTB=0xFF;
11
12
DDRD&=~(1<<PD2);
13
PORTD&=~(1<<PD2);
14
15
sei();
16
17
18
uart_puts_P("Sender laeuft !\n");
19
20
while(1)
21
{
22
23
}
24
25
return1;
26
}
Das Problem ist ja das der AVR bei der Taste "*" immer einfriert.
Hier passt was nicht. Ersten feht das Setzen von PD2, ausserdem misst du
auf der falschen Flanke. Denn beim Tastendruck wird eine FALLENDE Flanke
ausgelöst. IMMER!
1
ISR(SIG_PIN_CHANGE1)
2
{
3
4
if(!(PINC&(1<<PINC0)))// fallende Flanke
5
{
6
PORTB^=(1<<PB0);
7
8
DDRD|=(1<<PD2);
9
// PORTD &= ~(1<<PD2); // falsch, du musst ja PD2 SETZEN
Hab folgendes gemessen: An PIN PD2 liegt bei jeder Taste die ich drücke
kleiner als 1V Spannung an. Wenn ich aber Taste "*" Drücke wird V5,08
angezeigt. Ist das Normal`? Kann das, dass Problem sein?
@ Richard B. (rbrose)
>angezeigt. Ist das Normal`? Kann das, dass Problem sein?
Nein, das ist nciht normal. Und das ist scheinbar das Problem. Sieht so
aus al ob die taste defekt wäre.
>Wenn ich PORTD &= ~(1<<PD2); in PORTD |= (1<<PD2); ändere, ist egal>welche Taste ich drücke, friert der AVR sofort ein.
Dann mach mal die doofe if Abfrage im Interrupt raus. PD2 MUSS auf HIGH
gesetzt werden.
MFG
Falk
@ Richard B. (rbrose)
>Wenn ich die if-abfrage ganz weglasse und PORTD |= (1<<PD2); lasse ..>friert es ein. Er friert als immer bei FALLENDE Flanke ein. Sehr>komisch.
Pack mal die Routine in deine while-Schleife und schalte die Interrupts
aus. Ich fürchte das kann man nicht mit Pin-Change Interrupt machen,
weil die Spannung nicht immer niedrig genug ist, um die Schaltschwellen
zu erreichen. Es ist sicher besser, die Tasten per Timer zyklisch zu
pollen.
MfG
Falk
ok ich teste es mal. Aber ich glaube ich weiss warum bei Taste "*" ich
5V kriege ... weil alle Widerstände zusammen 12,4kOhm sind und die
10kOhm sind ja weniger ... deshalb geht der Strom da drüber weil PD2 ja
5V dann ist oder?
@ Richard B. (rbrose)
>ok ich teste es mal. Aber ich glaube ich weiss warum bei Taste "*" ich>5V kriege ... weil alle Widerstände zusammen 12,4kOhm sind und die>10kOhm sind ja weniger ... deshalb geht der Strom da drüber weil PD2 ja>5V dann ist oder?
???
Das ist ein Spannungsteiler! Der spukt maximal Vcc aus. Und wenn er
das tut, dann ist KEINE Taste gedrückt.
MFG
Falk
@ Richard B. (rbrose)
>Und was bezwegt das Schalten von PD2? Wieso wird es zwischen Eingang und>Ausgang geschaltet?
Das musst DU doch wissen! War das nicht mal aus Energiespargründen
gemacht worden? Im Normalfall ist PD2 immer HIGH und Ausgang, eigentlich
kann man den Widerstand direkt an Vcc hängen.
MfG
Falk
Ich vermute, dass das Umschalten des PD2 dafür sorgt, dass man man den
Pin PC0 auch noch als PCINT-Pin benutzen kann und etwas Strom spart.
Im Normalzustand ist PD2 hochohmig (Eingang, Pull-Up ausgeschaltet).
Dann sorgt ein Tastendruck dafür, dass PC0 auf GND-Pegel gezogen wird.
Dadurch wird die ISR angesprungen, in der PD2 zum Ausgang mit H-Pegel
wird.
Dadurch fällt R6 nicht mehr ins Gewicht und man hat eine ADC-Tastatur.
PC0 wird jetzt als ADC-Eingang benutzt.
Sobald die ADC-Wandlung abgeschlossen ist, wird die Tastatur bzw. das
Widerstandsnetzwerk wieder zu einem PCINT-Trigger gemacht.
Fertig ist die Laube...
>bezwegt
Nach 5-10maligem Lesen habe ich dann auch verstanden, dass "bezweckt"
gemeint ist, was mit dem "Zweck" und nicht dem "Weg" zu tun hat.
@ STK500-Besitzer (Gast)
>Ich vermute, dass das Umschalten des PD2 dafür sorgt, dass man man den>Pin PC0 auch noch als PCINT-Pin benutzen kann und etwas Strom spart.
Schon klar, aber, das hat seine Tücken.
>Im Normalzustand ist PD2 hochohmig (Eingang, Pull-Up ausgeschaltet).>Dann sorgt ein Tastendruck dafür, dass PC0 auf GND-Pegel gezogen wird.
Soweit, so gut.
>Dadurch wird die ISR angesprungen, in der PD2 zum Ausgang mit H-Pegel>wird.>Dadurch fällt R6 nicht mehr ins Gewicht und man hat eine ADC-Tastatur.>PC0 wird jetzt als ADC-Eingang benutzt.>Sobald die ADC-Wandlung abgeschlossen ist, wird die Tastatur bzw. das>Widerstandsnetzwerk wieder zu einem PCINT-Trigger gemacht.>Fertig ist die Laube...
Ja? Und was ist, wenn die Taste gedrückt bleibt, ewas sie im allegmeinen
auch tut, schliesslich ist die Messung sehr kurz? Und was ist mit
Prellen?
Alles heiss.
MfG
Falk
hallo STK500-Besitzer,
hab die schaltung auch auf einem STK500 aufgebaut :-)
So funktioniert es auch wie du gesagt hast. Aber kannst du dir erklären
wieso der AVR bei der Taste "*" oder manchmal auch "0" und "2"
einfriert?
@ Richard B. (rbrose)
>OK wenn das alles heiss ist ... was ist dein Vorschlag? Wie soll ich die>Tastatur am besten auslesen? Nicht mit ADC?
DOCH, aber nicht per Pin Change Interrupt sondern per Timer alle
10..100ms. pack die Routone ohne das doofe if in einen Timerinterrupt
und sie sollte prima laufen.
MFG
Falk
>Aber kannst du dir erklären wieso der AVR bei der Taste "*" oder manchmal >auch
"0" und "2" einfriert?
Wo friert es denn?
Ich habe mir nicht den ganzen Thread (und das Programm) angeguckt.
Ich vermute ein Schaltungsproblem.
>Ja? Und was ist, wenn die Taste gedrückt bleibt, ewas sie im allegmeinen
auch tut, schliesslich ist die Messung sehr kurz?
Dann sollte das Programm bei nächster Gelegenheit wieder in die ISR
springen.
>Und was ist mit Prellen?
Ich habe nie behauptet, dass das Progemm perfekt funktioniert. ;)
Ich würde den Controller schon per PCINT oder sowas "wecken" und dann
mit der Standard-Methode des Polling per Timer-Interrupt die Tastatur
auslesen.
Das könnte man dann solange machen, bis keine Taste über längere Zeit
gedrückt wurde. Dann kann der Controller wieder Heia machen.
Ja Richtig ... das hatte ich doch schon mal so und hat auch prima
funktioniert. Aber da es eine Fernbedingung werden soll, meinte man mir
das die Batterie schnell leergesaugt würde wenn der ADC jede 10..100ms
misst.
Über wieviel mAh reden wir da?
Ist es viel mehr als wenn ich die Tastatur mit allen 7 Leitungen
anschliesse in im timer alle pins durchtesten würde?
@ Richard B. (rbrose)
>Ja Richtig ... das hatte ich doch schon mal so und hat auch prima>funktioniert. Aber da es eine Fernbedingung werden soll, meinte man mir>das die Batterie schnell leergesaugt würde wenn der ADC jede 10..100ms>misst.
Naja, kommt drauf an. Pin Change wäre in diesem Fall schon besser,
stimmt schon.
>Über wieviel mAh reden wir da?
Rechne doch mal. Siehe Sleep Mode.
>Ist es viel mehr als wenn ich die Tastatur mit allen 7 Leitungen>anschliesse in im timer alle pins durchtesten würde?
Nein. Du brauchst dann halt 7 IOs. Die Messung per ADC ist schon OK,
aber irgendwie hakt das Ganze noch.
Und was passiert ohne die if Abfrage im interrupt? Dann darf sich der
AVR eigentlich nicht aufhängen, nur halt viel "Müll" ausspucken.
MfG
Falk
@ Richard B. (rbrose)
>"Standard-Methode des Polling">Was ist die Standard-Methode? also nicht ADC?
NEIN!
Polling oder Interrupt, das ist der Unterschied!
Ich habe eine neue Vermutung: Kann es daran liegen das die Taste "*" bei
PC0 zwischen 2.4V und 2.5V ist und somit der PCINT sich nicht
entscheiden kann ob es hight oder low ist. Und dadurch der Interrupt
1000 mal ausgeführt wird wenn die Taste gedrückt wird?
Soll ich anstatt den 4.7kOhm, 3.3kOhm drantun?
Und kann ich im PCINT Interrupt cli() und sei() jeweils am Anfang und am
Ende benutzen damit kein Interrupt gemacht wird bis der noch in dem
Interrupt ist?
Was meint ihr?
Richard B. wrote:
> Ich habe eine neue Vermutung: Kann es daran liegen das die Taste "*" bei> PC0 zwischen 2.4V und 2.5V ist und somit der PCINT sich nicht> entscheiden kann ob es hight oder low ist. Und dadurch der Interrupt> 1000 mal ausgeführt wird wenn die Taste gedrückt wird?
Kann sein, aber dann hast Du das Prinzip noch immer nicht verstanden.
Im Sleep ist ja nur der 100k Pullup aktiv und damit liefert jede Taste
einen richtigen Low-Pegel.
Der PCINT dient allein nur zum Aufwachen und dann wird er abgeschaltet.
Es ist also völlig wurscht, was dann für ein Analogpegel anliegt.
Ist die CPU aufgewacht, macht sie die ganz normale Tastenauswertung mit
ADC und Timerinterrupt, vorzugsweise mit der 4-fach Entprellung wie in
meinem Beispiel.
Erst wenn wieder erkannt wird, daß keine einzige Taste gedrückt ist,
dann wird auf Sleep und PCINT umgeschaltet.
Das Sleep ist etwas tricky, damit auch wirklich kein Aufwachen
fehlschlägt:
Zuerst müssen die Interrupts global disabled werden, dann den PCINT
enablen, dann nochmal prüfen, ob der Pin wirklich high ist.
Und dann unmittelbar hintereinander SEI und SLEEP!
Es darf keine Möglichkeit bestehen, daß der Interrupt schon vor dem
Sleep zuschlägt.
Und der SEI-Befehl bewirkt, daß genau der nächste Befehl noch unter
Interruptsperre ausgeführt wird.
Der PCINT muß völig leer bleiben, er soll ja nur aufwachen und es geht
dann nach dem Sleep-Befehl weiter.
> Soll ich anstatt den 4.7kOhm, 3.3kOhm drantun?
Nö.
Peter
ASO, ich dachte ich habe den PCINT bei jedem Tasten Druck und so nur
messe wenn einer Drückt.
Ich habe das ganze im Moment nur ohne Sleep getestet.
Aber es sollte ja auch ohne Sleep funktionieren oder?
Szenario:
PCINT(PC0) ist Aktiviert und PD2 ist als Eingang und Pullups aus(0).
Wenn eine Taste gedrückt wird, dann wird im PCINT Interrupt der PCINT
Interrupt ausgeschaltet, PD2 wird zum Ausgang und High und ein Timer für
die Tasten mit ADC gestartet. Im Timer wird auch eine Variable
hochgezählt für die verflossene Zeit ... wenn ca nach 30 Sekunden keine
Taste gedrückt wurde ... wird der PCINT wieder aktiviert, PD2 zum
Eingang + Pullups aus(0) und der timer wird auch gestoppt.
Ist der Gedanke Richtig? Wenn das super funktioniert werde ich es mit
Sleep versuchen.
@Peter
>"4-fach Entprellung"
Wo finde ich diesen Code? du hast viele Entprellung schon gemacht :-)