STM32 操作 DMX512 探讨 の 2------arduino-DMX

[复制链接]
楼主: wangjiahao88
 楼主 | 2017-12-7 13:10 | 显示全部楼层
// return true when some DMX data was updated.
bool DMXSerialClass::dataUpdated()
{
    return(_dmxUpdated);
}
 楼主 | 2017-12-7 13:11 | 显示全部楼层
// reset DMX data update flag.
void DMXSerialClass::resetUpdated()
{
    _dmxUpdated = false;
}
 楼主 | 2017-12-7 13:11 | 显示全部楼层
// When mode is DMXProbe this function reads one DMX buffer and then returns.
// wait a meaningful time on a packet.
// return true whan a packet has been received.
bool DMXSerialClass::receive() {
    return(receive(DMXPROBE_RECV_MAX));
} // receive()
 楼主 | 2017-12-7 13:12 | 显示全部楼层
// When mode is DMXProbe this function reads one DMX buffer and then returns.
// wait approximately gives the number of msecs for waiting on a packet.
// return true whan a packet has been received.
bool DMXSerialClass::receive(uint8_t wait)
{
    bool ret = false;

    if (_dmxMode == DMXProbe) {
        _DMXStartReceiving();
        // UCSRnA
        while ((wait > 0) && (_dmxRecvState != DONE)) {
            delay(1);
            wait--;
        } // while

        if (_dmxRecvState == DONE) {
            ret = true;
        } else {
            _DMXSerialInit(Calcprescale(DMXSPEED), (1 << RXENn), DMXFORMAT);
        } // if
    } // if

    return(ret);
} // receive(wait)
 楼主 | 2017-12-7 13:13 | 显示全部楼层
// Terminate operation
void DMXSerialClass::term(void)
{
    // Disable all USART Features, including Interrupts
    UCSRnB = 0;
} // term()
 楼主 | 2017-12-7 13:13 | 显示全部楼层
// Initialize the Hardware serial port with the given baud rate
// using 8 data bits, no parity, 2 stop bits for data
// and 8 data bits, even parity, 1 stop bit for the break
void _DMXSerialInit(uint16_t baud_setting, uint8_t mode, uint8_t format)
{
    // assign the baud_setting to the USART Baud Rate Register
    UCSRnA = 0;                 // 04.06.2012: use normal speed operation
    UBRRnH = baud_setting >> 8;
    UBRRnL = baud_setting;

    // enable USART functions RX, TX, Interrupts
    UCSRnB = mode;

    // 2 stop bits and 8 bit character size, no parity
    UCSRnC = format;
} // _DMXSerialInit
 楼主 | 2017-12-7 13:13 | 显示全部楼层
// Setup Hardware for Sending
void _DMXStartSending()
{
    // Start sending a BREAK and send more bytes in UDRE ISR
    // Enable transmitter and interrupt
    _DMXSerialInit(Calcprescale(BREAKSPEED), ((1 << TXENn) | (1 << TXCIEn)), BREAKFORMAT);

    _DMXSerialWriteByte((uint8_t)0);
} // _DMXStartSending()
 楼主 | 2017-12-7 13:17 | 显示全部楼层
// Setup Hardware for Receiving
void _DMXStartReceiving()
{
    uint8_t  voiddata;

    // Enable receiver and Receive interrupt
    _dmxDataPtr = _dmxData;
    _dmxRecvState = STARTUP;

    _DMXSerialInit(Calcprescale(DMXSPEED), (1 << RXENn) | (1 << RXCIEn), DMXFORMAT);
    // delay(10);
    // flush all incomming data packets in the queue
    while (UCSRnA & (1<<RXCn))
        voiddata = UDRn; // get data
} // _DMXStartReceiving()
 楼主 | 2017-12-7 13:17 | 显示全部楼层
// send the next byte after current byte was sent completely.
inline void _DMXSerialWriteByte(uint8_t data)
{
    // putting data into buffer sends the data
    UDRn = data;
} // _DMXSerialWrite
 楼主 | 2017-12-7 13:18 | 显示全部楼层

