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. 串口调试助手:监控串口通信数据
相关推荐
XINVRY-FPGA1 小时前
XC7A100T-2CSG324I AMD Xilinx Artix-7 FPGA
arm开发·人工智能·嵌入式硬件·神经网络·fpga开发·硬件工程·fpga
Szime1 小时前
四通道高速ADC国产替代:14位500MSPS深智微科技选型参考
科技·单片机·嵌入式硬件·fpga开发
嵌入式小站1 小时前
STM32 可移植教程 01:VSCode 环境搭建 + 点亮 LED(实战篇)
vscode·stm32·嵌入式硬件
guygg881 小时前
STM32正交编码器接口指南
stm32·单片机·嵌入式硬件
lin135380675732 小时前
AH810L输入 48~54V 转 5V/100mA 完整方案
嵌入式硬件·物联网
星夜夏空992 小时前
STM32单片机学习(36) —— RTC
stm32·单片机·学习
森利威尔电子-2 小时前
森利威尔 SL3042 | 9V-120V 宽压输入 1.25-50V 可调输出 峰值 10A 电源芯片
单片机·嵌入式硬件·电源芯片·降压恒压芯片
金线银线还是铜线?2 小时前
国产微能量收集PMIC芯片MF9005/MF9006如何选型?
嵌入式硬件·物联网·太阳能
Szime12 小时前
高速 ADC 国产替代选型:通信、雷达、仪器仪表项目要看哪些参数?
单片机·嵌入式硬件·fpga开发
菜鸟的学习日记、14 小时前
GPIO的几种模式——以STM32为例
stm32·单片机·嵌入式硬件·gpio