Sep . 2025
Para controlar el DMR858M de forma eficiente y fiable, se recomienda un enfoque orientado a objetos, creando una clase de controlador que encapsule todas las interacciones con el módulo. Esta arquitectura es similar a las bibliotecas diseñadas para otros módulos de comando AT (como los módulos GSM o Wi-Fi) y ofrece buena modularidad y reutilización.
Diseñaremos una clase C++ llamada DMR858M_Controller. Esta clase se encargará de gestionar la comunicación UART, construir y analizar tramas de datos, gestionar comandos y respuestas, y gestionar el estado del módulo.
// DMR858M_Controller.h #include <Arduino.h> clase DMR858M_Controller { público: DMR858M_Controller(HardwareSerial& serial, int pttPin, int csPin); vacío begin(long speed); bool setFrequency(uint32_t txFreq, uint32_t rxFreq); bool setPowerLevel(bool highPower); bool getFirmwareVersion(String& version); vacío setPTT(bool active); // ... otros prototipos de funciones privado: HardwareSerial& _serial; int _pttPin; int _csPin; vacío sendCommand(uint8_t cmd, uint8_t rw, const uint8_t* data, uint16_t len); bool waitForResponse(uint8_t* búfer, uint16_t& len, uint32_t tiempo de espera = 1000); uint16_t calculateChecksum(const uint8_t* datos, tamaño_t len); };
sendCommand es el núcleo de todas las operaciones de escritura. Se encarga de ensamblar el paquete binario completo, calcular la suma de comprobación y enviarlo mediante UART.
// DMR858M_Controller.cpp void DMR858M_Controller::sendCommand(uint8_t cmd, uint8_t rw, const uint8_t* data, uint16_t len) { const uint16_t totalFrameLen = 9 + len; uint8_t frame[totalFrameLen]; frame[0] = 0x68; // Encabezado frame[1] = cmd; // CMD frame[2] = rw; // L/E frame[3] = 0x01; // S/R (Solicitud) frame[4] = 0x00; // CKSUM_HI (temporal) frame[5] = 0x00; // CKSUM_LO (temporal) frame[6] = (len >> 8) & 0xFF; // LEN_HI frame[7] = len & 0xFF; // LEN_LO si (datos y len > 0) { memcpy(&frame[8], datos, len); } frame[8 + len] = 0x10; // Cola // Calcular la suma de comprobación desde CMD hasta el final de DATOS uint16_t checksum = calculateChecksum(&frame[1], 7 + len); frame[4] = (suma de comprobación >> 8) y 0xFF; // CKSUM_HI frame[5] = suma de comprobación y 0xFF; // CKSUM_LO _serial.write(frame, totalFrameLen); } uint16_t DMR858M_Controller::calculateChecksum(const uint8_t* buf, size_t len) { uint32_t suma = 0; const uint8_t* current_buf = buf; size_t current_len = len; mientras (longitud_actual > 1) { suma += (uint16_t)((*buf_actual << 8) | *(buf_actual + 1)); buf_actual += 2; longitud_actual -= 2; } si (longitud_actual > 0) { suma += (uint16_t)(*buf_actual << 8); } mientras (suma >> 16) { suma = (suma & 0xFFFF) + (suma >> 16); } devolver (uint16_t)(suma ^ 0xFFFF); }
En sistemas embebidos, las esperas bloqueantes son un patrón de programación que debe evitarse. Una simple función waitForResponse que utilice un bucle como while(!_serial.available()){} congelará todo el bucle principal, impidiendo que el MCU realice otras tareas, como actualizar una pantalla o responder a las pulsaciones de botones, lo que provocará que el sistema no responda.
Un diseño más robusto debería ser no bloqueante . En el bucle principal, el programa debe verificar continuamente la presencia de datos en el puerto serie y usar una máquina de estados para procesar la trama de datos entrante. Este enfoque garantiza que el sistema pueda gestionar otros eventos en tiempo real mientras espera la respuesta del módulo. Para una plataforma como el ESP32 compatible con FreeRTOS, una mejor solución es crear una tarea RTOS dedicada a gestionar la comunicación con el módulo DMR. Esta tarea puede bloquearse cuando no hay datos sin afectar la ejecución de otras tareas.
A continuación se muestra un ejemplo simplificado de lógica de lectura sin bloqueo adecuada para una función loop() de Arduino:
// Lógica simplificada de manejo de respuesta sin bloqueo void loop() { // ... otras tareas... if (_serial.available()) { // Leer el byte y colocarlo en un búfer // Usar una máquina de estados para analizar el marco de datos (buscar el encabezado 0x68, leer la longitud especificada, verificar la suma de comprobación y la cola 0x10) // Una vez analizado exitosamente, procesar los datos de respuesta } }
El siguiente es un ejemplo completo de Arduino/PlatformIO que demuestra cómo inicializar el módulo, controlar PTT con un botón y enviar un SMS a través del monitor serial.
#include <Arduino.h> #include "DMR858M_Controller.h" #define PTT_BUTTON_PIN 25 #define PTT_MODULE_PIN 26 #define LED_PIN 2 HardwareSerial SerialTwo(2); DMR858M_Controller dmr(SerialTwo, PTT_MODULE_PIN, -1); void setup() { Serial.begin(115200); pinMode(PTT_BUTTON_PIN, INPUT_PULLUP); pinMode(LED_PIN, OUTPUT); dmr.begin(57600); delay(500); String fwVersion; if (dmr.getFirmwareVersion(fwVersion)) { Serial.println("Firmware DMR858M: " + fwVersion); } else { Serial.println("Error al comunicarse con el módulo DMR858M."); } // Ejemplo: Establecer la frecuencia para el canal 1 a 433,500 MHz dmr.setFrequency(433500000, 433500000); } void loop() { // Lógica de control PTT if (digitalRead(PTT_BUTTON_PIN) == LOW) { dmr.setPTT(true); digitalWrite(LED_PIN, HIGH); // Indicador de transmisión } else { dmr.setPTT(false); digitalWrite(LED_PIN, LOW); } // ... se puede agregar aquí una lógica de manejo de respuesta serial no bloqueante... // Ejemplo: Enviar SMS a través del monitor serial if (Serial.available()) { String cmd = Serial.readStringUntil('\n'); if (cmd.startsWith("sms")) { // Analizar el contenido del SMS y el ID del destino // Llamar a dmr.sendSMS(...) Serial.println("Comando SMS recibido."); } } }
Parte 1: Análisis en profundidad del módulo DMR858M
Parte 2: Integración de hardware y diseño de referencia
Parte 3: Desconstrucción del protocolo de control en serie
Parte 4: Desarrollo de firmware y diseño de controladores
Parte 5: Exploración de funciones avanzadas y conclusión
+86-755-23080616
ventas@nicerf.com
Sitio web: https://www.nicerf.com/
Dirección: 309-314, 3/F, Bldg A, edificio comercial Hongdu, Zona 43, Baoan Dist, Shenzhen, China
política de privacidad
· Política de privacidad
Actualmente no hay contenido disponible
Correo electrónico:sales@nicerf.com
Teléfono:+86-755-23080616