Hallo zusammen,
ich bin ganz neu hier und auch blutiger Anfänger in C.
Habe mir lange überlegt ob ich eure Hilfe in Anspruch nehme...
Bitte zerreißt mich nicht gleich in der Luft ;-)
Ich habe gegooglet, mir div. Tutorial angeschaut, ein teures Buch
gekauft aber ich komme einfach nicht weiter.
Die Aufgaben und Beispiele sind alle zu aufwendig und ich möchte doch
nur etwas einfaches realisieren und vor allem verstehen.
Ich habe ein aTeVaL (Microchip AVR Evaluationsboard) von ehajo
Ich arbeite mit Atmel Studio 7
Im Board habe ich z.Zt. einen ATtiny2313A
Wie in der Überschrift schon angedeutet habe ich mir ein (vermeintlich)
einfaches Projekt für den Anfang vorgenommen:
Es soll ein Modellleuchtturm beleuchtet werden.
Modell: Westerhever Sand
Was soll leuchten?
Leuchtfeuer mit original Kennung 10 sek an, 1 sek aus, 1 sek an, 1 sek
aus, 1 sek an, 1 sek aus
Es gibt zwei Leuchtturmwärter Häuschen dort sollen jeweils zwei LEDs
verbaut werden.
Wohnzimmer und Bad
Das Leuchtfeuer soll dauernd vor sich hin leuchten und die vier anderen
LEDs sollen ein belebtes Haus simulieren.
Wohnzimmer Licht an, ab und zu Licht im Bad an und wieder aus, dann
Licht im Wohnzimmer auch aus.
Das Leuchtfeuer habe ich zum Blinken gebracht habe aber keine Ahnung wie
ich die anderen LEDs ansteuern soll, da ich eine Endlosschleife habe die
nie endet.
Wie löst man so etwas?
Mit einem Timer? Wenn ja wie?
Andere Lösungsansätze für mich?
Bin für jede Hilfe dankbar!
Viele Grüße
Christian
Hier mein bisheriger Code:
/*
* LED mit Kennung Westerhever Sand
* 10 sek an 1 sek aus 1 sek an 1 sek aus 1 sek an 1 sek aus
* AtmelStudio 7.0
* ATtiny2313A
*/
#
#ifndef F_CPU
#define F_CPU 1000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
////////////////////////////////////////////////////////////////////////
///////////////////////////
int main(void) {
DDRD |= (1 << 6); // Port D Pin PC6 als Ausgang
while (1) { // Beginn Schleife
PORTD ^= (1 << 6); // flip state
_delay_ms(10000); // delay 10 Sekunden an
PORTD ^= (1 << 6); // flip state
_delay_ms(1000); // delay 1 Sekunde aus
PORTD ^= (1 << 6); // flip state
_delay_ms(1000); // delay 1 Sekunde an
PORTD ^= (1 << 6); // flip state
_delay_ms(1000); // delay 1 Sekunde aus
PORTD ^= (1 << 6); // flip state
_delay_ms(1000); // delay 1 Sekunde an
PORTD ^= (1 << 6); // flip state
_delay_ms(1000); // delay 1 Sekunde aus
}
return(0);
}
> Wie löst man so etwas?
Du willst im Grunde genommen mehrere Leuchtmuster parallel abarbeiten.
Ein für µC gangiger Lösungsansatz dazu ist der Zustandsautomat. Lies mal
die ersten Absätze von http://stefanfrings.de/net_io/protosockets.html
dann siehst du, was ich damit meine.
In meinem Buch http://stefanfrings.de/mikrocontroller_buch/index.html
Band 3 findest du ein paar konkrete Anwendungsbeispiele. Achte dabei mal
darauf, wie ich Enumerations für die switch() Anweisungen verwendet
habe.
Danke für die schnelle Antwort!
Noch mehr zu lesen für mich ;-)
Sieht aber für mich als Anfänger auf den ersten Blick sehr aufwendig aus
und ich verstehe nur Bahnhof...
Werde das mal alles durcharbeiten und auf mich wirken lassen.
Wenn jemand noch einen Beispiel-Code für mich hat, wie so etwas aussehen
könnte, wäre ich nicht abgeneigt.
Mit einem Beispiel fällt mir das Verstehen leichter.
Ich dachte man arbeitet in Blöcken:
LED1 soll dies machen
LED2 soll das machen....
Oder mit mehreren Dateien.
Dem ist wohl nicht so :-/
Christian S. schrieb:> habe aber keine Ahnung wie ich die anderen LEDs ansteuern soll,> da ich eine Endlosschleife habe die nie endet.
Offenkundig ist _delay die falsche Wahl.
Eine Schleife, die die Sekunden zählt
1
while(1)
2
{
3
_delay_ms(1000);
4
}
kann bei jedem Durchlauf das ein- oder ausschalten, was als nächstes
kommt:
> Ich dachte man arbeitet in Blöcken:
Ja eben. Für jede LED schreibst du einen Zustandsautomaten (also ein
switch() Konstrukt).
In der Hauptschleife führst du dann beide quasi parallel aus.
> Dem ist wohl nicht so :-/
Doch.
Michaels Ansatz kann man nehmen, aber es wäre 'professioneller', das
Delay durch einen Timer zu ersetzen. Im Interrupt setzt du ein Flag und
wartest in der Hauptschleife, bis das Flag gesetzt ist. Etwa so
1
_ISR(Timer0_OVF)// Oder so ähnlich, ich kann mir das nie merken
2
{
3
Flag=1;
4
}
5
6
main()
7
{
8
while(1)
9
{
10
while(Flag!=1);// Schleife, bis Flag 1 ist
11
Flag=0;
12
SchalteLeuchtturm();
13
SchalteHauslicht();
14
}
15
}
In dem Beispiel ist das kein großer Unterschied, aber wenn der Code
länger wird, wird mit Delay auch die Zeit zwischen den Durchläufen
länger. Mit dem Timer hast du immer das gleiche Intervall.
Geht leider nicht.
Was habe ich falsch gemacht?
Fehlermeldungen siehe screenshot
PS der Code wird nicht länger werden und wenn es geht auch in einen
tiny13A passen
Christian S. schrieb:> Fehler_Code.jpg
Der Fehler ist (fast) immer bei der niedrigsten Zeilennummer.
Der angezeigte Fehlertext ist doch eindeutig!
Selbst besser schauen.
Gruss
Christian S. schrieb:> PS der Code wird nicht länger werden und wenn es geht auch in einen> tiny13A passen
Der Code schon, aber nicht die Daten. Allein die 3 Arrays sind schon 80
Byte, die du irgendwie in 64 Byte RAM stapeln musst.
Sieh dir im Tutorial an, wie man Konstanten im Flash ablegt und wie man
darauf zugreift. Ob alles in die 1K reinpasst, ist eine andere Frage.
Die Tiny 25/45/85 sind pinkompatibel zum Tiny 13. Mit denen hättest du
wesentlich meht Luft nach oben.
Danke Thomas.
An diese Dinge hatte ich gar nicht gedacht.
Bin eben noch ganz am Anfang.
Habe heute von euch mehr, für dieses Projekt, gelernt als in der letzen
Woche in der ich Bücher gelesen und Tutorial angeschaut und gelesen
habe.
So da bin ich schon wieder...
Dachte es geht alles habe aber festgestellt dass etwas nicht stimmt mit
PD4 und 5.
Also habe ich den Code angepasst und nun sollten PD4 und 5 abwechselt an
und aus sein...
Aber PD5 ist immer an und PD4 nach 3x an und 2x aus also 5 Minuten
dauernd an.
Oh eben ist PD5 nach 10 Minuten doch mal aus gegangen.
Jetzt leuchten wieder PD4 und 5 dauerhaft.
PD6 blinkt wie es soll.
Also irgendwo ist da noch der Wurm drin!?
Außerdem ist 1 Minute keine Minute sondern eher 44 Sekunden.
Takt Controller? Wo korrigieren?
1
/*
2
* LED mit Kennung Westerhever Sand
3
* 10 sek an 1 sek aus 1 sek an 1 sek aus 1 sek an 1 sek aus
Christian S. schrieb:> festgestellt dass etwas nicht stimmt
Sagte schon Thomas, der Speicher reicht wohl nicht, weil die an/aus bits
recht grosszügig deklariert wurden.
1
/*
2
* LED mit Kennung Westerhever Sand
3
* 10 sek an 1 sek aus 1 sek an 1 sek aus 1 sek an 1 sek aus
Christian S. schrieb:> Modell: Westerhever Sand> Was soll leuchten?> Leuchtfeuer mit original Kennung 10 sek an, 1 sek aus, 1 sek an, 1 sek> aus, 1 sek an, 1 sek aus
Die originale Kennung des Leuchtfeuers Westerhever Sand lautet:
Oc(3) WRG 15s [(1)+2+(1)+2(1)+8 s]
light_house schrieb:> Oc(3) WRG 15s [(1)+2+(1)+2(1)+8 s]
Vielleicht könntest du das auch für eine Landratte und einen
Nicht-Funkamteur in eine verständliche Form bringen?
Danke light_house das stimmt natürlich.
Weiß nicht was ich da gedacht hatte.
Ist wohl alles ein bisschen viel auf einmal ;-)
Danke für den Hinweis.
1 Sek dunkel
2 Sek hell
1 Sek dunkel
2 Sek hell
1 Sek dunkel
8 Sek hell
= 15 Sekunden
> Vielleicht könntest du das auch für eine Landratte und einen> Nicht-Funkamteur in eine verständliche Form bringen?> Oc(3) WRG 15s [(1)+2+(1)+2(1)+8 s]
Licht: 1s(aus) - 2s(ein) - 1s(aus) - 2s(ein) - 1s(aus) - 8s(ein)
NB Info für Nicht-Funkamateure: dies ist kein Morsecode
Noch ein Ergebnis für heute:
Ich habe PD4 und 5 getauscht und jetzt scheint alles so abzulaufen wie
gewünscht.
Erklärungen für dieses Phänomen?
Vorher (LEDs schalten willkürlich bzw. mir nicht erklärbar):
1
#define LED_Bad (1<<PD4)
2
#define LED_WZ (1<<PD5)
3
#define LED_LT (1<<PD6)
Nachher (LEDs schalten wie gewünscht):
1
#define LED_LT (1<<PD6)
2
#define LED_Bad (1<<PD5)
3
#define LED_WZ (1<<PD4)
Noch etwas ist mir aufgefallen:
Vorher Speicher zu 68% belegt.
Nachher zu 59% belegt.
????????Komisch????????
Christian S. schrieb:> Vorher Speicher zu 68% belegt.
Hier denkt der Compiler beim Optimieren, ok Bad und Wohnzimmer sind
getrennt
> Nachher zu 59% belegt.
Hier denkt er ah ich kann optimieren und ein Wohn-Klo draus machen :-D
>> ????????Komisch????????
Lass' Dich von meinem Spaß nicht verwirren, kann es auch nicht erklären
Hi
Hatte vorhin, beim überfliegen der ersten Posts, den Gedanken, ob man
ein Array nicht auch als boolean (statt byte/int/char/whatever) erzeugen
kann - dann müsste der Compiler halt 8 dieser Werte zu einen Byte
zusammen schustern und irgendwo in den Tiefen des RAM/Flash unter
bringen.
(im Endeffekt das Gleiche, wie 'laberkopp' Es schon in Seinem Code
angepasst hatte)
Wobei man ggf. auch einfach die 64 (bei Sekunden wohl nur 60) Bit als
binäre Zahl angeben könnte - wobei hier dann das Auszählen wieder
fehleranfällig wird.
MfG
Patrick J. schrieb:> Hatte vorhin, beim überfliegen der ersten Posts, den Gedanken, ob man> ein Array nicht auch als boolean (statt byte/int/char/whatever) erzeugen> kann - dann müsste der Compiler halt 8 dieser Werte zu einen Byte> zusammen schustern und irgendwo in den Tiefen des RAM/Flash unter> bringen.
Man kann es auch als verkettete Liste mit Texten "Ein" und "Aus"
ablegen.
Einfacher wäre es aber wohl, das Muster einfach Bitweise in ein uint16_t
zu packen. Die Kennung ist 15s lang und passt dort wunderbar rein, wenn
jedes Bit 1s repräsentiert. Zusätzlich braucht man einen Zähler, der
immer von 0 bis 14 zählt.
HildeK schrieb:> Vielleicht könntest du das auch für eine Landratte und einen> Nicht-Funkamteur in eine verständliche Form bringen?
Das hat mit Funken überhaupt nichts zu tun:
Oc(3) heißt "Unterbrochen Gruppe 3" (oc (en) =occulted), d.h. 3
Unterbrechungen hintereinander. Die Zeiten in Klammern sind die
Dunkelphasen, die Zeiten ohne Klammer die Hellphasen, also wie oben
schon genannt
Westerhever Sand
LFV schrieb:> Zusätzlich braucht man einen Zähler, der immer von 0 bis 14 zählt
Nein, dazu braucht man eine Maske. Die startet mit 1 und dieses Bit wird
nach jeder Sekunde um 1 nach links geschoben. Die verknüpft man dann mit
dem Ausgabemuster und schaltet den Pin entsprechend.
Dann muß das Delay raus. Nicht, weil es sich so gehört, sondern damit
die LED im Leuchtturm nicht hart blinkt, wie eine LED nun mal blinkt,
sondern mit Fading, wie bei einem richtigen Leuchtturm. Und dafür
braucht man einen Timer, der die PWM und das ganze Timing macht.
Das soll natürlich auf einen Tiny13. Mal grob geschätzt: Passt locker.
>> Vielleicht könntest du das auch für eine Landratte und einen>> Nicht-Funkamteur in eine verständliche Form bringen?> Das hat mit Funken überhaupt nichts zu tun:
Nur der Vollständigkeit halber: Eher selten strahlen Leuchtürme aber
auch im Morse-Code ab. Eine typische Kennung lautet dann beispielsweise:
Mo (V)
Mo Hinweis auf Morse-Code
V Buchstabe V (Punkt – Punkt – Punkt – Strich)
Hierbei gilt für das jeweilige Morsezeichen:
n Länge eines Punktes
n Länge der Pause zwischen Punkt/Strich
3n Länge eines Striches
Beim Leuchfeuer Westerhever Sand liegt schon deshalb kein Morse-Code
vor, weil der Blinkrhythmus nicht nach diesem Zeitplan gestaltet ist.
Danke für eure Anregungen den Code weiter zu verbessern oder das mit dem
fading klingt auch interessant.
Ich bitte euch aber nicht zu vergessen, dass ich das Board erst seit
einer Woche und ich somit wirklich noch null Ahnung habe.
Wenn ihr Lust habt, könnt ihr euch ja gern daran austoben.
Damit ich es aber verstehe und nachvollziehen kann wäre es nett wenn ihr
mir dann den kompletten Code postet und etwas //kommentiert.
Es muss übrigens nicht auf einen tiny passen ich hätte auch noch
ATMega8A-PU da, der dürfte ausreichend sein ;-)
Nur nicht noch größer, es handelt sich um ein Spur N Modell.
Wenn das Projekt fertig ist möchte ich es auch hier im Forum mit Bildern
posten und den Code natürlich für alle zugänglich machen...
Noch mal vielen Dank für eure Unterstützung!
Thomas E. schrieb:> Nein, dazu braucht man eine Maske. Die startet mit 1 und dieses Bit wird> nach jeder Sekunde um 1 nach links geschoben. Die verknüpft man dann mit> dem Ausgabemuster und schaltet den Pin entsprechend.
Was heißt "nein"?
Ob du nun deiner Maske auf die Finger guckst oder das ganze Pattern
verschiebst und immer das unterste Bit beguckst ist nun ziemlich egal.
Wenn man bei der Maskenmethode nicht mit 1 startet, sondern mit 2^14 und
dann nicht nach links, sondern nach rechts schiebt, weiß man gleich,
wann man wieder von vorne anfangen muss - nämlich wenn 0 in der Maske
steht.