// This Interrupt Service Routine is called when a byte or frame error was received.
// In DMXController mode this interrupt is disabled and will not occur.
// In DMXReceiver mode when a byte was received it is stored to the dmxData buffer.
ISR(USARTn_RX_vect)
{
    uint8_t  USARTstate = UCSRnA;    // get state before data!
    uint8_t  DmxByte    = UDRn;           // get data
    uint8_t  DmxState   = _dmxRecvState;        //just load once from SRAM to increase speed

    if (DmxState == STARTUP) {
        // just ignore any first frame comming in
        _dmxRecvState = IDLE;
        return;
    }

    if (USARTstate & (1<<FEn)) {          //check for break
        // break condition detected.
        _dmxRecvState = BREAK;
        _dmxDataPtr = _dmxData;

    } else if (DmxState == BREAK) {
        // first byte after a break was read.
        if (DmxByte == 0) {
            // normal DMX start code (0) detected
            _dmxRecvState = DATA;
            _dmxLastPacket = millis(); // remember current (relative) time in msecs.
            _dmxDataPtr++; // start saving data with channel # 1

        } else {
            // This might be a RDM or customer DMX command -> not implemented so wait for next BREAK !
            _dmxRecvState = DONE;
        } // if

    } else if (DmxState == DATA) {
        // check for new data
        if (*_dmxDataPtr != DmxByte) {
            _dmxUpdated = true;
            // store received data into dmx data buffer.
            *_dmxDataPtr = DmxByte;
        } // if
        _dmxDataPtr++;

        if (_dmxDataPtr > _dmxDataLastPtr) {
            // all channels received.
            _dmxRecvState = DONE;
        } // if
    } // if

    if (_dmxRecvState == DONE) {
        if  (_dmxMode == DMXProbe) {
            // stop listening on the serial port for now.
            // UCSRnB = 0;
            // continue listening without interrupts
            _DMXSerialInit(Calcprescale(DMXSPEED), (1 << RXENn), DMXFORMAT);
            //UCSRnB = (1 << RXENn);


        } else {
            // continue on DMXReceiver mode.
            _dmxRecvState = IDLE;        // wait for next break
        }
    } // if

} // ISR(USARTn_RX_vect)
 楼主 | 2017-12-7 13:18 | 显示全部楼层
// Interrupt service routines that are called when the actual byte was sent.
// When changing speed (for sending break and sending start code) we use TX finished interrupt
// which occurs shortly after the last stop bit is sent
// When staying at the same speed (sending data bytes) we use data register empty interrupt
// which occurs shortly after the start bit of the *previous* byte
// When sending a DMX sequence it just takes the next channel byte and sends it out.
// In DMXController mode when the buffer was sent completely the DMX sequence will resent, starting with a BREAK pattern.
// In DMXReceiver mode this interrupt is disabled and will not occur.
ISR(USARTn_TX_vect)
{
    if ((_dmxMode == DMXController) && (_dmxChannel == -1)) {
        // this interrupt occurs after the stop bits of the last data byte
        // start sending a BREAK and loop forever in ISR
        _DMXSerialInit(Calcprescale(BREAKSPEED), ((1 << TXENn) | (1 << TXCIEn)), BREAKFORMAT);
        _DMXSerialWriteByte((uint8_t)0);
        _dmxChannel = 0;

    } else if (_dmxChannel == 0) {
        // this interrupt occurs after the stop bits of the break byte

        // now back to DMX speed: 250000baud
        // take next interrupt when data register empty (early)
        _DMXSerialInit(Calcprescale(DMXSPEED), ((1 << TXENn) | (1 << UDRIEn)), DMXFORMAT);

        // write start code
        _DMXSerialWriteByte((uint8_t)0);
        _dmxChannel = 1;
    } // if
} // ISR(USARTn_TX_vect)
 楼主 | 2017-12-7 13:20 | 显示全部楼层
// this interrupt occurs after the start bit of the previous data byte
ISR(USARTn_UDRE_vect)
{
    _DMXSerialWriteByte(_dmxData[_dmxChannel++]);

    if (_dmxChannel > _dmxMaxChannel) {
        _dmxChannel = -1; // this series is done. Next time: restart with break.
        // get interrupt after this byte is actually transmitted
        // UCSRnB = (1 << TXENn) | (1 << TXCIEn);
        _DMXSerialInit(Calcprescale(DMXSPEED), ((1 << TXENn) | (1 << TXCIEn)), DMXFORMAT);
    } // if

} // ISR(USARTn_UDRE_vect)
 楼主 | 2017-12-7 13:21 | 显示全部楼层
#ifndef DmxSerial_h
#define DmxSerial_h

#include <avr/io.h>

// ----- Constants -----

#define DMXSERIAL_MAX 512 ///< max. number of supported DMX data channels

#define DMXMODEPIN 2     ///< Arduino pin 2 for controlling the data direction is the default value.
#define DmxModeOut HIGH  ///< set the level to HIGH for outgoing data direction
#define DmxModeIn  LOW   ///< set the level to LOW  for incomming data direction

