Forum: Mikrocontroller und Digitale Elektronik DMX-Slave ATmega644P


von Olli (Gast)


Lesenswert?

Hallo,

ich möchte den Code von hier:

http://www.hoelscher-hi.de/hendrik/light/ressources.htm

auf einen ATmega644P portieren.

Ich habe dabei die Register nach bestem Wissen angepasst. Aber ihr 
Experten seht vermutlich auf den ersten Blick an welcher Stelle mir der 
Fehler unterlaufen ist.

Hier der Original-Code der Datei

lib_dmx_in.h
1
#include <avr/io.h>
2
#include <stdint.h>
3
#include <avr/interrupt.h>
4
5
6
#define USE_DIP                //use DIPs?
7
#define DMX_CHANNELS    (2)          //use at least 2ch
8
#define F_OSC      (8000)          //oscillator freq. in kHz (typical 8MHz or 16MHz)
9
10
11
volatile uint8_t   DmxField[DMX_CHANNELS]; //array of DMX vals (raw)
12
volatile uint16_t   DmxAddress;      //start address
13
14
extern void init_DMX(void);
15
extern void get_dips(void);

lib_dmx_in.c
1
/**** A P P L I C A T I O N   N O T E   ************************************
2
*
3
* Title      : DMX512 reception library
4
* Version    : v1.2
5
* Last updated  : 21.04.07
6
* Target    : Transceiver Rev.3.01 [ATmega8515]
7
* Clock      : 8MHz, 16MHz
8
*
9
* written by hendrik hoelscher, www.hoelscher-hi.de */
10
#include "lib_dmx_in.h"
11
// ********************* local definitions *********************
12
13
14
enum {IDLE, BREAK, STARTB, STARTADR};      //DMX states
15
16
     uint8_t    gDmxState;
17
     uint8_t   *gDmxPnt;
18
     uint16_t   DmxCount;
19
20
// *************** DMX Reception Initialisation ****************
21
void init_DMX(void)
22
{
23
#ifdef USE_DIP
24
DDRC= 0;                    //set up DIPs
25
PORTC= 0xFF;
26
DDRE &= ~((1<<2)|(1<<1));
27
PORTE |= (1<<2)|(1<<1);
28
#endif
29
30
DDRD |= (1<<2);
31
PORTD &= ~(1<<2);                //enable reception
32
UBRRH  = 0;
33
UBRRL  = ((F_OSC/4000)-1);            //250kbaud, 8N2
34
UCSRC |= (1<<URSEL)|(3<<UCSZ0)|(1<<USBS);
35
UCSRB |= (1<<RXEN)|(1<<RXCIE);
36
gDmxState= IDLE;
37
38
uint8_t i;
39
for (i=0; i<DMX_CHANNELS; i++)
40
  {
41
  DmxField[i]= 0;
42
  }
43
44
}
45
46
// ************* get DMX start address **************
47
48
void get_dips(void)
49
{
50
#ifdef USE_DIP
51
uint16_t Temp= (255-PINC);            //invert DIP state
52
if (!(PINE &(1<<2)))
53
  {
54
  Temp= Temp +256;              //9th bit
55
  }
56
57
if (Temp != 0)
58
  {
59
  DmxAddress= Temp;
60
  if (!(UCSRB &(1<<RXCIE)))          //if receiver was disabled -> enable and wait for break
61
    {
62
    gDmxState= IDLE;
63
    UCSRB |= (1<<RXCIE);
64
    }
65
  }
66
else
67
  {
68
  UCSRB &= ~(1<<RXCIE);            //disable Receiver if start address = 0
69
  for (Temp=0; Temp<DMX_CHANNELS; Temp++)
70
    {
71
    DmxField[Temp]= 0;
72
    }
73
  }
74
#endif 
75
}
76
77
// *************** DMX Reception ISR ****************
78
ISR (UART_RX_vect)
79
{
80
uint8_t USARTstate= UCSRA;            //get state
81
uint8_t DmxByte= UDR;              //get data
82
uint8_t DmxState= gDmxState;          //just get once from SRAM!!!
83
 
84
if (USARTstate &(1<<FE))            //check for break
85
  {
86
  UCSRA &= ~(1<<FE);              //reset flag
87
  DmxCount= DmxAddress;            //reset frame counter
88
  gDmxState= BREAK;
89
  }
90
91
else if (DmxState == BREAK)
92
  {
93
  if (DmxByte == 0) 
94
    {
95
    gDmxState= STARTB;            //normal start code detected
96
    gDmxPnt= ((uint8_t*)DmxField +1);
97
    }
98
  else gDmxState= IDLE;
99
  }
100
101
else if (DmxState == STARTB)
102
  {
103
  if (--DmxCount == 0)            //start address reached?
104
    {
105
    gDmxState= STARTADR;
106
    DmxField[0]= DmxByte;
107
    }
108
  }
109
110
else if (DmxState == STARTADR)
111
  {
112
  uint8_t *DmxPnt;
113
  DmxPnt= gDmxPnt;
114
  *DmxPnt= DmxByte;
115
  if (++DmxPnt >= (DmxField +DMX_CHANNELS))   //all ch received?
116
    {
117
    gDmxState= IDLE;
118
    }
119
  else gDmxPnt= DmxPnt;
120
  }              
121
}

