GSM/GPRS模塊 AT指令集C語言編程——基於有方M660+和MSP430單片機

GSM/GPRS芯片是手機中負責收發短信、撥打電話以及訪問GPRS網絡的核心器件。有方M660+爲深圳有方公司生產的一款超小封裝的GSM/GPRS工業無線模塊,可以提供高品質的語音、短信、數據業務等功能,在各種工業和民用領域得到廣泛的應用。

有方M660+ GPRS模塊的硬件設計

硬件設計參考附件《M660+ 硬件設計指南》。

需要注意的幾點:

  1. 模塊工作電壓爲3.5V~4.3V(推薦值3.9V),不是5V。

  2. 模塊平時工作電流較小,但是在模塊註冊網絡或者其他一些特殊情況下,電流可能瞬間達到1.8A,如果電源供電能力不足,電壓瞬間下降嚴重,將可能導致模塊工作異常,沒有信號,無法收發短信等情況。建議採用大電流的開關電源芯片供電,如LM2596 DC-DC轉換模塊;對於移動式設備,採用一塊3.7V鋰離子電池則剛好可以滿足要求;另外應在GPRS模塊供電端附近增加大電容濾波,濾波電容大小見硬件設計指南。

    • 瞬間電流Max 1.8A
    • 平均工作電流 <300mA
    • 待機電流1.5mA typ

  3. 該模塊使用3.3V 電平串口,即高電平爲3.3V,不是5V,對於5V電平的單片機或TTL串口,爲保證工作可靠,不至於燒壞芯片,最好按照硬件設計指南中電路圖搭建電平轉換電路。

單片機系統的硬件設計

通常使用較多的單片機有51、AVR、MSP430、STM32等。需要根據系統功能,考慮選擇合適的單片機。

51單片機使用5V電平,且多數型號RAM、ROM較小,運行速度較慢,適合做一些較簡單的應用,優點是簡便易學,且焊接容易(很容易買到使用DIP(直插式)封裝的51單片機)。

430單片機使用3.3V電平,與GPRS模塊能很好的兼容,且配置相比51更好,最大的特點是低功耗,且性價比較高,適合做不需要處理大量數據(如多媒體信息處理,複雜的人機交互)的多數應用。缺點是大部分430採用貼片封裝,不易於焊接,且使用不當容易燒壞芯片。

STM32單片機基於ARM7內核,功能強大,功耗較低,性價比很高,但對於只接觸過51一類單片機的人來說,不一定能很好的掌握,因爲正是由於功能強大,導致其程序龐大,一些比較簡單的應用不需要使用STM32。STM32適合開發一些需要處理一些圖片、音頻,以及用戶可視化交互的系統。

總體來說,推薦優先選用MSP430;如果應用比較簡單,可使用51;如果需要一些較爲複雜的數據處理,尤其是多媒體信息,可考慮使用STM32、ARM9及以上處理器,或者結合FPFA、DSP來實現。

有方M660+ GPRS模塊的軟件設計

從硬件層面來說,有方GPRS模塊僅僅涉及了串口通信,硬件層的編程比較容易。初次接觸GPRS模塊編程時,比較難的是面向AT指令集協議編程(尤其是字符串處理很麻煩),以及如何編寫高效,而又可靠健壯的程序。

AT指令集是一種可用於GSM/GPRS模塊的通信協議。何謂協議?舉個簡單的例子,我們說話過程中使用的語言,作爲大家共同接受的標準,可以在我們之間傳遞信息,這就叫做協議。而串口則是一種接口,接口又是什麼呢?接口就是收發信息的實現,我們的嘴巴和耳朵就相當於接口。

接口和協議又有什麼關係呢?串口作爲接口,只能一個字節一個字節的傳輸字符,類似的,我們的嘴巴和耳朵原本也只能收發不同的聲音。接口是具體實現,而協議則規定了接口傳輸的信息代表什麼含義。如果沒有接口,協議肯定沒法實現,人沒有嘴巴和耳朵是沒法用聲音交流的。另一方面,如果沒有協議,或者協議不兼容,接口的實現也並不能代表什麼含義。沒有語言的話,兩個人只是亂叫完全沒法交流;如果兩個人使用不同的語言,而且聽不懂彼此的語言(相當於協議不兼容),也是同樣不能交流的。

在GPRS模塊軟件的開發中,接口的實現遠比協議實現要簡單。接口的實現在這裏就不做介紹,這裏主要探討如何編寫高效可靠的程序來實現GPRS模塊的協議即AT指令集。

完整的AT指令集請參考附件《AT命令手冊》,這裏只介紹一些基本用法。

AT指令集的學習

要想編寫程序實現AT指令集的功能,就應該先學習AT指令集。如何學習AT指令集呢?一些人會直接給單片機寫程序去控制GPRS模塊的方式學習。事實上,這樣很難學好AT指令集,往往會出現各種錯誤。當你對AT指令集不瞭解的情況下,盲目的去寫程序,而又並不能保證程序沒有錯誤按設想運行(如果你能保證這一點,那麼你就是編程經驗非常豐富的高手了,反正我是做不到這一點),這樣的情況下,實驗失敗時,你根本沒法確定是程序的問題還是AT指令集的問題,甚至有可能是硬件問題等等。

於是,一般我們將GPRS模塊連接到計算機上來學習AT指令集。對於大多數沒有串口的計算機,你需要有個USB轉TTL串口的轉接線,即使有RS232串口,也需要通過一些轉接芯片進行電平轉換,轉換成TTL串口。注意GPRS模塊TTL串口的電平爲3.3V,儘量使用電平轉換電路以免電平不兼容燒壞GPRS模塊。同時,你需要設計好GPRS模塊的供電電路,給其提供一個穩定可靠的電壓。然後插上一張可用的手機SIM卡,連接好電源和串口,GPRS模塊上電後會和手機開機一樣,需要數分鐘的時間搜索信號,然後就可以正常工作。

電腦端我們使用串口超級終端軟件來調試GPRS模塊。

當我們從超級終端給GPRS模塊發送“AT”,並按回車時,如果一切正常,屏幕上會顯示返回的“OK”字符,這就是AT指令集最基本的操作:確認AT指令集工作正常。

