DMX512输出协议详解

DMX512输出协议详解_第1张图片

目录

​编辑

1、DMX512协议简介

2、DMX512协议分析

DMX512指令帧介绍

DMX512信息包

3、DMX512接口电路

4、参考代码


1、DMX512协议简介

DMX512是一种用于舞台灯光控制的数字传输协议。它是由美国舞台灯光协会(USITT)于1990年发布的工业标准,全称为USITT DMX512(1990)。DMX512协议定义了灯光控制器与灯具设备之间进行数据传输的电气特性、数据协议和数据格式等方面的内容。通过DMX512协议,可以实现对舞台灯光设备的精确控制,包括调整亮度、颜色、运动等。DMX512协议常用于舞台演出、演唱会、剧院等场合,以及其他需要对灯光进行精确控制的应用领域。

DMX512是一种用于控制舞台灯光和特效设备的通信协议。它在物理层采用EIA-485差分信号,并结合可变尺寸和基于分组的通信协议。DMX512是单向的,意味着只能从控制器发送数据到灯光和特效设备,而不能反向传输数据。

DMX512协议不包含自动错误检查和纠正功能,因此不适用于一些危险应用,如烟火或舞台装置的移动。电磁干扰、静电放电、不正确的电缆端接、电缆过长或电缆质量等因素可能会导致虚假触发或通信错误。


2、DMX512协议分析

DMX512指令帧介绍

每一个DMX 控制字节叫做一个指令帧,称作一个控制通道,可以控制灯光设备的一个或几个功能。一个DMX 指令帧由1个开始位(S)、8个数据位(D0-D8)和2个结束位(E)共11位构成,采用单向异步串行传输,如图:

DMX512输出协议详解_第2张图片

图1 中虚线内控制指令中的S为开始位,宽度为一个比特,是受控灯具准备接收并解码控制数据的开始标志;

E为结束位,宽度为两个比特,表示一个指令帧的结束;

D0~ D7为8 位控制数据,其电平组合从00000000一11111111 共有256个状态(对应十进制数的0~255),控制灯光的亮度时,可产生256个亮度等级,0000~ (0)对应灯光最暗,11111111(255)对应灯光最亮。

DMX512指令的位宽(每比特宽度)是4 us,每一个指令帧11位,故指令帧宽度为44 us,传输速率为1/44us = 250 kbps。

DMX512信息包

一个完整的DMX512信息包(Packet)由一个MTBP位、一个Break 位、一个MAB位、一个SC 和512个数据帧构成。

DMX512输出协议详解_第3张图片

MTBP(Mark TimeBetween Packets)标志着一个完整的信息包发送完毕,是下一个信息包即将开始的“空闲位”,高电平有效。

Break为中断位,对应一个信息包结束后的程序复位阶段,宽度不少于两个帧(22 比特)。程序复位结束后应发送控制数据,

MAB位,由于每一个数据帧的第一位(即开始位)为低电平,所以必须用一个高电平脉冲间隔前后两个低电平脉冲,这个起间隔、分离作用的高电平脉冲即MAB(Mark After Break),此脉冲一到,意味着“新一轮”的控制又开始了。

SC(Start Code)意为开始代码帧(图1中的第0帧),和此后到来的数据帧一样,也是由11 位构成,除最后的两个高电平的结束位之外,其他9位全部是低电平,通常将其叫做第0 帧或第0通道(Ch~nel No 0),可理解为一个不存在的通道(Non一~istent Channe1)。

DMX512 信息包定时表:

DMX512输出协议详解_第4张图片

表1 是DMX512 信息包的定时表,表中NS意为自己设定,宽度没有严格限制,由程序设计者自行决定,比如MTBP的宽度可以介于0~1秒之间,其他建议采用典型值。

调光控制台每发送一个信息包,可以对全部512个受控通道形成一次全面的控制。发送一个信息包的时间大约是23 ms,每秒钟将对所有512个受控通道完成44 次控制,即受控光路的刷新频率44 Hz,如果实际受控通道少于512个,那么刷新频率将相应提高。

3、DMX512接口电路

以下是使用RJ45连接器的接线及驱动电路 :

(XLR-5和RJ45基本类似)

