STC8单片机实现简单花样DMX512控制器

一、DMX512协议概述

DMX512是舞台灯光控制的标准数字协议,基于RS485物理层,传输速率为250kbps。每个数据包包含:

  1. Break信号:≥88μs的低电平,标志数据包开始
  2. MAB信号:≥8μs的高电平,区分Break和数据起始位
  3. 起始码(SC):通常为0x00,表示标准灯光数据
  4. 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 核心模块功能

  1. UART模块:配置为250kbps,11位帧格式(1起始+8数据+2停止)
  2. DMX协议模块:数据包解析与生成
  3. 花样模式模块:预置灯光效果算法
  4. 定时器模块:精确时间控制
  5. 按键扫描模块:用户交互

四、完整代码实现

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(&current_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 硬件连接步骤

  1. 按照电路图焊接所有元件
  2. 连接22.1184MHz晶振到STC8的XTAL1和XTAL2
  3. 连接MAX485到STC8的对应引脚
  4. 焊接5芯XLR接口,注意引脚定义:
    • 引脚1:屏蔽地
    • 引脚2:DMX+(A)
    • 引脚3:DMX-(B)
    • 引脚4、5:备用(可接地)
  5. 连接电源(5-12V DC)

5.2 软件烧录

  1. 使用STC-ISP工具烧录程序
  2. 选择正确的单片机型号(STC8H8K64U)
  3. 设置IRC频率为22.1184MHz
  4. 选择正确的COM口和波特率
  5. 点击"下载/编程"按钮

5.3 操作说明

  1. 模式切换:按MODE键循环切换工作模式

    • DMX接收模式:接收外部DMX信号控制
    • 花样播放模式:播放内置灯光效果
    • 手动控制模式:手动调节各通道
    • 设置模式:设置DMX地址等参数
  2. 花样选择:在花样播放模式下,按SELECT键切换不同效果

    • 单色常亮
    • 渐变
    • 闪烁
    • 跑马灯
    • 彩虹渐变
    • 呼吸灯
    • 随机变化
    • 音乐同步(需外接音频)
  3. 参数调整

    • SPEED键:调整效果速度(1-10级)
    • BRIGHT键:调整整体亮度

六、扩展功能建议

6.1 硬件扩展

  1. 增加PWM输出:使用STC8的PWM模块实现真正的调光控制
  2. 增加OLED显示屏:显示当前模式、参数等信息
  3. 增加SD卡存储:存储更多花样程序
  4. 增加无线模块:支持无线DMX控制
  5. 增加音频输入:实现真正的音乐同步效果

6.2 软件扩展

  1. 增加RDM支持:实现远程设备管理
  2. 增加Art-Net协议:支持网络DMX控制
  3. 增加场景存储:保存多个场景预设
  4. 增加时间控制:支持定时节目播放
  5. 增加DMX输入合并:支持多路DMX输入合并输出

七、调试技巧

7.1 常见问题解决

  1. DMX信号不稳定

    • 检查终端电阻(120Ω)是否接在总线末端
    • 检查屏蔽线是否良好接地
    • 检查电源是否稳定
  2. 通信距离短

    • 使用高质量的双绞线
    • 确保总线两端都有终端电阻
    • 避免与强电线路平行走线
  3. 灯光效果不流畅

    • 调整刷新率,确保DMX帧率在30-44Hz之间
    • 优化代码,减少中断处理时间
    • 使用硬件PWM代替软件模拟

7.2 测试工具

  1. DMX信号测试仪:检测DMX信号质量
  2. 示波器:观察Break、MAB信号时序
  3. DMX控制器软件:如DMXControl、QLC+等
  4. 串口调试助手:监控串口通信数据
相关推荐
szxinmai主板定制专家5 小时前
RK3568 + CODESYS+实时系统运动控制器PLC,支持 AI 视觉目标检测,预测性维护,混合多系统部署,多路模拟量采集
arm开发·人工智能·嵌入式硬件·fpga开发
rit84324995 小时前
STM32移植NES模拟器指南
stm32·单片机·嵌入式硬件
都在酒里5 小时前
STM32 I2C通信协议详解——标准库函数实现(通讯协议总结一)
stm32·嵌入式硬件·i2c
fengfuyao9855 小时前
STM32 HAL库实现串口DMA接收不定长数据
stm32·单片机·嵌入式硬件
yuan199975 小时前
STM32直流无刷电机六拍方波控制器程序
stm32·单片机·嵌入式硬件
番茄灭世神6 小时前
PN学堂GD32教程第21篇——WiFiIOT
c语言·stm32·单片机·嵌入式·gd32
不怕犯错,就怕不做7 小时前
ARM设备异常断电容易造成数据损坏,硬件如何设计
linux·驱动开发·嵌入式硬件
jghhh018 小时前
基于DSP28335的RS485串口通信与AD采样开发方案
单片机·嵌入式硬件