pdf-icon

Arduino入門

2. デバイス&サンプル

6. アプリケーション

Module COMX LTE Arduino チュートリアル

1. 準備

2. 注意事項

ピン互換性
ホストごとにピン配置が異なるため、使用前に製品ドキュメントのピン互換表を参照し、実際のピン接続に合わせてサンプルプログラムを修正してください。

3. サンプルプログラム

  • 本チュートリアルでは CoreS3-SE をメインコントローラーとして使用し、Module COMX LTE と外付けマイク付きイヤホンを組み合わせて発信通話を行います。使用前に、下図を参考にピン用 DIP スイッチを指定の位置に切り替えてください。

3.1 ピン用 DIP スイッチ

Module COMX LTE は UART で通信します。実際の回路接続に応じてプログラム内のピン定義を修正してください。デバイス接続後、対応するシリアル IO は G1 (RX)G7 (TX) です。実物は下図の通りです:

説明
1. DIP スイッチの COM RST を ON に設定すると、モジュールがホストのリセットピンに接続されます。ホストのリセット時にモジュールもリセットされるため、モジュールの初期化に要する時間が長くなります。実際の要件に応じて設定してください。
2. Core シリーズのホストを使用する場合、DIP スイッチの 25 OUT を ON に設定すると、ホスト内蔵スピーカーを通話音声の出力として使用できます(Core シリーズのみ対応)。

3.2 イヤホンの選定

Module COMX LTE には 3.5mm TRRS イヤホンジャックが搭載されており、マイク付きイヤホンを接続して通話音声の入出力に使用できます。本ジャックは 17mm 長のプラグに対応します。14mm 長のプラグでは正常に使用できないため、下図のようなオス-メス変換アダプタを使用して接続してください:

3.3 プログラムコード

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
#include <M5Unified.h>

// Call-related status variables (volatile for interrupt-safe access)
volatile bool call_connected = false;
volatile bool call_ended     = false;
volatile int  call_result    = 0;   // Call result code: 0=Unknown, 1=Connected, 2=Unanswered, 3=Busy

bool  network_ready = false;
bool  calling       = false;

// Read all available data from LTE module serial port and update call status
// Parses Unsolicited Result Codes (URC) from LTE module to detect call state changes
void readLTEURC()
{
    static String buf;

    while (Serial2.available() > 0) {
        char c = (char)Serial2.read();
        buf += c;
    }

    if (buf.length() == 0) return;

    // Determine call status by matching URC keywords
    if (buf.indexOf("VOICE CALL: BEGIN") != -1) {
        call_connected = true;
        call_result    = 1;
        Serial.println("[COMX LTE URC] CALL CONNECTED (VOICE CALL: BEGIN)");
    }
    if (buf.indexOf("VOICE CALL: END") != -1) {
        call_ended = true;
        Serial.println("[COMX LTE URC] CALL ENDED (VOICE CALL: END)");
    }
    if (buf.indexOf("NO CARRIER") != -1) {
        call_ended = true;
        if (!call_connected) {
            call_result = 2;
        }
        Serial.println("[COMX LTE URC] CALL ENDED (NO CARRIER)");
    }
    if (buf.indexOf("BUSY") != -1) {
        call_ended  = true;
        call_result = 3;
        Serial.println("[COMX LTE URC] CALL BUSY");
    }

    // Print raw OK/ERROR responses (dialing uses sendATandWait's timeout handling)
    if (buf.indexOf("OK") != -1 || buf.indexOf("ERROR") != -1) {
        Serial.print("[COMX LTE RSP RAW] ");
        Serial.println(buf);
    }

    // Clear after processing to prevent overflow
    buf = "";
}

