Guten Morgen liebe Forum Gemeinde,
ich habe mich an den vergangenen Tagen mal mit einem Projekt, welches
ich im Internet gefunden habe auseinander gesetzt.
http://extremeelectronics.co.in/avr-projects/avr-project-relay-timer-with-atmega8-avr-mcu/
Dazu habe ich alle nötigen Daten heruntergeladen und im AVR Studio
eingefügt, sowie die Schaltung auf meinen Steckbrettern
zusammengesteckt. Siehe Foto.
Leider funktioniert es aber nicht. Ich habe aber darauf geachtet, die
Fuses umzustellen.
Anschließend habe ich es versucht mit AVR Simulator IDE zu simulieren,
auch ohne Erfolg. (Aber ohne die Fuses).
Kann mir jemand Tipps geben wie ich es zum laufen bekomme?
Hier der Code aus LCD_RELAY_TIMER.c:
Sebastian M. schrieb:> Leider funktioniert es aber nicht.
Was heißt funktioniert nicht?
Fang mit was einfacherem an.
Steck mal eine LED an einen Port Pin und sieh nach, ob der µC überhaupt
läuft, indem du die LED blinken lässt.
Im Moment sind da zu viele ungetestete Systeme im Spiel, so dass man
nicht wirklich eine Aussage darüber treffen kann, was das Problem ist.
Also muss man abspecken und mit einem möglichst einfachen Testprogramm
System für System, Komponente für Komponente in Betrieb nehmen.
Autsch.
Der LCD Code ist furchtbar. So wie der geschrieben ist, trau ich dem
nicht über den Weg.
Hol dir vom P.Fleury die LCD Library, konfigurier sie und mach damit mal
ein Testprogramm.
PS: Auch der restliche Code ist furchtbar. Aber das ist ein anderes
Thema.
Sebastian M. schrieb:> wovon möchtest du ein Foto haben, von der Hardware?
Nein, von deiner Schwester.
Natürlich von deiner Hardware!
Was denkst du wieviele hier schon nach Hilfe gefragt haben und Bein und
Stein geschworen haben, ihre Anschlüsse wären korrekt und dann stellte
sich nach Stunden heraus, dass sie sich zb bei den Pinnummern verzählt
haben?
Sebastian M. schrieb:> #define LCD_RS D> #define LCD_RS_POS PD6>> #define LCD_RW D> #define LCD_RW_POS PD5
Das kann nicht stimmen.
Wenn am Port D die Datenbits auf den Pins PD4 bis PD7 liegen, dann kann
die RS Leitung nicht auf PD6 liegen
Karl Heinz Buchegger schrieb:> Das kann nicht stimmen.>> Wenn am Port D die Datenbits auf den Pins PD4 bis PD7 liegen, dann kann> die RS Leitung nicht auf PD6 liegen
Die Ports am Controller sind PD0 - PD3 das sind die Anschlüsse am
LCD D4 - D7.
Sebastian M. schrieb:> Karl Heinz Buchegger schrieb:>> Das kann nicht stimmen.>>>> Wenn am Port D die Datenbits auf den Pins PD4 bis PD7 liegen, dann kann>> die RS Leitung nicht auf PD6 liegen>> Die Ports am Controller sind PD0 - PD3 das sind die Anschlüsse am> LCD D4 - D7.
Ja, habs schon gemerkt.
In deinem Projekt ist eine etwas andere Version der LCD Routinen als
die, die ich mir von der angegebenen Web-Site gezogen habe.
Karl Heinz Buchegger schrieb:> In deinem Projekt ist eine etwas andere Version der LCD Routinen als> die, die ich mir von der angegebenen Web-Site gezogen habe.
Wie meinst du das? Habe diese runtergeladen und eingebunden und
eigentlich nichts verändert.
Sebastian M. schrieb:> Hier die Bilder...
Ach ja, der Aufbau ist nicht mehr komplett, hatte bereits angefangen mit
dem Rückbau. LCD ist aber noch dran gewesen...
Sebastian M. schrieb:> Ach ja, der Aufbau ist nicht mehr komplett, hatte bereits angefangen mit> dem Rückbau. LCD ist aber noch dran gewesen...
Da ist aber nicht wirklich irgendwas nachvollziehbar zu erkennen.
Karl Heinz Buchegger schrieb:> Da ist aber nicht wirklich irgendwas nachvollziehbar zu erkennen.
Das habe ich mir schon fast gedacht. Ich hatte es bereits mehrmals
kontrolliert und immer wieder neu zusammengesteckt.
Welche unterschiede hast du denn in den Routinen gefunden?
Habe jetzt auch Unterschiede festgestellt zwischen dem Quellcode der auf
der Homepage abgedruckt ist und der Datei die gedownloaded wird. Dabei
ist meiner Meinung nach die Abgedruckte version die "fehlerhafte".
cyblord ---- schrieb:> Ist auch kein Fehler, sondern eine Warnung.
das klingt so einfach. Spielt es keine rolle, wie ich main() deklariere?
Was schlägst du vor?
Sebastian M. schrieb:> cyblord ---- schrieb:>> Ist auch kein Fehler, sondern eine Warnung.>> das klingt so einfach. Spielt es keine rolle, wie ich main() deklariere?> Was schlägst du vor?
int
Deshalb sollte auch ans Ende der main() ein return 0.
So macht man das sauber. Auch wenns im Controller keine Rolle spielt.
Und Rückgabetyp weglassen ist nie gut. Wieso fehlt der überhaupt?
cyblord ---- schrieb:> nt>> Deshalb sollte auch ans Ende der main() ein return 0.
nur zum Verständnis, da ich den rückgabetyp nicht weiterverarbeite, ist
es egal wie ich diesen Deklariere?
Sebastian M. schrieb:> cyblord ---- schrieb:>> nt>>>> Deshalb sollte auch ans Ende der main() ein return 0.>> nur zum Verständnis, da ich den rückgabetyp nicht weiterverarbeite, ist> es egal wie ich diesen Deklariere?
Nach irgendwelchen C Standards (die ich grade nicht genau benennen kann)
sollte main() einen INT zurückgeben. Ich würde dabei bleiben. Auf einem
Laufzeitsystem, ist das wichtig, damit ein programm einen errocode
rückgeben kann. Darum auch return 0, da 0=kein fehler, <>0 = Fehler.
Du hast kein Laufzeitystem auf dem Controller, darum egal. Trotzdem
würde ich mich bei C daran halten.
cyblord ---- schrieb:> Nach irgendwelchen C Standards (die ich grade nicht genau benennen kann)> sollte main() einen INT zurückgeben. Ich würde dabei bleiben. Auf einem> Laufzeitsystem, ist das wichtig, damit ein programm einen errocode> rückgeben kann. Darum auch return 0, da 0=kein fehler, <>0 = Fehler.> Du hast kein Laufzeitystem auf dem Controller, darum egal. Trotzdem> würde ich mich bei C daran halten.
Ok, danke für den Tipp.
Ich werde jetzt die Schaltung im Keller erneut aufbauen. Mal schauen ob
es mit den neuen Komponenten klappt.
Sebastian M. schrieb:> kann ich dir auch nicht sagen, dieses Projekt stammt von einer Homepage,> ich versuche nur zur Übung das zum laufen zu bekommen.
Konzentrier dich erst mal nur auf das LCD und lass den Timer-Code weg.
Ein einfaches
1
intmain()
2
{
3
InitLCD(0);
4
LCDWriteString(" Welcome ");
5
6
while(1)
7
;
8
}
reicht, um das LCD in Betrieb zu nehmen und den Funktionsnachweis zu
erbringen.
Alles andere sind erst mal nur zusätzliche Möglichkeiten, Fehler zu
machen.
Und so prickelnd gut ist der Code von diesem Timer dann auch wieder
nicht geschrieben.
So habe die Schaltung erneut zusammengesteckt, leider ohne Funktion. Als
ich dann das Quarz gegen ein frisch geliefertes ausgetauscht habe, habe
ich endlich eine Anzeige bekommen.
=> Quarz defekt <=
Nun gibt es aber ein neues Problem, welches dieses mal nicht an der
Hardware liegen kann.
Nach dem Einschalten ist folgendes zu sehen:
("||||||||||||||||") = schwarze Rechtecke
(" ")
Nach dem Drücken von "Select" erscheint:
(" Welcome ")
(" Relay Timer ")
dann passiert nach 4 sek. nichts, erst durch drücken von
"select" oder "up" oder "down" für eine dauer von 3 sek. danach ist
folgendes Bild:
("Set Time - 00:00")
(" Start ^ ");
Jedes drücken einer Taste führt wieder zum Bild:
(" Welcome ")
(" Relay Timer ")
Karl Heinz Buchegger schrieb:> Und so prickelnd gut ist der Code von diesem Timer dann auch wieder> nicht geschrieben.
Leider bin ich aber nicht in der Lage, selbst einen Code zu schreiben.
Somit bleibt mir nur noch die Möglichkeit, einen zu suchen, und diesen
dann nach meinen Wünschen anzupassen.
Sebastian M. schrieb:> Leider bin ich aber nicht in der Lage, selbst einen Code zu schreiben.> Somit bleibt mir nur noch die Möglichkeit, einen zu suchen, und diesen> dann nach meinen Wünschen anzupassen.
Ich denke du willst üben?
Dann analysier den Anfang des Codes, sieh nach was passiert (die ganze
Timer Sache lässt du erst mal weg), und analysiere wie die Sache mit den
Tasten funktioniert.
Und dann schreibst du den ganzen Teil, der sich um LCD, Tasten und
erhöhen/erniedrigen der einzelnen Zahlenwerte dreht neu und nach deinen
Vorstellungen.
Eine bessere Übung gibt es nicht.
Wenn der Teil dann erst mal zufriedenstellend funktioniert, dann können
wir uns über den Timer unterhalten, bzw. wie man dann die eingestellte
Zeit tatsächlich ablaufen lässt. Aber erst mal hast du mit LCD, Tasten
und deren Auswertung genug zu tun.
Sorry. Aber wer etwas selber bauen will, der muss auch selber ran. Das
war schon immer die Maxime hier im Forum.
Sebastian M. schrieb:> Karl Heinz Buchegger schrieb:>> Eine bessere Übung gibt es nicht.>> Hast du auch einen Vorschlag wie man dort am besten ran geht?
Sicher.
Ignorier erst mal die komplette Timer Sache.
Du hast 2 Variablen, die Stunden und die Minuten.
Und du hast 3 Tasten.
Mit einer Taste wählst du aus, welchen Zahlenwert (Stunden oder Minuten)
du verändern willst und mit den anderen beiden erhöhst bzw. erniedrigst
du den Wert. Und dann werden die neuen Werte wieder am LCD angezeigt.
Analysier den Code. Genau diese Funktionalität ist da im Grunde schon
programmiert, wenn auch etwas ... seltsam und langatmig. D.h. du hast
schon Code, an dem du dir ansehen kannst, wie man zb den Wert einer
Variablen ausgibt. Du hast schon Code der, ähm, Tastenabfragen
realisiert. Nur bitte nimm nicht diese besch.... delay Funktionen des
Autors, sondern wenigstens die im AVR-GCC bereits vorhandenen.
Fürs erste reicht es ja auch, wenn du nach dem Drücken einer Taste erst
mal 2 unterschiedliche Texte anzeigst
1
intmain()
2
{
3
lcd_init(0);
4
5
PORTB|=(1<<PB0);
6
7
while(1)
8
{
9
if(PINB&(1<<PB0))
10
{
11
LCDGotoXY(0,0);
12
LCDWriteString("Oben ");
13
}
14
else{
15
LCDGotoXY(0,0);
16
LCDWriteString("Unten");
17
}
18
}
19
}
Dann gehts eben weiter. Nicht etwas tun solange eine Taste gedrückt ist,
sondern eine gedrückte Taste nur einmal auswerten. Um beim Original zu
beliben, zb so
1
intmain()
2
{
3
uint8_toldPin;
4
uint8_tnewPin;
5
6
uitn8_tcnt=0;
7
8
lcd_init(0);
9
10
PORTB|=(1<<PB0);
11
12
oldPin=PINB&(1<<PB0);
13
14
LCDWriteIntXY(4,1,cnt,2);
15
16
while(1)
17
{
18
newPin=PINB&(1<<PB0);
19
20
if(newPin!=oldPin)// gibts einen Unterschied zu 'vorher'
21
// wenn ja, dann ist die Taste entweder
22
{// gedrückt oder losgelassen worden
23
cnt++;
24
LCDWriteIntXY(4,1,cnt,2);
25
}
26
oldPin=newPin;
27
28
_delay_ms(10);
29
}
30
}
(@Alle: Ja ich weiß, die Entprellung ist nicht gut gelöst. Aber bei den
Voraussetzungen ist alles andere noch zu schwer für ihn.)
Und so geht das eben weiter. Eines führt zum anderen.
Als nächstes brauchst du dann eine zweite Taste, so dass du den Wert
nicht nur erhöhen, sondern auch verringern kannst.
Klappt das, dann kommt eine 2-te Variable ins Spiel, die verändert wird.
Und du musst irgendwie zwischen den beiden umschalten, so dass du beide
voneinander unabhängig erhöhen/erniedrigen kannst.
Dazu brauchst du eine weitere (3-te) Taste, die die Umschaltung macht.
Und du musst deinem Benutzer irgendwie anzeigen, welche der beiden
Zahlen er gerade verändert.
Aber Grundvoraussetzung ist es nun mal, dass du Tasten auswerten und
Aktionen daran knüpfen kannst. Perfekt um das zu üben.
Sebastian M. schrieb:> Puh, ein ganz schönes Brett. Ich mach mich gleich dran...
Tja. So ist das nun mal, wenn man etwas selber bauen will.
Man muss es lernen.
Aber dafür kriegt man dann auch exakt das, was man sich vorstellt :-)
Karl Heinz Buchegger schrieb:> lcd_init( 0 );
das ist doch aber nicht der Aufruf der funktion in meinem Projekt oder?
Hier lautet deiser Befehl InitLCD(0).
Wollen wir von vorne rein gleich die bessere LCD Routine nehmen?
Sebastian M. schrieb:> Karl Heinz Buchegger schrieb:>> lcd_init( 0 );>> das ist doch aber nicht der Aufruf der funktion in meinem Projekt oder?> Hier lautet deiser Befehl InitLCD(0).
OK. Dann eben so.
Ich hab nicht bei jedem Aufruf der vorgefertigten Funktionen nachgesehen
(*), ob sich die Funktion wirklich so schreibt. Dazu hast du ja die
'Vorlage' mit dem Originalcode, in dem man schnell und einfach nachsehen
kann.
(*) das ist von hier aus nämlich recht mühsam zu bewerkstelligen. Aber
du hast ja den Code vor dir - sieh nach, wie die Funktion wirklich
heißt. Aus dem Zusammenhang sollte klar sein, welche Funktion gemeint
ist.
Sebastian M. schrieb:> Wollen wir von vorne rein gleich die bessere LCD Routine nehmen?
Wenn die hier jetzt funktionieren, dann nimm sie auch. Die sind momentan
das kleinste Problem, so wie ich das sehe.
Sebastian M. schrieb:> Ehrlich gesagt, verstehe ich jetzt nicht was dass oben für> Codeausschnitte sind? Der erste ist ja nur ein Test, knopf drücken => Anzeige.>> Aber sagt>
1
>PORTB|=(1<<PB0);
2
>
>> nicht aus , dass der Ausgang auf logisch 1 gesetzt werden soll?
Nein, nicht nicht in diesem Fall.
Denn der Pin PB0 am Port B wurde ja nicht mittels DDRB auf Ausgang
programmiert. Daher ist er nach wie vor ein Eingang und daher schaltet
diese Anweisung den Pullup Widerstand für diesen Pin ein.
AVR-GCC-Tutorial> Der erste ist ja nur ein Test
Aber offenbar einer, den du in seiner Einfachheit nicht komplett
verstehst.
Üben!
Solche Dinge, wie die Zusammenhänge der DDRx, PORTx und PINx Register
dürfen kein Problem sein. Sowas musst du einwandfrei erkennen können,
wenn du es siehst.
Denn sonst unterhalten wir uns über eine einfache Blinddarmoperation,
dessen ausführender Arzt Schwierigkeiten beim Aufkleben eines Pflasters
hat. Keine guten Voraussetzungen.
Sagtest du nicht, du willst üben?
Dann übe! Und fang endlich an, nicht nur "malen nach Zahlen" zu
betreiben, sondern deine Programme selbst zu entwickeln!
Den Grundstein hab ich dir gelegt um daraus das Programm zu entwickeln.
Die weitere Entwicklung wirst du aber selber machen müssen. Denn letzten
Endes willst DU ja dieses Projekt stemmen, nicht ich. Ich helfe dir
nur, wenn du nicht mehr weiterkommst (und glaub mir, es wäre für mich
wesentlich einfacher das Programm einfach zu schreiben als dich da durch
die Entwicklung zu begleiten. Die 30 Minuten, die ich für das
vollständige Programm brauchen würde, sind schon lange um)
Karl Heinz Buchegger schrieb:> Die 30 Minuten, die ich für das> vollständige Programm brauchen würde, sind schon lange um
Respekt... ich werde wahrscheinlich 3000 minuten brauchen... :-/, da ich
das mit den schaltern nicht schnalle.
Hey,
zur Info, ich habe jetzt zumindest den Ursprünglichen Code zum laufen
bekommen. In der Schaltung von der Homepage fehlte die Verbindung von
Pin 22 (AGND) zu GND und 21(AREF) zu +5V.
Wenn ich jetzt eine Zeit einstelle und starte:
2min eingestellt und gestartet:
Wahrscheinlich es liegt an die Timer Dinge, es ist die Timer
Funktionalität die Probleme gibt.
Es scheint dass das Problem ist das deine Sekunden Counter in eine
Variable ohne Vorzeichen gespeichert ist.
Also, im General jede Variable ist nur ein Sammlung von Bits die
irgendwo in den Arbeitsspeicher des Mikrocontroller liegen. Wie die Bits
interpretiert werden stellt man ein durch den Typ Deklaration.
Zum Beispiel:
1
chara=0;// 8 bit variable (mit oder ohne Vorzeichen abhängig von Kompilator/Plattform) und Anfangswert = 0
2
unsignedcharb=0;// 8 bit variable ohne Vorzeichen und Anfangswert = 0
3
signedcharc=0;// 8 bit variable mit Vorzeichen und Anfangswert = 0
was passiert wenn man eins subtrahiert:
1
a--;// a hat jetzt ein Wert von -1 oder 255 (hängt von ob der Kompilator char als ein Typ mit oder ohne Vorzeichen nimnt )
2
b--;// b hat jetzt ein Wert von 255 ( Typ ohne Vorzeichen, 0 ist die Minimalwert)
3
c--;// a hat jetzt ein Wert von -1 ( Typ mit Vorzeichen, -127 ist die Minimalvert. Analogisch zum der Fall mit Variable b, wenn b ein wert von -127 hätte und eins davon subtrahiert wird, dann würde c ein Wert von +127
Wieso sieht man 00:02:99 statt 00:02:255? Ich nehme an, dass wenn deine
Anzeige Funktion ein Wert mit Mehr Stellen als erwarten kriegt dann
Zeigt die die Maximale Wert die man mit die gewünschte Stellenmenge
anzeigen kann. Ich bin aber nicht sicher, ich hab fast kein Ehrfahrung
mit avr gcc und überall kein mit diese LCD Code.
Wenn du Englisch verstehen kannst (es ist sowieso extrem schwer
Programmieren zu Lernen ohne Englisch zu verstehen zu können) lies mal
den Artikel hier: https://en.wikipedia.org/wiki/C_data_types
Bisschen offtopic:
Ich weiss dass das ganze Ding an Anfang sehr verwirrend aussehen kann.
Man muss gleichzeitig auf Software und Hardware aufpassen: Dinge wie:
versorgt den Spannungsquelle eine gleiche Spannung? Auch under Last?
Sind die Kondensatoren für den Quarz die Richtige wert? Hab ich die
richtige Fuses am Kontroller programiert? Benutzt den Projektcode
irgendwelche nicht Standarte Erweiterungen und werden die von den
Kompilator die ich benutze Unterstützt? und viele viele mehr ähnliche
Fragen...
Wenn aber in die Ende man sein Projekt zu eine korrekt funktionierende
Zustand bringt alle diese Schwierigkeiten blenden in Vergangenheit aus.
Mindestens bis man genug zum Spielen mit seine neue Gadget hatte und ein
neues und mehr kompliziertes Projekt annimmt.
wunder bar, danke euch beiden.
Bin gerade am rumspielen, klappt auch ganz gut.
aber ein problem bekomm ich nicht weg, und zwar ist das der blinkende
Cursor.
Ich habe folgende Änderungen versucht:
LCD.h
1
...
2
#define LS_BLINK 0B00000001 //geändert auf 0B00000000
3
#define LS_ULINE 0B00000010 //geändert auf 0B00000000
4
...
5
#define LCDClear() LCDCmd(0b00000001) //geändert auf 0b00000000