Autor | Thema |
---|---|
Turambar
SP-Schnüffler
Registriert seit: Jun 2005 Wohnort: Österreich Verein: Beiträge: 874 Status: Offline |
Beitrag 133930
, Countdown mit LCD/ATmega8
[18. Dezember 2007 um 20:14]
HiHo,
als erstes richtiges Projekt möchte ich eine Countdownuhr realisieren, und zwar mit einem ATmega8, 2 8x1 LCDs und C als Programmiersprache. Aber ich steig bei mikrokontroller.net einfach nicht durch, jeder macht das anders, jeder hat andere Routinen und als Anfänger hat man da keine Chance, irgendwas zu verstehen. Das Tutorial bringt mich da auch nicht weiter, weil da reine Theorie drinsteht und kein Anwendungsbeispiel dabei ist. Deshalb meine Frage: ich will nen einfachen Timer oder sonst irgendwas, das mir jede Sekunde eine Variable um 1 verringert, nen Countdown halt... Ich weiß es ist lächerlich aber das bekomm ich nicht auf die Reihe -.- Wär schön wenn mir das jemand erklären könnte, da ich im Mikrocontrollerforum nicht durchsteige.. Lg Stefan Bei der Eroberung des Weltraums sind zwei Probleme zu lösen: Die Schwerkraft und der Papierkrieg. Mit der Schwerkraft wären wir fertig geworden. - Wernher Freiherr von Braun http://are.modellraketen.at MfG Stefan |
TheSmartGerman
PU-Meister Registriert seit: Jun 2007 Wohnort: Schwabenland Verein: Beiträge: 245 Status: Offline |
Beitrag 133933
[18. Dezember 2007 um 21:42]
Hallo stefan,
also gleich zu Anfang ich bin auch Anfänger was die Programmierung angeht aber im großen und ganzen nutze ich die gleiche Plattform ATMega8 bzw 88, C und LCD-Display. Als Entwickungsumgebung nutze ich AVR Studio 4 mit WinAVR tut soweit ganz gut... Also rein theoretisch kanns du mit #include <util/delay.h> und delay_ms() ne Verzögerung realisieren... allerdings hab ich das Prob dass mir der Compieler nen Code erzeugt der zu groß für den Flash des Controllers ist und ich hab die richtigen "Schalter" nicht gefunden. Mein Studium fordert mir gerade einiges ab sodass ich erst wieder nach den Prüfungen ab Feb wieder in die Vollen steigen kann. Sonst die Codesammlung bei mikrocontroller.net durchsehen... Gruß Benedikt |
Turambar
SP-Schnüffler
Registriert seit: Jun 2005 Wohnort: Österreich Verein: Beiträge: 874 Status: Offline |
Beitrag 133935
[18. Dezember 2007 um 22:56]
ja aber woher weiß ich denn welchen Timer das nutzt? Die info brauch ich, da ich ja nur so auf den entsprechenden interrupt reagieren kann
Bei der Eroberung des Weltraums sind zwei Probleme zu lösen: Die Schwerkraft und der Papierkrieg. Mit der Schwerkraft wären wir fertig geworden. - Wernher Freiherr von Braun http://are.modellraketen.at MfG Stefan |
MarkusJ
Gardena Master of Rocketry
Registriert seit: Apr 2005 Wohnort: Kandel Verein: Beiträge: 2148 Status: Offline |
Beitrag 133938
[18. Dezember 2007 um 23:20]
Hi Stefan,
ich empfehle den für den Einstieg, auch wenn du C programmierst, das Buch von Roland Walter, in welchem es komplett um Bascom geht. Daneben habe ich mir noch ein weiteres, Bascom-spezifisches Buch gekauft (sind eine Menge netter Hintergrundinfos dabei) und angefangen, eine Datenblatt durchzugehen. Inzwischen bin ich dabei, ohne je einen AVR geproggt zu haben, auf C umzuschwenken. Dass ich durch die Bücher schon eine Menge über die AVRs weiß, hilft mir nun dabei, das etwas kryptischere C zu verstehen. Inzwischen hab ich mich durch das AVR-GCC-Tutorial durchgelesen und glaube, alles weitestgehend verstanden zu haben ... ein Paar Tipps: Das AVR-GCC-Tutorial lehrt dich NICHT im Programmieren mit C, es geht hauptsächlich auf plattformspezifische Eigenheiten ein. Andererseits gibt es wenig/keine Bücher zum Thema C auf AVRs. Die Lösung: Wenn du dich durch das Tutorial liest, musst du bei allem unbekannten hier ein oder mehrere Tutorials zu Rate ziehen, ich habe die Nummer eins (Achtung, sehr verworren, komplex und nur bedingt für den Anfang geeignet) und Nummer fünf zur Rate gezogen. Viel Erfolg! mfG Markus PS: Einige Denkanstöße: Einen Timer nehmen (Timer1 dürfte wegen 16 Bit breite komfortabler sein), einen möglichst großen Prescaler wählen, und dann aus AVR-Takt/Prescaler errechnen, mit welcher Frequenz der Timer zählt. Dann legst du den Startwert so fest, dass er genau so viele Schritte zählen muss, wie er in einer Sekunde schafft, der Timer zählt dann immer in einer Sekunde hoch zu diesem Wert. Deswegen ist es sinnvoll, eine Möglichst genaue Prescaler/Compare-Wert-Kombination zu wählen, um nicht noch X-Takte zu viel oder zu wenig zu haben. Dann stellst du den Modus auf CTC (Clear Timer on Compare Match) ein, beschaffst dir eine passende Interrupt-Routine und zählst in dieser dann eine globale Variable herunter. Je nach Geschmack kannst du das Display dann entweder in der ISR (schlechtes Vorbild), oder aber in einer auf eine Änderung pollenden Schleife im Main-Programm aktualisieren, was dann gleich eine Lektion für die Zukunft ist (Erstes AVR-Gebot: Du sollst die ISR möglichst kurz machen ) Geändert von MarkusJ am 18. Dezember 2007 um 23:29 WARNUNG: Dieser Beitrag kann Spuren von Ironie beinhalten Ich bin weder eine Suchmaschine, noch ein Nachschlagewerk - PNs zu Themen die im Forum stehen oder dorthin gehören, werde ich nicht beantworten. Bilder bitte NICHT über Imageshack oder andere Imagehoster einbinden! |
Stefan Wimmer
Grand Master of Rocketry
Registriert seit: Aug 2000 Wohnort: Berlin Verein: Deutsche Experimental Raketen Arbeitsgruppe (DERA) Beiträge: 2398 Status: Offline |
Beitrag 133941
[19. Dezember 2007 um 01:53]
Hallo Stefan,
das mit den c-libs ist n der Tat so 'ne Sache. Manche sind einfach gleichzeitig entstanden, manche mussten unbedingt eine neue schreiben, weil ihnen der Stil der/des anderen nicht gefiel, manche machen es einfach immer so. Man muss das Ganze einfach etwas stressfrei sehen und sich jeweils das passende herauspicken. Ich selber verwende neben Selbstgestricktem auch min. 3-4 verschiedene Libs, je nachdem, welche Funktionen ich brauche. Mit Peter Fleury's und der Procyon-Lib hat man schon mal eine gute Grundlage. Zu Deiner "Countdown-Engine": normalerweise macht man alle Verzögerungen über ein paar Mikrosekunden mit Timern. In fast jedem Embedded-Programm hat man mit zeitgesteuerten Ereignissen zu tun und definiert sich daher erst mal eine Timer mit der kleinsten gemeinsamen Zeiteinheit als "Systemtick". Darauf aufbauend kann man dann Soft-Counter bauen, mit welchen dann nahezu beliebige Ablaufsteuerungen zu machen sind. Kurzes Beispiel: Will ich in einem Programm Servos mit einer Auflösung von 100 Schritten steuern und gleichzeitig eine LED wahlweise kurz blitzen lassen oder im 1/2 Sekundentakt blinken, so würde ich einen Hardware-Timer auf 10µs initialisieren. Daraus kann man dann a) die 1ms/100Schritte=10µs Timing für die Servos ableiten, mit einem Softcounter, der bis 200 zählt die 2ms Wiederholrate der Servos steuern und mit einem Zähler bis 100000 die LED wahlweise 1/10 Sekunde (Ausschalten bei Zählerstand 10000) oder 1/2 Sekunde (Ausschalten bei Zählerstand 50000) ansteuern. Um die Zahlen etwas leichter handhabbar zu machen, kann man in der ISR auch erst mal einen "Vorteiler" z.b. bis 10000 Zählen lassen und bei dessen Überlauf dann einen Zehntelsekundenzähler hochzählen. In C sähe das dann irgendwie so aus (passt jetzt nicht 1:1 zum oben geschriebeben, aber ich hoffe, das Konzept wird klar): Erst mal eine Timer-Init bauen: void timer0_init(void) { TCCR0 = ((1<<CS02)|(0<<CS01)|(1<<CS00)); // prescaler CLK / 1024 TIFR = 1<<TOV0; // Clear pending interrupts TIMSK = 1<<TOIE0; // enable Timer0 overflowinterrupt TCNT0 = T0_TC; // muss natürlich alles passend zur CPU-Frequenz ausgerechnet werden! } (oh je: auf Mikrocontroller.net könnte man das wenigstens schön formatieren...) Die Interruptroutine kann (und sollte) recht knapp ausfallen: SIGNAL(SIG_OVERFLOW0) // ALTER GCC SYNTAX!! { TCNT0 = T0_TC; BaseTimer++; // der zählt die Basis-Ticks vor sich hin if (BlinkTimer<100000) BlinkTimer++; else BlinkTimer = 0; } Man kann für kurze Verzögerungen somit jederzeit den (volatile deklarierten!) BaseTimer holen, die gewünschte Wartezeit in Ticks draufaddieren und warten, bis er den Wert erreicht hat. Man kann ihn auch einfach auf Null setzen und dann warten, bis er den zur Wartezeit passenden Zählerstand erreicht hat: BaseTimer = 0; while(BaseTimer < 200) // 20ms { //wait } Das LED-Blinken kann man entweder - durch Flags gesteuert - in der Interruproutine miterledigen, oder man hat oft in der Main-Loop zwischen irgendwelche Ereignissen eh' nicht viel besseres zu tun als ab&zu mal nach dem BlinkTimer zu sehen und die LED entsprechend an- oder ausknipsen. Auf die Mikrosekunde kommt's da ja auch nun wirklich nicht an. :-) if (BlinkTimer < 5000) LedOn(); else LedOff(); } Nach der Port-Init ruft man dann die Timer-Init auf, gibt mit sei(); die Interrupts frei und erfreut sich der automatisch laufenden Zählerchen. Viel Spass, Stefan Geändert von Stefan Wimmer am 19. Dezember 2007 um 02:01 It's the Government - it doesn't have to make sense! (B. Kaplow in r.m.r) |
Reinhard
Überflieger Registriert seit: Sep 2003 Wohnort: Österreich Verein: TRA #10691, AGM Beiträge: 1187 Status: Offline |
Beitrag 133954
[19. Dezember 2007 um 17:42]
Zitat: Hi, die Delay Funktionen haben ein paar Eigenheiten die man beachten muss. Siehe hier Gruß Reinhard |
Turambar
SP-Schnüffler
Registriert seit: Jun 2005 Wohnort: Österreich Verein: Beiträge: 874 Status: Offline |
Beitrag 133961
[19. Dezember 2007 um 19:04]
das passiert wenn man den Wald vor lauter Bäumen nicht sieht, dabei ists doch so einfach.....
Hab das jetzt so gelöst: Zitat: Code kann man leider nicht anzeigen lassen, ich hab mal die datei angehängt damit's besser lesbar ist... Anhang: main.rar Meine Hauptfrage: Funktioniert die Pausenfunktion wirklich so einfach? BZW. Reagiert das Programm überhaupt solang sie in der while-schleife vom Countdown "gefangen" ist? Die Lösung kommt mir so einfach vor, das kann doch eigentlich nicht funktionieren ^^ Lg Stefan Geändert von Turambar am 19. Dezember 2007 um 19:05 Bei der Eroberung des Weltraums sind zwei Probleme zu lösen: Die Schwerkraft und der Papierkrieg. Mit der Schwerkraft wären wir fertig geworden. - Wernher Freiherr von Braun http://are.modellraketen.at MfG Stefan |
Neil
99.9% harmless nerd
Registriert seit: Aug 2000 Wohnort: Delft Verein: SOLARIS Beiträge: 7776 Status: Offline |
Beitrag 133963
[19. Dezember 2007 um 19:21]
Zitat: Was macht der Compiller eigentlich aus sowas? Das wäre ja erstmal nur ein Delay Befehl von 1000ms. Faßt er sowas zusammen oder macht er es einzeln? Ich denke bei wenig Speicher ist das schon eine wichtige Sache. Warum hast du 5 mal 200ms gewählt? Gruß Neil Die Erde ist eine Scheibe. Egal in welche Richtung sich die Menschheit bewegt, sie geht immer auf einen Abgrund zu. |
Reinhard
Überflieger Registriert seit: Sep 2003 Wohnort: Österreich Verein: TRA #10691, AGM Beiträge: 1187 Status: Offline |
Beitrag 133964
[19. Dezember 2007 um 19:57]
Hi Stefan,
das Programm wird so wohl nicht funktionieren. Was mir bis jetzt ins Auge gestochen ist: In der Debounce Funktion wird vor dem "return 1;" ohne erkennbaren Grund noch 100ms gewartet. An sich macht das das Programm nur langsamer, aber vermutlich war diese Konstruktion anders gedacht. Das _delay_ms() Makro wird inkonsistent verwendet. Einmal mit max. 50ms einmal mit 200ms. Wenn der AVR schneller als mit 1 MHz getacktet ist funktioniert das _delay_ms(200) nicht. Wenn er es aber nicht ist, braucht man das 100ms Delay nicht in zwei mit 50ms aufspalten. Ich vermute die Schaltung verwendet externe PullUp Widerstände. Die internen werden nämlich nicht aktiviert. Ich kenne deine LCD-Bibliothek nicht, aber der Befehl "lcd_blind_data()" sieht nicht unbedingt danach aus als ob er das Lcd initialisieren würde. Falls er das nicht tut, muss vorher noch das Lcd initialisiert werden. Die erste "Endlosschleife" ist keine Endlosschleife, weil sie abbricht sobald sec 0 wird. Dabei sollte aber auch sichergestellt sein dass min 0 ist, sonst dauert z.B. ein 90s Countdown nur 30s. Deine Minuten haben nur 59 Sekunden. Sobald die Sekunde 0 erreicht wird sie sofort, und nicht erst in der nächsten Sekunde, wieder auf 59 gesetzt und die Minute dekrementiert. Überprüfe nicht ob die Sekunde 0 ist sondern ob sie kleiner 0 ist, oder stelle den Ablauf ganzlich um. Eine Bedingung wie "if(sec = 0)" ist immer falsch. Der Befehl weist zuerst der Sekunde den Wert 0 zu und wird dann auch als 0 ausgewertet. Bei C ist 0 falsch, alles andere wahr. Du musst stattdessen "if(sec == 0)" verwenden. = ist der Zuweisungsoperator, == ist der Vergleichsoperator. Der Fehler kommt zumindest dreimal im Code vor. Dieses "Feature" von C hat schon so manch einen reingelegt. Die "while(1)" Schleife am Code wird nie wieder verlassen. Da nützt das Drücken des Tasters auch nichts. @Neil Das _delay_ms() Makro hat, abhängig von der Prozessortaktfreuquenz, einen beschränkten Wertebereich. Siehe den Link aus meinem vorherigen Posting. Gruß Reinhard |
Turambar
SP-Schnüffler
Registriert seit: Jun 2005 Wohnort: Österreich Verein: Beiträge: 874 Status: Offline |
Beitrag 133966
[19. Dezember 2007 um 21:03]
Argh... das mit den operatoren ist wirklich n dummer Fehler ^^
die debounce funktion will ich lieber unangetastet lassen, da ich sie nur übernommen habe. Zitat: Stimmt. Den LCD Befehl hab ich übersehen - habe vorher was ausprobiert und die zeile nicht gelöscht. Natürlich muss ich das noch initialieren und enablen. @Neil: Ich dachte dass 200ms noch funktionieren, deshalb hab ich 5x 200ms gewählt um 1 sekunde zu bekommen. Da der Programmierer bei der debounce funktion schon 2x 50ms für 100ms nimmt, gehe ich davon aus dass der timer nicht mehr packt, deshalb habe ich folgende funktion geschrieben: void timer_1s(void) { int i = 0; while (i <= 20) { _delay_ms(50); i++; } } Die rufe ich jetzt jedes mal auf. Wie kann ich denn möglichst einfach nen Pausen-Taster realisieren? In der while-schleife den Zustand des Tasters abfragen? Wenn ja wie kann ich dann wieder in die andere Schleife springen? Bei der Eroberung des Weltraums sind zwei Probleme zu lösen: Die Schwerkraft und der Papierkrieg. Mit der Schwerkraft wären wir fertig geworden. - Wernher Freiherr von Braun http://are.modellraketen.at MfG Stefan |