archive files

This commit is contained in:
saad 2023-10-04 01:13:38 -04:00
commit eddc403e3c
6 changed files with 389 additions and 0 deletions

239
DmxMaster.cpp Normal file
View 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
View 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
View 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)

View 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);
}
}

View 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
View File

@ -0,0 +1,18 @@
#######################################
# Syntax Coloring Map For Ultrasound
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
DmxMaster KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
#######################################
# Constants (LITERAL1)
#######################################