• Hallo TT-Modellbahner, schön, dass du zu uns gefunden hast.
    Um alle Funktionen nutzen zu können, empfehlen wir dir, dich anzumelden. Denn vieles, was das Board zu bieten hat, ist ausschließlich angemeldeten Nutzern vorbehalten. Du benötigst nur eine gültige E-Mail-Adresse und schon kannst du dich registrieren.
    Deine Mailadresse wird für nichts Anderes verwendet als zur Kommunikation zwischen uns.
    Die Crew des TT-Boardes

PIC oder Atmel? Aller Anfang ist schwer...

Hab die Tage auch mal ein bißchen bzgl. der Servoansteuerung experimentiert. Ich muss sagen, ich fühle mich mit ASM doch recht wohl, obwohl es im Vergleich zum Ux88y0 (hab mein gutes altes EMR-Buch gefunden) recht umständlich ist, weil wichtige Befehlskombinationen fehlen und damit nur auf Umwegen erreichbar sind (beim Ux88y0: xor r4, #%02, beim AVR: ld r5, 0x02 eor r4, r5) und die Mnemonics je nach Parametern variieren (beim Ux88y0 gingen z.B. LD r4, r5 und LD r4, #%20, beim AVR heißt das MOV r4, r5 bzw. LDI r4, 0x20). Auch arbeiten viele Befehle nur auf den r-Registern, nicht aber auf den Spezialfunktionsregistern oder den Ports.
 
...wichtige Unterschiede (wenn erforderlich, Korrektur erwünscht):
- Atmels sind offenbar 16-bit-Controller...
Die normalen AVR haben alle einen 8 Bit breiten Datenbus. Der Adressbus besitzt je nach Controller 10 bis 18 Bit "Bandbreite".
Entweder hab ich grad den Link nicht gefunden oder Atmel hat die Produktion der 16Bit-µC auslaufen lassen. Neben den 32 Bit Controllern der ARM-Reihe gibts noch die AVR32.
Mit denen brauchen wir uns aber meiner Meinung nach nicht auseinandersetzen. Das wär etwa so als wenn man den Triebwerk aus nem Düsenjet in nen Trabbi schraubt.


Wenn Port B eingang sein soll, braucht eigendlich nur der Pin von port B gelesen werden. (...)
Wie gesagt, ich arbeite ausschließlich in Assembler, da weiß ich nicht, wie man enzelne bits in Basic oder C ansprechen kann...
Geht in Basic zumindest unter BASCOM so:
Portb = Input
oder
Portb = Output
oder
Portb=&B00001111 'hier sind Pinb.0 bis Pinb.3 Aus- und die Pinb.4 bis Pinb.7 Eingänge
oder
Portb=&H0F 'in Hexadezimal geschrieben und wie eine Zeile weiter oben Pins 0 bis 3 sind Ausgänge....
oder
Portb = 16 'analog zu Portb=&B... und Portb=&H...

Man kann auch schreiben:
Pinb.0 = 1 'Ausgang
Pinb.0 = 0 'Eingang

Der Text hinter dem Apostroph wird vom Compiler ignoriert - er dient nur zur Trennung zwischen Befehlen und eigenen Stichpunkten die man sich in das Programm tippt um die Übersicht zu behalten.

...
- Welche Auflösung nehmt Ihr für die Impulsbreite - 8bit.
8 Bit gehen in Ordnung, 16 sind aber besser weil feiner. Ich hab's mal mit ner Mischung aus Hardware-PWM und Software ausprobiert die alle 2ms einen Interrupt über das Overflowflag des Timer0 (OVF0) auslöst und einen Zähler um 1 incrementiert damit ich nicht großartig rumfummeln musste.
Das bot mir den Vorteil das ich den anderen Zähler noch frei zur Verfügung habe und allein durch die Internen Takteiler unter Verwendung eines 2MHz oder eines 16MHz-Quarzes auf die gewünschten 50Hz Wiederholfrequenz komme.
Bin aber noch nicht ganz zufrieden weil ich nach ner Lösung suche die Hardware mit dem Timer0 auf 10 bis 12 Bit zu interpolieren. Technisch muss es gehen - ich hab allerdings noch mit der Soft Probleme.

So langsam kommen wir (ich) der Sache näher.
Nur was das Beschreiben angeht, es bringt mich zur Verzweiflung. Stecker dran und ab ist ja ok, aber zum Beschreiben muss ich noch dran denken dass PB5 - PB7 nicht auf Masse liegen oder mein Testboard abgeschaltet ist...
Entkoppel Dein Testboard doch einfach durch Widerstände vom Controller. Zwischen den Widerständen und dem µC befinden sich dann die Kreuzungspunkte zu MOSI, MISO und SCK.
 
Die normalen AVR haben alle einen 8 Bit breiten Datenbus. Der Adressbus besitzt je nach Controller 10 bis 18 Bit "Bandbreite".
Richtig, es sind 8-Bit-Controller mit 16-bit-aufgelöstem Programmspeicheradressbus. Hab es im originalen Beitrag korrigiert, damit kein Blödsinn weiter da steht.
8 Bit gehen in Ordnung, 16 sind aber besser weil feiner. Ich hab's mal mit ner Mischung aus Hardware-PWM und Software ausprobiert die alle 2ms einen Interrupt über das Overflowflag des Timer0 (OVF0) auslöst und einen Zähler um 1 incrementiert damit ich nicht großartig rumfummeln musste.
Das bot mir den Vorteil das ich den anderen Zähler noch frei zur Verfügung habe und allein durch die Internen Takteiler unter Verwendung eines 2MHz oder eines 16MHz-Quarzes auf die gewünschten 50Hz Wiederholfrequenz komme.
Ich verwende nicht den 8-Bit-Timer 0, da der zu "dumm" ist. Statt dessen nehme ich den 16-bit-Timer 1. Dem kann man im OCR1A den Maximalwert setzen, bis zu dem er zählen soll (entspricht bei mir dem zeitlichen Offset zwischen den steigenden Flanken der Servoimpulse zweier aufeinanderfolgender Servos). Dem OCR1B habe ich den impulslängenrelevanten Wert gesetzt. Der zugehörige Interrupt erzeugt die fallende Flanke des Servoimpulses. Das sieht dann ungefähr so aus (mit kurzen Servoimpulsen):
Servo 0: _-___________-___________
Servo 1: ____-___________-________
Servo 2: _______-___________-_____
Servo 3: __________-___________-__

bzw. mit langen Impulsen:
Servo 0: _--__________--__________
Servo 1: ____--__________--_______
Servo 2: _______--__________--____
Servo 3: __________--__________--_

Die Wiederholungsrate ergibt sich aus dem konstanten OCR1A-Wert und der Anzahl der Servos. Also bei ca. 8 Servos ist Schluss, dafür aber sehr genau (8 * (~2,5ms maximale Impulslänge + ~0,5ms Mindestpause bis zum nächsten Servo) = ~24ms).
 
... nur auf Umwegen erreichbar sind (beim Ux88y0: xor r4, #%02, beim AVR: ld r5, 0x02 eor r4, r5) und die Mnemonics je nach Parametern variieren (beim Ux88y0 gingen z.B. LD r4, r5 und LD r4, #%20, beim AVR heißt das MOV r4, r5 bzw. LDI r4, 0x20)....

Nun, bei Register r0-r15 funktioniren die Befehle LDI, Addi, Ori und CPI nicht, das stimmt. Aber in Register R16-R32 ist das problemlos möglich!
Also
ld r5,0x02
geht nicht, da must du
ldi r(>)15,0x02 genommen werde.
und dann
mov r4, r(>)15.
 
@tsinger:
Warum nimmste dann nicht gleich die Hardware-PWM?
Erstens hast Du dann keinen Interrupt mehr der den Programmablauf verzögern kann und zweitens brauchst Du die geänderten Werte nur noch in die OutputCompareRegister OCR1A und OCR1B reinschreiben (wenn Du Dich mit Zwei Servos begnügst).
Oder Du nutzt einen OutputCompareMatch (ebenfalls ein Interruptvektor (als Anmerkung für Neulinge)) und nimmst diesen um den Impuls per Schieberregister oder ähnlichem an einen anderen Servo weiter zu geben.
Damit lassen sich dann theoretisch bis zu 10 Servos an einem PWM-Ausgang betreiben was aber etwas externe Hadrware erfordert (ein Schieberegister und ein passendes AND-Gatter). Einfach den Timer per Hardware und passendem Quarz auf 500 Hz oder weniger einstellen und den OVF1A (oder OVF1B) nutzen um das Schieberegister anzusprechen.
Ist mir grad so durch den Kopf geschossen als ich Dein Timingdiagramm sah.
 
@E-Fan

Aha, wäre eine Lösung. So fit bin ich in Elektronik nun aber auch nicht. Hättest du einen Wert so als Anhaltspunkt? Besonders hochohmig sollte es bestimmt nicht sein, 5,6k wäre das ok? Oft rumlöten kann ich auf dem Testboard nicht, dann lösen sich die Lötpunkte in Wohlgefallen auf.

@pltbahn
Also die Eingänge für die Weichen kommen von den Rückmeldern der motorischen Antriebe (Dauersignal). Geschaltet werden die Weichen extern.
Die Eingänge für das Bremssignal G1-3 kommen von einem simplen Schalter (2pol UM) der einmal den normalen Fahrstrom oder das Bremssignal auf die Gleise 1-3 schaltet und parallel das Steuersignal für die Eingänge des µC. Deshalb auch dauerhaft "An" damit das Bremssignal auf den Gleisen 1-3 anliegt und das Züglein dort auch verweilt. Spannungslos in Digital ist "unschön" wurde mir gelehrt. Die Gleise 1-3 sind isolierte Abschnitte.
Der Eingang der LS ist ein Impuls.
Die beiden Ausgänge für die Bremsstrecken steuern, wie du schon vermutet hast, zwei simple Relais an welche das Bremssignal auf die Abschnitte legt.

PB0 - W8Stamm
PB1 - W8Abzweig
PB2 - W9Stamm
PB3 - W9Abzweig
PB4 - BremsenG1
PB5 - BremsenG2
PB6 - BremsenG3
PB7 - Lichtschranke

PD6 - Bremsstrecke 1
PD5 - Bremsstrecke 2

Die Ausgangsweichen auf Durchfahrt mit zu überwachen hatte ich mir auch schon überlegt. In dem Fall könnte man ein automatisches Bremsen auslösen. Setzt aber ein 2pol UM Relais statt meiner simplen Schalter voraus >> vorerst vertagt.
Sinvoller wäre je Gleis die GBM auszuwerten und wenn das Zielgleis besetzt ist und eine Art Nothalt (in dem Fall einfach mit "Strom weg") auszulösen (eleganter wäre ein sauberes Bremsen im Block vorher, aber dafür reicht die Strecke nicht). Das hab ich so im meiner Hardwarelösung des unteren Schattenbhf. gemacht. Im Moment hab ich leider noch leichte Probleme ein sauberes HI/LO bei GBM auszukoppeln. Naja, erst ein Versuch gemacht, muss mich nochmal damit beschäftigen.

Was den Sinn der Bremsstrecken angeht...
Meine BHf Gleise sind zwischen 1,40 uns 1,80m. Damit das Bremsen wenigstens halbwegs ordentlich aussieht ist die Bremstrecke ist auf 2,40m eingestellt. Ziel ist es eben in Abhängigkeit des Zielgleises (Bremsen oder Durchfahrt) und der Weichenstellungen die benötigten Bremsstrecken mit auf Bremssignal zu schalten. Die zwei Bremsstrecken ergeben sich durch den Versatz der Haltepunkte, da ja die Länge des Bremsweges konstant ist.

Es ist schwierig rein in Worten das richtig zu erläutern. Ein µC ist auch ziehmlich "overdrive" für diese Aufgabe. Aber ist ja zum Üben, außerdem flexibel gegenüber Hardware.

flic
 
Nun, bei Register r0-r15 funktioniren die Befehle LDI, Addi, Ori und CPI nicht, das stimmt. Aber in Register R16-R32 ist das problemlos möglich!
Also
ld r5,0x02
geht nicht, da must du
ldi r(>)15,0x02 genommen werde.
und dann
mov r4, r(>)15.
Bei diesem Beispiel ging es mir um die Mnemonics, die beim Ux88y0 immer 'LD' waren, während beim AVR es mal 'LD', 'LDI', 'MOV', 'LDS', 'IN', 'OUT' und weiß der Kuckuck was sein können. Blöd ist auch, dass man bei den SFR (Special Function Registers) die Bitmanipulierbefehle SBI bzw. CBI nicht benutzen kann. Statt dessen muss man immer erst den Wert in ein r-Register speichern:

in r0, TIMSK
cbr r0, 1 << OCIE1A
sbr r0, 1 << OCIE1B
out TIMSK, r0

Aber egal, man kommt damit zurecht.
Warum nimmste dann nicht gleich die Hardware-PWM?
Weil ich dann nur einen (oder 2?) Servos anschließen kann? An die Hardware-Version, die das Signal an verschiedene Servos verteilt, hab ich auch schon gedacht, aber wozu hab ich denn einen AVR?
 
Weiß jemand, wie man im AVR Studio für die *Assembler* Simulation den Prozessortakt ändern kann? Bei mir ist der immer auf 4MHz eingestellt.
 
Die Befehle sind auf Grund der RISC Struktur auf elementare Befehle beschränkt da spezielle Befehle zu komplex wären. Dafür brauchen viele Befehle eben nur einen Takt für die Ausführung. Du kannst dir aber auch selber Befehle definieren (Makros). Übrigens gibt es unter den Simulator Options noch die Funktion für Logging und Stimuli. Wenn eine entsprechende Stimulidatei verwendet wird kann z.Bsp. ein DCC Signal an einem Eingang simuliert werden und die Dekodierung überprüft werden. Die Logging Funktion ist das Gegenteil. Es kann ein Port in eine Datei gespeichert werden während das Programm simuliert wird. Damit kann etwa ein Servosignal überprüft werden.
 
Das Logging- und Stimuli-Feature hab ich auch gerade gefunden und ersteres zur Messung meiner Servo-Impuls-Länge herangezogen. Vorher hatte ich es mit VMLab versucht - ist zwar grafisch, aber die Zeitanzeige zu ungenau.
 
@Flic:

Kommt auf die Nutzung an. 2k7 sollten auch schon reichen.

...Weil ich dann nur einen (oder 2?) Servos anschließen kann? An die Hardware-Version, die das Signal an verschiedene Servos verteilt, hab ich auch schon gedacht, aber wozu hab ich denn einen AVR?

Um zum Beispiel im DCC-Fall:
- neben der Dekodierung des Signals eine Motorstromüberwachung reinzubasteln um zu überprüfen ob der Servo auch umgelaufen ist. Stellt er nämlich ne defekte Weiche dürfte der Stromfluß beim Umlaufen anders als im Normalfall sein

- über den S88 Bus eine Rückmeldung zu realisieren. Soweit ich mich erinnere entspricht der dem SPI-Bus.

- Das Weichenherzstück im Kurzschlußfall (Entgleisung) Stromlos zu schalten damit weder Relais noch edle Modelle durch Überstrom ihren Geist aufgeben (müssen)

- Abhängigkeiten von Fahrstraßen und Signalen beim Stellen der Weiche einzubinden (optional)

Jeder Timer hat (bis auf wenige Ausnahmen) zwei OutputCompareRegister die sich unabhängig voneinander einstellen lassen. Damit lassen sich beim Atmega48 zum Beispiel maximal 6 Servos per Hardware ansteuern da dieser 3 Timer besitzt. Ich würd mir aber da einen Timer übrig lassen und diesen zur u.a. Dekodierung des DCC-Signals nutzen.

Also programmier- und schaltungstechnisch gibts da noch viele Möglichkeiten die einem dann doch dazu verleiten könnten dicke Backen zu machen ;)
 
um Zeiten zu messen setze ich mir Breakpoints und nutze die Stoppuhr. Ersten Breakpoint anfahren Zähler auf Null, nächsten Breakpoint anfahren Zeit ablesen. Die Uhr kann von µs auf ms umgeschaltet werden.
 
Um DCC zu dekodieren brauchste keine Zeiten messen.
Dat is viel zu umständlich weil man mit nem fest eingestellten Interrupt und zwei rotierenden Registern (bzw. mit dem Verschieben einzelner Bits) auch alles erledigen kann.
 
es ging hier um den Programmtest, deshalb auch die Breakpoints. Die DCC Dekodierung läuft bei mir über Interrupts. Mein Post war eigentlich für Tsinger bestimmt. Dein Post kam beim Schreiben dazwischen.
 
Langsam (da wenig Zeit) geht die Servoprogrammierung weiter (der 1. Servo dreht sich schon langsam von der Mitte nach rechts und von dort dann nach links). Leider ist das Arbeiten (vom Editor her) im AVR-Studio eine Qual.

Ich kann meine programmatischen 8 Servos frei konfigurieren, auf welchem Port sie an welchen Pin angeschlossen sind. Der Zugriff auf den Portpin erfolgt parametrisiert über (and-Verknüpfung entsprechend)

ldi XH, 0
mov XL, portRegister
ld temp1, X
or temp1, temp2
st X, temp1

Habt Ihr eine Empfehlung, wie ich dem C-Compiler mitteilen soll, dass er so eine indirekte Registeradressierung benutzt? Oder wird es am einfachsten sein, ein solches Codeschnipsel als Assembler zu hinterlegen?
 
So hier ist mein erstes, kleines Servoansteuerungsprogrämmchen für den ATmega8. Mit Taster 3 (PD4, high-aktiv) schaltet man zwischen den 8 Servos um, mit Taster 1 (PD2, high-aktiv) verringert man den Sollwert, mit Taster 2 (PD3, high-aktiv) erhöht man den Sollwert. Ohne irgendeine Änderung läuft ein Servo an PD5 (wird auch durch LED1 angezeigt), die anderen lassen sich auf jeden beliebigen Portpin mappen (siehe initServos).

Feed-back ist willkommen.
 

Anhänge

  • servo.asm.txt
    7,7 KB · Aufrufe: 27
Sorry, durch Leipzig, dann seit Montag totale Erkältung und nächste woche Peine bin ich noch nicht zum Programmieren gekommen!

Zu Tszinger
Da du in deinem Schnipsel alles mit Variablen gelöst hast, würde ich es als Unterprogramm mit Call aufrufen.

Weitere Variante:

ldi XH, 0
ldi XL, 0

ld temp1, X+portvariable
or temp1, temp2
st X+portvariable, temp1

Dann aber für jeden Port extra, da X nicht mit einem Register verknüpft werden kann.

Dann müßte aber auch :

lds temp1, portvariable
or temp1, temp2
sts portvariable, temp1

klappen.
 
Ich grabe das hier mal aus. Wenn ich einen AVR (z.B. 8535) programmieren will, reicht dann die Pollin-Platine und ein serielles Kabel dazu aus?

Wie sehen eure Beschaltungen für die Servoansteuerung aus?
 
Hallo,
Pollin-Platine geht voll in Ordnung.
Aber die Sache mit dem seriellen Kabel funktioniert meist nicht so richtig. Wenn du über USB anschließen mußt, nimm auf jeden Fall einen Programmieradapter dazu. Das spart jede Menge Ärger. Mit einem AVRISP MKII-Adapter (z.B. bei Reichelt) hab ich sehr gute Erfahrungen gemacht.

Gruß Hagen
 
Also ich programiere die Atmel mit einem Verbindungskabel LPT1-Atmel 4-adrig selbst gelötet und +5V-Netzteil oder 3,6V Akku, weiter nix!
Servoansteuerung:
Tastenmatrix 4x4 für 8 Servos. Dafür habe ich die Eingänge genutzt, die intern mit den AD-Wandlern verbunden werden können, so kann ich wahlweise die Tastaturmatrix oder 8 Potis anschließen, über die die Stellung (zB. bei Wasserkränen oä) von Hand beliebig eingestellt werden kann.
 
8 Potis anschließen, über die die Stellung (zB. bei Wasserkränen oä) von Hand beliebig eingestellt werden kann.
Das ist keine dumme Idee :idee:! Wobei, dann kann man auch einen Servotester dazu nehmen, etwas mehr Aufwand in der Verkablung (weil extra Kabel), beim Finanziellen wird es sich wohl nix nehmen.
 
Zurück
Oben