Il listato C seguente è una versione ripulita da varie cose specifiche della mia applicazione e dovrebbe essere una traccia valida anche per altri micro. Ho comunque lasciato la funzione di inizializzazione al poweron delle periferiche del micro che ovviamente è molto legata al micro usato (Silicon Lab).
In definitiva devi usare la porta seriale a 250000 bit/s e solo in ricezione in quanto il DMX prevede solo l'andata dal mixer ai proiettori (quindi il MAX485 è "semisprecato").
La UART è poi a 9 bit di dato e quello che nel listato è indicato con RB80, nello specifico micro, è questo bit ausiliario.
Tutto il lavoro è svolto da una semplice routine di interrupt che si esegue ad ogni byte ricevuto. Questa tiene il conto del numero di bytes ricevuti e cattura solo i 3 che hanno come base il valore del dip-switch pari all'indirizzo dello specifico apparecchio.
Lo standard prevede 9 dip da cui 512 indidirizzi, ma nel mio caso ho usato solo 8 dip e quindi l'indirizzo base massimo è dimezzato.
Precedentemente avevo parlato di un quarto byte del bianco che in tale listato è invece ignorato.
Riguardo alla documentazione io avevo comperato (ma non ricordo dove) il libretto della specifica originale che conservo ancora, ma su internet è pieno di documentazione.
Inoltre questo è un link piuttosto ricco di informazioni e cose fatte sul tema:
http://www.opendmx.net- Codice: Seleziona tutto
#include "8051f520.h"
#define SYSCLK 24500000
// Risorse relative all'interfaccia DMX512.
#define DMX512_BAUD 250000
#define DMX512_TOT_BYTES 3
unsigned int DMX512_address;
unsigned int DMX512_counter;
unsigned char DMX512_started;
unsigned char DMX512_data[DMX512_TOT_BYTES];
// Risorse relative alle uscite PWM.
#define PWM_FREQ 300
#define PWM_RED PCA0CPH0
#define PWM_GREEN PCA0CPH1
#define PWM_BLUE PCA0CPH2
///////////////////////////////////////////////
// Funzione di inizializzazione al poweron. //
///////////////////////////////////////////////
void poweron_init(void)
{
unsigned int wait;
// Abilita VDD monitor, Poweron Reset e Missing Clock Detector.
VDDMON = 0xA0;
for (wait = 0; wait < 20; wait++);
RSTSRC = 0x06;
// Abilita l'oscillatore interno ed imposta il System Clock a 24.5MHz.
OSCICN = 0xC7;
// Configura porte di I/O. Crossbar: UART0, PCA0. Abilita pull-ups.
P0MDIN = 0xFF;
P1MDIN = 0xFF;
P0MDOUT = 0x17;
P1MDOUT = 0x00;
P0 = 0xFF;
P1 = 0xFF;
P0SKIP = 0x30;
P1SKIP = 0x00;
XBR0 = 0x01;
XBR1 = 0x43;
// TIMER0 in autoreload 8bits per clock PCA0, TIMER1 come baudrate gen.
CKCON = 0x08;
TCON = 0x50;
TMOD = 0x22;
TH0 = 256 - SYSCLK / (12L * 256 * PWM_FREQ);
TH1 = 256 - SYSCLK / (2 * DMX512_BAUD);
// PCA0 con 3 moduli PWM.
PCA0CN = 0x40;
PCA0MD &= ~0x40;
PCA0MD = 0x04;
PCA0CPH0 = 0x00;
PCA0CPH1 = 0x00;
PCA0CPH2 = 0x00;
PCA0CPM0 = 0x42;
PCA0CPM1 = 0x42;
PCA0CPM2 = 0x42;
// UART0 abilitatata in ricezione con 2 stop bits.
SCON0 = 0x90;
// Priorità interrupts: UART0.
EIP1 = 0x00;
IP = 0x10;
// Abilita interrupts: UART0.
EIE1 = 0x00;
IE = 0x90;
}
////////////////////////////////////////////////
// Funzione di risposta all'interrupt UART0. //
////////////////////////////////////////////////
static void UART0_isr(void) interrupt 4 using 1
{
if (RB80)
{
if (DMX512_started)
{
DMX512_counter++;
if ((DMX512_counter >= DMX512_address) && (DMX512_counter < DMX512_address + DMX512_TOT_BYTES)) DMX512_data[DMX512_counter - DMX512_address] = SBUF0;
}
else
{
if (SBUF0)
{
DMX512_counter = 0;
DMX512_started = 0;
}
else
{
DMX512_started = 1;
}
}
}
else
{
DMX512_counter = 0;
DMX512_started = 0;
}
SCON0 = 0x90;
}
////////////////////////////////////////////////
// Funzione principale. //
////////////////////////////////////////////////
void main(void)
{
// Inizializzazione al poweron.
poweron_init();
// Main loop infinito.
while (TRUE)
{
// Definizione dell'indirizzo DMX512 dal dip-switch.
DMX512_address = ~P1;
// Uscita sui PWM dei tre canali DMX512.
PWM_RED = DMX512_data[0];
PWM_GREEN = DMX512_data[1];
PWM_BLUE = DMX512_data[2];
}
}