久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 4955|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

微信寵物屋 機(jī)智云系統(tǒng)

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:111475 發(fā)表于 2016-3-30 23:15 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
第一章:通信協(xié)議分析
                                                      ———以微信寵物屋為例

微信寵物屋是機(jī)智云提供的一套完整的基礎(chǔ)例程,在了解相關(guān)通信流程之后,我們可在該程序基礎(chǔ)上開發(fā)自己的程序,實(shí)現(xiàn)與云服務(wù)的對(duì)接,進(jìn)而達(dá)到遠(yuǎn)程控制的目的,接下來我們就來仔細(xì)分析下機(jī)智云的“M2M”機(jī)制到底是如何“跑起來的”。
  第一節(jié):文檔說明部分詳解
第一步:我們打開微信寵物屋程序gokit-mcu-master:看到他的目錄結(jié)構(gòu)如下











其中:MDK_Project即是STM32的程序入口,在分析程序之前我們先來看一下《寵物屋產(chǎn)品設(shè)備端開發(fā)指南》了解一下該程序?qū)崿F(xiàn)的功能和串口協(xié)議的規(guī)定是怎樣的。
首先:我們來看產(chǎn)品信息,該處定義了相關(guān)的數(shù)據(jù)點(diǎn)(如何建立數(shù)據(jù)點(diǎn)請(qǐng)?jiān)L問www.gizwits.com)和寵物屋實(shí)現(xiàn)的功能,包括:調(diào)節(jié)RGB三色燈、電機(jī)轉(zhuǎn)速、紅外探測(cè)等。這些大家了解就行。其中需要大家特別注意的是“設(shè)備識(shí)別碼”這個(gè)關(guān)鍵詞,可以看到微信寵物屋的識(shí)別碼是“6f3074fe43894547a4f1314bd7e3ae0b”,機(jī)智云對(duì)于每一款產(chǎn)品都會(huì)生成唯一的識(shí)別碼以作區(qū)分,待會(huì)我們將在程序中找到定義識(shí)別碼的位置。
其次:我們來看產(chǎn)品信息,可以看到流程圖上清楚的介紹了整個(gè)協(xié)議工作的流程,簡(jiǎn)單分析一下,其實(shí)可以分為兩部分處理:
第一部分、按鍵事件發(fā)生:主要用于MCU處理按鍵事件發(fā)生后與WIFI的通訊處理。
第二部分、串口事件發(fā)生:機(jī)智云是通過WIFI模塊與MCU以串口通信來實(shí)現(xiàn)的,所以下面的這些有關(guān)WIFI的事件都可以歸類為串口事件的發(fā)生,包括:Wifi 發(fā)送控制命令、Wifi 發(fā)送查詢命令、Wifi 發(fā)送心跳命令、Wifi 狀態(tài)更新、外設(shè)狀態(tài)變化。

總體來說,整個(gè)系統(tǒng)上電之后的流程如下:
1)MCU 先上電,初始化完成后,給模塊上電;
2) 模塊初始化;
3) 模塊向MCU 詢問必要信息,MCU 返回信息(見協(xié)議舉例);
4) 進(jìn)入正常工作循環(huán);
a) 模塊給MCU 下發(fā)控制命令(見協(xié)議舉例);
b) MCU 返回確認(rèn),表示收到命令,正在執(zhí)行(見協(xié)議舉例);
c) 執(zhí)行完新控制命令后,無論狀態(tài)是否發(fā)生變化,MCU 都需要通知模塊最新狀態(tài)(見       協(xié)議舉例);
d) 若MCU 檢測(cè)到環(huán)境屬性變化或者用戶在設(shè)備上按鍵引起的狀態(tài)變化,MCU 需要       通知模塊最新狀態(tài),但是其發(fā)送的頻率不能快于2 秒每次(見協(xié)議舉例);
e) 若環(huán)境狀態(tài)一直不變化,MCU 需要每隔10 分鐘定期主動(dòng)上報(bào)當(dāng)前狀態(tài)f) 模塊會(huì)       向MCU 發(fā)送心跳,MCU 收到后按照格式返回即可(見協(xié)議舉例);MCU 連續(xù)180 秒       收不到模塊的數(shù)據(jù),即可認(rèn)為模塊異常,可以給模塊重新上電;
最后:我們來了解具體通訊協(xié)議的約定,可以看到
命令格式:header(2B)=0xFFFF, len(2B), cmd(1B), sn(1B), flags(2B),DATA(XB),checksum(1B)
說明:
1) 包頭(header)固定為0xFFFF;
2) 長(zhǎng)度(len)是指從cmd 開始到整個(gè)數(shù)據(jù)包結(jié)束所占用的字節(jié)數(shù);
3) 命令字(cmd)表示具體的命令含義,詳見協(xié)議舉例;
4) 消息序號(hào)(sn)由發(fā)送方給出,接收方響應(yīng)命令時(shí)需把消息序號(hào)返回給發(fā)送方;
5) 標(biāo)志位(flag),本產(chǎn)品填寫默認(rèn)0;
6) p0 數(shù)據(jù)區(qū)(DATA),詳細(xì)參見p0 數(shù)據(jù)區(qū)約定;
7) 檢驗(yàn)和(checksum)的計(jì)算方式為從len~DATA,按字節(jié)求和;
8) 所有發(fā)送的命令都帶有確認(rèn),如在200 毫秒內(nèi)沒有收到接收方的響應(yīng),發(fā)送方;應(yīng)重       發(fā),最多重發(fā)3 次;
9) 多于一個(gè)字節(jié)的整型數(shù)字以大端字節(jié)序編碼(網(wǎng)絡(luò)字節(jié)序);
10) 數(shù)字均用16 進(jìn)制表示;
相信這一部分大家都能看懂,這里不再敘述,接下來看到“p0 數(shù)據(jù)區(qū)約定”,實(shí)現(xiàn)如下功能:
1)模塊向MUC 發(fā)送控制命令時(shí)攜帶p0 命令和命令標(biāo)志位以及可寫數(shù)據(jù)區(qū)
2)MCU 主動(dòng)發(fā)送狀態(tài)時(shí)或者回復(fù)wifi 模塊的狀態(tài)查詢時(shí)攜帶p0 命令和完整數(shù)據(jù)區(qū)
3)數(shù)據(jù)區(qū)會(huì)自動(dòng)合并布爾和枚舉變量,且有嚴(yán)格的順序,不可任意改變
怎么來理解這三個(gè)功能呢?我們知道在機(jī)智云上定義數(shù)據(jù)點(diǎn)完成后,系統(tǒng)會(huì)自動(dòng)生成對(duì)應(yīng)的“串口通訊協(xié)議”如下圖所示:
我們下載這份通訊協(xié)議文檔打開,可以看到具體有如下命令:
1)WiFi模組請(qǐng)求設(shè)備信息
2)WiFi模組與設(shè)備MCU的心跳
3)設(shè)備MCU通知WiFi模組進(jìn)入配置模式
4) 設(shè)備MCU重置WiFi模組
5)WiFi模組向設(shè)備MCU通知WiFi模組工作狀態(tài)的變化
6) WiFi模組請(qǐng)求重啟MCU
7)非法消息通知
8)WiFi模組讀取設(shè)備的當(dāng)前狀態(tài)
9)設(shè)備MCU向WiFi模組主動(dòng)上報(bào)當(dāng)前狀態(tài)
10)WiFi模組控制設(shè)備
這些命令中我們只要具體關(guān)注8、9、10三條命令即可,我們先來找到第10條命令如下:
4)對(duì)應(yīng)上面“p0 數(shù)據(jù)區(qū)約定”中的功能1來看,模塊向MUC 發(fā)送控制命令時(shí)攜帶p0 命令、命令標(biāo)志位、及可寫數(shù)據(jù)區(qū)三部分命令,至此大家應(yīng)該清楚了,前6位代表p0 命令、attr_flags(1B)代表命令標(biāo)志位、attr_vals(6B)代表可寫數(shù)據(jù)區(qū)。這就告訴了我們編寫mcu代碼時(shí),應(yīng)該怎么樣去識(shí)別WIFI發(fā)來的控制命令。那具體要怎么識(shí)別呢,往下看協(xié)議的注解:
1. 是否設(shè)置標(biāo)志位(attr_flags)表示相關(guān)的數(shù)據(jù)值是否為有效值,相關(guān)的標(biāo)志位為1表示值有效,為0表示值無效,
從右到左的標(biāo)志位依次為:
bit0: 設(shè)置LED_OnOff
bit1: 設(shè)置LED_Color
bit2: 設(shè)置LED_R
bit3: 設(shè)置LED_G
bit4: 設(shè)置LED_B
bit5: 設(shè)置Motor_Speed
這里可以清楚的看到attr_flags占1B字節(jié),其中bit0代表設(shè)置LED_OnOff......bit5: 設(shè)置Motor_Speed,那么對(duì)于我們的mcu接收到WIFI發(fā)來的控制命令后,我們通過識(shí)別attr_flags的每一位即可對(duì)應(yīng)出需要控制的設(shè)備,如果還看不懂,一會(huì)我們分析mcu程序。
看完標(biāo)志位之后我們看attr_vals(6B)  即可寫數(shù)據(jù)區(qū):