#define DMXPROBE_RECV_MAX 50 // standard maximum of waiting for a DMX packet in DMXPROBE mode.
 楼主 | 2017-12-7 13:21 | 显示全部楼层
/**
* Mode of Operation
*/
typedef enum {
  DMXNone, // unspecified
  DMXController , // always sending
  DMXReceiver,   // always listening
  DMXProbe       // send and receive upon request
} DMXMode;
 楼主 | 2017-12-7 13:22 | 显示全部楼层
DMXSerialFlow:

一个例程:

arduino
 楼主 | 2017-12-7 13:23 | 显示全部楼层
#include <DMXSerial.h>

// Constants for demo program

const int RedPin =    9;  // PWM output pin for Red Light.
const int GreenPin =  6;  // PWM output pin for Green Light.
const int BluePin =   5;  // PWM output pin for Blue Light.

#define PIXELS 60
 楼主 | 2017-12-7 13:23 | 显示全部楼层
void setup(void)
{
  // Serial.begin(57600); // only on Leonardo
  // Serial.println("DMXSerialFlow DMX Example");

  DMXSerial.init(DMXController);

  // Set the number of channels the controller will send
  // this call is not needed, because the DMXController extends the DMX packet length automatically when data is added.
  // DMXSerial.maxChannel(60);

  pinMode(RedPin,   OUTPUT); // sets the digital pin as output
  pinMode(GreenPin, OUTPUT);
  pinMode(BluePin,  OUTPUT);

  analogWrite(RedPin, 80);
  analogWrite(GreenPin, 80);
  analogWrite(BluePin, 80);
} // setup
 楼主 | 2017-12-7 13:24 | 显示全部楼层
// set 3 channels to a RGB value with the specified hue (0...764)
void setChannelRGB(int channel, int hue) {
  hue = hue % 765;
  if (hue < 256) {
    /// blue to red
    DMXSerial.write(channel  , hue);
    DMXSerial.write(channel+1, 0);
    DMXSerial.write(channel+2, 255-hue);

  } else if (hue < 511) {
    /// red to green
    DMXSerial.write(channel  , 255 - (hue-255));
    DMXSerial.write(channel+1, hue-255);
    DMXSerial.write(channel+2, 0);

  } else {
    /// green to blue
    DMXSerial.write(channel  , 0);
    DMXSerial.write(channel+1, 255 - (hue-510));
    DMXSerial.write(channel+2, hue-510);
  } // if
} // setChannelRGB()
 楼主 | 2017-12-7 13:24 | 显示全部楼层
void loop(void)
{
  unsigned long now = millis();
  int testchannel = 1;
  
  // create some DMX test values: 5 RGB channels
  // adjust the "12" for changing the speed
  int alpha = (now / 12) % 765;

  // uncomment this line to have a scenario where DMX values are changed ~ 2 times the second
  // alpha = (alpha / 64) * 64;
  // uncomment this line to have a scenario where DMX values are changed every 5 seconds
  // alpha &= 0xFF00;

  for (int n = 0; n < PIXELS; n++) {
    setChannelRGB (n*3+1, alpha + n*64);
  } // for
  
  // send the DMX values fo the testchannel to the PWM pins
  analogWrite(RedPin,   DMXSerial.read(testchannel+0));
  analogWrite(GreenPin, DMXSerial.read(testchannel+1));
  analogWrite(BluePin,  DMXSerial.read(testchannel+2));
}

// End
 楼主 | 2017-12-7 13:25 | 显示全部楼层
DmxSerialNeoPixels
--------------------------------

arduino 第二个例程

#include <Arduino.h>
#include <DMXSerial.h>

#include "ws2812.h"

// Constants for demo program

const int RedPin =    9;  // PWM output pin for Red Light.
const int GreenPin =  6;  // PWM output pin for Green Light.
const int BluePin =   5;  // PWM output pin for Blue Light.

#define RedDefaultLevel   5 // 100
#define GreenDefaultLevel 0 // 200
#define BlueDefaultLevel  0 // 255

// number of RGB neopixels, RGB channels are transfered
// warning: try with 12 first and scale up carefully.
#define PIXELS 60

// first DMX start address
#define DMXSTART 1

// number of DMX channels used
#define DMXLENGTH (PIXELS*3)
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式
我要创建版块 申请成为版主

论坛热帖

关闭

热门推荐上一条 /2 下一条

快速回复 返回顶部 返回列表