Und hier meine angepassten Versionen für den ATmega644P

lib_dmx_in.h
1
#include <avr/io.h>
2
#include <stdint.h>
3
#include <avr/interrupt.h>
4
5
//#define USE_DIP                //use DIPs?
6
#define DMX_CHANNELS    (2)          //use at least 2ch
7
#define F_OSC      (14746)          //oscillator freq. in kHz (typical 8MHz or 16MHz)
8
9
volatile uint8_t   DmxField[DMX_CHANNELS]; //array of DMX vals (raw)
10
volatile uint16_t   DmxAddress;      //start address
11
12
extern void init_DMX(void);
13
extern void get_dips(void);

lib_dmx_in.c
1
/**** A P P L I C A T I O N   N O T E   ************************************
2
*
3
* Title      : DMX512 reception library
4
* Version    : v1.2
5
* Last updated  : 21.04.07
6
* Target    : Transceiver Rev.3.01 [ATmega8515]
7
* Clock      : 8MHz, 16MHz
8
*
9
* written by hendrik hoelscher, www.hoelscher-hi.de
10
***************************************************************************
11
 This program is free software; you can redistribute it and/or
12
 modify it under the terms of the GNU General Public License
13
 as published by the Free Software Foundation; either version2 of
14
 the License, or (at your option) any later version.
15
16
 This program is distributed in the hope that it will be useful,
17
 but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19
 General Public License for more details.
20
21
 If you have no copy of the GNU General Public License, write to the
22
 Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
24
 For other license models, please contact the author.
25
26
;***************************************************************************/
27
28
#include <avr/io.h>
29
#include "lib_dmx_in.h"
30
31
// ********************* local definitions *********************
32
33
enum {IDLE, BREAK, STARTB, STARTADR};      //DMX states
34
35
     uint8_t    gDmxState;
36
     uint8_t   *gDmxPnt;
37
     uint16_t   DmxCount;
38
39
40
// *************** DMX Reception Initialisation ****************
41
void init_DMX(void)
42
{
43
#ifdef USE_DIP
44
DDRC= 0;                    //set up DIPs
45
PORTC= 0xFF;
46
DDRE &= ~((1<<2)|(1<<1));
47
PORTE |= (1<<2)|(1<<1);
48
#endif
49
50
DDRD |= (1<<2);
51
PORTD &= ~(1<<2);                //enable reception
52
//UBRRH  = 0;
53
UBRR0H = 0;  // NEW
54
//UBRRL  = ((F_OSC/4000)-1);            //250kbaud, 8N2
55
UBRR0L  = ((F_OSC/4000)-1); // NEW            //250kbaud, 8N2
56
//UCSRC |= (1<<URSEL)|(3<<UCSZ0)|(1<<USBS);
57
UCSR0C |= (3<<UCSZ01)|(1<<USBS0); // NEW
58
//UCSRB |= (1<<RXEN)|(1<<RXCIE);
59
UCSR0B |= (1<<RXEN0)|(1<<RXCIE0);  // NEW
60
gDmxState= IDLE;
61
62
uint8_t i;
63
for (i=0; i<DMX_CHANNELS; i++)
64
  {
65
  DmxField[i]= 0;
66
  }
67
68
}
69
70
71
// ************* get DMX start address **************
72
void get_dips(void)
73
{
74
#ifdef USE_DIP
75
uint16_t Temp= (255-PINC);            //invert DIP state
76
if (!(PINE &(1<<2)))
77
  {
78
  Temp= Temp +256;              //9th bit
79
  }
80
if (Temp != 0)
81
  {
82
  DmxAddress= Temp;
83
  if (!(UCSRB &(1<<RXCIE)))          //if receiver was disabled -> enable and wait for break
84
    {
85
    gDmxState= IDLE;
86
    UCSRB |= (1<<RXCIE);
87
    }
88
  }
89
else
90
  {
91
  UCSRB &= ~(1<<RXCIE);            //disable Receiver if start address = 0
92
  for (Temp=0; Temp<DMX_CHANNELS; Temp++)
93
    {
94
    DmxField[Temp]= 0;
95
    }
96
  }
97
#endif
98
  DmxAddress = 1;
99
}
100
101
102
// *************** DMX Reception ISR ****************
103
ISR (USART0_RX_vect)
104
{
105
//uint8_t USARTstate= UCSRA;            //get state
106
uint8_t USARTstate= UCSR0A;  //NEW            //get state
107
//uint8_t DmxByte= UDR;              //get data
108
uint8_t DmxByte= UDR0;    // NEW          //get data
109
uint8_t DmxState= gDmxState;          //just get once from SRAM!!!
110
111
//if (USARTstate &(1<<FE))            //check for break
112
if (USARTstate &(1<<FE0)) // NEW            //check for break
113
  {
114
  //UCSRA &= ~(1<<FE);              //reset flag
115
  UCSR0A &= ~(1<<FE0);  //NEW            //reset flag
116
  DmxCount= DmxAddress;            //reset frame counter
117
  gDmxState= BREAK;
118
  }
119
120
else if (DmxState == BREAK)
121
  {
122
  if (DmxByte == 0)
123
    {
124
    gDmxState= STARTB;            //normal start code detected
125
    gDmxPnt= ((uint8_t*)DmxField +1);
126
    }
127
  else gDmxState= IDLE;
128
  }
129
130
else if (DmxState == STARTB)
131
  {
132
  if (--DmxCount == 0)            //start address reached?
133
    {
134
    gDmxState= STARTADR;
135
    DmxField[0]= DmxByte;
136
    }
137
  }
138
139
else if (DmxState == STARTADR)
140
  {
141
  uint8_t *DmxPnt;
142
  DmxPnt= gDmxPnt;
143
  *DmxPnt= DmxByte;
144
  if (++DmxPnt >= (DmxField +DMX_CHANNELS))   //all ch received?
145
    {
146
    gDmxState= IDLE;
147
    }
148
  else gDmxPnt= DmxPnt;
149
  }
150
}

