一、DMX512协议概述
DMX512是舞台灯光控制的标准数字协议,基于RS485物理层,传输速率为250kbps。每个数据包包含:
- Break信号:≥88μs的低电平,标志数据包开始
- MAB信号:≥8μs的高电平,区分Break和数据起始位
- 起始码(SC):通常为0x00,表示标准灯光数据
- 512个数据帧:每个帧对应一个控制通道,值范围0-255
二、硬件设计方案
2.1 核心元件清单
| 元件 | 型号/参数 | 数量 | 作用 |
|---|---|---|---|
| 单片机 | STC8H8K64U | 1 | 主控制器 |
| RS485芯片 | MAX485/SP3485 | 1 | DMX信号收发 |
| 晶振 | 22.1184MHz | 1 | 精确波特率 |
| 电源芯片 | AMS1117-3.3V | 1 | 3.3V稳压 |
| XLR接口 | 5芯卡农座 | 1 | DMX标准接口 |
| LED指示灯 | 红/绿/蓝 | 各1 | 状态指示 |
| 按键 | 轻触开关 | 4 | 模式选择/设置 |
2.2 电路连接图
STC8H8K64U引脚分配:
P3.0 (RXD) → MAX485 RO (接收输出)
P3.1 (TXD) → MAX485 DI (数据输入)
P1.0 → MAX485 RE (接收使能,低有效)
P1.1 → MAX485 DE (发送使能,高有效)
P1.2-P1.5 → 按键输入(模式、速度、亮度、选择)
P2.0-P2.7 → LED输出(可扩展为8通道PWM)
P5.4 → 状态LED
VCC (3.3V) → 系统电源
GND → 公共地
MAX485连接:
A → XLR接口引脚2 (DMX+)
B → XLR接口引脚3 (DMX-)
GND → XLR接口引脚1 (屏蔽地)
2.3 电源设计
- 输入:DC 5-12V
- 稳压:AMS1117-3.3V提供稳定3.3V
- 滤波:100μF电解电容 + 0.1μF陶瓷电容
三、软件架构设计
3.1 文件结构
DMX512_Controller/
├── Inc/ # 头文件
│ ├── dmx512.h # DMX协议定义
│ ├── pattern.h # 花样模式定义
│ ├── uart.h # 串口配置
│ └── config.h # 系统配置
├── Src/ # 源文件
│ ├── main.c # 主程序
│ ├── dmx512.c # DMX协议处理
│ ├── pattern.c # 花样生成
│ ├── uart.c # 串口驱动
│ └── timer.c # 定时器
└── Project/ # 工程文件
└── DMX512_Controller.uvproj
3.2 核心模块功能
- UART模块:配置为250kbps,11位帧格式(1起始+8数据+2停止)
- DMX协议模块:数据包解析与生成
- 花样模式模块:预置灯光效果算法
- 定时器模块:精确时间控制
- 按键扫描模块:用户交互
四、完整代码实现
4.1 配置文件 (config.h)
c
#ifndef __CONFIG_H
#define __CONFIG_H
// 系统时钟频率
#define FOSC 22118400L // 22.1184MHz晶振
#define BAUD_RATE 250000 // DMX512标准波特率
// 引脚定义
sbit DMX_TX_EN = P1^1; // MAX485发送使能
sbit DMX_RX_EN = P1^0; // MAX485接收使能
sbit LED_STATUS = P5^4; // 状态指示灯
// 按键定义
sbit KEY_MODE = P1^2; // 模式切换
sbit KEY_SPEED = P1^3; // 速度调整
sbit KEY_BRIGHT = P1^4; // 亮度调整
sbit KEY_SELECT = P1^5; // 选择/确认
// LED输出通道(8通道PWM)
#define LED_CHANNELS 8
#define LED_PORT P2
// 系统参数
#define DMX_CHANNELS 512 // DMX通道数
#define PATTERN_COUNT 8 // 预置花样数量
#define MAX_SPEED 10 // 最大速度等级
#define MAX_BRIGHT 255 // 最大亮度值
#endif
4.2 DMX512协议头文件 (dmx512.h)
c
#ifndef __DMX512_H
#define __DMX512_H
#include "config.h"
#include <intrins.h>
// DMX512数据包结构
typedef struct {
unsigned char start_code; // 起始码(通常0x00)
unsigned char data[DMX_CHANNELS]; // 512个通道数据
unsigned int frame_count; // 帧计数器
} DMX_Packet;
// 工作模式
typedef enum {
MODE_DMX_RECEIVE = 0, // DMX接收模式
MODE_PATTERN_PLAY, // 花样播放模式
MODE_MANUAL, // 手动控制模式
MODE_SETUP // 设置模式
} WorkMode;
// 全局变量声明
extern DMX_Packet dmx_rx_packet;
extern DMX_Packet dmx_tx_packet;
extern WorkMode current_mode;
extern unsigned char dmx_address; // 本机起始地址
// 函数声明
void DMX512_Init(void);
void DMX512_SendPacket(void);
void DMX512_ReceiveStart(void);
void DMX512_ProcessData(void);
unsigned char DMX512_GetChannel(unsigned int channel);
void DMX512_SetChannel(unsigned int channel, unsigned char value);
unsigned char DMX512_CheckBreak(void);
#endif
4.3 花样模式定义 (pattern.h)
c
#ifndef __PATTERN_H
#define __PATTERN_H
#include "config.h"
// 花样模式枚举
typedef enum {
PATTERN_SOLID = 0, // 单色常亮
PATTERN_GRADIENT, // 渐变
PATTERN_FLASH, // 闪烁
PATTERN_CHASE, // 跑马灯
PATTERN_RAINBOW, // 彩虹渐变
PATTERN_BREATH, // 呼吸灯
PATTERN_RANDOM, // 随机变化
PATTERN_MUSIC_SYNC // 音乐同步
} PatternType;
// 花样参数结构
typedef struct {
PatternType type; // 花样类型
unsigned char speed; // 速度(1-10)
unsigned char brightness; // 亮度(0-255)
unsigned char colors[3]; // RGB颜色值
unsigned char direction; // 方向(0-正向,1-反向)
unsigned int step_counter; // 步进计数器
} PatternConfig;
// 函数声明
void Pattern_Init(void);
void Pattern_Play(PatternConfig *config);
void Pattern_Solid(PatternConfig *config);
void Pattern_Gradient(PatternConfig *config);
void Pattern_Flash(PatternConfig *config);
void Pattern_Chase(PatternConfig *config);
void Pattern_Rainbow(PatternConfig *config);
void Pattern_Breath(PatternConfig *config);
void Pattern_Random(PatternConfig *config);
void Pattern_MusicSync(PatternConfig *config);
void Pattern_Next(void);
void Pattern_Prev(void);
void Pattern_SetSpeed(unsigned char speed);
void Pattern_SetBrightness(unsigned char brightness);
#endif
4.4 主程序 (main.c)
c
#include "config.h"
#include "dmx512.h"
#include "pattern.h"
#include "uart.h"
#include "timer.h"
// 全局变量
DMX_Packet dmx_rx_packet;
DMX_Packet dmx_tx_packet;
WorkMode current_mode = MODE_PATTERN_PLAY;
PatternConfig current_pattern;
unsigned char dmx_address = 1; // 默认起始地址为1
unsigned char system_brightness = 200;
// 系统初始化
void System_Init(void)
{
// 关闭看门狗
WDT_CONTR = 0x00;
// 初始化IO口
P0M1 = 0x00; P0M0 = 0x00;
P1M1 = 0x00; P1M0 = 0x00;
P2M1 = 0x00; P2M0 = 0xFF; // P2推挽输出,用于LED控制
P3M1 = 0x00; P3M0 = 0x00;
P5M1 = 0x00; P5M0 = 0x10; // P5.4推挽输出,状态LED
// 初始化模块
UART1_Init();
Timer0_Init();
Timer1_Init();
DMX512_Init();
Pattern_Init();
// 默认花样配置
current_pattern.type = PATTERN_RAINBOW;
current_pattern.speed = 5;
current_pattern.brightness = system_brightness;
current_pattern.colors[0] = 255; // R
current_pattern.colors[1] = 0; // G
current_pattern.colors[2] = 0; // B
current_pattern.direction = 0;
current_pattern.step_counter = 0;
// 使能全局中断
EA = 1;
// 状态LED闪烁表示初始化完成
LED_STATUS = 0;
Delay_ms(100);
LED_STATUS = 1;
Delay_ms(100);
LED_STATUS = 0;
}
// 按键扫描处理
void Key_Scan(void)
{
static unsigned char key_delay = 0;
if (key_delay > 0) {
key_delay--;
return;
}
if (KEY_MODE == 0) { // 模式切换
key_delay = 20;
current_mode = (current_mode + 1) % 4;
// 根据模式设置LED状态
switch (current_mode) {
case MODE_DMX_RECEIVE:
LED_STATUS = 1; // 常亮
break;
case MODE_PATTERN_PLAY:
LED_STATUS = 0; // 熄灭
break;
case MODE_MANUAL:
LED_STATUS = 1; // 闪烁
break;
case MODE_SETUP:
LED_STATUS = 0; // 快速闪烁
break;
}
}
if (KEY_SPEED == 0) { // 速度调整
key_delay = 20;
if (current_pattern.speed < MAX_SPEED) {
current_pattern.speed++;
} else {
current_pattern.speed = 1;
}
Pattern_SetSpeed(current_pattern.speed);
}
if (KEY_BRIGHT == 0) { // 亮度调整
key_delay = 20;
system_brightness += 20;
if (system_brightness > 255) {
system_brightness = 50;
}
Pattern_SetBrightness(system_brightness);
}
if (KEY_SELECT == 0) { // 选择/确认
key_delay = 20;
Pattern_Next(); // 切换到下一个花样
}
}
// 主循环
void main(void)
{
System_Init();
while (1) {
// 按键扫描
Key_Scan();
// 根据当前模式执行相应操作
switch (current_mode) {
case MODE_DMX_RECEIVE:
// DMX接收模式
DMX512_ProcessData();
break;
case MODE_PATTERN_PLAY:
// 花样播放模式
Pattern_Play(¤t_pattern);
break;
case MODE_MANUAL:
// 手动控制模式
// 这里可以添加手动控制逻辑
break;
case MODE_SETUP:
// 设置模式
// 这里可以添加地址设置等逻辑
break;
}
// 系统延时
Delay_ms(10);
}
}
4.5 DMX512协议实现 (dmx512.c)
c
#include "dmx512.h"
#include "uart.h"
#include "timer.h"
// 全局变量
DMX_Packet dmx_rx_packet;
DMX_Packet dmx_tx_packet;
unsigned char dmx_address = 1;
unsigned char dmx_rx_index = 0;
unsigned char dmx_rx_state = 0;
unsigned char dmx_rx_buffer[513];
unsigned long dmx_last_time = 0;
// DMX512初始化
void DMX512_Init(void)
{
// 初始化接收缓冲区
memset(dmx_rx_buffer, 0, sizeof(dmx_rx_buffer));
memset(&dmx_rx_packet, 0, sizeof(DMX_Packet));
memset(&dmx_tx_packet, 0, sizeof(DMX_Packet));
// 设置起始码
dmx_tx_packet.start_code = 0x00;
// 初始化所有通道为0
for (int i = 0; i < DMX_CHANNELS; i++) {
dmx_tx_packet.data[i] = 0;
}
// 配置UART1为250kbps,11位帧格式
UART1_Init();
// 使能接收中断
ES = 1;
}
// 发送DMX512数据包
void DMX512_SendPacket(void)
{
unsigned int i;
// 发送Break信号(≥88μs低电平)
DMX_TX_EN = 1; // 使能发送
DMX_RX_EN = 1; // 禁用接收
TI = 0;
// 产生Break信号
REN = 0; // 禁用接收
TXD = 0; // 发送低电平
Delay_us(100); // 100μs Break
// 发送MAB信号(≥8μs高电平)
TXD = 1;
Delay_us(12); // 12μs MAB
// 重新启用UART
REN = 1;
// 发送起始码
SBUF = dmx_tx_packet.start_code;
while (!TI);
TI = 0;
// 发送512个通道数据
for (i = 0; i < DMX_CHANNELS; i++) {
SBUF = dmx_tx_packet.data[i];
while (!TI);
TI = 0;
}
// 更新帧计数器
dmx_tx_packet.frame_count++;
// 切换回接收模式
DMX_TX_EN = 0;
DMX_RX_EN = 0;
}
// 开始接收DMX数据
void DMX512_ReceiveStart(void)
{
dmx_rx_state = 0;
dmx_rx_index = 0;
dmx_last_time = Timer_GetTick();
// 配置为接收模式
DMX_TX_EN = 0;
DMX_RX_EN = 0;
}
// 检查Break信号
unsigned char DMX512_CheckBreak(void)
{
unsigned long current_time = Timer_GetTick();
unsigned long elapsed = current_time - dmx_last_time;
// 如果超过1ms没有收到数据,认为是一个Break
if (elapsed > 1000) {
dmx_last_time = current_time;
return 1;
}
return 0;
}
// 处理接收到的数据
void DMX512_ProcessData(void)
{
// 检查是否收到完整的数据包
if (dmx_rx_index >= 513) {
// 复制数据到接收包
dmx_rx_packet.start_code = dmx_rx_buffer[0];
memcpy(dmx_rx_packet.data, &dmx_rx_buffer[1], DMX_CHANNELS);
dmx_rx_packet.frame_count++;
// 处理本机通道数据
// 假设使用前8个通道控制8路LED
for (int i = 0; i < 8; i++) {
unsigned char value = DMX512_GetChannel(dmx_address + i);
// 应用亮度控制
value = (value * system_brightness) / 255;
// 输出到LED(这里简化处理,实际需要PWM)
if (i < 8) {
if (value > 127) {
LED_PORT |= (1 << i);
} else {
LED_PORT &= ~(1 << i);
}
}
}
// 重置接收状态
dmx_rx_index = 0;
dmx_rx_state = 0;
}
}
// 获取指定通道的值
unsigned char DMX512_GetChannel(unsigned int channel)
{
if (channel >= 1 && channel <= DMX_CHANNELS) {
return dmx_rx_packet.data[channel - 1];
}
return 0;
}
// 设置发送通道的值
void DMX512_SetChannel(unsigned int channel, unsigned char value)
{
if (channel >= 1 && channel <= DMX_CHANNELS) {
dmx_tx_packet.data[channel - 1] = value;
}
}
// UART1中断服务函数(接收DMX数据)
void UART1_ISR(void) interrupt 4
{
if (RI) {
RI = 0; // 清除接收中断标志
unsigned char data = SBUF;
// 检查Break信号(长时间空闲)
if (DMX512_CheckBreak()) {
dmx_rx_state = 1; // 开始接收新数据包
dmx_rx_index = 0;
}
if (dmx_rx_state) {
if (dmx_rx_index < 513) {
dmx_rx_buffer[dmx_rx_index++] = data;
}
// 更新最后接收时间
dmx_last_time = Timer_GetTick();
}
}
}
4.6 花样模式实现 (pattern.c)
c
#include "pattern.h"
#include "dmx512.h"
#include "timer.h"
// 全局变量
PatternConfig pattern_config;
unsigned int pattern_timer = 0;
unsigned char hue = 0; // 色相值(用于彩虹效果)
// 花样初始化
void Pattern_Init(void)
{
memset(&pattern_config, 0, sizeof(PatternConfig));
pattern_config.type = PATTERN_RAINBOW;
pattern_config.speed = 5;
pattern_config.brightness = 200;
pattern_config.colors[0] = 255; // R
pattern_config.colors[1] = 0; // G
pattern_config.colors[2] = 0; // B
pattern_config.direction = 0;
pattern_config.step_counter = 0;
}
// 播放花样
void Pattern_Play(PatternConfig *config)
{
static unsigned long last_time = 0;
unsigned long current_time = Timer_GetTick();
// 根据速度计算更新间隔
unsigned int interval = 100 - (config->speed * 8);
if (interval < 20) interval = 20;
// 检查是否需要更新
if (current_time - last_time < interval) {
return;
}
last_time = current_time;
// 根据花样类型调用相应的函数
switch (config->type) {
case PATTERN_SOLID:
Pattern_Solid(config);
break;
case PATTERN_GRADIENT:
Pattern_Gradient(config);
break;
case PATTERN_FLASH:
Pattern_Flash(config);
break;
case PATTERN_CHASE:
Pattern_Chase(config);
break;
case PATTERN_RAINBOW:
Pattern_Rainbow(config);
break;
case PATTERN_BREATH:
Pattern_Breath(config);
break;
case PATTERN_RANDOM:
Pattern_Random(config);
break;
case PATTERN_MUSIC_SYNC:
Pattern_MusicSync(config);
break;
}
config->step_counter++;
}
// 单色常亮
void Pattern_Solid(PatternConfig *config)
{
// 设置所有通道为固定颜色
for (int i = 0; i < LED_CHANNELS; i++) {
if (i % 3 == 0) { // R通道
DMX512_SetChannel(i + 1, config->colors[0]);
} else if (i % 3 == 1) { // G通道
DMX512_SetChannel(i + 1, config->colors[1]);
} else { // B通道
DMX512_SetChannel(i + 1, config->colors[2]);
}
}
// 发送DMX数据
DMX512_SendPacket();
}
// 渐变效果
void Pattern_Gradient(PatternConfig *config)
{
static unsigned char gradient_pos = 0;
// 计算渐变位置
gradient_pos = (gradient_pos + 1) % 256;
// 应用渐变
for (int i = 0; i < LED_CHANNELS; i++) {
unsigned char value = (gradient_pos + i * 10) % 256;
DMX512_SetChannel(i + 1, value);
}
DMX512_SendPacket();
}
// 闪烁效果
void Pattern_Flash(PatternConfig *config)
{
static unsigned char flash_state = 0;
// 切换闪烁状态
if (config->step_counter % 10 == 0) {
flash_state = !flash_state;
}
// 设置所有通道
unsigned char value = flash_state ? config->brightness : 0;
for (int i = 0; i < LED_CHANNELS; i++) {
DMX512_SetChannel(i + 1, value);
}
DMX512_SendPacket();
}
// 跑马灯效果
void Pattern_Chase(PatternConfig *config)
{
static unsigned char chase_pos = 0;
// 清空所有通道
for (int i = 0; i < LED_CHANNELS; i++) {
DMX512_SetChannel(i + 1, 0);
}
// 设置跑马灯位置
unsigned char led_count = LED_CHANNELS / 3; // RGB灯数量
for (int i = 0; i < 3; i++) { // 每个颜色
unsigned char pos = (chase_pos + i) % led_count;
DMX512_SetChannel(pos * 3 + i + 1, config->brightness);
}
// 更新位置
if (config->direction == 0) {
chase_pos = (chase_pos + 1) % led_count;
} else {
chase_pos = (chase_pos + led_count - 1) % led_count;
}
DMX512_SendPacket();
}
// 彩虹渐变效果
void Pattern_Rainbow(PatternConfig *config)
{
// 更新色相
hue = (hue + 1) % 256;
// 为每个LED计算彩虹颜色
for (int i = 0; i < LED_CHANNELS / 3; i++) {
unsigned char led_hue = (hue + i * 20) % 256;
unsigned char r, g, b;
// HSV转RGB(简化版)
if (led_hue < 85) {
r = 255 - led_hue * 3;
g = led_hue * 3;
b = 0;
} else if (led_hue < 170) {
led_hue -= 85;
r = 0;
g = 255 - led_hue * 3;
b = led_hue * 3;
} else {
led_hue -= 170;
r = led_hue * 3;
g = 0;
b = 255 - led_hue * 3;
}
// 应用亮度
r = (r * config->brightness) / 255;
g = (g * config->brightness) / 255;
b = (b * config->brightness) / 255;
// 设置通道
DMX512_SetChannel(i * 3 + 1, r);
DMX512_SetChannel(i * 3 + 2, g);
DMX512_SetChannel(i * 3 + 3, b);
}
DMX512_SendPacket();
}
// 呼吸灯效果
void Pattern_Breath(PatternConfig *config)
{
static unsigned char breath_dir = 0;
static unsigned char breath_val = 0;
// 更新呼吸值
if (breath_dir == 0) {
breath_val++;
if (breath_val >= 255) {
breath_dir = 1;
}
} else {
breath_val--;
if (breath_val <= 0) {
breath_dir = 0;
}
}
// 应用呼吸效果到所有通道
unsigned char value = (breath_val * config->brightness) / 255;
for (int i = 0; i < LED_CHANNELS; i++) {
if (i % 3 == 0) { // R通道
DMX512_SetChannel(i + 1, (config->colors[0] * value) / 255);
} else if (i % 3 == 1) { // G通道
DMX512_SetChannel(i + 1, (config->colors[1] * value) / 255);
} else { // B通道
DMX512_SetChannel(i + 1, (config->colors[2] * value) / 255);
}
}
DMX512_SendPacket();
}
// 随机变化效果
void Pattern_Random(PatternConfig *config)
{
static unsigned char random_seed = 0;
// 简单的伪随机数生成
random_seed = random_seed * 17 + 13;
// 为每个通道生成随机值
for (int i = 0; i < LED_CHANNELS; i++) {
random_seed = random_seed * 17 + 13;
unsigned char value = random_seed;
DMX512_SetChannel(i + 1, (value * config->brightness) / 255);
}
DMX512_SendPacket();
}
// 音乐同步效果(简化版)
void Pattern_MusicSync(PatternConfig *config)
{
// 这里可以连接音频输入,根据音频幅度控制灯光
// 简化版:使用模拟的节奏
static unsigned char beat = 0;
beat = (beat + 1) % 16;
if (beat < 4) {
// 强拍:高亮度
for (int i = 0; i < LED_CHANNELS; i++) {
DMX512_SetChannel(i + 1, config->brightness);
}
} else if (beat < 8) {
// 弱拍:中等亮度
for (int i = 0; i < LED_CHANNELS; i++) {
DMX512_SetChannel(i + 1, config->brightness / 2);
}
} else {
// 休止:低亮度
for (int i = 0; i < LED_CHANNELS; i++) {
DMX512_SetChannel(i + 1, config->brightness / 4);
}
}
DMX512_SendPacket();
}
// 切换到下一个花样
void Pattern_Next(void)
{
pattern_config.type = (pattern_config.type + 1) % PATTERN_COUNT;
pattern_config.step_counter = 0;
}
// 切换到上一个花样
void Pattern_Prev(void)
{
pattern_config.type = (pattern_config.type + PATTERN_COUNT - 1) % PATTERN_COUNT;
pattern_config.step_counter = 0;
}
// 设置速度
void Pattern_SetSpeed(unsigned char speed)
{
if (speed >= 1 && speed <= MAX_SPEED) {
pattern_config.speed = speed;
}
}
// 设置亮度
void Pattern_SetBrightness(unsigned char brightness)
{
if (brightness <= MAX_BRIGHT) {
pattern_config.brightness = brightness;
}
}
4.7 UART配置 (uart.c)
c
#include "uart.h"
#include "config.h"
// UART1初始化,250kbps @22.1184MHz
void UART1_Init(void)
{
// 使用定时器1作为波特率发生器
SCON = 0x50; // 模式1,8位UART,允许接收
PCON |= 0x80; // SMOD=1,波特率加倍
// 定时器1配置
TMOD &= 0x0F; // 清除定时器1模式位
TMOD |= 0x20; // 定时器1,模式2(8位自动重装)
// 计算波特率重装值
// 波特率 = (2^SMOD / 32) * (FOSC / (256 - TH1))
// 250000 = (2 / 32) * (22118400 / (256 - TH1))
// TH1 = 256 - (22118400 * 2) / (32 * 250000)
// TH1 = 256 - 44236800 / 8000000
// TH1 = 256 - 5.5296 ≈ 250
TH1 = 250; // 重装值
TL1 = 250;
TR1 = 1; // 启动定时器1
ES = 1; // 使能串口中断
}
// 发送一个字节
void UART1_SendByte(unsigned char dat)
{
SBUF = dat;
while (!TI);
TI = 0;
}
// 发送字符串
void UART1_SendString(char *str)
{
while (*str) {
UART1_SendByte(*str++);
}
}
// 接收一个字节(阻塞)
unsigned char UART1_ReceiveByte(void)
{
while (!RI);
RI = 0;
return SBUF;
}
4.8 定时器配置 (timer.c)
c
#include "timer.h"
#include "config.h"
volatile unsigned long system_tick = 0;
// 定时器0初始化(1ms中断)
void Timer0_Init(void)
{
// 定时器0,模式1(16位定时器)
TMOD &= 0xF0; // 清除定时器0模式位
TMOD |= 0x01; // 定时器0,模式1
// 计算重装值(1ms @22.1184MHz)
// 机器周期 = 12 / FOSC = 12 / 22118400 ≈ 0.5425μs
// 1ms需要计数 = 1000μs / 0.5425μs ≈ 1843
// 重装值 = 65536 - 1843 = 63693 = 0xF8CD
TH0 = 0xF8; // 高8位
TL0 = 0xCD; // 低8位
ET0 = 1; // 使能定时器0中断
TR0 = 1; // 启动定时器0
}
// 定时器1初始化(用于其他定时)
void Timer1_Init(void)
{
// 定时器1,模式2(8位自动重装)
TMOD &= 0x0F; // 清除定时器1模式位
TMOD |= 0x20; // 定时器1,模式2
TH1 = 0x00; // 初始值
TL1 = 0x00;
ET1 = 1; // 使能定时器1中断
TR1 = 1; // 启动定时器1
}
// 获取系统滴答数
unsigned long Timer_GetTick(void)
{
unsigned long tick;
EA = 0; // 关中断,防止读取时被中断修改
tick = system_tick;
EA = 1; // 开中断
return tick;
}
// 延时毫秒
void Delay_ms(unsigned int ms)
{
unsigned long start_tick = Timer_GetTick();
while (Timer_GetTick() - start_tick < ms);
}
// 延时微秒(近似)
void Delay_us(unsigned int us)
{
// 简单延时,不精确
while (us--) {
_nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_();
}
}
// 定时器0中断服务函数
void Timer0_ISR(void) interrupt 1
{
// 重装定时值
TH0 = 0xF8;
TL0 = 0xCD;
// 系统滴答计数
system_tick++;
}
// 定时器1中断服务函数
void Timer1_ISR(void) interrupt 3
{
// 定时器1中断处理
// 可以用于其他定时任务
}
参考代码 STC8单片机制作简单花样的DMX512控制器 www.youwenfan.com/contentcsv/71863.html
五、使用说明
5.1 硬件连接步骤
- 按照电路图焊接所有元件
- 连接22.1184MHz晶振到STC8的XTAL1和XTAL2
- 连接MAX485到STC8的对应引脚
- 焊接5芯XLR接口,注意引脚定义:
- 引脚1:屏蔽地
- 引脚2:DMX+(A)
- 引脚3:DMX-(B)
- 引脚4、5:备用(可接地)
- 连接电源(5-12V DC)
5.2 软件烧录
- 使用STC-ISP工具烧录程序
- 选择正确的单片机型号(STC8H8K64U)
- 设置IRC频率为22.1184MHz
- 选择正确的COM口和波特率
- 点击"下载/编程"按钮
5.3 操作说明
-
模式切换:按MODE键循环切换工作模式
- DMX接收模式:接收外部DMX信号控制
- 花样播放模式:播放内置灯光效果
- 手动控制模式:手动调节各通道
- 设置模式:设置DMX地址等参数
-
花样选择:在花样播放模式下,按SELECT键切换不同效果
- 单色常亮
- 渐变
- 闪烁
- 跑马灯
- 彩虹渐变
- 呼吸灯
- 随机变化
- 音乐同步(需外接音频)
-
参数调整:
- SPEED键:调整效果速度(1-10级)
- BRIGHT键:调整整体亮度
六、扩展功能建议
6.1 硬件扩展
- 增加PWM输出:使用STC8的PWM模块实现真正的调光控制
- 增加OLED显示屏:显示当前模式、参数等信息
- 增加SD卡存储:存储更多花样程序
- 增加无线模块:支持无线DMX控制
- 增加音频输入:实现真正的音乐同步效果
6.2 软件扩展
- 增加RDM支持:实现远程设备管理
- 增加Art-Net协议:支持网络DMX控制
- 增加场景存储:保存多个场景预设
- 增加时间控制:支持定时节目播放
- 增加DMX输入合并:支持多路DMX输入合并输出
七、调试技巧
7.1 常见问题解决
-
DMX信号不稳定:
- 检查终端电阻(120Ω)是否接在总线末端
- 检查屏蔽线是否良好接地
- 检查电源是否稳定
-
通信距离短:
- 使用高质量的双绞线
- 确保总线两端都有终端电阻
- 避免与强电线路平行走线
-
灯光效果不流畅:
- 调整刷新率,确保DMX帧率在30-44Hz之间
- 优化代码,减少中断处理时间
- 使用硬件PWM代替软件模拟
7.2 测试工具
- DMX信号测试仪:检测DMX信号质量
- 示波器:观察Break、MAB信号时序
- DMX控制器软件:如DMXControl、QLC+等
- 串口调试助手:监控串口通信数据