From eddc403e3cc7f704100c46a8ceb7e2d5c4d6be21 Mon Sep 17 00:00:00 2001 From: saad Date: Wed, 4 Oct 2023 01:13:38 -0400 Subject: [PATCH] archive files --- DmxMaster.cpp | 239 +++++++++++++++++++++++++++ DmxMaster.h | 27 +++ README.md | 18 ++ examples/FadeUp/FadeUp.ino | 41 +++++ examples/SerialToDmx/SerialToDmx.ino | 46 ++++++ keywords.txt | 18 ++ 6 files changed, 389 insertions(+) create mode 100644 DmxMaster.cpp create mode 100644 DmxMaster.h create mode 100644 README.md create mode 100644 examples/FadeUp/FadeUp.ino create mode 100644 examples/SerialToDmx/SerialToDmx.ino create mode 100644 keywords.txt diff --git a/DmxMaster.cpp b/DmxMaster.cpp new file mode 100644 index 0000000..783acfa --- /dev/null +++ b/DmxMaster.cpp @@ -0,0 +1,239 @@ +/** +* DmxMaster - A simple interface to DMX. +* +* Copyright (c) 2008-2009 Peter Knight, Tinker.it! All rights reserved. +*/ +#include +#include +#include +#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; diff --git a/DmxMaster.h b/DmxMaster.h new file mode 100644 index 0000000..8fd25c2 --- /dev/null +++ b/DmxMaster.h @@ -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 + +#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 \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c96c8b4 --- /dev/null +++ b/README.md @@ -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) diff --git a/examples/FadeUp/FadeUp.ino b/examples/FadeUp/FadeUp.ino new file mode 100644 index 0000000..989d900 --- /dev/null +++ b/examples/FadeUp/FadeUp.ino @@ -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 + +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); + } + +} + + diff --git a/examples/SerialToDmx/SerialToDmx.ino b/examples/SerialToDmx/SerialToDmx.ino new file mode 100644 index 0000000..17df3df --- /dev/null +++ b/examples/SerialToDmx/SerialToDmx.ino @@ -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: +** +** c : Select DMX channel +** 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 + +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; + } +} \ No newline at end of file diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..1cdd593 --- /dev/null +++ b/keywords.txt @@ -0,0 +1,18 @@ +####################################### +# Syntax Coloring Map For Ultrasound +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +DmxMaster KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +####################################### +# Constants (LITERAL1) +####################################### +