Перейти к содержимому

← Подключение оборудования | Содержание | Далее: Обмен по I2C →

Обмен по UART

Подробное описание протокола UART для управления DimmerLink.




Параметры подключения

Параметр Значение
Скорость (Baud Rate) 115200
Биты данных 8
Чётность Нет (N)
Стоп-биты 1
Формат 8N1

ℹ️ Примечание: Интерфейс UART доступен сразу после подачи питания.




Формат команд

Все команды начинаются со стартового байта 0x02 (STX — Start of Text):

python
┌──────────┬──────────┬──────────┬──────────┐
│  START   │   CMD    │   ARG1   │   ARG2   │
│   0x02   │  1 byte  │ optional │ optional │
└──────────┴──────────┴──────────┴──────────┘

⚠️ Важно: Без стартового байта 0x02 команда не будет обработана!




Таблица команд

Команда Код Формат Описание
SET 0x53 ('S') 02 53 IDX LEVEL Установить яркость
GET 0x47 ('G') 02 47 IDX Получить яркость
CURVE 0x43 ('C') 02 43 IDX TYPE Установить кривую диммирования
GETCURVE 0x51 ('Q') 02 51 IDX Получить тип кривой
FREQ 0x52 ('R') 02 52 Получить частоту сети
RESET 0x58 ('X') 02 58 Программный сброс
SWITCH_I2C 0x5B ('[') 02 5B Переключиться на I2C


Параметры

  • IDX — индекс диммера (0–7, текущая версия поддерживает только 0. Значения 1–7 зарезервированы для будущих многоканальных версий)
  • LEVEL — яркость 0–100 (в процентах)
  • TYPE — тип кривой: 0=LINEAR, 1=RMS, 2=LOG



Коды ответов

Код Имя Описание
0x00 OK Команда выполнена успешно
0xF9 ERR_SYNTAX Неверный формат или неизвестная команда
0xFC ERR_NOT_READY Ошибка записи в EEPROM
0xFD ERR_INDEX Неверный индекс диммера
0xFE ERR_PARAM Недопустимое значение параметра



Описание команд


SET — Установить яркость

Формат: 02 53 IDX LEVEL

python
Example: 02 53 00 32  → Set dimmer 0 to 50%
Response: 00          → OK
LEVEL Яркость
0x00 (0) 0% — выключено
0x32 (50) 50%
0x64 (100) 100% — полная яркость


GET — Получить текущую яркость

Формат: 02 47 IDX

python
Example: 02 47 00     → Request dimmer 0 brightness
Response: 00 32       → OK, level 50%

📝 Примечание: GET возвращает значение в процентах (0–100), так же как и SET.


CURVE — Установить кривую диммирования

Формат: 02 43 IDX TYPE

TYPE Кривая Применение
0 LINEAR Универсальная
1 RMS Лампы накаливания, галогенные
2 LOG LED (соответствует восприятию глаза)
python
Example: 02 43 00 01  → Set RMS curve for dimmer 0
Response: 00          → OK


GETCURVE — Получить тип кривой

Формат: 02 51 IDX

python
Example: 02 51 00     → Request dimmer 0 curve type
Response: 00 00       → OK, type LINEAR


FREQ — Получить частоту сети

Формат: 02 52

python
Example: 02 52        → Request frequency
Response: 00 32       → OK, 50 Hz (0x32 = 50)
Or:      00 3C       → OK, 60 Hz (0x3C = 60)


RESET — Программный сброс

Формат: 02 58

python
Example: 02 58        → Reset device
(no response — device reboots)


SWITCH_I2C — Переключение на I2C

Формат: 02 5B

python
Example: 02 5B        → Switch interface to I2C
Response: 00          → OK (last UART response)

После успешного выполнения UART отключается, устройство переходит в режим I2C. Дальнейшее управление — только по I2C по адресу 0x50 (или настроенному адресу).

📝 Примечание: Режим сохраняется в EEPROM и восстанавливается после перезагрузки.




Примеры кода


Arduino

cpp
// Use Serial1 for boards with multiple UARTs (Mega, Due, ESP32)
// Or SoftwareSerial for Uno/Nano

// For Arduino Mega, Due, ESP32 — use Serial1, Serial2
// For Arduino Uno/Nano — use SoftwareSerial (see example below)
#define DIMMER_SERIAL Serial1

void setup() {
    DIMMER_SERIAL.begin(115200);
}

