Du kannst keine neue Antwort schreiben
Seiten (2): [1] 2 »

Autor Thema 
Turambar

SP-Schnüffler


Moderator

Turambar

Registriert seit: Jun 2005

Wohnort: Österreich

Verein:

Beiträge: 874

Status: Offline

Beitrag 133930 , Countdown mit LCD/ATmega8 [Alter Beitrag18. Dezember 2007 um 20:14]

[Melden] Profil von Turambar anzeigen    Turambar eine private Nachricht schicken   Besuche Turambar's Homepage    Mehr Beiträge von Turambar finden

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

TheSmartGerman

Registriert seit: Jun 2007

Wohnort: Schwabenland

Verein:

Beiträge: 245

Status: Offline

Beitrag 133933 [Alter Beitrag18. Dezember 2007 um 21:42]

[Melden] Profil von TheSmartGerman anzeigen    TheSmartGerman eine private Nachricht schicken   Besuche TheSmartGerman's Homepage    Mehr Beiträge von TheSmartGerman finden

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

Schrauben-sägen-löten-kleben, so vergeht viel Zeit im Leben!

TheSmartGerman
Turambar

SP-Schnüffler


Moderator

Turambar

Registriert seit: Jun 2005

Wohnort: Österreich

Verein:

Beiträge: 874

Status: Offline

Beitrag 133935 [Alter Beitrag18. Dezember 2007 um 22:56]

[Melden] Profil von Turambar anzeigen    Turambar eine private Nachricht schicken   Besuche Turambar's Homepage    Mehr Beiträge von Turambar finden

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


Moderator

Registriert seit: Apr 2005

Wohnort: Kandel

Verein:

Beiträge: 2148

Status: Offline

Beitrag 133938 [Alter Beitrag18. Dezember 2007 um 23:20]

[Melden] Profil von MarkusJ anzeigen    MarkusJ eine private Nachricht schicken   MarkusJ besitzt keine Homepage    Mehr Beiträge von MarkusJ finden

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 wink)

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


Moderator

Stefan Wimmer

Registriert seit: Aug 2000

Wohnort: Berlin

Verein: Deutsche Experimental Raketen Arbeitsgruppe (DERA)

Beiträge: 2398

Status: Offline

Beitrag 133941 [Alter Beitrag19. Dezember 2007 um 01:53]

[Melden] Profil von Stefan Wimmer anzeigen    Stefan Wimmer eine private Nachricht schicken   Besuche Stefan Wimmer's Homepage    Mehr Beiträge von Stefan Wimmer finden

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

Reinhard

Registriert seit: Sep 2003

Wohnort: Österreich

Verein: TRA #10691, AGM

Beiträge: 1186

Status: Offline

Beitrag 133954 [Alter Beitrag19. Dezember 2007 um 17:42]

[Melden] Profil von Reinhard anzeigen    Reinhard eine private Nachricht schicken   Besuche Reinhard's Homepage    Mehr Beiträge von Reinhard finden

Zitat:
Original geschrieben von TheSmartGerman

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.




Hi,

die Delay Funktionen haben ein paar Eigenheiten die man beachten muss. Siehe hier

Gruß
Reinhard
Turambar

SP-Schnüffler


Moderator

Turambar

Registriert seit: Jun 2005

Wohnort: Österreich

Verein:

Beiträge: 874

Status: Offline

Beitrag 133961 [Alter Beitrag19. Dezember 2007 um 19:04]

[Melden] Profil von Turambar anzeigen    Turambar eine private Nachricht schicken   Besuche Turambar's Homepage    Mehr Beiträge von Turambar finden

das passiert wenn man den Wald vor lauter Bäumen nicht sieht, dabei ists doch so einfach.....

Hab das jetzt so gelöst:

Zitat:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include lcd-blind-routines.c
#include lcd-countdown-routines.c

inline uint8_t debounce(volatile uint8_t *port, uint8_t pin)
{
if ( ! (*port & (1 << pin)) )
{
/* Pin wurde auf Masse gezogen, 100ms warten */
_delay_ms(50); // max. 262.1 ms / F_CPU in MHz
_delay_ms(50);
if ( *port & (1 << pin) )
{
/* Anwender Zeit zum Loslassen des Tasters geben */
_delay_ms(50);
_delay_ms(50);
return 1;
}
}
return 0;
}

int main(void)
{
DDRC &= ~( 1 << PC0 ); /* PIN PC0 auf Eingang (Taster) */
DDRC &= ~( 1 << PC1 ); /* PIN PC1 auf Eingang (Taster) */

int min = 15;
int sec = 59;
int big = 25:
int small = 50;

lcd_blind_data(small & ":" & big);

if (debounce(&PINC, PC0)) /* Taster Start*/
{

while(sec >= 0) /* Ist ne Endlosschleife, soll auch so sein*/
{

_delay_ms(200);
_delay_ms(200);
_delay_ms(200); /* 1 sec warten*/
_delay_ms(200);
_delay_ms(200);

sec = sec-1;

if(sec = 0 && min != 0) /* Sekunden bei 0, Minuten nicht*/
{
min = min-1;
sec = 59;
}

if(min = 0 && sec = 0) /* Timer abgelaufen */
{
// Summer starten, LED leuchtet..

_delay_ms(200);
_delay_ms(200);
_delay_ms(200); /* 1sec warten */
_delay_ms(200);
_delay_ms(200);

// Summer Stop, LED aus

min = 15; /* Automatisch resetten und von vorne */
sec = 59;

}

// Am Ende der While-Schleife kommen die Befehle ans LCD, Minuten und Sekunden anzeigen
}


}

if (debounce(&PINC, PC1)) /* Taste Pause*/
{

while(1)
{
// Endlosschleife, der Countdown pausiert und startet bei tastendruck Start wieder
}

}
}





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


Administrator

Neil

Registriert seit: Aug 2000

Wohnort: Delft

Verein: SOLARIS

Beiträge: 7776

Status: Offline

Beitrag 133963 [Alter Beitrag19. Dezember 2007 um 19:21]

[Melden] Profil von Neil anzeigen    Neil eine private Nachricht schicken   Neil besitzt keine Homepage    Mehr Beiträge von Neil finden

Zitat:
_delay_ms(200);
_delay_ms(200);
_delay_ms(200); /* 1 sec warten*/
_delay_ms(200);
_delay_ms(200);



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

Reinhard

Registriert seit: Sep 2003

Wohnort: Österreich

Verein: TRA #10691, AGM

Beiträge: 1186

Status: Offline

Beitrag 133964 [Alter Beitrag19. Dezember 2007 um 19:57]

[Melden] Profil von Reinhard anzeigen    Reinhard eine private Nachricht schicken   Besuche Reinhard's Homepage    Mehr Beiträge von Reinhard finden

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


Moderator

Turambar

Registriert seit: Jun 2005

Wohnort: Österreich

Verein:

Beiträge: 874

Status: Offline

Beitrag 133966 [Alter Beitrag19. Dezember 2007 um 21:03]

[Melden] Profil von Turambar anzeigen    Turambar eine private Nachricht schicken   Besuche Turambar's Homepage    Mehr Beiträge von Turambar finden

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:
Ich vermute die Schaltung verwendet externe PullUp Widerstände. Die internen werden nämlich nicht aktiviert.


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
Seiten (2): [1] 2 »
[Zurück zum Anfang]
Du kannst keine neue Antwort schreiben