5)這里可以清楚的看到,只有相關(guān)的設(shè)置標(biāo)志位(attr_flags)為1時(shí),數(shù)據(jù)值才是有效的,需要特別注意的是“p0 數(shù)據(jù)區(qū)約定”約定第三條,數(shù)據(jù)區(qū)會(huì)自動(dòng)合并布爾和枚舉變量,且有嚴(yán)格的順序,不可任意改變。對(duì)應(yīng)上面的“byte0”合并了“bool”和“enum”類型。
至此p0 數(shù)據(jù)區(qū)約定 到此結(jié)束,后面在MCU程序中會(huì)對(duì)應(yīng)具體代碼講解。
《寵物屋設(shè)備端開發(fā)指南》通訊寫一部分最后一個(gè)包頭排重約定
原則:我們的包頭是兩個(gè)連續(xù)的FF FF,如果此包中還有某字節(jié)出現(xiàn)FF,僅在傳輸和接收的時(shí)候處理,其他環(huán)節(jié)按正常數(shù)據(jù)處理;
舉例:
1) 某設(shè)備上報(bào)狀態(tài)幀:FF FF 00 15 05 03 00 00 04 01 01 02 03 01 00 00 00 32 FF 20 00 03 7D, 除包頭外,出現(xiàn)了FF;
2) 在程序內(nèi)部,作為正常的數(shù)據(jù)去處理;
3) 當(dāng)需要傳輸時(shí),將除包頭外的FF后,增加一個(gè)55字節(jié),其他不變;
4) 將上述數(shù)據(jù)處理成:FF FF 00 15 05 03 00 00 04 01 01 02 03 01 00 00 00 32 FF 55 20 00 03 7D,長(zhǎng)度不變,校驗(yàn)碼不變;
5) 接收方在接收過程中,如果收到字節(jié)是FF,及判斷第二個(gè)字節(jié)是否也是FF,如果是FF,表示一個(gè)新包,按照新包處理;
6) 如果第二個(gè)字節(jié)是55,直接丟棄,不算接收長(zhǎng)度,繼續(xù)接收下一個(gè)字節(jié);
7) 直到按照長(zhǎng)度接收完,或者碰到下一個(gè)連續(xù)的FF FF;
這部分代碼出現(xiàn)在mcu與WIFI 的串口通訊部分,所以我們一會(huì)找到mcu的串口接收程序,簡(jiǎn)而分析,即可清楚什么是包頭排重約定。
《寵物屋設(shè)備端開發(fā)指南》第4部分協(xié)議舉例,下節(jié)配合mcu程序講解。








