一文教會你嵌入式網路模組的聯網操作
作者:良知猶存
轉載授權以及圍觀:歡迎新增微信公眾號:Conscience_Remains
總述
現在物聯網的概念越來越突出,軟體雲端小米IOT平臺、阿里物聯網雲等等,嵌入式百度手環開源很久了,此外網上關於ESP8266接入閘道器進行遠端控制的原始碼不計其數。
物聯網嵌入式端開發使用中都是各大主流網路模組,其中無線方式通訊方式區分的話,主要分為兩類:一類是Zigbee、WiFi、藍芽、Z-wave等短距離通訊技術;另一類是LPWAN(low-powerWide-AreaNetwork,低功耗廣域網),即廣域網通訊技術。
至於幾種通訊模組使用的技術區別,改天可以寫一篇文章進行詳細介紹。不過 今天我來介紹一下,我使用過的一款2G網路模組,在車載行駛中使用,在很惡劣的情況下,依舊可以保證網路快速連結。因為現在的網路模組都是差不多的,尤其是IOT、LORA以及2G 3G 4G這些通過基站進行組網的模組。
有興趣的朋友可以看看百度手環的開源資料,後臺回覆 find me加我好友進行分享。
一、概念介紹
2G:第二代移動通訊技術加入更多的多址技術,包括TDMA和CDMA,同時2G是數字通訊,因此在抗干擾能力上大大增強。第二代行動通訊可以說對接下來的3G和4G奠定了基礎,比如分組域的引入,和對空中介面的相容性改造,使得手機不再只有語音、簡訊這樣單一的業務,還可以更有效率的連入網際網路(電路域也可以提供internet業務,只是相對來說分組域更適合internet業務)。2G主要的制式也是兩個,分別是來自歐洲ETSI組織的GSM(GPRS/EDGE)和來自美洲以高通公司為主力的TIA組織的CDMA IS95/CDMA2000 1x。
看到這裡大家就有疑問了,上面巴拉巴拉一堆介紹中,2G網路看上去都是很落後的了,畢竟現在5G都出了。2G都沒人用了,有什麼好講的。那我這裡就給2G正個名。
現在網路通訊技術發展的很快,手機等終端對最新通訊技術的支援也是很及時,但是也是在手機這塊。要知道手機現在的售價是很高的,在長時間的快速更新換代中,消費者也逐漸接受了這些技術指標以及消費價格。但是在一些工業領域,物聯網產品中,只要很小的頻寬,網路覆蓋率廣,流量費用足夠低,甚至需要低功耗的模組。IOT LORA就是現在物聯網選擇比較多的模組,但是IOT依舊 也有自己的缺點。
“NB-IOT實際使用沒有理論宣傳那麼好,NB-IOT,功耗低、傳輸距離遠、系統容量大,這些都是耳熟能詳的好處了。但是,功耗低:在大部分場景下,NB並不比2G功耗低多少;傳輸距離遠:現在2G網路全覆蓋,NB-IOT還在鋪網階段,體現不出來優勢;系統容量大:當前物聯網產品遠遠沒有把2G網路佔滿,更體現不出來NB能容納更多裝置的優勢了。價格貴:NB-IOT模組比2G模組貴3-4倍,算上運營商補貼還是要貴不少。”
而2G由於通訊模組成本較低,不到4G模組的三分之一。市面上的共享單車定位和開鎖、POS刷卡支付也採用2G網路連線。所以2G網路現階段應用還是比較廣的,所以我們之前也是採用了2G網路模組進行的開發。
二、模組情況
2G模組比較有名就是上海移遠公司的M26模組,出來時間比較長了,但是M26只有GPRS的功能。
所以我們選擇了中移的M6313模組GPRS和GNSS二合一模組。相關的資料現在也是很多了,一般我們用到是AT命令使用手冊,通訊流程示例手冊。通訊手冊我開發的時候還沒有,現在中移出了,挺開心的,又解決了開發者的一些難題。
首先我們開發使用是也是雲,嵌入式端沒有使用現在比較火的MQTT或者CoAP這些協議,而是直接使用TCP進行埠連結到伺服器。
因為M6313模組的功能和M26很像,所以這個TCP連結過程是可以沿用的。
三、聯網狀態機分析
下面是當初開發時候的寫一個聯網狀態機,最後基本達到在CSQ在12~24時候,聯網時候可以最快達到4~5秒。
這個狀態機可以實現聯網,設定模組自動心跳、切換IP等功能。具體的解釋也都在程式碼裡面展示了。
static void TCP_Conncect(const char* ipaddr, const char* ipport) { char* p = NULL; p = (char*) malloc(100); if(NULL == p) { LOG("malloc p error!\r\n"); } else { memset(p, 0, 100); sprintf(p, "AT+QIOPEN=\"TCP\",\"%s\",%s",ipaddr, ipport); mdm_send_cmd_noack((u8*)p); LOG("%s\r\n", p); //DEBUG } free(p); } /* ****************************************************************** * @brief 進行IP修改時候IP正確性標誌清零 * @author Conqueror(征服者) * @version V1.0 * @date 2019-6-10 ****************************************************************** */ u8 IsIPvalid = 0; static void ChangeIP(void) { IsIPvalid = 0; dprintf("Clear IsIPvalid!\r\n"); } /* ****************************************************************** * @brief timer.c進行呼叫此函式進行判斷IP是否正常通訊 * @author Conqueror(征服者) * @version V1.0 * @date 2019-6-17 ****************************************************************** */ TimTypeDef SecIPTimeManage; void SecIPManageTimer(void) { if(SecIPTimeManage.stat == TON) { (SecIPTimeManage.cunt < SecIPTimeManage.des)?(SecIPTimeManage.cunt++):\ (TimerManageInit(&SecIPTimeManage,TOFF,0),IsIPvalid=0); } } /* ****************************************************************** * @brief IP為正確可用的,可以進行寫進FLASH * @author Conqueror(征服者) * @version V1.0 * @date 2019-6-17 ****************************************************************** */ void IPValid(void) { if(devParam.secondTcp.addr[0] !=0) { IsIPvalid=1; TimerManageInit(&SecIPTimeManage,TOFF,0); LOG("IP Valid !\r\n"); } } /* ****************************************************************** * @brief 用於第一次連線新的IP地址的時候進行傳送測試 * @author Conqueror(征服者) * @version V1.0 * @date 2019-6-17 ****************************************************************** */ static void TestTCP(void) { if(cntMdm == 1 && devParam.secondTcp.addr[0] !=0) { M6313SendTestData();/*確認IP情況*/ TimerManageInit(&SecIPTimeManage,TON,2000);/*20s判斷*/ } } /* ****************************************************************** * @brief 判斷IP是否正確,不正確直接清零 * @author Conqueror(征服者) * @version V1.0 * @date 2019-6-17 ****************************************************************** */ void IsTCPIPVaild(void) { if(gCnt.mdmTotalErr > 3&&mdmInfo.signalIntensity > 10) { memset(&devParam.secondTcp,0x00,sizeof(devParam.secondTcp));/*只要新的進入則清除之前的資料*/ } if(IsIPvalid == 0 && SecIPTimeManage.stat == TOFF && cntMdm==1\ && econdTcp.addr[0] !=0) { LOG("IPInvalid !\r\n"); mdmFSMPWRRSTInit(); /*斷電重啟*/ memset(&devParam.secondTcp,0x00,sizeof(devParam.secondTcp));/*只要新的進入則清除之前的資料*/ } } void mdmFSMPWRRSTInit(void) { MDM_STA = MDM_EXE_PWRRST_ACT; /*設定mdmComFSM狀態*/ TBoxInfoType.userInfo.bit.cntMdm = 0; /*網路預設斷開*/ SysFlag.mdmFSMRunSta = 1; /*啟動MDM_FSM,TCP錯誤處理程式將在一定時間內不執行*/ gtimer.mdmFSMRun = gtimer.timer; /*MDM_FSM處理,開始時刻*/ dprintf("-mdmFSM_PWRRST_Init\r\n"); } void STOP_MDM_FSM(void) { SysFlag.mdmFSMRunSta = 0; /*MDM_FSM強制結束*/ gtimer.mdmFSMRun = 0; } void mdmComFSM(void) { static u8 iTimes = 0; /*發AT CMD次數*/ static u8 mdmPwrOnCnt = 0; /*MDM開機次數*/ if(MDM_STA != MDM_IDLE_STA) /*FSM執行中,重新整理*/ { refreshWorkTimer(); } switch(MDM_STA) { case MDM_IDLE_STA: break; /*----------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ /*模組斷電覆位*/ case MDM_EXE_PWRRST_ACT: LOG("*%d<-:MDM_PWR_RST[T:%d]\r\n", MDM_EXE_PWROFF_ACT, gtimer.timer); MDM_PWR_EN_L; gtimer.mdmFSMTimerout = 0; MDM_STA = MDM_WAIT_PWRRST_RES; break; case MDM_WAIT_PWRRST_RES: if(gtimer.mdmFSMTimerout > 2000) /*超過10秒*/ { gtimer.mdmFSMTimerout = 0; MDM_PWR_EN_H; LOG("MDM_PWR_EN_H!\r\n"); MDM_STA = MDM_EXE_PWRON_ACT; LOG("MDM_PWR_RST Finish!\r\n"); } break; /*模組關機*/ case MDM_EXE_PWROFF_ACT: /*模組關機:開機狀態模組的PWRKEY拉低1s關機*/ LOG("\r\n*Step:%d,MDM_EXE_PWROFF_ACT,time:%d\r\n", MDM_EXE_PWROFF_ACT, gtimer.timer); MDM_PWRKEY_EN_H; gtimer.mdmFSMTimerout = 0; MDM_STA = MDM_WAIT_PWROFF_RES; break; case MDM_WAIT_PWROFF_RES: if(gtimer.mdmFSMTimerout > 200) /*超過1秒*/ { gtimer.mdmFSMTimerout = 0; MDM_PWRKEY_EN_L; /*m6313的PWRKEY處產生高電平*/ MDM_STA = MDM_WAIT_PWROFF_DELAY; LOG("MDM_PWRKEY_EN_L,PWROFF_time:%d\r\n", gtimer.timer); } break; case MDM_WAIT_PWROFF_DELAY: if(gtimer.mdmFSMTimerout > 2400) /*12秒等待,模組關機完成*/ { LOG("MDM_POWER_OFF finish\r\n"); MDM_STA = MDM_EXE_PWRON_ACT; } break; /*模組開機*/ case MDM_EXE_PWRON_ACT: /*模組開機:在關機狀態模組的PWRKEY拉低2s開機*/ LOG("\r\n*Step:%d,MDM_EXE_PWRON_ACT,time:%d\r\n", MDM_EXE_PWRON_ACT,gtimer.timer); M6313ComInit(); MDM_PWRKEY_EN_H; gtimer.mdmFSMTimerout = 0; MDM_STA = MDM_WAIT_PWRON_RES; break; case MDM_WAIT_PWRON_RES: if(gtimer.mdmFSMTimerout > 400) /*超過2秒*/ { MDM_PWRKEY_EN_L; /*PWRKEY開機流程結束*/ mdmPwrOnCnt++; LOG("MDM_POWER_ON,,time:%d\r\n", gtimer.timer); MDM_STA = MDM_TX_AT_CMD; } break; /*檢查MDM通訊*/ case MDM_TX_AT_CMD: LOG("\r\n*Step:%d,AT\r\n", MDM_TX_AT_CMD);//step 1 LOG("AT-%d-\r\n", iTimes); mdm_send_cmd_noack((u8*)"AT"); iTimes++; gtimer.mdmFSMTimerout = 0; MDM_STA = MDM_WAIT_AT_RES; break; case MDM_WAIT_AT_RES: if(!mdm_check_str((u8*)"OK")) /*查詢到OK*/ { LOG("AT-OK-%d-\r\n", iTimes); if(mdmPwrOnCnt > 0) { MDM_STA = MDM_WAIT_GSM_READY; /*模組開機,需要一定時間,等待GSM註冊成功*/ gtimer.mdmFSMTimerout = 0; } else{ MDM_STA = MDM_START_INIT; } } else if(gtimer.mdmFSMTimerout > 400) /*本次等待2秒超時*/ { if(iTimes < EXE_AT_TIMES) { MDM_STA = MDM_TX_AT_CMD; /*繼續傳送AT*/ LOG("continue-%d- send\"AT\"\r\n", iTimes); } else /*iTimes超過次數*/ { iTimes = 0; LOG("AT error,%d times\r\n", EXE_AT_TIMES); if(mdmPwrOnCnt < EXE_MDM_PWRON_TIMES) { MDM_STA = MDM_EXE_PWRON_ACT; //進入開機流程 LOG(".MDM_EXE_PWRON_ACT\r\n"); } else { mdmPwrOnCnt = 0; /*開機次數清零*/ MDM_STA = MDM_IDLE_STA; STOP_MDM_FSM(); /*MDM_FSM結束*/ gCnt.mdmTotalErr++; LOG("send \"AT\" %d times error,mdmTotalErr++\r\n", EXE_AT_TIMES); } } } break; case MDM_WAIT_GSM_READY: /*等待GSM網路註冊成功*/ if(!mdmWaitGSMReady()) { MDM_STA = MDM_START_INIT; /*GSM註冊成功*/ LOG("MDM_GSM_READY\r\n"); } else if(gtimer.mdmFSMTimerout > WAIT_GSM_READY_MAX_TIME) { MDM_STA = MDM_START_INIT; /*GSM註冊失敗*/ LOG("MDM_GSM_NO_READY\r\n"); } break; /*MDM初始化配置*/ case MDM_START_INIT: /*開始初始化*/ LOG("\r\n*Step:%d,MDM_START_INIT\r\n", MDM_START_INIT); MDM_STA = MDM_TX_ATQINDI_CMD; break; #if 1 //190115 case MDM_TX_ATQINDI_CMD://AT+QINDI配置是否快取接收到的資料 LOG("*%d<-:AT+QINDI=2[%d]\r\n", MDM_TX_ATQINDI_CMD, iTimes); mdm_send_cmd_noack((u8*)"AT+QINDI=2"); //0-不快取 2-快取模式 iTimes++; MDM_STA = MDM_WAIT_ATQINDI_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_ATQINDI_RES: if(!mdm_check_result((u8*)"OK")) { MDM_STA = MDM_TX_ATCMVERSION_CMD; LOG("->:OK[%d]\r\n", iTimes); gCnt.fsmErrCnt = 0; } else if(!mdm_check_result((u8*)"ERROR")) { MDM_STA = MDM_TX_ATCMVERSION_CMD; LOG("->:ERROR[%d]\r\n", iTimes); gCnt.fsmErrCnt = 0; if(iTimes < 3) //190220 { MDM_STA = MDM_TX_ATQINDI_CMD; } else { iTimes = 0; MDM_STA = MDM_TX_ATCMVERSION_CMD; LOG("AT+QINDI=2,error 3 times!\r\n"); gCnt.fsmErrCnt++; } } else if(gtimer.mdmFSMTimerout > 400) { if(iTimes < 3) { MDM_STA = MDM_TX_ATQINDI_CMD; } else { iTimes = 0; MDM_STA = MDM_TX_ATCMVERSION_CMD; LOG("AT+QINDI=2,error 3 times!\r\n"); gCnt.fsmErrCnt++; } } break; #endif /*查版本*/ case MDM_TX_ATCMVERSION_CMD: LOG("*<-%d:AT+CMVERSION\r\n", MDM_TX_ATCMVERSION_CMD); memset(USART1_RX_BUF, 0, sizeof(USART1_RX_BUF)); mdm_send_cmd_noack((u8*)"AT+CMVERSION"); MDM_STA = MDM_WAIT_ATCMVERSION_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_ATCMVERSION_RES: if(!mdm_check_str((u8*)"M6313")) { char* p = strstr((const char*)USART1_RX_BUF, (const char*)"M6313"); /*USART1_RX_STA被mdm_check_str清0了*/ if(NULL != p)//格式:M6313-MBRH0S02-release-EXT-20181025 { char* p1 = NULL; p1 = strchr((const char*)USART1_RX_BUF, '-'); /*第一個'-'內容*/ if(NULL !=p1) { strncpy(mdmInfo.MDMSoftInfo, p1+1, 8); /*取"MBRH0S02"*/ } char* p2 = NULL; p2 = strrchr((const char*)USART1_RX_BUF, '-'); /*最後一個'-'內容*/ if((NULL!=p2) && (p2!=p1)) { strncpy(&mdmInfo.MDMSoftInfo[8], p2+3, 6);/*取"181025"*/ } mdmInfo.MDMSoftInfo[14] = '\0'; p1 = NULL; p2 = NULL; LOG("Copy...\r\n"); } else { LOG("Copy error!\r\n"); } p = NULL; MDM_STA = MDM_TX_ATQITKA_CMD; LOG("->:M6313...\r\n"); } else if(gtimer.mdmFSMTimerout > 200) { MDM_STA = MDM_TX_ATQITKA_CMD; LOG("Fault\r\n"); } break; /*TCP自動心跳 AT+QITKA=< keepalive >[,<keepidle>][,<keepinterval>][,< keepcount>]*/ //MDM_AUTO_TICK_EN case MDM_TX_ATQITKA_CMD: LOG("*<-%d:AT+QITKA=1,60,300,3\r\n", MDM_TX_ATQITKA_CMD); mdm_send_cmd_noack((u8*)"AT+QITKA=1,60,300,3"); MDM_STA = MDM_WAIT_ATQITKA_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_ATQITKA_RES: if(!mdm_check_str((u8*)"OK")) { MDM_STA = MDM_TX_ATQSCLK_CMD; LOG("->:OK\r\n"); } else if(gtimer.mdmFSMTimerout > 200) { MDM_STA = MDM_TX_ATQSCLK_CMD; LOG("Fault\r\n"); } break; /*設定慢時鐘*/ case MDM_TX_ATQSCLK_CMD: /*慢時鐘*/ LOG("\r\n*Step:%d,AT+QSCLK\r\n", MDM_TX_ATQSCLK_CMD); mdm_send_cmd_noack((u8*)"AT+QSCLK=1"); /*開啟慢時鐘*///修改 lyn 2018.10.6 MDM_STA = MDM_WAIT_ATQSCLK_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_ATQSCLK_RES: if(!mdm_check_str((u8*)"OK")) { MDM_STA = MDM_TX1_ATGSN_CMD; LOG("AT+QSCLK=1 ok\r\n"); } else if(gtimer.mdmFSMTimerout > 200) /*1s超時*/ { MDM_STA = MDM_TX1_ATGSN_CMD; LOG("AT+QSCLK=1 error\r\n"); } break; /*第1次讀取IMEI*/ case MDM_TX1_ATGSN_CMD: LOG("\r\n*Step:%d,read IMEI\r\n", MDM_TX1_ATGSN_CMD); mdm_send_cmd_noack((u8*)"AT+GSN"); /*讀取IMEI*/ MDM_STA = MDM_WAIT1_ATGSN_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT1_ATGSN_RES:/*讀取IMEI*/ if(!mdm_check_str((u8*)"OK")) /*查詢到OK*/ { Str2BCD(USART1_RX_BUF, (u8*)temp1IMEI); MDM_STA = MDM_TX2_ATGSN_CMD; /*第2次讀取IMEI*/ LOG("-1-get IMEI ok\r\n"); } else if(gtimer.mdmFSMTimerout > 400) /*2s超時*/ { MDM_STA = MDM_TX_ATCIMI_CMD; LOG("-1-get IMEI error\r\n"); } break; /*第2次讀取IMEI*/ case MDM_TX2_ATGSN_CMD: LOG("\r\n*Step:%d,read IMEI\r\n", MDM_TX2_ATGSN_CMD); mdm_send_cmd_noack((u8*)"AT+GSN"); /*讀取IMEI*/ MDM_STA = MDM_WAIT2_ATGSN_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT2_ATGSN_RES:/*讀取IMEI*/ if(!mdm_check_str((u8*)"OK")) /*查詢到OK*/ { Str2BCD(USART1_RX_BUF, (u8*)temp2IMEI); MDM_STA = MDM_TX_ATCIMI_CMD; LOG("-2-get IMEI ok\r\n"); if(memcmp(&temp1IMEI[0], &temp2IMEI[0], sizeof(temp2IMEI)) == 0) /*兩次結果相等*/ { LOG("read 2 times same IMEI\r\n"); LOG("IMEI1:\r\n"); printfHex(temp1IMEI,sizeof(temp1IMEI)); LOG("IMEI2:\r\n"); printfHex(temp2IMEI,sizeof(temp2IMEI)); if(memcmp(&deviceInfo.deviceIMEI[0], &temp2IMEI[0], sizeof(temp2IMEI)) != 0)/*和舊IMEI比較*/ { memcpy(&deviceInfo.deviceIMEI[0], &temp2IMEI[0], sizeof(temp2IMEI)); writeFlash(); //儲存引數 LOG("updata IMEI ok\r\n"); } else { LOG("old IMEI ok\r\n"); } memset(temp1IMEI, 0x00, sizeof(temp1IMEI)); memset(temp2IMEI, 0x00, sizeof(temp2IMEI)); } else { LOG("read 2 times different IMEI\r\n"); } } else if(gtimer.mdmFSMTimerout > 400) /*2s超時*/ { MDM_STA = MDM_TX_ATCIMI_CMD; LOG("-2-get IMEI error\r\n"); } break; /*讀取IMSI*/ case MDM_TX_ATCIMI_CMD: /*讀取IMSI*/ LOG("\r\n*Step:%d,read IMSI\r\n", MDM_TX_ATCIMI_CMD); mdm_send_cmd_noack((u8*)"AT+CIMI"); MDM_STA = MDM_WAIT_ATCIMI_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_ATCIMI_RES: if(!mdm_check_str((u8*)"OK")) /*查詢到OK*/ { char tmpIMSI[8]; Str2BCD(USART1_RX_BUF, (u8*)tmpIMSI); /*TBoxInfoType.deviceInfo.deviceIMSI*/ MDM_STA = MDM_GPRS_INTI; LOG("get IMSI:\r\n"); printfHex(tmpIMSI,sizeof(tmpIMSI)); if(memcmp(&TBoxInfoType.deviceInfo.deviceIMSI[0], &tmpIMSI[0], sizeof(tmpIMSI)) != 0)/*和舊資料比較*/ { memcpy(&TBoxInfoType.deviceInfo.deviceIMSI[0], &tmpIMSI[0], sizeof(tmpIMSI)); writeFlash(); //儲存引數 LOG("updata IMSI ok\r\n"); } else { LOG("old IMSI ok\r\n"); } memset(tmpIMSI, 0x00, sizeof(tmpIMSI)); } else if(gtimer.mdmFSMTimerout > 400) /*2s超時*/ { MDM_STA = MDM_GPRS_INTI; LOG("get IMSI error\r\n"); } break; /*GPRS配置*/ case MDM_GPRS_INTI: LOG("\r\n*Step:%d,MDM_GPRS_INTI\r\n", MDM_GPRS_INTI); MDM_STA = MDM_TX_ATE_CMD; break; case MDM_TX_ATE_CMD:/*開關回顯*/ LOG("\r\n*Step:%d,%s\r\n", MDM_TX_ATE_CMD, ATEx); mdm_send_cmd_noack((u8*)ATEx); /*開關回顯*/ MDM_STA = MDM_WAIT_ATE_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_ATE_RES: if(!mdm_check_str((u8*)"OK")) { MDM_STA = MDM_TX_ATCPIN_CMD; LOG("%s ok\r\n", ATEx); } else if(gtimer.mdmFSMTimerout > 200) /*1s超時*/ { MDM_STA = MDM_TX_ATCPIN_CMD; LOG("ATEx error\r\n"); } break; case MDM_TX_ATCPIN_CMD: /*非阻塞式,最大等待時長5s*/ LOG("\r\n*Step:%d,AT+CPIN?\r\n", MDM_TX_ATCPIN_CMD); mdm_send_cmd_noack((u8*)"AT+CPIN?"); MDM_STA = MDM_WAIT_ATCPIN_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_ATCPIN_RES: if(!mdm_check_str((u8*)"READY")) /*查詢*/ { MDM_STA = MDM_TX_ATCCID_CMD; LOG("AT+CPIN? ok\r\n"); } else if(gtimer.mdmFSMTimerout > WAIT_ATCPIN_MAX_TIME) /*超時,最大5s*/ { MDM_STA = MDM_TX_ATCCID_CMD; /*next*/ gCnt.mdmTotalErr++; SIM_Handler();/*SIM卡故障*/ LOG("AT+CPIN? error\r\n"); } break; case MDM_TX_ATCCID_CMD: /*查詢SIM卡CCID*/ LOG("\r\n*Step:%d,read CCID\r\n", MDM_TX_ATCCID_CMD); mdm_send_cmd_noack((u8*)"AT+CCID"); MDM_STA = MDM_WAIT_ATCCID_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_ATCCID_RES: if(!mdm_check_str((u8*)"+CCID:")) /*查詢*/ { char* tempCCID = NULL; u8 ccidSize = 21; tempCCID = (char*)malloc(sizeof(char)*ccidSize); memset(tempCCID, 0x00, ccidSize); memcpy(tempCCID, &USART1_RX_BUF[10], ccidSize);//儲存CCID tempCCID[20] = '\0'; /*新增結束符*/ LOG("tmpCCID:%s\r\n", tempCCID); if(strstr((const char*)tempCCID, (const char*)"OK")== NULL) //無OK { if(strstr((const char*)tempCCID, (const char*)"\r\n")== NULL) //無回車換行 { memcpy(m6313Debug.ccid, tempCCID, ccidSize);//更新CCID m6313Debug.ccid[20] = '\0'; /*新增結束符*/ LOG("newCCID:%s\r\n", m6313Debug.ccid); } else { LOG("error\"OK\","); LOG("old CCID:%s\r\n", m6313Debug.ccid); } } else { LOG("error\"0x0A,0x0D\"\r\n"); LOG("old CCID:%s\r\n", m6313Debug.ccid); } free(tempCCID); MDM_STA = MDM_TX_ATCREG_CMD; } else if(gtimer.mdmFSMTimerout > WAIT_ATCCID_MAX_TIME) /*超時,5s*/ { MDM_STA = MDM_TX_ATCREG_CMD; LOG("CCID get timeout! "); LOG("old CCID:%s\r\n", m6313Debug.ccid); } break; case MDM_TX_ATCREG_CMD: /*查詢2G網路是否註冊*/ LOG("\r\n*Step:%d,AT+CREG?\r\n", MDM_TX_ATCREG_CMD); mdm_send_cmd_noack((u8*)"AT+CREG?"); MDM_STA = MDM_WAIT_ATCREG_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_ATCREG_RES: if(!mdm_check_str((u8*)",1")) /*查詢,已註冊*/ { MDM_STA = MDM_TX_ATCSQ_CMD; LOG("AT+CREG? ok:1\r\n"); } else if(!mdm_check_str((u8*)",5")) /*查詢,漫遊*/ { MDM_STA = MDM_TX_ATCSQ_CMD; LOG("AT+CREG? ok:5\r\n"); } else if(gtimer.mdmFSMTimerout > WAIT_ATCREG_MAX_TIME) /*超時,3s*/ { USART1_RX_STA=0; MDM_STA = MDM_TX_ATCSQ_CMD; /*進入下一步*/ LOG("AT+CREG? error\r\n"); } break; case MDM_TX_ATCSQ_CMD: /*查詢當前訊號質量*/ LOG("\r\n*Step:%d,AT+CSQ\r\n", MDM_TX_ATCSQ_CMD); mdm_send_cmd_noack((u8*)"AT+CSQ"); MDM_STA = MDM_WAIT_ATCSQ_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_ATCSQ_RES: if(!mdm_check_str((u8*)"OK")) /*查詢*/ { u8 len; mdmInfo.signalIntensity = NMEA_Str2num(&USART1_RX_BUF[8],&len); /*得到MDM的CSQ*/ MDM_STA = MDM_TX_ATQICLOSE_CMD; LOG("MDM_CSQ=%d\r\n", mdmInfo.signalIntensity); } else if(gtimer.mdmFSMTimerout > 200) /*1s超時*/ { MDM_STA = MDM_TX_ATQICLOSE_CMD; LOG("get CSQ error.\r\n"); } break; /*AT+QICLOSE關閉TCPUDP連線*/ case MDM_TX_ATQICLOSE_CMD: /*關閉PDP使用場景*/ LOG("\r\n*Step:%d,AT+QICLOSE\r\n", MDM_TX_ATQICLOSE_CMD); mdm_send_cmd_noack((u8*)"AT+QICLOSE"); MDM_STA = MDM_WAIT_ATQICLOSE_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_ATQICLOSE_RES: if(!mdm_check_str((u8*)"ERROR")) /*關閉連線失敗*/ { MDM_STA = MDM_TX_ATQIDEACT_CMD; /*NEXT關閉PDP*/ LOG("AT+QICLOSE ok:\"ERROR\"\r\n"); } else if(!mdm_check_str((u8*)"CLOSE OK")) /*關閉連線成功*/ { MDM_STA = MDM_TX_ATQIDEACT_CMD; /*NEXT關閉PDP*/ LOG("AT+QICLOSE ok:\"CLOSE OK\"\r\n"); } else if(gtimer.mdmFSMTimerout > WAIT_ATQICLOSE_MAX_TIME) /*超時,最大2s*/ { MDM_STA = MDM_TX_ATQIDEACT_CMD; /*NEXT關閉PDP*/ LOG("AT+QICLOSE error\r\n"); } break; /*AT+QIDEACT關閉PDP使用場景*/ case MDM_TX_ATQIDEACT_CMD: LOG("\r\n*Step:%d,AT+QIDEACT\r\n", MDM_TX_ATQIDEACT_CMD); mdm_send_cmd_noack((u8*)"AT+QIDEACT"); MDM_STA = MDM_WAIT_ATQIDEACT_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_ATQIDEACT_RES: if(!mdm_check_str((u8*)"ERROR")) /*查詢*/ { MDM_STA = MDM_TX_ATQIREGAPP_CMD; LOG("AT+QIDEACT ok:\"ERROR\"\r\n"); } else if(!mdm_check_str((u8*)"DEACT OK")) /*查詢*/ { MDM_STA = MDM_TX_ATQIREGAPP_CMD; LOG("AT+QIDEACT ok:\"DEACT OK\"\r\n"); } else if(gtimer.mdmFSMTimerout > WAIT_ATQIDEACT_MAX_TIME) /*超時,最大45s*/ { MDM_STA = MDM_TX_ATQIREGAPP_CMD; LOG("AT+QIDEACT error\r\n"); } break; case MDM_TX_ATQIREGAPP_CMD: /*設定GPRS的APN(配置為 SIM卡簽約對應的APN)*/ LOG("\r\n*Step:%d,AT+QIREGAPP\r\n", MDM_TX_ATQIREGAPP_CMD); mdm_send_cmd_noack((u8*)"AT+QIREGAPP=\"CMNET\""); MDM_STA = MDM_WAIT_ATQIREGAPP_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_ATQIREGAPP_RES: if(!mdm_check_str((u8*)"OK")) /*查詢*/ { MDM_STA = MDM_START_ATQIACT_CMD; LOG("AT+QIREGAPP ok\r\n"); } else if(gtimer.mdmFSMTimerout > WAIT_ATQIREGAPP_MAX_TIME) /*超時,3s*/ { MDM_STA = MDM_START_ATQIACT_CMD; /*NEXT*/ LOG("AT+QIREGAPP error\r\n"); } break; case MDM_START_ATQIACT_CMD: /*開始啟用PDP*/ LOG("\r\n*Step:%d,MDM_START_ATQIACT_CMD\r\n", MDM_START_ATQIACT_CMD); iTimes = 0; MDM_STA = MDM_TX_ATQIACT_CMD; break; case MDM_TX_ATQIACT_CMD: /*啟用PDP,GPRS網路*/ LOG("\r\n*step:%d,AT+QIACT\r\n", MDM_TX_ATQIACT_CMD); mdm_send_cmd_noack((u8*)"AT+QIACT"); iTimes++; LOG("AT+QIACT,count-%d-!\r\n", iTimes); gtimer.mdmFSMTimerout = 0; MDM_STA = MDM_WAIT_ATQIACT_RES; break; case MDM_WAIT_ATQIACT_RES: if(!mdm_check_str((u8*)"OK")) /*查詢到OK*/ { MDM_STA = MDM_START_TCP_SETUP; LOG("AT+QIACT-OK[%d]\r\n", iTimes); } else if(gtimer.mdmFSMTimerout > WAIT_ATQIACT_MAX_TIME) /*10秒超時*/ { if(iTimes < EXE_ATQIACT_TIMES) { MDM_STA = MDM_TX_ATQIACT_CMD; /*繼續啟用PDP*/ LOG(".AT+QIACT,Continue-%d-!\r\n", iTimes); } else /*iTimes超過次數*/ { iTimes = 0; MDM_STA = MDM_START_TCP_SETUP; /*NEXT*/ LOG("AT+QIACT,%d times PDP active error\r\n", EXE_ATQIACT_TIMES); } } break; /*建立TCP連線*/ case MDM_START_TCP_SETUP: LOG("\r\n*Step:%d,MDM_START_TCP_SETUP\r\n", MDM_START_TCP_SETUP); MDM_STA = MDM_TX_ATQIMUX_CMD; break; case MDM_TX_ATQIMUX_CMD: /*配置單路連線*/ LOG("\r\n*Step:%d,AT+QIMUX\r\n", MDM_TX_ATQIMUX_CMD); mdm_send_cmd_noack((u8*)"AT+QIMUX=0"); MDM_STA = MDM_WAIT_ATQIMUX_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_ATQIMUX_RES: if(!mdm_check_str((u8*)"OK")) /*查詢*/ { MDM_STA = MDM_TX_ATQIMODE_CMD; LOG("AT+QIMUX ok\r\n"); } else if(gtimer.mdmFSMTimerout > 200) /*超時,1s*/ { MDM_STA = MDM_TX_ATQIMODE_CMD; /*NEXT*/ LOG("AT+QIMUX error\r\n"); } break; case MDM_TX_ATQIMODE_CMD: /*配置非透傳模式*/ LOG("\r\n*Step:%d,AT+QIMODE\r\n", MDM_TX_ATQIMODE_CMD); mdm_send_cmd_noack((u8*)"AT+QIMODE=0"); /*非透傳*/ MDM_STA = MDM_WAIT_ATQIMODE_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_ATQIMODE_RES: if(!mdm_check_str((u8*)"OK")) /*查詢*/ { MDM_STA = MDM_TX_ATQIDNSIP_CMD; LOG("AT+QIMODE ok\r\n"); } else if(gtimer.mdmFSMTimerout > 200) /*超時,1s*/ { MDM_STA = MDM_TX_ATQIDNSIP_CMD; /*NEXT*/ LOG("AT+QIMODE error\r\n"); } break; case MDM_TX_ATQIDNSIP_CMD: /*使用域名訪問*/ LOG("\r\n*Step:%d,AT+QIDNSIP\r\n", MDM_TX_ATQIDNSIP_CMD); mdm_send_cmd_noack((u8*)"AT+QIDNSIP=1"); /*非透傳*/ MDM_STA = MDM_WAIT_ATQIDNSIP_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_ATQIDNSIP_RES: if(!mdm_check_str((u8*)"OK")) /*查詢*/ { MDM_STA = MDM_START_ATQIOPEN_CMD; /*NEXT*/ LOG("AT+QIDNSIP ok\r\n"); } else if(gtimer.mdmFSMTimerout > 400) /*超時2s*/ { MDM_STA = MDM_START_ATQIOPEN_CMD; /*NEXT*/ LOG("AT+QIDNSIP error\r\n"); } break; case MDM_START_ATQIOPEN_CMD: /*開始TCP連線*/ LOG("\r\n*Step:%d,MDM_START_ATQIOPEN_CMD\r\n", MDM_START_ATQIOPEN_CMD); iTimes = 0; MDM_STA = MDM_TX_ATQIOPEN_CMD; break; case MDM_TX_ATQIOPEN_CMD: LOG("\r\n*Step:%d,AT+QIOPEN\r\n", MDM_TX_ATQIOPEN_CMD); if(devParam.secondTcp.addr[0] !=0)/*聯網IP選擇*/ { TCP_Conncect(devParam.secondTcp.addr,devParam.secondTcp.port); } else{ TCP_Conncect(IPaddr,IPport);} iTimes++; LOG("send\"AT+QIOPEN\",count-%d-\r\n", iTimes); MDM_STA = MDM_WAIT_ATQIOPEN_RES; gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_ATQIOPEN_RES: if(!mdm_check_str((u8*)"CONNECT OK")) /*查詢CONNECT*/ { MDM_STA = MDM_WAIT_TCPSEND_CMD; /*TCP建立成功,進入空閒狀態*/ LOG(".get\"CONNECT OK\"\r\n"); } else if(!mdm_check_str((u8*)"ALREAY CONNECT")) { MDM_STA = MDM_WAIT_TCPSEND_CMD; /*TCP建立成功,進入空閒狀態*/ LOG(".get\"ALREAY CONNECT\"\r\n"); } else if(gtimer.mdmFSMTimerout > WAIT_ATQIOPEN_MAX_TIME) /*超時,30s*/ { LOG("count-%d-,MDM_FSM timeout!\r\n", iTimes); if(iTimes < EXE_ATQIOPEN_TIMES) { MDM_STA = MDM_TX_ATQIOPEN_CMD; /*繼續建立TCP*/ LOG(".continue AT+QIOPEN!\r\n"); } else /*iTimes超過次數*/ { iTimes = 0; MDM_STA = MDM_IDLE_STA; /*中斷*/ STOP_MDM_FSM(); /*MDM_FSM結束*/ cntMdm = 0; /*MDM連網失敗*/ gCnt.mdmTotalErr++; //MDM錯誤統計 LOG("AT+QIOPEN:%d times exe error,TCP connect fail!\r\n",EXE_ATQIOPEN_TIMES); } } break; /*進行延時傳送任務*/ case MDM_WAIT_TCPSEND_CMD: MDM_STA = MDM_WAIT_TCPSEND_RES; /*TCP建立成功,進入等待發送任務*/ LOG("MDM_FSM:TCP connect suc!\r\n"); gtimer.mdmFSMTimerout = 0; break; case MDM_WAIT_TCPSEND_RES: if(gtimer.mdmFSMTimerout > 400) /*等待兩秒*/ { MDM_STA = MDM_IDLE_STA; /*TCP建立成功,進入空閒狀態*/ MDM_NET_CONNECT_OK_HANDLE(); STOP_MDM_FSM(); /*MDM_FSM結束*/ } break; default: break; } }
這就是我分享的2G網路模組聯網的過程哈,裡面程式碼是實踐過的,如果大家有什麼更好的思路,歡迎分享交流哈。
更多分享,掃碼關注我