// Set brightness (0-100%)
bool setLevel(uint8_t level) {
    uint8_t cmd[] = {0x02, 0x53, 0x00, level};
    DIMMER_SERIAL.write(cmd, 4);

    delay(10);
    if (DIMMER_SERIAL.available()) {
        return DIMMER_SERIAL.read() == 0x00;
    }
    return false;
}

// Get current brightness (returns 0-100%)
int getLevel() {
    uint8_t cmd[] = {0x02, 0x47, 0x00};
    DIMMER_SERIAL.write(cmd, 3);

    delay(10);
    if (DIMMER_SERIAL.available() >= 2) {
        uint8_t status = DIMMER_SERIAL.read();
        uint8_t level = DIMMER_SERIAL.read();
        if (status == 0x00) {
            return level;
        }
    }
    return -1;
}

// Set curve (0=LINEAR, 1=RMS, 2=LOG)
bool setCurve(uint8_t curve) {
    uint8_t cmd[] = {0x02, 0x43, 0x00, curve};
    DIMMER_SERIAL.write(cmd, 4);

    delay(10);
    if (DIMMER_SERIAL.available()) {
        return DIMMER_SERIAL.read() == 0x00;
    }
    return false;
}

// Get mains frequency (50 or 60 Hz)
int getFrequency() {
    uint8_t cmd[] = {0x02, 0x52};
    DIMMER_SERIAL.write(cmd, 2);

    delay(10);
    if (DIMMER_SERIAL.available() >= 2) {
        uint8_t status = DIMMER_SERIAL.read();
        uint8_t freq = DIMMER_SERIAL.read();
        if (status == 0x00) {
            return freq;
        }
    }
    return -1;
}

void loop() {
    setLevel(50);   // 50%
    delay(2000);
    setLevel(100);  // 100%
    delay(2000);
}


Arduino с SoftwareSerial (для Uno/Nano)

cpp
#include 

SoftwareSerial dimmerSerial(10, 11);  // RX, TX

void setup() {
    Serial.begin(115200);
    dimmerSerial.begin(115200);

    Serial.println("DimmerLink ready");
}

bool setLevel(uint8_t level) {
    uint8_t cmd[] = {0x02, 0x53, 0x00, level};
    dimmerSerial.write(cmd, 4);

    delay(10);
    if (dimmerSerial.available()) {
        return dimmerSerial.read() == 0x00;
    }
    return false;
}

void loop() {
    if (setLevel(50)) {
        Serial.println("Set to 50%: OK");
    } else {
        Serial.println("Set to 50%: ERROR");
    }
    delay(3000);
}

⚠️ Примечание: SoftwareSerial на Arduino Uno/Nano может работать нестабильно на скорости 115200. При возникновении ошибок связи рекомендуем использовать интерфейс I2C или плату с аппаратным UART (Arduino Mega, ESP32).


Python (pyserial)

python
import serial
import time

class DimmerLink:
    def __init__(self, port, baudrate=115200):
        try:
            self.ser = serial.Serial(port, baudrate, timeout=0.1)
        except serial.SerialException as e:
            print(f"Connection error to {port}: {e}")
            print("Check:")
            print("  - Is USB-UART adapter connected?")
            print("  - Correct port? (Windows: COM3, Linux: /dev/ttyUSB0)")
            raise

    def set_level(self, level):
        """Set brightness 0-100%"""
        cmd = bytes([0x02, 0x53, 0x00, level])
        self.ser.write(cmd)
        resp = self.ser.read(1)
        return len(resp) > 0 and resp[0] == 0x00

    def get_level(self):
        """Get brightness 0-100%"""
        cmd = bytes([0x02, 0x47, 0x00])
        self.ser.write(cmd)
        resp = self.ser.read(2)
        if len(resp) == 2 and resp[0] == 0x00:
            return resp[1]
        return None

    def set_curve(self, curve_type):
        """Set curve: 0=LINEAR, 1=RMS, 2=LOG"""
        cmd = bytes([0x02, 0x43, 0x00, curve_type])
        self.ser.write(cmd)
        resp = self.ser.read(1)
        return len(resp) > 0 and resp[0] == 0x00

    def get_frequency(self):
        """Get mains frequency (50 or 60 Hz)"""
        cmd = bytes([0x02, 0x52])
        self.ser.write(cmd)
        resp = self.ser.read(2)
        if len(resp) == 2 and resp[0] == 0x00:
            return resp[1]
        return None

    def close(self):
        self.ser.close()

