打印

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

[复制链接]
5732|49
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wangjiahao88|  楼主 | 2017-12-7 12:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
沙发
wangjiahao88|  楼主 | 2017-12-7 12:25 | 只看该作者
DMXSerial CPP源码 与头文件解析:

使用特权

评论回复
板凳
wangjiahao88|  楼主 | 2017-12-7 12:26 | 只看该作者
// - - - - -
// DMXSerial - A Arduino library for sending and receiving DMX using the builtin serial hardware port.
// DMXSerial.cpp: Library implementation file
//
// Copyright (c) 2011 by Matthias Hertel, http://www.mathertel.de
// This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx
//
// Documentation and samples are available at http://www.mathertel.de/Arduino
// Changelog: See DMXSerial.h
// - - - - -

#include "Arduino.h"

#include "DMXSerial.h"
#include <avr/interrupt.h>

使用特权

评论回复
地板
wangjiahao88|  楼主 | 2017-12-7 12:26 | 只看该作者
// ----- Constants -----

// Define port & bit values for Hardware Serial Port.
// The library works unchanged with the Arduino 2009, UNO, MGEA 2560 and Leonardo boards.
// The Arduino MGEA 2560 boards use the serial port 0 on pins 0 an 1.
// The Arduino Leonardo will use serial port 1, also on pins 0 an 1. (on the 32u4 boards the first USART is USART1)
// This is consistent to the Layout of the Arduino DMX Shield http://www.mathertel.de/Arduino/DMXShield.aspx.

// For using the serial port 1 on a Arduino MEGA 2560 board, enable the following DMX_USE_PORT1 definition.
// #define DMX_USE_PORT1

使用特权

评论回复
5
wangjiahao88|  楼主 | 2017-12-7 12:27 | 只看该作者
::::::::::
以上部分 就是头文件与宏定义的哪个串口来执行这个功能!

使用特权

评论回复
6
wangjiahao88|  楼主 | 2017-12-7 12:28 | 只看该作者
#if !defined(DMX_USE_PORT1) && defined(USART_RXC_vect)
// These definitions are used on ATmega8 boards
#define UCSRnA UCSRA  // Control and Status Register A
#define TXCn   TXC    // Transmit buffer clear

#define UCSRnB UCSRB  // USART Control and Status Register B

#define RXCIEn RXCIE  // Enable Receive Complete Interrupt
#define TXCIEn TXCIE  // Enable Transmission Complete Interrupt
#define UDRIEn UDRIE  // Enable Data Register Empty Interrupt
#define RXENn  RXEN   // Enable Receiving
#define TXENn  TXEN   // Enable Sending

#define UCSRnC UCSRC  // Control and Status Register C
#define USBSn  USBS   // Stop bit select 0=1bit, 1=2bits
#define UCSZn0 UCSZ0  // Character size 00=5, 01=6, 10=7, 11=8 bits
#define UPMn0  UPM0   // Parity setting 00=N, 10=E, 11=O

#define UBRRnH UBRRH  // USART Baud Rate Register High
#define UBRRnL UBRRL  // USART Baud Rate Register Low

#define UDRn   UDR    // USART Data Register
#define UDREn  UDRE   // USART Data Ready
#define FEn    FE     // Frame Error

#define USARTn_RX_vect   USART_RXC_vect  // Interrupt Data received
#define USARTn_TX_vect   USART_TXC_vect  // Interrupt Data sent
#define USARTn_UDRE_vect USART_UDRE_vect // Interrupt Data Register empty

使用特权

评论回复
7
wangjiahao88|  楼主 | 2017-12-7 12:28 | 只看该作者

::::::::::
以上部分 就是宏定义串口的相关寄存器

使用特权

评论回复
8
wangjiahao88|  楼主 | 2017-12-7 12:29 | 只看该作者
#elif !defined(DMX_USE_PORT1) && defined(USART_RX_vect)
// These definitions are used on ATmega168p and ATmega328p boards
// like the Arduino Diecimila, Duemilanove, 2009, Uno
#define UCSRnA UCSR0A
#define RXCn   RXC0
#define TXCn   TXC0
#define UCSRnB UCSR0B
#define RXCIEn RXCIE0
#define TXCIEn TXCIE0
#define UDRIEn UDRIE0
#define RXENn  RXEN0
#define TXENn  TXEN0
#define UCSRnC UCSR0C
#define USBSn  USBS0
#define UCSZn0 UCSZ00
#define UPMn0  UPM00
#define UBRRnH UBRR0H
#define UBRRnL UBRR0L
#define UDRn   UDR0
#define UDREn  UDRE0
#define FEn    FE0
#define USARTn_RX_vect   USART_RX_vect
#define USARTn_TX_vect   USART_TX_vect
#define USARTn_UDRE_vect USART_UDRE_vect

使用特权

