⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dmx.c

📁 Light dimmer application firmware code.
💻 C
字号:
/*
 * Digital AC Dimmer
 *
 * Copyright (c) 2005-2006 Chris Fallin <chris@cfallin.org>
 * Placed under the modified BSD license
 *
 * dmx.c: DMX-512 transmitter module
 */

#include "dmx.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

// PD0 (RXD) and PD1 (TXD) are connected to 75176's RXD and TXD; PD4 is
// connected to REN/TXEN (high = transmit)

static char levels[512];
static int channel_count;

// the channel to be transmitted when the UART is ready for the next char;
// a value of -1 indicates the start code
// additionally, a value of -3 indicates that the break is currently being
// transmitted, and -2 indicates that the mark-after-break is being
// transmitted
static int cur_channel;

void dmx_initialize(int n_chan)
{
  channel_count = n_chan;
  if(channel_count > 512)
    channel_count = 512;

  // initialize I/O pins
  PORTD = PORTD & ~0x10; // PD4 = 1: 75176 always in transmit mode
  DDRD = (DDRD & ~0x13) | 0x12; // PD1, PD4 out; PD0 in

  // initialize the USART
  UBRRH = 0;
  UBRRL = 3; // gives 250kbps for a 16MHz system clock
  UCSRA = 0x00;
  UCSRB = 0xd8; // everything enabled except for UDR Empty interrupt
  UCSRC = 0x8e; // 8 data bits, 2 stop bits

  // intialize Timer 1
  TCCR1A = 0x00;
  TCCR1B = 0x03; // timer 1: CPU clock / 64 (1 tick = 1 bit time, or 4 us)
}

void dmx_set_level(int channel, char level)
{
  if(channel >= channel_count)
    return;

  levels[channel] = level;
}

void dmx_start()
{
  // start it off with the break
  cur_channel = -3;

  // disable the transmitter and set the pin low
  UCSRB &= ~0x08;
  PORTD &= ~0x02;

  // start the timer
  OCR1A = 21; // 88 us, or 22 bit times
  TCNT1 = 0; // start the timer
  TIMSK |= 0x10; // enable the int
}

SIGNAL(SIG_UART_TRANS)
{
  // sanity check
  if(cur_channel < 0)
    return;

  // if we've reached the end of our data, start the whole thing over again
  if(cur_channel >= channel_count)
  {
    dmx_start();
    return;
  }

  UDR = levels[cur_channel];
  cur_channel++;
}

SIGNAL(SIG_UART_RECV)
{
  char rx_byte;

  // discard the received byte and return
  rx_byte = UDR;
}

SIGNAL(SIG_OUTPUT_COMPARE1A)
{
  if(cur_channel == -3)
  {
    // we were transmitting the break; this interrupt ends it

    // re-enable the transmitter
    UCSRB |= 0x08;

    // now we move on to the mark-after-break: 8 us of idle

    cur_channel = -2;
    TCNT1 = 0;
    OCR1A = 1; // 8 us, or 2 bit times

    return;
  }
  else if(cur_channel == -2)
  {
    // we were in the mark-after-brea; this interrupt ends it

    // transmit the start code (always zero in our implementation: no custom
    // non-dimmer data packets)
    UDR = 0;

    // when that's done, we start with the channel data
    cur_channel = 0;

    return;
  }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -