問題
esp32を使ってSIMカード経由でネット通信がしたい
解決
- SIM7600のモジュールを買う (T-PCIE 4MB 9102、T-PCIE-SIM7600JC-H)
- ATコマンドを理解する
T-PCIE 4MB 9102
esp32のベースモジュール
T-PCIE-SIM7600JC-H
SIMカードを刺す通信モジュール
ベースモジュールに差し込んでビスで留める
ATコマンド
製造元のページよりユーザー登録して、ログインして、これらのPDFをダウンロードする
- SIM7500_SIM7600 Series_AT Command Manual_V3.00
- SIM7500_SIM7600_Series_HTTP(S)_Application Note_V3.00
- SIM7600_Series_PCIE_Hardware_Design_V1.03
参考
サンプルコード(VS Codeでplatform.ioを使っている)
どうも巷にあるサンプルコードではOCN ONEモバイルには素直に繋がらなかった
AT+COPS?
で通信業者を探してから、AT+COPS=
でちゃんとしてやらないとどうもネットワークを検索するばかりで繋がらなかった
一度つなげてしまえば、その後は巷にあるサンプルでも動き出す(というか多分設定がSIMに保存される?のでネットワークがすぐに見つかってる感じ?)
AT+COPS=で通信業者を自前で設定するコード
まず初回はこれでIPアドレスが取れるまでは確認しておく
ATコマンドの流れはここを参考にした
upload_port = /dev/cu.wchusbserial537D0225881は自分のものに変える
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
upload_port = /dev/cu.wchusbserial537D0225881
monitor_speed = 115200
build_flags = -DCORE_DEBUG_LEVEL=5
lib_deps =
vshymanskyy/TinyGSM@^0.11.5
vshymanskyy/StreamDebugger@^1.0.1
#define SerialMon Serial
#define SerialAT Serial1
static const char *TAG = "SIM LTE";
const char *apn = "ocn.ne.jp";
const char *gprsUser = "mobileid@ocn";
const char *gprsPass = "mobile";
#define uS_TO_S_FACTOR 1000000ULL
#define TIME_TO_SLEEP 60
#define PIN_TX 27
#define PIN_RX 26
#define UART_BAUD 115200
#define PWR_PIN 4
#define LED_PIN 12
#define POWER_PIN 25
#define IND_PIN 36
// https://github.com/vshymanskyy/TinyGSM#diagnostics-sketch
// デバッグログを出す(TinyGsmClient内に記載)
#define TINY_GSM_DEBUG SerialMon
// SIM7600指定(TinyGsmClient内に記載)
#define TINY_GSM_MODEM_SIM7600
// その上で読み込む
#include <TinyGsmClient.h>
// デバッグ設定
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm modem(debugger);
void setup() {
// デバッグログ用
SerialMon.begin(115200);
// 基本モジュールからの電源供給
pinMode(POWER_PIN, OUTPUT);
digitalWrite(POWER_PIN, HIGH);
delay(1000);
// この操作はここの事だと思う
// SIM7600_Series_PCIE_Hardware_Design_V1.03.pdf
// 3.2 PERST#
// The active low level time impulse on PERST# pin to reset module
pinMode(PWR_PIN, OUTPUT);
digitalWrite(PWR_PIN, HIGH);
delay(500);
digitalWrite(PWR_PIN, LOW);
// モデムにATcommandを送る用
SerialAT.begin(UART_BAUD, SERIAL_8N1, PIN_RX, PIN_TX);
// 起動までにちょっとまっておかないとATコマンドが受け付けられない
delay(5000);
if (!modem.init()) {
ESP_LOGD(TAG, "初期化失敗");
return;
}
//////////////////////////////////////////////
// ネットワーク、とりあえず全部ON(よく分かってない)
//////////////////////////////////////////////
// network
modem.sendAT(GF("+CREG=1"));
ESP_LOGD(TAG, "+CREG=1 %d", modem.waitResponse());
// GPRS network
modem.sendAT(GF("+CGREG=1"));
ESP_LOGD(TAG, "+CGREG=1 %d", modem.waitResponse());
// LTE network
// https://atmarkit.itmedia.co.jp/ait/articles/1001/13/news105.html
// LTEネットワークは、「進化したパケットシステム」という意味で「EPS(Evolved
// Packet System)」とも呼ばれ
modem.sendAT(GF("+CEREG=1"));
ESP_LOGD(TAG, "+CEREG=1 %d", modem.waitResponse());
//////////////////////////////////////////////
// 通信業者指定
//////////////////////////////////////////////
// 検索(時間がかかる)
modem.sendAT(GF("+COPS=?"));
ESP_LOGD(TAG, "+COPS=? %d", modem.waitResponse(20000L, GF("+COPS:")));
// 指定(ドコモ)
modem.sendAT(GF("+COPS=1,2,\"44010\""));
ESP_LOGD(TAG, "+COPS=1,2,\"44010\" %d", modem.waitResponse());
// 設定状況確認
modem.sendAT(GF("+COPS?"));
ESP_LOGD(TAG, "+COPS? %d", modem.waitResponse());
// APN接続
modem.sendAT(GF("+CGAUTH=1,2,\""), gprsPass, GF("\",\""), gprsUser, '"');
modem.waitResponse();
// 設定状況確認
modem.sendAT(GF("+CGAUTH?"));
ESP_LOGD(TAG, "+CGAUTH? %d", modem.waitResponse(GF("+CGAUTH:")));
////////////////////////////////////////
// TinyGsmClientSIM7600.h
// bool gprsConnectImpl をそのままコピーした
modem.sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"', ",\"0.0.0.0\",0,0");
modem.waitResponse();
modem.sendAT(GF("+CIPMODE=0"));
modem.waitResponse();
modem.sendAT(GF("+CIPSENDMODE=0"));
modem.waitResponse();
modem.sendAT(GF("+CIPCCFG=10,0,0,0,1,0,75000"));
if (modem.waitResponse() != 1) {
return;
}
modem.sendAT(GF("+CIPTIMEOUT="), 75000, ',', 15000, ',', 15000);
modem.waitResponse();
modem.sendAT(GF("+NETOPEN"));
if (modem.waitResponse(75000L, GF(GSM_NL "+NETOPEN: 0")) != 1) {
return;
}
// TinyGsmClientSIM7600.h
// bool gprsConnectImpl
////////////////////////////////////////
ESP_LOGD(TAG, "GPRS status: %s",
modem.isGprsConnected() ? "接続中 ..." : "接続していない");
IPAddress local = modem.localIP();
ESP_LOGD(TAG, "Local IP: %s", local.toString().c_str());
ESP_LOGD(TAG, "Signal Status: %d", modem.getRegistrationStatus());
}
void loop() {
ESP_LOGD(TAG, "...");
delay(1000);
}
上記で接続確認後は以下だけで動く
1点問題なのはTinyGsmClientSIM7600.h
のgprsConnectImpl
内+CGAUTH
ATコマンドのパラメータ順序が多分間違っていて、
- password
- user
という順序にTinyGsmClientSIM7600.h
を書き換えないといけないのかなと思うが、今思うと他の人がそんな事をせずに素直に動いているのは不思議。
セルラーモデムの試食というページを読んでみると、APNの情報はSIMに保存しているのか?とも思うがよく分かってない。
アクセスポイント情報の登録
単にSIMカードをセットしただけでは動作しません。新しいSIMカードを使うときは、まず最初にアクセスポイント関するデータ(APN、ユーザ名、パスワード、認証方式)を設定する必要があるのです。
#include <Arduino.h>
#define SerialMon Serial
#define SerialAT Serial1
#define PIN_TX 27
#define PIN_RX 26
#define UART_BAUD 115200
#define PWR_PIN 4
#define POWER_PIN 25
// #define DUMP_AT_COMMANDS
#define TINY_GSM_DEBUG SerialMon
#define TINY_GSM_MODEM_SIM7600
#include <TinyGsmClient.h>
#define APN "ocn.ne.jp"
#define APN_USER "mobileid@ocn"
#define APN_PASS "mobile"
#ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
Mobile::Mobile() : modem(debugger){};
#else
Mobile::Mobile() : modem(SerialAT){};
#endif
void setup() {
// 基本モジュールからの電源供給
pinMode(POWER_PIN, OUTPUT);
digitalWrite(POWER_PIN, HIGH);
delay(1000);
// この操作はここの事だと思う
// SIM7600_Series_PCIE_Hardware_Design_V1.03.pdf
// 3.2 PERST#
// The active low level time impulse on PERST# pin to reset module
pinMode(PWR_PIN, OUTPUT);
digitalWrite(PWR_PIN, HIGH);
delay(500);
digitalWrite(PWR_PIN, LOW);
SerialAT.begin(UART_BAUD, SERIAL_8N1, PIN_RX, PIN_TX);
// 起動までにちょっと待っておかないとATコマンドが受け付けられない
delay(5000);
// SIMにPINの設定があればinitに渡せる
if (!modem.init()) {
// AT→OKが出なかった
// 上のdelayが短いとかが考えられる
ESP_LOGE(MOBILE_TAG, "初期化失敗");
return;
}
// SIM7500_SIM7600 Series_AT Command Manual_V3.00.pdf
// 4.2.11 AT+CNMP Preferred mode selection
if (!modem.setNetworkMode(2)) {
ESP_LOGE(MOBILE_TAG, "ネットワーク選択設定失敗");
return;
}
if (!modem.waitForNetwork()) {
ESP_LOGE(MOBILE_TAG, "ネットワーク接続失敗");
return;
}
//////////////////////////////////////////////////////////////////
// TinyGsmClientSIM7600.h
// https://i.gyazo.com/9399b27cfb442030991e60d51acf95ca.png
//////////////////////////////////////////////////////////////////
// sendAT(GF("+CGAUTH=1,2,\""), user, GF("\",\""), pwd, '"');
// ↓ ↓
// sendAT(GF("+CGAUTH=1,2,\""), pwd, GF("\",\""), user, '"');
//////////////////////////////////////////////////////////////////
// /*
// * GPRS functions
// */
// protected:
// bool gprsConnectImpl(const char *apn, const char *user = NULL,
// const char *pwd = NULL) {
// gprsDisconnect(); // Make sure we're not connected first
// // Define the PDP context
// // The CGDCONT commands set up the "external" PDP context
// // Set the external authentication
// if (user && strlen(user) > 0) {
// sendAT(GF("+CGAUTH=1,2,\""), pwd, GF("\",\""), user, '"');
// waitResponse();
// }
// APNに接続
if (!modem.gprsConnect(APN, APN_USER, APN_PASS)) {
ESP_LOGE(MOBILE_TAG, "APN接続失敗");
return;
}
for (auto c = 0; c < 20; c++) {
delay(1000);
const auto quality = modem.getSignalQuality();
ESP_LOGI(MOBILE_TAG, "受信感度: %d", quality);
if (quality < 99) {
ESP_LOGI(MOBILE_TAG, "IPアドレス: %s",
modem.localIP().toString().c_str());
return;
}
}
}
void loop() {
ESP_LOGD(TAG, "...");
delay(1000);
}