评论回复
9
wangjiahao88|  楼主 | 2017-12-7 12:30 | 只看该作者
#elif !defined(DMX_USE_PORT1) && defined(USART0_RX_vect)
// These definitions are used on ATmega1280 and ATmega2560 boards
// like the Arduino MEGA boards
#define UCSRnA UCSR0A
#define RXCn   RXC0
#define TXCn   TXC0
#define UCSRnB UCSR0B
#define RXCIEn RXCIE0
#define TXCIEn TXCIE0
#define UDRIEn UDRIE0
#define RXENn  RXEN0
#define TXENn  TXEN0
#define UCSRnC UCSR0C
#define USBSn  USBS0
#define UCSZn0 UCSZ00
#define UPMn0  UPM00
#define UBRRnH UBRR0H
#define UBRRnL UBRR0L
#define UDRn   UDR0
#define UDREn  UDRE0
#define FEn    FE0
#define USARTn_RX_vect   USART0_RX_vect
#define USARTn_TX_vect   USART0_TX_vect
#define USARTn_UDRE_vect USART0_UDRE_vect

#elif defined(DMX_USE_PORT1) || defined(USART1_RX_vect)
// These definitions are used for using serial port 1
// on ATmega32U4 boards like Arduino Leonardo, Esplora
// You can use it on other boards with USART1 by enabling the DMX_USE_PORT1 port definition
#define UCSRnA UCSR1A
#define RXCn   RXC1
#define TXCn   TXC1
#define UCSRnB UCSR1B
#define RXCIEn RXCIE1
#define TXCIEn TXCIE1
#define UDRIEn UDRIE1
#define RXENn  RXEN1
#define TXENn  TXEN1
#define UCSRnC UCSR1C
#define USBSn  USBS1
#define UCSZn0 UCSZ10
#define UPMn0  UPM10
#define UBRRnH UBRR1H
#define UBRRnL UBRR1L
#define UDRn   UDR1
#define UDREn  UDRE1
#define FEn    FE1
#define USARTn_RX_vect   USART1_RX_vect
#define USARTn_TX_vect   USART1_TX_vect
#define USARTn_UDRE_vect USART1_UDRE_vect

#endif

使用特权

评论回复
10
wangjiahao88|  楼主 | 2017-12-7 12:49 | 只看该作者
// formats for serial transmission
#define SERIAL_8N1  ((0<<USBSn) | (0<<UPMn0) | (3<<UCSZn0))
#define SERIAL_8N2  ((1<<USBSn) | (0<<UPMn0) | (3<<UCSZn0))
#define SERIAL_8E1  ((0<<USBSn) | (2<<UPMn0) | (3<<UCSZn0))
#define SERIAL_8E2  ((1<<USBSn) | (2<<UPMn0) | (3<<UCSZn0))

使用特权

评论回复
11
wangjiahao88|  楼主 | 2017-12-7 13:06 | 只看该作者
// the break timing is 10 bits (start + 8 data + parity) of this speed
// the mark-after-break is 1 bit of this speed plus approx 6 usec
// 100000 bit/sec is good: gives 100 usec break and 16 usec MAB
// 1990 spec says transmitter must send >= 92 usec break and >= 12 usec MAB
// receiver must accept 88 us break and 8 us MAB
#define BREAKSPEED     100000
#define DMXSPEED       250000
#define BREAKFORMAT    SERIAL_8E1
#define DMXFORMAT      SERIAL_8N2


关于时序部分的介绍

使用特权

评论回复
12
wangjiahao88|  楼主 | 2017-12-7 13:06 | 只看该作者
// ----- Enumerations -----

// State of receiving DMX Bytes
typedef enum {
    STARTUP = 1,  // wait for any interrupt BEFORE starting anylyzig the DMX protocoll.
    IDLE    = 2,  // wait for a BREAK condition.
    BREAK   = 3,  // BREAK was detected.
    DATA    = 4,  // DMX data.
    DONE    = 5   // All channels received.
} __attribute__((packed)) DMXReceivingState;

使用特权

评论回复
13
wangjiahao88|  楼主 | 2017-12-7 13:06 | 只看该作者
// ----- Macros -----

// calculate prescaler from baud rate and cpu clock rate at compile time
// nb implements rounding of ((clock / 16) / baud) - 1 per atmega datasheet
#define Calcprescale(B)     ( ( (((F_CPU)/8)/(B)) - 1 ) / 2 )

// ----- DMXSerial Private variables -----
// These variables are not class members because they have to be reached by the interrupt implementations.
// don't use these variable from outside, use the appropriate methods.

DMXMode  _dmxMode;    // Mode of Operation
int      _dmxModePin; // pin used for I/O direction.

uint8_t _dmxRecvState;  // Current State of receiving DMX Bytes
int     _dmxChannel;  // the next channel byte to be sent.

volatile unsigned int  _dmxMaxChannel = 32; // the last channel used for sending (1..32).
volatile unsigned long _dmxLastPacket = 0; // the last time (using the millis function) a packet was received.

bool _dmxUpdated = true; // is set to true when new data arrived.

// Array of DMX values (raw).
// Entry 0 will never be used for DMX data but will store the startbyte (0 for DMX mode).
uint8_t  _dmxData[DMXSERIAL_MAX+1];

// This pointer will point to the next byte in _dmxData;
uint8_t *_dmxDataPtr;

