Hallo Leute,
ich bastel zur Zeit an einer DMX-Schaltung. Ein DMX-Singnal muss bis zu
alle 4us den Wert am Ausgang ändern... Ich habe jetzt alle Komponeten
einzeln getestet und
-mein Controller empfängt das Singnal vom PC,
-mein Controller kann das Signal in ein DMX-Signal umwandeln
-und der MAX485 wandelt das Singnal in ein invertiertes Signal und ein
uninvertiertes Signal um.
Aber einerseits fehlt mir noch der Sendevorgang vom Controller, und da
ist auch mein Betreff wieder zufinden und andererseits hab ich noch eine
kleine Frage zum MAX485:
Zunächst die kleine Frage zum MAX:
Ich verstehe nicht ganz was der MAX bringen soll... Ich könnte doch
auch einfach zwei Port von meinem Controller immer genau verkehrt
setzten, oder macht der MAX noch etwas anderers?
Und jetzt mein Hauptproblem:
Ich betreibe meinen ATmega32 mit einem externen 10MHz Quarz und habe
sonst eine typische Grundbeschaltung(siehe Anhang(Bild von
http://www.kreatives-chaos.com/images/37.png)).
Ich hab etwas vom CTC-Modus gelesen und versuch in meinem Code
anzuwenden aber irgendwie kommt mein Controller nicht in diesen Timer,
jedenfalls bleibt die Variable "zaehler" beim Debuggen immer "0".
Was hab ich falsch gemacht?!?
Mein Code:
ASSR |= (1<<AS2); //Syncronisation mit Quarz(C7/C6)//10MHz
Äh, das hast du falsch verstanden.
AS2 brauchst du nur dann, wenn du für den Timer 2 einen eigenen Quarz
hast. Soalnge du den Timer sowieso vom Hauptquarz takten willst, setzt
du dieses Bit NICHT!
> TIFR |= (1<<TOV2); //Flag ->'0' Aussetzen
freigegebene Interrupts, für die es keine ISR gibt, werden im Fall eines
Auftreten des Ereignisses mit einem Prozessor-Reset bestraft.
Danke, für die so schnellen und hilfreichen Antworten!!!
Aber wenn ich einen extrenen Quarz mit 10MHz anschließe, ist das dann
nicht ein eigener Quarz? Und auch den Hinweis mit dem Interrupt verstehe
ich nicht ganz, ich meine, ich hab doch die Timer2 ISR behandelt...
An Walter: Ich hab den Code zwar aus einem anderen Beispiel, aber ich
hatte extra alle Register nachkontrolliert, ob die auch im Datenblatt
des ATmega32 vorhanden sind.
Trotzdem danke...
Ich teste es morgen einfach erstmal, wenn ich die zwei Zeilen streiche
und sonst lese ich mir nochmal das Datenblatt gründlicher durch. Es kann
ja nicht sein, dass mir so ein kleiner Timer ein Strich durch mein
Projekt macht...
Ich freue mich trotz der zwei hilfreichen Tipps weiter über Erklärungen
und Hinweise zu dem Fehler.
Justus schrieb:> Ich hab etwas vom CTC-Modus gelesen und versuch in meinem Code> anzuwenden aber irgendwie kommt mein Controller nicht in diesen Timer,> jedenfalls bleibt die Variable "zaehler" beim Debuggen immer "0".
Von diesem Problem abgesehen, ein Interrupt jede µS ist schlicht nicht
möglich. Deine ISR braucht auf jeden Fall immer mehr als 10 Takte.
Justus schrieb:> Danke, für die so schnellen und hilfreichen Antworten!!!> Aber wenn ich einen extrenen Quarz mit 10MHz anschließe, ist das dann> nicht ein eigener Quarz?
Das ist der Hauptquarz. Der versorgt den kompletten µC mit einem Takt.
Und an dem bedient sich auch der Timer 2 über die normalen Clock-Kanäle.
Mit einem eigenen asynchronen Quarz ist zb ein zusätzlicher 32kHz QUarz
gemeint, mit dem man den Timer 2 in die Lage versetzt, unabhängig vom
Hauptquarz zb eine Uhr zu relisieren.
> Und auch den Hinweis mit dem Interrupt verstehe> ich nicht ganz, ich meine, ich hab doch die Timer2 ISR behandelt...
Ja. Einen davon.
Du gibst aber 2 frei.
Justus schrieb:> Ich betreibe meinen ATmega32 mit einem externen 10MHz Quarz und habe> sonst eine typische Grundbeschaltung(siehe Anhang(Bild von> http://www.kreatives-chaos.com/images/37.png)).
Ähm. Die passt aber nicht zu einem Mega32
Am Mega32 sind die XTAL Pins ganz woanders.
Hey,
danke nochmal!!!
Also zusammenfassend ...
- Ich nutze keinen Asyncronen Taktgeber und setzte somit das Bit nict
- Dann muss ich wahrscheinlich mein Quarz an XTAL1 und XTAL2 klemmen,
die am Pin 12 und 13 des Controllers liegen
Zu dem Kommentar von Stefan: Wenn ich durch den Quarz jede 1/8 us ein
Impuls bekomme, und dann durch den CTC-Modus bei jedem 8 Impuls ein
Überlauf reneiere, und dann noch durch einen Zähler erst alle 4
Überläufe in den DMX-Code gehe, müsste das doch funktionieren? Oder kann
ich so schnell nicht meine Ausgänge setzen?
Danke
Justus
@Justus (Gast)
>ich bastel zur Zeit an einer DMX-Schaltung.
Schön.
>Ein DMX-Singnal muss bis zu>alle 4us den Wert am Ausgang ändern...
Komische Formulierung. Ein Bit dauert 4us, ja.
>-mein Controller empfängt das Singnal vom PC,
Welches?
>-mein Controller kann das Signal in ein DMX-Signal umwandeln>-und der MAX485 wandelt das Singnal in ein invertiertes Signal und ein>uninvertiertes Signal um.>Aber einerseits fehlt mir noch der Sendevorgang vom Controller,
Wo ist das Problem? Dein UART macht das für dich.
>Ich verstehe nicht ganz was der MAX bringen soll...
Er ist ein Pegelwandler von Single Ended CMOS auf Diffentielles
RS485 + Schutzschaltung.
>Ich könnte doch>auch einfach zwei Port von meinem Controller immer genau verkehrt>setzten
Nö, denn das müsste sinnvollerweise die UART selber machen, damit die
CPU nicht zu 1000% belastet wird. Geht aber bei keinem mir bekannten
Mikrocontroller. Braucht man auch nicht.
Ausserdem ist RS485 nicht direkt mit CMOS kompatibel, nur als Versuch im
Labor.
>Ich betreibe meinen ATmega32 mit einem externen 10MHz Quarz und habe>sonst eine typische Grundbeschaltung(siehe Anhang(Bild vonhttp://www.kreatives-chaos.com/images/37.png)).
>Ich hab etwas vom CTC-Modus gelesen und versuch in meinem Code>anzuwenden
Wozu? Das braucht man für DMX512 keine Sekunde.
>Was hab ich falsch gemacht?!?
Ja, dein Grundkonzept ist untauglich. Schau dir an, wie das andere Leute
richtig machen. Mit UART, nicht mit Pins schalten per CPU.
http://www.mikrocontroller.net/forum/codesammlung?filter=DMX
Justus schrieb:> Zu dem Kommentar von Stefan: Wenn ich durch den Quarz jede 1/8 us ein> Impuls bekomme, und dann durch den CTC-Modus bei jedem 8 Impuls ein> Überlauf reneiere, und dann noch durch einen Zähler erst alle 4> Überläufe in den DMX-Code gehe, müsste das doch funktionieren?
Nein, weil dein "Zähler" (nämlich die ISR) viel mehr als 8 Takte zur
Ausführung braucht (von der Zeit, die dein "DMX-Code" braucht, ganz zu
schweigen).
Wenn du 10 Tage brauchst, um ein Buch durchzulesen, dann kannst du nun
mal nicht alle zwei Tage ein neues anfangen.
Justus schrieb:> Hallo Leute,>> ich bastel zur Zeit an einer DMX-Schaltung. Ein DMX-Singnal muss bis zu> alle 4us den Wert am Ausgang ändern... Ich habe jetzt alle Komponeten> einzeln getestet und> -mein Controller empfängt das Singnal vom PC,> -mein Controller kann das Signal in ein DMX-Signal umwandeln> -und der MAX485 wandelt das Singnal in ein invertiertes Signal und ein> uninvertiertes Signal um.
Dann nimm einen passenden Controller mt 2 UARTs:
http://www.atmel.com/Images/doc8152.pdf
mfg.
Okay, danke
@Falk Brunner:
Danke für deine sehr präzise Antworten!!! Mein Controller empfängt
immoment die Singnale auf einem I/O Pin von einem anderen Board, welches
Daten vom PC empfängt, aber das funktionier auch alles deshalb, hab ich
es nicht näher erläutert.
Später soll mein Controller die Daten aber direkt vom PC über die
Serielle Schnittstelle empfangen und dann wären doch die beiden Pins TxD
und RxD weg. Wie soll ich dann noch den MAX485 anschließen? Aber da ich
ja jetzt vorläufig die Daten indirekt vom PC über I/O-Ports empfange,
kann ich ja den MAX erstmal an die Pins TxD und RxD schließen. Wie muss
dann der Code aufsehen? Ich hab nähmlich das Problem das in der
Codesammlung entweder nur als Empfänger fungieren oder nicht der
ATmega32 verwendet wird...
Auch danke an Stefan: Dann versteh ich dein Einwand, aber das bedeutet
ja, dass ich es entweder nur, wie Falk gesagt hat über ein ganz anderes
Verfahren laufen lassen kann, oder es gar nicht geht
Oder versteh ich da schon wieder etwas falsch?
Danke für eure Geduld, ich merke selber, dass ich mich irgentwie etwas
schwer tue, die DMX-Sendegeschichte zu verstehen!!!
Justus
Justus schrieb:> Serielle Schnittstelle empfangen und dann wären doch die beiden Pins TxD> und RxD weg. Wie soll ich dann noch den MAX485 anschließen? Aber da ich> ja jetzt vorläufig die Daten indirekt vom PC über I/O-Ports empfange,> kann ich ja den MAX erstmal an die Pins TxD und RxD schließen. Wie muss> dann der Code aufsehen? Ich hab nähmlich das Problem das in der> Codesammlung entweder nur als Empfänger fungieren oder nicht der> ATmega32 verwendet wird...
Ooch du armer.
Dann wirst du eben lernen müssen, wie man mit der UART umgeht.
Tip: Vom Prinzip her funktioniert die UART auf allen AVR identisch.
Lediglich ein paar der Konfigurationsbits mögen auf deinem System ein
wenig anders heißen (aber doch normalerweise sehr ähnlich). Hat ein AVR
2 oder mehrere UARTs, dann taucht einfach in allen Bezeichnungen (sei es
Register, sei es Bit, sei es ISR Name) die Nummer der gewünschten UART
auf.
Fertig. Das is es.
Hast du eine UART verstanden, hast du alle UARTs auf allen AVR
verstanden. Kunststück. Atmel verbaut ja im Prinzip auch die immer
gleiche Hardware-Einheit in den unterschiedlichen Prozessoren.
> Auch danke an Stefan: Dann versteh ich dein Einwand, aber das bedeutet> ja, dass ich es entweder nur, wie Falk gesagt hat über ein ganz anderes> Verfahren laufen lassen kann, oder es gar nicht geht>> Oder versteh ich da schon wieder etwas falsch?
Das verstehst du schon richtig.
Es ist ganz einfach unsinnig, für DMX etwas anderes als eine fertige
UART-Hardware im AVR zu benutzen. Punkt.
Was ist da drann so schwer zu verstehen?
> Danke für eure Geduld, ich merke selber, dass ich mich irgentwie etwas> schwer tue, die DMX-Sendegeschichte zu verstehen!!!
Das ist nicht weiter schwer.
Du konfigurierst die UART und damit die ein Byte rausbläst, weißt du es
dem UDRx Register zu. So wie im Tutorial beschrieben.
Einzig das Erzeugen des vorausgehenden Break ist ein wenig trickreicher.
Aber das kann man sich bei anderem DMX Code abschauen, wie die das
gemcht haben.
@Justus (Gast)
>Später soll mein Controller die Daten aber direkt vom PC über die>Serielle Schnittstelle empfangen und dann wären doch die beiden Pins TxD>und RxD weg.
Sicher. Dann brauchst du wie bereits gesagt einen Controller mit zwei
UARTs. Die gibt es für wenig Geld. z.B. ATmega644PA
> Wie soll ich dann noch den MAX485 anschließen?
So wie alle im Internet ;-)
An den 2. UART.
>ja jetzt vorläufig die Daten indirekt vom PC über I/O-Ports empfange,
Das nennt man Soft-UART. D.h, der UART, der eigentlich ein Stück
unabhängige Hardware auf dem Chip ist, wird durch ein Programm nur mit
CPU nachgebildet. Macht man manchmal auf kleinen uCs, wenn die keine
UART haben oder wenn es andere, exotische Gründe gibt.
Allerdings ist so eine Soft-UARt nur für moderate Baudraten sinnvoll und
belastet die CPU recht stark. Deshabl macht man das bei DMX512 nicht.
>kann ich ja den MAX erstmal an die Pins TxD und RxD schließen. Wie muss>dann der Code aufsehen?
Siehe die Millionen Beispiele im Internet.
> Ich hab nähmlich das Problem das in der>Codesammlung entweder nur als Empfänger fungieren
Es gibt auch Sender. Hab ich aber im Moment keinen Link parat.
> oder nicht der>ATmega32 verwendet wird...
Das dürfe das kleinste Problem sein. Ein paar Registernamen leicht
ändern ist keine große Sache.
>Danke für eure Geduld, ich merke selber, dass ich mich irgentwie etwas>schwer tue, die DMX-Sendegeschichte zu verstehen!!!
Ist eigentlich nicht schwer.
1.) einfacher Ansatz ohne Interrupt
1
while(1){
2
// BREAK erzeugen, DMX Zyklus fängt an
3
TXDUARTabschalten
4
PinaufLOWsetzen
5
>=88uswarten
6
PinaufHIGHsetzen
7
TXDUARTeinschalten
8
9
startbytesenden(immerNull)
10
for(i=1;i<Kanalzahl;i++){
11
KanalNsenden
12
}
13
xmswarten,umBildwiederholzeitvonDMXzuerreichen
14
}
2.) mit Interrupts, das Gleiche in grün, nur halt etwas anders
strukturiert.
Hey ich bin es nochmal: Ich hab jetzt mein ganzes Programm überarbeitet
und so erstellt, dass es sich nicht mehr aufhängt...
Leider tauchen nun zwei Fehler auf:
Erst mal muss ein Fehler in der ADC_Read liegen egal was ich an PA0 oder
PA1 anklemme es kommt immer der Wert 255 raus,
und der Zweite Fehler muss im USART liegen am TxD Pin erhalte ich immer
5V...
Mein Programablauf sollte so sein:
-Alle ~25ms alle 512 Kanäle senden, sowie ein normales DMX-Signal nun
mal ist
-Wenn ein Interrupt kommt, wir über zwei PWM-Signale der Kanal ermittelt
und an PORTB der passende Wert. Da mein Board, welches die Daten vom PC
empfängt, nur alle 20ms den Kanal neu schreiben kann, sendet es immer
nur den sich ändernden Kanal. Und da esauch nur insgesamt 10
Ausgänge(2PWM,8I/O) besitzt, muss ich mein Interrupt von irgendeinem I/O
Port auslösen lassen, der sich danach auf den Passenden Kanal-Wert
setzt(20ms Interrupt + 20ms richtig setzten. Daher meine große
"Entprell"-Zeit
Das sollte alles sein und es wäre super wenn ihr mir helfen könnt die
zwei Fehler zu finden. Ich suche heute schon den ganzen Tag und wäre
froh wenn ich mein Tag morgen etwas anders verbringen könnte... DANKE
schonmal
@ Justus (Gast)
>Hey ich bin es nochmal: Ich hab jetzt mein ganzes Programm überarbeitet>und so erstellt, dass es sich nicht mehr aufhängt...
Für den Anfang ganz OK.
>Erst mal muss ein Fehler in der ADC_Read liegen egal was ich an PA0 oder>PA1 anklemme es kommt immer der Wert 255 raus,
hast du mal mit dem Multimeter gemessen?
>und der Zweite Fehler muss im USART liegen am TxD Pin erhalte ich immer>5V...
Also Schweigen im Walde. Hmm. Schau mer mal.
>-Alle ~25ms alle 512 Kanäle senden, sowie ein normales DMX-Signal nun>mal ist
OK.
>-Wenn ein Interrupt kommt, wir über zwei PWM-Signale der Kanal ermittelt
Welcher Interrupt? Das sollte man dazu sagen.
>und an PORTB der passende Wert. Da mein Board, welches die Daten vom PC>empfängt, nur alle 20ms den Kanal neu schreiben kann, sendet es immer>nur den sich ändernden Kanal. Und da esauch nur insgesamt 10>Ausgänge(2PWM,8I/O) besitzt, muss ich mein Interrupt von irgendeinem I/O>Port auslösen lassen, der sich danach auf den Passenden Kanal-Wert>setzt(20ms Interrupt + 20ms richtig setzten. Daher meine große>"Entprell"-Zeit
Ich verstehe nur Bahnhof. Und fang erstmal EINFACHER an! Sende KONSTANTE
Daten. Keine Tasten- oder ADC Abfrage. Das kommt später!
Siehe Fehlersuche.
>Das sollte alles sein und es wäre super wenn ihr mir helfen könnt die>zwei Fehler zu finden.
Jaja, und dann ist alles perfekt ;-) Schöne Illusion.
1. Fehler. Tasten fragt man in 99% der Fälle NICHT mit einem externen
Interrupt ab, sondern zyklisch in einem Timer. Dann kann man auch die
Entprellung locker in Software machen.
> Ich suche heute schon den ganzen Tag und wäre
Mit der falschen Methode. Siehe Fehlersuche.
> #define F_CPU 10000000> #define DMX_BAUD 250000> #define myBaud (F_CPU / (DMX_BAUD_BREAK * 16L) - 1)
Falsch. Eher so.
#define myBaud (F_CPU / (DMX_BAUD * 16L) - 1)
> #define DMX_BAUD_BREAK 80000
Hier fehlt was
#define myBaudBreak (F_CPU / (DMX_BAUD_BREAK * 16L) - 1)
>//Variablen> volatile uint8_t data;> volatile unsigned char slot[512];> volatile int adc1, adc2, interrupt, zaehler;
interrupt und adc1/2 sind schlechte Variablennamen. Siehe
Strukturierte Programmierung auf Mikrocontrollern> ADCSRA |= (1<<ADSC);// eine ADC-Wandlung> while (ADCSRA & (1<<ADSC) ) {> // auf Abschluss der Konvertierung warten> }> // ADCW muss einmal gelesen werden, sonst wird Ergebnis> der nächsten Wandlung nicht übernommen.> (void) ADCW;// nach Aktivieren des ADC wird ein "Dummy->Readout" empfohlen, man liest also einen Wert und verwirft diesen, um den >ADC
"warmlaufen zu lassen"
Solche Endlosen Kommentare besser formatieren. Ausserdem wäre das alles
viel einfacher mit ADC_read(0); erledigt gewesen. Wo das doppelt
schreiben?
> //USART-Routine(DMX)> ISR(USART_TX_vect){
Das ist eigentlich der falsche Vektor. DMX sendet man eher mit dem
USART_UDRE_vect. Denn nur damit nutzt du deinen Sende-FIFO und
kannst lückenlos Daten senden. Beim Obigen Vektor gibt es erst einen
Interupt, wenn der FIOF leer ist und das letzte Zeichen komplett
gesendet wurde. Damit entstehen IMMER Lücken und man kann definitiv
nicht 40Hz bei 512 Kanälen ereichen. Für den ersten Test ist diese
Methode aber OK.
Ausserdem heißt dieser Vektor beim mega32 USART_TXC_vect. Ich wette,
dein Compiler hat eine Warnung erzeugt, die du ignoriert hast.
> switch (aufgabe)> {> case (0):> UBRRH = (unsigned char)(myBaud>>8);> UBRRL = (unsigned char)myBaud;
Hier muss myBaudBreak rein. Und wenn man anstatt einer normalen Zahl ein
enum nimmt, sind die Zustände selbsterklärend.
http://www.mikrocontroller.net/articles/Statemachine#Implementierungsvariationen> case (2):> _delay_us(10);
Das macht deine DMX Auganbe NOCH langsamer. Wozu soll das gut sein?
größee Lücken zwischen den Bytes brauchen nur schlechte DMX-Empfänger.
Einen direkten Fehler sehe ich erstmal nicht. Aber wie gesagt, lass die
ganze Eingabe erstmal weg, der UART muss erstmal laufen. Dann geht es
weiter.
Wenn ich den Vektornamen korrgiere und die das define für F_CPU VOR das
Include von delay.h schreibe, dann läuft das Programm im Simulator.
Sorry dass ich mich erst so spät melde, aber ich musste vorher noch das
Programm testen und es sind ein paar Timingprobleme aufgetaucht. Jetzt
sollte es aber funktionieren. Ich stelle bald das gesamte Programm mit
Schaltplan hoch damit ihr den die die selbe Idee haben nicht die
gleichen Fragen wie mir beantworten müsst sondern das die einfach die
Datei runterladen können Danke, noch einmal an alle, die mir geholfen
haben...
Zudem Zeitpunkt hat es noch nicht funktioniert, nur an alle nach
folgenden DMX-Interfacebauer: IHR MÜSST EIN 8MHZ QUARZ VERWENDEN. Ich
saß an diesem Projekt jetzt bis gerade und hab alles ausprobiert. Es lag
nicht am Code. ES LAG AN DIESEM S***** Quarz. Sorry, für die
Ausdrucksweise, aber ich bin gerade echt erleichtert.