MoinMoin
ich schreib grad ein kleines NightRider-Lauflicht auf nem Mega128. Das
klappt soweit auch ganz gut, nur geht es nur einmal hin und her und
bleibt dann stehen.
Dazu gehe ich wie folgt vor:
Mit Timer1A/B/C erzeuge per PWM drei feste Helligkeitsstufen. Diese gebe
ich dann auf PortE aus und lasse nach einer Zeit, die ich per Timer0
erzeuge, aufs nächste "Muster" umschalten.
Der Timer0 läuft im CTC und erhöht mit jedem Durchlauf eine Variable
Zeit (uint8_t).
Speicher aktuelle Zeit in Zeitalt,
gib solange MusterX aus wie Zeitalt+y größer als Zeit ist
Speicher aktuelle Zeit in Zeitalt,
gib solange MusterX+1 aus .......
Wenn nun der Überlauf kommt, klappt das ganze nicht mehr. Also wenn mein
Zeitversatz bspw 10(Timertakte) ist, und Zeit bei 252 gespeichert wurde,
ist der nächste Vergleich: solange 252 + 10 größer als die aktuelle Zeit
ist (also eigentlich ja 6 wegen der 8bit Variable) mache das Muster.
Aber da nach 252 die Zeit 253 kommt, klappt das ganze halt nicht, da 6
kleiner als 252 ist.
Wie kann ich das ganze so lösen, das ich einfach immer mein Offset zu
addieren kann, und das trotz Überlauf klappt?
Hier nochmal mein Code:
LostInMusic schrieb:> Finde ich unnötig kompliziert. Warum nicht so:> Zeit = 0;> while (Zeit < 12)> ...
Vermutlich denke ich gern zu kompliziert, merk ich immer wieder :D
Guter Tipp, ich werds direkt mal versuchen =)
Deine Zeit Variable sollte auch volatile sein
(https://www.mikrocontroller.net/articles/FAQ#Was_hat_es_mit_volatile_auf_sich).
Außerdem überleg dir mal wie man deine Funktion verallgemeinern kann,
sodass man nicht 8 Step Funktionen hat die fast das gleiche machen. Der
Code wird dadurch deutlich übersichtlicher und kürzer.
Müsste das nicht reichen, wenn die Zeit-Variable global definiert ist?
Sie zählt ja schließlich hoch wie sie soll, der "Fehler" lag ja im
Überlauf zusammen mit dem Vergleich.
Wobei ich mich dunkel erinnere, das ich das auch mal irgendwie so
hinbekommen hatte, das ich immer eine Differenz aufaddieren konnte, und
das ganze auch über den Überlauf hinweg geklappt hat.
Fpga Kuechle schrieb:> kürzerS1 = (PINB & (1 << PB5)) ;> if (S1 != 0) S1 = 1;
Das ist schön! Danke dafür.
Ich versuche das Ganze grad ein wenig einzukürzen, wie Sebastian schon
vorschlug. Jetzt erzeuge ich wieder mein "Grundmuster" und verschiebe es
dann um die Steps. Gibt es nicht auch eine Möglichkeit, das in einem
Schritt zu machen?
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
4
#define Offset 10
5
6
voidInit(void);
7
voidStep1(uint8_tSteps);
8
/*void Step2(void);
9
void Step3(void);
10
void Step4(void);
11
void Step5(void);
12
void Step6(void);
13
void Step7(void);
14
void Step8(void);*/
15
16
uint8_tZeit=0;
17
18
19
ISR(TIMER0_COMP_vect)
20
{
21
Zeit++;
22
}
23
24
25
intmain(void)
26
{
27
Init();
28
29
uint8_tSteps=2;
30
uint8_tUpDownFlag=0;
31
32
while(1)
33
{
34
Zeit=0;
35
while(Zeit<Offset)
36
{
37
Step1(Steps);
38
}
39
40
if(UpDownFlag==0)
41
{
42
Steps++;
43
if(Steps==8)
44
{
45
UpDownFlag=1;
46
}
47
}else
48
{
49
Steps--;
50
if(Steps==0)
51
{
52
UpDownFlag=0;
53
}
54
}
55
56
57
}
58
}
59
60
voidStep1(uint8_tSteps)
61
{
62
uint8_tS1;
63
uint8_tS2;
64
uint8_tS3;
65
66
S1=(PINB&(1<<PB5));
67
if(S1!=0)S1=1;
68
69
S2=(PINB&(1<<PB6));
70
if(S2!=0)S2=1;
71
72
S3=(PINB&(1<<PB7));
73
if(S3!=0)S3=1;
74
75
76
PORTE=~((S1<<0)|(S2<<1)|(S3<<2)|(S2<<3)|(S1<<4));
77
PORTE=(PORTE<<Steps);//Mustererzeugung und Shit in 2Steps, einer möglich?
J. T. schrieb:> Müsste das nicht reichen, wenn die Zeit-Variable global definiert ist?
Nein, denn die Zeit Variable wird im Interrupt verändert und davon weiß
der Compiler in der main Funktion aber nichts. So wie es jetzt steht
könnte der Compiler auch eine Endlosschleife einbauen weil er nicht
sieht, dass sich Zeit oder Zeit_alt ändern können. Warum das nicht
passiert liegt wohl daran, dass du Optimierungen ausgeschaltet hast.
J. T. schrieb:> Wobei ich mich dunkel erinnere, das ich das auch mal irgendwie so> hinbekommen hatte, das ich immer eine Differenz aufaddieren konnte, und> das ganze auch über den Überlauf hinweg geklappt hat.
Versuch mal:
Sebastian V. O. schrieb:> Versuch mal:while(Zeit - Zeit_alt <= 12)
Werd ich gleich mal versuchen. Danke auch dafür.
Nun seh ich grad das nächste Problem. Wenn das Lauflicht auf dem
"Rückweg" ist, bleiben die LED´s an.....
P.S.
Da fällt mirs wie Schuppen von den Augen. Die LEDs auf dem STK500 sind
ja Lowactiv.
Aber wieso bleiben sie denn nur in einer Richtung an?
P.P.S.
Auch da bleibt er stehen. Wobei ich die Variable noch nicht volatile
gemacht hab. Ich hab die Optimierungen ausgeschaltet, von daher sollte
dass dann in dem Fall doch egal sein? Ich erlaube dem Compiler somit
doch garnicht, irgendwelche Annahmen zu machen?
Ach falschrum... Die LEDs bleiben auf dem "Hinweg" an(LED0 ist aber
rechts und nicht links). Und noch ein Problem, das damit zu tun hat
(glaub ich). Ich hab Steps mit 2 initialisiert, in der Hoffnung, das
damit mein "Startmuster" auch in Richtung LED0 rausgeschoben wird. Dabei
hab ich aber nicht bedacht, dass damit einfach das Muster nicht an LED0
startet, sondern halt mit LED2. Die ist dann "dunkelhell",
LED3"mittelhell", 4"hell", 5"mittelhell", 6"dunkelhell". Ich müsste also
eigentlich von Steps (der Wert, um den geshiftet wird) 2 abziehen, damit
die hellste LED LED0 wird, und somit den Rand erreicht.
Macht der Compiler aus nem negativen leftshift automatisch nen
entsprechenden rechtshift?
J. T. schrieb:> Oder muss ich Steps als int8 machen, und dann bei negativen Werten "per> Hand" zwischen links und rechtsshift wechseln?
Ja. Aus einem Shift nach links um -1 wird kein Rechtsshift.
Ok, das hilft schonmal weiter.
Hast du evtl noch einen Tip zum Anbleiben der LEDs?
ich habs schon mit
1
PORTE=~((S1<<0)|(S2<<1)|(S3<<2)|(S2<<3)|(S1<<4));
2
PORTE=(PORTE<<Steps);
3
PORTE^=PORTE;
versucht, aber da bleibt komischerweise alles an, ohne irgendwelches
Geblinke. "^" ist doch xor? Damit invertiert man doch ein Byte wenn man
es mit sich selbst xort(schönes Wort, find ich :D)?
J. T. schrieb:> PORTE ^= PORTE;> versucht, aber da bleibt komischerweise alles aus. "^" ist doch xor?> Damit invertiert man doch ein Byte wenn man es mit sich selbst> xort(schönes Wort, find ich :D)?
nein, da kommt immer 0 raus
J. T. schrieb:> "^" ist doch xor? Damit invertiert man doch ein Byte wenn man> es mit sich selbst xort(schönes Wort, find ich :D)?
Ja ^ is XOR aber XOR mit sich selbst ergibt 0. Wenn du alle Bits
invertieren willst musst du XOR mit 0xFF machen oder besser du nutzt den
Operator zum invertieren:
J. T. schrieb:> Ich habs. Es liegt daran, das die leeren Stellen vom shiften mit Nullen> gefüllt werden... Kann man die auch mit 1 füllen lassen?
Statt:
Sebastian V. O. schrieb:> Ja ^ is XOR aber XOR mit sich selbst ergibt 0. Wenn du alle Bits> invertieren willst musst du XOR mit 0xFF machen oder besser du nutzt den> Operator zum invertieren:PORTE = ~PORTE;
Ach ja klar, ich bin auch n Idiot, das hab ich in der Ursprungsversion
sogar genauso benutzt. Hilft aber hier nicht weiter, da nach dem shiften
irgendwas wie 11xxxxx00. Die vorderen Einsen vom invertieren fürs
Ausgeben, in der while, die hinteren Nullen vom Shiften. Wenn ich
invertiere, hätte ich nur erreicht, dass die LEDs nach vorn statt nach
hinten wegleuchten.
Also nochmal die Frage, kann man beim shiften auch mit Einsen auffüllen
lassen?
Sebastian V. O. schrieb:> J. T. schrieb:>> Ich habs. Es liegt daran, das die leeren Stellen vom shiften mit Nullen>> gefüllt werden... Kann man die auch mit 1 füllen lassen?>> Statt:PORTE = (PORTE << Steps);sowas:PORTE = (PORTE << Steps) | (0xFF >>> (8-Steps));
Mhhh eigentlich total offensichtlichh... wieso komm ich auf sowas nicht
von selbst?
Mhhh irgendwas hapert da aber noch. Sieht aber ganz lustig aus. Das
"Grundmuster" steht im ersten Schritt an seiner Stelle, fängt an zu
Wandern, aber gleichzeitig bleibt es die ganze Zeit im an der
Startstelle stehen.
Also ich hab das stehende Grundmuster, da bewegt sich dann das selbe
Muster raus, ich habs also einmal stehend und einmal in Bewegung.
Hier ist die aktuellste Version: (Eigentlich nur langsamer gemacht und
die erwähnten Änderungen)
den Sinn nicht bzw. ist das meiner Meinung nach viel zu kompliziert.
Worin liegt der Sinn, ein Muster (das noch invertiert werden muss), erst
mal im PORTE kompliziert zusammenzusetzen, nur um sich dann hinterher
damit rumzuärgern, dass man an allen Nicht-Muster-Stellen ein 1 Bit rein
pfriemeln muss, welche durch die Verschiebung frei geworden sind.
Setz dir doch das Muster zusammen
Schieb es an die richtige Position
dann invertierst du es, weil du das für die Low-activen LED so brauchst
und erst dann gibst du es am Port aus.
Wenn du die Bits umdrehen musst, weil deine LED low-activ sind, dann ist
es eine gute Idee, wenn diese Invertierung der allerletze Schritt vor
der Ausgabe ist.
Denn eines ist unbestritten: Wir Menschen tun uns in der Logik leichter,
wenn wir 'Led leuchtet' mit einer 1 assoziieren. Mit negativer Logik
verhauen wir uns leicht.
Und ja: Zwischenvariablen zu benutzen macht manchmal vieles leichter,
weil man dann keine Monsterausdrücke hat. Meistens zieht der Compiler
die einzelnen Ausdrücke dann ohnehin wieder zusammen und wird die
Zwischenvariable los.
J. T. schrieb:> NightRider-Lauflicht
Nur zur Allgemeinbildung: der legendäre Reiter ist kein "Nacht-Reiter",
sondern ein "Ritter-Reiter" und schreibt sich deshalb mit K am Anfang...
https://de.wikipedia.org/wiki/Knight_Rider
BTW:
1
Antwort schreiben
2
Wichtige Regeln - erst lesen, dann posten!
3
* Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
Karl Heinz schrieb:> Setz dir doch das Muster zusammen
Ich würde einfach ein Muster im Flash ablegen, und das der Reihe nach
abfahren. In VHDL (einer üblicherweise als sehr geschwätzig verschrienen
Hardware-Beschreibungssprache) passt das dann locker auf einen
Bildschirm. Und ich denke in C wird das nicht viel länger. Siehe dort
ganz unten:
http://www.lothar-miller.de/s9y/archives/61-Lauflicht.html
Mit ein wenig Überlegen kommt amn locker auf die Idee: die aktuell
hellste LED ist im ROM. Die wird dauerhaft angeschaltet, danach wird
dieses Muster in das Register leddimmed übernommen und leuchtet mit
einer PWM nur die Hälfte der Zeit. Danach wird dieser Wert in ein
Register ledglow übernommen und leuchtet nur mit 1/4 der
Tastverhältnis...
Karl Heinz schrieb:> Ich versteh hier PORTE = ~( (S1 << 0) | (S2 << 1) | (S3 << 2) | (S2> <<3) | (S1 << 4) );> PORTE = (PORTE << Steps) | (0xFF >> (8-Steps));> den Sinn nicht bzw. ist das meiner Meinung nach viel zu kompliziert.Karl Heinz schrieb:> Denn eines ist unbestritten: Wir Menschen tun uns in der Logik leichter,> wenn wir 'Led leuchtet' mit einer 1 assoziieren. Mit negativer Logik> verhauen wir uns leicht.
Genau deshalb. Ich hatte im Hinterkopf das die LEDs Lowavtive sind, also
hab ich mir gedacht, die normal hellste wird die dunkelste sein, das
muss ja aber andersrum sein. Also Muster erzeugen und umdrehen. Das
kommt noch aus meiner ersten Version, wo ich einfach jedes nötige Muster
als einzelne Funktion gemacht hatte. Das mit dem shiften kam dann erst
beim Versuch dazu, das ganze in einer Funktion zusammenzufassen, die
dann Zustandsabhängig das richtige Muster ausgibt.
Das ist also quasi gewachsene Komplexität :D
Hast du zufällig den Beitrag über deinem gelesen? (Manche Leute lesen ja
nur das Eingangsposting, wobei ich bei dir aus dem Bauch heraus sagen
würde, du gehörst eher zu denen, die den Threadverlauf wenigst einmal
überfliegen).
Das Problem dass das Muster doppelt auftaucht (einmal bewegt, einmal
unbewegt) konnte ich immer noch nicht lösen. Ich hab noch nichtmal einen
Ansatz, wo das herkommen könnte. Magst du nochmal in deine gut gefüllte
Zaubertruhe gucken, ob du da nicht n Wundermittelchen für mich drin
hast?
Ich hab schon versucht, das ganze mit dem Simulator nachzuvollziehen,
aber der gibt mir irgendwie sehr verwirrende Sachen aus. Erwartet hatte
ich, das er mir das Grundmuster ausgibt, nur nicht in unterschiedlichen
Helligkeiten, sondern in unterschiedlichen Zeitanteilen(das läuft ja
alles etwas langsamer im Simulator), die die jeweilige LED 0 oder 1
sind. Die hellste halt dauernd 0(dem Lowactiv geschuldet), die mittlere
ca 50/50 oder welchen Wert ich da nun genau für gewählt hatte, und die
dunkelste die meiste Zeit 1und ab und an 0. Aber er irgendwie hat er so
garnichts ausgeben, was auch nur entfernt an mein Muster erinnert hätte.
Ich starte mal eben das Studio, ums nochmal kurz nachzuvollziehen.
Also irgendwie stimmen Simulator und Realität nicht überein. Im
Simulator ist nach der Invertierung LED5 0. Nach ner Weile nextStep
klicken kommen dann die anderen dazu. Also das ist wie auf dem STK. Das
bewegte Muster startet auch bei LED5 als hellste. Aber im Simulator
bleiben LED0-4 auf 1 (also aus), auf dem STK dagegen leuchten sie in
ganzer Pracht. Mal das Oszi ranhängen und gucken, ob sie wirklich
leuchten, oder nicht doch Blinken (also die hellste zumindest, die
dunkleren werden natürlich schon Blinken)......
Ich hätte nicht gedacht, das son einfaches nicht-nächtliches
Ritter-Reiter-Lauflicht so viel ärger macht.
Lothar Miller schrieb:> J. T. schrieb:>> NightRider-Lauflicht> Nur zur Allgemeinbildung: der legendäre Reiter ist kein "Nacht-Reiter",> sondern ein "Ritter-Reiter" und schreibt sich deshalb mit K am Anfang...
Da hier gezeigt hast, das du da deutlich mehr als ich drüber weißt, hast
du dich hiermit zum Experten qualifiziert und darfst mir gleich bei der
nächsten Frage helfen *gg (alle anderen selbstverständlich auch)
Sieht das Lauflicht überhaupt so aus? also dunkelhell, mittelhell, hell,
mittelhell, dunkelhell und das läuft dann hin und her? Oder ist das in
aktueller Laufrichtung Vorderste das hellste, und zieht eine Spur
dunklerwerdender hinter sich her? (würd mir jetzt grad eigentlich viel
logischer vorkommen, aber in meiner dunklen Erinnerung wars so, wie ich
es jetzt gemacht hab)
Lothar Miller schrieb:> BTW:Antwort schreiben> Wichtige Regeln - erst lesen, dann posten!> * Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
Daran dachte ich nach dem posten beim ersten auch, ich sah das es dann
deutlich länger geworden war, als ich dachte. Aber den 2ten fand ich von
der Länge eigentlich noch okay, evtl Richtung grenzwertig aber noch ok.
Lothar Miller schrieb:> J. T. schrieb:>> NightRider-Lauflicht> Nur zur Allgemeinbildung: der legendäre Reiter ist kein "Nacht-Reiter",> sondern ein "Ritter-Reiter" und schreibt sich deshalb mit K am Anfang...> https://de.wikipedia.org/wiki/Knight_Rider
Hach. Ich mag Lothar, den lieben alten Erbsenzähler. :-)
Hach! Die Amerikaner und ihr Bild von Europo bzw. genauer: Ihr Bild von
germanischen Sprachen (wobei Englisch ja auch eine ist.).
Denn ein "Ritter" ist per Definition vor allem erstmal ein Reiter, ein
"Berittener". Die Sendung heisst dann irgendwie "Reiter-Reiter" Aber
gut. Mir egal.
Denn ich möchte dann doch mal darauf hinweisen, dass nicht etwa der
Reiter, Rider oder Ritter das Licht getragen oder an sich gehabt hat,
sondern ich - sein Auto, sein Beschützer und Freund.
;-)
P.S. mal schnell das Multimeter mit Frequenzmessung rangehalten. LED3
blinkt mit 45kHz bei 52% Pulsweite, also doch kein Dauerleuchten. Wenn
man genau hinsieht, sieht man auch, das sie heller wird, wenn sich die
hellste vom bewegten auf die hellste stehende LED "legt"
K.I.T. schrieb:> Denn ich möchte dann doch mal darauf hinweisen, dass nicht etwa der> Reiter, Rider oder Ritter das Licht getragen oder an sich gehabt hat,> sondern ich - sein Auto, sein Beschützer und Freund.
Dafür langt meine geringe nicht-Nacht-Ritter-Reiter-Kenntnis dann doch
grad noch :D
K.I.T. schrieb:> Denn ein "Ritter" ist per Definition vor allem erstmal ein Reiter, ein> "Berittener". Die Sendung heisst dann irgendwie "Reiter-Reiter" Aber> gut. Mir egal.
Evtl wollten sie nur darauf hinweisen, das er noch krasser als Ritter
mit krasses Pfärd ist, und daher keine Pferde als Reittier benutzt,
sondern halt Ritter :D
Ist ja auch irgendwie praktisch, wenn einem das Reittier in der Schlacht
mit ner 2ten Schwerthand zur Seite stehen kann. Ob die auch Kokosnüsse
benutzt haben, um guten Hufsound zu haben?
gemacht, und es geht.
Aber wie kann das sein, das sich das Grundmuster so stark durchgesetzt
hat, obwohl es doch im nächsten Takt direkt umgeschaltet wurde?
Ich hab nun mal ein Blick ins Disassembly geworfen. Das erklärte
einiges.
Da werden ja nur aus der Ausgabe auf PORTE soviele Schritte draus, das
der gesamte Rest des Programms völlig erblasst. Somit war das nix mit
meiner Überlegung, dass das die erste Ausgabe nach einem Takt durch
wäre... Und somit ist das bewegte Lauflicht nahezu gleichlang im Wechsel
mit dem Stehenden zu sehen, und nicht im von mir angenommen Verhältnis
von ca "1Takt/Befehl / gesamter Rest des Programms", das Verhältnis war
quasi zu "riesiger Haufen Befehle/riesiger Haufen Befehle + winziger
Rest des Programms" eingeschrumpft worden.
Ich hab nun noch versucht, ein Rechtsshift mit einzubauen.
Karl Heinz schrieb:> Wenn du die Bits umdrehen musst, weil deine LED low-activ sind, dann ist> es eine gute Idee, wenn diese Invertierung der allerletze Schritt vor> der Ausgabe ist.
Hab ich nun auch beachtet, und es liest sich nebenbei auch viel
angenehmer, wenn man das viele Geshifte durchs frühe Invertieren
spart.=)
Aber ganz klappt das noch nicht, wenn Steps negativ wird, bleibt das
Lauflicht im "Grundmuster" stehen, statt über LED0 nach rechts "aus dem
Bild zu laufen". Wenn Steps dann wieder positiv wird läufts wieder
sauber. Läuft zurück, bleibt wieder stehen usw.
hier nochmal die Stelle
else if (Steps < 0)
{
PORTE = ~(Sammler >> Steps);
Steps ist natürlich negativ, das hab ich nun durch :
[c]
else if (Steps < 0)
{
Stephalter = 0 - Steps;
PORTE = ~(Sammler >> Stephalter);
}
ersetzt(Stephalter als int8).
Im Anhang der nochmal der Code für Interessierte
J. T. schrieb:> Sieht das Lauflicht überhaupt so aus? also dunkelhell, mittelhell, hell,> mittelhell, dunkelhell und das läuft dann hin und her?
Meines sieht aus wie deines aussehen soll: die erste LED ist hell,
danach wirds dunkler. Ich werde das aber überarbeiten müssen, denn im
Auto vom Herrn Knight sind die ersten 3 Lampen hell, die folgenden
werden dann abnehmend dunkler... :-/
> Sieht das Lauflicht überhaupt so aus?
Siehe dort bei 0:20 oder 1:20
https://www.youtube.com/watch?v=iQwlrEdka6Q
Ein wenig historische Genauigkeit muss sein... ;-)
> Ich hätte nicht gedacht, das son einfaches nicht-nächtliches> Ritter-Reiter-Lauflicht so viel ärger macht.
Jeder Code, der nicht auf 1 Bilschirmseite passt, macht Ärger. Immer...
;-)
K.I.T. schrieb:> Denn ich möchte dann doch mal darauf hinweisen, dass nicht etwa der> Reiter, Rider oder Ritter das Licht getragen oder an sich gehabt hat,> sondern ich - sein Auto, sein Beschützer und Freund.
Hallo K.I.T., das Ganze ist mehrschichtig. Dein Fahrer (= rider, naja,
wenigstens wenn du ein Moped wärst) ist ein gewisser Herr "Michael
Knight" ist. Damit ist der Knight-Rider eigentlich nur "Fahrer
Knight"...