# Usage example
if __name__ == "__main__":
    # Windows: 'COM3', Linux: '/dev/ttyUSB0'
    dimmer = DimmerLink('/dev/ttyUSB0')

    print(f"Mains frequency: {dimmer.get_frequency()} Hz")

    # Smooth brightness change
    for level in range(0, 101, 10):
        if dimmer.set_level(level):
            print(f"Brightness: {level}%")
        time.sleep(0.5)

    dimmer.close()


MicroPython (ESP32, Raspberry Pi Pico)

python
from machine import UART, Pin
import time

class DimmerLink:
    def __init__(self, uart_id=1, tx_pin=17, rx_pin=16):
        self.uart = UART(uart_id, baudrate=115200, tx=Pin(tx_pin), rx=Pin(rx_pin))

    def set_level(self, level):
        """Set brightness 0-100%"""
        cmd = bytes([0x02, 0x53, 0x00, level])
        self.uart.write(cmd)
        time.sleep_ms(10)
        if self.uart.any():
            return self.uart.read(1)[0] == 0x00
        return False

    def get_level(self):
        """Get brightness 0-100%"""
        cmd = bytes([0x02, 0x47, 0x00])
        self.uart.write(cmd)
        time.sleep_ms(10)
        if self.uart.any() >= 2:
            resp = self.uart.read(2)
            if resp[0] == 0x00:
                return resp[1]
        return None

    def set_curve(self, curve_type):
        """Set curve: 0=LINEAR, 1=RMS, 2=LOG"""
        cmd = bytes([0x02, 0x43, 0x00, curve_type])
        self.uart.write(cmd)
        time.sleep_ms(10)
        if self.uart.any():
            return self.uart.read(1)[0] == 0x00
        return False

    def get_frequency(self):
        """Get mains frequency"""
        cmd = bytes([0x02, 0x52])
        self.uart.write(cmd)
        time.sleep_ms(10)
        if self.uart.any() >= 2:
            resp = self.uart.read(2)
            if resp[0] == 0x00:
                return resp[1]
        return None

# Usage example
dimmer = DimmerLink()

print(f"Mains frequency: {dimmer.get_frequency()} Hz")

while True:
    for level in range(0, 101, 10):
        dimmer.set_level(level)
        print(f"Brightness: {level}%")
        time.sleep(0.5)



Для тех, кто не знаком с HEX

HEX (шестнадцатеричная система) — способ записи чисел.

Десятичное HEX Примечание
0 0x00 Ноль
50 0x32 Пятьдесят
100 0x64 Сто
255 0xFF Максимум для 1 байта


Как перевести число в HEX

Python:

python
level = 50
hex_value = hex(level)  # '0x32'
print(f"50 in HEX = {hex_value}")

Arduino:

cpp
int level = 50;
Serial.print("50 in HEX = 0x");
Serial.println(level, HEX);  // Prints "32"


Шпаргалка: яркость в HEX

Яркость HEX Команда SET
0% (выкл.) 0x00 02 53 00 00
10% 0x0A 02 53 00 0A
25% 0x19 02 53 00 19
50% 0x32 02 53 00 32
75% 0x4B 02 53 00 4B
100% 0x64 02 53 00 64


Вспомогательная функция для формирования команд

Python:

python
def make_set_command(level_percent):
    """Create SET command from percent"""
    return bytes([0x02, 0x53, 0x00, level_percent])

# Usage
cmd = make_set_command(75)  # 75%
print(f"Command: {cmd.hex()}")  # Prints: 0253004b

Arduino:

cpp
void sendSetCommand(uint8_t level) {
    uint8_t cmd[] = {0x02, 0x53, 0x00, level};
    Serial1.write(cmd, 4);
}

// Usage
sendSetCommand(75);  // 75%



Отладка


Проверка связи

Отправьте команду запроса частоты:

python
TX: 02 52
RX: 00 32  (OK, 50 Hz)


Типичные ошибки

Проблема Причина Решение
Нет ответа Отсутствует стартовый байт Добавьте 0x02 в начало
Нет ответа Неверная скорость Проверьте 115200
Нет ответа Интерфейс в режиме I2C Переключитесь обратно на UART
0xF9 Неизвестная команда Проверьте код команды
0xFC Ошибка записи в EEPROM Повторите команду
0xFE Недопустимый параметр level > 100 или curve > 2


Терминальные программы

For debugging you can use:
- Windows: RealTerm (HEX mode), SSCOM
- Linux: picocom, minicom
- Cross-platform: PuTTY, CoolTerm




What's Next?

← Подключение оборудования | Содержание | Далее: Обмен по I2C →