Forum: Mikrocontroller und Digitale Elektronik Atmega32A DMX senden


von Luca E. (derlucae98)


Angehängte Dateien:

Lesenswert?

Hallo,

für ein Projekt versuche ich DMX Daten mit einem Atmega32A zu senden. 
Ich verwende die Senderoutine von Ulrich Radig 
(https://www.ulrichradig.de/home/index.php/avr/atmega8-experimentierboard/avr---dmx), 
die für einen Atmega88 geschrieben ist und versuche sie für den 
Atmega32A anzupassen.
Als Takt nutze ich einen 16MHz Quarz, weil der Atmega gleichzeitig noch 
MIDI Daten per Software UART empfangen soll.
Auf einem Atmega328 funktioniert das senden, auf dem Atmega32A bekomme 
ich es jedoch nicht zum laufen.

Folgendes habe ich angepasst:
Statt des UBRR0 Registers beschreibe ich das UBRRL Register mit der 
berechneten Baudrate. Da im UBRRH Register sowieso 0 steht, beschreibe 
ich es nicht.
UCSR0B habe ich zu UCSRB geändert, UCSR0C habe ich zu UCSRC geändert und 
das URSEL Bit gesetzt, um ins UCSRC Regsiter zu schreiben.
Den Interruptvektor habe ich von USART_TX_vect zu USART_TXC_vect 
geändert.

Aus dem UART kommt zwar etwas raus, allerdings scheinen es keine 
verwertbaren DMX Daten zu sein.
Ich habe leider keinen Bus Decoder, nur eine DMX Lampe zum testen.

Die Fuses sind richtig gesetzt und der Atmega läuft nachweislich mit den 
16MHz.

Nach mehreren Stunden vergeblicher Fehlersuche gehen mir die Ideen 
aus...

Wo liegt der Fehler?

Code:
1
#define F_CPU 16000000L
2
#include <avr/interrupt.h>
3
#include <avr/io.h>
4
#include <stdio.h>
5
#include <util/delay.h>
6
7
#define DMX_BAUD 250000
8
#define DMX_BAUD_BREAK 80000
9
10
volatile unsigned char dmx_buffer[512];
11
12
13
//DMX Senderoutine
14
ISR (USART_TXC_vect)
15
{
16
    static unsigned int  dmx_channel_tx_count = 0;
17
    static unsigned char dmx_tx_state = 0;
18
  
19
    switch (dmx_tx_state)
20
    {
21
        case (0):
22
        UBRRL = (F_CPU / (DMX_BAUD_BREAK * 16L) - 1);
23
        UDR = 0; //RESET Frame
24
        dmx_tx_state = 1;
25
        break;
26
27
        case (1):
28
        UBRRL = (F_CPU / (DMX_BAUD * 16L) - 1);
29
        UDR = 0; //Start Byte
30
        dmx_tx_state = 2;
31
        break;
32
33
        case (2):
34
        _delay_us(10);
35
        //Ausgabe des Zeichens
36
        UDR = dmx_buffer[dmx_channel_tx_count];
37
        dmx_channel_tx_count++;
38
        
39
        if(dmx_channel_tx_count == 512)
40
        {
41
            dmx_channel_tx_count = 0;
42
            dmx_tx_state = 0;
43
        }
44
        break;
45
    }
46
}
47
48
49
50
int main(void)
51
{
52
    DDRA = 0b11111111;
53
    DDRB = 0b11111111;
54
    DDRC = 0b11111111;
55
    DDRD = 0b11111010;
56
  
57
    //Init usart DMX-BUS
58
    UBRRL = (F_CPU / (DMX_BAUD * 16L) - 1);
59
    UCSRB |= (1 << TXEN)|(1 << TXCIE); // TXEN Transmitter enable / TXCIE TX complete interrupt enable
60
    UCSRC |= (1 << URSEL) | (1<<USBS); //USBS 2 Stop bits
61
    sei();//Globale Interrupts Enable
62
    UDR = 0;//Start DMX
63
  
64
    while(1)
65
    {
66
        dmx_buffer[1]=255;
67
    }
68
}

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Luca E. schrieb:
> Wo liegt der Fehler?

 Warum probierst du nicht einfach:
1
  UBRRL = 3;

von Luca E. (derlucae98)


Lesenswert?

Marc V. schrieb:
> Warum probierst du nicht einfach:  UBRRL = 3;

Funktioniert leider genauso wenig.

von Dirk B. (Gast)


Lesenswert?

Luca E. schrieb:
>     UCSRC |= (1 << URSEL) | (1<<USBS); //USBS 2 Stop bits
zur Sicherheit falls der Compiler UCSRC=UBRRH lesen sollte
UCSRC = (1 << URSEL) | (1<<USBS)|(1 << UCSZ1) (1 <<UCSZ0); //8n2
(auch nur als Test-Idee)

von spess53 (Gast)


Lesenswert?

Hi

> Warum probierst du nicht einfach:

>  UBRRL = 3;

zum Schreiben muss erst UBRRH, dann UBRRL beschrieben werden. Oder 
einfacher

in C: UBRR = ... .

Mfg Spess

von Christian S. (roehrenvorheizer)


Lesenswert?

"The UBRRH Register shares the same I/O location as the UCSRC Register. 
Therefore some special consideration must be taken when accessing this 
I/O location.

Accessing UBRRH/ UCSRC Registers


Write Access When doing a write access of this I/O location, the high 
bit of the value written, the USART Reg- ister Select (URSEL) bit, 
controls which one of the two registers that will be written. If URSEL 
is zero during a write operation, the UBRRH value will be updated. If 
URSEL is one, the UCSRC setting will be updated."

von Luca E. (derlucae98)


Lesenswert?

Dirk B. schrieb:
> zur Sicherheit falls der Compiler UCSRC=UBRRH lesen sollte
> UCSRC = (1 << URSEL) | (1<<USBS)|(1 << UCSZ1) (1 <<UCSZ0); //8n2
> (auch nur als Test-Idee)

Danke, nun funktioniert es. ;-)
Ich frage mich allerdings, warum es im Original ohne gesetzte UCSZ0 und 
UCSZ1 Bits funktioniert. Wenn diese nicht gesetzt sind, werden ja nur 5 
Bit pro Zeichen übertragen.

