PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : 4 Led´s unabhängig per Zufall blinken lassen?



DanielSan
16.07.2011, 16:27
Hi,

ich habe einen Atmega48, welcher ja 2 8bit und einen 16bit Timer hat.
Mein Problem ist das ich 4 Led´s unabhängig voneinander Blinken lassen möchte. Die Einschaltzeit ist bei allen 10ms, die Zeit in der sie abgeschaltet sind liegt bei jeweils 2 einmal bei 51ms und einmal bei 86ms. Dabei soll die Zeitspanne in der die Led´s aus sind jeweils um ca. +-5-10ms variieren. Die Variation wollte ich mit dem rnd() Befehl machen. Allerdings weiss ich nicht wie die Led´s jetzt unabhängig voneinander Blinken lasse.
Ich hoffe ihr versteht mein Problem. Ich brauche nur eine Herangehensweise, das Programm schreibe ich dann natürlich selbst.

Danke
Gruß Daniel

DanielSan
18.07.2011, 16:19
Hi,

ich habe selbst noch keine Lösung gefunden.

Ist mein Problem zu schwer? Oder hab ichs unverständlich dargestellt?

Danke
Gruß Daniel

Ceos
18.07.2011, 16:25
verständlich JA, aber ohne wissen über die existierende Lösung kann man da jetzt keine sachdienlichen Hinweis geben, die Lösungsmöglichkeiten divergieren zu stark.

Je nachdem wie du das Blinken realisierst, kannst du im Compare-Interrupt ja den nächsten Compare-Wert mit deiner Rnd() um ein paar Takte vergrößern oder verkleinern .... bring mal ein wenig Code mit was du bisher shco hast, dann sehen wir weiter ^^

DanielSan
18.07.2011, 16:45
Also eine existierende Lösung habe ich noch nicht so recht. Den Atmega48 wollte ich nehmen, weil es der kleinste µC ist den ich hier rumliegen habe. Ich denke schnell genug ist er. Die Leds hab ich im Moment an PB1-PB4, das kann aber gerne geändert werden.

Mein Code sagt nicht viel weil ich ja noch keinen Ansatz habe. Aber trotzdem zeig ich was ich bis jetzt habe:

$regfile = "m48def.dat"
$crystal = 1000000
$baud = 9600
Config Timer0 = Timer, Prescale = 8

Config Pinb.1 = Output
Config Pinb.2 = Output
Config Pinb.3 = Output
Config Pinb.4 = Output

Dim I As Integer

Const Timervorgabe = 131
On Timer0 Timer_irq
Enable Timer0
Enable Interrupts

Do

Loop
End

Timer_irq:
Timer0 = Timervorgabe

Return


Ich dachte mir ich lass den Timer einfach 1000 mal pro Sekunde auslösen, so das er dann für die vier Kanäle jeweils den Status berechnet. Also ob die Led an oder aus sein soll. Aber so recht weiss ich nicht wie ich das realisieren soll.

Das ist meine Überlegung dazu es kann aber alles noch geändert werden, da bin ich flexibel.

Wenn du sonst noch infos brauchst, sag mir was fehlt ich versuche es zu liefern.

Danke
Gruß Daniel

Ceos
19.07.2011, 01:19
die überlegung ist schonmal sehr gut! du legst einfach 4 counter fest und jedesmal wenn einer deiner counter abgelaufen ist, setzt du ihn mit einem neuen wert + (rnd() * zu variierendem Wert) ... aber unter der vorraussetzung, dass rnd() einen wert zwischen 0 udn 1 liefert, das weis ich leider grad nicht ^^

beachte unbedingt, wenn du mit float arbeitest auch immer schön zu casten und die ergebnisvariablen richtig festzulegen, damit du keine kommastellen verlierst!

achja das wichtigeste vergessen, in den counterüberläufen dekrementierst du deine counter bis sie 0 erreichen, vll. noch 4 variablen die signalisieren ob du für die jeweilige LLED gerade in die on oder off phase gehst! und fasse dich bei deinen bedingungen so kurz wie möglich, der interrupt darf nciht so lange dauern!

radbruch
19.07.2011, 08:59
Hallo

Als Bascom-Laie würde ich es so versuchen:

