mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik DMX-Slave ATmega644P


Autor: Olli (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>


#define USE_DIP                //use DIPs?
#define DMX_CHANNELS    (2)          //use at least 2ch
#define F_OSC      (8000)          //oscillator freq. in kHz (typical 8MHz or 16MHz)


volatile uint8_t   DmxField[DMX_CHANNELS]; //array of DMX vals (raw)
volatile uint16_t   DmxAddress;      //start address

extern void init_DMX(void);
extern void get_dips(void);

lib_dmx_in.c
/**** A P P L I C A T I O N   N O T E   ************************************
*
* Title      : DMX512 reception library
* Version    : v1.2
* Last updated  : 21.04.07
* Target    : Transceiver Rev.3.01 [ATmega8515]
* Clock      : 8MHz, 16MHz
*
* written by hendrik hoelscher, www.hoelscher-hi.de */
#include "lib_dmx_in.h"
// ********************* local definitions *********************


enum {IDLE, BREAK, STARTB, STARTADR};      //DMX states

     uint8_t    gDmxState;
     uint8_t   *gDmxPnt;
     uint16_t   DmxCount;

// *************** DMX Reception Initialisation ****************
void init_DMX(void)
{
#ifdef USE_DIP
DDRC= 0;                    //set up DIPs
PORTC= 0xFF;
DDRE &= ~((1<<2)|(1<<1));
PORTE |= (1<<2)|(1<<1);
#endif

DDRD |= (1<<2);
PORTD &= ~(1<<2);                //enable reception
UBRRH  = 0;
UBRRL  = ((F_OSC/4000)-1);            //250kbaud, 8N2
UCSRC |= (1<<URSEL)|(3<<UCSZ0)|(1<<USBS);
UCSRB |= (1<<RXEN)|(1<<RXCIE);
gDmxState= IDLE;

uint8_t i;
for (i=0; i<DMX_CHANNELS; i++)
  {
  DmxField[i]= 0;
  }

}

// ************* get DMX start address **************

void get_dips(void)
{
#ifdef USE_DIP
uint16_t Temp= (255-PINC);            //invert DIP state
if (!(PINE &(1<<2)))
  {
  Temp= Temp +256;              //9th bit
  }

if (Temp != 0)
  {
  DmxAddress= Temp;
  if (!(UCSRB &(1<<RXCIE)))          //if receiver was disabled -> enable and wait for break
    {
    gDmxState= IDLE;
    UCSRB |= (1<<RXCIE);
    }
  }
else
  {
  UCSRB &= ~(1<<RXCIE);            //disable Receiver if start address = 0
  for (Temp=0; Temp<DMX_CHANNELS; Temp++)
    {
    DmxField[Temp]= 0;
    }
  }
#endif 
}

// *************** DMX Reception ISR ****************
ISR (UART_RX_vect)
{
uint8_t USARTstate= UCSRA;            //get state
uint8_t DmxByte= UDR;              //get data
uint8_t DmxState= gDmxState;          //just get once from SRAM!!!
 
if (USARTstate &(1<<FE))            //check for break
  {
  UCSRA &= ~(1<<FE);              //reset flag
  DmxCount= DmxAddress;            //reset frame counter
  gDmxState= BREAK;
  }

else if (DmxState == BREAK)
  {
  if (DmxByte == 0) 
    {
    gDmxState= STARTB;            //normal start code detected
    gDmxPnt= ((uint8_t*)DmxField +1);
    }
  else gDmxState= IDLE;
  }

else if (DmxState == STARTB)
  {
  if (--DmxCount == 0)            //start address reached?
    {
    gDmxState= STARTADR;
    DmxField[0]= DmxByte;
    }
  }

else if (DmxState == STARTADR)
  {
  uint8_t *DmxPnt;
  DmxPnt= gDmxPnt;
  *DmxPnt= DmxByte;
  if (++DmxPnt >= (DmxField +DMX_CHANNELS))   //all ch received?
    {
    gDmxState= IDLE;
    }
  else gDmxPnt= DmxPnt;
  }              
}

Und hier meine angepassten Versionen für den ATmega644P

lib_dmx_in.h
#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>

//#define USE_DIP                //use DIPs?
#define DMX_CHANNELS    (2)          //use at least 2ch
#define F_OSC      (14746)          //oscillator freq. in kHz (typical 8MHz or 16MHz)

volatile uint8_t   DmxField[DMX_CHANNELS]; //array of DMX vals (raw)
volatile uint16_t   DmxAddress;      //start address

extern void init_DMX(void);
extern void get_dips(void);

lib_dmx_in.c
/**** A P P L I C A T I O N   N O T E   ************************************
*
* Title      : DMX512 reception library
* Version    : v1.2
* Last updated  : 21.04.07
* Target    : Transceiver Rev.3.01 [ATmega8515]
* Clock      : 8MHz, 16MHz
*
* written by hendrik hoelscher, www.hoelscher-hi.de
***************************************************************************
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version2 of
 the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 General Public License for more details.

 If you have no copy of the GNU General Public License, write to the
 Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

 For other license models, please contact the author.

;***************************************************************************/

#include <avr/io.h>
#include "lib_dmx_in.h"

// ********************* local definitions *********************

enum {IDLE, BREAK, STARTB, STARTADR};      //DMX states

     uint8_t    gDmxState;
     uint8_t   *gDmxPnt;
     uint16_t   DmxCount;


// *************** DMX Reception Initialisation ****************
void init_DMX(void)
{
#ifdef USE_DIP
DDRC= 0;                    //set up DIPs
PORTC= 0xFF;
DDRE &= ~((1<<2)|(1<<1));
PORTE |= (1<<2)|(1<<1);
#endif

DDRD |= (1<<2);
PORTD &= ~(1<<2);                //enable reception
//UBRRH  = 0;
UBRR0H = 0;  // NEW
//UBRRL  = ((F_OSC/4000)-1);            //250kbaud, 8N2
UBRR0L  = ((F_OSC/4000)-1); // NEW            //250kbaud, 8N2
//UCSRC |= (1<<URSEL)|(3<<UCSZ0)|(1<<USBS);
UCSR0C |= (3<<UCSZ01)|(1<<USBS0); // NEW
//UCSRB |= (1<<RXEN)|(1<<RXCIE);
UCSR0B |= (1<<RXEN0)|(1<<RXCIE0);  // NEW
gDmxState= IDLE;

uint8_t i;
for (i=0; i<DMX_CHANNELS; i++)
  {
  DmxField[i]= 0;
  }

}


// ************* get DMX start address **************
void get_dips(void)
{
#ifdef USE_DIP
uint16_t Temp= (255-PINC);            //invert DIP state
if (!(PINE &(1<<2)))
  {
  Temp= Temp +256;              //9th bit
  }
if (Temp != 0)
  {
  DmxAddress= Temp;
  if (!(UCSRB &(1<<RXCIE)))          //if receiver was disabled -> enable and wait for break
    {
    gDmxState= IDLE;
    UCSRB |= (1<<RXCIE);
    }
  }
else
  {
  UCSRB &= ~(1<<RXCIE);            //disable Receiver if start address = 0
  for (Temp=0; Temp<DMX_CHANNELS; Temp++)
    {
    DmxField[Temp]= 0;
    }
  }
#endif
  DmxAddress = 1;
}


// *************** DMX Reception ISR ****************
ISR (USART0_RX_vect)
{
//uint8_t USARTstate= UCSRA;            //get state
uint8_t USARTstate= UCSR0A;  //NEW            //get state
//uint8_t DmxByte= UDR;              //get data
uint8_t DmxByte= UDR0;    // NEW          //get data
uint8_t DmxState= gDmxState;          //just get once from SRAM!!!

//if (USARTstate &(1<<FE))            //check for break
if (USARTstate &(1<<FE0)) // NEW            //check for break
  {
  //UCSRA &= ~(1<<FE);              //reset flag
  UCSR0A &= ~(1<<FE0);  //NEW            //reset flag
  DmxCount= DmxAddress;            //reset frame counter
  gDmxState= BREAK;
  }

else if (DmxState == BREAK)
  {
  if (DmxByte == 0)
    {
    gDmxState= STARTB;            //normal start code detected
    gDmxPnt= ((uint8_t*)DmxField +1);
    }
  else gDmxState= IDLE;
  }

else if (DmxState == STARTB)
  {
  if (--DmxCount == 0)            //start address reached?
    {
    gDmxState= STARTADR;
    DmxField[0]= DmxByte;
    }
  }

else if (DmxState == STARTADR)
  {
  uint8_t *DmxPnt;
  DmxPnt= gDmxPnt;
  *DmxPnt= DmxByte;
  if (++DmxPnt >= (DmxField +DMX_CHANNELS))   //all ch received?
    {
    gDmxState= IDLE;
    }
  else gDmxPnt= DmxPnt;
  }
}

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:
#include "lib_dmx_in.h"

int main(void)
{
cli();
DDRD |= (1<<PD7);          //red LED pin is output
init_DMX();
sei();

for(;;)
  {
  get_dips();
  if (DmxField[0] >= 127)      //enable LED if 1st DMX val is >127
    {
    PORTD &= ~(1<<PD7);      //LED ON
    }
  else
    {
    PORTD |= (1<<PD7);      //LED OFF
    }
  }
}

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Olli (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Original-Version

Autor: Olli (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Portierte Version

Autor: Olli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Bereich im Heuhaufen, in dem ich vermute, dass sich die Nadel 
befindet, ist folgender (portierte Version):
void init_DMX(void)
{
  DDRD     |=  (1<<2);
  PORTD    &= ~(1<<2);         //enable reception
  UBRR0H    = 0;
  UBRR0L    = ((F_OSC/4000)-1);      //250kbaud, 8N2
  UCSR0C   |= (3<<UCSZ01) | (1<<USBS0);
  UCSR0B   |= (1<<RXEN0)  | (1<<RXCIE0);
  gDmxState = IDLE;

  uint8_t i;
  for (i=0; i<DMX_CHANNELS; i++)
  {
    DmxField[i]= 0;
  }
}

Ich vermute, dass ich irgendwelche Register verwurschtelt habe.

Autor: Olli (Gast)
Datum:

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

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

Autor: Olli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falscher Oszillator?

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

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.