von Dirk B. (Gast)


Lesenswert?

Im 'Original' ist UCSCR ein konventionelles Register und die übliche 
(und wohl auch sinnvolle) Vorgehensweise nur das zu ändern was gerade 
geändert werden soll (also original-Wert|= bit) funktioniert, im 
speziellen Register wird wirklich UBRH gelesen (0)

Vom Prinzip wäre für das Register ein esoterischer Compiler notwendig, 
der je nach Benennung des Registers anderen Code erzeugt oder für das 
Register 4 Makros (UBRH_r,UBRH_w,UCSRC_r,UCSRC_w) verwendet... kurz: als 
zwangsläufige/unvermeidbare Fehlerquelle hat das Register durchaus 
Unterhaltungscharakter, wenn Fehlersuche nicht auch etwas 
Rätselcharakter hat dann sind die Stunden natürlich nur ärgerlich.

von Luca E. (derlucae98)


Lesenswert?

Müsste der Code nicht auch 1:1 auf einem Atmega32 (ohne A) 
funktionieren? Die Register sind ja gleich.

Es kommen nur verwertbare Daten aus dem UART, wenn ich den Wert 255 oder 
0 sende. Alle anderen Zwischenwerte sorgen dafür, dass die Lampe 
entweder kein DMX Signal erkennt oder flackert.
Auch dieser Atmega läuft mit 16MHz (geprüft). Der MAX485 gibt auch 
saubere Signale aus.
Ich kann es mir nicht erklären.

von Dirk B. (Gast)


Lesenswert?

Luca E. schrieb:
> Müsste der Code nicht auch 1:1 auf einem Atmega32 (ohne A)
> funktionieren? Die Register sind ja gleich.
Eigentlich schon....vielleicht wäre das der Moment doch nicht nur eine 
Lampe zum Thema was gesendet wird zu befragen: viele USB-TTL-Rs232 
können auch 250k, bei hterm u.ä. Programmen lässt die Baudrate auch frei 
einstellen (Senden dann natürlich nur einmal )

> Es kommen nur verwertbare Daten aus dem UART, wenn ich den Wert 255 oder
> 0 sende. Alle anderen Zwischenwerte sorgen dafür, dass die Lampe
> entweder kein DMX Signal erkennt oder flackert.
Flackern würde bedeuten bei jedem Durchlauf würde was anderes gesendet. 
Wenn die Lampe und Leitung stabil sind würde als unregelmäßige 
Fehlerquelle u.U. ein Watchdog-timer in Frage kommen der den µC 
neustartet.

Zur Fehlereingrenzung evtl. auch erstmal mit dem Atmega32a die Lampe 
prüfen: (dmx_buffer[1]=255 ist DMX-Kanal 2 )
if(dmx_channel_tx_count == 512)
-->if(dmx_channel_tx_count == 16)// nur Kanal 1-16 und
dmx_buffer[0]=16;
...
dmx_buffer[15]=255;// alle 16 Kanäle mit unterschiedlichen Daten testen

