Archiv verlassen und diese Seite im Standarddesign anzeigen : Einfache Schreibweise einer 5-Bit Wahrheitstabelle
stardust19322
13.12.2014, 11:26
Hallo BASCOM-Freunde ^^.
Für mein aktuelles Projekt, einer 24-Port RGB-Steuerung mit 2 Mikrocontrollern, wobei ein Controller die RGB-Steuerung UND WEITERE FUNKTIONEN übernimmt, der 2te dann nur für die Steuerung der 24 Ausgangsports zuständig ist. Zwischen beiden Controllern besteht eine permanente 5-Bit-Anbindung (sprich über 5 I/O-Pins), da mit eine Datenbus-Anbindung für diese Zwecke doch etwas aufwändig ist.
Mein Problem dabei ist die Wahrheitstabelle. Momentan ist noch nicht ganz raus, ob ich alle möglichen der 31 Wahrheitszustände auch aufbrauchen werde, aber es ist durchaus real.
Meine Frage nun ist die Folgende:
Gibt es in BASCOM eine (einfache) Möglichkeit, massiv Code einzusparen? Bei 30 geschriebenen Zeilen sind bereits gut 40% des 8KB-Speichers weg, und das ist schlecht. Das Programm selbst für jeden angesteuerten Zustand ist (noch) recht simpel und überschaubar, aber der Controller ist noch zu weitaus mehr fähig, weshalb ich den Platz später gern auch anderweitig nutzen würde.
Der Code zeigt die Wahrheitstabelle... Es müssen dabei immer ALLE Pins benannt sein, auch die inaktiven, damit es zu keinem Logikfehler kommen kann...
If Bit1 = 0 And Bit2 = 0 And Bit3 = 0 And Bit4 = 0 And Bit5 = 1 Then Programmwahl = 1 ' 00001
If Bit1 = 0 And Bit2 = 0 And Bit3 = 0 And Bit4 = 1 And Bit5 = 0 Then Programmwahl = 2 ' 00010
If Bit1 = 0 And Bit2 = 0 And Bit3 = 0 And Bit4 = 1 And Bit5 = 1 Then Programmwahl = 3 ' 00011
If Bit1 = 0 And Bit2 = 0 And Bit3 = 1 And Bit4 = 0 And Bit5 = 0 Then Programmwahl = 4 ' 00100
If Bit1 = 0 And Bit2 = 0 And Bit3 = 1 And Bit4 = 0 And Bit5 = 1 Then Programmwahl = 5 ' 00101
If Bit1 = 0 And Bit2 = 0 And Bit3 = 1 And Bit4 = 1 And Bit5 = 0 Then Programmwahl = 6 ' 00110
If Bit1 = 0 And Bit2 = 0 And Bit3 = 1 And Bit4 = 1 And Bit5 = 1 Then Programmwahl = 7 ' 00111
If Bit1 = 0 And Bit2 = 1 And Bit3 = 0 And Bit4 = 0 And Bit5 = 0 Then Programmwahl = 8 ' 01000
If Bit1 = 0 And Bit2 = 1 And Bit3 = 0 And Bit4 = 0 And Bit5 = 1 Then Programmwahl = 9 ' 01001
If Bit1 = 0 And Bit2 = 1 And Bit3 = 0 And Bit4 = 1 And Bit5 = 0 Then Programmwahl = 10 ' 01010
If Bit1 = 0 And Bit2 = 1 And Bit3 = 0 And Bit4 = 1 And Bit5 = 1 Then Programmwahl = 11 ' 01011
If Bit1 = 0 And Bit2 = 1 And Bit3 = 1 And Bit4 = 0 And Bit5 = 0 Then Programmwahl = 12 ' 01100
If Bit1 = 0 And Bit2 = 1 And Bit3 = 1 And Bit4 = 0 And Bit5 = 1 Then Programmwahl = 13 ' 01101
If Bit1 = 0 And Bit2 = 1 And Bit3 = 1 And Bit4 = 1 And Bit5 = 0 Then Programmwahl = 14 ' 01110
If Bit1 = 0 And Bit2 = 1 And Bit3 = 1 And Bit4 = 1 And Bit5 = 1 Then Programmwahl = 15 ' 01111
If Bit1 = 1 And Bit2 = 0 And Bit3 = 0 And Bit4 = 0 And Bit5 = 0 Then Programmwahl = 16 ' 10000
If Bit1 = 1 And Bit2 = 0 And Bit3 = 0 And Bit4 = 0 And Bit5 = 1 Then Programmwahl = 17 ' 10001
If Bit1 = 1 And Bit2 = 0 And Bit3 = 0 And Bit4 = 1 And Bit5 = 0 Then Programmwahl = 18 ' 10010
If Bit1 = 1 And Bit2 = 0 And Bit3 = 0 And Bit4 = 1 And Bit5 = 1 Then Programmwahl = 19 ' 10011
If Bit1 = 1 And Bit2 = 0 And Bit3 = 1 And Bit4 = 0 And Bit5 = 0 Then Programmwahl = 20 ' 10100
If Bit1 = 1 And Bit2 = 0 And Bit3 = 1 And Bit4 = 0 And Bit5 = 1 Then Programmwahl = 21 ' 10101
If Bit1 = 1 And Bit2 = 0 And Bit3 = 1 And Bit4 = 1 And Bit5 = 0 Then Programmwahl = 22 ' 10110
If Bit1 = 1 And Bit2 = 0 And Bit3 = 1 And Bit4 = 1 And Bit5 = 1 Then Programmwahl = 23 ' 10111
If Bit1 = 1 And Bit2 = 1 And Bit3 = 0 And Bit4 = 0 And Bit5 = 0 Then Programmwahl = 24 ' 11000
If Bit1 = 1 And Bit2 = 1 And Bit3 = 0 And Bit4 = 0 And Bit5 = 1 Then Programmwahl = 25 ' 11001
If Bit1 = 1 And Bit2 = 1 And Bit3 = 0 And Bit4 = 1 And Bit5 = 0 Then Programmwahl = 26 ' 11010
If Bit1 = 1 And Bit2 = 1 And Bit3 = 0 And Bit4 = 1 And Bit5 = 1 Then Programmwahl = 27 ' 11011
If Bit1 = 1 And Bit2 = 1 And Bit3 = 1 And Bit4 = 0 And Bit5 = 0 Then Programmwahl = 28 ' 11100
If Bit1 = 1 And Bit2 = 1 And Bit3 = 1 And Bit4 = 0 And Bit5 = 1 Then Programmwahl = 29 ' 11101
If Bit1 = 1 And Bit2 = 1 And Bit3 = 1 And Bit4 = 1 And Bit5 = 0 Then Programmwahl = 30 ' 11110
Zuletzt noch eine Frage:
Für das Ansteuern einer Ausgangs-Pinbank: Da ich 24 Ausgänge beschalten muss, bedeutet dies immer 3 komplette Pinbänke. Kann ich zum Ansteuern folgende Schreibweise verwenden?:
If Programmwahl = 1 then
Portb = &B10101010 : Portc = &C10101010 : Portd = &D10101010
Habe zu der oberen Schreibweise leider nicht viel gefunden, weshalb ich sicherheitshalber noch einmal nachfrage.
Danke euch.
LG - Maik
Hi,
ich habe jetzt nicht Deine ganze Tabelle durchgesehen, aber der Anfang und Stichproben mittendrin sehen so aus, als könntest Du die Zahl einfach dezimal auswerten. Also wenn in den ersten fünf Bit Deiner Variable zB "00101" steht, dann ist ihr dezimalwert schlicht und einfach 5. Falls Du in Deiner binären Belegung von dem Schema abweichst, wäre es fraglich, ob Du die Belegung nicht dahingehend ändern kannst, dass die dezimale Auswertung möglich ist.
Zu Deiner anderen Frage: was Du schreibst geht im Prinzip, allerdings ist Deine Syntax falsch. Hier
Portb = &B10101010
bedeutet das "&B", dass Du die Zahl binär angibst, und nicht etwa, dass Du Portb meinst. Dementsprechend musst Du auch bei allen anderen binären Zuweisungen "&B" vor der Folge aus Einsen und Nullen verwenden. Dann funktioniert das.
Gruß
Malte
Searcher
13.12.2014, 12:52
Gibt es in BASCOM eine (einfache) Möglichkeit, massiv Code einzusparen?
Ich glaub ich würd es so machen:
$regfile = "ATtiny44.DAT"
$hwstack = 32
$swstack = 32
$framesize = 32
$crystal = 8000000
Dim Bit1 As Bit
Dim Bit2 As Bit
Dim Bit3 As Bit
Dim Bit4 As Bit
Dim Bit5 As Bit
Dim Bit_pattern As Byte
Dim Programmwahl As Byte
Bit_pattern = 0
Bit_pattern.0 = Bit1
Bit_pattern.1 = Bit2
Bit_pattern.2 = Bit3
Bit_pattern.3 = Bit4
Bit_pattern.4 = Bit5
Select Case Bit_pattern
Case &B00001 : Programmwahl = 1 ' 00001
Case &B00010 : Programmwahl = 2 ' 00010
Case &B00011 : Programmwahl = 3 ' 00011
Case &B00100 : Programmwahl = 4 ' 00100
Case &B00101 : Programmwahl = 5 ' 00101
Case &B00110 : Programmwahl = 6 ' 00110
Case &B00111 : Programmwahl = 7 ' 00111
Case &B01000 : Programmwahl = 8 ' 01000
Case &B01001 : Programmwahl = 9 ' 01001
Case &B01010 : Programmwahl = 10 ' 01010
Case &B01011 : Programmwahl = 11 ' 01011
Case &B01100 : Programmwahl = 12 ' 01100
Case &B01101 : Programmwahl = 13 ' 01101
Case &B01110 : Programmwahl = 14 ' 01110
Case &B01111 : Programmwahl = 15 ' 01111
Case &B10000 : Programmwahl = 16 ' 10000
Case &B10001 : Programmwahl = 17 ' 10001
Case &B10010 : Programmwahl = 18 ' 10010
Case &B10011 : Programmwahl = 19 ' 10011
Case &B10100 : Programmwahl = 20 ' 10100
Case &B10101 : Programmwahl = 21 ' 10101
Case &B10110 : Programmwahl = 22 ' 10110
Case &B10111 : Programmwahl = 23 ' 10111
Case &B11000 : Programmwahl = 24 ' 11000
Case &B11001 : Programmwahl = 25 ' 11001
Case &B11010 : Programmwahl = 26 ' 11010
Case &B11011 : Programmwahl = 27 ' 11011
Case &B11100 : Programmwahl = 28 ' 11100
Case &B11101 : Programmwahl = 29 ' 11101
Case &B11110 : Programmwahl = 30 ' 11110
End Select
End 'end program
Spart etwa 2kB und mehr im Romimage.
Oder wenn die Bitx in Bitpattern sind, dann nur "Programmwahl = Bit_pattern" (wahrscheinlich das, was Malty meint).
Gruß
Searcher
Oder wenn die Bitx in Bitpattern sind, dann nur "Programmwahl = Bit_pattern" (wahrscheinlich das, was Malty meint).
So ist's :-) Und wenn die Bitpattern abweichen vom normalen dualen System, dann sollte man das dahingehend abändern (wenn technisch irgend möglich), dass es sich so auswerten lässt. Alle anderen Lösungen sind wirkliche seeehr unelegant und werden mit unnötig großem Code bestraft :-).
Sauerbruch
13.12.2014, 15:53
Welche I/O-Ports werden denn zum "Einlesen" der Programmwahl benutzt?
Wenn es Dir die Hardware erlaubt, hierfür die unteren 5 Bits eines kompletten Ports zu verwenden (also z.B. PINA.4, PINA.3... PINA.0), könntest Du die Variable Programmwahl noch einfacher bekommen:
Programmwahl = PINA 'Übernimmt das komplette Eingangsregister von PortA
Programmwahl = Programmwahl AND &B00011111 'Löscht die Bits 7...5 und lässt die Bits 4...0 unverändert
stardust19322
13.12.2014, 20:57
Hallo Bascom-Freunde und (deutlich) fortgeschrittenere Programmierer als ich ^^.
Ich danke euch vielmals für eure Mühen und Hilfen, insbesondere auch für die Programmbeispiele.
Es werden genau 5 Ports des ersten Controllers an den 2ten übergeben. Die Ports sind fortlaufend von PortA.0 bis PortA.4. Ich verwende einen ATMega8515.
Irgendwann werde ich mich auch an Byte-Übergaben per 1- oder 2-Wire ransetzen, aber soweit bin ich noch lange nicht. Zudem habe ich Platz genug auf dem Bord ^^.
Zunächst @ malthy: Danke dir. Diese Schreibweise habe ich gesucht. Ich habe daheim eines DER (angeblich) besten BASCOM-AVR-Bücher für Einsteiger daheim, aber sowas steht da nicht drin. Da steht so vieles nicht drin, leider, ist hier aber nicht Thema.
@ Sauerbruch und @ Searcher: Das mit dem "Bit_Pattern" habe ich noch nicht so ganz verstanden. Bit_Pattern ist eine als Byte definierte Variable, hat aber dennoch Aus- oder Eingangs-Nummerierungen. Wie funktioniert das und was bewirkt es genau?
Sauerbruch - korrekt. Wie oben bereits geschrieben, gibt es nur Pin 0 bis 4 der Portbank A. Soweit habe ich verstanden, dass ich die einzelnen Portpins ja ein- und abschalten kann, würde mit DDRA = &B00011111 ja auch gehen, korrekt?
Was ich jedoch nicht verstehe, ist "Programmwahl = PINA" - wird Die Pinbank A damit zur Variable "Programmwahl"?
Was bewirkt die 2te Zeile im Detail, außer dass damit die einzelnen Pins gesetzt werden?
Muss ich den Kopf der Anweisungsliste genauso schreiben wie Searcher es schrieb, auch wenn ich nur 5 feste Pin-High/Low-Zustände abfrage?
Soweit bin ich leider mit den Kurzschreibweisen noch nicht.
LG - Maik
Sauerbruch
13.12.2014, 21:56
Das mit dem "Bit_Pattern" habe ich noch nicht so ganz verstanden. Bit_Pattern ist eine als Byte definierte Variable, hat aber dennoch Aus- oder Eingangs-Nummerierungen. Wie funktioniert das und was bewirkt es genau?
Korrekt - Programmwahl ist eine Byte-Variable, die demzufolge aus 8 einzelnen Bits besteht: Programmwahl.7, Programmwahl.6, Programmwahl.5.... usw.
Bei Bascom kann man jedes einzelne Bit eines Bytes nach diesem Muster setzen, löschen, abfragen etc., etc.
Soweit habe ich verstanden, dass ich die einzelnen Portpins ja ein- und abschalten kann, würde mit DDRA = &B00011111 ja auch gehen, korrekt?
Das ist nicht ganz korrekt. Das DDR-Register legt fest ob ein Anschluss als Ausgang (d.h. führt "aktive" Pegel High oder Low) oder als Eingang (führt keinen eigenen Pegel) konfiguriert ist. Beim Einschalten des Controllers sind alle I/O-Ports erstmal als Eingänge konfiguriert, da sie so keinen Schaden anrichten können.
Ist ein Anschluss als Eingang konfiguriert, ist der logische Pegel, der an diesem Eingang anliegt, im entsprechenden PIN-Register.
Legst Du also z.B. den als Eingang konfigurierten Anschluss B.2 auf +5V, ist das Bit PINB.2 "1". Liegt der Anschluss auf Masse, wird PINB.2 = 0.
Wenn ein Anschluss aber als Ausgang definiert ist, muss ja irgendwo festgelegt werden, ob dieser Ausgang ein High oder ein Low führen soll - und genau das macht das PORT-Register. Willst Du z.B. C.3 als Ausgang haben und mit einem High-Pegel eine LED leuchten lassen, müsstest Du folgendes schreiben:
DDRC.3=1
PORTC.3 = 1
Das PORT-Register hat aber noch eine wichtige Aufgabe, und zwar dann, wenn der Anschluss als Eingang konfiguriert ist:
Dadurch dass die Eingänge sehr hochohmig sind (mehrere 100 MOhm) fangen sie jede Menge Störstrahlungen ein, wenn sie frei in der Luft hängen. Wenn Du also z.B. einen Eingang mit einem Taster auf +5V legst, wird er bei gedrücktem Taster zwar eine saubere "1" sehen. Bei offenem Taster befindet er sich aber in einem vollkommen undefinierten Zustand; oft führt 50Hz-Einstrahlung dazu, dass sich der logische Pegel ständig ändert. Eingänge dürfen also nie frei in der Luft hängen, sondern sollten über einen hochohmigen Widerstand (z.B. 50kOhm) auf +5V oder Masse gelegt werden. Liegt der Eingang z.B. auf +5V, kann man ihn über einen Taster trotzdem problemlos auf 0V ziehen, ohne dass ein nennenswerter Strom fließt - ist der Taster offen, liegt am Eingang ein sauberes "High" an.
Solche Widerstände nennt man PullUp- (oder PullDown-) Widerstände, und die Controller haben sie schon eingebaut! Sie werden allerdings nur dann aktiv, wenn im dazugehörigen PORT-Register eine 1 steht.
Also nochmal zusammengefasst:
DDRDX.Y legt fest, ob der Anschluss X.Y ein Eingang oder Ausgang sein soll.
Ist er ein Ausgang, legt PORTX.Y fest, ob der Ausgang eine 1 oder eine 0 führt.
Ist er ein Eingang, kann man an PINX.Y sehen, ob an diesem Eingang eine 1 oder 0 anliegt.
Und ist er ein Eingang, kann man mit PORTX.Y = 1 den PullUp-Widerstand aktivieren, der den Eingang auf ein sauberes High zieht.
Ich habe daheim eines DER (angeblich) besten BASCOM (http://www.rn-wissen.de/index.php/Bascom)-AVR (http://www.rn-wissen.de/index.php/AVR-Einstieg_leicht_gemacht)-Bücher (http://www.amazon.de/s?ie=UTF8&ref_=nb_sb_noss&field-keywords=avr&url=search-alias%3Daps&_encoding=UTF8&site-redirect=de&tag=xls-21&linkCode=ur2&camp=1638&creative=19454)für Einsteiger daheim, aber sowas steht da nicht drin.
Ich habe auch einen Haufen BASCOM-Bücher gekauft - aber zum ersten mal verstanden habe ich es mit dem Buch von Roland Walter :-)
peterfido
13.12.2014, 22:02
DDR gibt die Datenrichtung vor. DDRA dann für Port A. Eine 1 ist gleich Ausgang und eine 0 gleich Eingang.
Du kannst mit X=PINA den Zustand eines gesamten Ports gleich der Variable X zuweisen. Ungenutzte PINs liegen in der Luft und können (machen sie auch...) mal eine 1 und mal eine 0 annehmen. Daher die UND Verknüpfung. X=X AND &B00011111. So wird sichergestellt, dass die oberen 3 Bits nicht gesetzt sind. Sonst könnten unerwartete / ungewollte Werte auftreten.
Den "Kopf" von Searcher brauchst Du dann nicht übernehmen. Ein Byte besteht aus 8 Bits. Wird X (oder z.B. Programmwahl) als Byte deklariert, dann hat es automatisch 8 Bits. Ein Port hat auch (bis zu) 8 Bits. Weniger evtl. bei kleineren Atmels oder wo die PINs eine alternative bieten, wie z.B. Anschlüsse für den Quarz. Das trifft bei den DIL 40 Atmels, wie in Deinem Fall hier, nicht zu. Also nicht verwirren lassen. Liest Du als den Port ein, werden alle 8 PINs in ein Byte gelesen und dessen Wert X zugewiesen.
stardust19322
13.12.2014, 22:33
Hi Sauerbruch.
Und noch einmal muss ich mir bei dir herzlichst bedanken. Deine Hilfe weiß ich wirklich extrem zu schätzen - wirklich zu schätzen. Mit Hilfe deiner Erläuterungen habe ich mehr verstanden als gedacht ^^.
Das mit den PullUp-Widerständen hatte mir vor 4 Monaten bereits ein guter Freund erklärt. Anfänglich hatte ich Pull-Down-Widerstände per Hardware gesetzt, was sich bei einem PWM-Eingangssignal nicht negativ auswirkt. Bei meinen letzten Projekten jedoch, u.A. einer Taster-gesteuerten Hardware, gab es jedoch extreme Probleme, weshalb ich die Eingänge mit PullUp's gegen VDD ziehen musste.
Die internen PullUp's setze ich mittlerweile eigentlich nie, sondern verwende Hardware-Widerstände mit 4,7K, welche ich gegen +5V parallel zum Taster schalte. Zwar habe ich keine Taster am ATMega8515, sollte aber trotzdem funktionieren ^^.
Das ist der letzte Versuch, den ich ich mit einem Buch starte, der absolut letzte. Das Buch von Roland Walter scheint genau das zu sein, was ich suche: Es wird ausschließlich BASCOM beschrieben und alles am Beispiel eines ATMega8. Mehr braucht es im Grunde nicht, denke ich. Und da es sich um ein Schul-Lehrbuch handelt, sollte alles gut und verständlich abgehandelt sein/werden.
Ich denke, dass ich heute nichts mehr am Programm schreibe, dafür aber sicher morgen noch. Wenigstens die Eingänge möchte ich so konfigurieren und die entsprechenden Konfigs mit einem einfachen Testprogramm ausprobieren. Nächste Woche habe ich aber wieder weitaus mehr Zeit dafür, sowohl zwischen Weihnachten und Neujahr.
Und damit du siehst, dass ich u.A. mit eurer Hilfe auch durchaus praktische Anwendungen umsetze - hier ein kleines Demo-Video von mir ^^. Der in der Steuerung verwendete ATMega8 wird auch in der 24-Port-Steuerung verwendet, muss jedoch noch zusätzlich ein Display und den ATMega8515 ansteuern. Krieg ich hin ^^.
http://www.youtube.com/watch?v=orn2SIB0j0g&list=UUuYiOBFnB_xx1HCLFRTfjHw
Danke dir.
LG - Maik
Sauerbruch
14.12.2014, 10:04
Hey, das Projekt ist ja schon ganz schön weit fortgeschritten - und die Plexiglas-Gehäuse sind wirklich sehr edel!!
Anfänglich hatte ich Pull-Down-Widerstände per Hardware gesetzt, was sich bei einem PWM-Eingangssignal nicht negativ auswirkt.
Klar wirkt sich hier ein PullUp-Widerstand nicht negativ aus - aber in diesem Fall brauchst Du ihn gar nicht: Der Eingang ist ja mit einem Ausgang verbunden (dem PWM-Signal), und dieser Ausgang liefert ja ganz zuverlässige High- und Low-Pegel! Den Widerstand brauchst Du nur, wenn der Eingang über einen Taster (oder Schalter) angesteuert wird, damit ein definierter Pegel hergestellt wird, wenn das Bauteil geöffnet ist. Aber wenn der Eingang an irgendeiner "aktiven" Quelle hängt (kann auch der Ausgang eines CMOS-Gatters, eine Transistorschaltstufe oder sonstwas sein), ist er überflüssig.
Die internen PullUp's setze ich mittlerweile eigentlich nie, sondern verwende Hardware-Widerstände mit 4,7K, welche ich gegen +5V parallel zum Taster schalte.
Das heißt, sowohl der PullUp als auch der Taster geht nach +5V? Das würde keinen Sinn machen, denn dann ist der Eingang immer auf High!!
Wenn Du gerne lötest, sind Hardware-PullUps eine feine Sache... aber bei geschätzt einigen hundert Millionen Anwendungen funktionieren die internen Widerstände ganz ausgezeichnet :-)
stardust19322
14.12.2014, 14:12
Hallo Sauerbruch und
lieben vielen Dank für das Lob :roll:. Weiß ich zu schätzen ^^
Ok. Also wenn ich in Zukunft wieder einmal einen Controller mit einem anderen verbinde, brauchen die Eingänge des Slave keinen PullUp-Widerstand. Sehr gut - spart ein wenig Ressourcen ^^.
Nein, das habe ich vermutlich falsch ausgedrückt. Die Eingänge sind mit PullUp-Widerständen versehen, korrekt. Die Taster hingegen sind gegen 0V geschaltet, ziehen den Eingang also bei Betätigung gegen 0V. Wenn ich das noch recht in Erinnerung habe, bricht durch diese Art "Kurzschluss" nach dem PullUp-Widerstand der anliegende (sehr kleine) Strom am Eingangsport zusammen und fällt unter 1V - ein Low-Signal :rolleyes:
Bei meinen ersten Versuchen, auf ein High-Signal als Eingangssignal zu setzen, was katastrophal. Der Controller machte, was er wollte, nur nicht das, was er sollte ^^.
Kann ich die internen PullUp-Widerstände eigentlich auch mit dem Befehl "PortX = &HFF" setzen?
Ich habe da noch eine Frage zu deinem Beispiel in Antwort #5:
Programmwahl = PINA 'Übernimmt das komplette Eingangsregister von PortA
Programmwahl = Programmwahl AND &B00011111 'Löscht die Bits 7...5 und lässt die Bits 4...0 unverändert
In dem für mich verständlichen Programmierdeutsch ^^ würde das jetzt so aussehen:
Programmwahl = PINA ' Hier werden alle Pins mit der Variable "Programmwahl" definiert (benannt)
Programmwahl = Programmwahl AND &B00011111 ' Die ersten 3 Bits sind gelöscht oder Ausgänge, während die letzten 5 als Eingänge anwählbar sind
PinA = &HFF ' Würde die internen PullUp-Widerstände aktivieren, alternative Schreibweise wäre "PinA = 1"???
DIM Programm as Byte
Dim Programmwahl as Byte ' Kann ich diese Variablendeklaration auch weglassen???
Do
Select Case Programmwahl
Case &B00001 : Programm = 1
Case &B00010 : Programm = 2
Case &B00011 : Programm = 3
Case &B00100 : Programm = 4
etc.pp
Abgesehen vom Header wäre das dann auch schon das gesamte Einlese-Prozedere?
LG - Maik
- - - Aktualisiert - - -
Nachtrag: Das, was du da im Video siehst, ist die erste RGB-Steuerung, die ich selbst aufgebaut habe. Das Gehäuse aus qualitativ hochwertigsten Acyralglas (kratzfester als das überteuerte Bastlerglas aus dem Baumarkt - und günstiger noch dazu ^^) baue ich ebenfalls selbst. Da ist nix CNC oder mit Präzisionsmaschinen gemacht. Eine Dekupiersäge, eine Ständerbohrmaschine (mit der ich auch "fräse" sowie eine Bügel-Laubsäge mit 360°-Sägeblatt ^^.
Habe aber leider bei dieser Steuerung vergessen, die Kabelfernbedienung mit einem Stecker zu versehen. Das Kabel hat zwar einen Stecker, jedoch wird der fix auf die Mitte der Platine gesteckt. Für mich daheim aber vollkommen ausreichend ^^.
LG _ Maik
Sauerbruch
14.12.2014, 15:31
Nein, die beiden Codezeilen sind etwas anders zu verstehen.
Wenn Du in Bascom X = A schreibst, bezeichnet "X" eine Variable um die es geht, und "A" den Wert, den sie haben soll. Konkret also z.B.
Dim Zähler as Byte
Zähler = 20
Zähler = Zähler + 1
(Zähler hätte am Schluss den Wert 21.)
Da ein Byte 8 Bits hat, könnte man statt der 20 auch den Binärwert schreiben:
Zähler = &b00010100
Oder Hexadezimal:
Zähler = &h14
Du kannst einer Variablen aber nicht nur einen numerischen Wert (also eine Zahl) zuweisen, sondern auch gleich direkt den Inhalt eines Registers:
Dim Programmwahl as byte
Programmwahl = PINA
Damit nimmt die Variable Programmwahl den Wert an, der gerade im 8-bit-Register PINA steht.
Zur Erinnerung: Im Register PINA steht das Muster aus Einsen und Nullen, das an den Anschlüssen A.7 bis A.0 anliegt (vorausgesetzt sie sind per DDR-Register als Eingänge konfiguriert). Diesem Register kannst Du also nicht auf Befehlsebene einen Wert zuweisen, sondern sein Inhalt hängt ausschließlich von den Highs und Lows an den Anschlüssen ab. PINA = XYZ macht also keinen Sinn - man kann dieses Register nur auslesen, d.h. XYZ = PINA.
Liegt also z.B. an den Anschlüssen A.4, A.2 und A.0 ein High (und an den anderen ein Low), stünde im Register PINA der Wert &b00010101. Mit dem Befehl Programmwahl = PINA übernimmst Du also das "Muster" aus Highs und Lows aus dem Register PINA direkt in Deine Variable Programmwahl. Klar?
Jetzt könnte es ja aber sein, dass Du die Anschlüsse A.7, A.6 und A.5 für was ganz anderes brauchst - zu den Bits, die die Programmwahl steuern, gehören sie ja definitiv nicht. Du kannst aber nur das ganze Register PINA auf die Variable Programmwahl übertragen. Wenn also nur die Bits Programmwahl.4 bis Programmwahl.0 ausgewertet werden sollen, musst Du gegebenenfalls die höchsten 3 Bits der Variable Programmwahl auf 0 setzen. Das geht entweder einzeln:
Programmwahl.7 = 0
Programmwahl.6 = 0
Programmwahl.5 = 0
oder eben am Stück, indem Du die oberen 3 Bits mit einer 0 Und-verknüpfst (das Ergebnis einer UND-Verknüpfung mit 0 ist immer 0), und die unteren 5 Bits mit einer 1 UND-Verknüpfst (das Ergebnis ist immer die Ausgangsvariable selbst: 0 UND 1 = 0, 1 UND 1 = 1).
Kurz und gut: Programmwahl = Programmwahl AND &b00011111 setzt die obersten 3 Bits der Variable auf 0, egal was vorher drin gewesen war, während die unteren 5 Bits unverändert bleiben.
Searcher
14.12.2014, 18:19
Abgesehen vom Header wäre das dann auch schon das gesamte Einlese-Prozedere?
Eigentlich ja. Ich habe noch die blau gefärbten Kommentare eingefügt, die meiner Meinung nach besser passen. Für aktive Pullupwiderstände muß der Portpin als Eingang konfiguriert sein und im PORT Register das entsprechende Bit auf 1 gesetzt werden.
Programmwahl = PINA 'Hier werden alle Pins mit der Variable "Programmwahl" definiert (benannt)
'Hier wird der Zustand aller Pins von PortA in die Variable Programmwahl übertragen.
Programmwahl = Programmwahl AND &B00011111 'Die ersten 3 Bits sind gelöscht oder Ausgänge, während die letzten 5 als Eingänge anwählbar sind
'Die ersten 3, nicht zu beachtenden Bits werden auf 0 gesetzt.
PinA = &HFF 'Würde die internen PullUp-Widerstände aktivieren, alternative Schreibweise wäre "PinA = 1"???
PortA = &HFF 'Würde die internen PullUp-Widerstände aktivieren, alternative Schreibweise wäre "PortA.0 = 1 , PortA.1 = 1, ...
DIM Programm as Byte
Dim Programmwahl as Byte 'Kann ich diese Variablendeklaration auch weglassen???
'Nein. Wird dir der Compiler aber schon melden. Ist kein in Bascom vordefinierter String sondern eine Anwendervariable und muß vor erster Verwendung deklariert sein.
Do
Select Case Programmwahl
Case &B00001 : Programm = 1 'Hier könnten jetzt schon Aufrufe von Unterprogrammen stehen. Das was "Programm" zugewiesen wird steht ja schon in "Programmwahl".
Case &B00010 : Programm = 2
Case &B00011 : Programm = 3
Case &B00100 : Programm = 4
etc.pp
Gruß
Searcher
stardust19322
14.12.2014, 20:03
Aaaah - jetzt hats Klick gemacht. Daaaaanke seeehr. Bin dir ein Bier schuldig ^^.
Mit Pin und Port hatte ich schon immer meine ganz kleinen schwierigkeiten, sobald ich aber direkt im Programm stecke, ist das weg. Weiß auch nicht - vermutlich der Unterschied zwischen Theorie und Praxisnähe, was im Kopf nen Schalter umlegt.
Klar, kein Thema. Es war nur ein Beispiel, nach jedem Case in der Select eine Variable zu definieren. Im späteren Programm rufe ich hingegen gleich die anschließend fertig geschriebenen Unterprogramme auf, mit "Call XYZ", also "Case &B00000101 : Call Sub Muster_5" ...und die dazu passende Call ^^.
Bislang bin ich nun gewappnet. Morgen muss ich wieder auf Montage, da habe ich dann abends Zeit zum Programmieren, wenn ich das nicht verschwitze. Ein Regal mit 24 Fächern soll in unterschiedlichen Modulen leuchten - habe dazu eigens ein 12V_10A Vorschaltgerät gekauft. Dauert aber halt noch etwas.
Vorteil: Das Programm auf dem ATMega8, welches die Farben ansteuert, ist im Großen und Ganzen schon fertig. Allerdings will ich noch ein Display und Cursortaster einbinden, plus eben die Auswahlmöglichkeit der unterschiedlichen Module.
Die Haupt-Steuerplatine für die ersten 12 Ports schaut dann so aus:
29501
Zur Erläuterung: Die Pinbank rechts neben dem ATMega8 hat oben 4 Taster als Eingang, darunter Spannungsversorgung und Display-Ansteuerung.
Die Ausgänge des ATMega8 sind an den Hardware-PWM-Registern angeschlossen, OC1A, OC1B und OC2. Sie steuern die Farben und das Fading.
Die untersten Transistoren schalten die Spannungsversorgung und werden durch den ATMega8515 angesteuert.
Die Pinbänke links werden anschließend zur 2ten Platine gelegt, welche die letzten 12 Ports beinhaltet.
Finde das echt klasse und ärgere mich tierisch, dass ich das nicht schon viel früher mit dem Programmieren begonnen habe...
LG - Maik
stardust19322
15.12.2014, 21:48
Hallo.
@ Searcher: Das, was du als Beispiel geschrieben hast, funktioniert leider nicht. Die Eingangsports können nicht an eine Variable übergeben werden. Wenn ich die Variable entsprechend als Byte deklariere und dem Port mit "Programm = PINA" zuweise, kann ich machen was ich will - das Register reagiert nicht auf Tastenbefehle.
Schreibe ich allerdings z.B. "If PinA.0 = 0 then ...etc.pp", dann klappt alles.
Denke, dass ich die Wahrheitstabelle vielleicht so aufbaue, mit direktem Portzugriff.
Da ich keine weiteren Ports benötige, sollte das funktionieren, denke ich.
Mal probieren.
LG - Maik
Sauerbruch
15.12.2014, 22:00
@ Searcher: Das, was du als Beispiel geschrieben hast, funktioniert leider nicht. Die Eingangsports können nicht an eine Variable übergeben werden. Wenn ich die Variable entsprechend als Byte deklariere und dem Port mit "Programm = PINA" zuweise, kann ich machen was ich will - das Register reagiert nicht auf Tastenbefehle.
Also bei mir hat sich dieses Vorgehen sehr bewährt, und wenn die einzelnen Bits im Register PINA offensichtlich die Pegel auf den Leitungen korrekt darstellen, muss der Fehler wo anders liegen. Was hast Du denn Hardware-seitig mit den Anschlüssen A.7 bis A.5 gemacht?
Sehr hilfreich wäre es, wenn Du uns Deinen Code mal zeigen könntest. Mit so ´ner quadratmetergroßen Wahrheitstabelle statt einer einzigen (korrekten!!) Befehlszeile wirst Du doch ramdösig, oder???
stardust19322
16.12.2014, 00:23
Und wie ich das werden würde... ^^
Hallo Sauerbruch.
Die Wahrheitstabelle habe ich jetzt im Ganzen umgesetzt. Dabei sind alle Eingangspins benannt. Die internen PullUp's sind gesetzt, wodurch ich die nicht angeschlossenen Pins im Grunde auch in der Luft hängen lassen könnte - oder was meinst/denkst du? Würde dies vielleicht zu Fehlfunktionen führen?
Der Code sieht bislang so aus (nach meinem letzten Post geschrieben):
$regfile = "m8515.dat"
$crystal = 8000000
$hwstack = 40
$swstack = 16
$framesize = 32
'-------------------------------------------------------------------------------
' *** Konfiguriere Ein- und Ausgangsports ***
Config Porta = Input
Config Portb = Output
Config Portc = Output
Config Portd = Output
Porta = &HFF ' Aktiviert die internen Pullup-Widerstände
Portb = &HFF ' schaltet alle Ausgänge 1, LED = 0
Portc = &HFF
Portd = &HFF
'-------------------------------------------------------------------------------
' *** Konfiguriere Timer ***
Config Timer0 = Timer , Prescale = 1024
On Timer0 Isr_timer0
Enable Timer0
Timer0 = 177
Enable Interrupts
'-------------------------------------------------------------------------------
' *** Deklarieren der Variablen ***
Dim Timercounter As Byte
'-------------------------------------------------------------------------------
' *** Deklarieren der Subroutinen ***
Declare Sub All_off
Declare Sub All_on
Declare Sub Horizontal_lines
Declare Sub Vertical_lines
Declare Sub Straight
Declare Sub Diagonal_falling
Declare Sub Diagonal_rising
Declare Sub Net
Declare Sub Net_invert
Declare Sub Arrow_up
Declare Sub Moving_net
'-------------------------------------------------------------------------------
' ===============================
' ***** Hauptprogramm *****
' ===================================
Do
Select Case Pina
Case &B11111111 : Call All_off ' 00000
Case &B11111110 : Call All_on ' 00001
Case &B11111101 : Call Horizontal_lines ' 00010
Case &B11111100 : Call Vertical_lines ' 00011
Case &B11111011 : Call Straight ' 00100
Case &B11111010 : Call Diagonal_falling ' 00101
Case &B11111001 : Call Diagonal_rising ' 00110
Case &B11111000 : Call Net ' 00111
Case &B11110111 : Call Net_invert ' 01000
Case &B11110110 : Call Arrow_up ' 01001
Case &B11110101 : Call Moving_net ' 01010
End Select
Loop
'-------------------------------------------------------------------------------
' *** ISR für Timer erzeugen - Overflow-Counter in Warteposition bringen ***
Isr_timer0:
Timer0 = 177
Incr Timercounter
' ### Gestartet wird der Timer im jeweiligen Unterprogramm.
' Eingestellt ist der Timer auf 0,01s. ###
'-------------------------------------------------------------------------------
' ====================================
' **** Unterprogramme ****
' ================================
Sub All_off: ' 00000
Portd = &B11111111
Portc = &B11111111
Portb = &B11111111
Stop Timer0
Timer0 = 177
End Sub All_off
Sub All_on: ' 00001
Portd = &B00000000
Portc = &B00000000
Portb = &B00000000
End Sub All_on
Sub Horizontal_lines: ' 00010
Portd = &B10101010
Portb = &B10101010
Portc = &B10101010
End Sub Horizontal_lines
Sub Vertical_lines: ' 00011
Portd = &B00000000
Portc = &B11111111
Portb = &B00000000
End Sub Vertical_lines
Sub Straight: ' 00100
Portd = &B11111111
Portc = &B00000000
Portb = &B11111111
End Sub Straight
Sub Diagonal_falling : ' 00101
Portd = &B00100100
Portc = &B01001001
Portb = &B10010010
End Sub Diagonal_falling
Sub Diagonal_rising: ' 00110
Portd = &B10010010
Portc = &B01001001
Portb = &B00100100
End Sub Diagonal_rising
Sub Net: ' 00111
Portd = &B10101010
Portc = &B01010101
Portb = &B10101010
End Sub Net
Sub Net_invert: ' 01000
Portd = &B01010101
Portc = &B10101010
Portb = &B01010101
End Sub Net_invert
Sub Arrow_up: ' 01001
Portd = &B11011101
Portc = &B10111011
Portb = &B11011101
End Sub Arrow_up
Sub Moving_net ' 01010
Start Timer0
If Timercounter = 1 Then
Portd = &B10101010
Portc = &B01010101
Portb = &B10101010
Elseif Timercounter = 120 Then
Portd = &B01010101
Portc = &B10101010
Portb = &B01010101
Elseif Timercounter = 240 Then
Timercounter = 0
End If
End Sub Moving_net
Erläuterungen zu den einzelnen Modulen habe ich nicht mehr beigefügt. Bei Interesse kann man sich das Ergebnis im Code der einzelnen Ports anschauen. Quasi stellen die 3 Ports das Regal dar, welches eigentlich nur nach links gekippt wurde ^^.
Beim letzten Modul mit dem Timer habe ich derzeit noch ein kleines Konflikt-Problem: Die LED leuchten nicht konstant, sondern nur ganz kurz auf, erlöschen sofort wieder und mit dem nächsten Takt erleuchtet die andere LED-Reihe nur ganz kurz - usw.ff. Denke, dass es mit der Ausschalt-Logik zusammenhängt, die ich schreiben musste, wenn kein Eingangsport ein Low-Signal führt. Dann muss die Steuerung nämlich auch alle Ports auf High schalten.
Konfiguriert ist die Steuerung derzeit noch für mein Testboard, das STK-500. Für den Controller selbst muss ich es später komplett invertieren.
LG - Maik
Searcher
16.12.2014, 07:58
Hallo,
@ Searcher: Das, was du als Beispiel geschrieben hast, funktioniert leider nicht.
Auf welches Codestück beziehst Du Dich da?
Ich habe Dein letztes Programm von hier gesehen:
Der Code sieht bislang so aus (nach meinem letzten Post geschrieben):
Dort fehlt noch ein Return in der ISR. Aber funktioniert das oder nicht?
Es sollte funktionieren, es sei den die höherwertigen Bits (Bit 5, 6, 7) sind nicht 1. Dadurch, daß in deinem letzten Programm die Pullups eingeschaltet sind, sollten diese Bits auf 1 stehen, so wie Du sie auch im Select-Case abfragst.
Die Leitungen (PA5, PA6, PA7) brauchen/sollten nicht angeschlossen werden, da sie durch die Pullups auf definiertem Pegel liegen. Es schadet auch nichts, sie durch eine extra Variable auf 0 zu setzen wie hier:
Programmwahl = PINA
Programmwahl = Programmwahl AND &B00011111 '(natürlich bei Case berücksichtigen)
Sollen die auf 1 gesetzt werden geht es mit der ODER Verknüfung:
Programmwahl = Programmwahl OR &B11100000
Bitte poste beides, das was geht und das was nicht geht.
Die Eingangsports können nicht an eine Variable übergeben werden.
Das was passieren soll ist, daß der Wert aus Register PINA in die Bytevariable übertragen werden. Das mußßß gehen. :)
Wenn ich die Variable entsprechend als Byte deklariere und dem Port mit "Programm = PINA" zuweise, kann ich machen was ich will - das Register reagiert nicht auf Tastenbefehle. Schreibe ich allerdings z.B. "If PinA.0 = 0 then ...etc.pp", dann klappt alles.
Wie schon gesagt, bitte poste beide Varianten, die funktionierende und die nicht funktionierende.
Gruß
Searcher
Sauerbruch
16.12.2014, 09:19
@ Searcher: Die Eingänge A.7 bis A.5 scheinen korrekt "versorgt" zu sein: Die PullUps sind aktiviert, und in der Case-select-Abfrage beginnt jeder Case mit &b111... . Da sehe ich im Moment jedenfalls keinen Fehler.
@ Maik:
In solchen Fällen finde ich es immer hilfreich, das Programm in kleine Abschnitte zu "zerlegen" und diese einzeln zu überprüfen.
Du könntest z.B. "simulieren", dass die Daten korrekt aus dem PINA-Register übernommen werden, indem Du eine neue Byte-Variable einrichtest, diese alle 3 Sekunden von &b11111111 (=255) auf &b11110101 (=245) runterzählen lässt, und mit dieser Variable die Case-Select Überprüfung durchführst. Wenn sich dann alle 3 Sekunden das Lichtprogramm ändert, müssen wir tatsächlich nochmal irgendwo beim PINA-Register suchen. Praktisch würde ich das so machen:
Dim Zähler as Byte
Zähler = 255
...
do
Select Case Zähler
Case &b11111111: Call All_off
Case &b11111110: Call All_on
.....
.....
Case &b11110101: Cal Moving_net
End select
Wait 3 'das aktuelle Unterprogramm wird 3 Sek. ausgeführt
If Zähler = 245 then Zähler = 255 else Zähler = Zähler - 1 'Sorgt dafür, dass Zähler immer zwischen 255 und 245 durchläuft
Loop
(Subroutinen)
..
..
Dass man den Inhalt des PINA-Registers definitiv in eine Variable übernehmen kann (wie Searcher ja auch schon sagte!), steht außer Frage. Allerdings könnte ich mir vorstellen, dass so ein "komplexer" Befehl wie Case Select mit einem Register nicht funktioniert. Von daher wäre dann mein nächster Vorschlag, tatsächlich mit einer Variablen zu arbeiten:
Dim Zähler as Byte
..
Do
Zähler = PINA
Select Case Zähler
Case &b11111111: Call All_off
Case &b11111110: Call All_on
.....
.....
Case &b11110101: Cal Moving_net
End select
..
..
Wenn´s dann immer noch nicht geht, müsste man das Register PINA mal genauer unter die Lupe nehmen. Aber probier´ die beiden Sachen doch mal aus!
stardust19322
16.12.2014, 18:55
Hallo Freunde.
Wirklich keine Ahnung, woran es lag, aber jetzt plötzlich funktioniert die Variablendeklaration eines Ports. Hier der funktionsfähige Code eines Testprogramms:
$regfile = "m8515.dat"
$crystal = 8000000
$hwstack = 40
$swstack = 16
$framesize = 32
'-------------------------------------------------------------------------------
' *** Konfiguriere Ein- und Ausgangsports ***
Config Porta = Input
Config Portb = Output
Porta = &HFF ' Aktiviert die internen Pullup-Widerstände
Portb = &HFF ' schaltet alle Ausgänge 1, LED = 0
Portc = &HFF
Portd = &HFF
'-------------------------------------------------------------------------------
' *** Deklarieren der Variablen ***
Dim Zaehler As Byte
'-------------------------------------------------------------------------------
' *** Deklarieren der Subroutinen ***
Declare Sub Test_1
Declare Sub Test_2
'-------------------------------------------------------------------------------
' ===============================
' ***** Hauptprogramm *****
' ===================================
Do
Zaehler = Pina
Select Case Zaehler
Case &B11111110 : Call Test_1
Case &B11111101 : Call Test_2
End Select
Loop
Sub Test_1:
Toggle Portb.2
Waitms 200
End Sub Test_1
Sub Test_2:
Toggle Portb.4
Waitms 200
End Sub Test_2
End
Es funktioniert sogar so gut, dass ich nun auch vermutlich den vermeintlichen "Fehler" bei der Timer-Steuerung gefunden habe. Das Programm läuft ja immer wieder ab, solange die Bedingung an den Eingängen TRUE ist. Bei älteren, ersten Programmversuchen hatte ich immer das Problem, dass das Programm nur solange lief, wie die ISR bestand. Am Ende der ISR wurde die Bedingung aber nicht erneut geprüft, sondern das Programm hielt einfach an. Dadurch musste ich While-Wend-Schleifen einbauen, um damit das Programm die ISR immer wieder durchlief.
Eröffnet mir nun viele neue Möglichkeiten. Wenn ich Probleme dabei habe, melde ich mich sofort wieder.
Danke euch beiden.
LG - Maik
Searcher
16.12.2014, 19:47
Das mußßß gehen. :)
Wirklich keine Ahnung, woran es lag, aber jetzt plötzlich funktioniert ... Es funktioniert sogar so gut, dass ich nun auch ...
Astrein !!! Manchmal braucht es eben auch etwas Druck :lol: (Nebenbei bemerkt würd ich es jetzt auch etwas anders machen als bei meinem ersten Vorschlag. @Sauerbruch ;) )
Viel Spaß und Erfolg
Gruß
Searcher
Sauerbruch
16.12.2014, 19:47
Wirklich keine Ahnung, woran es lag,
Ich schon: Ich denke, dass mit Registerinhalten keine größeren Rechenoperationen durchgeführt werden können. Und erst recht nicht, wenn sich der Inhalt des Registers schnell mal ändern kann (wie PINA). Deshalb ist es im Zweifelsfall immer sicherer, den Registerinhalt in eine Variable zu übernehmen, und dann mit dieser Variablen weiterzuspielen. Vielleicht gibt es hier ja irgendwelche Freaks, die diese Vermutung bestätigen (und vielleicht sogar erklären!) können...
Viel Spaß beim Weitermachen :-)
stardust19322
17.12.2014, 01:18
Hallöle Allerseits ^^.
Das eine Problem war nun gebannt und kam auch nicht wieder, dafür ein Anderes. Ich kann es aber auch nur beschreiben, und zwar wie folgt:
Zum Auf- und Abdimmen einer bzw. mehrerer LED habe ich den Timer0 mit einem Prescaler von 64 versehen (8MHz Systemtakt) und anschließend den Timer0 immer auf 249 vorgeladen. Es klingt vielleicht ein wenig umständlich, dass ich den Timer mit NUR 6 Takten betreibe, aber so ist das LED-Fading einfach viel besser einstellbar als mit einem Prescaler von 8 und Vorladen um die 170.
Wie dem auch sei - ihr seht im ersten Programmabschnitt den ersten Case, in welchem bei [alle Eingangsbits = 1] alle Ausgangsregister auf 1 gesetzt werden, also alle LED = Off.
In einer speziellen Sub (standardgemäß über den CASE selektiert) wurde nun der Timer aufgerufen und sollte die Ausgänge mit einer LED-PWM auf- und abdimmen.
Und was geschah? NICHTS!
Also habe ich ein Testprogramm auf einer neuen Seite geschrieben, in welchem der lediglich 2 Test-CASE vorkamen - die LED fadete so, wie sie sollte.
Also wieder zurück ins Hauptprogramm und - funktioniert noch immer nicht.
Also habe ich den Übetäter kurz deaktiviert (den ersten Case mit dem " ' " in Schrift gewandelt) und - fadet noch immer nicht.
Nach gut einer Stunde Suchen habe ich dann alle Case, bis auf den letzten (in dem der Timer genutzt wurde) deaktiviert. Und plötzlich - funktioniert.
Also nacheinander alle Step-by-step wieder reaktiviert. Als ich dann beim ersten CASE ankam, funktionierten die anderen wieder problemlos.
Habe diesen dann auch wieder reaktiviert und was soll ich sagen - keine Spur mehr von einem Problem. Die Ausgänge fadeten ohne Murren.
Mittlerweile läuft das Programm fehlerfrei und ich teste jede neue CASE ausgiebig, bevor ich diese endgültig abspeichere.
Beispielsweise hatte ich auch das Problem der Signalüberschneidung. Am Ende der ISR des Timer0 stehen ja die angesteuerten Ports mit entsprechenden Bedingungen drin. Da ich aber unter verschiedenen Bedingungen bestimmte Ports ansteuere, kam es beim Fading dazu, dass die LED nur halbhell aufleuchteten.
Wie ich das gelöst habe, seht ihr am Ende des Codes...
$regfile = "m8515.dat"
$crystal = 8000000
$hwstack = 40
$swstack = 32
$framesize = 60
'-------------------------------------------------------------------------------
' *** Konfiguriere Ein- und Ausgangsports ***
Config Porta = Input
Config Portb = Output
Config Portc = Output
Config Portd = Output
Porta = &HFF ' Aktiviert die internen Pullup-Widerstände
Portb = &HFF ' schaltet alle Ausgänge 1, LED = 0
Portc = &HFF
Portd = &HFF
'-------------------------------------------------------------------------------
' *** Konfiguriere Timer ***
Config Timer0 = Timer , Prescale = 64
On Timer0 Timerroutine
Enable Timer0
Start Timer0
Enable Interrupts
'-------------------------------------------------------------------------------
' *** Deklarieren der Variablen ***
Dim Programm As Byte
Dim Zaehler As Word
Dim Timerzaehler As Word
Dim Led_rack0 As Word ' Abrufbar wenn nur ein Rack gefordert
Dim Led_rack1 As Word ' Acht LED-Racks - abrufbar, wenn mehr als ein Racks gefordert
Dim Led_rack2 As Word ' Jedes Rack steht dabei für ein Regalfach, egal ob horizontal oder vertikal
Dim Led_rack3 As Word
Dim Led_rack4 As Word
Dim Led_rack5 As Word
Dim Led_rack6 As Word
Dim Led_rack7 As Word
Dim Led_rack8 As Word
Dim Choose_rack As Byte ' Variable zum Weiterschalten eines Racks in einer Ablaufprozedur
Dim Folgesequenz As Byte ' Variable zum Weiterschalten einer Sequenz in die Folgende
Dim M1 As Bit ' Programmabbruch-Variable
'-------------------------------------------------------------------------------
' *** Deklarieren der Subroutinen ***
Declare Sub All_off
Declare Sub All_on
Declare Sub Horizontal_lines
Declare Sub Vertical_lines
Declare Sub Straight
Declare Sub Diagonal_falling
Declare Sub Diagonal_rising
Declare Sub Net
Declare Sub Net_invert
Declare Sub Arrow_up
Declare Sub Pulsing_rack
Declare Sub Left_to_right
'-------------------------------------------------------------------------------
' ===============================
' ***** Hauptprogramm *****
' ===================================
Do
Programm = Pina ' Variable übernimmt das Portregister von Port A
Programm = Programm And &B00011111 ' Die ersten 3 Bits von Port A werden deaktiviert, somit brauchen
' im folgenden Select nur noch die Folgebits stehen
Select Case Programm
Case &B11111 : Call All_off ' 00000
Case &B11110 : Call All_on ' 00001
Case &B11101 : Call Horizontal_lines ' 00010
Case &B11100 : Call Vertical_lines ' 00011
Case &B11011 : Call Straight ' 00100
Case &B11010 : Call Diagonal_falling ' 00101
Case &B11001 : Call Diagonal_rising ' 00110
Case &B11000 : Call Net ' 00111
Case &B10111 : Call Net_invert ' 01000
Case &B10110 : Call Arrow_up ' 01001
Case &B10101 : Call Pulsing_rack ' 01010
Case &B10100 : Call Left_to_right ' 01011
End Select
If Programm = &B11111 Then M1 = 1 Else M1 = 0 ' Programmabbruch-Bedingung
Loop
'-------------------------------------------------------------------------------
' ====================================
' **** Unterprogramme ****
' ================================
Sub All_off: ' 00000
Portd = &B11111111
Portc = &B11111111
Portb = &B11111111
Choose_rack = 0 ' Setzt bei Programmabbruch Variable zurück
Disable Timer0 ' Setzt bei Programmabbruch Timer0 Ausser Kraft
End Sub All_off
Sub All_on: ' 00001
Portd = &B00000000
Portc = &B00000000
Portb = &B00000000
End Sub All_on
Sub Horizontal_lines: ' 00010
Portd = &B10101010
Portb = &B10101010
Portc = &B10101010
End Sub Horizontal_lines
Sub Vertical_lines: ' 00011
Portd = &B00000000
Portc = &B11111111
Portb = &B00000000
End Sub Vertical_lines
Sub Straight: ' 00100
Portd = &B11111111
Portc = &B00000000
Portb = &B11111111
End Sub Straight
Sub Diagonal_falling : ' 00101
Portd = &B00100100
Portc = &B01001001
Portb = &B10010010
End Sub Diagonal_falling
Sub Diagonal_rising: ' 00110
Portd = &B10010010
Portc = &B01001001
Portb = &B00100100
End Sub Diagonal_rising
Sub Net: ' 00111
Portd = &B10101010
Portc = &B01010101
Portb = &B10101010
End Sub Net
Sub Net_invert: ' 01000
Portd = &B01010101
Portc = &B10101010
Portb = &B01010101
End Sub Net_invert
Sub Arrow_up: ' 01001
Portd = &B11011101
Portc = &B10111011
Portb = &B11011101
End Sub Arrow_up
Sub Pulsing_rack: ' 01010
Enable Timer0 ' Startet Timer0 (muss ja nicht immer laufen)
'----- Aufdimmen -----
For Zaehler = 0 To 300
Led_rack0 = Zaehler
Waitms 10
Next Zaehler
'----- Abdimmen -----
For Zaehler = 300 To 0 Step -1
Led_rack0 = Zaehler
Waitms 10
Next Zaehler
End Sub Pulsing_rack
Sub Left_to_right:
' Diese Sub dimmt jeweils 3 LED-Streifen (bestehend aus je 1 Port) nacheinander auf und in gleicher Reihenfolge wieder ab.
' Mit Hilfe der Variable "CHOOSE_RACK" war es möglich, jeweils um 1 LED-Rack (1 Port) weiterzuschalten, ohne eine neue
' FOR-Schleife aufbauen zu müssen.
Enable Timer0
Choose_rack = Choose_rack + 1 ' 01011
Aufdimmen:
For Zaehler = 0 To 300
If M1 = 1 Then Exit Sub ' Abbruchbedingung
If Choose_rack = 1 Then Led_rack1 = Zaehler
If Choose_rack = 2 Then Led_rack2 = Zaehler
If Choose_rack = 3 Then Led_rack3 = Zaehler
Waitms 3
Next Zaehler
If Choose_rack = 3 Then Gosub Abdimmen:
Abdimmen:
For Zaehler = 300 To 0 Step -1
If M1 = 1 Then Exit Sub
If Choose_rack = 4 Then Led_rack1 = Zaehler
If Choose_rack = 5 Then Led_rack2 = Zaehler
If Choose_rack = 6 Then Led_rack3 = Zaehler
Waitms 3
Next Zaehler
If Choose_rack = 6 Then Choose_rack = 0
End Sub Left_to_right
End
'-------------------------------------------------------------------------------
' *** ISR für Timer erzeugen - Overflow-Counter in Warteposition bringen ***
Timerroutine:
Timer0 = 249
Incr Timerzaehler
If Timerzaehler = 300 Then Timerzaehler = 0 ' Auflösung der LED's von 300Hz
' Die nachfolgenden Port-PWM-Ansteuerungen werden durch die Programm-Bedingung separiert.
' Ohne Trennung gäbe es eine Signalüberschneidung, welche die Helligkeit um 50% reduziert.
'---------- Sub Pulsing_Rack ----------
If Programm = &B10101 Then
If Timerzaehler < Led_rack0 Then Portb = &B00000000 Else Portb = &B11111111
End If
'---------- Sub Left_To_Right ----------
If Programm = &B10100 Then
If Timerzaehler < Led_rack1 Then Portb = &B00000000 Else Portb = &B11111111
If Timerzaehler < Led_rack2 Then Portc = &B00000000 Else Portc = &B11111111
If Timerzaehler < Led_rack3 Then Portd = &B00000000 Else Portd = &B11111111
End If
Return
Bin echt froh, dass ich an vielen Stellen selbst weiterkomme, aber ohne eure Hilfe würde der Code sicher um Einiges größer.
Wobei ich aber auch sagen muss, dass es keinen nennenswerten Unterschied zur Schreibweise "PinA = &B00011101" und "PinA = 11101" gibt. Habe es mehrfach geprüft - die Dateigröße bleibt gleich.
Der Code oben liegt derzeit übrigens bei ca. 1,7KB - und für meine Verhältnisse ist das echt verdammt wenig. Denke, dass das Deklarieren der Subs auch eine ganze Menge raus haut. Gosub-Sprungmarken ohne Deklaration der Sub ziehen doch schon ihren Speicherplatz...
LG - Maik
Sauerbruch
17.12.2014, 10:32
Wobei ich aber auch sagen muss, dass es keinen nennenswerten Unterschied zur Schreibweise "PinA = &B00011101" und "PinA = 11101" gibt. Habe es mehrfach geprüft - die Dateigröße bleibt gleich.
Also, bevor ich versuche zu verstehen ob es jetzt aktuell noch ein Problem gibt, muss ich Dich nochmal auf drei fundamentale Denkfehler hinweisen:
Erstens:
Man kann das Register PINA (ebenso wie alle anderen PIN-Register) nicht beschreiben!!! D.h. man kann es schon, aber bereits mit dem nächsten Taktzyklus des Controllers übernimmt jedes der 8 Bits den Wert, der den logischen Pegeln auf den Anschlüssen PINX.7 bis PINX.0 anliegt. In PORT-Register kann man durchaus alle möglichen Werte reinschreiben - aber beim PIN-Register funktioniert es nicht und macht vor allem keinen Sinn. Es ist ein reines Auslese-Register!!!!
Zweitens:
Natürlich macht es einen Unterschied, ab man einer Byte-Variablen den Wert 11101 oder &b00011101 zuweist! Das kann man am Simulator sehr schön sehen - aber nicht am Speicherplatz, den der Programmcode benötigt!! Der benötigte Speicherplatz ist nur ein ganz, ganz grober Schätzer - aber wenn Du Dir mal vergegenwärtigst, dass die meisten Befehle 2 Byte Speicher benötigen wird klar, dass man ein Programm komplett umändern kann, ohne dass sich der Speicherplatz-Bedarf ändert.
Drittens:
Wenn Du einer Byte-Variablen eine Dezimal-Wert von 11101 zuweist, müsste Bascom eigentlich sofort die Fehlermeldung rausgeben "Hey Du Troll - Bytes können einen Wert von maximal 255 annehmen". Aber Bascom ist da etwas gnädiger. Was es macht, kannst Du verstehen, wenn mal die "Taschenrechner"-App auf Deinem PC aktivierst, dort die Dezimalzahl 11101 eingibst, und sie in einen Binärwert umwandelst. Das Ergebnis ist &b 0010 1011 0101 1101. Bascom ignoriert einfach die oberen 8 Bits und schreibt wenigstens die unteren 8 Bits (also &b 0101 1101) in das Byte. Wenn Du irgendeine LCD-Anzeige an Deinem Controller hast, kannst Du das ja mal ausprobieren:
Dim X as Byte
X = 11101
LCD X
Auf dem Display wird die Zahl 93 stehen (=&b 0101 1101)
Wenn diese Dinge nicht klar sind, wird´s wohl immer wieder Schwierigkeiten geben :-)
stardust19322
17.12.2014, 19:53
Hi Sauerbruch.
Danke nochmals.
Display ist vorhanden, momentan jedoch keine Zeit. Ich bin gestern so gut voran gekommen und habe auch viel Neues dazu gelernt, dass ich jetzt da weitermache, wo ich gestern aufgehört habe.
Für Display-Übungen steht aber auch noch eine Programmierwoche an, nämlich wenn ich den MASTER-Controller beschreibe. Der hat neben der PWM-Ausgabe und den Eingabe-Tastern auch noch ein Display. Wird das erste mal - bin selbst schon gespannt ^^.
LG - Maik
stardust19322
26.12.2014, 00:34
Hallo Freunde.
Das Arbeiten am Slave-Controller habe ich nun erst einmal beiseite gepackt und mich an den Master gesetzt, welcher neben dem Display und der Cursor-Steuerung auch Übertragungsbits bereit stellt.
Allerdings habe ich dabei ein kleines Problem, und es kann ja sogar auch sein, dass das Ganze so gar nicht funktioniert, wie ich mir das vorstelle:
Beim Einlesen eines ganzen Registers konnte ich ja das gesamte Register verwenden. Nun allerdings habe nur noch Teile 2er Ausgaberegister zur Verfügung, nämlich von PortB und PortD.
Mit den nun für mich relevanten Ports versuchte ich, eine neue Wahrheitstabelle aufzubauen, welche in einer "Select" zusätzlich zu einem ausgegebenen Display-Text angesprochen wird.
Hier der Codeausschnitt:
' Konfiguration der Ausgangsbits für Wahrheitstabelle
Ausgabebyte.0 = Portd.7
Ausgabebyte.1 = Portd.6
Ausgabebyte.2 = Portd.5
Ausgabebyte.3 = Portb.7
Ausgabebyte.4 = Portb.6
Ausgabebyte.7 = Portb.0
Locate 1 , 1 : Lcd "3.1 Stillstehend" : Locate 2 , 1 : Lcd Chr(1) : Locate 2 , 16 : Lcd Chr(2)
'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
' Konfigurieren und Ausgabe der Musterbits für stehende Muster
Locate 2 , 2
Select Case Starr
Case 0 : Ausgabebyte = &B00000000 : Lcd " Bitte w hlen " : Locate 2 , 10 : Lcd Chr(3)
Case 1 : Ausgabebyte = &B11111111 : Lcd " Alle Cluster "
End Select
Die Ausgangsbits sind korrekt als Ausgänge konfiguriert, die zugewiesene Variable als Byte deklariert. Dieser kleine Bereich ist Teil eines 5,3KB großen Programms, weshalb ich nur diesen Ausschnitt poste. Bislang funktioniert auch alles tadellos, und mit dem Sprung in die Variable "Starr" wird auch der in der Select stehende Text für den entsprechenden Wert von "Starr" korrekt ausgegeben. Die Variable funktioniert also tadellos, nur werden die Ausgänge nicht gesetzt.
Setze ich hingegen testweise NUR einen einzelnen Port, indem ich ihn direkt anrufe, dann wird der Ausgang wie gewünscht gesetzt.
In etwa so:
Locate 1 , 1 : Lcd "3.1 Stillstehend" : Locate 2 , 1 : Lcd Chr(1) : Locate 2 , 16 : Lcd Chr(2)
'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
' Konfigurieren und Ausgabe der Musterbits für stehende Muster
Locate 2 , 2
Select Case Starr
Case 0 : Portb.0 = 0 : Lcd " Bitte w hlen " : Locate 2 , 10 : Lcd Chr(3)
Case 1 : portb.0 = 1 : Lcd " Alle Cluster "
End Select
Kann es also u.U. daran liegen, dass ich in einem Byte lediglich Ports eines einzelnen Registers anrufen kann oder geht das bei Ausgängen gar nicht?
LG - Maik
Sauerbruch
26.12.2014, 09:20
Ach menno - das hatten wir doch schon:
X = A bedeutet, dass der Variablen X der Wert von A zugewiesen wird. So rum - und nicht anders!!!
Das Gleichheitszeichen geht bei Bascom nur in eine Richtung: Der rechts vom Gleichheitszeichen stehende Wert wird der links davon stehenden Variablen zugewiesen. Die links stehende Variable macht NIEMALS etwas mit der rechts stehenden Variable. Das ist der fundamentale Unterschied zum Gleichheitszeichen im mathematischen Sinne.
Wenn Du also am Anfang schreibst X = A und dann im Verlauf mit X weiterrechnest, ändert sich A in keinster Weise! Der Befehl X = A liegt erstens schon lange zurück, und zweitens hat die links stehende Variable wie gesagt niemals einen Einfluss auf die rechts stehende Variable!
Was macht also diese Befehlssequenz:
Ausgabebyte.0 = Portd.7
Ausgabebyte.1 = Portd.6
Ausgabebyte.2 = Portd.5
Ausgabebyte.3 = Portb.7
Ausgabebyte.4 = Portb.6
Ausgabebyte.7 = Portb.0
?????
Riiiiiichtiiiig - nicht das Byte "Ausgangsbyte" bestimmt die Port-Pegel, sondern aus den Bits, die in den Registerzellen PORTD.7, D.6, D.5, B.7 B.6 und B.0 stehen, wird das Byte "Ausgangsbyte" zusammengebastelt.UND NICHT ANDERSHERUM!!!! Ich nehme an, dass an einer so frühen Stelle alle Bits in den PORT-Regsitern noch 0 sind, damit dürfte Ausgangsbyte in diesem Moment auch &b00000000 sein - aber das ist ja auch egal, denn später passiert ja anscheinend irgendwas mit diesem Byte, d.h. es wird ohnehin verändert.
Klingelt´s jetzt vielleicht so weit, dass Du auf die Lösung kommst?
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.