NBIOT-BC28模塊程序操作接口編寫(基于STM32F103ZET6)
項(xiàng)目最終效果,大家可以根據(jù)API的去實(shí)現(xiàn)自己的業(yè)務(wù)需求。
程序設(shè)計(jì)結(jié)構(gòu)體,存儲獲取模組的相關(guān)信息
typedef struct NETWORK_INFO
{
//初始化NB模塊的狀態(tài)
u8 Init_NB_Status ;
//NB模塊的信號強(qiáng)度
u8 signalCSQ ;
//IMEI卡號
char IMEI[16];
//IMSI卡號
char IMSI[16];
//注網(wǎng)標(biāo)志位
bool Register_NetWork_Flag ;
//服務(wù)器連接標(biāo)志位
bool Connect_Server_Flag ;
} NETWORK_DEVICE_INFO;
extern NETWORK_DEVICE_INFO NBIOT_MODULE_INFO ;
下面實(shí)現(xiàn)操作NB的方法,首先是最核心的NB指令發(fā)送函數(shù),有了這樣一個函數(shù),后面的應(yīng)用才能寫,這里用的是中斷采集的方式,后續(xù)可以更改成DMA接收,傳輸效率會更高一些,等下次更新一個新的版本,附帶完整的測試工程。
/*
* 函數(shù)名:NBIOT_Cmd
* 描述 :對NBIOT模塊發(fā)送AT指令
* 輸入 :cmd,待發(fā)送的指令
* reply1,reply2,期待的響應(yīng),為NULL表不需響應(yīng),兩者為或邏輯關(guān)系
* waittime,等待響應(yīng)的時間
* 返回 : 1,指令發(fā)送成功
* 0,指令發(fā)送失敗
* 調(diào)用 :被外部調(diào)用
*/
bool NBIOT_Cmd ( char * cmd, char * reply1, char * reply2, u32 waittime )
{
bool status = false ;
USART4_RX_STA = 0; //從新開始接收新的數(shù)據(jù)包
NB_FramLength = 0 ;
memset(RXBuffer, 0, RXBUFFER_LEN); //清空接收緩沖
u4_printf("%s\r\n", cmd);
if ( ( reply1 == 0 ) && ( reply2 == 0 ) ) //不需要接收數(shù)據(jù)
return true;
Delay_ms ( waittime ); //延時
RXBuffer[NB_FramLength] = '\0';
printf("RXBuffer:%s\n", RXBuffer);
if(strstr((char *)RXBuffer, reply2) != NULL)
{
printf("ackerror:%s\n", reply2);
return false ;
}
if(strstr((char *)RXBuffer, reply1) != NULL)
{
printf("acksuccess:%s\n", RXBuffer);
//如果匹配到斷連標(biāo)志,就重新建立連接
if(strstr((char *)RXBuffer, "+NSOCLI: 1") != NULL)
{
status = NB_Create_TCP("120.78.136.134", 9002);
if(false == status)
{
printf("重新創(chuàng)建TCP連接失敗\n");
return -1 ;
}
else
{
printf("重新創(chuàng)建TCP連接成功\n");
}
}
return true ;
}
return false ;
}
根據(jù)實(shí)現(xiàn)的發(fā)送函數(shù),下面來實(shí)現(xiàn)驅(qū)動NB模塊的接口以及整套初始化流程,可以減少開發(fā)者的負(fù)擔(dān)。
在對NB模塊的編程中,其實(shí)就是對串口操作,通常我們會有一個與模塊的應(yīng)答指令,尋問模塊是否在線,進(jìn)而來判斷模塊是否硬件是否已經(jīng)連接正確或者模塊是否損壞。
//檢查模組是否在線
bool checkNBIOT(void)
{
return NBIOT_Cmd("AT", "OK", NULL, 100);
}
當(dāng)發(fā)出AT時,模組應(yīng)給主機(jī)回復(fù)OK作為應(yīng)答,這樣主機(jī)就和模組建立通信。
根據(jù)前面寫過的一篇文章,我們還要對BC28做一系列的適配操作,比如,使能自動尋網(wǎng)、設(shè)置頻段(電信為5,移動為8)、打開優(yōu)碼控制選項(xiàng)第二項(xiàng)、第三項(xiàng)。
//NBIOT基礎(chǔ)配置===>band 5 ==> 電信卡 8===>移動卡
bool BASE_Config_NBIOT(int band)
{
char buffer[50] = {0};
bool status = true ;
//設(shè)置頻段
sprintf(buffer, "AT+NBAND=%d", band);
status = NBIOT_Cmd(buffer, "OK", NULL, 100);
//自動尋網(wǎng)
status = NBIOT_Cmd("AT+NCONFIG=AUTOCONNECT,TRUE", "OK", NULL, 100);
//打開優(yōu)碼控制2,3項(xiàng)
status = NBIOT_Cmd("AT+NCONFIG=CR_0354_0338_SCRAMBLING,TRUE", "OK", NULL, 100);
status = NBIOT_Cmd("AT+NCONFIG=CR_0859_SI_AVOID,TRUE", "OK", NULL, 100);
return status ;
}
3.1 IMSI 設(shè)備識別碼
NB模塊或者其它的一些通信模塊,它都會有一個獨(dú)有的IMEI號,它是模塊生產(chǎn)廠家指定的一個設(shè)備識別碼,通過指令A(yù)T+CGSN=1來獲取,功能函數(shù)如下:
bool Get_IMEI(void)
{
bool status = true ;
status = NBIOT_Cmd("AT+CGSN=1", "OK", "ERROR", 100);
if(status == true)
{
memcpy((char *)NBIOT_MODULE_INFO.IMEI, RXBuffer + 8, 15);
return true ;
}
return false ;
}
3.2 IMSI 國際移動用戶識別碼
通常該碼存儲在SIM卡中,我們可以使用AT+CIMI這條指令來獲取,這樣可以知道卡到底有沒有插好或者是否存在,功能編寫如下:
//獲取IMSI
bool Get_IMSI(void)
{
bool status = true ;
status = NBIOT_Cmd("AT+CIMI", "OK", "ERROR", 2000);
if(status == true)
{
memcpy((char *)NBIOT_MODULE_INFO.IMSI, RXBuffer + 2, 15);
return true ;
}
return false ;
}
模塊注冊相應(yīng)的運(yùn)行商成功,就會收到相應(yīng)的標(biāo)志,標(biāo)志已經(jīng)注冊成功,功能編寫如下:
//獲取入網(wǎng)狀態(tài)
bool Get_Enter_Net_Status(void)
{
int status = 0 ;
bool cmd_status = false ;
char buffer[30] = {0};
cmd_status = NBIOT_Cmd("AT+CGATT?", "OK", "ERROR", 5000);
memcpy(buffer, RXBuffer + 9, 1);
status = atoi(buffer);
if(1 == status)
return true;
else
return false ;
}
BC28的模組信號級別是0-31,返回99則可能模塊還沒有初始化完畢,或者信號異常。低于10可以認(rèn)為信號為低,一般別的通信模組(比如4G,WIFI等)如果低于這個級別,數(shù)據(jù)可能出現(xiàn)丟包狀態(tài),但NB模塊號稱只要大于8,即可無丟損數(shù)據(jù),實(shí)現(xiàn)函數(shù)如下:
//獲取信號強(qiáng)度
int Get_CSQ(void)
{
int signal_value = -1;
bool status = true ;
char csq_buffer[50] = {0};
status = NBIOT_Cmd("AT+CSQ", "+CSQ", NULL, 100);
if(status == true)
{
memcpy(csq_buffer, RXBuffer + 7, 2);
signal_value = atoi(csq_buffer);
return signal_value ;
}
return 99 ;
}
這里一定要注意一點(diǎn),模組刷寫的固件帶ONT版本的,是不能把數(shù)據(jù)傳到私有的服務(wù)器的,只有不帶ONT的才可以,版本可以通過AT指令的ATI查看。
如果版本是帶ONT,而你又想傳數(shù)據(jù)到自己的后臺,那就請你連接移遠(yuǎn)的FAE,提供最新的固件和固件燒寫工具給你,如圖所示,利用軟件對NB模組進(jìn)行固件更新。
//創(chuàng)建TCP Socket===>成功返回1,失敗返回0
u8 NB_Create_TCP(const char *server_ip, int port)
{
char buffer[50] = {0};
bool status = true ;
//1.創(chuàng)建一個TCP Socket
status = NBIOT_Cmd("AT+NSOCR=STREAM,6,56000,1", "OK", NULL, 2000);
//如果創(chuàng)建成功,則連接遠(yuǎn)程服務(wù)器和端口號
if(true == status)
{
sprintf(buffer, "AT+NSOCO=1,%s,%d", server_ip, port);
status = NBIOT_Cmd(buffer, "OK", NULL, 2000);
if(true == status)
return 1 ;
else
return 0 ;
}
return 0 ;
}
//關(guān)閉Socket連接
bool Close_Socket(void)
{
bool status = true ;
status = NBIOT_Cmd("AT+NSOCL=0", "OK", NULL, 2000);
return status ;
}
//NBIOT發(fā)送數(shù)據(jù)到后臺服務(wù)器
/*
Data_Length:要發(fā)送到后臺的原始數(shù)據(jù)的長度
hex_data:要發(fā)送到后臺的,但必須將原始數(shù)據(jù)轉(zhuǎn)換成十六進(jìn)制編碼的數(shù)據(jù)
*/
bool NB_Send_Data_To_Server(int Data_Length, char *hex_data)
{
bool status = true ;
char data_buffer[1024] = {0};
sprintf(data_buffer, "AT+NSOSD=1,%d,%s", Data_Length, hex_data);
printf("數(shù)據(jù)上傳:\n");
printf("%s\n", data_buffer);
status = NBIOT_Cmd(data_buffer, "OK", "ERROR", 5000);
return status ;
}
通常給模組復(fù)位,一般是設(shè)置完參數(shù)后,手冊要求要進(jìn)行復(fù)位操作,復(fù)位大概需要5s的時間,模組才會穩(wěn)定下來,所以Delay_ms(5000)最好不要丟掉,否則其它的指令可能出現(xiàn)設(shè)置失敗的情況。
//復(fù)位NBIOT模組
bool NB_RESET(void)
{
bool status = true ;
status = NBIOT_Cmd("AT+NRB", "OK", NULL, 10000);
return status ;
}
/**
* 功能:初始化NBIOT
* 參數(shù):None
* 返回值:初始化結(jié)果,非0為初始化成功,0為失敗
*/
int initNBIOT(void)
{
bool status_return = false ;
while(1)
{
switch(NBIOT_MODULE_INFO.Init_NB_Status)
{
//1、檢查NBIOT模塊是否在線
case 0:
status_return = checkNBIOT();
if(false == checkNBIOT)
{
printf("NB模塊硬件故障..\n");
return 0 ;
}
else
{
printf("NB模塊正常連接\n");
NBIOT_MODULE_INFO.Init_NB_Status = 1 ;
}
break ;
//2、進(jìn)行NBIOT的基礎(chǔ)配置
case 1:
status_return = BASE_Config_NBIOT(5);
if(false == status_return)
{
NBIOT_MODULE_INFO.Init_NB_Status = 0 ;
printf("配置自動尋網(wǎng)與優(yōu)碼控制第2、3項(xiàng)失敗\n");
}
else
{
NBIOT_MODULE_INFO.Init_NB_Status = 2 ;
printf("配置自動尋網(wǎng)與優(yōu)碼控制第2、3項(xiàng)成功\n");
}
break ;
//3、復(fù)位模組
case 2:
status_return = NB_RESET();
if(false == status_return)
{
printf("模組復(fù)位失敗\n");
NBIOT_MODULE_INFO.Init_NB_Status = 0 ;
}
else
{
printf("模組復(fù)位成功\n");
Delay_ms(2000);
NBIOT_MODULE_INFO.Init_NB_Status = 3 ;
}
break ;
//4、獲取NB模組號
case 3:
status_return = Get_IMEI();
if(false == status_return)
{
printf("沒有模組卡號,模塊故障\n");
NBIOT_MODULE_INFO.Init_NB_Status = 0 ;
break ;
}
else
{
NBIOT_MODULE_INFO.Init_NB_Status = 4 ;
printf("模組號:%s\n", NBIOT_MODULE_INFO.IMEI);
}
break ;
//獲取SIM卡卡號,確認(rèn)設(shè)備是否已經(jīng)插卡
case 4:
status_return = Get_IMSI();
if(false == status_return)
{
printf("沒有插SIM卡,模塊無法連接網(wǎng)絡(luò)\n");
NBIOT_MODULE_INFO.Init_NB_Status = 0 ;
break ;
}
else
{
printf("SIM卡號:%s\n", NBIOT_MODULE_INFO.IMSI);
NBIOT_MODULE_INFO.Init_NB_Status = 5 ;
}
break ;
//查看注網(wǎng)狀態(tài)
case 5:
status_return = Get_Enter_Net_Status();
if(false == status_return)
{
printf("入網(wǎng)失敗,請重新復(fù)位模塊\n");
NBIOT_MODULE_INFO.Init_NB_Status = 5 ;
break ;
}
else
{
printf("模組入網(wǎng)成功..\n");
NBIOT_MODULE_INFO.Init_NB_Status = 6 ;
}
break ;
//獲取信號強(qiáng)度
case 6:
NBIOT_MODULE_INFO.signalCSQ = Get_CSQ();
if(99 == NBIOT_MODULE_INFO.signalCSQ)
{
printf("設(shè)備無信號....\n");
NBIOT_MODULE_INFO.Init_NB_Status = 5 ;
}
else
{
printf("信號級別:%d\n", NBIOT_MODULE_INFO.signalCSQ);
NBIOT_MODULE_INFO.Init_NB_Status = 7 ;
}
break ;
default:
break ;
}
if(7 == NBIOT_MODULE_INFO.Init_NB_Status)
{
break ;
}
}
return 1;
}
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點(diǎn),不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!