表2 DMX512 设备使用RJ45连接器的接线表

DMX512输出协议详解_第5张图片

DMX512输出协议详解_第6张图片

4、参考代码

#include "stm32f0xx.h"

// 定义DMX512数据包长度
#define DMX_PACKET_LENGTH 512

// 定义WS2812B LED串的数量
#define NUM_LEDS 8

// 定义WS2812B数据包长度
#define WS2812B_PACKET_LENGTH (NUM_LEDS * 24)

// 定义DMX512数据包缓冲区
uint8_t dmxPacket[DMX_PACKET_LENGTH];

// 定义WS2812B数据包缓冲区
uint8_t ws2812bPacket[WS2812B_PACKET_LENGTH];

// 初始化USART1
void USART1_Init(void) {
    // 启用USART1时钟
    RCC->APB2ENR |= RCC_APB2ENR_USART1EN;

    // 配置USART1引脚
    GPIOA->MODER |= GPIO_MODER_MODER9_1; // PA9作为USART1的TX引脚
    GPIOA->AFR[1] |= (1 << (4 * (9 - 8))); // 将PA9配置为USART1的TX引脚

    // 配置USART1
    USART1->BRR = 48000000 / 250000; // 设置波特率为250000
    USART1->CR1 |= USART_CR1_TE; // 使能发送
    USART1->CR1 |= USART_CR1_UE; // 使能USART1
}

// 发送DMX512数据包
void DMX512_SendPacket(uint8_t *packet, uint16_t length) {
    for (uint16_t i = 0; i < length; i++) {
        while (!(USART1->ISR & USART_ISR_TXE)); // 等待发送缓冲区为空
        USART1->TDR = packet[i]; // 发送数据
    }
}

// 初始化WS2812B
void WS2812B_Init(void) {
    // 配置GPIOA引脚0-7为推挽输出
    GPIOA->MODER |= GPIO_MODER_MODER0_0 | GPIO_MODER_MODER1_0 | GPIO_MODER_MODER2_0 | GPIO_MODER_MODER3_0 |
                    GPIO_MODER_MODER4_0 | GPIO_MODER_MODER5_0 | GPIO_MODER_MODER6_0 | GPIO_MODER_MODER7_0;

    // 配置GPIOA引脚0-7的输出速度为高速
    GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR0 | GPIO_OSPEEDER_OSPEEDR1 | GPIO_OSPEEDER_OSPEEDR2 | GPIO_OSPEEDER_OSPEEDR3 |
                      GPIO_OSPEEDER_OSPEEDR4 | GPIO_OSPEEDER_OSPEEDR5 | GPIO_OSPEEDER_OSPEEDR6 | GPIO_OSPEEDER_OSPEEDR7;
}

// 发送WS2812B数据包
void WS2812B_SendPacket(uint8_t *packet, uint16_t length) {
    for (uint16_t i = 0; i < length; i++) {
        uint8_t data = packet[i];
        for (uint8_t j = 0; j < 8; j++) {
            if (data & 0x80) {
                GPIOA->BSRR = GPIO_BSRR_BS_0; // 设置引脚为高电平
                __NOP(); // 空操作,延时约400ns
                GPIOA->BRR = GPIO_BRR_BR_0; // 设置引脚为低电平
                __NOP(); // 空操作,延时约850ns
            } else {
                GPIOA->BSRR = GPIO_BSRR_BS_0; // 设置引脚为高电平
                __NOP(); // 空操作,延时约850ns
                GPIOA->BRR = GPIO_BRR_BR_0; // 设置引脚为低电平
                __NOP(); // 空操作,延时约400ns
            }
            data <<= 1;
        }
    }
}

int main(void) {
    // 初始化USART1
    USART1_Init();

    // 初始化WS2812B
    WS2812B_Init();

    while (1) {
        // 发送DMX512数据包
        DMX512_SendPacket(dmxPacket, DMX_PACKET_LENGTH);

        // 发送WS2812B数据包
        WS2812B_SendPacket(ws2812bPacket, WS2812B_PACKET_LENGTH);
    }
}

你可能感兴趣的:(#,硬件通信协议,嵌入式硬件,硬件通信,灯具驱动,笔记)