目录
DMX512是一种用于舞台灯光控制的数字传输协议。它是由美国舞台灯光协会(USITT)于1990年发布的工业标准,全称为USITT DMX512(1990)。DMX512协议定义了灯光控制器与灯具设备之间进行数据传输的电气特性、数据协议和数据格式等方面的内容。通过DMX512协议,可以实现对舞台灯光设备的精确控制,包括调整亮度、颜色、运动等。DMX512协议常用于舞台演出、演唱会、剧院等场合,以及其他需要对灯光进行精确控制的应用领域。
DMX512是一种用于控制舞台灯光和特效设备的通信协议。它在物理层采用EIA-485差分信号,并结合可变尺寸和基于分组的通信协议。DMX512是单向的,意味着只能从控制器发送数据到灯光和特效设备,而不能反向传输数据。
DMX512协议不包含自动错误检查和纠正功能,因此不适用于一些危险应用,如烟火或舞台装置的移动。电磁干扰、静电放电、不正确的电缆端接、电缆过长或电缆质量等因素可能会导致虚假触发或通信错误。
每一个DMX 控制字节叫做一个指令帧,称作一个控制通道,可以控制灯光设备的一个或几个功能。一个DMX 指令帧由1个开始位(S)、8个数据位(D0-D8)和2个结束位(E)共11位构成,采用单向异步串行传输,如图:
图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信息包(Packet)由一个MTBP位、一个Break 位、一个MAB位、一个SC 和512个数据帧构成。
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 信息包定时表:
表1 是DMX512 信息包的定时表,表中NS意为自己设定,宽度没有严格限制,由程序设计者自行决定,比如MTBP的宽度可以介于0~1秒之间,其他建议采用典型值。
调光控制台每发送一个信息包,可以对全部512个受控通道形成一次全面的控制。发送一个信息包的时间大约是23 ms,每秒钟将对所有512个受控通道完成44 次控制,即受控光路的刷新频率44 Hz,如果实际受控通道少于512个,那么刷新频率将相应提高。
以下是使用RJ45连接器的接线及驱动电路 :
(XLR-5和RJ45基本类似)
表2 DMX512 设备使用RJ45连接器的接线表
#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);
}
}