一、搭建程式的開發環境:
NB-Iot 無線通訊板我們選擇的主控晶片是 我們選擇的是華大半導體的HC32F005C6PA, 這個晶片是基於M0的32位低功耗微控制器。
開發環境我們選擇的是Keil MDK, 這個非常通用,在這裡我就不給大家介紹了。
二、準備工作:
NB-Iot通訊的主要功能是為了將煙感的資料上次到雲平臺。
目前的NB-Iot 的雲平臺主要中國移動的OneNet 和中國電信cwing。今天華維微控制器程式設計主要給大家介紹一下BC26和OneNet平臺的通訊。
為什麼不選擇中國電信平臺? 中國電信也是可以的,只不過中國電信平臺需要企業註冊認證才可以註冊賬號,有點麻煩。
1.我們首先要註冊一個OneNet 賬號,OneNet個體就可以註冊。
開啟網頁,大家在右上腳,註冊賬號,然後再登陸。
我們登入以後需要新建自己的專案, 注意要選擇舊版本。
新建專案如下,可以根據自己的需求 填寫專案名稱,選擇專案標籤。點增加即可。
專案新建完成後如下圖所示:
接下來,我們需要新增產品:
新增裝置的時候,需要和我們的產品裝置對應 ,每個NB-IOT 模組都一個對應的IMEI號。IMSI是裝置安裝的SIM卡的卡號 也是15位。
以上就是我們平臺準備的工作,接下來,我們就開始我們程式的開發
三、產品NB-Iot 通訊指令流程
NB-IOT 是基於運營商的基站通訊的,所有需要準備一張有效的NB-Iot SIM卡。我們選擇的是貼片SIM卡,可以直接使用。
我們先研究一下NB-IOT 的初始化過程。(參考BC26軟體開發相關資料)
1.NB-Iot的初始化指令:
獲取模組的IMEI號
指令: AT + CGSN = 1;
OneNet平臺註冊需要
490154203237511 就是模組的IMEI序號,平臺註冊要用。
程式處理:
如果串列埠傳送了 AT + CGSN = 1;NB模組沒有回覆,就需要確定是否模組開機失敗?或者模組硬體有故障等。(如果模組沒有回覆, 需要嘗試傳送3次,連續3次失敗表示他獲取失敗)
如果獲取到了有效值,則執行下一條指令
獲取產品SIM卡的IMSI OneNet平臺註冊需要
指令: AT+CIMI
460001357924680 SIM卡的IMSI序號
程式處理:
獲取失敗: 表示檢測SIM卡失敗,裝置異常,透過提示燈報故障,
獲取成功:執行下一條指令
查詢訊號值
指令: AT+CSQ
從指令可以獲取 當前的CSQ值為22,表示為有效值。CSQ的其他取值的含義。
0 -113 dBm 或以下
1 -111 dBm
2~30 -109 至-53 dBm
31 -51 dBm 或以上
程式初始化過程中,我們需要判斷CSQ的值 需要大於10,且小於32.才能有效,負責後期會嚴重影響產品的穩定性,需要提示生產者 產看是否天線沒有安裝好,或其他問題。
程式處理:
CSQ異常: 表示檢測SIM卡失敗,裝置異常,透過提示燈報故障,
CSQ的值有效:執行下一條指令
注意:CSQ 的值需要系統每隔2秒,連續迴圈查詢20次,等待模組入網。
查詢模組網路是否已經註冊。
指令: AT+CEREG?
本條指令說明:
+CEREG: 1,1
第一個1,表示允許上報網路註冊狀態,如果=0,表示禁止上報網路註冊狀態 URC
第二個1,表示EPS 註冊狀態。其他取值說明。
0 未註冊,MT 當前未搜尋網路
1 已註冊,歸屬網路
2 未註冊,但 MT 當前正在嘗試附著或搜尋網路以進行註冊
3 註冊被拒絕
4 未知(例如:超出 E-UTRAN 覆蓋範圍)
5 已註冊,漫遊狀態
程式處理:
傳送 AT+CEREG?,模組需要回復+CEREG: 1,1,或+CEREG: 0,1 表示網路已註冊。
回覆失敗:迴圈等待查詢20,間隔2秒。 超時提示故障,需要查詢模組的硬體故障
回覆成功: 執行下一條指令。
查詢 PDP 上下文啟用狀態
指令:AT+CGATT?
+CGATT:0:
0 去附著或未附著
1 附著
程式處理:
傳送 AT+CGATT?模組需要回復+CGATT:1
回覆失敗:迴圈等待查詢20,間隔2秒。 超時提示故障,需要查詢模組的硬體故障
回覆成功: 執行下一條指令。
查詢工作頻段
指令: AT+QBAND?
+QBAND:5 的有效值:1、3、5、8、20 等;
我們的是中國移動,取值需要是8.
程式處理:
傳送 AT+CGATT?模組需要回復+QBAND:8
回覆失敗:執行AT+QBAND = 8 來設定網路
回覆成功: 執行下一條指令。
2. NB-Iot註冊網路:
網路註冊,需要使用者,根據NB模組的IMEI 和IMSI 再OneNet 平臺上註冊,再執行本段程式程式碼,否則會失敗。
註冊流程如下:
詳細說明:
AT+MIPLCREATE指令
功能:建立 OneNET 通訊套件例項
程式開發說明:
本條指令的響應時間最大為5秒,只能傳送一次,等待5秒超時。
返回值: +MIPLCREATE:0
獲取失敗:需要執行AT+MIPLCLOSE=0 關閉例項,再執行AT+MIPLDELETE=0 刪除例項,再執行AT+MIPLCREATE。
獲取成功:執行下條指令。
AT+MIPLADDOBJ=0,3311,1,”1″,4,2指令 (重要)
功能: 新增 LwM2M 物件
說明: NB-IOT 是基於LwM2M 協議開發的,需要增加LwM2M才可以和平臺通訊
指令說明:
(引數說明:省略,有疑問的 請找無際微控制器程式設計。
程式開發說明:
本條指令的響應時間最大為5秒,只能傳送一次,等待5秒超時。
返回值:OK
獲取失敗:需要執行AT+MIPLCLOSE=0 關閉例項,再執行AT+MIPLDELETE=0 刪除例項,再從AT+MIPLCREATE開始執行。 本條指令一般不會出錯。
獲取成功:執行下條指令。
AT+MIPLOPEN=0,86400 指令(重要)
功能說明: 傳送註冊請求
指令說明:86400 設定裝置的生命週期,實際生命週期為<lifetime> × 0.9。範圍:
15~268435455,若設定為 0,則表示 3600 秒;單位:秒。
返回值:
+MIPLEVENT: 0,1 //開始連線到 Bootstrap 伺服器。
+MIPLEVENT: 0,2 //成功連線到 Bootstrap 伺服器。
+MIPLEVENT: 0,4 //成功連線到 OneNET 平臺。
+MIPLEVENT: 0,6 //成功註冊到 OneNET 平臺。
如果返回:+MIPLEVENT: 0,3 表示OneNet 平臺沒有註冊本裝置
程式處理:
獲取失敗: 獲取到 +MIPLEVENT: 0,4 表示註冊到平臺,否則註冊失敗,執行AT+MIPLCLOSE=0 關閉例項,再執行AT+MIPLDELETE=0 刪除例項,再從AT+MIPLCREATE開始執行。
獲取成功:執行下一條指令
AT+MIPLOBSERVE: 0,69234,1,3311,0,-1 指令(重要)
功能說明:響應訂閱請求
指令說明:
返回值:
+MIPLDISCOVER: 0,26384,3311 //接收到發現資源請求。
程式處理:
本條指令的響應時間最大為5秒,只能傳送一次,等待5秒超時。 獲取到資料後,需要獲取msgid的值,下條指令需要該值。
獲取失敗:因網路穩定型問題,會導致本條指令執行失敗或錯誤。
如果失敗,需要執行AT+MIPLCLOSE=0 關閉例項,再執行AT+MIPLDELETE=0 刪除例項,再從AT+MIPLCREATE開始執行。
獲取成功:執行下一條指令
AT+MIPLDISCOVERRSP=0,26384,1,19,”5850;5851;5706;5805″ 指令(重要)
功能說明:該命令用於響應來自 OneNET 平臺的發現資源請求。
指令說明:
程式響應: OK
程式處理:
本條指令的響應時間最大為5秒,只能傳送一次,等待5秒超時。 msgid的值需要從上一條指令獲取。
獲取失敗:因網路穩定型問題,會導致本條指令執行失敗或錯誤。
如果失敗,需要執行AT+MIPLCLOSE=0 關閉例項,再執行AT+MIPLDELETE=0 刪除例項,再從AT+MIPLCREATE開始執行。
獲取成功:表示裝置再OneNet平臺註冊成功。 需要獲取。
3. NB-Iot上傳資料。
指令說明:
程式處理:
如果傳送成功:則返回OK。
返回失敗: 需要先確定指令的資料格式是否正常。 如果正常則需要檢測裝置的網路是否異常,如果異常需要執行AT+MIPLCLOSE=0 關閉例項,再執行AT+MIPLDELETE=0 刪除例項,再從AT+MIPLCREATE開始重新註冊網路。
返回正常: 裝置進入休眠,或等待處理其他資料。
4更新裝置生命週期,如果確實這條指令,會導致裝置離線。
AT+MIPLOPEN=0,86400 設定裝置的生命週期為86400秒,也就是說,再裝置工作86400之前需要更新裝置的生命週期,才能確保產品持續線上,否則會離線。
返回值:+MIPLEVENT: 0,11 //更新結果。
程式開發說明:
本條指令的響應時間最大為5秒,只能傳送一次,等待5秒超時。負責就需要執行AT+MIPLCLOSE=0 關閉例項….
因為網路問題,執行本條指令需要等待5秒時間。需要再裝置的生命週期結束前執行本條指令。
四、程式開發:
上面我們瞭解了NB-Iot的通訊流程和相關指令,下面我們開始程式的相關開發,再這裡我給大家做個簡單的介紹,因為產品的選擇的微控制器和平臺都不一樣。
程式開發邏輯:
微控制器控制NB-Iot模組的PowerKey腳位拉低800毫秒開機,詳細請參考BC26的硬體設計。
見上圖,微控制器控制MCU_PKEY 拉高500ms
開始NB-Iot 的指令控制:
AT + CGSN = 1;
AT+CIMI
AT+CSQ
…..
以上已介紹。
備註:每條指令的超時時間,執行次數都不一樣,都需要等待正確的回覆才能執行下一條指令。
在這裡大家需要做一個結構體陣列:程式碼如下:
typedef struct stCmdStr
{
unsigned char id; // 傳送ID號
unsigned char const *str; // 傳送AT指令包
unsigned char neddack; // 是否需要檢驗應答
unsigned short len; //傳送資料長度
unsigned char ResenTimes; //傳送的次數
unsigned short DelaySetTim; // 傳送前延時時間
unsigned short SetInterDelayTim; // 傳送間隔時間
unsigned char Next_SucIdx; // 下個指標 成功操作後
unsigned char Next_FaiIdx; // 下個指標 失敗操作後
}stCmdStrTy;
stCmdStrTy atCmdInMain; ////
void SetCmdBuff(unsigned char scmid,stCmdStrTy * cmd)
{
atCmdBuff[scmid].id = cmd->id;
atCmdBuff[scmid].str = cmd->str;
atCmdBuff[scmid].neddack = cmd->neddack;
atCmdBuff[scmid].len = cmd->len;
atCmdBuff[scmid].DelaySetTim = cmd->DelaySetTim;
atCmdBuff[scmid].SetInterDelayTim = cmd->SetInterDelayTim;
atCmdBuff[scmid].ResenTimes = cmd->ResenTimes;
atCmdBuff[scmid].Next_FailOverTimID = cmd->Next_FailOverTimID;
}
void NBIOT_SysteMode_ListInit(void)
{
atCmdInMain.id = NB_MODE_RESET; ///確認模組AT指令收發是否正常。 返回OK 表示正常
atCmdInMain.str = &NBIOT_BC95_At_Com[NBIOM_ATCOM_RESET][0];
atCmdInMain.neddack = TRUE;
atCmdInMain.len=Fun_GetStrLen((unsigned char *)NBIOT_BC95_At_Com[NBIOM_ATCOM_RESET]);
atCmdInMain.DelaySetTim = 0;
atCmdInMain.SetInterDelayTim = 6000;
atCmdInMain.ResenTimes = 3;
atCmdInMain.Next_SucIdx = NB_MODE_AT;
atCmdInMain.Next_FaiIdx = NB_MODE_RESET;
SetCmdBuff(NB_MODE_RESET,&atCmdInMain);
atCmdInMain.id = NB_MODE_AT; ///確認模組AT指令收發是否正常。 返回OK 表示正常
atCmdInMain.str = &NBIOT_BC95_At_Com[NBIOT_ATCOM_AT][0];
atCmdInMain.neddack = TRUE;
atCmdInMain.len=Fun_GetStrLen((unsigned char *)NBIOT_BC95_At_Com[NBIOT_ATCOM_AT]);
atCmdInMain.DelaySetTim = 0;
atCmdInMain.SetInterDelayTim = 200;
atCmdInMain.ResenTimes = 20;
atCmdInMain.Next_SucIdx = NB_MODE_CGSN;
atCmdInMain.Next_FaiIdx = NB_MODE_RESET;
SetCmdBuff(NB_MODE_AT,&atCmdInMain);
.....
}
void TxThread(void)
{
static unsigned short InterTimer=0;
switch(satCmdStatu)
{
case ATSTATUSEND: //tx 資料傳送
{
if(SystemModeIdx < NB_MODE_SLEEP)
{
if(SentReDelayT > 0)////傳送資料前延時
{
SentReDelayT--;
return;
}
satCmdAck = ATNULL;
UART1_SendStrLen((unsigned char *)atCmdBuff[SystemModeIdx].str,atCmdBuff[SystemModeIdx].len);//傳送資料
InterTimer = atCmdBuff[SystemModeIdx].SetInterDelayTim; ///間隔時間
if(atCmdBuff[SystemModeIdx].neddack)//判斷本次傳送是否需要等待應答
{
satCmdStatu = ATSTATUCHECK; //checkack 檢測應答
}
else
{
SystemModeIdx = atCmdBuff[SystemModeIdx].Next_SucIdx;////指標Next
SentReDelayT = atCmdBuff[SystemModeIdx].DelaySetTim; ////更新發送資料前延時時間
return;
}
satCmdWaitCnt = 0; //間隔時間復位
satCmdErrorCnt = 0; // 錯誤次數清零
satCmdRepeatCnt = 0; // 重發次數清零
}
else
{
//myprintf("NO CMD");
satCmdStatu = ATSTATUSEND;
return;
}
}
break;
case ATSTATUCHECK: //應答檢測
{ switch(satCmdAck)
{
case ATNULL: ///if(ATNULL == j ) // 等待
case ATERROR:// TCP準備好傳送資料返回OK
{////沒有回覆
if(satCmdWaitCnt++ > InterTimer)// 等待次數超時
{
satCmdStatu = ATSTATUREPEAT;// 重發
satCmdWaitCnt = 0;
}
}
break;
case ATATOK:
{
satCmdStatu = ATSTATUSEND;
satCmdErrorCnt = 0;
satCmdRepeatCnt =0;
atCmdTx = ATTXSENDOK; //TX 傳送Ok
satCmdAck = ATNULL;
SystemModeIdx = atCmdBuff[SystemModeIdx].Next_SucIdx;
SentReDelayT = atCmdBuff[SystemModeIdx].DelaySetTim;
}
break;
case ATRESTR:// TCP準備好傳送資料返回OK
{
satCmdStatu = ATSTATUSEND;
satCmdErrorCnt = 0;
satCmdRepeatCnt =0;
atCmdTx = ATTXSENDOK; //TX 傳送Ok
}
break;
default:
{
myprintf("NO Ack\n");
//sleep(1);
satCmdWaitCnt = 0;
satCmdRepeatCnt=0;
satCmdAck = ATNULL;
satCmdStatu = ATSTATUREPEAT; //其它狀態重發
}
break;
}
}
break;
case ATSTATUREPEAT:
{
satCmdRepeatCnt++;
if(satCmdRepeatCnt >= atCmdBuff[SystemModeIdx].ResenTimes)// 重發計數超
{
if(NB_MODE_WAIT_SLEEP == atCmdBuff[SystemModeIdx].Next_FailOverTimID)
{////系統進入延時
SystemSleepTime = TIME_SYSTEM_SLEEP_ERROR;
satCmdStatu = ATSTATUSEND;
satCmdErrorCnt = 0;
satCmdRepeatCnt =0;
SystemModeIdx =NB_MODE_RESET;
myprintf("模組進入間隔休眠狀態中\r\n");
satCmdAck = ATNULL;
return;
}
else
{
satCmdStatu = ATSTATUSEND;// 傳送狀態復位
SystemModeIdx = atCmdBuff[SystemModeIdx].Next_FailOverTimID;
SentReDelayT = atCmdBuff[SystemModeIdx].DelaySetTim;
}
}
else
{
satCmdStatu = ATSTATUCHECK;// 傳送完後檢測應答
}
satCmdWaitCnt = 0;
satCmdWaitCnt = 0;
satCmdAck = ATNULL;
UART1_SendStrLen((unsigned char *)atCmdBuff[SystemModeIdx].str,atCmdBuff[SystemModeIdx].len);
}
break;
}
}
xxxxxxxxxxbr typedef struct stCmdStrbr{br unsigned char id; // 傳送ID號 br unsigned char const *str; // 傳送AT指令包 br unsigned char neddack; // 是否需要檢驗應答br unsigned short len; //傳送資料長度br unsigned char ResenTimes; //傳送的次數br unsigned short DelaySetTim; // 傳送前延時時間br unsigned short SetInterDelayTim; // 傳送間隔時間 br unsigned char Next_SucIdx; // 下個指標 成功操作後br unsigned char Next_FaiIdx; // 下個指標 失敗操作後 br}stCmdStrTy;brbrstCmdStrTy atCmdInMain; ////brbrvoid SetCmdBuff(unsigned char scmid,stCmdStrTy * cmd)br{ br atCmdBuff[scmid].id = cmd->id;br atCmdBuff[scmid].str = cmd->str;br atCmdBuff[scmid].neddack = cmd->neddack;br atCmdBuff[scmid].len = cmd->len;br atCmdBuff[scmid].DelaySetTim = cmd->DelaySetTim;br atCmdBuff[scmid].SetInterDelayTim = cmd->SetInterDelayTim; br atCmdBuff[scmid].ResenTimes = cmd->ResenTimes;br atCmdBuff[scmid].Next_FailOverTimID = cmd->Next_FailOverTimID; br}brbrvoid NBIOT_SysteMode_ListInit(void)br{br atCmdInMain.id = NB_MODE_RESET; ///確認模組AT指令收發是否正常。 返回OK 表示正常br atCmdInMain.str = &NBIOT_BC95_At_Com[NBIOM_ATCOM_RESET][0];br atCmdInMain.neddack = TRUE;br atCmdInMain.len=Fun_GetStrLen((unsigned char *)NBIOT_BC95_At_Com[NBIOM_ATCOM_RESET]);br atCmdInMain.DelaySetTim = 0;br atCmdInMain.SetInterDelayTim = 6000;br atCmdInMain.ResenTimes = 3;br atCmdInMain.Next_SucIdx = NB_MODE_AT;br atCmdInMain.Next_FaiIdx = NB_MODE_RESET;br SetCmdBuff(NB_MODE_RESET,&atCmdInMain);brbr atCmdInMain.id = NB_MODE_AT; ///確認模組AT指令收發是否正常。 返回OK 表示正常br atCmdInMain.str = &NBIOT_BC95_At_Com[NBIOT_ATCOM_AT][0];br atCmdInMain.neddack = TRUE;br atCmdInMain.len=Fun_GetStrLen((unsigned char *)NBIOT_BC95_At_Com[NBIOT_ATCOM_AT]);br atCmdInMain.DelaySetTim = 0;br atCmdInMain.SetInterDelayTim = 200;br atCmdInMain.ResenTimes = 20;br atCmdInMain.Next_SucIdx = NB_MODE_CGSN;br atCmdInMain.Next_FaiIdx = NB_MODE_RESET;br SetCmdBuff(NB_MODE_AT,&atCmdInMain);br .....br}brvoid TxThread(void)br{br static unsigned short InterTimer=0; br switch(satCmdStatu)br {br case ATSTATUSEND: //tx 資料傳送br {br if(SystemModeIdx < NB_MODE_SLEEP)br {br if(SentReDelayT > 0)////傳送資料前延時br {br SentReDelayT--;br return; br } br satCmdAck = ATNULL;br UART1_SendStrLen((unsigned char *)atCmdBuff[SystemModeIdx].str,atCmdBuff[SystemModeIdx].len);//傳送資料br InterTimer = atCmdBuff[SystemModeIdx].SetInterDelayTim; ///間隔時間br if(atCmdBuff[SystemModeIdx].neddack)//判斷本次傳送是否需要等待應答br { br satCmdStatu = ATSTATUCHECK; //checkack 檢測應答br }br elsebr {br SystemModeIdx = atCmdBuff[SystemModeIdx].Next_SucIdx;////指標Nextbr SentReDelayT = atCmdBuff[SystemModeIdx].DelaySetTim; ////更新發送資料前延時時間 br return;br }br satCmdWaitCnt = 0; //間隔時間復位 br satCmdErrorCnt = 0; // 錯誤次數清零br satCmdRepeatCnt = 0; // 重發次數清零br }br elsebr {br //myprintf("NO CMD");br satCmdStatu = ATSTATUSEND;br return;br }br }br break; br case ATSTATUCHECK: //應答檢測br { switch(satCmdAck)br {br case ATNULL: ///if(ATNULL == j ) // 等待br case ATERROR:// TCP準備好傳送資料返回OKbr {////沒有回覆br if(satCmdWaitCnt++ > InterTimer)// 等待次數超時br { br satCmdStatu = ATSTATUREPEAT;// 重發br satCmdWaitCnt = 0;br }br }br break;br case ATATOK:br {br satCmdStatu = ATSTATUSEND; br satCmdErrorCnt = 0; br satCmdRepeatCnt =0;br atCmdTx = ATTXSENDOK; //TX 傳送Okbr satCmdAck = ATNULL; br SystemModeIdx = atCmdBuff[SystemModeIdx].Next_SucIdx;br SentReDelayT = atCmdBuff[SystemModeIdx].DelaySetTim;br }br break;br case ATRESTR:// TCP準備好傳送資料返回OKbr {br satCmdStatu = ATSTATUSEND; br satCmdErrorCnt = 0; br satCmdRepeatCnt =0;br atCmdTx = ATTXSENDOK; //TX 傳送Okbr }br break;br default:br {br myprintf("NO Ack\n"); brbr //sleep(1);br satCmdWaitCnt = 0;br satCmdRepeatCnt=0;br satCmdAck = ATNULL; br satCmdStatu = ATSTATUREPEAT; //其它狀態重發 br }br break; br }br }br break;br case ATSTATUREPEAT:br {br satCmdRepeatCnt++;br if(satCmdRepeatCnt >= atCmdBuff[SystemModeIdx].ResenTimes)// 重發計數超br {br if(NB_MODE_WAIT_SLEEP == atCmdBuff[SystemModeIdx].Next_FailOverTimID)br {////系統進入延時br SystemSleepTime = TIME_SYSTEM_SLEEP_ERROR;br satCmdStatu = ATSTATUSEND; br satCmdErrorCnt = 0; br satCmdRepeatCnt =0;br SystemModeIdx =NB_MODE_RESET;br myprintf("模組進入間隔休眠狀態中\r\n");br satCmdAck = ATNULL; br return;br }br elsebr {br satCmdStatu = ATSTATUSEND;// 傳送狀態復位 br SystemModeIdx = atCmdBuff[SystemModeIdx].Next_FailOverTimID;br SentReDelayT = atCmdBuff[SystemModeIdx].DelaySetTim;br } br }br elsebr {br satCmdStatu = ATSTATUCHECK;// 傳送完後檢測應答br } br satCmdWaitCnt = 0;br satCmdWaitCnt = 0;br satCmdAck = ATNULL;br UART1_SendStrLen((unsigned char *)atCmdBuff[SystemModeIdx].str,atCmdBuff[SystemModeIdx].len); br }br break;br } br}
完整程式篇幅太長,這裡就不放了,可以找華維微控制器程式設計獲取。
NB-Iot 接收程式:
為了防止串列埠接收資料丟失,我們訂了一個256位元組的佇列,
Queue256 Uart1RxMsg;
串列埠接收主函式如下,使用到了回撥函式:
void RxThread(void)
{
if(satCmdAck == ATNULL)
{
satCmdAck = (unsigned char)NB_IOT_UartRec((Enum_NbIot_Mode)atCmdBuff[SystemModeIdx].id,Fuc_GetAtRespose);
}
}
串列埠獲取資料解析函式:
unsigned char Uart_GetDat(unsigned char *getbuf)
{
unsigned char i;
unsigned char len,dat,idx;
static unsigned char lenx,GetDat_Delay;
len = QueueDataLen(Uart1RxMsg);
if(len)
{
if(len == lenx)
{///接收資料延時
GetDat_Delay++;
}
else
{///收到了新的資料
lenx = len;
GetDat_Delay = 0;
}
if(GetDat_Delay > 100)
{/////收到資料起,延時120毫秒,開始判斷接收到的資料
idx = 0xff;
i = 0;
do
{
i++;
QueueDataOut(Uart1RxMsg,&dat);
if(dat == 0x0A) /////10 0A '\n'
{
if((idx == 0xff) || (idx < 2))
{
idx = 0;
}
}
else if(dat == 0x0D)////12 0D '\r'
{
if(idx == 0)
idx = 0;
else if((idx > 1) && (idx != 0xff))
return idx;
else
idx = 0xff;
}
else
{
if(idx != 0xff)
{
getbuf[idx ++] = dat;
if(idx > 59)
return 0xff;
}
}
}while(i< len);
}
}
else
{
lenx = 0;
GetDat_Delay = 0;
}
return 0xff;
}
xxxxxxxxxxbr void RxThread(void)br{br if(satCmdAck == ATNULL)br {br satCmdAck = (unsigned char)NB_IOT_UartRec((Enum_NbIot_Mode)atCmdBuff[SystemModeIdx].id,Fuc_GetAtRespose);br }br}br串列埠獲取資料解析函式:brunsigned char Uart_GetDat(unsigned char *getbuf)br{br unsigned char i;br unsigned char len,dat,idx;br static unsigned char lenx,GetDat_Delay;br len = QueueDataLen(Uart1RxMsg);br if(len)br {br if(len == lenx)br {///接收資料延時br GetDat_Delay++; br }br elsebr {///收到了新的資料br lenx = len;br GetDat_Delay = 0;br } br if(GetDat_Delay > 100)br {/////收到資料起,延時120毫秒,開始判斷接收到的資料br idx = 0xff;br i = 0;br dobr {br i++;br QueueDataOut(Uart1RxMsg,&dat);br if(dat == 0x0A) /////10 0A '\n'br {br if((idx == 0xff) || (idx < 2))br {br idx = 0; br }br }br else if(dat == 0x0D)////12 0D '\r'br {br if(idx == 0)br idx = 0;br else if((idx > 1) && (idx != 0xff)) br return idx;br elsebr idx = 0xff;br } br elsebr {br if(idx != 0xff)br {br getbuf[idx ++] = dat; br if(idx > 59)br return 0xff; br }br }br }while(i< len); br }br }br elsebr {br lenx = 0;br GetDat_Delay = 0;br }br return 0xff;br}br
Ok,那我們這節課就先講到這裡,到此整個專案就實現功能了,本節課較長,大家可以多看幾遍加深理解,下篇文章我跟大家講解這個產品的一些測試驗證方法及注意問題。