// Send AT command to LTE module and wait for OK/ERROR response with timeout
// @param cmd: AT command string (must include \r\n for line ending)
// @param resp: Reference to store full response from module
// @param timeout_ms: Maximum wait time in milliseconds
// @return: true = "OK" received, false = "ERROR" received or timeout
bool sendATandWait(const String& cmd, String& resp, uint32_t timeout_ms)
{
    resp = "";
    Serial.print("[COMX LTE TX] ");
    Serial.print(cmd);

    Serial2.print(cmd);// Transmit AT command to LTE module

    uint32_t start = millis();
    // Wait for response until timeout expires
    while (millis() - start < timeout_ms) {
        while (Serial2.available() > 0) {
            char c = (char)Serial2.read();
            resp += c;

            // Check for termination conditions (OK/ERROR)
            if (resp.indexOf("OK") != -1) {
                Serial.print("[COMX LTE RSP] ");
                Serial.println(resp);
                return true;
            }
            if (resp.indexOf("ERROR") != -1) {
                Serial.print("[COMX LTE RSP] ");
                Serial.println(resp);
                return false;
            }
        }
        delay(10);
    }

    Serial.print("[COMX LTE RSP TIMEOUT] ");
    Serial.println(resp);
    return false;
}

// Wait for LTE module initialization completion
// Verifies basic AT command responsiveness (OK response to "AT" command)
// @param timeout_ms: Maximum wait time for module to respond
// @return: true = module ready (AT port responsive), false = timeout
bool waitForModuleReady(uint32_t timeout_ms)
{
    uint32_t start = millis();
    Serial.println("[COMX LTE] Waiting for module ready...");
    while (millis() - start < timeout_ms) {
        readLTEURC();                 // 吃掉启动URC/残留输出
        String resp;
        if (sendATandWait("AT\r\n", resp, 1000)) {
            Serial.println("[COMX LTE] Module ready.");
            return true;              // 回复OK,说明AT口已就绪
        }
        delay(200);
    }
    Serial.println("[COMX LTE] Module not ready (timeout).");
    return false;
}

// Wait for SIM7600G network readiness (GPRS attach + LTE network registration)
// Verifies both CGATT (attach) and CEREG (registration) statuses
// @param timeout_ms: Maximum wait time for network registration
// @return: true = network registered, false = timeout
bool waitForNetworkReady(uint32_t timeout_ms)
{
    uint32_t start = millis();
    Serial.println("[COMX LTE] Waiting for network...");

    while (millis() - start < timeout_ms) {
        String resp;

        // 1) Query GPRS attach status: AT+CGATT?
        // Expected response: +CGATT: 1 (attached) / +CGATT: 0 (detached)
        if (sendATandWait("AT+CGATT?\r\n", resp, 2000)) {
            if (resp.indexOf("+CGATT: 1") == -1) {
                Serial.println("[COMX LTE] Not attached, retry...");
                delay(1000);
                continue;
            }
        } else {
            Serial.println("[COMX LTE] CGATT? error, retry...");
            delay(1000);
            continue;
        }

        // 2) Query LTE network registration status: AT+CEREG?
        // Expected responses: 
        // +CEREG: 0,1 = Registered (home network)
        // +CEREG: 0,5 = Registered (roaming network)
        resp = "";
        if (sendATandWait("AT+CEREG?\r\n", resp, 2000)) {
            if (resp.indexOf("+CEREG:") != -1 &&
                (resp.indexOf(",1") != -1 || resp.indexOf(",5") != -1)) {
                Serial.println("[COMX LTE] Network registered.");
                return true;
            } else {
                Serial.println("[COMX LTE] Not registered, retry...");
            }
        } else {
            Serial.println("[COMX LTE] CEREG? error, retry...");
        }

        delay(100);
    }

    Serial.println("[COMX LTE] Network not ready (timeout).");
    return false;
}

void setup()
{
    M5.begin();
    Serial.begin(115200);
    Serial.println("\r\n[COMX LTE] Start");
    Serial2.begin(115200, SERIAL_8N1, 1, 7); // Initialize LTE module serial port RX=1,TX=7

    M5.Display.setFont(&fonts::FreeMonoBold9pt7b);
    M5.Display.setTextDatum(middle_center);
    M5.Display.clear();
    M5.Display.drawString("Module Initializing...", 160, 120);

    delay(500);

    // Initialize LTE module first, then check network status
    if (!waitForModuleReady(25000)) {// Module initialization typically takes up to 20s
        network_ready = false;
    } else {
        network_ready = waitForNetworkReady(30000);
    }

    M5.Display.clear();
    if (network_ready) {
        Serial.println("[COMX LTE] Touch screen to dial/stop");
        M5.Display.drawString("Touch screen to dial", 160, 80);
    } else {
        Serial.println("[COMX LTE] Network NOT ready, please reset.");
        M5.Display.drawString("Network not ready", 160, 120);
    }
}