$regfile = "m48def.dat"
$crystal = 1000000
$baud = 9600
Config Timer0 = Timer, Prescale = 8

Config Pinb.1 = Output
Config Pinb.2 = Output
Config Pinb.3 = Output
Config Pinb.4 = Output

Dim I As Integer
Dim Led1 As Byte
Dim Led2 As Byte

Const Timervorgabe = 131
On Timer0 Timer_irq
Enable Timer0
Enable Interrupts

Led1 = 51
Led2 = 86

Do

Loop
End

Timer_irq:
Timer0 = Timervorgabe

If Led1 > 0 Then
Decr Led1
Else
Toggle Pinb.1
If Pinb.1 = 1 Then
Led1 = 10 ' Anzeit
Else
Led1 = Rnd(10) + 51 ' Auszeit
End If
End If

If Led2 > 0 Then
Decr Led2
Else
Toggle Pinb.2
If Pinb.2 = 1 Then
Led2 = 10
Else
Led2 = Rnd(10) + 86
End If
End If

Return
(Ungetestet)

Gruß

mic

Andree-HB
19.07.2011, 09:15
....ich hatte mir für meine Lichtsteuerung von der letzten Party einfach Zufallszahlen generieren lassen und per if then mit festen Werten verglichen und geschaltet....

à la
if x =2 or x=4 or x=7 then Licht1an
if x =1 or x=4 or x=8 then Licht2an

...usw.

http://www.youtube.com/watch?v=Jk1I7pQMXlU&
http://www.youtube.com/watch?v=UsCiMEjm3Cw
[nachtrag]....habe mal wieder nur Alles halb durchgelesen, da sind ja noch ganz andere Anforderungen... ;-)

DanielSan
19.07.2011, 10:25
Hi,

danke für eure Antworten. Ich habe jetzt auch mal meinen Ansatz in Bascom umgesetzt.


$regfile = "m48def.dat"
$crystal = 1000000

Config Timer0 = Timer , Prescale = 8

Config Pinb.1 = Output
Config Pinb.2 = Output
Config Pinb.3 = Output
Config Pinb.4 = Output

Mg1 Alias Pinb.1
Mg2 Alias Pinb.2
Mg3 Alias Pinb.3
Mg4 Alias Pinb.4

Dim Mg1flag As Byte
Dim Mg2flag As Byte
Dim Mg3flag As Byte
Dim Mg4flag As Byte
Dim Mg1time As Integer
Dim Mg2time As Integer
Dim Mg3time As Integer
Dim Mg4time As Integer
Dim I As Integer

Const Timervorgabe = 131
On Timer0 Timer_irq
Enable Timer0
Enable Interrupts

Mg1flag = 0
Mg2flag = 0
Mg3flag = 0
Mg4flag = 0
Mg1time = 0
Mg2time = 0
Mg3time = 0
Mg4time = 0

Do

Loop
End

Timer_irq:
Timer0 = Timervorgabe
If Mg1time = 0 Then
If Mg1flag = 0 Then
Mg1time = Rnd(10) + 46 '46 weil ich gerne 51 +- 5 ms hätte
Mg1 = 1
Mg1flag = 1
Else
Mg1time = 10
Mg1 = 0
Mg1flag = 0
End If
End If

If Mg2time = 0 Then
If Mg2flag = 0 Then
Mg2time = Rnd(10) + 46
Mg2 = 1
mg2flag = 1
Else
mg2time = 10
mg2 = 0
mg2flag = 0
End If
End If

If Mg3time = 0 Then
If mg3flag = 0 Then
mg3time = Rnd(10) + 81
mg3 = 1
mg3flag = 1
Else
mg3time = 10
mg3 = 0
mg3flag = 0
End If
End If

If mg4time = 0 Then
If mg4flag = 0 Then
mg4time = Rnd(10) + 81
mg4 = 1
mg4flag = 1
Else
mg4time = 10
mg4 = 0
mg4flag = 0
End If
End If

Mg1time = Mg1time - 1
Mg2time = Mg2time - 1
Mg3time = Mg3time - 1
Mg4time = Mg4time - 1

Return


