對于一個DIYer來說,想用嵌入式實現(xiàn)互聯(lián)網(wǎng)通信(比如WEB網(wǎng)頁瀏覽,智能家居遠程控制等)這樣的功能,最頭痛的不是嵌入式部分的設計,而是服務器端的搭建,首先遇到的就是私有IP訪問的問題,除非你能申請到一個固定IP,讓嵌入式內(nèi)部寫入這個固定IP來進行訪問,不過DIY一般都沒有這樣的條件,服務器端的IP地址是動態(tài)變化的,你只能使用動態(tài)IP+NAT穿透,這樣就必須使用域名來訪問,有一種方法是申請花生殼動態(tài)域名綁定,但是這種綁定一般需要 ADSL+有動態(tài)域名綁定功能的路由器;另外,就算搞定了服務器訪問的問題,接下來你還得使用各種服務器端編程腳本為服務器編程,總之就是麻煩重重,自己搭建服務器很難做到穩(wěn)定的訪問質(zhì)量以及良好的模型設計。
我找到了一種方法能夠一秒解決上面的問題:使用云計算平臺技術!直接把服務器放置到云端,每個嵌入式設備都相當于客戶端連接到云端,用戶也通過WEB瀏覽器或手機APP訪問云端,這樣的技術能夠使通信模型的設計難度大大降低,并且成本很低,很適合DIY設計。我已經(jīng)使用這種技術成功設計了一個GPS跟蹤器,可以使用瀏覽器實時查看設備的具體位置,使用百度地圖顯示出來,接下來就一一描述這一設計流程。
如上圖所示,GPS設備負責實時采集地理坐標,并通過一個GPRS模塊接入互聯(lián)網(wǎng),實時將坐標傳送到服務器,服務器接收到坐標之后在緩存中刷新,用戶在瀏覽器(PC或手機或PAD瀏覽器都可以)中訪問服務器的WEB頁面,在瀏覽器中顯示地圖,完成這一追蹤過程。按照一般的做法,需要一臺實體的服務器,你可以使用你的PC主機當服務器,但這臺主機需要24小時不間斷運行,并且假設你的主機網(wǎng)絡接入是ADSL,你還需要去申請一個域名,以便讓GPRS設備和任意瀏覽器都能訪問到你的服務器,如果你是校內(nèi)網(wǎng),那就基本沒戲了,因為校內(nèi)網(wǎng)是經(jīng)過多層路由的,無法進行外問NAT穿透,也就無法讓外部訪問到你的主機。
我使用云計算平臺技術PK掉了實體服務器,GPRS設備和用戶瀏覽器可以在任意時間任意地點輕松訪問到服務器。什么叫云計算平臺?其實就是一個服務器群,你只需要擁有一個應用帳號,將服務器代碼上傳到你的云空間,不需要知道你的代碼具體運行在什么地方,甚至連提供商都不知道它到底放在哪里,這就是云的概念。目前國外大型的云有谷歌、亞馬遜、微軟等公司,國內(nèi)的有新浪、百度、盛大等,最好用的是谷歌,但...GFW,你懂的,國內(nèi)訪問谷歌很不穩(wěn)定,經(jīng)常會被查封,所以國外產(chǎn)品基本沒有選擇的希望。再看國內(nèi),個人覺得目前做得比較好的是新浪,已經(jīng)推出一整套解決方案,并且已經(jīng)有各種應用在其上面,百度云比較麻煩,現(xiàn)在還不是很成熟,并且在其上面開發(fā)應用需要得到其邀請碼,綜合考慮我使用了新浪云,官網(wǎng)地址:http://sae.sina.com.cn/
新浪云(Sina App Engine簡稱SAE)使用七層沙箱模型,提供了PHP、JAVA、PYTHON等編程語言,但是目前只開放了PHP,JAVA和PYTHON正在測試無法使用,我選擇了PHP;SAE里面提供了大量你所需要的服務,包括SQL數(shù)據(jù)庫,MEMCACHE,Storage大容量存儲等,足夠開發(fā)一般的 WEB應用。
PHP是一種在服務器端執(zhí)行的腳本語言,適用于制作動態(tài)頁面,語言風格類似C語言,瀏覽器申請PHP頁面的時候服務器會將PHP頁面里面的PHP語句執(zhí)行然后生成標準的HTML文檔發(fā)向瀏覽器,在本地編寫PHP需要在PC布置PHP環(huán)境,絕大多數(shù)環(huán)境都使用"LAMP"架構,即:LINUX操作系統(tǒng)+APACHE服務器+MYSQL數(shù)據(jù)庫+PHP腳本,當然也可以在WINDOWS里面開發(fā),可以在WINDOWS里面安裝APACHE服務器,亦可以使用WINDOWS的IIS服務。我選擇使用LAMP環(huán)境,在UBUNTU里面安裝了APACHE,在UBUNTU里面將代碼測試完畢之后使用SVN工具將代碼上傳到云空間,上傳流程在SAE的官網(wǎng)有詳細的教程可供參考:http://sae.sina.com.cn/?m=devcenter&catId=20
在UBUNTU里面使用命令行打開gedit編輯器即可開始編寫你的PHP代碼
在APACHE中設置根目錄為你的PHP代碼所在目錄,將文件類型設置為PHP,瀏覽器訪問本機的時候即可執(zhí)行PHP代碼,我測試寫了一行PHP代碼如下,向屏幕打開“hello world”
在本機瀏覽器中訪問:localhost/test.php即可即得訪頁面:
表示環(huán)境布置成功,接下來可以盡情編寫你的PHP代碼了!
/****************************************************網(wǎng)絡編程方面一系列關鍵技術點*********************************************/
A,如何向服務器上傳GPS坐標
向服務器上傳信息,首先需要確定一種網(wǎng)絡通信協(xié)議,如果是自己搭建實體服務器,則可自由選擇各種協(xié)議,比如面向數(shù)據(jù)報類型的UDP,面向連接的TCP等等,但是在云平臺中,因為云平臺是一種用于WEB的服務,目前僅開放了HTTP協(xié)議,用戶僅可以通過80端口利用HTTP跟服務器通信,所以嵌入式設備必須實現(xiàn)一個HTTP通信協(xié)議并用按照HTTP協(xié)議以及WEB支持的數(shù)據(jù)交換格式AJAX技術進行坐標上傳。
HTTP 協(xié)議基于文本傳輸,客戶端使用“GET”、"POST"等方法進行請求,關于HTTP的更多詳細資料可百度搜索,本文僅針對"GET"進行描述;“GET”主要用于用戶向服務器請求一個頁面,沒錯,所有的HTTP通信都是要由客戶端首先發(fā)起訪問的,服務器端響應用戶需求并返回頁面之后立刻斷開鏈接,客戶端再次請求頁面需要再次連接。那如何使用“GET”上傳數(shù)據(jù)呢?你打開一個普通頁面的時候經(jīng)過可以看到輸入欄里面的網(wǎng)址后面會帶一長串數(shù)據(jù),那些數(shù)據(jù)就是瀏覽器向服務器上傳的參數(shù),比如你在百度搜索的首頁輸入框里面輸入“HTTP”點擊搜索,會發(fā)現(xiàn)網(wǎng)址欄會變成:http://www.baidu.com/s?wd=HTTP&rsv_spt=1&issp=1&rsv_bp=0&ie=utf-8&tn=baiduhome_pg&rsv_sug3=2&rsv_sug=0&rsv_sug4=299&rsv_sug1=1并且頁面跳轉到搜索結果,這串URL中從“?”號后面開始即為一個"GET"的請求參數(shù),根據(jù)不同,需要參數(shù)的頁面請求會事先定義好每個參數(shù)并且接收客戶端的參數(shù)進行解析并返回相應的結果,你可以試試打開一個空白頁面并輸入:http://www.baidu.com/s?wd=HTTP 頁面會跳轉到百度對“HTTP”的搜索結果,這時你就人工完成了一次附帶參數(shù)的“GET”請求。
根據(jù)這種原理,我在服務器中編寫了一個頁面用于測試GET參數(shù)是否成功工作
頁面接收一個名字為test的請求,判斷該參數(shù)是否等于2013,如果是則返回right,否則返回you are wrong,在瀏覽器中輸入localhost/gettest.php?test=2013返回正確。所以使用GET來上傳數(shù)據(jù)是可行的。
B,服務器如何保存GPS坐標
服務器在執(zhí)行完一個PHP頁面之后將銷毀頁面中所有變量,PHP是動態(tài)腳本,在PHP中沒有所謂的“全局變量”,想保存接收到的數(shù)據(jù)必須另想辦法。有一種方法是創(chuàng)建一個數(shù)據(jù)庫,每次將數(shù)據(jù)更新到數(shù)據(jù)庫中,但是要在這種小型應用中使用數(shù)據(jù)庫未免太大材小用了,可以使用memcache來保存,SAE中支持 memcache服務:http://sae.sina.com.cn/?m=devcenter&catId=201 memcache是一個緩存區(qū),可以保存臨時數(shù)據(jù)但不會隨著頁面消失,而且速度高于sql,在SAE中使用memcache必須向在該應用中開通memcache服務,并且在設置中聲明你所需要的變量名字,這些在SAE官網(wǎng)中均有介紹
C,如何顯示地圖
顯示地圖需要另外一種腳本語言:javascript,javascript是一種在瀏覽器端執(zhí)行的腳本編程語言,很多網(wǎng)頁地圖如谷歌、百度、高德等都提供了API代碼供你在網(wǎng)頁里使用,只要在你的網(wǎng)頁中包含了其js源,即可在網(wǎng)頁中正常調(diào)用地圖并顯示。谷歌,shit,又是因為GFW,谷歌很不穩(wěn)定,基本沒戲,使用百度地圖吧,百度開發(fā)者中心官網(wǎng)提供了詳細的教程教你如何簡單地使用百度地圖API http://developer.baidu.com/map/ 里面提供了一份基本的調(diào)用代碼,在你的頁面中包含它就可以正常使用,當然了,前提是你需要有一點基礎。
GPS 設備定時向云平臺遞交坐標信息,云平臺刷新保存到memcache;瀏覽器在打開頁面之后開始繪制地圖,并定時向云平臺的一個PHP頁面申請實時坐標,刷新顯示到瀏覽器中;整個網(wǎng)絡工作框架就大致如此。PK掉了實體服務器!是不是瞬間感覺到讓你的設計接入網(wǎng)絡部分容易多了?沒錯,這就是云時代,它來了,別再想著自己折騰自己的電腦當服務器了,當然了,這些網(wǎng)絡編程語言以及技術基本得懂。
/******************************接下來是嵌入式系統(tǒng)一系列關鍵技術點****************************************/
硬件框架圖
主要由三部分構成,一個MCU,一個GPS模塊,一個GPRS模塊;MCU負責采集GPS坐標并轉換成符合百度所需要的格式,GPRS模塊打開連接并向服務器上傳坐標。MCU采用STM32F103C8T6來做,具有20KB內(nèi)存,128KB FLASH存儲,72MHz主頻,夠我揮霍了。GPS模塊采用TELIT JN3模塊,輸出標準NMEA格式的坐標信息,首次搜星30秒左右,可電池保存數(shù)據(jù)。GPRS模塊采用QUECTEL M50模塊,通過串口與MCU通信,使用AT指令集格式。
硬件部分架構很簡單,就不上傳照片了,下面主要是描述嵌入式編程方面的技術點。
A,UC/OS III嵌入式實時操作系統(tǒng)
要完成這樣一個系統(tǒng)編程,雖說應用不大型,但如果使用裸機編程,會使代碼變得臃腫,不利于移植和新應用的加入,既然MCU資源都這么足了,跑個OS kernel是必須的了。選擇了UC/OS III內(nèi)核,與UC/OS II的區(qū)別是增加了時間片輪詢調(diào)度算法,可以讓多個任務處于同一層優(yōu)先級進行時間片輪轉運行。在UC/OS III進行模塊化設計,在底層為GPS和GPRS模塊設計好一個驅動模型,封裝之后向上層應用提供API函數(shù)調(diào)用。
B,GPRS驅動模型
GPRS 模塊使用AT指令集進行通信,功能包括通話、短信、GPRS接入;如果只是完成一個互聯(lián)網(wǎng)訪問的功能,是很簡單的,但要做到穩(wěn)定卻很有難度,比如網(wǎng)絡通信中突然遇到無信號的時候會中斷傳輸,這時候MCU需要偵測出來并做處理,在超時之后命令模塊斷開并重連,并且這部分超時等待必須不能影響到操作系統(tǒng)中其他應用程序對GPRS驅動的訪問。我使用三個線程來完成一個GPRS的驅動任務,結構如下:
對模塊的操作都是基于AT指令集,經(jīng)過對指令集的功能進行分類之后可分為兩大類,一類屬于操作型指令,只返回“OK”或者"ERROR",這類封裝成一個統(tǒng)一的函數(shù)進行調(diào)用,另一類屬于返回具體數(shù)據(jù),需要對具體的指令進行單獨處理;整個通信模型都是基于這種分類操作的思想進行設計。
數(shù)據(jù)接收線程負責接收模塊的數(shù)據(jù),來自模塊的數(shù)據(jù)又分為兩種類型,一種是普通的命令返回,開頭和結尾都帶有回車+新行符,一種是網(wǎng)絡的二進制數(shù)據(jù)返回,這種直接返回具體的數(shù)據(jù);接收線程必須能識別到這兩種類別,并且根據(jù)當前的工作狀態(tài)將接收到的回應通過UC/OS III提供的郵箱功能分別送往不同的隊列,即完成一次接收過程。
網(wǎng)絡通信線程專門負責處理GPRS事務,包括TCP/UDP連接,發(fā)送,接收等功能,我在系統(tǒng)中將這些功能封裝成類socket接口的形式,以便于與PC編程環(huán)境相似,降低應用層的開發(fā)難度,比如一個連接API:
這個函數(shù)用于打開一條TCP/UDP連接,該函數(shù)接收一個GSM_GPRS_STRUCTURE結構體指針,這個結構定義如下:
結構體包含一個GPRS模塊網(wǎng)絡連接點號,一個GPRS訪問模式標志字節(jié)用于標志該連接是用IP地址還是域名訪問,一個協(xié)議類型標志字節(jié)用于標志該連接是用 TCP還是UDP進行連接,接下來是訪問地址,端口號,連接狀態(tài),最后附帶兩個消息郵箱隊列,一個用于請求事務,一個用于接收網(wǎng)絡數(shù)據(jù)。用于標志狀態(tài)的字節(jié)均使用枚舉類型來表示,這樣可以使整個結構看起來很明確,看其名字就知道其作用,以及其有限個狀態(tài)的類別。
該函數(shù)中最后需要一個很重要的參數(shù): GPRS_ERR_CODE *GPRSErrCode 用于返回函數(shù)的操作結果碼,這個結果很重要,因為應用程序在進行一個連接的時候,模塊此時可能處于無信號狀態(tài),也有可能SIM卡無話費、GPRS服務無開啟、該連接已存在等多種情況導致連接不成功,應用程序需要知道連接的結果才能進行下一步處理,這個返回的結果碼向應用程序提供了連接的結果,讓應用程序可以知道狀態(tài),其定義使用枚舉類型,如下:
}GPRS_ERR_CODE;
如上所示,在整個系統(tǒng)中,絕大多數(shù)函數(shù)都會返回一個操作結果碼用于告知調(diào)用者函數(shù)執(zhí)行的結果,基于這種機制,可以使程序在調(diào)試階段很簡單,及時修改BUG,在正常應用階段保證高度的穩(wěn)定性。
C,HTTP網(wǎng)頁請求
模塊只提供TCP連接功能,這需要我們自己使用TCP來封裝一個HTTP協(xié)議,本應用很簡單,只需要向服務器端索取一個帶參數(shù)的頁面即可,但有一點需要警惕,SAE使用HTTP1.1協(xié)議,并且在后面需要HTTP文本中需要帶一個HOST參數(shù),該參數(shù)后面設置為你需要訪問的應用的域名:
首先打開一條TCP連接,我申請了一個個人應用,域名為:,使用80端口連接:
連接成功之后接下來需要發(fā)送數(shù)據(jù),需要組裝一條標準的HTTP報文,如:GET /updateloc.php?id=2013&lat=0&lng=0 HTTP/1.1\r\nHOST:\r\n\r\n,其中l(wèi)at參數(shù)為緯度值,lng為經(jīng)度值,服務器接收之后解析成功將會返回ok,如果格式失敗將會返回error(ok和error是我自己的PHP頁面中定義的),如果收到OK,表示坐標已成功上傳到服務器,嵌入式端的工作完成了!為了達到實時效果,需要嵌入式設備每隔一定時間遞交坐標。
/*********************************************************************** 最終效果*******************************************************************************/
最后我使用javascript開源庫寫了一個個人主頁,在個人主頁里面設置一個鏈接指向我的地圖頁面,在任意時間任意地點訪問我的主頁都能夠顯示出我的設備的具體位置!
這是我的個人主頁地址:http://
因為是調(diào)用開源Js庫的關系,可能首頁訪問會有點慢,可以直接訪問 http:///index.php 進入地圖頁面,速度很快
首頁效果如下:
點擊“玩玩看”菜單里面的“看看我在哪里”即可跳轉到我的地圖頁面:
地圖中顯示的位置即是我家那邊的位置:
一個GPS定位設備就這樣DIY出來了!你可以在任何地方任何時間使用任何設備訪問到你的頁面!!!!!!!!!
就這樣,一個嵌入式+互聯(lián)網(wǎng)的通信模型就搭建完成了,而且這個服務器成本很低,我現(xiàn)在在新浪進行了實名認證,這樣一個應用每天只需要5個云豆租金(100云豆=1RMB),算下來一個月只需要3毛錢租金,如果你的訪問量不大,個人玩玩的話,這個成本確實很低很低了,但如果訪問量大就另外計算了,具體資費可到 SAE官網(wǎng)查看。