Hallo!
Ich habe folgende Frage, auf deren Lösung ich einfach nicht komme:
Ich habe einen Taster an PORTC angeschlossen. Nun soll auf dem Display
die Anzahl der Tastendrücke (Zählvariable: iMessung) angezeigt werden.
z.B. 1x Drücken = "Messung-1", 3x Drücken = "Messung-3" bis Messung-5.
Zur Displayansteuerung verwendete ich Peter Fleury's Library.
Mein Display zeigt einfach nicht den Wert der Variablen iMessung an.
Woran liegt das?
Hier der Code:
1
#include<stdlib.h>
2
#include<avr/io.h>
3
#include<avr/pgmspace.h>
4
#include"lcd.h"
5
#include<inttypes.h>
6
7
8
staticconstPROGMEMunsignedcharcopyRightChar[]=
9
{
10
0x07,0x08,0x13,0x14,0x14,0x13,0x08,0x07,
11
0x00,0x10,0x08,0x08,0x08,0x08,0x10,0x00
12
};
13
14
15
/*
16
*
17
* function prototypes
18
*/
19
voidwait_until_key_pressed(void);
20
21
22
voidwait_until_key_pressed(void)
23
{
24
unsignedchartemp1,temp2;
25
unsignedinti;
26
27
do{
28
temp1=PIND;// read input
29
for(i=0;i<65535;i++);
30
temp2=PIND;// read input
31
temp1=(temp1&temp2);// debounce input
32
}while(temp1&_BV(PIND2));
33
34
35
}
36
37
Disp_Messung(shortAnzahl)
38
{
39
switch(Anzahl)
40
{
41
case1:lcd_puts("Messung-1");
42
break;
43
case2:lcd_puts("Messung-2");
44
break;
45
case3:lcd_puts("Messung-3");
46
break;
47
case4:lcd_puts("Messung-4");
48
break;
49
case5:lcd_puts("Messung-5");
50
break;
51
}
52
}
53
54
voidDisp_Ctrl(void)
55
{
56
wait_until_key_pressed();
57
58
59
lcd_command(LCD_DISP_ON);
60
61
62
63
lcd_command(_BV(LCD_CGRAM));/* set CG RAM start address 0 */
> for(i=0;i<65535;i++);
Das ist schon mal ein klasse Kandidat für den Optimizer. Mach sowas
nicht. Leere Zählschleifen werden gerne wegoptimiert. Entweder schreib
was in die Schleife rein (z.B. ein "asm(nop::);) oder (besser) nimm für
kurze Wartezeiten die fertigen Funktionen aus der delay.h.
> if (PINC == 0xFE)
Wie soll PINC denn in Deinem Programm jemals 0xFE werden? Hast Du
externe Pull-Ups da dran? Abgesehen davon: Du wartest am Ende der
Endlosschleife darauf, dass ein Taster an PIND2 gedrückt wird. Wenn das
der Fall ist, müsste gleichzeitig der an PINC0 befindliche Taster
gedrückt sein, damit überhaupt eine Änderung erfasst wird. Und dabei
müssen auch noch alle anderen Pins von Port C High-Pegel haben.
Ich denke, da ist einiges verkehrt...
Das liegt daran, dass dein Programm zwar jede Menge Code
beinhaltet, dieser Code aber völlig für die Katz ist.
Du überwachst hier:
for(;;)
{
if (PINC == 0xFE)
{
iMessung++;
}
den Eingang. Und solange dieser Eingang auf 0xFE
steht, wird die Variable hochgezählt.
Dieser Eingang steht aber lange auf 0xFE. Wenn du
da einen Taster dran hast, und die Taste auch nur
100 ms lang gedrückt hältst, dann kann dein µC die
konmplette Schleife wahrscheinlich ein paar Hundert
mal ausführen. Dementsprechend wurde die Variable
iMessung auch 100 mal erhöht.
Dein Code macht: Solange eine Taste gedrückt ist,
zähle die Variable hoch
Dein Code soll machen: Nur in dem Moment, in dem sich
der Zustand der Taste ändert, und zwar von nicht
gedrückt auf gedrückt, soll die Variable erhöht
werden.
PS: Deine debounce Funktion kannst du in der Pfeife
rauchen. Die funktioniert nicht richtig.
Hol dir aus dem Wiki die PeDa-Entprell Routinen und
benutze sie.
http://www.mikrocontroller.net/articles/Entprellung#Komfortroutine_.28C_f.C3.BCr_AVR.29
also, ich habe das STK500 und da habe ich mir einen PORT (nämlich den
PORT-C) über ein Flachkabel nach außen gelegt, wo ich einfach einen
Taster von Masse nach PIN0 schalte. Also ich habe da keinen Pullup dran.
diese "wait until keypressed" funktion kommt von Peter Fleurys Lib. Ich
habe keine Ahnung was sie macht, ich weiß nur, wenn ich sie
auskommentiere, flimmert mein Display eigenartig, drum hab ich es drin
gelassen. Ich wäre gerne bereit, eine Alternative (auch zwecks
Zählschleife) von euch anzunehmen, da ihr ja wirklich die Profis seid.
Ich möchte eigentlich erstmal nur diesen einen PIN (portC -> PIN0)
abfragen, und dann sofort per Tastendruck die dadurch inkrementierte
Variable "iMessung" auf dem Display ausgeben.
Vielen Dank
Wie gesagt:
geh auf die Web Seite auf der der Entprellcode liegt und
hol dir diesen Code. Der ist zwar für den Anfang wahrlich
nicht einfach zu durchschauen, die Details wie er funktioniert
musst du aber fürs erste nicht wissen.
Auf der Seite ist auch ein main() angegeben, welches den
Code benutzt und in Aktion zeigt. Damit sollte es dann
ein leichtes sein, dein Vorhaben umzusetzen.
> Ich möchte eigentlich erstmal nur diesen einen PIN (portC -> PIN0)> abfragen, und dann sofort per Tastendruck die dadurch inkrementierte> Variable "iMessung" auf dem Display ausgeben.>
Das ist dann fast so einfach wie einem Baby den Schnuller klauen.
> noch jemand da??
Logisch.
> Funktioniert der Timer_interrupt auch, obwohl ich schon einen Timer> in Verwendung habe?
Warum sollte es nicht funktionieren? Du brauchst getrennte Timer, wenn
du den Code direkt übernehmen willst.
Aber wenn du im eigenen Programmteil schon einen Timer am laufen hast
(ich sehe das in deinem Sourcecode nicht), könntest du überlegen, wie du
das Entprellen dort mit erledigst. Dort wäre das Entprellen
wahrscheinlich Kleinkram für nebenher.
Hallo!
Also ich schicke nun mal meine main.c, damit ihr seht um was es
geht....Ich brauche unbedingt eine Routine in meinem Code, die die
Tastendrücke verarbeitet und daraufhin am Display einen entsprechenden
Code ausgibt.
Habe einfach mal eine Endlosschleife um eine Tastenabfrage gemacht, aber
es rührt sich NULL!
Vielen Dank!
Sowas geht mit dem neuen GCC nicht mehr, diese for-schleife wird
gnadenlos wegoptimiert:
1
voidwait_until_key_pressed(void)
2
{
3
unsignedchartemp1,temp2;
4
unsignedinti;
5
6
do{
7
temp1=PIND;// read input
8
for(i=0;i<65535;i++);
9
temp2=PIND;// read input
10
temp1=(temp1&temp2);// debounce input
11
}while(temp1&_BV(PIND2));
12
13
loop_until_bit_is_set(PIND,PIND2);/* wait until key is released */
14
}
mach das stattdessen mit _delay_ms(). 20-30ms reichen. Den Maximalwert
bei _delay_ms() beachten, siehe Abschnitt Warteschleifen im
AVR-GCC-Tutorial
1
voidwait_until_key_pressed(void)
2
{
3
unsignedchartemp1,temp2;
4
unsignedinti;
5
6
do{
7
temp1=PIND;// read input
8
_delay_ms(10);
9
_delay_ms(10);
10
_delay_ms(5);
11
temp2=PIND;// read input
12
temp1=(temp1&temp2);// debounce input
13
}while(temp1&_BV(PIND2));
14
15
loop_until_bit_is_set(PIND,PIND2);/* wait until key is released */
16
}
Jetzt kontrolliere die Sourcen, ob noch mehr solcher Daumendrehschleifen
drin sind.
_delay_ms() erfordert ein #include <util/delay.h> und ein Übersetzen mit
Optimierung (-Os zum Beispiel).
ok danke:
Nächstes Problem: Object file not found.... habe avr-studio
geschlossen und wieder geöffnet, jetzt geht das kompilieren plötzlich
mit oben genanntem fehler nicht!! :(
Schon Rebuild All im Menü Build probiert?
Kommen beim Kompilieren Fehler? Kannst du die Ausgabe im Message-Fenster
komplett per Copy&Paste hier angeben? Alles dort mit Gelben oder Roten
Punkten ist fischig und muss kontrolliert werden.
Björn wrote:
> wo soll denn diese komische .elf-Datei sein?? ich finde die in keinem> Ordner!
Genau das meldet dir das GCC-Plugin auch als Fehler.
*.elf ist das kompilierte und gelinkte fertige Programm.
DIese Datei fehlt, wenn das Kompilieren fehlgeschlagen ist.
Warum das Fehlgeschlagen ist, kann zwei Ursachen haben.
1/ Der Quelltext enthält Fehler.
2/ Es gibt Probleme mit dem Projekt- bzw. Speicherpfad. Ist da bei dir
ein Leerzeichen oder ein Sonderzeichen drin?
ok funktioniert wieder, war an einem Pfadnamen gelegen und an einem
syntax-fehler im Code.
Ähm zu deinem Codebeispiel, erstmal vielen lieben Dank :)
also nach dem Einschalten des Board erscheint mal garnix auf dem
Display, dann wenn ich eine Taste drücke flaggert die Zahl nach
"Messung" zwischen 2 und 3 und nach etwa 1 sec. bleibt sie dann auf
einer von beiden stehen.
Danke!
Das das flackert liegt an den vielen Löschaktionen mit lcd_clrscr();
Mein Beispiel ist ja kein fertiges Programm, sondern etwas mit dem du
selber ein Stück weitermachen kannst. Versuche es zu verstehen und passe
es dir an.
Zwei Sachen noch:
1/ Tastenzaehler initialisieren. Der Compiler meldet korrekterweise eine
Warnung bei obigem Code ohne die Zuweisung. Wegen der zufälligen
Initialisierung kommt bei obigem Code auch keine Anfangsmeldung.
unsigned char tastenzaehler = 0; // <==
2/ Die Abfrage auf den Tastendruck besser nur auf genau das eine
interessante Bit vergleichen:
// while(PINC == 0xFE)
while(!(PINC & (1<<PC0)))
{
// Entprellen: Taste ist mindestens 25ms lang gedrückt
_delay_ms(10);
_delay_ms(10);
_delay_ms(5);
// if (PINC == 0xFE)
if (!(PINC & (1<<PC0)))
taste_gedrueckt = 1;
}
also ich füge mal meinen Code-Schnipsel ein, habe jetzt selber irgendwie
ohne Entprellung erstmal hinbekommen:
Es gibt aber noch ein Problem.: Ich schalte das Board ein. Es kommt die
Meldung "Mit Scrolltaster Durchlauf wählen". Sobald ich nun die
Scrolltaste drücke DAUERT ES etwa 1 sec, bis das Display reagiert (Die
Anzeige ändert). Wenn ich schließlich bei "Messung 3 ?" angelangt bin,
bleibt es nur 1 sec. im Display und danach ist das ganze display
"gelöscht".
Woran liegt das?
1
voidDisp_Messung(shorti)
2
{
3
switch(i)
4
{
5
case1:lcd_puts("Messung - 1 ?");
6
case2:lcd_puts("Messung - 2 ?");
7
case3:lcd_puts("Messung - 3 ?");
8
}
9
}
10
11
lcd_clrscr();//Display l?schen
12
lcd_puts("Mit SCROLLtaster\nDurchlauf wahlen");
13
//lcd_puts("Mit SCROLLtaster\nDurchlauf wahlen"); //Ausgangstext auf dem Display
1/ C-Grundlagen switch case
Es fehlt ein break; in den case Abfragen. dadurch bekommt das Programm
Durchfall. Ein auftretender case 1 fällt durch case 2 und case 3...
2/ for(;;)
{
if (PINC == 0xFE)
Wie oft schätzt du kommt dein Programm an dieser Stelle pro Sekunde
vorbei? Zig tausend Male! Auch wenn du die Taste drückst. Der AVR ist
sauschnell!
Wenn du die Taste drückst, wird jedesmal das LCD gelöscht (das dauert),
der tastenzsehler erhöht (bis er überläuft und von 0 anfängt) und dann
dreimal hintereinander kurz was anderes angezeigt und gleich
weitergestolpert in die nächste Runde.
Ich empfehle dir stark, dein Programm mal im Einzelschritt im Simulator
durchzusteppen. Dir werden Sachen auffallen, die du so nie gewollt hast
;-)
ok Danke, wird wohl das problem sein, bin nun in der Arbeit....
Werde es abends noch mal ausprobieren ;)
naja, ich bin eben kein Profi, drum bin ich ja teilweise auf euere gute
Hilfe angewiesen.
Ich werde euch abend noch berichten!
Hallo!
Ich habe nun noch eine Idee: Ich möchte desweiteren in der
switch-Anweisung die Zeit in einer Array speichern, die verstreicht,
solange ein Taster gedrückt ist.
Könntet ihr mir dabei helfen?
Sollte gehen.
Im Grunde ist das eine Anwendung der Timer so wie es im AVR-Tutorial
bzw. im AVR-GCC-Tutorial ausführlich erklärt ist. Timer mit diesen
Anleitungen so einrichten, dass er im Interrupt die Zeit hochzählt. Im
Hauptprogramm Startzeit merken, Endzeit abfragen, Differenz bilden,
Ergebnis formatieren und ausgeben. Pronto.
Hast du den Rest des Programms schon fertig geschrieben und entwanzt und
nach Wunsch lauffähig auf'm µC, so dass man den die Zeitbehandlung nur
noch einbauen muss, oder hapert es noch an allem?