第二節(jié):MCU程序詳解(STM32)
注意:此節(jié)的分析需要讀者有一定的STM32開發(fā)能力,如果不具備,請(qǐng)先學(xué)習(xí)STM32。
打開MCU程序,在main.c下我們可以看到這樣一段注釋:
意思已經(jīng)很清楚了,大部分的命令代碼機(jī)智云已經(jīng)為我們實(shí)現(xiàn)了,這也是我在講解《微信寵物屋-機(jī)智云接入串口通信協(xié)議文檔》命令時(shí)說只需要關(guān)注8、9、10三條指令的原因了,這三條指令對(duì)應(yīng)在protocol.c下的CmdSendMcuP0和CmdReportModuleStatus這兩個(gè)函數(shù)下,即我們開發(fā)自己的程序時(shí)只需關(guān)注這兩個(gè)函數(shù)即可。
首選來看主函數(shù):


可以看到主函數(shù)下載完成了一堆初始化之后,在循環(huán)值進(jìn)行了三個(gè)函數(shù),第一個(gè)和第三個(gè)是串口事件處理,第二個(gè)是按鍵事件處理(對(duì)應(yīng)之前第一節(jié)講的流程圖)。
我們先來看串口事件處理函數(shù)MessageHandle(),在這之前,我們需要考慮到串口事件發(fā)生的前提是串口已經(jīng)接收到了數(shù)據(jù)幀,因此我們需要找到串口再那里接收這些命令的,我們找到串口接收函數(shù),在STM32里串口接收是以串口中斷出現(xiàn)的,而庫(kù)函數(shù)里所有的中斷都是默認(rèn)在stm32f10x_it.c下的,所以在c文件下我們可找到void USART1_IRQHandler(void),這就是串口1的中斷接收函數(shù)。這段代碼我已經(jīng)做了詳細(xì)注釋,大家可參考上一節(jié)的《寵物屋設(shè)備端開發(fā)指南》下的命令格式和包頭排重約定仔細(xì)對(duì)照查看:
void USART1_IRQHandler(void)
{  
   uint8_t    vlue;
   short         i;

  if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
  {
   USART_ClearITPendingBit(USART1,USART_IT_RXNE);
   vlue = USART_ReceiveData(USART1);
   if(get_one_package ==0) //數(shù)據(jù)包還沒有接收完
      {
         if(cmd_flag1 ==0)   //初始化為0
         {
            if(vlue == 0xff)//接收到第一個(gè)0xff
            {   
               uart_Count = 0;                  
               uart_buf[uart_Count]=vlue;    //uart_buf[0]=0xff
                  uart_Count++;   
                  cmd_flag1 = 1;          //第一個(gè)0xff收到標(biāo)志位
            }         
            return ;  //如果沒收到返回
         }
         if(cmd_flag2 ==0)
         {
            if(cmd_flag2)                     //cmd_flag2=1
            {
                  uart_buf[uart_Count]=vlue;
                  uart_Count++;
                  if(uart_buf[1] == 0xff)      
                  {
                     cmd_flag2 = 1;     //已經(jīng)收到了第二個(gè)0xFF            
                  }   
                  else
                  {
                     cmd_flag1 = 0;    //兩個(gè)0XFF接收完清標(biāo)志位
                  }
            }
            cmd_flag2 = 1;
         }
         uart_buf[uart_Count] = vlue;
         if(uart_Count >=4 && uart_buf[uart_Count] == 0x55 && uart_buf[uart_Count-1] == 0xFF){}  //包頭排重
         else uart_Count++;
         if(uart_Count == 0x04)
         {
            cmd_len = uart_buf[2]*256 +  uart_buf[3];                                             
         }
         if(uart_Count ==  (cmd_len + 4))   //接收的數(shù)據(jù)包是否完整
         {
            get_one_package = 1; //數(shù)據(jù)包接收完成標(biāo)志位
            cmd_flag1 = 0;      
         }                                          
看懂串口接收代碼后,我們回到主函數(shù),鼠標(biāo)右鍵單擊MessageHandle()選擇gotodifinitionMessageHandle找到該處理函數(shù):
可以看到if(get_one_package)這條語(yǔ)句,只有g(shù)et_one_package=1的時(shí)候下面的程序才會(huì)執(zhí)行,而get_one_package=1就是在串口接收函數(shù)里賦值的,表示接收到完整的數(shù)據(jù)幀。繼續(xù)往下看到
















   


這個(gè)switch語(yǔ)句下的各種命令可以對(duì)應(yīng)在《《微信寵物屋-機(jī)智云接入串口通信協(xié)議文檔》》下的命令列表中找到,前面說過這里面大部分命令機(jī)智云已經(jīng)幫我們實(shí)現(xiàn)了,我們只需要關(guān)注兩個(gè)函數(shù)即可,這兩個(gè)函數(shù)就在這個(gè)switch下面:

其實(shí)說的在簡(jiǎn)單一點(diǎn):我們只需要關(guān)注控制命令這一個(gè)函數(shù)即可
不信大家可以進(jìn)入到void       CmdReportModuleStatus(uint8_t *buf) 這個(gè)函數(shù)下看看都做了哪些工作:

從注釋也可以看出這個(gè)函數(shù)只是描述WIFI狀態(tài)變化的函數(shù),比如我們連接的是AirLink模式還是softap模式,如果你想?yún)^(qū)分,就在這段代碼下添加狀態(tài)指示程序即可,我們不做過多講解,重點(diǎn)用來解釋控制命令函數(shù)void       CmdSendMcuP0(uint8_t *buf)
大家拿到開發(fā)板之后,應(yīng)該都知道第一步需要按下按鍵去配置WIFI連接到云端,才能實(shí)現(xiàn)遠(yuǎn)程控制,所以在講解控制命令函數(shù)void       CmdSendMcuP0(uint8_t *buf)之前,我們先來看看通過按鍵配置開發(fā)板的這些程序在哪里,既然是按鍵配置,那肯定是在按鍵處理函數(shù)里找嘍,我們回到主函數(shù)下,找到按鍵處理函數(shù)       KeyHandle();         鼠標(biāo)右鍵單擊 選擇 goto        difinition KeyHandle,可以看到




















這里代碼已經(jīng)很清楚了,就不做過多解釋,這里需要大家思考的地方是,按鍵的長(zhǎng)按和短按是怎么實(shí)現(xiàn)的呢?這里告訴大家,本mcu程序定義了定時(shí)器3中斷,去判斷按鍵的長(zhǎng)按與短按,超過2秒即認(rèn)為是長(zhǎng)按,既然是定時(shí)器中斷函數(shù),那肯定是在stm32f10x_it.c下面嘍,我們找到它,看看它的函數(shù)原型void TIM3_IRQHandler(void) :(這部分代碼我在原來的基礎(chǔ)上做了更多的注解,相信大家都能看懂的)


了解的開發(fā)板配置的代碼后,我們?cè)诨仡^看控制命令函數(shù)void       CmdSendMcuP0(uint8_t *buf),這是最重點(diǎn)的部分啦,我們復(fù)制其中的重點(diǎn)代碼做詳細(xì)講解。






這部分代碼大體的工作流程是:如果串口0傳來了數(shù)據(jù)(buf != NULL),先調(diào)用memcpy函數(shù)將其拷貝到m_w2m_controlMcu 結(jié)構(gòu)體中去,其中結(jié)構(gòu)體成員m_w2m_controlMcu.sub_cmd 是命令標(biāo)志位,如果為SUB_CMD_REQUIRE_STATUS(0x02)則表示查詢命令,當(dāng)即上報(bào)當(dāng)前的狀態(tài)到服務(wù)器,如果為SUB_CMD_CONTROL_MC(0x01)則表示控制命令,控制部分就是我們需要重點(diǎn)實(shí)現(xiàn)的了。既然是控制部分,那肯定要和我們之前講的《微信寵物屋-機(jī)智云接入串口通信協(xié)議文檔.pdf》中的4.10節(jié)《WIFI模塊控制設(shè)備》相聯(lián)系起來了,

我們之前講過這部分 最重要的就是attr_flags(1B) 、attr_vals(6B)這兩位;忘記的同學(xué)請(qǐng)返回前面看一看。這兩位是怎么對(duì)應(yīng)程序的呢?我們來看





      


我們鼠標(biāo)右鍵 GOTO 到  m_w2m_controlMcu.cmd_tag 里面,可以看到該結(jié)構(gòu)體內(nèi)容如下:


現(xiàn)在是不是已經(jīng)和《微信寵物屋-機(jī)智云接入串口通信協(xié)議文檔.pdf》中的4.10節(jié)《WIFI模塊控制設(shè)備》對(duì)應(yīng)起來了,哈哈,我們接著往下看程序

前面我們已經(jīng)知道程序里的cmd_tag就對(duì)應(yīng)《微信寵物屋-機(jī)智云接入串口通信協(xié)議文檔.pdf》中的4.10節(jié)《WIFI模塊控制設(shè)備》中的attr_flags(1B),是用來選擇控制哪一位的,在文檔中我們可以看到attr_flags的第0位是用來選擇控制LED燈開關(guān)的,即只要設(shè)置了第0位為1就表示要控制LED等開關(guān)了,如下所示:

對(duì)應(yīng)程序中
if((m_w2m_controlMcu.cmd_tag & 0x01) == 0x01)
即標(biāo)志第0位為1,接下來就可以控制LED燈的開關(guān)了,我們接著程序往下看;


這段程序就控制了LED燈的開關(guān),即cmd_byte的第0位為1表示燈開,為0表示燈關(guān)。
這對(duì)應(yīng)《微信寵物屋-機(jī)智云接入串口通信協(xié)議文檔.pdf》中的4.10節(jié)《WIFI模塊控制設(shè)備》中的attr_vals(6B),即設(shè)置數(shù)據(jù)位,如下所示:
可以清楚的看到只要控制byte0(0x07)的第0位就可以控制LED燈了,第一位是用來控制LED顏色的。
這里需要說明的是一般設(shè)置數(shù)據(jù)位的數(shù)據(jù)包的byte0 是用來控制bool型變量和枚舉類型變量的了,應(yīng)為機(jī)智云默認(rèn)是把bool變量和枚舉類型合并處理的。

下面的程序基本和上面一樣了,只要大家看懂了《微信寵物屋-機(jī)智云接入串口通信協(xié)議文檔.pdf》中的4.10節(jié)《WIFI模塊控制設(shè)備》中的attr_flags(1B) 、attr_vals(6B)這兩位和程序代碼中的cmd_tag、status_w的對(duì)應(yīng)關(guān)系就能自己編寫控制程序了。

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 亚洲入口 | 国产精品视频免费观看 | 久久男人| 欧美日韩激情 | 久久精品99 | 国产综合网站 | 久久久av | 日韩国产欧美在线观看 | 日韩精品久久一区二区三区 | 日韩欧美中文字幕在线观看 | 欧洲一区二区在线 | 亚洲精品久久久久久久久久久久久 | 一区二区高清在线观看 | 国产亚洲精品久久久久久豆腐 | 成人不卡在线 | 我要看黄色录像一级片 | 国产欧美精品一区二区三区 | 瑟瑟激情 | 午夜视频免费在线观看 | 羞羞视频网站免费看 | 亚洲精品一区二区三区蜜桃久 | 免费在线观看av网站 | 男女在线免费观看 | 亚洲精品国产一区 | 日韩中文电影 | 免费国产一区二区 | 中文字幕乱码一区二区三区 | 成人午夜视频在线观看 | 国产精品乱码一区二三区小蝌蚪 | 久久久毛片 | 久热爱 | 天天狠狠| 欧美一级片在线看 | 成人亚洲视频 | 国产成人免费在线 | 久久中文高清 | 久久人体 | 91美女在线观看 | 欧美 日韩 国产 成人 在线 | 欧美一级免费片 | 成人久久18免费网站 |