AVR based 8-channel DMX dimmer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

125 lines
3.2 KiB

/***************************************************************************
* Copyright (C) 05/2006 by Olaf Rempel *
* razzor@kopf-tisch.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 version 2 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. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <avr/io.h>
#include <avr/interrupt.h>
#define TIMER1_STEP 40
#define TIMER1_RELOAD (0xFFFF - (255 * TIMER1_STEP))
// channel values
volatile uint8_t chan[8] = { 0xFF, 0xFE, 0x80, 0x40, 0x20, 0x10, 0x01, 0x00 };
// rx receive variables
static uint16_t rx_chan;
static uint16_t my_base;
// timer variables
static uint8_t cnt;
static uint16_t pwm_next;
static uint8_t out_next;
/* Timer 1 Overflow (every 10ms) */
ISR(SIG_OVERFLOW1)
{
TCNT1 = TIMER1_RELOAD;
OCR1A = (TIMER1_RELOAD + TIMER1_STEP);
pwm_next = (TIMER1_RELOAD + (TIMER1_STEP * 2));
cnt = 0x00;
}
/*
* Timer 1 Compare Match (every 40us)
* asap:
* - schedule next compare match
* - set PWM Outputs
* interruptible:
* - calc next compare match
* - calc next output values
*/
ISR(SIG_OUTPUT_COMPARE1A)
{
OCR1A = pwm_next;
PORTB = out_next;
/* rest can be interrupted by DMX receive */
sei();
pwm_next += TIMER1_STEP;
if (cnt == 0x00)
out_next = 0x00;
cnt--;
uint8_t i, shift = 1;
volatile uint8_t *tmp = chan;
for (i = 0; i < 8; i++) {
if (*tmp++ >= cnt)
out_next |= shift;
shift <<= 1;
}
}
/*
* DMX Receive (every 44us)
* - count received bytes
*/
ISR(SIG_UART_RECV)
{
// FrameError & Data 0x00 -> Reset
if (USR & (1<<FE)) {
if (UDR == 0)
rx_chan = 0;
// Our 8 channels?
} else if ((rx_chan & 0x1F8) == my_base) {
chan[(rx_chan++ & 0x07)] = UDR;
} else {
uint8_t tmp = UDR;
tmp = tmp;
}
}
int main(void)
{
/* PortB as outputs */
DDRB = 0xFF;
PORTB = 0x00;
/* Uart-Init: 250kBaud, 8n2, receive only */
UBRR = 0x01;
UCR = (1<<RXCIE) | (1<<RXEN) | (1<<CHR9);
/* Timer Init: F_OSC/8, overflow & compare Int */
TCCR1A = 0x00;
TCCR1B = (1<<CS11);
TIMSK = (1<<TOIE1) | (1<<OCIE1A);
TCNT1 = TIMER1_RELOAD;
/* Enable Interrupts */
sei();
while (1);
return 0;
}