archive files
This commit is contained in:
commit
eddc403e3c
239
DmxMaster.cpp
Normal file
239
DmxMaster.cpp
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
/**
|
||||||
|
* DmxMaster - A simple interface to DMX.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2009 Peter Knight, Tinker.it! All rights reserved.
|
||||||
|
*/
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include "pins_arduino.h"
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
#include "DmxMaster.h"
|
||||||
|
|
||||||
|
/** dmxBuffer contains a software copy of all the DMX channels.
|
||||||
|
*/
|
||||||
|
volatile uint8_t dmxBuffer[DMX_SIZE];
|
||||||
|
static uint16_t dmxMax = 16; /* Default to sending the first 16 channels */
|
||||||
|
static uint8_t dmxStarted = 0;
|
||||||
|
static uint16_t dmxState = 0;
|
||||||
|
|
||||||
|
static volatile uint8_t *dmxPort;
|
||||||
|
static uint8_t dmxBit = 0;
|
||||||
|
static uint8_t dmxPin = 3; // Defaults to output on pin 3 to support Tinker.it! DMX shield
|
||||||
|
|
||||||
|
void dmxBegin();
|
||||||
|
void dmxEnd();
|
||||||
|
void dmxSendByte(volatile uint8_t);
|
||||||
|
void dmxWrite(int,uint8_t);
|
||||||
|
void dmxMaxChannel(int);
|
||||||
|
|
||||||
|
/* TIMER2 has a different register mapping on the ATmega8.
|
||||||
|
* The modern chips (168, 328P, 1280) use identical mappings.
|
||||||
|
*/
|
||||||
|
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||||
|
#define TIMER2_INTERRUPT_ENABLE() TIMSK2 |= _BV(TOIE2)
|
||||||
|
#define TIMER2_INTERRUPT_DISABLE() TIMSK2 &= ~_BV(TOIE2)
|
||||||
|
#elif defined(__AVR_ATmega32U4__)
|
||||||
|
#define TIMER2_INTERRUPT_ENABLE() TIMSK3 |= _BV(TOIE3)
|
||||||
|
#define TIMER2_INTERRUPT_DISABLE() TIMSK3 &= ~_BV(TOIE3)
|
||||||
|
#elif defined(__AVR_ATmega8__)
|
||||||
|
#define TIMER2_INTERRUPT_ENABLE() TIMSK |= _BV(TOIE2)
|
||||||
|
#define TIMER2_INTERRUPT_DISABLE() TIMSK &= ~_BV(TOIE2)
|
||||||
|
#else
|
||||||
|
#define TIMER2_INTERRUPT_ENABLE()
|
||||||
|
#define TIMER2_INTERRUPT_DISABLE()
|
||||||
|
/* Produce an appropriate message to aid error reporting on nonstandard
|
||||||
|
* platforms such as Teensy.
|
||||||
|
*/
|
||||||
|
#warning "DmxMaster does not support this CPU"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/** Initialise the DMX engine
|
||||||
|
*/
|
||||||
|
void dmxBegin()
|
||||||
|
{
|
||||||
|
dmxStarted = 1;
|
||||||
|
#ifdef __AVR_ATmega32U4__
|
||||||
|
TCCR3A = _BV(WGM30);
|
||||||
|
TCCR3B = _BV(CS31) | _BV(CS30);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Set up port pointers for interrupt routine
|
||||||
|
dmxPort = portOutputRegister(digitalPinToPort(dmxPin));
|
||||||
|
dmxBit = digitalPinToBitMask(dmxPin);
|
||||||
|
// Set DMX pin to output
|
||||||
|
pinMode(dmxPin,OUTPUT);
|
||||||
|
|
||||||
|
// Initialise DMX frame interrupt
|
||||||
|
//
|
||||||
|
// Presume Arduino has already set Timer2 to 64 prescaler,
|
||||||
|
// Phase correct PWM mode
|
||||||
|
// So the overflow triggers every 64*510 clock cycles
|
||||||
|
// Which is 510 DMX bit periods at 16MHz,
|
||||||
|
// 255 DMX bit periods at 8MHz,
|
||||||
|
// 637 DMX bit periods at 20MHz
|
||||||
|
TIMER2_INTERRUPT_ENABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Stop the DMX engine
|
||||||
|
* Turns off the DMX interrupt routine
|
||||||
|
*/
|
||||||
|
void dmxEnd()
|
||||||
|
{
|
||||||
|
TIMER2_INTERRUPT_DISABLE();
|
||||||
|
dmxStarted = 0;
|
||||||
|
dmxMax = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Transmit a complete DMX byte
|
||||||
|
* We have no serial port for DMX, so everything is timed using an exact
|
||||||
|
* number of instruction cycles.
|
||||||
|
*
|
||||||
|
* Really suggest you don't touch this function.
|
||||||
|
*/
|
||||||
|
void dmxSendByte(volatile uint8_t value)
|
||||||
|
{
|
||||||
|
uint8_t bitCount, delCount;
|
||||||
|
__asm__ volatile (
|
||||||
|
"cli\n"
|
||||||
|
"ld __tmp_reg__,%a[dmxPort]\n"
|
||||||
|
"and __tmp_reg__,%[outMask]\n"
|
||||||
|
"st %a[dmxPort],__tmp_reg__\n"
|
||||||
|
"ldi %[bitCount],11\n" // 11 bit intervals per transmitted byte
|
||||||
|
"rjmp bitLoop%=\n" // Delay 2 clock cycles.
|
||||||
|
"bitLoop%=:\n"\
|
||||||
|
"ldi %[delCount],%[delCountVal]\n"
|
||||||
|
"delLoop%=:\n"
|
||||||
|
"nop\n"
|
||||||
|
"dec %[delCount]\n"
|
||||||
|
"brne delLoop%=\n"
|
||||||
|
"ld __tmp_reg__,%a[dmxPort]\n"
|
||||||
|
"and __tmp_reg__,%[outMask]\n"
|
||||||
|
"sec\n"
|
||||||
|
"ror %[value]\n"
|
||||||
|
"brcc sendzero%=\n"
|
||||||
|
"or __tmp_reg__,%[outBit]\n"
|
||||||
|
"sendzero%=:\n"
|
||||||
|
"st %a[dmxPort],__tmp_reg__\n"
|
||||||
|
"dec %[bitCount]\n"
|
||||||
|
"brne bitLoop%=\n"
|
||||||
|
"sei\n"
|
||||||
|
:
|
||||||
|
[bitCount] "=&d" (bitCount),
|
||||||
|
[delCount] "=&d" (delCount)
|
||||||
|
:
|
||||||
|
[dmxPort] "e" (dmxPort),
|
||||||
|
[outMask] "r" (~dmxBit),
|
||||||
|
[outBit] "r" (dmxBit),
|
||||||
|
[delCountVal] "M" (F_CPU/1000000-3),
|
||||||
|
[value] "r" (value)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** DmxMaster interrupt routine
|
||||||
|
* Transmit a chunk of DMX signal every timer overflow event.
|
||||||
|
*
|
||||||
|
* The full DMX transmission takes too long, but some aspects of DMX timing
|
||||||
|
* are flexible. This routine chunks the DMX signal, only sending as much as
|
||||||
|
* it's time budget will allow.
|
||||||
|
*
|
||||||
|
* This interrupt routine runs with interrupts enabled most of the time.
|
||||||
|
* With extremely heavy interrupt loads, it could conceivably interrupt its
|
||||||
|
* own routine, so the TIMER2 interrupt is disabled for the duration of
|
||||||
|
* the service routine.
|
||||||
|
*/
|
||||||
|
#ifdef __AVR_ATmega32U4__
|
||||||
|
ISR(TIMER3_OVF_vect,ISR_NOBLOCK)
|
||||||
|
#else
|
||||||
|
ISR(TIMER2_OVF_vect,ISR_NOBLOCK)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
|
||||||
|
// Prevent this interrupt running recursively
|
||||||
|
TIMER2_INTERRUPT_DISABLE();
|
||||||
|
|
||||||
|
uint16_t bitsLeft = F_CPU / 31372; // DMX Bit periods per timer tick
|
||||||
|
bitsLeft >>=2; // 25% CPU usage
|
||||||
|
while (1) {
|
||||||
|
if (dmxState == 0) {
|
||||||
|
// Next thing to send is reset pulse and start code
|
||||||
|
// which takes 35 bit periods
|
||||||
|
uint8_t i;
|
||||||
|
if (bitsLeft < 35) break;
|
||||||
|
bitsLeft-=35;
|
||||||
|
*dmxPort &= ~dmxBit;
|
||||||
|
for (i=0; i<11; i++) _delay_us(8);
|
||||||
|
*dmxPort |= dmxBit;
|
||||||
|
_delay_us(8);
|
||||||
|
dmxSendByte(0);
|
||||||
|
} else {
|
||||||
|
// Now send a channel which takes 11 bit periods
|
||||||
|
if (bitsLeft < 11) break;
|
||||||
|
bitsLeft-=11;
|
||||||
|
dmxSendByte(dmxBuffer[dmxState-1]);
|
||||||
|
}
|
||||||
|
// Successfully completed that stage - move state machine forward
|
||||||
|
dmxState++;
|
||||||
|
if (dmxState > dmxMax) {
|
||||||
|
dmxState = 0; // Send next frame
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable interrupts for the next transmission chunk
|
||||||
|
TIMER2_INTERRUPT_ENABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dmxWrite(int channel, uint8_t value) {
|
||||||
|
if (!dmxStarted) dmxBegin();
|
||||||
|
if ((channel > 0) && (channel <= DMX_SIZE)) {
|
||||||
|
if (value<0) value=0;
|
||||||
|
if (value>255) value=255;
|
||||||
|
dmxMax = max((unsigned)channel, dmxMax);
|
||||||
|
dmxBuffer[channel-1] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dmxMaxChannel(int channel) {
|
||||||
|
if (channel <=0) {
|
||||||
|
// End DMX transmission
|
||||||
|
dmxEnd();
|
||||||
|
dmxMax = 0;
|
||||||
|
} else {
|
||||||
|
dmxMax = min(channel, DMX_SIZE);
|
||||||
|
if (!dmxStarted) dmxBegin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* C++ wrapper */
|
||||||
|
|
||||||
|
|
||||||
|
/** Set output pin
|
||||||
|
* @param pin Output digital pin to use
|
||||||
|
*/
|
||||||
|
void DmxMasterClass::usePin(uint8_t pin) {
|
||||||
|
dmxPin = pin;
|
||||||
|
if (dmxStarted && (pin != dmxPin)) {
|
||||||
|
dmxEnd();
|
||||||
|
dmxBegin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set DMX maximum channel
|
||||||
|
* @param channel The highest DMX channel to use
|
||||||
|
*/
|
||||||
|
void DmxMasterClass::maxChannel(int channel) {
|
||||||
|
dmxMaxChannel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Write to a DMX channel
|
||||||
|
* @param address DMX address in the range 1 - 512
|
||||||
|
*/
|
||||||
|
void DmxMasterClass::write(int address, uint8_t value)
|
||||||
|
{
|
||||||
|
dmxWrite(address, value);
|
||||||
|
}
|
||||||
|
DmxMasterClass DmxMaster;
|
27
DmxMaster.h
Normal file
27
DmxMaster.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* DmxMaster - A simple interface to DMX.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2009 Peter Knight, Tinker.it! All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DmxMaster_h
|
||||||
|
#define DmxMaster_h
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#if RAMEND <= 0x4FF
|
||||||
|
#define DMX_SIZE 128
|
||||||
|
#else
|
||||||
|
#define DMX_SIZE 512
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class DmxMasterClass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void maxChannel(int);
|
||||||
|
void write(int, uint8_t);
|
||||||
|
void usePin(uint8_t);
|
||||||
|
};
|
||||||
|
extern DmxMasterClass DmxMaster;
|
||||||
|
|
||||||
|
#endif
|
18
README.md
Normal file
18
README.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
DmxSimple
|
||||||
|
---------
|
||||||
|
|
||||||
|
Simple DMX master library for Arduino (TM)
|
||||||
|
|
||||||
|
|
||||||
|
Originally written by Tinker.it Ltd
|
||||||
|
|
||||||
|
|
||||||
|
DmxSimple v3 release:
|
||||||
|
Changes from v2 to v3:
|
||||||
|
Optimised interrupt routine now supports serial baud rates up to 115200.
|
||||||
|
DMX output pin can be changed with the DmxMaster.usePin() function.
|
||||||
|
Automatic support for future clock rates and pin mappings.
|
||||||
|
Syntax highlighting in Arduino editor fixed.
|
||||||
|
More comments added to FadeUp and SerialToDmx examples
|
||||||
|
FadeUp example now demonstrates all DmxMaster functions.
|
||||||
|
Release notes file added. (For older revisions, see SVN log on Google Code)
|
41
examples/FadeUp/FadeUp.ino
Normal file
41
examples/FadeUp/FadeUp.ino
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/* Welcome to DmxMaster. This library allows you to control DMX stage and
|
||||||
|
** architectural lighting and visual effects easily from Arduino. DmxMaster
|
||||||
|
** is compatible with the Tinker.it! DMX shield and all known DIY Arduino
|
||||||
|
** DMX control circuits.
|
||||||
|
**
|
||||||
|
** DmxMaster is available from: http://code.google.com/p/tinkerit/
|
||||||
|
** Help and support: http://groups.google.com/group/DmxMaster */
|
||||||
|
|
||||||
|
/* To use DmxMaster, you will need the following line. Arduino will
|
||||||
|
** auto-insert it if you select Sketch > Import Library > DmxMaster. */
|
||||||
|
|
||||||
|
#include <DmxMaster.h>
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
/* The most common pin for DMX output is pin 3, which DmxMaster
|
||||||
|
** uses by default. If you need to change that, do it here. */
|
||||||
|
DmxMaster.usePin(3);
|
||||||
|
|
||||||
|
/* DMX devices typically need to receive a complete set of channels
|
||||||
|
** even if you only need to adjust the first channel. You can
|
||||||
|
** easily change the number of channels sent here. If you don't
|
||||||
|
** do this, DmxMaster will set the maximum channel number to the
|
||||||
|
** highest channel you DmxMaster.write() to. */
|
||||||
|
DmxMaster.maxChannel(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
int brightness;
|
||||||
|
/* Simple loop to ramp up brightness */
|
||||||
|
for (brightness = 0; brightness <= 255; brightness++) {
|
||||||
|
|
||||||
|
/* Update DMX channel 1 to new brightness */
|
||||||
|
DmxMaster.write(1, brightness);
|
||||||
|
|
||||||
|
/* Small delay to slow down the ramping */
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
46
examples/SerialToDmx/SerialToDmx.ino
Normal file
46
examples/SerialToDmx/SerialToDmx.ino
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/* This program allows you to set DMX channels over the serial port.
|
||||||
|
**
|
||||||
|
** After uploading to Arduino, switch to Serial Monitor and set the baud rate
|
||||||
|
** to 9600. You can then set DMX channels using these commands:
|
||||||
|
**
|
||||||
|
** <number>c : Select DMX channel
|
||||||
|
** <number>v : Set DMX channel to new value
|
||||||
|
**
|
||||||
|
** These can be combined. For example:
|
||||||
|
** 100c355w : Set channel 100 to value 255.
|
||||||
|
**
|
||||||
|
** For more details, and compatible Processing sketch,
|
||||||
|
** visit http://code.google.com/p/tinkerit/wiki/SerialToDmx
|
||||||
|
**
|
||||||
|
** Help and support: http://groups.google.com/group/DmxMaster */
|
||||||
|
|
||||||
|
#include <DmxMaster.h>
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
Serial.println("SerialToDmx ready");
|
||||||
|
Serial.println();
|
||||||
|
Serial.println("Syntax:");
|
||||||
|
Serial.println(" 123c : use DMX channel 123");
|
||||||
|
Serial.println(" 45w : set current channel to value 45");
|
||||||
|
}
|
||||||
|
|
||||||
|
int value = 0;
|
||||||
|
int channel;
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
int c;
|
||||||
|
|
||||||
|
while(!Serial.available());
|
||||||
|
c = Serial.read();
|
||||||
|
if ((c>='0') && (c<='9')) {
|
||||||
|
value = 10*value + c - '0';
|
||||||
|
} else {
|
||||||
|
if (c=='c') channel = value;
|
||||||
|
else if (c=='w') {
|
||||||
|
DmxMaster.write(channel, value);
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
}
|
18
keywords.txt
Normal file
18
keywords.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#######################################
|
||||||
|
# Syntax Coloring Map For Ultrasound
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Datatypes (KEYWORD1)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
DmxMaster KEYWORD1
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Methods and Functions (KEYWORD2)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Constants (LITERAL1)
|
||||||
|
#######################################
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user