Viele Anfänger machen gern den Fehler und vergessen der Picaxe beim Programieren als erstes mitzuteilen , welcher Pin denn eigentlich was sein soll.
Laut Manual steht zwar , das durch manche Befehle sich die Pins selbstständig als Ein- oder Ausgang definieren. Ich empfehle jedoch , es sich zur Gewohnheit zu machen , dennoch immer am Anfang erst die Pins definitiv als Ein-oder Ausgang festzulegen.
Der Editor bietet im Menu die Möglichkeit : Simulate ( deutsch: Simulator )
Wenn man jetzt mal nur den Befehl : Pause 100 programmiert und den Simulator startet , kann man wunderbar erkennen , das alle Pins immer erst Eingänge sind.
Alle Pins die ein Ausgang sind , werden flach dargestellt , alle Pins die ein Eingang sind als Button. Da bei der 08M2 der Pin C.0 der serielle Ausgang ist , wird dieser als einziger bereits flach , als Ausgang ,dargestellt.
Mit dem Befehl : let dirs ( deutsch: setze Richtung ) wird der Picaxe mitgeteilt welcher Pin was sein soll.
Man kann jetzt einen Wert dezimal angeben , jedoch wäre diese Schreibweise recht umständlich bzw. unübersichtlich. Da die Pins vom Hersteller wie das Binärsystem angeordnet sind , bietet sich die binäre Schreibweise hierbei an.
Da bei der 08M2 die Pin3 und Pin5 von haus aus Eingänge sind, ließen sich nur noch die Pins 1 , 2 , 4 als Ausgang defineren. Dies würde dann als Befehl wie folgt aussehen :
Let Dirs = %000010110 ( wichtig dabei ist das Vorzeichen : % ) |addpics|nqa-l-1ed9.jpg,nqa-m-e540.jpg|/addpics|
Das ist natürlich riiiiiiiesen Blödsinn !!! Die Picaxe ist ja nur ein aufgesetztes System und als Grundtyp dient eine PIC.
Eine PIC kann ohne zusätzliche Hardware nicht schneller als 8 Mhz laufen ! Würde man also dem Manual glauben schenken , hätten wir spätestens bei der Einstellung setfreq m16 ein Perpetuum-Mobile !
Also kann man vielleicht eher sagen , das die Einstellung setfreq m32 die original 8Mhz sind, bedingt dadurch das die Picaxe aufgesetzt ist, vielleicht nur noch 5-6Mhz. Alle anderen setfreq Einstellungen sind eben entsprechend langsamere Taktgeschwindigkeiten.
Im Vergleich hat sich gezeigt, das eine Picaxe mit setfreq m8 und ein AVR mit absolut der gleichen Aufgabenstellung , ein AVR um den Faktor 1000 schneller ist. Da brauch man dann nichts mehr zu zusagen.
Wichtig ist noch, wenn also nicht mit der "normalen" , voreingestellten Frequenz von 4Mhz gearbeitet wird, ändern sich viele Befehle proportional !! Z.B. der Befehl : Pause
Pause 1000 ist bei 4 Mhz "exakt" 1 Sekunde. Bei 8 Mhz allerdings nur noch 500ms ! Bei 16 Mhz nur noch 250ms ! Bei 32 Mhz nur noch 125ms !
Anderes Beispiel : Pulsin Bei 4 Mhz mißt dieser in einer max Zeit von 655ms Bei 8 Mhz in 327ms Bei 16 Mhz in 163ms Bei 32Mhz in 82ms
Einige wenige Befehle bleiben von einem solchen Frequenzwechsel unberührt , andere Befehle mögen sowas überhaupt nicht. Es empfiehlt sich daher immer mal ins Manual.pdf zu schaun , ob bei Änderung der Frequenz alle programmierten Befehle auch ausgeführt werden.
Ein schöner Umstand der proportionalen Änderung ist der Befehl: sertxd + serrxd Bei 4 Mhz ist die Geschwindigkeit fest 4800 Baud. Bei 8Mhz jedoch schöne 9600 Baud. Bei 16 Mhz schon 19200 Baud Und bei 32Mhz bereits 38400 Baud.
Man sieht, es hat alles Vor- und Nachteile. Es handelt sich aber auf jeden Fall um eine reine Softwareeinstellung , die so mit der Wirklichkeit rein garnichts gemeinsam hat.
Ack so, .... wichtig seih noch zu erwähnen , das das Multitasking ausschliesslich unter 4Mhz funktionert !
Viele haben noch immer das Problem , das sie mehrfache Kontaktauslöser bekommen , weil der angeschlossene Taster am "zittern" ist.
Es gibt da auch immer wieder nette Vorschläge wie man sowas hardwareseitig lösen könnte , jedoch halt ich das eher für eine 50:50 Chance , je nachdem wie schlecht der benutzte Taster gebaut ist.
Die beste oder sicherste Methode ist noch die Software-Entprellung. Dazu gibt es 2 Möglichkeiten.
1.)
Man gibt eine Zeit vor nachder wieder geprüft wird. Beispiel :
1 2 3 4 5 6 7
nochmal: If pinc.2 = 1 then Pause 200 goto nochmal endif
Hier wird also nach Auslösen des Tasters 200ms gewartet und wieder nachgefragt ob noch immer der Taster gedrückt worden ist. Wenn ja , .... warten .... wieder nachfragen. Bis der Taster losgelassen wurde.
2.)
Durch eine Endlos-Schleife wird einfach so lange gewartet bis erkannt wird, das der Taster losgelassen wurde. Beispiel :
1 2 3 4
Do loop until pinc.0=0
Löst der Taster aus wird in die Do .. Loop Schleife gesprungen und so lange nüx gemacht bis der Taster losgelassen wurde.
Welche Möglichkeit man am Ende nutzt hängt ein wenig von ab welche Situation vorliegt. Man kann auch Hardware-Entprellung und Software-Entprellung kombinieren|addpics|nqa-k-4d7f.jpg|/addpics|
Hier erkläre ich einmal den Zusammenhang von Bits , Bytes und Words bei einer Picaxe.
Ein Byte besteht , wie man wissen sollte , aus 8 Bits. Gezählt wird ab 0 und von rechts nach links , also : bit7 , bit6 , bit5 , bit4 , bit3 , bit2 , bit1 , bit0
Das Picaxe-System benutzt anders als bei anderen Basicdialekten feste Namen als Variablen. Somit sind die Bits vorgegeben mit bit0 bis bit15 , die Bytes mit b0 bis b27 und die Words mit w0 bis w13
Wie man ein LCD-Display ( 16 x 2 ) an einer Picaxe betreibt , habe ich ja schon einmal ausführlich beschrieben. ^^
Viele möchten aber gerne auch einmal ein 20x4 Display nutzen. OK. Wenn man nicht gerade einen "Exoten" kauft , hat man in der Regel die gleichen Anschlüsse wie bei einem 16x2 Display. 14 Pins ohne Backlightpins und 16 Pins mit Backlightpins - Belegungen sind von Pin1 - Pin14 identisch.
Der Code ist im grunde auch gleich, zumindest die Initialisierung. Lediglich beim Anzeigen der Zeilen haben wir jetzt 2 zeilen mehr und müssen dementsprechend vor der Anzeige von Texten in die entsprechende Reihe schalten.
symbol Wert = b0 symbol HighWert = b1 symbol LowWert = b2
let dirsb=%11111111 let dirsc=0
' INITIALISIERUNG FOR b10=1 to 3 LET PINSb=%00100011:low 5 LET PINSb=%00100011:low 5 pause 50 NEXT b10
' 4 Bit Modus LET PINSb=%00100000:low 5 LET PINSb=%00100010:low 5 pause 10
' 5x8 Matrix / 2 Reihen LET PINSb=%00100010:low 5 LET PINSb=%00101000:low 5 pause 10
'Display Clear LET PINSb=%00100000:low 5 LET PINSb=%00100001:low 5 pause 10
'Return Home LET PINSb=%00100000:low 5 LET PINSb=%00100110:low 5 pause 10
' Display ON,Cursor OFF, No blinken LET PINSb=%00100000:low 5 LET PINSb=%00101100:low 5 pause 10 let pinsb=0 '####################################### '#######################################
' ~~~~~~~~ Reihe 1 ~~~~~~~~~~~~~~~~~~~ LET PINSb=%00100000:low 5 LET PINSb=%00100010:low 5 for b10=0 to 15 lookup b10,("Dies ist Zeile 1"),Wert gosub Sendtext next b10 ' ~~~~~~~~ Reihe 2 ~~~~~~~~~~~~~~~~~~~ LET PINSb=%00101100:low 5 LET PINSb=%00100000:low 5 for b10=0 to 15 lookup b10,("Dies ist Zeile 2"),Wert gosub Sendtext next b10 ' ~~~~~~~~ Reihe 3 ~~~~~~~~~~~~~~~~~~~ LET PINSb=%00101001:low 5 LET PINSb=%00100100:low 5 for b10=0 to 15 lookup b10,("Dies ist Zeile 3"),Wert gosub Sendtext next b10 ' ~~~~~~~~ Reihe 4 ~~~~~~~~~~~~~~~~~~~ LET PINSb=%00101101:low 5 LET PINSb=%00100100:low 5 for b10=0 to 15 lookup b10,("Dies ist Zeile 4"),Wert gosub Sendtext next b10
Viele fertige Routinen sind ja in der Picaxe schon enthalten , nur für ein Display leider bis heute noch nichts. Etwas verwunderlich , da echte Mikrocontroller solch Routinen schon von je her enthalten haben.
Von daher gibt es 2 Möglichkeiten :
1. man kauft sich ein teures serielles Display 2. man erstellt sich selbst eine Routine
Ein normales LCD-Display 16x2 gibt es ja schon bei Ebay für 3.- bis 5.- Euro. Zu 99,9% sind alle Displays völlig identisch vom Anschluss als auch von der Programmierung her.
Solch Display läßt sich im sogenannten 8Bit-Modus als auch im 4Bit-Modus programieren. Beim 8Bit-Modus benötigt man 8 Datenleitungen + RS + Enable = 10 Leitungen. Beim 4Bit-Modus benötigt man nur 4 Datenleitungen + RS + Enable = 6 Leitungen.
Der 4Bit-Modus hat sich mittlerweile durchgesetzt und wird am häufigsten benutzt. Einzige Besonderheit dabei ist, das man eben für jeden Befehl zur Ausführung 2x ein 4Bit-Byte senden muss.
Der Trick beim 4Bit-Modus ist , das man die unteren 4 Bits eines Bytes auf Masse setzt und somit diese auf logisch 0 setzt. Dadurch brauch man nur noch 4 Leitungen für die oberen 4Bits um ein volles Byte zu erhalten.
Um sich die Sache einfach zu halten , insbesondere beim Programmieren einer Routine , empfiehlt es sich , zusammenliegende Pins von xx.0 bis xx.5 für das Display zu nehmen.
So ein Display hat im Grunde 2 Modi :
a ) ist der RS-Pin auf Low = Command-Mode b) ist der RS-Pin auf High = ASCII-Mode
Im Command-Mode werden folgende Aktionen ausgeführt : - Initialisierung - Setzen der Cursorposition - Cursor an/aus - Cursor blinken oder nicht - Shiften rechts/links - Display Clear
Im ASCII-Mode werden ausschließlich nur ASCII-Zeichen gesendet für die Anzeige auf dem Display.
Ein Display kann man also nicht einfach so anschliessen und danach einfach mal ein paar Texte rübersenden. Solch ein Display hat selbst einige Mikrocontroller auf seiner Platine denen man ja erst einmal mitteilen muß was man gern möchte. Dazu macht man am Anfang immer erst eine Initialisierung
Ich denke jetzt die Initialisierung im Detail zu erklären gehört mehr in ein Fortgeschrittenen Tutorial , insofern hier die Initialisierung ohne groß Kommentar :
FOR b0=1 to 3 LET PINSb=%00100011:low 5 LET PINSb=%00100011:low 5 pause 50 NEXT b0
' 4 Bit Modus LET PINSb=%00100000:low 5 LET PINSb=%00100010:low 5 pause 10
' 5x8 Matrix / 2 Reihen LET PINSb=%00100010:low 5 LET PINSb=%00101000:low 5 pause 10
'Display Clear LET PINSb=%00100000:low 5 LET PINSb=%00100001:low 5 pause 10
'Return Home LET PINSb=%00100000:low 5 LET PINSb=%00100110:low 5 pause 10
' Display ON,Cursor OFF, No blinken LET PINSb=%00100000:low 5 LET PINSb=%00101100:low 5 pause 10 let pinsb=0
Return
Diesen Code , zusammen mit dem Schaltplan für die Anschlussbelegung kann man immer und immer wieder nutzen.
Vielleicht wird dem ein oder anderen aufgefallen sein , das ich ja sagte , das wir "nur" 4 Bits senden , jedoch immer das 5. Bit auf 1 gesetzt ist.
Tjaaa , wenn man alles richtig angeschlossen hat, ist ja Bit5 ( Pin xx.5 ) => Enable Ein Display benötigt immer eine Art Clock-Signal um etwas auszuführen. Das heißt , wenn ich etwas senden will , muß ich einmal das Bit5 auf High und wieder auf Low setzen.
In der Initialisierung mache ich das Setzen des Bit5 durch Angabe von Let Pins in einem Atemzug.
Anschliessend durch den Befehl : low 5 setze ich das Bit5 wieder auf 0
Damit habe ich also eine Clock ausgelöst und das Display führt den Befehl aus.
Jetzt haben wir also das Display initialisiert, aber das reicht ja noch nicht. :)
Jetzt benötigen wir ja noch eine Routine , die uns ASCII-Zeichen auf´s Display sendet. Dazu benutzen wir folgende :
Was wird hier gemacht ? Nun, .... nehmen wir an , wir wollen ein 'A' ans Display senden. Ein 'A' ist ja das ASCII-Zeichen '65' Da wir ja keine vollen Bytes senden können, müssen wir dieses in 2x 4Bits unterteilen. Da 4Bits max. eine Zahl von 16 sein kann , ist also der Teilungsfaktor => 16 Also rechnen wir:
Da wir ja gesagt haben , das wenn wir ASCII-Zeichen senden wollen , wir den Pin RS auf high haben müssen , zudem der Pin Enable auch high sein soll , wären das also Bit4 + Bit5 ( 16+32 = 48 ) , und zähle somit auf den ersten Wert, dem Highwert noch 48 drauf. ( HighWert=HighWert+48 )
Da eine Ausführung ja ein Clock-Signal benötigt , wir durch die Addition von 48 den Enable schon auf high gesetzt haben , müssen wir den Enable nur noch auf low setzen um den Clock zu vollenden. ( let pinsb=HighWert:low 5 )
Das ganze "Spiel" erfolgt jetzt auch nochmal mit dem LowWert ..... ( LowWert=LowWert+48 : let pinsb=LowWert:low 5 )
Das war schon die ganze Routine für das Senden von ASCII-Zeichen. :thumbsup: Wenn man das einmal verstanden hat , einfacher als Fahrrad fahren.
Was jetzt noch fehlt , das wären ja die Command-Befehle.
Zunächst beschränke ich mich hier auf die Positionierung des Cursors. Wir können , wenn genug Interesse besteht , später noch auf andere Commands eingehen. ^^
Eigentlich ist bei allen Displays der Befehl für : Cursor 1. Zeile - links und Cursor 2. Zeile - links immer gleich.
Einen sogenannten Drehencoder oder Drehimpulsgeber mit einer Picaxe auszuwerten ist leider garnicht so einfach. :(
"Normale" Mikrocontroller haben meistens bereits schon fertige Routinen enthalten , während bei einer Picaxe man das leider selber machen muss.
Drehencoder gibt es in viele Variationen :
Sie arbeiten in der Regel alle nach dem selben Prinzip:
2 Pins ( meist A + B ) werden mit einem Pullup-Widerstand auf High gesetzt. Während des Drehens verbindet der Drehencoder nun abwechselnd Pin A oder Pin B mit Pin C = Masse. Ab und an wird sogar noch ein Kondensator von 100nF parallel zum Pullup gesetzt.
Da ja nun beim Drehen unheimlich schnelle Impulse entstehen , ist die Picaxe leider nicht in der Lage ohne Verluste den Encoder auswerten zu können und auch noch eine Anzeige darzustellen.
Es ist aber möglich nach dem Auswerten 2 Ausgänge passend zur Drehrichtung mit LED´s zu versehen , die einem die Richtung und Anzahl der Impulse darstellen.
Dazu hier der Schaltplan :
Der zugehörige Code ist am Anfang vielleicht nicht so ganz leicht zu verstehen , aber evtl. kommt der Ein oder Andere hinter das Prinzip :
Die Picaxe eignet sich sehr gut um Spannungen zu messen.
Wichtig zu beachten ist allerdings : Die zu messende Spannung darf niemals höher als die Versorgungsspannung der Picaxe sein - sprich 5V !
Um eine vernünftige Messung zu erzielen , benötigt man eine sehr stabile Versorgungsspannung , da die Picaxe die Versorgungsspannung als Referenzspannung beim Messen nutzt. ( Bei manchen Picaxe kann man die Referenzspannung einstellen , ob intern oder extern - hier nutzen wir ausschließlich die interne )
ADC bedeutet : Analog - Digital - Conversion Das heißt , aus einer Gleichspannung eine Dezimalzahl ermitteln.
Es gibt 2 Befehle dazu :
1. readadc -> hierbei wird mit 8Bit aufgelöst , was allerdings recht wenig ist 2. readadc10 -> hierbei wird mit 10Bit aufgelöst , dieser Befehl ist zu empfehlen
10Bit bedeutet , das aus der analogen Spannung ein Wert von 0 bis 1023 ermittelt werden kann.
Wenn wir also eine stabile Versorgungsspannung von 5V haben , dann wäre : 0 = 0 Volt / 1023 = 5V
Jetzt benötigen wir lediglich den Teilungsfaktor : 5V : 1023 = 0,0048
Fangen wir hier erst einmal mit dem Schaltplan an. Als Test nutzen wir ein simples Poti mit 10K um Werte zu erhalten.
Den ermittelten Wert lassen wir uns über ein Terminalprogramm anzeigen. ( Wir nutzen 4Mhz , das heißt : 4800 Baud einstellen )
Einen LDR ( Light Diode Resistor ) ist ein lichtempfindlicher Widerstand , der je nach Helligkeit eine angelegte Spannung mehr oder weniger durch läßt.
Dadurch läßt sich ein LDR wunderbar mit einer ADC-Messung auswerten.
Hier will ich einmal eine Schaltung vorstellen , die einen LDR ausliest und entsprechend eine LED an- oder ausschaltet.
Wobei , die LED geht erst an , wenn ein voreingestellter Wert an Helligkeit erreicht ist und aus erst , wenn ein voreingestellter Wert unterschriten wird.
Der Befehl BINTOASCII ( binär Zahl zum ASCII-Zeichen ) wird hauptsätzlich benutzt , wenn Werte die größer als ein Byte sind , seriell übertragen werden sollen oder bei der Kommunikation mit LCD-Displays.
Bei der seriellen Übertragung kann man ja nur Bytes verwenden. Was aber tun , wenn man Zahlen hat die weit größer sind ? Z.B. ein Word ? Oder eine Kommazahl ?
Hier kommt dann der Befehl : BINTOASCII ins Spiel. Mit diesem Befehl "zerlegt" man quasi die große Zahl in deren einzelne Ziffern.
Es gibt 2 Möglichkeiten BINTOASCII zu nutzen:
1. zum Übermitteln eines Bytes 2. zum Übermitteln eines Word
Bei einem "Zerlegen" eines Bytes benötigt der Befehl 3 Variablen : Hunderter - Zehner - Einer
Beispiel : die Zahl 123 würde "zerlegt" werden in -> Hunderter = 1 , Zehner = 2 , Einer = 3
Beim einem "Zerlegen" eines Word benötigt der Befehl 5 Variablen : Zehntausender - Tausender - Hunderter - Zehner - Einer Beispiel :
die Zahl 12345 würde "zerlegt" werden in : Zehntausender = 1 Tausender = 2 Hunderter = 3 Zehner = 4 Einer = 5
Danach kann man dann mit dem Befehl sertxd z.B. die Werte einzeln übermitteln :
sertxd (Zehntausender , Tausender , Hunderter,Zehner , Einer , 13,10)
Ein einfacher Dimmer , der mittels nur einem Taster eine LED hell und dunkel schalten kann , ist recht einfach zu realisieren.
Wir nutzen dazu den Befehl : PWMOUT zum Aktivieren und PWMDUTY zum Einstellen . Da wir PWMOUT nutzen ist bei der jeweilgen Picaxe im Manual nachzusehen , welcher Pin dafür geeigent ist.
Ein Shift Register an einer Picaxe kann viele Vorteile bringen. Mit nur 3 Pins ist es möglich 8 Ausgänge schalten zu können.
Das macht es besonders bei kleineren Picaxe interessant , die von Haus aus wenig Pins zu bieten haben.
Es gibt viele Typen an Shift Registern , jedoch empfehle ich das CD4094. 1. es hat eine breite Spanne an möglicher Versorgungsspannung 2. es bietet ein STROBE 3. es hat eine Latch-Funktion
Strobe :
Der Vorteil bei einer STROBE-Funktion ist es, das man "in Ruhe" die einzelnen Bits an Shift Register senden kann , ohne das diese gleich ausgeführt werden . Erst nachdem die STROBE-Leitung einen Impuls erhalten hat, werden die aktuellen Bitzustände übernommen und sind an den Ausgängen sichtbar - quasi eine Quittierung.
Latch:
Die Latch-Funktion hat den Vorteil , das der letzte Zustand gehalten wird, egal was derzeitig an die aktuellen Bits gesendet wurde. Erst nach dem Strobe wird der neue Zustand angezeigt und weiter gehalten. Damit ist es also nicht nötig ständig den Zustand senden zu müssen , sondern nur bei einer Änderung.
Zunächst hier einmal der Schaltplan :
Auf Lochraster könnte es z.B. so aussehen :
Jetzt kann man das Shift Register ja zu vielen Zwecken benutzen. Also Beispiel habe ich hier einmal ein paar Arten von Lauflichtern programiert.
Das wichtigste ist eigentlich , das man sich eine Routine fertig macht , die das Senden übernimmt , in der die einzelnen Bits des Bytes rückwärts an das Shift Register gesendet werden. Alles andere ist dann nur noch "Spielerei" und simple Programierung.
Bei etwas komplexeren Mustern , empfiehlt es sich den Befehl : Lookup zu nutzen
Der Befehl : GOSUB ist zwar ein netter Befehl , macht das System allerdings sehr sehr langsam !! Wenn man also Muster hat , die so schnell als möglich ablaufen sollen , empfiehlt es sich immer GOTO einzusetzen !
Im Vergleich zum vorherigen Code hier das Beispiel mit GOTO :
' ################################### ' # Lauflicht => 2 LED kreuzen sich # ' ###################################
symbol Clock = c.0 symbol Data_ = pinc.1 symbol Strobe = c.2
let dirsc=%00000111
do
for b1=0 to 43 lookup b1,(0,0,128,128,1,1,64,64,2,2,32,32,4,4,16,16,8,8,16,16,4,4,32,32,2,2,64,64,1,1,128,128,0,0),b0 goto Senden weiter: pause 4 next b1
In diesem kleinen Beispiel ist die Steigerung mit GOTO relativ gering , jedoch schon erkennbar. Bei längeren Mustern oder komplexeren Aufgaben würde sich das wesentlich deutlicher zeigen.
Gosub ist programmiertechnisch eleganter , jedoch kann Eleganz niemals = Schnelligkeit heißen - ein Widerspruch ins sich selbst ! Also aufpassen was so in anderen Foren evtl. für Blödsinn verzapft wird. Anstelle von lookup könnte man auch Read und Write nehmen , aber auch diese Eleganz geht auf Kosten des Tempos. Die Funktion(en) table / tablecopy sind das tötlichste an Tempo schlechthin. Erst in die Variablen kopieren , dann erst zum Senden schicken ist mind. 1 Schritt unnötig zu viel und kostet Zeit.
Meist gilt hier eh , doing by learning ..... selber testen und entscheiden |addpics|nqa-5-b541.jpg,nqa-6-76f4.jpg|/addpics|
Der ein oder andere möchte vielleicht gern einmal einen Servo mittels Poti und einer ADC-Messung steuern.
Grundsätzlich ist das kein Problem. Allerdings , sind die Wertebereiche beider etwas unterschiedlich !
Ein Servo kann i.d.R von 75 bis 225 und eine ADC-Messung von 0 bis 1023.
Würde man jetzt 1:1 die ADC-Werte übernehmen , müßte jetzt auch jeder Laie erkennen , das das so nicht gehen kann und unter Umständen sogar den Servo bzw. dessen Elektronik zerstören kann :!: :o
Also benötigt man eine Umrechung von 1023 möglichen ADC-Werten auf 150 mögliche Servopositionen. Dazu reicht es wenn man sich einen Faktor errechnet mit :
readadc10 c.1,ADC_Messung ' Spannung am Poti messen if ADC_Messung<>ADC_Wert then ' hat sich Spannung geändert ...? ADC_Wert=ADC_Messung ' neue Spannung merken
ADC_Messung=ADC_Messung *10 ' umrechnen auf ADC_Messung=ADC_Messung /68 ' möglichen Servostellbereich
Servo_Position=Servo_min+ADC_Messung ' neue Position erechnen servopos c.1,Servo_Position ' Servo neu Positionieren endif
loop end
Das gleiche kann man auch per LDR-Messung machen :
readadc10 c.1,LDR_Messung ' Spannung am LDR messen if LDR_Messung<>LDR_Wert then ' hat sich Spannung geändert ...? LDR_Wert=LDR_Messung ' neue Spannung merken
LDR_Messung=LDR_Messung *10 ' umrechnen auf LDR_Messung=LDR_Messung /68 ' möglichen Servostellbereich
Servo_Position=Servo_min+LDR_Messung ' neue Position erechnen servopos c.1,Servo_Position ' Servo neu Positionieren endif
Viele haben schon mal vor dem Problem gestanden , eine Hysterese bzw. einen Schwellwert auslesen zu müssen.
Das ist im Grunde nicht schwer und viele programmieren dies auf einfachste Weise wie z.B. :
Schleife : If Wert_xyz >= Schwellwert then .....
If Wert_xyz < Schwellwert then ..... goto Schleife
grundsätzlich und für den Menschen logisch.
In den meisten Fällen funktioniert das auch , insbesondere wenn "nur" LED's zu schalten sind. In Wahrheit kann dies aber zu ungewollten Effekten führen und für das ein oder andere Baueil sogar schädlich enden.
Wenn jetzt z.B. die Schleife durchlaufen wird, der Wert_xyz IST größer als der Schwellwert , ..... wird eine Ausführung je nach Code gemacht, da hier jetzt das then erfolgt. Aber ...... wenn jetzt beim nächsten (Schleifen)-Durchgang der Wert_xyz sich nicht geändert hat und somit immer noch >= dem Schwellwert ist , wird wieder das then zutreffen und es wird wieder die gleiche Ausführung wie zuvor erfolgen.
Wenn diese Ausführung z.B. das Wechseln von 2 LED Zuständen ist ( High/Low) , tut denen das nicht so "weh" und wenn die Picaxe schnell genug ist , bekommt das menschliche Auge das auch nicht wirklich mit. Ist es aber ein anderes Bauteil, was evtl. etwas empfindlich darauf reagiert , das ständig AN geschaltet wird , obwohl es ja schon AN ist , ..... kann das unter Umständen solch Bauteil in Mitleidenschaft ziehen.
Darum sollte man die Hysterese etwas konkreter gestalten in dem man zwar wie gehabt fragt :
If Wert_xyz >= Schwellwert then .....
aber dann noch mal explizit nachfragt , ob eine zugehörige Ausführung schon erfolgt ist . Denn dann muß diese nicht wiederholt erfolgen.
symbol Schwellwert = w0 symbol ADC_Messung = w1 symbol rot = b4 symbol gruen = b5 symbol aus = 0 symbol an = 1
Schwellwert=100
Do
readadc10 c.4,ADC_Messung ' Spannung am Poti messen
if ADC_Messung>=Schwellwert then ' wenn Spannung >= Schwellwertvorgabe ... if rot=aus then ' wenn rote LED noch NICHT an ... gosub schalte_rot ' Sprung zur Routine : schalte_rot endif endif
if ADC_Messung<Schwellwert then ' wenn Spannung < Schwellwertvorgabe ... if gruen =aus then ' wenn grüne LED noch NICHT an .... gosub schalte_gruen ' Sprung zur Routine : schalte_gruen endif endif
loop end
schalte_rot: rot=an ' merken das rote LED jetzt an ist gruen=aus ' merken das grüne LED jetzt aus ist high c.1 ' rote LED anschalten low c.2 ' grüne LED ausschalten return
schalte_gruen: gruen=an ' merken das rote LED jetzt aus ist rot=aus ' merken das grüne LED jetzt an ist low c.1 ' rote LED ausschalten high c.2 ' grüne LED anschalten return
In diesem Codebeispiel wird erst dann ausgeführt wenn : a) entsprechender Schwellwert erreicht b) noch keine entsprechende Ausführung erfolgte
Das verschnellert zum Einen den Code und zum Anderen schützt es das(die) Bauteil(e) die angeschlossen sind und geschaltet werden sollen.
if neue_Wunschzahl<>vorherige_Wunschzahl then ' Abfragen ob neue Zufallszahl <> alte Zufallszahl ( keine Wiederholung )
vorherige_Wunschzahl=neue_Wunschzahl ' neue Zufallszahl merken
sertxd (#neue_Wunschzahl,13,10) ' Zufallszahl über Tx ausgeben ( 4800 , n , 8 , 1 )
endif ' Abfrage schliessen
loop
Einzig "Besonderheit" hierbei ist , das ich bei jeder neuen generierten Zufallszahl vor der Übernahme erst abfrage , ob diese <> als die vorherige Zufallszahl war um nicht 2 auf einander folgende gleiche Zahlen zu bekommen. :ugeek:
Um eine Zufallszahl innerhalb eines Bereichs zu generieren muß man auch hier ein wenig tricksen .... .... da die Picaxe nur von 0 bis 65535 kann.
Möchte man jetzt z.B. eine Zufallszahl von 5 bis 10 , müßte man eine Zahl mittels MOD von 1-6 generieren lassen. Diesen Wert dann mit 4 addieren , so das man einen Wertebereich von 5-10 erhält.
Ein Klassiker aus meinen Anfängen mit der Picaxe - passend zum Thema : Zufallszahl
Das Prinzip ist sehr einfach , es werden 4 Ausgänge genutzt. Drei dieser Ausgänge sind jeweils mit 2 LED bestückt für die Zahlen : 2 - 4 - 6 Um die zahlen 1 - 3 - 5 darstellen zu können , wird an einem weiteren Ausgang nur eine LED gesetzt. Damit sind alle Zahlen von 1 - 6 darstellbar.
Als Quellcode habe ich einmal 3 verschiedene Variationen entwickelt :
1. die simpelste Methode per Zufall eine Zahl zwischen 1 und 6 zu ermitteln und dann entsprechende Ausgänge schalten:
symbol PWM1_Duty = w0 ' b0+b1 symbol PWM2_Duty = w1 ' b2+b3 symbol PWM3_Duty = w2 ' b4+b5 symbol PWM4_Duty = w3 ' b6+b7
symbol PWM1_Duty_merken = w4 ' b8+b9 symbol PWM2_Duty_merken = w5 ' b10+b11 symbol PWM3_Duty_merken = w6 ' b12+b13 symbol PWM4_Duty_merken = w7 ' b14+b15
symbol Zaehler1 = b16 symbol Zaehler2 = b17 symbol Zaehler3 = b18 symbol Zaehler4 = b19
symbol Grundwert1 = 10 symbol Grundwert2 = 30 symbol Grundwert3 = 65 symbol Grundwert4 = 80
start:
random PWM1_Duty if PWM1_Duty<>PWM1_Duty_merken then PWM1_Duty_merken=PWM1_Duty PWM1_Duty = PWM1_Duty // 240+1 PWM1_Duty = PWM1_Duty + Grundwert1 pwmout b.2,100,PWM1_Duty
for Zaehler1= PWM1_Duty to Grundwert1 step -1 pwmduty b.2,PWM1_Duty next Zaehler1
for Zaehler1= Grundwert1 to PWM1_Duty pwmduty b.2,PWM1_Duty next Zaehler1 else goto start endif
goto start
'------------------------------------------
start1:
random PWM2_Duty if PWM2_Duty<>PWM2_Duty_merken then if PWM2_Duty<> PWM1_Duty_merken then if PWM2_Duty<> PWM3_Duty_merken then if PWM2_Duty<> PWM4_Duty_merken then
for Zaehler2= PWM2_Duty to Grundwert2 step -1 pwmduty b.4,PWM2_Duty next Zaehler2
for Zaehler2= Grundwert2 to PWM2_Duty pwmduty b.4,PWM2_Duty next Zaehler2 else goto start1 endif endif endif endif
goto start1
'------------------------------------------
start2:
random PWM3_Duty if PWM3_Duty<>PWM3_Duty_merken then if PWM3_Duty<> PWM1_Duty_merken then if PWM3_Duty<> PWM2_Duty_merken then if PWM3_Duty<> PWM4_Duty_merken then
for Zaehler3= PWM3_Duty to Grundwert3 step -1 pwmduty c.0,PWM3_Duty next Zaehler3
for Zaehler3= Grundwert3 to PWM3_Duty pwmduty c.0,PWM3_Duty next Zaehler3 else goto start2 endif
endif endif endif
goto start2
'------------------------------------------
start3:
random PWM4_Duty if PWM4_Duty<>PWM4_Duty_merken then if PWM4_Duty<> PWM1_Duty_merken then if PWM4_Duty<> PWM2_Duty_merken then if PWM4_Duty<> PWM3_Duty_merken then
for Zaehler4= PWM4_Duty to Grundwert4 step -1 pwmduty c.2,PWM4_Duty next Zaehler4
for Zaehler4= Grundwert4 to PWM4_Duty pwmduty c.2,PWM4_Duty next Zaehler4 else goto start3 endif
endif endif endif
goto start3
Es werden 4 unabhängige Zufallszahlen generiert . Die jeweilige Zufallszahl ein jeder LED wird zum einen jeweils mit deren eigenen, vorherigen Wert verglichen, als auch mit den anderen 3 aktuellen LED-Werten , um zu vermeiden das 2 LED' s gleich flackern.
Das ganze läuft im Multitasking-Modus und mit der PWM-Funktion.