void loop()
{
    M5.update();
    auto touchDetail = M5.Touch.getDetail();

    // Continuously read URC messages from LTE module
    readLTEURC();

    // Block dialing if network is not fully registered
    if (!network_ready) {
        delay(50);
        return;
    }

    // Handle touch input for dial/hangup control
    if (!calling && touchDetail.wasPressed()) {
        calling          = true;
        call_connected = false;
        call_ended     = false;
        call_result    = 0;

        Serial.println("[COMX LTE] Dialing...");
        M5.Display.clear();
        M5.Display.drawString("Calling......", 160, 120);
        M5.Display.drawString("Touch screen to hang up", 160, 80);

        String resp;
        // ATD command format: ATD<phone_number>
        bool ok = sendATandWait("ATDXXXXXXXXXXX;\r\n", resp, 10000);

        Serial.print("[DIAL RESULT] ");
        Serial.println(ok ? "OK" : "ERROR/TIMEOUT");
    }
    else if (calling && touchDetail.wasPressed()) {
        Serial.println("[COMX LTE] Hangup");
        String resp;
        sendATandWait("AT+CHUP\r\n", resp, 5000);

        calling     = false;
        call_ended  = true; 
        M5.Display.clear();
        M5.Display.drawString("Call ended", 160, 120);
        M5.Display.drawString("Touch screen to dial", 160, 80);
    }

    // Update display based on real-time call status
    if (calling) {
        if (call_connected) {
            M5.Display.clear();
            M5.Display.drawString("Speaking......", 160, 120);
            M5.Display.drawString("Touch screen to hang up", 160, 80);
        }
        if (call_ended) {
            calling = false;
            M5.Display.clear();
            M5.Display.drawString("Call ended", 160, 120);
            M5.Display.drawString("Touch screen to dial", 160, 80);
        }
    }

    delay(20);
}

4. コンパイルと書き込み

  • 1. ダウンロードモードに入る:CoreS3-SE のリセットボタンを(約 2 秒)長押しし、内部の緑色 LED が点灯したら離します。デバイスはダウンロードモードに入り、書き込みを待機します。
説明
デバイスによっては、書き込み前にダウンロードモードへ移行する必要があります。主控デバイスにより手順が異なる場合があります。詳細は Arduino IDE 入門チュートリアル ページ下部の「デバイスへの書き込み」手順一覧を参照し、具体的な操作方法を確認してください。
  • デバイスのポートを選択し、Arduino IDE 左上のコンパイルと書き込みボタンをクリックして、プログラムのコンパイルとデバイスへの書き込みが完了するまで待ちます。

5. 発信通話

  • 電源投入後、Module COMX LTE モジュールは自動的に初期化され、ネットワークへの接続を試みます。接続に成功したら、ホストの画面をタッチすると発信できます。通話中にもう一度画面をタッチすると通話を終了し、画面には現在の通話状態が表示されます。

  • シリアルモニターの出力例:
[COMX LTE] Start
[COMX LTE] Waiting for module ready...
[COMX LTE TX] AT
[COMX LTE RSP] AT

OK
[COMX LTE] Module ready.
[COMX LTE] Waiting for network...
[COMX LTE TX] AT+CGATT?
[COMX LTE RSP] 
AT+CGATT?

+CGATT: 1

OK
[COMX LTE TX] AT+CEREG?
[COMX LTE RSP] 
AT+CEREG?

+CEREG: 0,1

OK
[COMX LTE] Network registered.
[COMX LTE] Touch screen to dial/stop
[COMX LTE] Dialing...
[COMX LTE TX] ATDXXXXXXXXXX;
[COMX LTE RSP] ATDXXXXXXXXXX;

OK
[DIAL RESULT] OK
[COMX LTE URC] CALL CONNECTED (VOICE CALL: BEGIN)
[COMX LTE] Hangup
[COMX LTE TX] AT+CHUP
[COMX LTE RSP] AT+CHUP

VOICE CALL: END: 000008

OK
On This Page