C PIN als Eingänge, reagieren zu schnell

oabel5

Neues Mitglied
07. Apr. 2010
5
0
0
Sprachen
Hallo,
ich benutze den Atmel Studio 6.2; ich habe ein Programm (in C) geschrieben, ich steuere mit dem ein HD44780.
[CCODE]DDRC &= ~(1<<PINC0);
DDRC &= ~(1<<PINC1);
DDRC &= ~(1<<PINC2);
DDRC &= ~(1<<PINC3);
DDRC &= ~(1<<PINC4);

PORTC &= ~(1<<PC0);
PORTC &= ~(1<<PC1);
PORTC &= ~(1<<PC2);
PORTC &= ~(1<<PC3);
PORTC &= ~(1<<PC4);

while(1)
{

if(PINC & (1<<PC0))tag++;
if(PINC & (1<<PC1))monat++;
if(PINC & (1<<PC2))jahr++;
if(PINC & (1<<PC3))min++;
if(PINC & (1<<PC4))stunde++;

if(sek>=60) { sek=0; min++;}
if(min>=60) { min=0;stunde++;}
if(stunde>=24) stunde=0;
if(tag>=32) { tag=1;monat++;}
if(monat>=13) monat=1;

sprintf(buffer,"%.2i:%.2i:%.2i %.2i:%.2i:%.2i",stunde, min, sek,tag,monat,jahr);
LCDstring(buffer, 0, 2);
if(num>=100)
{
sek++;
num=0;
}
num++;[/CCODE]
mein Problem liegt daran, daß, wenn ich die Zeit oder Datum ändern will (durch drücken der Tasten), diese Variablen ändern sich sehr schnell. Das ist mir klar, es hängt ab, wie lange ich die Taste drücke.
Deswegen habe ich ein delay() nach der IF Abfrage eingebaut:

[CCODE]if(PINC & (1<<PC0)){_delay_ms(100);tag++;};[/CCODE]
nach flashen sehe ich auf dem Display, daß die Sekunden und das Jahr sich um "eins" erhöht, warum?.
Wenn ich diese delay() nach jedem IF einbaue, dann bleibt alles stecken, also die Sekunden erhöhen sich nicht, als ob das Programm in eine endlose Schleife wäre.
Kann mir jemand bitte sagen, wo mein Fehler ist? Ich danke für jede Antwort.
Abel.
PS. Die Pins 0-4 an Port C habe ich jeden mit einem Widerstand 100Ohm auf Masse gezogen. Bei jedem dieser PIN ist ein Taster nach VCC eingebaut. Ich benutze den Atmega640.
 
Mahlzeit,

Dein Problem ist, dass die Abfrage permanent ausgeführt wird, damit hast Du sowas erreicht wie "die LED leuchtet, solange ich auf die Taste drücke". Verstehst, wie ich meine?

Was Du brauchst, ist noch eine Variable, die den Zustand (status) der Taste abbildet und dann beim Setzen der Variable (tag, monat, ...) mit abgefragt wird. Beim Loslassen des Tasters wird sie dann wieder zurückgesetzt.

Alternativ machst Du am Ende der while ein etwas längeres Delay von sagen wir mal 500ms, dann werden die Taster nur zwei Mal pro Sekunde abgefragt.

100Ohm? Ein ungewöhnlicher Wert, normallerweise nimmt man 10k.
 
...Dein Problem ist, dass die Abfrage permanent ausgeführt wird, damit hast Du sowas erreicht wie "die LED leuchtet, solange ich auf die Taste drücke". Verstehst, wie ich meine?...
Ich versteh's nicht...

Die Hauptschleife läuft durch.
Bei jedem Durchlauf wird jede Taste einmal geprüft (und die dazugehörende Variable ggf inkrementiert),
Anschließend werden vorgegebene "Überläufe" der Variablen behandelt,
Dann wird aus den Variablen ein String abgeleitet und ausgegeben,
Dann werden die Sekunden inkrementiert, aber nur bei jedem hundertsten Durchlauf.

Die Ausgabe erfolgt bei jedem Durchlauf. Unabhängig davon ob 'ne Taste gedrückt wird, oder nicht...

Eigentlich sollte doch nur was an das Display ausgegeben werden, wenn sich was geändert hat - das Display stellt seinen Inhalt solange (selbst) statisch dar, oder nicht?

Warum sich das Jahr überhaupt ändert, ist aus dem Code überhaupt nicht ersichtlich, warum es mit der Warteschleife dann gar nicht mehr zu gehen scheint, ist mir nicht klar...
 
:)