Der ist allerdings auch noch ungetestet. Es geht sicherlich noch einfacher da muss ich nochmal ran und optimieren. Ich gucke nachher mal in Bascom wielange ein IRQ braucht. Dann muss ich evtl auf 2ms "Auflösung" gehen oder ich setz die Fuses auf 8Mhz dann wirds wohl reichen!? Soo Zeitkritisch ist das ganze nicht. Ob ich überhaupt mit den Zeiten so klar komme oder ob ich die Pausen länger ziehen muss weiss ich auch noch nicht. Aber ich denke das gröbste ist geschafft.

EDIT: Ok ich muss die Fuses für 8Mhz setzen. Mit 1Mhz schafft er die IRQ nicht rechtzeitig zu beenden. Bei 8Mhz schafft er es ganz locker.

@Mic: Deine Lösung scheint schonmal etwas kürzer zu sein. Das werde ich mir nachher mal genauer ansehen. Durch den Toggle Befehl würde ich ja schonmal die Flags und deren Abfrage sparen.

Danke
Gruß Daniel

DanielSan
19.07.2011, 15:49
So hab jetzt mein Programm ausprobiert.
Irgendwie spuckt der Befehl:
rnd(10)
aber nicht die Gewünschten Zufallszahlen von 0-9 aus sondern von 0-5500 (oderso).

Ein weiteres Problem ist, das die Zeiten für "an" und "aus" scheinbar gleich lang sind. Wenn ich die "an"Zeit auf 1000 setze, ist die Led genauso lange an wie aus!?

Gruß Daniel

radbruch
19.07.2011, 19:30
Hallo

Ich programmiere selten mit Bascom und habe das jetzt mal mit dem Simulator überprüft:

...
Dim I As Integer
Dim J As Integer
Dim Led1 As Byte
Dim Led2 As Byte

Const Timervorgabe = 131
On Timer0 Timer_irq
Enable Timer0
Enable Interrupts

Led1 = 51
Led2 = 86
J = 0

Do
I = Rnd(10)
Incr J
Loop
End
...Tatsächlich zeigt der Simulator im Watch-Modus nach immer der selben Anzahl von J-Durchläufen einen I-Wert von über 9! In der ersten Variante ohne J war der I-Wert über 9 aber wiederrum ganz anders. Interessanterweise funktioniert rnd() scheinbar richtig, wenn man den Timer0-Interrupt nicht freigibt oder alle Interrupts gesperrt sind. Vielleicht verwendet rnd() irgendwie den Timer0? Seltsam und wieder typisch Bascom..

[Edit]
Weil ich auch was sehen will habe ich das Programm an meinen asuro (8 MHz Mega8) angepasst:

$regfile = "m8def.dat"
$crystal = 8000000
$baud = 2400
Config Timer0 = Timer , Prescale = 64

Config Pind.2 = Output
Config Pind.3 = Output

Dim I As Integer
Dim J As Integer
Dim Led1 As Integer
Dim Led2 As Integer

Const Timervorgabe = 131
On Timer0 Timer_irq
Enable Timer0
Enable Interrupts

Led1 = 51
Led2 = 86
J = 0

Print "Hallo"
Print
Do
I = Rnd(10)
Incr J
If I > 9 Then
Print "I: " ; I
Print "J: " ; J
Print
J = 0
End If
Loop
End

Timer_irq:
Timer0 = Timervorgabe

If Led1 > 0 Then
Decr Led1
Else
Toggle Portd.2
If Pind.2 = 1 Then
Led1 = 500 ' Anzeit
Else
Led1 = 500 ' Auszeit
End If
End If

If Led2 > 0 Then
Decr Led2
Else
Toggle Portd.3
If Pind.3 = 1 Then
Led2 = 200
Else
Led2 = Rnd(400) + 500
End If
End If

Return
Ausgabe auf dem Bascom-Terminal:

Hallo

I: 4767
J: 13

I: 61
J: 1

I: 116
J: 9

I: 172
J: 28

I: 59
J: 5

I: 10
J: 53

I: 180
J: 6

I: 176
J: 38

I: 14
J: 2

I: 164
J: 10

I: 157
J: 14

I: 46
J: 57

I: 71
J: 63

I: 113
J: 16
Verblüffend

btw. muss es Toggle PORTx.y lauten...

[Edit2]
So scheint es zu funktionieren:

Disable Interrupts
I = Rnd(10)
Enable Interrupts

Ceos
20.07.2011, 10:21
das finde ich jetzt aber EXTREM interessant, da wir uns beim ausführen des rnd() IN einer ISR befinden dürften die Interrupts doch gar nicht eingeschalten sein oder? ! ? !

Oder steh ich aufm Schlauch ? !

Bye the Way, dein Enable Interrupt nach dem Rnd() hätte fatale Auswirkungen innerhalb der ISR!

Richard
20.07.2011, 12:00
Eine Möglichkeit echte Zufallszahlen aus (Rauschen) zu erzeugen sind "offene" ADC Eingänge, kleine verschieden lange "Antennen" müsste man testen. Die dabei autretende Werte dann einfach auf eine Einschaltdauer "Rechnen" und auf die LED's verteilen?

Gruß Richard

DanielSan
20.07.2011, 12:21
@Radbruch, Ceos: Das ist echt interessant. Ich weiss aber grad nicht was ich dazu sagen soll. :)

@Richard: Das hört sich gut an. Der Atmel in meiner Anwendung, kriegt ne Menge EM-Strahlung ab. Er liegt in der nähe eines 2,4Ghz RC-Empfängers (inkl. Rückkanal) und eines 50A Brushlessreglers.

Sollte ich die "Antenne" dann so lang machen, wie eine 2,4Ghz Antenne sein sollte? Das wäre ja nicht besonders lang und würde die Platzverhältnisse nicht zu arg in Anspruch nehmen.

Danke
Gruß Daniel

radbruch
20.07.2011, 13:28
Warum das mit rnd() mit den Interrupts zusammenhängt kann ich auch nicht sagen. ich habe das auch nur mit meinem Testprogramm in der Hauptschleife geprüft, nicht im Interrupt. Aber das erzeugte Blinken der LEDs scheint mir in Ordnung zu sein.

"Echte", besser vielleicht "den Ansprüchen genügende" Zufallszahlen zu erzeugen ist ein altes Problem:
https://www.roboternetz.de/community/search.php?searchid=200513

DanielSan
20.07.2011, 13:35
Dein Link funktioniert leider so nicht. Was für suchbegriffe hast du eingegeben?

Nochmal kurz zu meinem Programm...
Ich habe es jetzt erstmal ohne Zufallszahl und mit nur einer Led gemacht.


Timer_irq:
Timer0 = Timervorgabe

If Mg1time = 0 Then
If Mg1flag = 1 Then
Mg1time = 10 ' Anzeit
Mg1 = 1
Mg1flag = 0
Else
Mg1time = 5100 ' Auszeit
Mg1 = 0
Mg1flag = 1
End If
End If

Decr Mg1time
Return

Die Zeiten habe ich ich bewusst so weit auseinander gelegt um zu prüfen ob das ordentlich funktioniert. Leider scheint die "Anzeit" genauso lang wie die "Auszeit" zu sein. Die Zeit in der die LED an bzw aus ist, entspricht auch nicht 5,1 Sekunden sondern ehr 1 Sekunde an 1 Sekunde aus. Das sollte aber doch eigentlich so sein!? Denn ich springe jede ms in die IRQ und zähle einen runter. Dann müsste ich doch auf 5100 ms kommen!?

Danke
Gruß Daniel

radbruch
20.07.2011, 13:42
"zufallszahl bascom"

:)

Richard
20.07.2011, 13:48
@Richard: Das hört sich gut an. Der Atmel in meiner Anwendung, kriegt ne Menge EM-Strahlung ab. Er liegt in der nähe eines 2,4Ghz RC-Empfängers (inkl. Rückkanal) und eines 50A Brushlessreglers.

Sollte ich die "Antenne" dann so lang machen, wie eine 2,4Ghz Antenne sein sollte? Das wäre ja nicht besonders lang und würde die Platzverhältnisse nicht zu arg in Anspruch nehmen.



