基于STM32+華為云IOT設計的智能防盜單車鎖【玩轉華為云】

      網友投稿 789 2025-04-04

      一、前言


      近年來隨著國民經濟的發展,交通擁堵和環境污染問題越來越突出,而自行車對改善交通與環境起到了重要作用。中國本身是一個自行車使用大國,隨著自行車的發展,自行車的科技含量越來越高,然而自行車安防問題突出。目前市場上自行車鎖大多是傳統機械結構車鎖,沒有實現智能化,急需解決。本文提出一種基于STM32單片機的智能自行車鎖(馬蹄鎖)的設計方法,來提高自行車鎖的智能化及安防等級。

      硬件選項說明:單片機采用STM32F103RCT6,GSM模塊采用SIM800C,完成網絡連接、數據上傳,GPS經緯度解析,短信發送,物聯網平臺采用華為云IOT,作為數據存儲端,藍牙模塊采用正點原子低功耗BLE藍牙,支持藍牙開鎖解鎖,車輛的狀態使用ADXL345三軸加速度傳感器檢測,密碼鍵盤采用電容矩陣鍵盤。

      二、設計思路總結

      需要設計一款Android手機APP,可以遠程開鎖解鎖,手機APP對接華為云物聯網平臺,實現遠程與自行車鎖完成數據交互,命令下發。智能鎖與華為云IOT服務器之間的通信協議采用MQTT協議,手機APP與華為云IOT服務器之間采用HTTP協議。智能鎖除了支持遠程開鎖關鎖之外,還支持藍牙解鎖和輸入密碼開始,設計的APP支持藍牙功能,可以連接智能鎖上的藍牙完成開鎖和關鎖,如果沒有帶手機,可以輸入密碼完成開鎖。

      車輛的狀態檢測通過ADXL345三軸加速度計檢測,如果車輛處于鎖定狀態,發現車輛被移動了會觸發報警,鎖里的蜂鳴器會持續響,并且SIM800C會向指定的手機號碼發送短信,提示車輛可能被盜,同時上傳GPS經緯度到云端服務器,手機APP上可以獲取智能鎖上傳的GPS經緯度,調用百度地圖顯示車輛的位置,方便尋車。

      三、硬件選型

      (1) 加速度計傳感器

      ADXL345是一款小尺寸、薄型、低功耗、完整的三軸加速度計,提供經過信號調理的電壓輸出。

      說明:CS接高電平則選擇IIC通信,反之則SPI通信。SDO(地址引腳)接高電平,根據手冊器件的7位I2C地址是0x1D,后面跟上讀取/寫位(R/W),則寫寄存器為0x3A,讀寄存器為0x3B;接低電平,則7位I2C地址是0x53,同理,跟上讀寫標志位后寫寄存器為0xA6,讀寄存器為0xA7;

      (2) STM32開發板

      STM32F103RCT6的芯體規格是32位,速度是72MHz,程序存儲器容量是256KB,程序存儲器類型是FLASH,RAM容量是48K。

      (3) BLE低功耗藍牙模塊

      (4) SIM800C

      基于STM32+華為云IOT設計的智能防盜單車鎖【玩轉華為云】

      模塊特點:

      1、支持極限DC5V-18V寬電壓輸入

      2、有電源使能開關引腳EN

      3、支持鋰電池供電接口VBAT3.5-4.5V

      4、輸入支持移動和聯通手機卡Micro SIM卡

      5、送51/STM32/ARDUINO驅動例程

      1、DC 5V-18V電源輸入,推薦使用DC 9V

      2、電源開始使能引腳默認使能

      3、電源地

      4、GSM模塊的TXD引腳接其它模塊的RXD

      5、GSM模塊的RXD引腳接其它模塊的TXD

      6、數據終端準備

      7、內核音頻輸出引腳

      8、內核音頻輸出引腳

      9、鋰電池輸入引腳,DC 3.5 - 4.5V

      10、電源地

      11、啟動引腳和GND短路可實現開機自啟動

      12、電源地

      13、RTC外置電池引腳

      14、內核振鈴提示引腳

      15、內合音頻輸入引腳

      16、內核音頻輸入引腳

      加粗的引腳一般都用到。

      建議使用V_IN單獨供電DC5-18V輸入(推薦使用9V),或者VBAT供電鋰電池兩種供電方式這兩種供電方式最穩定。如果只是簡單調試,也可使用USB-TTL或者開發板的5V直接給模塊供電。不過一般電腦或者開發板的功率有限,可能會不穩定。請根據具體情況自己取舍選擇合適電源。

      3. 手機APP軟件設計

      3.1 通信說明

      上位機與設備之間支持通過BLE低功耗串口藍牙進行通信,支持通過網絡連接華為云服務器進行通信,手機APP下發open_lock和close_lock實現關鎖開鎖。

      3.2 搭建開發環境

      上位機軟件采用Qt框架設計,Qt是一個跨平臺的C++圖形用戶界面應用程序框架。Qt是一個1991年由Qt Company開發的跨平臺C++圖形用戶界面應用程序開發框架。它既可以開發GUI程序,也可用于開發非GUI程序,比如控制臺工具和服務器。簡單來說,QT可以很輕松的幫你做帶界面的軟件,甚至不需要你投入很大精力。

      QT官網: https://www.qt.io/

      QT學習入門實戰專欄文章: https://blog.csdn.net/xiaolong1126626497/category_11400392.html

      QT5.12.6的-:

      https://download.qt.io/archive/qt/5.12/5.12.6/

      4. 創建云端設備

      4.1 創建產品

      登錄官網: https://www.huaweicloud.com/product/iothub.html

      直接搜索物聯網,打開頁面。

      4.2 自定義模型

      4.3 注冊設備

      設備創建成功:

      { "device_id": "6274b1d62d5e854503d3a67e_lock", "secret": "12345678" }

      4.4 MQTT設備密匙

      創建完產品、設備之后,接下來就需要知道如何通過MQTT協議登陸華為云服務器。

      官方的詳細介紹在這里:

      https://support.huaweicloud.com/devg-iothub/iot_01_2127.html#ZH-CN_TOPIC_0240834853__zh-cn_topic_0251997880_li365284516112

      屬性上報格式:

      https://support.huaweicloud.com/api-iothub/iot_06_v5_3010.html

      MQTT設備登陸密匙生成地址:

      DeviceId 6274b1d62d5e854503d3a67e_lock DeviceSecret 12345678 ClientId 6274b1d62d5e854503d3a67e_lock_0_0_2022050605 Username 6274b1d62d5e854503d3a67e_lock Password 334dd7c0c10e47280880e9dd004ae0d8c5abc24dbbc9daa735315722707fe13b

      4.5 使用MQTT客戶端軟件登錄

      所有的參數已經得到,接下來采用MQTT客戶端登錄華為云進行測試。

      華為云物聯網平臺的域名是: 161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com

      華為云物聯網平臺的IP地址是:121.36.42.100

      在軟件里參數填充正確之后,就看到設備已經連接成功了。

      接下來打開設備頁面,可以看到設備已經在線了。

      4.6 數據上報測試

      //訂閱主題: 平臺下發消息給設備 $oc/devices/6274b1d62d5e854503d3a67e_lock/sys/messages/down //設備上報數據 $oc/devices/6274b1d62d5e854503d3a67e_lock/sys/properties/report //上報的屬性消息 (一次可以上報多個屬性,在json里增加就行了) {"services": [{"service_id": "lock","properties":{"lock":1}}]}

      //訂閱主題: 平臺下發消息給設備 $oc/devices/6274b1d62d5e854503d3a67e_lock/sys/messages/down //設備上報數據 $oc/devices/6274b1d62d5e854503d3a67e_lock/sys/properties/report //上報的屬性消息 (一次可以上報多個屬性,在json里增加就行了) {"services": [{"service_id": "lock","properties":{"GPS信息":"lat:12.345,lng:45.678"}}]}

      4.7 應用側開發

      為了更方便的展示設備數據,與設備完成交互,還需要開發一個配套的上位機,官方提供了應用側開發的API接口、SDK接口,為了方便通用一點,我這里采用了API接口完成數據交互,上位機軟件采用QT開發。

      幫助文檔地址: ttps://support.huaweicloud.com/api-iothub/iot_06_v5_0034.html

      設備屬性就是設備上傳的傳感器狀態數據信息,應用側提供了API接口,可以主動向設備端下發請求指令;設備端收到指令之后需要按照約定的數據格式上報數據;所以,要實現應用層與設備端的數據交互,需要應用層與設備端配合才能完成。

      5. STM32開發

      5.1 ADXL345.c

      #include "app.h" /* 函數功能: 各種硬初始化 繼電器模塊--DAT--->PA4 PB12-----輸入引腳,檢測模塊是否連接或者斷開 */ void Hardware_Init(void) { RCC->APB2ENR|=1<<2; GPIOA->CRL&=0xFFF0FFFF; GPIOA->CRL|=0x00030000; RCC->APB2ENR|=1<<3; GPIOB->CRH&=0xFFF0FFFF; GPIOB->CRH|=0x00080000; } ////////////////////////////////////////////////////////////////////////////////// //初始化ADXL345. //返回值:0,初始化成功;1,初始化失敗. u8 ADXL345_Init(void) { IIC_Init(); //初始化IIC總線 if(ADXL345_RD_Reg(DEVICE_ID)==0XE5) //讀取器件ID { ADXL345_WR_Reg(DATA_FORMAT,0X2B); //低電平中斷輸出,13位全分辨率,輸出數據右對齊,16g量程 ADXL345_WR_Reg(BW_RATE,0x0A); //數據輸出速度為100Hz ADXL345_WR_Reg(POWER_CTL,0x28); //鏈接使能,測量模式 ADXL345_WR_Reg(INT_ENABLE,0x00); //不使用中斷 ADXL345_WR_Reg(OFSX,0x00); ADXL345_WR_Reg(OFSY,0x00); ADXL345_WR_Reg(OFSZ,0x00); return 0; } return 1; } //寫ADXL345寄存器 //addr:寄存器地址 //val:要寫入的值 //返回值:無 void ADXL345_WR_Reg(u8 addr,u8 val) { IIC_Start(); IIC_Send_Byte(ADXL_WRITE); //發送寫器件指令 IIC_Wait_Ack(); IIC_Send_Byte(addr); //發送寄存器地址 IIC_Wait_Ack(); IIC_Send_Byte(val); //發送值 IIC_Wait_Ack(); IIC_Stop(); //產生一個停止條件 } //讀ADXL345寄存器 //addr:寄存器地址 //返回值:讀到的值 u8 ADXL345_RD_Reg(u8 addr) { u8 temp=0; IIC_Start(); IIC_Send_Byte(ADXL_WRITE); //發送寫器件指令 temp=IIC_Wait_Ack(); IIC_Send_Byte(addr); //發送寄存器地址 temp=IIC_Wait_Ack(); IIC_Start(); //重新啟動 IIC_Send_Byte(ADXL_READ); //發送讀器件指令 temp=IIC_Wait_Ack(); temp=IIC_Read_Byte(0); //讀取一個字節,不繼續再讀,發送NAK IIC_Stop(); //產生一個停止條件 return temp; //返回讀到的值 } //讀取ADXL的平均值 //x,y,z:讀取10次后取平均值 void ADXL345_RD_Avval(short *x,short *y,short *z) { short tx=0,ty=0,tz=0; u8 i; for(i=0;i<10;i++) { ADXL345_RD_XYZ(x,y,z); delay_ms(10); tx+=(short)*x; ty+=(short)*y; tz+=(short)*z; } *x=tx/10; *y=ty/10; *z=tz/10; } //自動校準 //xval,yval,zval:x,y,z軸的校準值 void ADXL345_AUTO_Adjust(char *xval,char *yval,char *zval) { short tx,ty,tz; u8 i; short offx=0,offy=0,offz=0; ADXL345_WR_Reg(POWER_CTL,0x00); //先進入休眠模式. delay_ms(100); ADXL345_WR_Reg(DATA_FORMAT,0X2B); //低電平中斷輸出,13位全分辨率,輸出數據右對齊,16g量程 ADXL345_WR_Reg(BW_RATE,0x0A); //數據輸出速度為100Hz ADXL345_WR_Reg(POWER_CTL,0x28); //鏈接使能,測量模式 ADXL345_WR_Reg(INT_ENABLE,0x00); //不使用中斷 ADXL345_WR_Reg(OFSX,0x00); ADXL345_WR_Reg(OFSY,0x00); ADXL345_WR_Reg(OFSZ,0x00); delay_ms(12); for(i=0;i<10;i++) { ADXL345_RD_Avval(&tx,&ty,&tz); offx+=tx; offy+=ty; offz+=tz; } offx/=10; offy/=10; offz/=10; *xval=-offx/4; *yval=-offy/4; *zval=-(offz-256)/4; ADXL345_WR_Reg(OFSX,*xval); ADXL345_WR_Reg(OFSY,*yval); ADXL345_WR_Reg(OFSZ,*zval); } //讀取3個軸的數據 //x,y,z:讀取到的數據 void ADXL345_RD_XYZ(short *x,short *y,short *z) { u8 buf[6]; u8 i; IIC_Start(); IIC_Send_Byte(ADXL_WRITE); //發送寫器件指令 IIC_Wait_Ack(); IIC_Send_Byte(0x32); //發送寄存器地址(數據緩存的起始地址為0X32) IIC_Wait_Ack(); IIC_Start(); //重新啟動 IIC_Send_Byte(ADXL_READ); //發送讀器件指令 IIC_Wait_Ack(); for(i=0;i<6;i++) { if(i==5)buf[i]=IIC_Read_Byte(0);//讀取一個字節,不繼續再讀,發送NACK else buf[i]=IIC_Read_Byte(1); //讀取一個字節,繼續讀,發送ACK } IIC_Stop(); //產生一個停止條件 *x=(short)(((u16)buf[1]<<8)+buf[0]); *y=(short)(((u16)buf[3]<<8)+buf[2]); *z=(short)(((u16)buf[5]<<8)+buf[4]); } //讀取ADXL345的數據times次,再取平均 //x,y,z:讀到的數據 //times:讀取多少次 void ADXL345_Read_Average(short *x,short *y,short *z,u8 times) { u8 i; short tx,ty,tz; *x=0; *y=0; *z=0; if(times)//讀取次數不為0 { for(i=0;iAPB2ENR|=1<<3; //先使能外設IO PORTB時鐘 GPIOB->CRL&=0X00FFFFFF; //6/7 推挽輸出 GPIOB->CRL|=0X33000000; GPIOB->ODR|=3<<6; //6,7 輸出高 } //產生IIC起始信號 void IIC_Start(void) { SDA_OUT(); //sda線輸出 IIC_SDA=1; IIC_SCL=1; delay_us(4); IIC_SDA=0;//START:when CLK is high,DATA change form high to low delay_us(4); IIC_SCL=0;//鉗住I2C總線,準備發送或接收數據 } //產生IIC停止信號 void IIC_Stop(void) { SDA_OUT();//sda線輸出 IIC_SCL=0; IIC_SDA=0;//STOP:when CLK is high DATA change form low to high delay_us(4); IIC_SCL=1; IIC_SDA=1;//發送I2C總線結束信號 delay_us(4); } //等待應答信號到來 //返回值:1,接收應答失敗 // 0,接收應答成功 u8 IIC_Wait_Ack(void) { u8 ucErrTime=0; SDA_IN(); //SDA設置為輸入 IIC_SDA=1;delay_us(1); IIC_SCL=1;delay_us(1); while(READ_SDA) { ucErrTime++; if(ucErrTime>250) { IIC_Stop(); return 1; } } IIC_SCL=0;//時鐘輸出0 return 0; } //產生ACK應答 void IIC_Ack(void) { IIC_SCL=0; SDA_OUT(); IIC_SDA=0; delay_us(2); IIC_SCL=1; delay_us(2); IIC_SCL=0; } //不產生ACK應答 void IIC_NAck(void) { IIC_SCL=0; SDA_OUT(); IIC_SDA=1; delay_us(2); IIC_SCL=1; delay_us(2); IIC_SCL=0; } //IIC發送一個字節 //返回從機有無應答 //1,有應答 //0,無應答 void IIC_Send_Byte(u8 txd) { u8 t; SDA_OUT(); IIC_SCL=0;//拉低時鐘開始數據傳輸 for(t=0;t<8;t++) { IIC_SDA=(txd&0x80)>>7; txd<<=1; delay_us(2); //對TEA5767這三個延時都是必須的 IIC_SCL=1; delay_us(2); IIC_SCL=0; delay_us(2); } } //讀1個字節,ack=1時,發送ACK,ack=0,發送nACK u8 IIC_Read_Byte(unsigned char ack) { unsigned char i,receive=0; SDA_IN();//SDA設置為輸入 for(i=0;i<8;i++ ) { IIC_SCL=0; delay_us(2); IIC_SCL=1; receive<<=1; if(READ_SDA)receive++; delay_us(1); } if (!ack) IIC_NAck();//發送nACK else IIC_Ack(); //發送ACK return receive; }

      5.2 sim800.c

      #include "sim800c.h" /* 函數功能:向SIM800C模塊發送指令 函數參數: char *cmd 發送的命令 char *check_data 檢測返回的數據 返回值: 0表示成功 1表示失敗 */ u8 SIM800C_SendCmd(char *cmd,char *check_data) { u16 i,j; for(i=0;i<5;i++) //測試的總次數 { USART2_RX_FLAG=0; USART2_RX_CNT=0; memset(USART2_RX_BUFFER,0,sizeof(USART2_RX_BUFFER)); USARTx_StringSend(USART2,cmd); //發送指令 for(j=0;j<500;j++) //等待的時間(ms單位) { if(USART2_RX_FLAG) { USART2_RX_BUFFER[USART2_RX_CNT]='\0'; if(strstr((char*)USART2_RX_BUFFER,check_data)) { return 0; } else break; } delay_ms(20); //一次的時間 } } return 1; } /* 函數 功能:GSM模塊初始化檢測 函數返回值:1表示模塊檢測失敗,0表示成功 */ u8 SIM800C_InitCheck(void) { if(SIM800C_SendCmd("AT\r\n","OK"))return 1; else printf("SIM800模塊正常!\r\n"); if(SIM800C_SendCmd("ATE0\r\n","OK"))return 2; else printf("設置模塊不回顯成功!\r\n"); if(SIM800C_SendCmd("AT+CGMI\r\n","OK"))return 3; else printf("查詢制造商名稱成功!%s\r\n",USART2_RX_BUFFER); if(SIM800C_SendCmd("AT+CGMM\r\n","OK"))return 4; else printf("查詢模塊型號成功!%s\r\n",USART2_RX_BUFFER); DelayMs(1000); DelayMs(1000); if(SIM800C_SendCmd("AT+CNUM\r\n","+CNUM:"))return 5; else printf("獲取本機號碼成功!%s\r\n",USART2_RX_BUFFER); /* 返回格式如下: +CNUM: "","+8613086989413",145,7,4 OK */ return 0; } /* 函數 功能:GSM模塊短信模式設置 函數返回值:0表示模塊設置成功 */ u8 SIM800C_SetNoteTextMode(void) { if(SIM800C_SendCmd("AT+CSCS=\"GSM\"\r\n","OK"))return 1;// "GSM"字符集 else printf("短信GSM字符集設置成功!\r\n"); if(SIM800C_SendCmd("AT+CMGF=1\r\n","OK"))return 2; //文本模式 else printf("短信文本模式設置成功!\r\n"); return 0; } /* 函數功能:發送短信 函數參數: num:電話號碼 text:短信內容 函數返回值:0表示發送成功 */ u8 SIM800C_SendNote(u8 *num,u8 *text,u16 len) { char data[50]; char send_buf[2]; sprintf(data,"AT+CMGS=\"%s\"\r\n",num); if(SIM800C_SendCmd(data,">"))return 1; //設置發送的手機號 USARTx_DataSend(USART2,text,len); //發送短信內容 send_buf[0] = 0x1a; send_buf[1] = '\0'; if(SIM800C_SendCmd(send_buf,"+CMGS"))return 2; //發送結束符號 return 0; }

      5.3 MQTT信息

      //華為物聯網服務器的設備信息 #define MQTT_ClientID "62381267575fb713ee164ad2_xl_1_0_0_2022032106" #define MQTT_UserName "62381267575fb713ee164ad2_xl_1" #define MQTT_PassWord "124344feff3e3d96ff6af13cf36af36766619ff1eeee40e99cbae9b7b9739fe4" //訂閱與發布的主題 #define SET_TOPIC "$oc/devices/62381267575fb713ee164ad2_xl_1/sys/messages/down" //訂閱 #define POST_TOPIC "$oc/devices/62381267575fb713ee164ad2_xl_1/sys/properties/report" //發布 //設置連接的路由器信息 #define CONNECT_WIFI "abc" //將要連接的路由器名稱 --不要出現中文、空格等特殊字符 #define CONNECT_PASS "1234567890" //將要連接的路由器密碼 #define CONNECT_SERVER_IP "a161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com" //服務器IP地址 #define CONNECT_SERVER_PORT 1883 //服務器端口號 u8 *mqtt_rxbuf; u8 *mqtt_txbuf; u16 mqtt_rxlen; u16 mqtt_txlen; u8 _mqtt_txbuf[256];//發送數據緩存區 u8 _mqtt_rxbuf[256];//接收數據緩存區 typedef enum { //名字 值 報文流動方向 描述 M_RESERVED1 =0 , // 禁止 保留 M_CONNECT , // 客戶端到服務端 客戶端請求連接服務端 M_CONNACK , // 服務端到客戶端 連接報文確認 M_PUBLISH , // 兩個方向都允許 發布消息 M_PUBACK , // 兩個方向都允許 QoS 1消息發布收到確認 M_PUBREC , // 兩個方向都允許 發布收到(保證交付第一步) M_PUBREL , // 兩個方向都允許 發布釋放(保證交付第二步) M_PUBCOMP , // 兩個方向都允許 QoS 2消息發布完成(保證交互第三步) M_SUBSCRIBE , // 客戶端到服務端 客戶端訂閱請求 M_SUBACK , // 服務端到客戶端 訂閱請求報文確認 M_UNSUBSCRIBE , // 客戶端到服務端 客戶端取消訂閱請求 M_UNSUBACK , // 服務端到客戶端 取消訂閱報文確認 M_PINGREQ , // 客戶端到服務端 心跳請求 M_PINGRESP , // 服務端到客戶端 心跳響應 M_DISCONNECT , // 客戶端到服務端 客戶端斷開連接 M_RESERVED2 , // 禁止 保留 }_typdef_mqtt_message; //連接成功服務器回應 20 02 00 00 //客戶端主動斷開連接 e0 00 const u8 parket_connetAck[] = {0x20,0x02,0x00,0x00}; const u8 parket_disconnet[] = {0xe0,0x00}; const u8 parket_heart[] = {0xc0,0x00}; const u8 parket_heart_reply[] = {0xc0,0x00}; const u8 parket_subAck[] = {0x90,0x03}; void MQTT_Init(void) { //緩沖區賦值 mqtt_rxbuf = _mqtt_rxbuf; mqtt_rxlen = sizeof(_mqtt_rxbuf); mqtt_txbuf = _mqtt_txbuf; mqtt_txlen = sizeof(_mqtt_txbuf); memset(mqtt_rxbuf,0,mqtt_rxlen); memset(mqtt_txbuf,0,mqtt_txlen); //無條件先主動斷開 MQTT_Disconnect(); delay_ms(100); MQTT_Disconnect(); delay_ms(100); } /* 函數功能: 登錄服務器 函數返回值: 0表示成功 1表示失敗 */ u8 MQTT_Connect(char *ClientID,char *Username,char *Password) { u8 i,j; int ClientIDLen = strlen(ClientID); int UsernameLen = strlen(Username); int PasswordLen = strlen(Password); int DataLen; mqtt_txlen=0; //可變報頭+Payload 每個字段包含兩個字節的長度標識 DataLen = 10 + (ClientIDLen+2) + (UsernameLen+2) + (PasswordLen+2); //固定報頭 //控制報文類型 mqtt_txbuf[mqtt_txlen++] = 0x10; //MQTT Message Type CONNECT //剩余長度(不包括固定頭部) do { u8 encodedByte = DataLen % 128; DataLen = DataLen / 128; // if there are more data to encode, set the top bit of this byte if ( DataLen > 0 ) encodedByte = encodedByte | 128; mqtt_txbuf[mqtt_txlen++] = encodedByte; }while ( DataLen > 0 ); //可變報頭 //協議名 mqtt_txbuf[mqtt_txlen++] = 0; // Protocol Name Length MSB mqtt_txbuf[mqtt_txlen++] = 4; // Protocol Name Length LSB mqtt_txbuf[mqtt_txlen++] = 'M'; // ASCII Code for M mqtt_txbuf[mqtt_txlen++] = 'Q'; // ASCII Code for Q mqtt_txbuf[mqtt_txlen++] = 'T'; // ASCII Code for T mqtt_txbuf[mqtt_txlen++] = 'T'; // ASCII Code for T //協議級別 mqtt_txbuf[mqtt_txlen++] = 4; // MQTT Protocol version = 4 對于 3.1.1 版協議,協議級別字段的值是 4(0x04) //連接標志 mqtt_txbuf[mqtt_txlen++] = 0xc2; // conn flags mqtt_txbuf[mqtt_txlen++] = 0; // Keep-alive Time Length MSB mqtt_txbuf[mqtt_txlen++] = 100; // Keep-alive Time Length LSB 100S心跳包 保活時間 mqtt_txbuf[mqtt_txlen++] = BYTE1(ClientIDLen);// Client ID length MSB mqtt_txbuf[mqtt_txlen++] = BYTE0(ClientIDLen);// Client ID length LSB memcpy(&mqtt_txbuf[mqtt_txlen],ClientID,ClientIDLen); mqtt_txlen += ClientIDLen; if(UsernameLen > 0) { mqtt_txbuf[mqtt_txlen++] = BYTE1(UsernameLen); //username length MSB mqtt_txbuf[mqtt_txlen++] = BYTE0(UsernameLen); //username length LSB memcpy(&mqtt_txbuf[mqtt_txlen],Username,UsernameLen); mqtt_txlen += UsernameLen; } if(PasswordLen > 0) { mqtt_txbuf[mqtt_txlen++] = BYTE1(PasswordLen); //password length MSB mqtt_txbuf[mqtt_txlen++] = BYTE0(PasswordLen); //password length LSB memcpy(&mqtt_txbuf[mqtt_txlen],Password,PasswordLen); mqtt_txlen += PasswordLen; } memset(mqtt_rxbuf,0,mqtt_rxlen); MQTT_SendBuf(mqtt_txbuf,mqtt_txlen); for(j=0;j<10;j++) { delay_ms(50); if(USART2_RX_FLAG) { memcpy((char *)mqtt_rxbuf,USART2_RX_BUFFER,USART2_RX_CNT); //memcpy for(i=0;i 0 ) encodedByte = encodedByte | 128; mqtt_txbuf[mqtt_txlen++] = encodedByte; }while ( DataLen > 0 ); //可變報頭 mqtt_txbuf[mqtt_txlen++] = 0; //消息標識符 MSB mqtt_txbuf[mqtt_txlen++] = 0x0A; //消息標識符 LSB //有效載荷 mqtt_txbuf[mqtt_txlen++] = BYTE1(topiclen);//主題長度 MSB mqtt_txbuf[mqtt_txlen++] = BYTE0(topiclen);//主題長度 LSB memcpy(&mqtt_txbuf[mqtt_txlen],topic,topiclen); mqtt_txlen += topiclen; if(whether) { mqtt_txbuf[mqtt_txlen++] = qos;//QoS級別 } for(i=0;i<10;i++) { memset(mqtt_rxbuf,0,mqtt_rxlen); MQTT_SendBuf(mqtt_txbuf,mqtt_txlen); for(j=0;j<10;j++) { delay_ms(50); if(USART2_RX_FLAG) { memcpy((char *)mqtt_rxbuf,(char*)USART2_RX_BUFFER,USART2_RX_CNT); USART2_RX_FLAG=0; USART2_RX_CNT=0; } if(mqtt_rxbuf[0]==parket_subAck[0] && mqtt_rxbuf[1]==parket_subAck[1]) //訂閱成功 { return 0;//訂閱成功 } } } return 1; //失敗 } //MQTT發布數據打包函數 //topic 主題 //message 消息 //qos 消息等級 u8 MQTT_PublishData(char *topic, char *message, u8 qos) { int topicLength = strlen(topic); int messageLength = strlen(message); static u16 id=0; int DataLen; mqtt_txlen=0; //有效載荷的長度這樣計算:用固定報頭中的剩余長度字段的值減去可變報頭的長度 //QOS為0時沒有標識符 //數據長度 主題名 報文標識符 有效載荷 if(qos) DataLen = (2+topicLength) + 2 + messageLength; else DataLen = (2+topicLength) + messageLength; //固定報頭 //控制報文類型 mqtt_txbuf[mqtt_txlen++] = 0x30; // MQTT Message Type PUBLISH //剩余長度 do { u8 encodedByte = DataLen % 128; DataLen = DataLen / 128; // if there are more data to encode, set the top bit of this byte if ( DataLen > 0 ) encodedByte = encodedByte | 128; mqtt_txbuf[mqtt_txlen++] = encodedByte; }while ( DataLen > 0 ); mqtt_txbuf[mqtt_txlen++] = BYTE1(topicLength);//主題長度MSB mqtt_txbuf[mqtt_txlen++] = BYTE0(topicLength);//主題長度LSB memcpy(&mqtt_txbuf[mqtt_txlen],topic,topicLength);//拷貝主題 mqtt_txlen += topicLength; //報文標識符 if(qos) { mqtt_txbuf[mqtt_txlen++] = BYTE1(id); mqtt_txbuf[mqtt_txlen++] = BYTE0(id); id++; } memcpy(&mqtt_txbuf[mqtt_txlen],message,messageLength); mqtt_txlen += messageLength; MQTT_SendBuf(mqtt_txbuf,mqtt_txlen); return mqtt_txlen; }

      云端實踐 移動APP IoT

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:生產計劃管理系統(3分鐘之前已更新)
      下一篇:怎樣讓照片隱藏(怎樣讓照片隱藏起來蘋果手機)
      相關文章
      亚洲VA中文字幕无码毛片| 在线aⅴ亚洲中文字幕| 亚洲综合色婷婷在线观看| 亚洲大尺度无码无码专区| 日韩精品成人亚洲专区| 亚洲av无码一区二区三区天堂 | 亚洲av无码专区在线电影| 在线综合亚洲中文精品| 亚洲人成综合网站7777香蕉| 亚洲性无码av在线| 亚洲人成网男女大片在线播放| 亚洲毛片一级带毛片基地| 亚洲精品在线不卡| 亚洲国产成人片在线观看无码| 国产国拍亚洲精品mv在线观看 | 亚洲人成网站在线播放2019| 亚洲日产乱码一二三区别| 亚洲成a∨人片在无码2023| 国产精品亚洲专区无码牛牛| 无码天堂亚洲国产AV| 日韩欧美亚洲国产精品字幕久久久| 亚洲人成网站免费播放| 亚洲精品女同中文字幕| 亚洲AV无码一区二区三区鸳鸯影院| 国产精品亚洲天堂| 久久精品国产精品亚洲下载| 亚洲一区二区女搞男| 久久精品国产亚洲av四虎| 亚洲综合男人的天堂色婷婷| 亚洲一区二区三区不卡在线播放| 亚洲色最新高清av网站| 国产偷国产偷亚洲清高APP| 久久精品国产亚洲Aⅴ香蕉| 国产亚洲美女精品久久久久狼| 亚洲国产精品久久久久网站 | 亚洲综合色成在线播放| 亚洲人成伊人成综合网久久久| 久久久久亚洲AV成人无码| 亚洲成aⅴ人在线观看| 亚洲真人无码永久在线观看| 国产亚洲精品成人久久网站|