von Luca E. (derlucae98)


Lesenswert?

Scheint ein Hardwareproblem gewesen zu sein. Habe gerade die Platine für 
das Projekt geätzt und bestückt und den Mega32 von meinem Prototypen auf 
die Platine gesteckt.
Läuft einwandfrei.
Jetzt wundert mich allerdings, warum ich mit der selben Hardware 
problemlos MIDI-Daten versenden konnte...

von Dirk B. (Gast)


Lesenswert?

vielleicht der alte Trick für spannende Fehlersuchen:
kein Vcc--> der µC versorgt sich notdürftig über eine Datenleitung und 
verhält sich unauffällig--> Dmx sendet 0[break],255,0,....,0[*254] 
(ca.70%low-Anteil) --> Notversorgung bricht trotz Abblockkondensatoren 
etc. zusammen --> manchmal reicht es um die Lampe noch (richtig) zu 
informieren; wie die Lampe 0 empfangen hat bleibt deren Geheimnis (oder 
so ähnlich)

von Luca E. (derlucae98)


Lesenswert?

Dirk B. schrieb:
> kein Vcc--> der µC versorgt sich notdürftig über eine Datenleitung

Ich hatte auch die Versorgung im Verdacht, weil ich den Prototypen über 
den USB Port gespeist hatte. Auf dem Oszi war die Versorgung absolut 
sauber und auch mit externer Versorgung über das Labornetzteil hat es 
nicht funktioniert.

Dirk B. schrieb:
> Wie die Lampe 0 empfangen hat bleibt deren Geheimnis (oder
> so ähnlich)

Der Laie staunt, der Fachmann wundert sich. ;-)

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Dirk B. schrieb:
> if(dmx_channel_tx_count == 512)
> -->if(dmx_channel_tx_count == 16)// nur Kanal 1-16 und
> dmx_buffer[0]=16;

Das muss nicht klappen, denn bei DMX müssen mindestens 24 Kanäle 
gesendet werden, damit die minimale Break-to-Break Time nicht 
unterschritten wird.

Das stört viele Empfänger nicht, aber einige doch:
https://en.wikipedia.org/wiki/DMX512#Timing

von Dirk B. (Gast)


Lesenswert?

Matthias S. schrieb:
> Dirk B. schrieb:
>Leseproblem(Mathias WS.):[Zur Fehlereingrenzung evtl. auch erstmal mit dem 
Atmega32a die Lampe
prüfen:]
>> if(dmx_channel_tx_count == 512)
>> -->if(dmx_channel_tx_count == 16)// nur Kanal 1-16 und
>> dmx_buffer[0]=16;
>
> Das muss nicht klappen, ...
Da hast du dich etwas zu spät zugeschaltet: es klappte bereits vorher 
nicht.
Beim einmaligen senden brauchst du auch keine Angst um die 
Break-to-Break Time haben ;-)

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Dirk B. schrieb:
> Da hast du dich etwas zu spät zugeschaltet: es klappte bereits vorher
> nicht.

Schön und gut, mit dem Vorschlag hätte man sich aber eine weitere 
Baustelle eröffnet und mögl. den grundlegenden Fehler verschüttet. Muss 
ja nicht sein.

von Dirk B. (Gast)


Lesenswert?

Matthias S. schrieb:
> Dirk B. schrieb:
>> Da hast du dich etwas zu spät zugeschaltet: es klappte bereits vorher
>> nicht.
>>[Beim einmaligen senden...]
>
> Schön und gut, mit dem Vorschlag hätte man sich aber eine weitere
> Baustelle eröffnet und mögl. den grundlegenden Fehler verschüttet.
Nein man hätte mit einem Test keine weitere Baustelle eröffnet. In 
Systemen in denen Forentexte bereits nur teilweise empfangen werden 
können mag das natürlich anders sein.

Wenn beim System von Matthias S. die Baudrate nicht richtig eingestellt 
ist und er deswegen von einem sog. "grundlegenden" Fehler fabulieren 
muss, dann hat das System einfach keinen barrierefreien Zugang zu den 
Texten auf die das System von Matthias S. reagiert.

Wenn Mathias S. ohne fremde Hilfe den verlinkten Wikipediartikel lesen 
könnte und von
Matthias S. schrieb im Beitrag
> Das stört viele Empfänger nicht, aber einige doch:
einen(1) Empfänger nennen könnte, dann müsste er nicht über mögliche 
sog. "grundlegende" Fehler spekulieren ;-)

Einfach mal einen konkreten Anfang ausprobieren ... Viel Glück

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.