Zu meiner Schaltung
Ich verwende einen 14.7456 MHz-Quarz und den 71576B als Wandlerchip von 
RS485 nach RS232 an der UART-Schnittstelle.

Verbunden habe ich so (Chip -- Mikrocontroller):
RE -- INT0
DE -- INT0
R  -- RXD
D  -- TXD

Leider togglet PD7 nicht, wenn ich an meinem DMX-Mischpult die Regler 
rauf- und runterfahre (habe einen PAR64-LED zur Kontrolle 
angeschlossen). Ich steuere mit dem Pult die Kanäle 1 bis 6. Als 
DMX-Adresse habe ich in der Funktion get_dips() die eins (1) 
eingestellt.

Wo sind die Fehler in meiner Portierung?

Achja: Die main-Datei ist in der portierten Version nicht verändert 
worden:
1
#include "lib_dmx_in.h"
2
3
int main(void)
4
{
5
cli();
6
DDRD |= (1<<PD7);          //red LED pin is output
7
init_DMX();
8
sei();
9
10
for(;;)
11
  {
12
  get_dips();
13
  if (DmxField[0] >= 127)      //enable LED if 1st DMX val is >127
14
    {
15
    PORTD &= ~(1<<PD7);      //LED ON
16
    }
17
  else
18
    {
19
    PORTD |= (1<<PD7);      //LED OFF
20
    }
21
  }
22
}

von Oliver (Gast)


Lesenswert?

Wo ist die Nadel im Heuhaufen? Sorry, aber hier im Browser kann man das 
doch so nicht finden.

Kompilierbare Dateien + makefile zusammenzippen und als Dateianhang 
anhängen.

Oliver

von Olli (Gast)


Angehängte Dateien:

Lesenswert?

Original-Version

von Olli (Gast)


Angehängte Dateien:

Lesenswert?

Portierte Version

von Olli (Gast)


Lesenswert?

Der Bereich im Heuhaufen, in dem ich vermute, dass sich die Nadel 
befindet, ist folgender (portierte Version):
1
void init_DMX(void)
2
{
3
  DDRD     |=  (1<<2);
4
  PORTD    &= ~(1<<2);         //enable reception
5
  UBRR0H    = 0;
6
  UBRR0L    = ((F_OSC/4000)-1);      //250kbaud, 8N2
7
  UCSR0C   |= (3<<UCSZ01) | (1<<USBS0);
8
  UCSR0B   |= (1<<RXEN0)  | (1<<RXCIE0);
9
  gDmxState = IDLE;
10
11
  uint8_t i;
12
  for (i=0; i<DMX_CHANNELS; i++)
13
  {
14
    DmxField[i]= 0;
15
  }
16
}

Ich vermute, dass ich irgendwelche Register verwurschtelt habe.

von Olli (Gast)


Lesenswert?

Eine Kleinigkeit habe ich noch gefunden. Leider befinden sich wohl noch 
mehr Fehler im Code... :-(

Korrektur
1
UCSR0C |= (3<<UCSZ01)|(1<<USBS0);
wird zu
1
UCSR0C |= (3<<UCSZ00)|(1<<USBS0);

von Olli (Gast)


Lesenswert?

Falscher Oszillator?

Kann es sein, dass ich mit einem 14.7456MHz-Quarz keine 250kBit BAUD 
verwenden kann?

von Falk B. (falk)


Lesenswert?

@  Olli (Gast)

>Kann es sein, dass ich mit einem 14.7456MHz-Quarz keine 250kBit BAUD
>verwenden kann?

Wird eng, macht einen systematischen Fehler von 1,7%.

Siehe Baudratenquarz

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.