Schau Dir das mal an (der Rest ist erstmal egal):

[CCODE]
while(1)
{

if(PINC & (1<<PC0))tag++;
[/CCODE]

Das sagt aus "wenn PC0 gedrückt ist, inkrementiere die Variable tag". An und für sich okay, aber mit wieviel MHz läuft der Atmega640 nochmal? Sprich die Variable tag wird solange inkrementiert, solange ich die Taste drücke, auch wenn es 100.000 Durchläufe der while sind, egal, das Ding wird inkrementiert und dadurch auch die Variable monat und jahr.
 
Richtig, aber eben genau das erklärt die Frage nicht.
Die Schleife läuft eben zich-mal pro Sekunde durch. Jedesmal wird der (ein) Text auf dem Display ausgegeben. Der wesentliche Zeitverbrauch ist dabei sicher die Formatierung/Ausgabe (bestimmt also die Durchlauffrequenz). Solange man also 'ne Taste hält, inkrementieren die Werte (entsprechend der hohen Durchlauffrequenz) sehr schnell. Wird kein Taster betätigt, inkrementieren die Sekunden nur noch bei jedem hundertsten Durchlauf, und der Rest entsprechend dem Uhrwerk - und werden jedesmal angezeigt.

Die Frage war jetzt, warum durch das zusätzliche delay gar nichts mehr geht - erwarten würde man ja während einer Betätigung ein langsameres inkrementieren der Werte (eben 'ne Zehntelsekunde Pause vor jedem Inkrement, also effektiv über den Daumen Zehn inkrements pro Sekunde).

Zum Widerstand: Da der Strom aber so nicht durch den AVR geht (da das Eingänge sind), nicht problematisch. Bei angenommenen 5V Versorgungsspannung und idealisierten 0 Ohm am Taster/Verdrahtung würden bei Betätigung I=U/R=5V/100Ohm=50mA fliessen. Der Widerstand würde P=U*I=5V*50mA=250mW in Wärme umsetzen. Ein Viertelwatt-Widerstand wäre also grenzwertig.
Edit:
... auch wenn es 100.000 Durchläufe der while sind, egal, das Ding wird inkrementiert und dadurch auch die Variable monat und jahr.
Wo? (also das Jahr, bei nicht betätigter Taste)
 
[CCODE]if(PINC & (1<<PC0)){_delay_ms(100);tag++;};[/CCODE]


Das Semikolon nach der geschweiften Klammer gehört da nicht hin! -> ok, das macht vermutlich nichts aus - ist mir nur aufgefallen.

Wenn du die delay-Funktion verwendest, hast du
#include <util/delay.h> eingebunden?

Wurde F_CPU (Takt, mit der dein Atmega läuft) in deinem Programm definiert? über Toolchain, bzw. über ein #define?

Wo werden deine Variablen initalisiert? - sieht man bei dem Codeschnippsel nicht? - evtl. gesamten Code posten?

Ich persönlich finde die Verwendung von Softwaretimern nicht gut, also die Verwendung von "_delay", da das ganze Programm ausgebremst wird. Also einen Hardwaretimer verwenden (Interrupt) Außer das spielt keine Rolle...

Damit du mit einem Tastendruck nur einmal inkrementierst würde ich zum einen eine Flankenauswertung machen (also inkrementiert z.B. nur bei "fallender Flanke") und zum einen musst du eine Entprellung realisieren - entweder über Hardware (z.B. RC-Glied) oder über Software (Hardwaretimer / Interrupt).

Beispiel bzw. um sich einzulesen (weiß ja nicht wie fit du im Programmieren bist) gibts hier:
http://www.mikrocontroller.net/articles/Entprellung

Ich persönlich würde nicht dieses Beispiel nehmen, selber programmieren und porbieren, dann lernt man auch was ;)


Wenn ichs richtig sehe, dann kann das Jahr ja nur über die Taste inkrementiert werden. Eigentlich darf sich das Jahr also nicht automatisch erhöhen.
Probier doch mal aus, wenn du vor der while-Schleife deine Variable (also das jahr) auf 0 setzt, ob es dann auch passiert....
 
Hi
Nun, C ist nicht grad meine Welt, aber mir ist auch so klar, welchen Fehler du machst. Du willst, das bei einem Tastendruck der Zähler auch nur um 1 erhöht wird. Damit das sauber läuft, brauchst du eine Flankenauswertung. Der Zähler reagiert damit nicht auf die Taste, sondern auf den Statuswechsel. Ein delay an der Stelle kann Abhilfe schaffen, ist aber keine saubere Lösung und hemmt auch den Ablauf deines Programms.
Mach mal folgendes:
Lege 5 Variablen an. In eine liest du bei jedem Durchlauf die Bits ein (aktuell) Nun setzt du eine Exclusiv-Oder auf diese sowie die zweite Variable (alt). Das Ergebnis packst du in die dritte Variable. (Wechsel) Nun kannst du noch herausfinden, wie der Wechsel stattgefunden hat, von 0 nach 1 oder von 1 nach 0. Dazu wird Aktuell mit Wechsel verundet . Eine 1 kann nur drin stehen, wenn der letzte Status von alt 1 war, also ist der neue Zustand 0 und du hast den Wechsel von 1 nach 0. (Flanke0) Verundest du Aktuell mit Wechsel, muss eine 1 in aktuell stehen und damit ein Wechsel von 0 nach 1 stattgefunden haben. (Flanke1). Nach diesen Logikoperationen setzt du alt auf aktuell, d. H. Inhalt der Variablen Aktuell wird in Variable alt kopiert.
Die Bits in Flanke1 oder Flanke0 nimmst du als Ereignis für deinen Zahler und setzt bei Bearbeitung das Flankenbit auf 0 zurück. Nun musst du wirklich jedes mal den Taster betätigen, wenn du weiter zählen willst.
Und so geht es:
Port C Bit 0 bis 4 in die Variable Aktuell Bit 0 bis 4. Bit 5, 6 und 7 bleiben unverändert.
Exlusiv Oder mit Aktuell 00001010
und Alt 00010010
Ergebnis in Wechsel 00011000 Bit 3 und 4 haben sich geändert
Und-Verknüpfung mit Alt 00010010
Ergebnis in Flanke0 00010000 Status Bit 4 ist auf 0 gefallen
Nochmal Wechsel 00011000 Bit 3 und 4 haben sich geändert
Und-Verknüpfung mit Aktuell 00001010
Ergebnis in Flanke1 00001000 Status Bit 3 ist auf 1gewechselt
Alt <= Aktuell

If Flanke1.0 =1 > Inc Zähler0
Flanke1.0 = 0
If Flanke1.1 =1 > Inc Zähler1
Flanke1.1 = 0
If Flanke1.2 =1 > Inc Zähler2
Flanke1.2 = 0
If Flanke1.3 =1 > Inc Zähler3
Flanke1.3 = 0
If Flanke1.4 =1 > Inc Zähler4
Flanke1.4 = 0
Sorry, das ich es dir nicht in C verpacken kann.


Gru0 oldmax
 
Hallo an Alle, die auf meine Frage geantwortet haben.
Erstmal Vielen Dank an euch alle.
Ich komme gerade zurück aus dem Urlaub, daher habe ich nichts geantwortet. Ich werde die Tips anwenden und dann melde ich mich.
Gruß.
Abel
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)