Sep . 2025
Pour contrôler le DMR858M de manière efficace et fiable, une approche orientée objet est recommandée, créant une classe de pilote pour encapsuler toutes les interactions avec le module. Cette architecture est similaire aux bibliothèques conçues pour d'autres modules de commande AT (tels que les modules GSM ou Wi-Fi) et offre une bonne modularité et une grande réutilisabilité.
Nous concevrons une classe C++ nommée DMR858M_Controller. Cette classe sera responsable de la gestion des communications UART, de la création et de l'analyse des trames de données, de la gestion des commandes et des réponses, et de la gestion de l'état du module.
// DMR858M_Controller.h #include <Arduino.h> class DMR858M_Controller { public: DMR858M_Controller(HardwareSerial& serial, int pttPin, int csPin); void begin(long speed); bool setFrequency(uint32_t txFreq, uint32_t rxFreq); bool setPowerLevel(bool highPower); bool getFirmwareVersion(String& version); void setPTT(bool active); // ... autres prototypes de fonctions private: HardwareSerial& _serial; int _pttPin; int _csPin; void sendCommand(uint8_t cmd, uint8_t rw, const uint8_t* data, uint16_t len); bool waitForResponse(uint8_t* tampon, uint16_t& len, uint32_t timeout = 1000); uint16_t calculateChecksum(const uint8_t* données, size_t len); };
La commande sendCommand est au cœur de toutes les opérations d'écriture. Elle est responsable de l'assemblage du paquet binaire complet, du calcul de la somme de contrôle et de son envoi via 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; // Head frame[1] = cmd; // CMD frame[2] = rw; // R/W frame[3] = 0x01; // S/R (Requête) frame[4] = 0x00; // CKSUM_HI (temporaire) frame[5] = 0x00; // CKSUM_LO (temporaire) frame[6] = (len >> 8) & 0xFF; // LEN_HI frame[7] = len & 0xFF; // LEN_LO if (data && len > 0) { memcpy(&frame[8], data, len); } frame[8 + len] = 0x10; // Tail // Calculer la somme de contrôle de CMD à la fin de DATA uint16_t checksum = calculateChecksum(&frame[1], 7 + len); frame[4] = (checksum >> 8) & 0xFF; // CKSUM_HI frame[5] = checksum & 0xFF; // CKSUM_LO _serial.write(frame, totalFrameLen); } uint16_t DMR858M_Controller::calculateChecksum(const uint8_t* buf, size_t len) { uint32_t sum = 0; const uint8_t* current_buf = buf; size_t current_len = len; while (current_len > 1) { somme += (uint16_t)((*current_buf << 8) | *(current_buf + 1)); current_buf += 2; current_len -= 2; } if (current_len > 0) { somme += (uint16_t)(*current_buf << 8); } while (somme >> 16) { somme = (somme & 0xFFFF) + (somme >> 16); } return (uint16_t)(somme ^ 0xFFFF); }
Dans les systèmes embarqués, les attentes bloquantes sont un schéma de programmation à éviter. Une simple fonction waitForResponse utilisant une boucle comme while(!_serial.available()){} gèlera toute la boucle principale, empêchant le microcontrôleur d'effectuer d'autres tâches, comme la mise à jour d'un affichage ou la réponse aux boutons, ce qui entraînera un système insensible.
Une conception plus robuste devrait être non bloquante . Dans la boucle principale, le programme doit vérifier en permanence la présence de données sur le port série et utiliser une machine à états pour traiter la trame de données entrante. Cette approche garantit que le système peut continuer à gérer d'autres événements temps réel en attendant une réponse du module. Pour une plateforme comme l'ESP32 prenant en charge FreeRTOS, une meilleure solution consiste à créer une tâche RTOS dédiée pour gérer la communication avec le module DMR. Cette tâche peut se bloquer en l'absence de données sans affecter l'exécution des autres tâches.
Voici un exemple simplifié de logique de lecture non bloquante adaptée à une fonction Arduino loop() :
// Logique simplifiée de gestion des réponses non bloquantes void loop() { // ... autres tâches... if (_serial.available()) { // Lire l'octet et le placer dans un tampon // Utiliser une machine à états pour analyser la trame de données (rechercher l'en-tête 0x68, lire la longueur spécifiée, vérifier la somme de contrôle et la queue 0x10) // Une fois l'analyse réussie, traiter les données de réponse } }
Ce qui suit est un exemple Arduino/PlatformIO complet qui montre comment initialiser le module, contrôler le PTT avec un bouton et envoyer un SMS via le moniteur série.
#include <Arduino.h> #include "DMR858M_Controller.h" #définir PTT_BUTTON_PIN 25 #définir PTT_MODULE_PIN 26 #définir 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("Micrologiciel DMR858M : " + fwVersion); } else { Serial.println("Échec de la communication avec le module DMR858M."); } // Exemple : définir la fréquence du canal 1 sur 433,500 MHz dmr.setFrequency(433500000, 433500000); } void loop() { // Logique de contrôle PTT if (digitalRead(PTT_BUTTON_PIN) == LOW) { dmr.setPTT(true); digitalWrite(LED_PIN, HIGH); // Indicateur de transmission } else { dmr.setPTT(false); digitalWrite(LED_PIN, LOW); } // ... une logique de gestion de réponse série non bloquante peut être ajoutée ici... // Exemple : envoyer des SMS via un moniteur série if (Serial.available()) { String cmd = Serial.readStringUntil('\n'); if (cmd.startsWith("sms")) { // analyser le contenu du SMS et l'ID cible // appeler dmr.sendSMS(...) Serial.println("Commande SMS reçue."); } } }
Partie 1 : Analyse approfondie du module DMR858M
Partie 2 : Intégration matérielle et conception de référence
Partie 3 : Déconstruction du protocole de contrôle série
Partie 4 : Développement du micrologiciel et conception des pilotes
Partie 5 : Exploration des fonctionnalités avancées et conclusion
+86-755-23080616
sales@nicerf.com
Site Internet : https://www.nicerf.com/
Adresse : 309-314, 3/F, bâtiment A, bâtiment commercial de Hongdu, zone 43, Baoan Dist, Shenzhen, Chine
politique de confidentialité
· Politique de confidentialité
Il n'y a actuellement aucun contenu disponible
Courriel : sales@nicerf.com
Tél : +86-755-23080616