通過AT指令集初始化GPRS模塊一般包括以下步驟(前面加“--”符號的表示正常工作返回的字符串,不同模塊不完全一樣,僅供參考,//表示註釋):

  1. AT // 確認AT指令集工作正常
  2. --OK
  3. ATE0 // 關閉回顯(即禁止GPRS模塊發送接收到每一個的字符,在電腦上調試時不需此語句)
  4. --OK
  5. AT+CPIN // SIM卡準備好?
  6. --READY
  7. AT+CMGF=1 // 設置短消息格式爲Text模式,需在模塊上電一段時間後才能正常返回OK,在此之前會返回ERROR
  8. --OK
  9. AT+CSMP=17,167,0,0 // 設置Text模式參數,用於短信發送
  10. --OK
  11. AT+CSCS="GSM" // 設置GSM字符集,用於短信發送
  12. --OK
  13. AT+CREG? // 網絡註冊完成?應該一直循環發送此句直到網絡註冊完成才能進行短信和電話操作,如果沒有信號,也會返回錯誤信息
  14. --+CREG: 0, 1, "341B", "2DBF"

如果需要使用GPRS網絡,也可以在此處初始化,或者在需要使用時才初始化。

寫程序時發送這些字符串要注意,在每一句結尾處應有一個"\r"結束標誌(回車符,ASCII碼中的13,常縮寫爲)。對於大部分指令,GPRS模塊接收到此結束符纔會執行指令。另外有些引號不可省略,在寫程序時應寫爲轉義字符。

網絡註冊正常後,發送ATD10086,就會給10086打電話,返回OK說明正在嘗試撥打,撥號成功或沒有信號會返回相應字符串。撥號成功,如果連接了話筒和耳機,就能正常通話了。

發送短信有兩種方式,一種是TEXT模式,另一種是PDU模式,需要先設置好。其中TEXT模式只支持英文(不排除可能有些模塊或者某些特別的方法能使其支持中文),PDU模式支持中文,但編碼方式較爲複雜。

PDU可參考:http://yuanyu5237.iteye.com/blog/1126185

注:文中提到一個字符ASCII碼中的26(0x1A),在超級終端中可通過Ctrl+Z輸入

AT指令集協議的編程實現

要編寫一個高效而又可靠的程序,我們既要向GPRS模塊發送數據,又需要接收返回的數據並判斷返回值是否正確。

發送數據可以調用串口發送函數直接發送,而接收數據時,需要接收一段完整的字符串。由於單片機可能正在處理其他任務,並不一定能馬上響應接收的指令。編程時我們可以使用環形隊列作爲串口接收緩衝區,並在接收到"\r"結束符時置位一個接收標誌,然後等待CPU處理。對於一些特殊情形,返回值並不是以"\r"結束,比如發送短信提示輸入短信內容時是以">"結束,此時可以通過延時等待並不斷查詢的方式判斷是否接收到正常的返回值。

還有一種通過超時判斷是否接收完一條指令的方法,效果相對比較好。當接收到第一個字符時,啓動定時器計時,如果一定時間內接收到下一個字符,清零定時器,再次重新計時……當接收到某個字符之後,計時到超過一定時間仍未收到下一個字符,表明接收完一條指令。因爲返回的每條指令都是連續發送出來的,間隔時間固定,所以這種方式能準確判斷指令是否接收完成,缺點是會佔用更多硬件資源(需要多用一個定時器)。

爲了充分實現代碼複用,加快程序開發,可以考慮實現這樣幾個函數:

  1. // 字符串複製(可使用string.h中的標準函數)
  2. void StrCopy(char*, char*);
  3. // 判斷一個字符串是否包含另一個字符串
  4. unsigned char StrContain(char*, char*);
  5. // 發送指令並等待返回指定字符串。注意如果超時仍未返回指定字符串,則應退出函數,以免死機
  6. unsigned char SendAndGet(char*, char*);
  7. // 發送指令並等待返回指定字符串,嘗試n次
  8. unsigned char SendAndGetTimes(char*, char*, unsigned char);
  9. // 初始化AT指令集設備,返回初始化是否成功結果
  10. unsigned char AT_Init(void);
  11. // 發送短信,並返回發送是否成功標誌
  12. unsigned char SendMsg(char*, char*);
  13. // 檢測模塊當前是否有信號
  14. unsigned char CheckSignal(void);

一些更復雜的問題

當先後間隔很短時間發送多條指令,或者是前一條指令需要GPRS模塊使用較長時間去響應時,情況就變得比較複雜了。比如說,我們給出指令發送一條短信,一般可能在10秒左右時間發完,然後返回OK。而在返回OK之前,如果又需要發送另外一條指令,或者很不幸有人打電話來,處理起來就很麻煩了。再比如在間隔很短時間內接收到多條消息,前一條正在處理,後一條消息又被接收到,這個時候怎麼保證不遺漏消息呢?我們可以考慮使用隊列來解決這個問題。

類似這樣的問題很多,尤其對於速度低存儲空間小的單片機來說也不太好解決,而對於一些簡單應用也不一定要考慮這麼多情況,本文不做詳細探討。

附件

串口超級終端 http://download.csdn.net/detail/jzj1993/5744509
有方M660+硬件設計指南 http://download.csdn.net/detail/jzj1993/5507753
AT命令手冊 http://download.csdn.net/detail/jzj1993/5507747

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章