Wie lang kann ich auch nicht sagen, ganz ohne b,.z.w. Irgend ein Ganzzahliger (Anteil) der zu Filternden Wellenlänge würde sich aber anbieten. Auch verschiedene Längen Pro Kanal, Auch interessant könnte ein Serien Schwingkreis LC sein, wobei der ADC dann zwischen L und C abgegriffen wird. Damit, bei richtiger Berechnung, kann auf bestimmte "Sender" gefiltert werden. Ob ich die Formel für die Resonanz Frequenz nuch zusammen bekomme? (1/2* Pi * √ (L*C)) "oder ähnlich". :-(

Gruß Richard

DanielSan
20.07.2011, 14:01
Das komische an meinem Programm, ist das es im Simulator sauber durchläuft. Die Zeiten stimmen die Led blinkt wie sie soll etc.
Warum klappt es dann nicht wenn ich das Programm in den Atmega48 schreibe?

Jtag ist aus und die Clock steht auf 8Mhz so wie im Code angegeben...

Danke
Gruß Daniel

radbruch
20.07.2011, 14:17
Bei mir funktioniert das wie erwartet:
$regfile = "m8def.dat" 'Setup asuro
$crystal = 8000000

Config Timer0 = Timer , Prescale = 64

Config Pind.2 = Output
Config Pind.3 = Output
Config Pind.4 = Output
Config Pind.5 = Output

Mg1 Alias Portd.2
Mg2 Alias Portd.3
Mg3 Alias Portd.4
Mg4 Alias Portd.5

Dim Mg1flag As Byte
Dim Mg2flag As Byte
Dim Mg3flag As Byte
Dim Mg4flag As Byte
Dim Mg1time As Integer
Dim Mg2time As Integer
Dim Mg3time As Integer
Dim Mg4time As Integer
Dim I As Integer

Const Timervorgabe = 131
On Timer0 Timer_irq
Enable Timer0
Enable Interrupts

Mg1flag = 0
Mg2flag = 0
Mg3flag = 0
Mg4flag = 0
Mg1time = 0
Mg2time = 0
Mg3time = 0
Mg4time = 0

Dim Led2 As Byte
Led2 = 0
Mg1 = 1 'LEDs aus
Mg2 = 1
Mg3 = 1
Mg4 = 1

Do

Loop
End

Timer_irq:
Timer0 = Timervorgabe

If Mg1time = 0 Then
If Mg1flag = 1 Then
Mg1time = 250 ' Anzeit
Mg1 = 1
Mg1flag = 0
Else
Mg1time = 250 ' Auszeit
Mg1 = 0
Mg1flag = 1
End If
End If
Decr Mg1time

If Led2 > 0 Then
Decr Led2
Else
Toggle Portd.3
If Pind.3 = 0 Then
Led2 = 249 ' Anzeit-1!
Else
Led2 = 249 ' Auszeit-1
End If
End If
Return

DanielSan
20.07.2011, 14:22
Oh man alles klar DANKE!
Es lag an:

Mg1 Alias Pinb.1
Das muss natürlich:

Mg1 Alias Portb.1
heissen. Das müsste doch der Compiler eigentlich merken oder?

Danke
Gruß Daniel

021aet04
20.07.2011, 14:27
Ich weiß zwar nicht wie es in Bascom ist, aber bei C ist es egal, da er beides kennt (nicht genau die Befehle, aber auch mit Ein-/Ausgängen).
Wenn es so ist wie in C (AVR Studio mit GCC) ist PINB für Eingänge vom Port B und PORTB Ausgänge vom Port B.

MfG Hannes

radbruch
20.07.2011, 14:35
würgs:
Timer_irq:
Timer0 = Timervorgabe

If Mg1time = 0 Then
If Mg1flag = 1 Then
Mg1time = 250 ' Anzeit
Mg1 = 1
Mg1flag = 0
Else
Do ' Auszeit
Mg1time = Rnd(500)
Loop Until Mg1time < 500
Mg1time = Mg1time + 250
Mg1 = 0
Mg1flag = 1
End If
End If
Decr Mg1time

Return

DanielSan
20.07.2011, 14:43
Edit: Ah jetzt seh ich erst was du gemacht hast! Du Fuchs ;-)

Ok deine Lösung ist zwar "gepfuscht" ;-) aber sie funktioniert. Ich denke das Rnd() nicht richtig funktioniert ist ein Bug in Bascom.

Gruß Daniel