// This pointer will point to the last byte in _dmxData;
uint8_t *_dmxDataLastPtr;

// Create a single class instance. Multiple class instances (multiple simultaneous DMX ports) are not supported.
DMXSerialClass DMXSerial;


// ----- forwards -----

void _DMXSerialInit(uint16_t baud_setting, uint8_t mode, uint8_t format);
inline void _DMXSerialWriteByte(uint8_t data);

void _DMXStartSending();
void _DMXStartReceiving();

使用特权

评论回复
14
wangjiahao88|  楼主 | 2017-12-7 13:07 | 只看该作者
// Initialize the specified mode.
void DMXSerialClass::init(int mode)
{
    init(mode, DMXMODEPIN);
}

DMX 初始化

使用特权

评论回复
15
wangjiahao88|  楼主 | 2017-12-7 13:08 | 只看该作者
// (Re)Initialize the specified mode.
// The mode parameter should be a value from enum DMXMode.
void DMXSerialClass::init(int mode, int dmxModePin)
{
    // initialize global variables
    _dmxMode = DMXNone;
    _dmxModePin = dmxModePin;
    _dmxRecvState = STARTUP; // initial state
    _dmxChannel = 0;
    _dmxDataPtr = _dmxData;
    _dmxLastPacket = millis(); // remember current (relative) time in msecs.

    _dmxMaxChannel = DMXSERIAL_MAX; // The default in Receiver mode is reading all possible 512 channels.
    _dmxDataLastPtr = _dmxData + _dmxMaxChannel;

    // initialize the DMX buffer
//  memset(_dmxData, 0, sizeof(_dmxData));
    for (int n = 0; n < DMXSERIAL_MAX+1; n++)
        _dmxData[n] = 0;

    // now start
    _dmxMode = (DMXMode)mode;

    if ((_dmxMode == DMXController) || (_dmxMode == DMXReceiver) || (_dmxMode == DMXProbe)) {
        // a valid mode was given
        // Setup external mode signal
        pinMode(_dmxModePin, OUTPUT); // enables the pin for output to control data direction
        digitalWrite(_dmxModePin, DmxModeIn); // data in direction, to avoid problems on the DMX line for now.

        if (_dmxMode == DMXController) {
            digitalWrite(_dmxModePin, DmxModeOut); // data Out direction
            _dmxMaxChannel = 32; // The default in Controller mode is sending 32 channels.
            _DMXStartSending();

        } else if (_dmxMode == DMXReceiver) {
            // Setup Hardware
            _DMXStartReceiving();

            // } else if (_dmxMode == DMXProbe) {
            //   // don't setup the Hardware now

        }  // if
    } // if
} // init()

使用特权

评论回复
16
wangjiahao88|  楼主 | 2017-12-7 13:08 | 只看该作者
// Set the maximum used channel.
// This method can be called any time before or after the init() method.
void DMXSerialClass::maxChannel(int channel)
{
    if (channel < 1) channel = 1;
    if (channel > DMXSERIAL_MAX) channel = DMXSERIAL_MAX;
    _dmxMaxChannel = channel;
    _dmxDataLastPtr = _dmxData + channel;
} // maxChannel


最大的通道定义 数量

使用特权

评论回复
17
wangjiahao88|  楼主 | 2017-12-7 13:09 | 只看该作者
// Read the current value of a channel.
uint8_t DMXSerialClass::read(int channel)
{
    // adjust parameter
    if (channel < 1) channel = 1;
    if (channel > DMXSERIAL_MAX) channel = DMXSERIAL_MAX;
    // read value from buffer
    return(_dmxData[channel]);
} // read()

使用特权

评论回复
18
wangjiahao88|  楼主 | 2017-12-7 13:09 | 只看该作者
// Write the value into the channel.
// The value is just stored in the sending buffer and will be picked up
// by the DMX sending interrupt routine.
void DMXSerialClass::write(int channel, uint8_t value)
{
    // adjust parameters
    if (channel < 1) channel = 1;
    if (channel > DMXSERIAL_MAX) channel = DMXSERIAL_MAX;
    if (value < 0)   value = 0;
    if (value > 255) value = 255;

    // store value for later sending
    _dmxData[channel] = value;

    // Make sure we transmit enough channels for the ones used
    if (channel > _dmxMaxChannel) {
        _dmxMaxChannel = channel;
        _dmxDataLastPtr = _dmxData + _dmxMaxChannel;
    } // if
} // write()

使用特权

评论回复
19
wangjiahao88|  楼主 | 2017-12-7 13:10 | 只看该作者
// Return the DMX buffer of unsave direct but faster access
uint8_t *DMXSerialClass::getBuffer()
{
    return(_dmxData);
} // getBuffer()

使用特权

评论回复
20
wangjiahao88|  楼主 | 2017-12-7 13:10 | 只看该作者
// Calculate how long no data packet was received
unsigned long DMXSerialClass::noDataSince()
{
    unsigned long now = millis();
    return(now - _dmxLastPacket);
} // noDataSince()

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

473

主题

7517

帖子

30

粉丝