Ir al contenido

← Conexión de hardware | Contenido | Siguiente: Comunicación I2C →

Comunicación UART

Descripción detallada del protocolo UART para el control de DimmerLink.




Parámetros de conexión

Parámetro Valor
Velocidad (Baud Rate) 115200
Bits de datos 8
Paridad Ninguna (N)
Bits de parada 1
Formato 8N1

ℹ️ Nota: La interfaz UART está disponible inmediatamente después del encendido.




Formato de comandos

Todos los comandos comienzan con el byte de inicio 0x02 (STX — Start of Text):

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

⚠️ Importante: ¡Sin el byte de inicio 0x02, el comando no será procesado!




Tabla de comandos

Comando Código Formato Descripción
SET 0x53 ('S') 02 53 IDX LEVEL Establecer brillo
GET 0x47 ('G') 02 47 IDX Obtener brillo
CURVE 0x43 ('C') 02 43 IDX TYPE Establecer curva de atenuación
GETCURVE 0x51 ('Q') 02 51 IDX Obtener tipo de curva
FREQ 0x52 ('R') 02 52 Obtener frecuencia de red
RESET 0x58 ('X') 02 58 Reinicio por software
SWITCH_I2C 0x5B ('[') 02 5B Cambiar a I2C


Parámetros

  • IDX — índice del dimmer (0–7, la versión actual solo admite 0. Los valores 1–7 están reservados para futuras versiones multicanal)
  • LEVEL — brillo 0–100 (porcentaje)
  • TYPE — tipo de curva: 0=LINEAR, 1=RMS, 2=LOG



Códigos de respuesta

Código Nombre Descripción
0x00 OK Comando ejecutado correctamente
0xF9 ERR_SYNTAX Formato inválido o comando desconocido
0xFC ERR_NOT_READY Error de escritura en EEPROM
0xFD ERR_INDEX Índice de dimmer inválido
0xFE ERR_PARAM Valor de parámetro inválido



Descripción de comandos


SET — Establecer brillo

Formato: 02 53 IDX LEVEL

python
Example: 02 53 00 32  → Set dimmer 0 to 50%
Response: 00          → OK
LEVEL Brillo
0x00 (0) 0% — apagado
0x32 (50) 50%
0x64 (100) 100% — brillo máximo


GET — Obtener brillo actual

Formato: 02 47 IDX

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

📝 Nota: GET devuelve el valor en porcentaje (0–100), igual que SET.


CURVE — Establecer curva de atenuación

Formato: 02 43 IDX TYPE

TYPE Curva Aplicación
0 LINEAR Universal
1 RMS Incandescente, halógena
2 LOG LED (se ajusta a la percepción visual)
python
Example: 02 43 00 01  → Set RMS curve for dimmer 0
Response: 00          → OK


GETCURVE — Obtener tipo de curva

Formato: 02 51 IDX

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


FREQ — Obtener frecuencia de red

Formato: 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 — Reinicio por software

Formato: 02 58

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


SWITCH_I2C — Cambiar a I2C

Formato: 02 5B

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

Tras la ejecución exitosa, UART se desactiva y el dispositivo pasa al modo I2C. El control posterior se realiza únicamente a través de I2C en la dirección 0x50 (o la dirección configurada).

📝 Nota: El modo se guarda en EEPROM y se restaura tras el reinicio.




Ejemplos de código


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 con SoftwareSerial (para 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);
}

⚠️ Nota: SoftwareSerial en Arduino Uno/Nano puede ser inestable a 115200 baudios. Si experimenta errores de comunicación, recomendamos usar la interfaz I2C o una placa con UART por hardware (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)



Para quienes no conocen HEX

HEX (hexadecimal) es una forma de escribir números.

Decimal HEX Nota
0 0x00 Cero
50 0x32 Cincuenta
100 0x64 Cien
255 0xFF Máximo para 1 byte


Cómo convertir un número a 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"


Tabla rápida: brillo en HEX

Brillo HEX Comando SET
0% (apagado) 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


Función auxiliar para construir comandos

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%



Depuración


Prueba de conexión

Envíe el comando de solicitud de frecuencia:

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


Errores comunes

Problema Causa Solución
Sin respuesta Falta el byte START Agregar 0x02 al inicio
Sin respuesta Velocidad incorrecta Verificar 115200
Sin respuesta Interfaz en modo I2C Cambiar de vuelta a UART
0xF9 Comando desconocido Verificar código de comando
0xFC Error de escritura en EEPROM Reintentar comando
0xFE Parámetro inválido level > 100 o curve > 2


Programas de terminal

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




What's Next?

← Conexión de hardware | Contenido | Siguiente: Comunicación I2C →