Passa al contenuto

← Collegamento hardware | Indice | Avanti: Comunicazione I2C →

Comunicazione UART

Descrizione dettagliata del protocollo UART per il controllo di DimmerLink.




Parametri di connessione

Parametro Valore
Baud Rate 115200
Bit di dati 8
Parità Nessuna (N)
Bit di stop 1
Formato 8N1

ℹ️ Nota: L'interfaccia UART è disponibile immediatamente dopo l'accensione.




Formato dei comandi

Tutti i comandi iniziano con il byte di avvio 0x02 (STX — Start of Text):

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

⚠️ Importante: Senza il byte di avvio 0x02, il comando non verrà elaborato!




Tabella dei comandi

Comando Codice Formato Descrizione
SET 0x53 ('S') 02 53 IDX LEVEL Impostare la luminosità
GET 0x47 ('G') 02 47 IDX Ottenere la luminosità
CURVE 0x43 ('C') 02 43 IDX TYPE Impostare la curva di dimmerizzazione
GETCURVE 0x51 ('Q') 02 51 IDX Ottenere il tipo di curva
FREQ 0x52 ('R') 02 52 Ottenere la frequenza di rete
RESET 0x58 ('X') 02 58 Reset software
SWITCH_I2C 0x5B ('[') 02 5B Passare a I2C


Parametri

  • IDX — indice del dimmer (0–7, la versione attuale supporta solo 0. I valori 1–7 sono riservati per future versioni multicanale)
  • LEVEL — luminosità 0–100 (percentuale)
  • TYPE — tipo di curva: 0=LINEAR, 1=RMS, 2=LOG



Codici di risposta

Codice Nome Descrizione
0x00 OK Comando eseguito con successo
0xF9 ERR_SYNTAX Formato non valido o comando sconosciuto
0xFC ERR_NOT_READY Errore di scrittura EEPROM
0xFD ERR_INDEX Indice dimmer non valido
0xFE ERR_PARAM Valore del parametro non valido



Descrizione dei comandi


SET — Impostare la luminosità

Formato: 02 53 IDX LEVEL

python
Example: 02 53 00 32  → Set dimmer 0 to 50%
Response: 00          → OK
LEVEL Luminosità
0x00 (0) 0% — spento
0x32 (50) 50%
0x64 (100) 100% — luminosità massima


GET — Ottenere la luminosità attuale

Formato: 02 47 IDX

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

📝 Nota: GET restituisce il valore in percentuale (0–100), come SET.


CURVE — Impostare la curva di dimmerizzazione

Formato: 02 43 IDX TYPE

TYPE Curva Applicazione
0 LINEAR Universale
1 RMS Incandescenza, alogene
2 LOG LED (corrisponde alla percezione visiva)
python
Example: 02 43 00 01  → Set RMS curve for dimmer 0
Response: 00          → OK


GETCURVE — Ottenere il tipo di curva

Formato: 02 51 IDX

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


FREQ — Ottenere la frequenza di rete

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 — Reset software

Formato: 02 58

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


SWITCH_I2C — Passare a I2C

Formato: 02 5B

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

Dopo l'esecuzione con successo, UART viene disabilitato e il dispositivo passa alla modalità I2C. Il controllo successivo avviene esclusivamente tramite I2C all'indirizzo 0x50 (o all'indirizzo configurato).

📝 Nota: La modalità viene salvata nella EEPROM e ripristinata dopo il riavvio.




Esempi di codice


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 (per 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 su Arduino Uno/Nano può essere instabile a 115200 baud. In caso di errori di comunicazione, si consiglia di utilizzare l'interfaccia I2C o una scheda con UART 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)



Per chi non conosce il formato HEX

HEX (esadecimale) è un modo per scrivere i numeri.

Decimale HEX Nota
0 0x00 Zero
50 0x32 Cinquanta
100 0x64 Cento
255 0xFF Massimo per 1 byte


Come convertire un numero in 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"


Tabella rapida: luminosità in HEX

Luminosità HEX Comando SET
0% (spento) 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


Funzione ausiliaria per costruire i comandi

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%



Debug


Test di connessione

Inviare il comando di richiesta frequenza:

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


Errori comuni

Problema Causa Soluzione
Nessuna risposta Byte START mancante Aggiungere 0x02 all'inizio
Nessuna risposta Baud rate errato Verificare 115200
Nessuna risposta Interfaccia in modalità I2C Tornare a UART
0xF9 Comando sconosciuto Verificare il codice comando
0xFC Errore di scrittura EEPROM Riprovare il comando
0xFE Parametro non valido level > 100 o curve > 2


Programmi terminale

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




What's Next?

← Collegamento hardware | Indice | Avanti: Comunicazione I2C →