多くのATコマンドがあり、コードが多すぎず、文字がたくさんあります。
必要なもの
GSMモジュールを初期化し、サーバーとの接続を確立し、任意のデータを送受信し、接続ステータスを確認し、失敗することなく動作するコードを記述する必要がありました。 また、マイクロコントローラの限られたメモリに収まるように十分にコンパクトであり、主な機能のための余地を残し、もう少し余裕があります。
結果として何が起こったのか
結果は、必要なことを何でも行うことができるCコードです。 コンパクトさの要件のため、回答を解析し、独自のコードを使用して文字列を生成する必要がありました。これは正直な人を表示するのは恥ずべきことです。 したがって、これらの目的のために正規表現を使用することを全員に推奨します。 また、コードを軽量の正規表現エンジンに転送しますが、完全に機能するファームウェアを作成した後です。
このコードには、シリアルポートで機能する関数/マクロ、およびmemset関数とmemcpy関数が必要です。 そのため、多くのライブラリをフックすることなく、比較的簡単に別のプラットフォームに転送できます。
そして、それはどのように見えますか?
プログラミングとテストはWindows 7で実行されました。結果として得られたコードがこの記事の主要な資料になりました。 コードを完全に引用してコメントすることはしませんが、代わりにGSMモジュールのセットアップと操作のアルゴリズムを示します。
コードに必要な機能:
-
uint16_t init_serial_port(char *port_name)
この関数は、指定されたシリアルポートを設定します。 Windowsの下。 -
uint16_t puts_serial(uint8_t *buffer, uint16_t size)
そして、このポートにバイト文字列を書き込みます。 -
gets_serial(uint8_t *buffer, uint16_t size)
これは、それぞれ、シリアルポートからバイトの文字列を読み取ります。
コードが提供する機能は次のとおりです。
-
init_gprs() & stop_gprs()
それぞれGSMモジュールを初期化および削減します。 -
uint16_t connect_gprs(uint8_t index, uint8_t mode, char *address, char *port)
サーバーとの接続を確立します。 モジュールがクライアントとしてもクライアントとしてもTCPおよびUDPプロトコルで動作できることは注目に値します。 最大8つの同時接続がサポートされています。 -
uint16_t close_gprs(uint8_t index)
指定された接続を閉じます。 -
uint16_t send_gprs(uint8_t index, uint8_t *buffer, uint16_t size)
指定された接続を介してメッセージを送信します。 -
uint16_t recv_gprs(uint8_t index, uint8_t *buffer, uint16_t size)
メッセージを受信します。 ノンブロッキング関数。つまり、ストリームにデータが現れるのを待たずに、受信するものがない場合は制御を返します。 この動作は、ブロッキングよりも実装が簡単であることに注意してください。
シリアルポートを使用する方法
とても簡単です。 ターゲットマイクロコントローラーの下には、 USARTを介してデータを送受信するためのマクロがありますが、このようなコードを固定コンピューターからデバッグする方が簡単なので、USB <-> USARTアダプターとGSMモジュールがたくさん提供されました。 Windowsでシリアルポートを操作する方法を学ぶために残っただけです。 簡単なことがわかりました。 要するに、シリアルポートはOSでは通常のファイルとして表示され、情報はReadFile 関数とWriteFile関数によって送信されます 。 SetCommTimeoutsおよびSetCommState関数を使用していくつかのパラメーターを設定するだけです。
ポート初期化関数は次のようになります。
uint16_t init_serial_port(char *port_name) { COMMTIMEOUTS timeouts; DCB parameters; int result; serial_port_handle = CreateFile(port_name, // "\\\\.\\COMx" GENERIC_READ | GENERIC_WRITE, 0, // NULL, OPEN_EXISTING, 0, NULL); if (serial_port_handle == INVALID_HANDLE_VALUE) { printf("Error opening a serial port!\n"); return 1; } // timeouts.ReadIntervalTimeout = 100; // timeouts.ReadTotalTimeoutMultiplier = 0; // , // timeouts.ReadTotalTimeoutConstant = 1000; // , , . timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = 1000; result = SetCommTimeouts(serial_port_handle, &timeouts); if (result == 0) { printf("Error setting timeouts for serial port!\n"); close_serial_port(); return 1; } // - // , , 1 -. memset(¶meters,0,sizeof(parameters)); parameters.DCBlength = sizeof(DCB); GetCommState(serial_port_handle, ¶meters); parameters.BaudRate = (DWORD)BAUD_RATE; parameters.ByteSize = 8; parameters.Parity = NOPARITY; parameters.StopBits = ONESTOPBIT; parameters.fAbortOnError = TRUE; parameters.fDtrControl = DTR_CONTROL_DISABLE; parameters.fRtsControl = RTS_CONTROL_DISABLE; parameters.fBinary = TRUE; parameters.fParity = FALSE; parameters.fOutX = FALSE; parameters.fInX = FALSE; parameters.XonChar = (uint8_t)0x00; parameters.XoffChar = (uint8_t)0xff; parameters.fErrorChar = FALSE; parameters.fNull = FALSE; parameters.fOutxCtsFlow = FALSE; parameters.fOutxDsrFlow = FALSE; parameters.XonLim = 128; parameters.XoffLim = 128; result = SetCommState(serial_port_handle, ¶meters); if (result == 0) { printf("Error setting serial port parameters!\n"); close_serial_port(); return 1; } return 0; }
GSMモジュールとの通信はどうですか
シリアルポートを設定したら、ATコマンドを送信できます。 最初のコマンドはシーケンス
"AT\r"
で、モジュールがシリアルポートのボーレートを自動的に構成できるようにする必要があります。 この後、ポートから取得できる答えは、
"AT\r\r\nOK\r\n"
ます。
コマンドは、ASCII文字の単純な文字列です。 モジュールがコマンドを受け入れるようにするには、末尾に復帰文字
"\r"
を付けます。 応答として、モジュールは2つの部分で構成される文字列を送信します。モジュールは、「\ r \ n \ n」で終わる文字「\ r \ r \ n」で区切られた応答で応答するコマンドです。 回答の解析を容易にするために、受信バッファーの応答の先頭にポインターを設定するマクロを作成しました。 コンソールに回答を表示する場合は、受信したメッセージの最後にヌル文字を追加する必要があります。
void at_send(char *cmd, uint16_t size) { uint16_t result; cmd[size - 1] = '\r'; result = puts_serial(cmd, size); return; } uint16_t at_recv(uint8_t *buffer, uint16_t size) { uint16_t result; result = gets_serial(buffer, size); return result; }
コマンドを送信し、応答を受信するための補助関数は次のようになります。
モジュールの初期化
コードの最大の機能は、モジュールのセットアップを担当します。 初期化により多くのATコマンドが送信されます。 それらをモジュールに送信された順序で説明します。 引数と回答オプションについて詳しく説明していません。これらはドキュメントに記載されているためです。
-
"AT+CPIN=pin-code"
とおり、このコマンドはピンコードを入力してSIMカードのロックを解除します。 PINコードが必要かどうかを確認するには、コマンド"AT+CPIN?"
使用できます"AT+CPIN?"
。 -
"AT+CREG?"
このコマンドは、ネットワーク内のモジュールの登録ステータスを返します。 モジュールがネットワークに登録されていると応答するまで実行する必要があります。 -
"AT+CGATT=1"
モジュールを強制的にGPRSに接続します。 接続されているかどうかを確認します。コマンド"AT+CGATT?"
使用できます"AT+CGATT?"
。 -
"AT+CIPRXGET=1"
接続を介して手動で送信されたデータの受信を有効にします。 デフォルトでは、このパラメーターは無効になっており、データは受信するとすぐにシリアルポートに送信されます。 これはあまり重要ではありませんが、あまり便利ではありません。モジュールは、データとともにIPヘッダーも送信するように構成できます。これにより、パケットの受信者を判別できます。 データを手動で受信する方が簡単であり、間違いではないと判断しました。 私が理解しているように、このコマンドはSIM.COM GSMモジュールでのみ受け入れられます。 -
"AT+CIPMUX=1"
デフォルトでは、モジュールは1つの接続のみを確立できます。 このオプションを使用すると、複数の接続を作成できます。 データの送信と受信は、接続インデックスという1つのパラメーターだけが異なります。 -
"AT+CSTT="internet""
アクセスポイント名、GPRSのアクセスポイント名。 私のプロバイダーにとってはまさにそのように見えます。 -
"AT+CIICR"
ワイヤレスGPRS接続を確立します。 時間がかかる場合があるため、ループで実行して応答を確認する必要があります。 -
"AT+CIFSR"
モジュールのIPアドレスを返します。 このモジュールを使用して、モジュールがインターネットに接続されているかどうかを確認します。 -
"AT+CDNSCFG="8.8.8.8","8.8.4.4""
このコマンドは、モジュールが使用するDNSサーバーをインストールします。 -
"AT+CIPSTATUS"
このコマンドは、接続ステータスデータに加えて、モジュールが接続を確立する準備ができているかどうかに関する情報を提供します。 彼女の答えを確認する必要があります。
これらのコマンドを実行すると、モジュールは動作可能な状態になります。 まあかどうか。 ここは幸運です。
インストールと切断
接続は
"AT+CIPSTART=index,"mode","address","port""
コマンド
"AT+CIPSTART=index,"mode","address","port""
。
-
index
は接続のシリアル番号を示し、0〜7の値を取ることができます。 -
mode
は、接続が使用するプロトコルを定義します。 「TCP」または「UDP」のいずれかです。 -
address
はサーバーのaddress
設定します。 構成中にDNSサーバーを指定した場合、IPアドレスとドメイン名の両方を使用できます。 -
port
は、接続が確立されるサーバーのポートを指定します。
UDPプロトコルを使用する場合、デフォルトでは、データグラムは1つのアドレスからのみ送受信されることに注意してください。 UDPを最大限に使用し、任意のアドレスからデータを送受信するには、コマンド
"AT+CIPUDPMODE"
で構成された、いわゆるアドバンストUDPモードを使用できます。 詳細については、ドキュメントを参照してください。
コマンドに対する応答で、いくつかの回答を得ることができます。 すべてが順調であれば、標準の
"OK"
後、しばらくしてから、次の3つの答えのいずれかを取得できます。
-
"index,ALREADY CONNECT"
これは、特定のインデックスとの接続が既に確立されており、それを探す価値があることを意味します。 -
"index,CONNECT OK"
すべてがここで明らかです。 -
"index,CONNECT FAIL"
は、接続の確立に問題があることを意味します。
コマンド
"AT+CIPCLOSE=index"
接続を終了できます。
"AT+CIPSHUT"
を使用して、すべての接続を切断し、GPRSインターフェースを無効にすることができます。
データ転送
データはコマンド
"AT+CIPSEND=index,length"
使用して送信されます
"AT+CIPSEND=index,length"
はデータの送信に使用する接続を示し、lengthはデータパケットの長
length
設定します。 ところで、コマンド
"AT+CIPSEND=?"
を使用して、各接続のMTUを確認できます
"AT+CIPSEND=?"
。
すべてが正常であれば、モジュールはコマンドに応答して
">"
プロンプトを発行します。その後、シリアルポートにデータを送信する必要があります。 モジュールが
length
に等しいバイト数を受け取るとすぐに、
"index,SEND OK"
ような
"index,SEND OK"
ます。 一般に、
length
パラメーターを使用しないことは可能ですが、この場合、データパケットの終わりは、端末でCtrl + Zの組み合わせで
0x1A
文字を使用して明示的に示す必要があります。 任意のデータの転送には、このオプションは明らかに適切ではありません。
ご覧のとおり、データ転送はそれほど複雑なプロセスではありません。 したがって、最も興味深いのはデータ受信です。
データ受信
GSMモジュールはデータを受信するとすぐに、
"+CIPRXGET:1,index\r\n"
という形式の文字列をシリアルポートに送信することにより、これを通知します。 モジュールのこの機能の文書化が不十分であるため、私はユニットの意味を正直に知りませんが、パケットの受信に関するすべてのメッセージに表示されます。
何らかの方法でモジュールメッセージを監視する必要があるという考えに満足できませんでした。 しかし、デバッガーで少し遊んだ後、モジュールが他の非同期メッセージを送信しないこと、およびATコマンドを実行した後、このメッセージがバッファーの先頭に表示されることがわかりました。 部分文字列
"\r\r\n"
検索してコマンドから応答を分離するマクロをコンパイルしたので、これは決して影響しませんでした。 したがって、データを受信する機能は非常に簡単に実装されました。
したがって、コマンド
"AT+CIPRXGET=2,index,length"
を使用してデータを受信できます。 2つは、受信モードを意味します。この場合、バイトはシリアルポートに単純に注がれます。 また、 プログラムによるフロー制御との競合を防ぐために、HEXテキスト形式でデータを受信するように設定することもできます。 フロー制御をまったく使用しないため、これは必要ありませんでした。
length
パラメーターは、一度に受信するデータパケットのサイズを設定します。
応答として、
"+CIPRXGET:2,index,received,excess\r\n__DATA__\r\nOK\r\n"
ようなものを取得します。
received
フィールドには
__DATA__
データ
__DATA__
のバイト数が含まれ、
excess
フィールドにはモジュールバッファーで順番を待つバイト数が含まれます。 したがって、
received
フィールドがゼロの場合、
received
するものがないことを正直に宣言できます。 実際、これを使用して、データを受信するためのノンブロッキング関数を実装しました。
結論として
コードを書く前にPuTTYで ATコマンドに慣れることを強くお勧めします。これはシリアルポートでうまく機能します。
この記事の情報が、誰かがSIM900のコードを書くのに役立つことを願っています。 上記のGSMモジュールでの作業の原則は、他のモデルのモジュール、場合によっては製造業者に適用できる可能性があります。