SIM900Dの例でGSMモジュールを使用する

少し前まで、友人がマイクロコントローラーのファームウェアの作成に関連する仕事を提供してくれました。これは、 SIM900D GSMモジュールを使用してサーバーと通信することになっています。 以前、私はプログラミングマイクロコントローラーでビジネスをしておらず、学生時代にCで最後にプログラミングしましたが、好奇心を上回り、仕事に取り掛かりました。 この鉄片に関するドキュメントはインターネット上にありますが、コードでTCP / IPを操作する良い例は見つかりませんでした。 文書化され、タバコとお茶を買いだめし、熊手の間を移動する以外に何も残っていませんでした。 熊手はたくさんありました。 実際、それが私がこの記事を書いた理由です-他の人にとってより簡単にするためです。



多くのATコマンドがあり、コードが多すぎず、文字がたくさんあります。



必要なもの



GSMモジュールを初期化し、サーバーとの接続を確立し、任意のデータを送受信し、接続ステータスを確認し、失敗することなく動作するコードを記述する必要がありました。 また、マイクロコントローラの限られたメモリに収まるように十分にコンパクトであり、主な機能のための余地を残し、もう少し余裕があります。



結果として何が起こったのか



結果は、必要なことを何でも行うことができるCコードです。 コンパクトさの要件のため、回答を解析し、独自のコードを使用して文字列を生成する必要がありました。これは正直な人を表示するのは恥ずべきことです。 したがって、これらの目的のために正規表現を使用することを全員に推奨します。 また、コードを軽量の正規表現エンジンに転送しますが、完全に機能するファームウェアを作成した後です。



このコードには、シリアルポートで機能する関数/マクロ、およびmemset関数とmemcpy関数が必要です。 そのため、多くのライブラリをフックすることなく、比較的簡単に別のプラットフォームに転送できます。



そして、それはどのように見えますか?



プログラミングとテストはWindows 7で実行されました。結果として得られたコードがこの記事の主要な資料になりました。 コードを完全に引用してコメントすることはしませんが、代わりにGSMモジュールのセットアップと操作のアルゴリズムを示します。



コードに必要な機能:



コードが提供する機能は次のとおりです。



シリアルポートを使用する方法



とても簡単です。 ターゲットマイクロコントローラーの下には、 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, &parameters); 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, &parameters); 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+CIPSTART=index,"mode","address","port""



コマンド"AT+CIPSTART=index,"mode","address","port""







UDPプロトコルを使用する場合、デフォルトでは、データグラムは1つのアドレスからのみ送受信されることに注意してください。 UDPを最大限に使用し、任意のアドレスからデータを送受信するには、コマンド"AT+CIPUDPMODE"



で構成された、いわゆるアドバンストUDPモードを使用できます。 詳細については、ドキュメントを参照してください。



コマンドに対する応答で、いくつかの回答を得ることができます。 すべてが順調であれば、標準の"OK"



後、しばらくしてから、次の3つの答えのいずれかを取得できます。



コマンド"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モジュールでの作業の原則は、他のモデルのモジュール、場合によっては製造業者に適用できる可能性があります。



All Articles