使用SIMCOM公司通信模塊將底層的通信與應用完全進行了分離,便於移植。
SIMCOM.h //定義了相關的結構體與類型。
SIMCOM_AT.c//定義了底層的AT接口
SIMCOM_GSM.c//需要的模塊GSM相關命令
SIMCOM_GPRS.c//上網相關-未移植
SIMCOM_SMS.c//短信收發相關-未移植
SIMCOM_USER.c//用戶最終接口
//需要自己實現數據收發相關接口,DCD,DTR,PWRKEY,STATUS相關IO接口,需要一個ms延時支持
//SIMCOM.h
/************************************************************************************************************* * 文件名: SIMCOM.h * 功能: SIMCOM 底層定義 * 作者: cp1300@139.com * 創建時間: 2015-02-15 * 最后修改時間: 2018-03-23 * 詳細: 注意:底層通信接口使用的是回調函數,但是必須提供系統延時函數 void SYS_DelayMS(u32 ms); *************************************************************************************************************/ #ifndef _SIMCOM_H_ #define _SIMCOM_H_ #include "system.h" //SIMCOM通信模塊定義 typedef enum { SIMCOM_SIM900 = 0 , //默認為SIM900 SIMCOM_SIM800 = 1 , //SIM800 SIMCOM_SIM2000 = 2 , //SIM2000 SIMCOM_SIM7600 = 3 , //SIM7600 SIMCOM_SIM868 = 4 , //SIM868 SIMCOM_SIM7000C = 5 , //SIM7000C LYNQ_L700 = 10 , //LYNQ_L700 SIMCOM_INVALID = 0XFF , //無效則默認 }SIMCOM_MODE_TYPE; //網絡注冊狀態 typedef enum { SIMCOM_NET_NOT = 0, //未注冊 SIMCOM_NET_YES = 1, //已經注冊 SIMCOM_NET_SEA = 2, //未注冊,正在搜索 SIMCOM_NET_TUR = 3, //注冊被拒絕 SIMCOM_NET_UNK = 4, //未知 SIMCOM_NET_ROA = 5, //已經注冊,但是漫游 SIMCOM_NET_ERROR=0XFF //錯誤 }SIMCOM_NETSTATUS; //SIMCOM網絡制式 typedef enum { SIMCOM_NETMODE_NOT = 0, //未注冊 SIMCOM_NETMODE_GSM = 1, //GSM SIMCOM_NETMODE_GPRS = 2, //GPRS SIMCOM_NETMODE_EGPRS = 3, //EGPRS (EDGE) SIMCOM_NETMODE_WCDMA = 4, //WCDMA SIMCOM_NETMODE_HSDPA = 5, //HSDPA only(WCDMA) SIMCOM_NETMODE_HSUPA = 6, //HSUPA only(WCDMA) SIMCOM_NETMODE_HSPA = 7, //HSPA (HSDPA and HSUPA, WCDMA) SIMCOM_NETMODE_LTE = 8, //LTE SIMCOM_NETMODE_TDS_CDMA = 9, //TDS-CDMA SIMCOM_NETMODE_TDS_HSDPA = 10, //TDS-HSDPA only(SIM7000C 電信NB也是這個) SIMCOM_NETMODE_TDS_HSUPA = 11, //TDS-HSUPA only SIMCOM_NETMODE_TDS_HSPA = 12, //TDS- HSPA (HSDPA and HSUPA) SIMCOM_NETMODE_CDMA = 13, //CDMA SIMCOM_NETMODE_EVDO = 14, //EVDO SIMCOM_NETMODE_HYBRID = 15, //HYBRID (CDMA and EVDO) SIMCOM_NETMODE_1XLTE = 16, //1XLTE(CDMA and LTE) SIMCOM_NETMODE_NULL = 0xff, //未知 }SIMCOM_NETMODE_TYPE; //SIM卡就緒狀態 typedef enum { SIM_READY = 0, //SIM卡就緒 SIM_NOT_READY = 1, //SIM卡未就緒 SIM_UNKNOWN = 2 //SIM卡狀態未知 }SIM_CARD_STATUS; //控制IO電平定義 #define SIMCOM_H_LEVEL 1 //高電平 #define SIMCOM_L_LEVEL 0 //低電平 //DCD狀態定義 #define DCD_DATA_MODE 0 //數據透傳模式 #define DCD_AT_MODE 1 //AT指令模式 //相關信息長度限制 #define SIMCOM_INFO_SIZE 24 //信息長度 #define SIMCOM_VER_SIZE 24 //軟件版本長度定義 //重試次數,防止AT指令操作失敗 #define SIMCOM_DEFAULT_RETRY 2 //SIMCOM模塊相關信息 typedef struct { char Manu[SIMCOM_INFO_SIZE+1]; //制造商 char Model[SIMCOM_INFO_SIZE+1]; //型號 char Ver[SIMCOM_VER_SIZE+1]; //軟件版本 char IMEI[SIMCOM_INFO_SIZE+1]; //序列號 }SIMCOM_INFO; //NBIOT模式定義 typedef enum { NB_IOT_MODE = 0, //NBIOT模式 CAT_M_MODE = 1, //CAT-M模式 }NBIOT_MODE_TYPE; //網絡模式設置 typedef struct { SIMCOM_MODE_TYPE ModeType; //模塊型號 NBIOT_MODE_TYPE NB_Mode; //NB模式 s8 NB_EnableMode; //NB模式使能模式,-1:無需設置;0:關閉NB,使能GSM模式;1:使能NB模式 bool isNB_ScarEnable; //NB模式擾碼使能 }NETWORK_CONFIG_TYPE; //SIMCOM通信模塊句柄 typedef struct { //所需變量 SIMCOM_MODE_TYPE SimcomModeType; //模塊型號 char TelecomCarr[SIMCOM_INFO_SIZE+1]; //運營商名稱 SIMCOM_INFO SIMCOM_Info; //SIMCOM通信模塊相關信息結構體 NETWORK_CONFIG_TYPE NetworkConfig; //網絡模式設置 SIMCOM_NETMODE_TYPE NetworkMode; //當前網絡制式 u8 Singal; //網絡信號強度 char LocalPhoneNumber[16]; //本機電話號碼 char ServiceCenterPhoneNumber[16]; //短信中心電話號碼 char SIM_CIMI[16]; //SIM卡唯一CIMI號碼 //底層通信接口 bool (* pSendData)(u8 *pDataBuff, u16 DataLen); //發送數據接口,如果發送失敗,返回FALSE,成功返回TRUE; int (* pReadData)(u8 **pDataBuff, u8 ByteTimeOutMs, u16 TimeOutMs, u16 *pReceiveDelay); //接收數據接口,返回數據長度,如果失敗返回<=0,成功,返回數據長度 void (*pClearRxData)(void); //清除接收緩沖區函數,用於清除接收數據緩沖區數據 void (*pSetDTR_Pin)(u8 Level); //DTR引腳電平控制-用於控制sleep模式或者退出透傳模式 void (*pSetPWRKEY_Pin)(u8 Level); //PWRKEY開機引腳電平控制-用於開機 u8 (*pGetSTATUS_Pin)(void); //獲取STATUS引腳電平-用於指示模塊上電狀態 u8 (*pGetDCD_Pin)(void); //獲取DCD引腳電平-高電平AT指令模式,低電平為透傳模式 //系統接口 void (*pDelayMS)(u32 ms); //系統延時函數 void (*pIWDG_Feed)(void); //清除系統看門狗(可以為空) //內部狀態定義 bool s_isInitStatus; //用於記錄模塊初始化狀態,復位或上電后變為無效 }SIMCOM_HANDLE; #endif /*_SIMCOM_H_*/
//SIMCOM_AT.c
/************************************************************************************************************* * 文件名: SIMCOM_AT.c * 功能: SIMCOM底層AT指令接口 * 作者: cp1300@139.com * 創建時間: 2015-02-15 * 最后修改時間: 2018-03-23 * 詳細: *************************************************************************************************************/ #include "system.h" #include "usart.h" #include "SIMCOM_AT.h" #include "SIMCOM.h" #include "string.h" #include "ucos_ii.h" bool g_SIMC0M_AT_Debug = TRUE; //底層AT指令調試狀態 //調試開關 #define SIMCOM_DBUG 1 #if SIMCOM_DBUG #include "system.h" #define SIMCOM_debug(format,...) {if(g_SIMC0M_AT_Debug){uart_printf(format,##__VA_ARGS__);}} #else #define SIMCOM_debug(format,...) /\ / #endif //SIMCOM_DBUG /************************************************************************************************************************* * 函數 : bool SIMCOM_SendAT(SIMCOM_HANDLE *pHandle, char *pStr) * 功能 : 發送一個AT指令(會添加結束符\r\n),不會等待響應 * 參數 : pHandle:SIMCOM句柄;pStr:指令字符串 * 返回 : 接口發送狀態 * 依賴 : 無 * 作者 : cp1300@139.com * 時間 : 2018-03-23 * 最后修改時間 : 2018-03-23 * 說明 : 用於底層AT指令發送 *************************************************************************************************************************/ bool SIMCOM_SendAT(SIMCOM_HANDLE *pHandle, char *pStr) { pHandle->pSendData((u8 *)pStr, strlen(pStr)); //發送指令 return pHandle->pSendData((u8 *)"\r\n", 2); //發送結束符 } /************************************************************************************************************************* * 函數 : bool SIMCOM_TestAT(SIMCOM_HANDLE *pHandle, u32 retry) * 功能 : SIMCOM AT 命令通信測試 * 參數 : pHandle:SIMCOM句柄;retry:重試次數 * 返回 : FALSE:通信失敗;TRUE:通信成功 * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2013-10-20 * 最后修改時間 : 2018-03-23 * 說明 : 每隔100ms向SIMCOM通信模塊發送一個"AT",等待響應返回 *************************************************************************************************************************/ bool SIMCOM_TestAT(SIMCOM_HANDLE *pHandle, u32 retry) { u32 cnt; u8 *pRxBuff; //檢測模塊存在 do { SIMCOM_SendAT(pHandle, "AT"); //發送"AT",同步波特率,並且等待應答 pHandle->pClearRxData(); //清除計數器 if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pRxBuff, &cnt, "OK", 10, 150)) //等待響應,超時150ms { pHandle->pDelayMS(100); return TRUE; } retry --; }while(retry); pHandle->pDelayMS(100); return FALSE; } /************************************************************************************************************************* * 函數 : bool SIMCOM_WaitSleep(SIMCOM_HANDLE *pHandle, u32 TimeOutMs) * 功能 : 等待模塊空閑,並重新喚醒 * 參數 : pHandle:句柄;TimeOut:等待超時,時間單位ms * 返回 : TRUE:成功;FALSE:超時 * 依賴 : 無 * 作者 : cp1300@139.com * 時間 : 2013-10-25 * 最后修改時間 : 2018-03-24 * 說明 : 用於等待操作完成,防止快速操作造成模塊不響應 *************************************************************************************************************************/ bool SIMCOM_WaitSleep(SIMCOM_HANDLE *pHandle, u32 TimeOutMs) { u32 i; u32 cnt; u8 *pData; if(TimeOutMs < 100) TimeOutMs = 100; //最少100ms pHandle->pSetDTR_Pin(SIMCOM_H_LEVEL); //等待模塊空閑后進入SLEEP模式 //循環發送命令,直到命令超時了則認為進入了sleep模式 for(i = 0;i < (TimeOutMs/100);i ++) { pHandle->pDelayMS(100); //延時100ms SIMCOM_SendAT(pHandle, "AT"); //發送"AT",同步波特率,並且等待應答 pHandle->pClearRxData(); //清除接收計數器 if(AT_RETURN_TIME_OUT == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, 100)) //等待響應,超時100ms { break; } } pHandle->pSetDTR_Pin(SIMCOM_L_LEVEL); //喚醒 if(i == (TimeOutMs/100)) { SIMCOM_debug("模塊進入空閑模式失敗!\r\n"); pHandle->pClearRxData(); //清除接收計數器 return FALSE; } pHandle->pDelayMS(100); //延時100ms SIMCOM_debug("模塊進入空閑模式成功!\r\n"); SIMCOM_TestAT(pHandle, 10); pHandle->pClearRxData(); //清除接收計數器 return TRUE; } /************************************************************************************************************************* * 函數 : SIMCOM_AT_ERROR SIMCOM_GetATResp(SIMCOM_HANDLE *pHandle, u8 **pRxBuff, u32 *pLen, const char *pKeyword, u8 ByteTimeOutMs, u16 TimeOutMs) * 功能 : 獲取SIMCOM的AT指令響應 * 參數 : pHandle:句柄 pRxBuff:接收緩沖區指針(輸出);pLen:接收到的數據大小(輸出), pKeyword:關鍵字,為字符串,比如"OK",如果在接收到的字符串中有OK字符,就返回成功,否則失敗(輸入) ByteTimeOutMs:字節超時時間,單位ms最大255ms TimeOutMs:等待超時時間,單位毫秒 * 返回 : SIM900_ERROR * 依賴 : 無 * 作者 : cp1300@139.com * 時間 : 2018-03-24 * 最后修改時間 : 2018-03-24 * 說明 : 本函數會在接收緩沖區字符串結束添加'\0' 本函數不能清除緩沖區 *************************************************************************************************************************/ SIMCOM_AT_ERROR SIMCOM_GetATResp(SIMCOM_HANDLE *pHandle, u8 **pRxBuff, u32 *pLen, const char *pKeyword, u8 ByteTimeOutMs, u16 TimeOutMs) { int len; u16 ReceiveDelay; if(ByteTimeOutMs < 1) ByteTimeOutMs = 1; len = pHandle->pReadData(pRxBuff, ByteTimeOutMs, TimeOutMs, &ReceiveDelay); //調用回調接口,讀取數據 //等待超時 if(len == 0) { return AT_RETURN_TIME_OUT; //返回超時錯誤 } //數據接收完畢 *pLen = len; //返回接收數據長度 if((*pRxBuff)[len-1] != 0) { (*pRxBuff)[len] = '\0'; //將數據結尾添加結束字符串 } SIMCOM_debug("\r\nSIMCOM(%dB)->%s\r\n",len, *pRxBuff); //打印返回信息 if(strstr((const char*)(*pRxBuff), pKeyword) != NULL) //搜索關鍵字 { SIMCOM_debug("%s 返回成功!\r\n",pKeyword); return AT_RETURN_OK; } else if(strstr((const char*)(*pRxBuff), "ERROR") != NULL) { SIMCOM_debug("%s 返回錯誤!\r\n",pKeyword); return AT_RETURN_ERROR; } else { SIMCOM_debug("%s 返回未知!\r\n",pKeyword); return AT_RETURN_UNKNOWN; } } /************************************************************************************************************************* * 函數 : bool SIM900_SetParametersReturnBool(char *pATCom, u8 retry, u16 TimeOutx10MS, const char *pErrorDebug) * 功能 : 設置SIM900一個參數,返回一個bool狀態 * 參數 : pATCom:AT命令;retry:重試次數;TimeOut:命令超時時間,單位10ms;pErrorDebug:失敗后提示的調試信息 * 返回 : TRUE:執行成功了,返回了OK,FALSE:執行失敗了,返回了ERROR或其它 * 依賴 : SIM900 * 作者 : cp1300@139.com * 時間 : 2014-12-19 * 最后修改時間 : 2014-12-19 * 說明 : 用於簡化命名發送,防止代碼重復 *************************************************************************************************************************/ bool SIMCOM_SetParametersReturnBool(SIMCOM_HANDLE *pHandle, char *pATCom, u8 retry, u16 TimeOutMs, const char *pErrorDebug) { u32 cnt; u8 *pData; retry += 1; //重試次數 do { SIMCOM_SendAT(pHandle,pATCom); //發送AT命令 pHandle->pClearRxData(); //清除接收計數器 if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, TimeOutMs)) //等待響應,超時10s { pHandle->pClearRxData(); //清除接收計數器 return TRUE; } SIMCOM_Ready(pHandle); //等待就緒 retry --; }while(retry); if(pErrorDebug!=NULL) { uart_printf("%s",pErrorDebug); //輸出調試信息 } pHandle->pClearRxData(); //清除接收計數器 return FALSE; } /************************************************************************************************************************* *函數 : u32 GSM_StringToHex(char *pStr, u8 NumDigits) *功能 : 將16進制樣式字符串轉換為16進制整型數(必須保證字符串字母都是大寫) *參數 : pStr:字符串起始指針 * NumDigits:數字位數,16進制數字位數 *返回 : 轉換后的數字 *依賴 : 無 *作者 : cp1300@139.com *時間 : 2013-04-30 *最后修改時間 : 2013-10-17 *說明 : 比如字符串"A865"轉換后為0xA865,位數為4位 必須保證字符串字母都是大寫 *************************************************************************************************************************/ u32 GSM_StringToHex(char *pStr, u8 NumDigits) { u8 temp; u32 HEX = 0; u8 i; NumDigits = (NumDigits > 8) ? 8 : NumDigits; //最大支持8位16進制數 for(i = 0;i < NumDigits;i ++) { HEX <<= 4; temp = pStr[i]; temp = (temp > '9') ? temp - 'A' + 10 : temp - '0'; HEX |= temp; } return HEX; } /************************************************************************************************************************* *函數 : void GSM_HexToString(u32 HexNum,c har *pStr, u8 NumDigits) *功能 : 將整型數字轉換為16進制樣式字符串(字母為大寫,不帶結束符) *參數 : HexNum:16進制數字 pStr:字符緩沖區指針 * NumDigits:數字位數,16進制數字位數 *返回 : 無 *依賴 : 無 *作者 : cp1300@139.com *時間 : 2013-04-30 *最后修改時間 : 2013-04-30 *說明 : 比如字符串0xA865轉換后為"A865",位數為4位 *************************************************************************************************************************/ void GSM_HexToString(u32 HexNum,char *pStr, u8 NumDigits) { u8 temp; u8 i; NumDigits = (NumDigits > 8) ? 8 : NumDigits; //最大支持8位16進制數 for(i = 0;i < NumDigits;i ++) { temp = 0x0f & (HexNum >> (4 * (NumDigits - 1 - i))); temp = (temp > 0x09) ? (temp - 0x0A + 'A') : (temp + '0'); pStr[i] = temp; } } /************************************************************************************************************************* *函數 : u32 GSM_StringToDec(char *pStr, u8 NumDigits) *功能 : 將10進制樣式字符串轉換為整型數(必須保證完全為數字字符) *參數 : pStr:字符串起始指針 * NumDigits:數字位數,10進制數字位數 *返回 : 轉換后的數字 *依賴 : 無 *作者 : cp1300@139.com *時間 : 2013-04-30 *最后修改時間 : 2013-04-30 *說明 : 比如字符串"1865"轉換后為1865,位數為4位 必須保證完全為數字字符 *************************************************************************************************************************/ u32 GSM_StringToDec(char *pStr, u8 NumDigits) { u32 temp; u32 DEC = 0; u8 i; u8 j; NumDigits = (NumDigits > 10) ? 10 : NumDigits; //最大支持10位10進制數 for(i = 0;i < NumDigits;i ++) { temp = pStr[i] - '0'; if(temp > 9) //只能是數字范圍 return 0; for(j = 1;j < (NumDigits - i);j ++) { temp *= 10; } DEC += temp; } return DEC; }
//SIMCOM_AT.h
/************************************************************************************************************* * 文件名: SIMCOM_AT.h * 功能: SIMCOM底層AT指令接口 * 作者: cp1300@139.com * 創建時間: 2015-02-15 * 最后修改時間: 2018-03-23 * 詳細: *************************************************************************************************************/ #ifndef _SIMCOM_AT_H_ #define _SIMCOM_AT_H_ #include "system.h" #include "SIMCOM.h" extern bool g_SIMC0M_AT_Debug; //底層AT指令調試狀態 //SIM900返回錯誤 typedef enum { AT_RETURN_OK = 0, //返回成功 AT_RETURN_ERROR = 1, //返回錯誤 AT_RETURN_UNKNOWN = 2, //返回結果未知 AT_RETURN_TIME_OUT = 0xf, //等待返回超時 }SIMCOM_AT_ERROR; //相關接口 bool SIMCOM_SendAT(SIMCOM_HANDLE *pHandle, char *pStr); //發送一個AT指令(會添加結束符\r\n),不會等待響應 SIMCOM_AT_ERROR SIMCOM_GetATResp(SIMCOM_HANDLE *pHandle, u8 **pRxBuff, u32 *pLen, const char *pKeyword, u8 ByteTimeOutMs, u16 TimeOutMs); //獲取SIMCOM的AT指令響應 bool SIMCOM_SendAT(SIMCOM_HANDLE *pHandle, char *pStr); //發送一個AT指令(會添加結束符\r\n),不會等待響應 bool SIMCOM_WaitSleep(SIMCOM_HANDLE *pHandle, u32 TimeOutMs); //等待模塊空閑,並重新喚醒 bool SIMCOM_TestAT(SIMCOM_HANDLE *pHandle, u32 retry); //SIMCOM AT 命令通信測試 #define SIMCOM_Ready(pHandle) if(SIMCOM_TestAT(pHandle, 5) == FALSE){SIMCOM_WaitSleep(pHandle, 1000);} //讓SIMCOM就緒,防止卡住//串口同步失敗,等待上一個操作完成 bool SIMCOM_SetParametersReturnBool(SIMCOM_HANDLE *pHandle, char *pATCom, u8 retry, u16 TimeOutMs, const char *pErrorDebug); //設置SIM900一個參數,返回一個bool狀態 //通用工具 u32 GSM_StringToHex(char *pStr, u8 NumDigits); //將16進制樣式字符串轉換為16進制整型數(必須保證字符串字母都是大寫) u32 GSM_StringToDec(char *pStr, u8 NumDigits); //將10進制樣式字符串轉換為整型數(必須保證完全為數字字符) void GSM_HexToString(u32 HexNum,char *pStr, u8 NumDigits); //將整型數字轉換為16進制樣式字符串(字母為大寫,不帶結束符) #endif /*SIMCOM_AT*/
//SIMCOM_GSM.c //通用的底層操作
/************************************************************************************************************* * 文件名: SIMCOM_GSM.c * 功能: SIMCOM GSM相關接口 * 作者: cp1300@139.com * 創建時間: 2015-02-15 * 最后修改時間: 2018-03-23 * 詳細: *************************************************************************************************************/ #include "system.h" #include "usart.h" #include "SIMCOM_GSM.h" #include "SIMCOM_AT.h" #include "string.h" #include "SIMCOM.h" #include <stdlib.h> bool g_SIMC0M_GSM_Debug = TRUE; //底層AT指令調試狀態 //調試開關 #define SIMCOM_GSM_DBUG 1 #if SIMCOM_GSM_DBUG #include "system.h" #define SIMCOM_GSM_debug(format,...) {if(g_SIMC0M_GSM_Debug){uart_printf(format,##__VA_ARGS__);}} #else #define SIMCOM_GSM_debug(format,...) /\ / #endif //SIMCOM_GSM_DBUG /************************************************************************************************************************* * 函數 : bool SIMCOM_NetworkConfig(SIMCOM_HANDLE *pHandle, SIMCOM_MODE_TYPE ModeType, SIMCOM_SIM_SELECT SIM_Select) * 功能 : SIMCOM網絡配置 * 參數 : pHandle:句柄;ModeType:通信模塊型號;SIM_Select:SIM卡選擇; * 返回 : TRUE:成功,FALSE:失敗 * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2018-01-17 * 最后修改時間 : 2018-03-24 * 詳細 : *************************************************************************************************************************/ bool SIMCOM_NetworkConfig(SIMCOM_HANDLE *pHandle, SIMCOM_MODE_TYPE ModeType, NETWORK_CONFIG_TYPE *pConfig) { char buff[16]; pConfig->ModeType = ModeType; //記錄通信模塊型號 if(ModeType == SIMCOM_SIM7000C) //SIM7000C需要選擇工作模式 { switch(pConfig->NB_EnableMode) { case 0: //GSM模式 { uart_printf("[DTU]設置GSM網絡模式!\r\n"); if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CNMP=13", SIMCOM_DEFAULT_RETRY, 200, "\r\n設置SIM7000C GSM模式失敗!\r\n") == FALSE) return FALSE; //GSM模式 }break; case 1://NB模式 { uart_printf("[DTU]設置NBIOT網絡模式!\r\n"); if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CNMP=38", SIMCOM_DEFAULT_RETRY, 200, "\r\n設置SIM7000C LTE NB模式失敗!\r\n") == FALSE) return FALSE; //LTE only(使用NB-IOT網絡時CNMP需要設置為38) //CAT NB模式設置 switch(pConfig->ModeType) { case CAT_M_MODE: //CAT模式 { sprintf(buff,"AT+CMNB=%d",1); //cat模式 }break; default: { sprintf(buff,"AT+CMNB=%d",2); //NBIOT模式 }break; } if(SIMCOM_SetParametersReturnBool(pHandle, buff, SIMCOM_DEFAULT_RETRY, 200, "\r\n設置SIM7000C CAT NB模式失敗!\r\n") == FALSE) return FALSE; //1: CAT-M 2: NB-IOT //擾碼設置 if(pConfig->isNB_ScarEnable) //開啟擾碼 { sprintf(buff,"AT+NBSC=%d",1); } else { sprintf(buff,"AT+NBSC=%d",0); } if(SIMCOM_SetParametersReturnBool(pHandle, buff, SIMCOM_DEFAULT_RETRY, 200, "\r\n設置SIM7000C NB 擾碼模式失敗!\r\n") == FALSE) return FALSE; }break; default:return TRUE; //忽略,無需設置 } } return TRUE; } /************************************************************************************************************************* * 函數 : SIM_CARD_STATUS SIMCOM_GetCPIN(SIMCOM_HANDLE *pHandle) * 功能 : 獲取SIM卡狀態 * 參數 : 無 * 返回 : FALSE:失敗;TRUE:成功 * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2014-06-26 * 最后修改時間 : 2014-06-26 * 說明 : 2017-09-05 : 增加SIM卡狀態為3種狀態 *************************************************************************************************************************/ SIM_CARD_STATUS SIMCOM_GetCPIN(SIMCOM_HANDLE *pHandle) { u32 cnt; char *p; u8 retry = SIMCOM_DEFAULT_RETRY; //重試次數 int status; u8 *pData; do { //+CPIN: READY SIMCOM_SendAT(pHandle, "AT+CPIN?"); pHandle->pClearRxData(); //清除接收計數器 status = SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 20, 200); //等待響應,超時200MS if(AT_RETURN_OK == status) //返回OK { p = strstr((const char*)pData, "+CPIN: READY"); //搜索字符"+CPIN: READY" if(p != NULL) //搜索成功 { return SIM_READY; //SIM卡就緒 } break; } else if(AT_RETURN_ERROR == status) //返回ERROR { p = strstr((const char*)pData, "ERROR"); //搜索卡未准備就緒標志 if(p != NULL) //搜索成功 { return SIM_NOT_READY; //SIM卡未就緒 } break; } SIMCOM_Ready(pHandle); //等待就緒 pHandle->pDelayMS(1000); //失敗延時1秒后重試 retry --; }while(retry); return SIM_UNKNOWN; //SIM卡未知 } /************************************************************************************************************************* * 函數 : SIMCOM_NETSTATUS SIM900_GetGSMNetworkStatus(SIMCOM_HANDLE *pHandle) * 功能 : 獲取GSM網絡注冊狀態 * 參數 : pHandle:句柄 * 返回 : SIMCOM_NETSTATUS * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2013-10-29 * 最后修改時間 : 2018-03-24 * 說明 : 當網絡注冊后,可能被拒絕,如果被拒絕,獲取網絡注冊狀態會提示 注冊成功的,但是通過發送AT 后再去查詢,會發現網絡注冊失敗 *************************************************************************************************************************/ SIMCOM_NETSTATUS SIM900_GetGSMNetworkStatus(SIMCOM_HANDLE *pHandle) { u32 cnt; char *p; u8 retry = SIMCOM_DEFAULT_RETRY; //重試次數 u8 *pData; do { //+CREG: 0,1 SIMCOM_SendAT(pHandle, "AT+CREG?"); //發送"AT+CREG?",獲取網絡注冊狀態 pHandle->pClearRxData(); //清除接收計數器 if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 20, 200)) //等待響應,超時200MS { p = strstr((const char*)pData, "+CREG:"); //搜索字符"+CREG:" if(p != NULL) //搜索成功 { SIMCOM_TestAT(pHandle, 1); return (SIMCOM_NETSTATUS)GSM_StringToDec(&p[9], 1); } break; } SIMCOM_Ready(pHandle); //等待就緒 pHandle->pDelayMS(1000); //失敗延時1秒后重試 retry --; }while(retry); SIMCOM_TestAT(pHandle, 2); return SIMCOM_NET_ERROR; } /************************************************************************************************************************* * 函數 : SIMCOM_NETSTATUS SIMCOM_GetDataNetworkStatus(SIMCOM_HANDLE *pHandle) * 功能 : 獲取數據網絡注冊狀態 * 參數 : pHandle:句柄 * 返回 : SIMCOM_NETSTATUS * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2013-10-29 * 最后修改時間 : 2018-03-24 * 說明 : 用於獲取NB數據網絡或GPRS數據網絡注冊狀態 *************************************************************************************************************************/ SIMCOM_NETSTATUS SIMCOM_GetDataNetworkStatus(SIMCOM_HANDLE *pHandle) { u32 cnt; char *p; u8 retry = SIMCOM_DEFAULT_RETRY; //重試次數 u8 *pData; do { //+CGREG: 0,1 SIMCOM_SendAT(pHandle, "AT+CGREG?"); //發送"AT+CGREG?",獲取網絡注冊狀態 pHandle->pClearRxData(); //清除接收計數器 if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 20, 200)) //等待響應,超時200MS { p = strstr((const char*)pData, "+CGREG:"); //搜索字符"+CGREG:" if(p != NULL) //搜索成功 { SIMCOM_TestAT(pHandle, 1); return (SIMCOM_NETSTATUS)GSM_StringToDec(&p[10], 1); } break; } SIMCOM_Ready(pHandle); //等待就緒 pHandle->pDelayMS(1000); //失敗延時1秒后重試 retry --; }while(retry); SIMCOM_TestAT(pHandle, 2); return SIMCOM_NET_ERROR; } /************************************************************************************************************************* * 函數 : bool SIM900_SetGPRS_PackDatatSize(SIMCOM_HANDLE *pHandle) * 功能 : 設置SIM900/SIM800 GPRS發送數據緩沖區 * 參數 : pHandle:句柄 * 返回 : FALSE:失敗;TRUE:成功 * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2014-09-11 * 最后修改時間 : 2014-09-11 * 說明 : 按照最大數據包1460B設置 *************************************************************************************************************************/ bool SIM900_SetGPRS_PackDatatSize(SIMCOM_HANDLE *pHandle) { char buff[36]; //先開啟透傳模式才能設置 SIMCOM_SetParametersReturnBool(pHandle, "AT+CIPMODE=1", SIMCOM_DEFAULT_RETRY, 2000, "開啟透傳模式失敗!\r\n"); //開啟透傳模式 //設置GPRS傳輸數據包大小 //AT+CIPCCFG=3,2,1024,1 //設置透傳參數 //3-重傳次數為3次,2-等待數據輸入時間為 //2*200ms,1024-數據緩沖區為1024個字節 //1-支持轉義退出透傳 sprintf(buff,"AT+CIPCCFG=3,2,%d,1",1460); return SIMCOM_SetParametersReturnBool(pHandle, buff, SIMCOM_DEFAULT_RETRY, 200, "GPRS發送數據緩沖區設置失敗!\r\n"); //發送 } /************************************************************************************************************************* * 函數 : bool SIMCOM_ModuleInit(SIMCOM_HANDLE *pHandle) * 功能 : 初始化SIMCOM模塊基本配置(不允許失敗) * 參數 : pHandle:句柄 * 返回 : FALSE:初始化失敗;TRUE:初始化成功 * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2013-10-16 * 最后修改時間 : 2018-03-24 * 說明 : 必須先上電,並獲取模塊型號,根據不同的型號模塊分別進行初始化 *************************************************************************************************************************/ bool SIMCOM_ModuleInit(SIMCOM_HANDLE *pHandle) { u8 retry = 5; //重試次數 pHandle->pSetDTR_Pin(SIMCOM_L_LEVEL); //DTR=0,退出低功耗模式 //檢測模塊存在,並保證通信正常 SIMCOM_Ready(pHandle); SIMCOM_TestAT(pHandle, 20); switch(pHandle->SimcomModeType) //不同的芯片存在不一樣的初始化 { case SIMCOM_SIM2000: //SIM2000需要先關閉URC,否則會提示Call Ready { SIMCOM_SetParametersReturnBool(pHandle, "AT+CIURC=0", SIMCOM_DEFAULT_RETRY, 110, "\r\n關閉Call Ready顯示失敗!\r\n"); }break; default:break; } //設置關閉回顯 if(SIMCOM_SetParametersReturnBool(pHandle, "ATE 0", SIMCOM_DEFAULT_RETRY, 110, "\r\n關閉AT回顯模式失敗!\r\n") == FALSE) { return FALSE; } //設置短消息格式為PDU格式 if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CMGF=0", SIMCOM_DEFAULT_RETRY, 110, "\r\n設置短消息格式為PDU格式失敗!\r\n") == FALSE) { uart_printf("\r\n設置DCD功能模式失敗!\r\n"); return FALSE; } //設置DCD功能模式,DCD線只在數據載波存在時為ON。 if(SIMCOM_SetParametersReturnBool(pHandle, "AT&C1", SIMCOM_DEFAULT_RETRY, 110, "\r\n設置DCD功能模式失敗!\r\n") == FALSE) { uart_printf("\r\n設置DCD功能模式失敗!\r\n"); //return FALSE; } //設置 DTR 功能模式,DTR 由ON至OFF:TA在保持當前數據通話的同時,切換至命令模式 if(SIMCOM_SetParametersReturnBool(pHandle, "AT&D1", SIMCOM_DEFAULT_RETRY, 110, "\r\n設置DTR功能模式失敗!\r\n") == FALSE) { uart_printf("\r\n設置DTR功能模式失敗!\r\n"); //return FALSE; } // //使能RI引腳提示 // if(SIM900_SetParametersReturnBool("AT+CFGRI=1", SIMCOM_DEFAULT_RETRY, 11, "\r\n啟動RI引腳提示失敗!\r\n") == FALSE) // { // return FALSE; // } //設置模塊sleep模式使能//發送"AT+CSCLK",啟動SLEEP模式;0:關閉;1:手動;2:自動空閑5S鍾后休眠 if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CSCLK=1", SIMCOM_DEFAULT_RETRY, 110, "\r\n設置SLEEP失敗!\r\n") == FALSE) { return FALSE; } //檢查卡是否就緒 retry = 8; //重試次數 do { if(SIMCOM_GetCPIN(pHandle)==SIM_READY) { uart_printf("\r\nSIM卡准備就緒!\r\n"); break; } else { uart_printf("\r\nSIM卡未准備就緒!\r\n"); } SIMCOM_Ready(pHandle); //等待就緒 pHandle->pDelayMS(1000); //失敗延時1秒后重試 retry --; }while(retry); if(retry == 0) { uart_printf("\r\nSIM卡未准備就緒!\r\n"); pHandle->pClearRxData(); //清除接收計數器 return FALSE; } // //上電刪除所有短信 // retry = SIMCOM_DEFAULT_RETRY; //重試次數 // do // { // if(SIM900_DelMultiSMS(DelSMS) == TRUE)//刪除短信 // { // //uart_printf("上電刪除短信成功!\r\n"); // break; // } // SIM900_Ready(); //等待就緒 // retry --; // }while(retry); // if(retry == 0) // { // uart_printf("上電刪除短信失敗!\r\n"); // SIM900_ClearRxCnt(); //清除計數器 // return FALSE; // } //2016-09-20:設置等待消息上報超時時間為1分鍾,因為西寧項目卡出現超時情況 switch(pHandle->SimcomModeType) //不同的芯片存在不一樣的初始化 { case SIMCOM_SIM800: //SIM800需要等待就緒時間長一些 { retry = 65; }break; default:retry=35;break; } //關閉新消息自動上報 while(retry) { if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CNMI=0", SIMCOM_DEFAULT_RETRY, 110, "\r\n關閉新消息自動上報失敗!\r\n") == FALSE) { //return FALSE; } else break; pHandle->pDelayMS(1000); //延時1秒 retry --; } if(retry == 0) return FALSE; switch(pHandle->SimcomModeType) //不同的芯片存在不一樣的初始化 { case LYNQ_L700: break; case SIMCOM_SIM7600: { //設置TCP收發相關 retry = SIMCOM_DEFAULT_RETRY; //重試次數 while(retry) { //設置重試次數為3次,並且發送延時為120ms if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CIPCCFG=3,100,,1,0,,1000", SIMCOM_DEFAULT_RETRY, 110, "\r\n配置TCP/IP失敗!\r\n") == FALSE) { //return FALSE; } else break; pHandle->pDelayMS(1000); //延時1秒 retry --; } if(retry == 0) { uart_printf("\r\n設置TCP重發次數以及發送延時失敗!\r\n"); pHandle->pClearRxData(); //清除接收計數器 return FALSE; } //設置不用等到發送響應 retry = SIMCOM_DEFAULT_RETRY; //重試次數 while(retry) { //設置重試次數為3次,並且發送延時為120ms if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CIPSENDMODE=0", SIMCOM_DEFAULT_RETRY, 110, "\r\n不用等待發送ACK設置失敗!\r\n") == FALSE) { //return FALSE; } else break; pHandle->pDelayMS(1000); //延時1秒 retry --; } if(retry == 0) { uart_printf("\r\n設置不用等待發送ACK失敗!\r\n"); pHandle->pClearRxData(); //清除接收計數器 } //顯示接收數據長度 retry = SIMCOM_DEFAULT_RETRY; //重試次數 while(retry) { //設置重試次數為3次,並且發送延時為120ms if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CIPHEAD=1", SIMCOM_DEFAULT_RETRY, 110, "\r\n顯示接收數據長度設置失敗!\r\n") == FALSE) { //return FALSE; } else break; pHandle->pDelayMS(1000); //延時1秒 retry --; } if(retry == 0) { uart_printf("\r\n設置顯示接收數據長度失敗!\r\n"); pHandle->pClearRxData(); //清除接收計數器 return FALSE; } //不顯示接收數據IP頭 retry = SIMCOM_DEFAULT_RETRY; //重試次數 while(retry) { //設置重試次數為3次,並且發送延時為120ms if(SIMCOM_SetParametersReturnBool(pHandle, "AT+CIPSRIP=0", SIMCOM_DEFAULT_RETRY, 110, "\r\n不顯示接收數據IP頭設置失敗!\r\n") == FALSE) { //return FALSE; } else break; pHandle->pDelayMS(1000); //延時1秒 retry --; } if(retry == 0) { uart_printf("\r\n不顯示接收數據IP頭失敗!\r\n"); pHandle->pClearRxData(); //清除接收計數器 return FALSE; } }break; default: //2G模塊均需要進行設置的 { //設置GPRS發送數據緩沖區大小 retry = SIMCOM_DEFAULT_RETRY; //重試次數 do { if(SIM900_SetGPRS_PackDatatSize(pHandle) == TRUE) { break; } retry --; }while(retry); if(retry == 0) { uart_printf("\r\n設置GPRS傳輸大小失敗!\r\n"); pHandle->pClearRxData(); //清除接收計數器 return FALSE; } }break; } pHandle->s_isInitStatus = TRUE; //模塊成功初始化 pHandle->pClearRxData(); //清除接收計數器 return TRUE; } /************************************************************************************************************************* * 函數 : bool SIMCOM_GetModuleInfo(SIMCOM_HANDLE *pHandle, SIMCOM_INFO *pInfo) * 功能 : 獲取模塊的相關信息 * 參數 : pHandle:句柄;pInfo:信息結構體指針 * 返回 : FALSE:失敗;TRUE:成功 * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2014-07-29 * 最后修改時間 : 2014-10-08 * 說明 : SIMCOM_INFO_SIZE:限制最大長度 SIMCOM_VER_SIZE:軟件版本長度限制 2014-10-08:在個別模塊上面遇到發送AT+GMI后返回了AT+GMI,導致獲取失敗,如果發現返回了AT+則重新獲取,可以避免此問題 2016-12-07:修改獲取模塊型號指令為AT+CGMM,用於兼容SIM7600 *************************************************************************************************************************/ bool SIMCOM_GetModuleInfo(SIMCOM_HANDLE *pHandle, SIMCOM_INFO *pInfo) { u32 i,cnt; u8 retry = SIMCOM_DEFAULT_RETRY; //重試次數 char *p; u8 *pData; //清空緩沖區 pInfo->Manu[0] = 0; pInfo->Model[0] = 0; pInfo->Ver[0] = 0; pInfo->IMEI[0] = 0; retry = SIMCOM_DEFAULT_RETRY; //重試次數 //獲取制造商信息 do { SIMCOM_TestAT(pHandle, 10); SIMCOM_SendAT(pHandle, "AT+GMI"); //請求制造商身份 if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, 200)) //等待響應,超時200MS { //uart_printf("%s\r\n",pData); if(strstr((const char*)pData, "AT+") == NULL) //搜索關鍵字 { for(i = 0;i < (SIMCOM_INFO_SIZE-1);i ++) { if((pData[2+i] == '\r') || (pData[2+i] == '\n') || (pData[2+i] == '\0')) break; pInfo->Manu[i] = pData[2+i]; } pInfo->Manu[i] = 0; break; } } SIMCOM_Ready(pHandle); //等待就緒 pHandle->pDelayMS(1000); //失敗延時1秒后重試 retry --; }while(retry); if(retry == 0) return FALSE; retry = SIMCOM_DEFAULT_RETRY; //重試次數 //獲取型號 do { SIMCOM_SendAT(pHandle, "AT+CGMM"); pHandle->pClearRxData(); //清除接收計數器 if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, 200)) //等待響應,超時200MS { for(i = 0;i < (SIMCOM_INFO_SIZE-1);i ++) { if((pData[2+i] == '\r') || (pData[2+i] == '\n') || (pData[2+i] == '\0')) break; pInfo->Model[i] = pData[2+i]; } pInfo->Model[i] = 0; break; } SIMCOM_Ready(pHandle); //等待就緒 pHandle->pDelayMS(1000); //失敗延時1秒后重試 retry --; }while(retry); if(retry == 0) return FALSE; retry = SIMCOM_DEFAULT_RETRY; //重試次數 //獲取軟件版本 do { SIMCOM_SendAT(pHandle, "AT+GMR"); pHandle->pClearRxData(); //清除接收計數器 if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, 200)) //等待響應,超時200MS { p = strstr((char *)pData, "+GMR: "); if(p != NULL) { p+= strlen("+GMR: "); //SIM7600前面會有 +GMR: ,跳過即可 for(i = 0;i < (SIMCOM_VER_SIZE-1);i ++) { if((p[i] == '\r') || (p[i] == '\n') || (p[i] == '\0')) break; pInfo->Ver[i] = p[i]; } pInfo->Ver[i] = 0; } else { for(i = 0;i < (SIMCOM_VER_SIZE-1);i ++) { if((pData[2+i] == '\r') || (pData[2+i] == '\n') || (pData[2+i] == '\0')) break; pInfo->Ver[i] = pData[2+i]; } pInfo->Ver[i] = 0; } break; } SIMCOM_Ready(pHandle); //等待就緒 pHandle->pDelayMS(1000); //失敗延時1秒后重試 retry --; }while(retry); if(retry == 0) return FALSE; retry = SIMCOM_DEFAULT_RETRY; //重試次數 //獲取序列號 do { SIMCOM_SendAT(pHandle, "AT+GSN"); pHandle->pClearRxData(); //清除接收計數器 if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, 200)) //等待響應,超時200MS { for(i = 0;i < (SIMCOM_INFO_SIZE-1);i ++) { if((pData[2+i] == '\r') || (pData[2+i] == '\n') || (pData[2+i] == '\0')) break; pInfo->IMEI[i] = pData[2+i]; } pInfo->IMEI[i] = 0; break; } SIMCOM_Ready(pHandle); //等待就緒 pHandle->pDelayMS(1000); //失敗延時1秒后重試 retry --; }while(retry); return TRUE; } /************************************************************************************************************************* * 函數 : bool SIMCOM_COPS(SIMCOM_HANDLE *pHandle, char pCOPS_Buff[SIMCOM_INFO_SIZE]) * 功能 : 獲取運營商名稱 * 參數 : pHandle:句柄;pCOPS_Buff:運營商名稱 * 返回 : FALSE:失敗;TRUE:成功 * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2014-07-29 * 最后修改時間 : 2018-03-24 * 說明 : SIMCOM_INFO_SIZE 限制最大長度 *************************************************************************************************************************/ bool SIMCOM_COPS(SIMCOM_HANDLE *pHandle, char pCOPS_Buff[SIMCOM_INFO_SIZE]) { u32 i,cnt; u8 retry = 5; //重試次數 char *p; u8 *pData; //清空緩沖區 pCOPS_Buff[0] = 0; switch(pHandle->SimcomModeType) //不同的芯片存在不一樣的初始化 { case SIMCOM_SIM2000: //SIM2000需要多次讀取,等待的時間比較長 { retry = 28; }break; default:break; } //獲取運營商 do { SIMCOM_SendAT(pHandle, "AT+COPS?"); //顯示模塊當前注冊的網絡運營商 pHandle->pClearRxData(); //清除接收計數器 if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 20, 150)) //等待響應,超時300MS { p = strstr((const char*)pData, "\""); if(p != NULL) { p ++; for(i = 0;i < (SIMCOM_INFO_SIZE-1);i ++) { if((p[i] == '\r') || (p[i] == '\n') || (p[i] == '\0') || (p[i] == '\"')) break; pCOPS_Buff[i] = p[i]; } pCOPS_Buff[i] = 0; return TRUE; } } SIMCOM_Ready(pHandle); //等待就緒 pHandle->pDelayMS(1000); //延時1秒 retry --; }while(retry); return FALSE; //超時//錯誤 } /************************************************************************************************************************* * 函數 : SIMCOM_NETMODE_TYPE SIM7XXX_GetNetworkMode(SIMCOM_HANDLE *pHandle) * 功能 : 獲取SIM7XXX系列模塊網絡制式 * 參數 : pHandle:句柄 * 返回 : SIMCOM_NETMODE_TYPE * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2016-12-29 * 最后修改時間 : 2018-03-24 * 說明 : 用於從SIM7600模塊網絡制式 必須在網絡注冊成功后進行獲取,正常返回 +CNSMOD: 0,15 用於SIM7000系列獲取網制式 *************************************************************************************************************************/ SIMCOM_NETMODE_TYPE SIM7XXX_GetNetworkMode(SIMCOM_HANDLE *pHandle) { u32 cnt; u8 retry = 3; char *p; int temp; u8 *pData; //獲取型號 do { SIMCOM_SendAT(pHandle, "AT+CNSMOD?"); pHandle->pClearRxData(); //清除接收計數器 if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, 200)) //等待響應,超時200MS { p = strstr((char *)pData, "+CNSMOD: 0,"); if(p==NULL) p = strstr((char *)pData, "+CNSMOD: 1,"); p += strlen("+CNSMOD: 0,"); temp = atoi(p); if(temp > 16) continue; else return (SIMCOM_NETMODE_TYPE)temp; } SIMCOM_Ready(pHandle); //等待就緒 pHandle->pDelayMS(1000); //失敗延時1秒后重試 retry --; }while(retry); return SIMCOM_NETMODE_NULL; } /************************************************************************************************************************* * 函數 : bool SIMCOM_HardwarePowerUP(SIMCOM_HANDLE *pHandle, bool isTest) * 功能 : SIMCOM模塊硬件開機 * 參數 : pHandle:句柄;isTest:是否檢測開機是否成功,通過STATUS腳變為高電平可以檢測是否開機成功 * 返回 : 開機是否成功 * 依賴 : 無 * 作者 : cp1300@139.com * 時間 : 2013-10-29 * 最后修改時間 : 2018-03-24 * 說明 : 用於SIM900模塊開機,拉低PWR 2016-12-07:修改動態監測是否上電成功,增加SIM7600CE兼容 *************************************************************************************************************************/ bool SIMCOM_HardwarePowerUP(SIMCOM_HANDLE *pHandle, bool isTest) { u8 i,j; pHandle->pSetDTR_Pin(SIMCOM_L_LEVEL); //DTR=0,退出低功耗模式 pHandle->s_isInitStatus = FALSE; //模塊沒有初始化,需要重新初始化 if(isTest) //需要檢測是否開機成功 { if(pHandle->pGetSTATUS_Pin() == SIMCOM_H_LEVEL) //開機腳已經是高電平了 { return TRUE; } for(i = 0;i < 2;i ++) { pHandle->pSetPWRKEY_Pin(SIMCOM_L_LEVEL); //拉低1200ms開機 pHandle->pDelayMS(1200); pHandle->pSetPWRKEY_Pin(SIMCOM_H_LEVEL); //恢復高電平 for(j = 0;j < 6;j ++) { pHandle->pDelayMS(1000); if(pHandle->pGetSTATUS_Pin() == SIMCOM_H_LEVEL) //開機腳已經是高電平了 { return TRUE; } } } return FALSE; } else //無需檢測是否開機成功 { pHandle->pSetPWRKEY_Pin(SIMCOM_L_LEVEL); //拉低1200ms開機 pHandle->pDelayMS(1200); pHandle->pSetPWRKEY_Pin(SIMCOM_H_LEVEL); //恢復高電平 pHandle->pDelayMS(3000);; //延時3S等待開機完畢 return TRUE; } } /************************************************************************************************************************* * 函數 : bool SIMCOM_HardwarePowerDOWN(SIMCOM_HANDLE *pHandle, bool isTest) * 功能 : SIMCOM模塊硬件關機 * 參數 : pHandle:句柄;isTest:是否檢測開機是否成功,通過STATUS腳變為高電平可以檢測是否關機成功 * 返回 : 關機是否成功 * 依賴 : 無 * 作者 : cp1300@139.com * 時間 : 2013-10-29 * 最后修改時間 : 2018-03-24 * 說明 : 用於SIM900模塊關機機,拉低PWR大於1S小於5S 2016-12-07:優化關機,兼容SIM7600 一定要先獲取模塊型號,不同模塊關機時間不一樣 *************************************************************************************************************************/ bool SIMCOM_HardwarePowerDOWN(SIMCOM_HANDLE *pHandle, bool isTest) { u8 i,j; pHandle->s_isInitStatus = FALSE; //模塊沒有初始化,需要重新初始化 if(isTest) //需要檢測是否開機成功 { if(pHandle->pGetSTATUS_Pin() == SIMCOM_L_LEVEL) //開機腳已經是低電平了 { return TRUE; } for(i = 0;i < 2;i ++) { pHandle->pSetPWRKEY_Pin(SIMCOM_L_LEVEL); //拉低1200ms關機 switch(pHandle->SimcomModeType) { case SIMCOM_SIM7600: { pHandle->pDelayMS(3000); //SIM7600關機至少2.5S }break; default: { pHandle->pDelayMS(1000); }break; } pHandle->pDelayMS(200); pHandle->pSetPWRKEY_Pin(SIMCOM_H_LEVEL); //恢復高電平 for(j = 0;j < 5;j ++) { pHandle->pDelayMS(3000); //延時3S等待關機完畢 if(pHandle->pGetSTATUS_Pin() == SIMCOM_L_LEVEL) //開機腳已經是低電平了 { return TRUE; } } } return FALSE; } else //無需檢測是否開機成功 { pHandle->pSetPWRKEY_Pin(SIMCOM_L_LEVEL); //拉低1200ms關機 pHandle->pDelayMS(1200); pHandle->pSetPWRKEY_Pin(SIMCOM_H_LEVEL); //恢復高電平 pHandle->pDelayMS(3000);; //延時3S等待關機完畢 return TRUE; } } /************************************************************************************************************************* * 函數 : SIMCOM_MODE_TYPE SIMCOM_GetMode(SIMCOM_HANDLE *pHandle) * 功能 : 獲取SIMCOM模塊的型號 * 參數 : pHandle:句柄 * 返回 : 型號,見SIMCOM_MODE_TYPE * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2015-09-12 * 最后修改時間 : 2015-09-12 * 說明 : 用於識別型號,對應初始化 2016-12-07:修改指令為AT+CGMM,兼容SIM7600,(舊指令:AT+GOI) *************************************************************************************************************************/ SIMCOM_MODE_TYPE SIMCOM_GetMode(SIMCOM_HANDLE *pHandle) { u32 cnt; u8 retry = SIMCOM_DEFAULT_RETRY+1; u8 *pData; //獲取型號 do { SIMCOM_SendAT(pHandle, "AT+CGMM"); pHandle->pClearRxData(); //清除接收計數器 if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, 200)) //等待響應,超時200MS { if(strstr((char *)pData, "SIM900") != NULL) return SIMCOM_SIM900; else if(strstr((char *)pData, "SIM800") != NULL) return SIMCOM_SIM800; else if(strstr((char *)pData, "SIM2000") != NULL) return SIMCOM_SIM2000; else if(strstr((char *)pData, "SIM7600") != NULL) return SIMCOM_SIM7600; else if(strstr((char *)pData, "SIMCOM_SIM868") != NULL) return SIMCOM_SIM868; else if(strstr((char *)pData, "SIMCOM_SIM7000C") != NULL) return SIMCOM_SIM7000C; else if(strstr((char *)pData, "LYNQ_L700") != NULL) return LYNQ_L700; else { uart_printf("未知通信模塊:%s\r\n",pData); return SIMCOM_INVALID; } } SIMCOM_Ready(pHandle); //等待就緒 pHandle->pDelayMS(1000); //失敗延時1秒后重試 retry --; }while(retry); return SIMCOM_INVALID; } /************************************************************************************************************************* * 函數 : bool SIMCOM_GetServeNumber(PHONE_NUMBER *pServeNumber) * 功能 : 獲取短信服務中心號碼(會去掉前面的86,限制長度15位,不能用於SIM7000,SIM2000以及電信卡) * 參數 : pServeNumber:電話號碼存儲緩沖區指針 * 返回 : FALSE:通信失敗;TRUE:通信成功 * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2013-10-20 * 最后修改時間 : 2013-10-20 * 說明 : 獲取SIM卡內部的短信服務中心號碼,一般在辦理SIM卡的時候已經進行了設置. 如果沒有預置短信中心號碼需要使用手機進行設置 2014-07-12:只要返回OK則認為成功,因為有可能沒有設置短信中心號碼 2016-01-26:自動選擇是否跳過+86 *************************************************************************************************************************/ bool SIMCOM_GetServeNumber(SIMCOM_HANDLE *pHandle, char pPhoneNumber[16]) { u8 i,n; u32 cnt; char *p,*p1; u8 retry = SIMCOM_DEFAULT_RETRY; //重試次數 u8 *pData; do { //+CSCA: "+8613800270500",145 SIMCOM_SendAT(pHandle, "AT+CSCA?"); //發送"AT+CSCA",獲取短信服務中心號碼 pHandle->pClearRxData(); //清除接收計數器 if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 30, 600)) //等待響應,超時600MS { p = strstr((const char*)pData, "+CSCA:"); //搜索字符"+CSCA:" if(p != NULL) //搜索成功 { p = strstr(p+1, "+"); //搜索"+" if(p != NULL) { p1 = strstr(p+1, "\""); //搜索"\"" if(p1 != NULL) { if(p[0] == '+') //如果是+開頭,則跳過加號 { p+=3; //跳過+86 } else if(p[0]=='8' && p[1] == '6') //跳過86 { p+=2; } n = p1 - p; //計算電話號碼長度 if(n > 15) n = 15; //限制號碼長度為15字節 for(i = 0;i < n;i ++) { pPhoneNumber[i] = p[i]; //復制電話號碼 } pPhoneNumber[i] = '\0'; //添加結束符 SIMCOM_GSM_debug("短信中心號碼:%s\r\n",pPhoneNumber); return TRUE; } } } else { pPhoneNumber[0] = '\0'; SIMCOM_GSM_debug("短信中心號碼:為空,沒有設置\r\n"); return TRUE; } } SIMCOM_Ready(pHandle); //等待就緒 pHandle->pDelayMS(1000); //失敗延時1秒后重試 retry --; }while(retry); return FALSE; } /************************************************************************************************************************* * 函數 : bool SIMCOM_GetPhoneNumber(SIMCOM_HANDLE *pHandle, char pPhoneNumber[16]) * 功能 : 獲取本機號碼(會去掉前面的86,限制長度15位,不能用於SIM7000,SIM2000以及電信卡) * 參數 : pHandle:句柄;pPhoneNumber:號碼緩沖區 * 返回 : FALSE:通信失敗;TRUE:通信成功 * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2013-10-20 * 最后修改時間 : 2018-03-24 * 說明 : 通常會預存本機號碼到SIM卡,也可能沒有(不能用於SIM7000,SIM2000C,不能用於電信卡) 2014-07-12:只要返回OK則認為成功,因為有可能沒有設置電話號碼 2016-01-26:修改字節超時,否則某些卡會出現超時,沒有收到OK 自動選擇是否跳過+86 *************************************************************************************************************************/ bool SIMCOM_GetPhoneNumber(SIMCOM_HANDLE *pHandle, char pPhoneNumber[16]) { u8 n; u8 i; u32 cnt; char *p,*p1; u8 retry = SIMCOM_DEFAULT_RETRY; //重試次數 u8 *pData; do { //+CNUM: "","15871750634",129,7,4 SIMCOM_SendAT(pHandle, "AT+CNUM"); //發送"AT++CNUM",獲取號碼 pHandle->pClearRxData(); //清除接收計數器 if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 30, 600)) //等待響應,超時600MS { p = strstr((const char*)pData, "+CNUM:"); //搜索字符"+CNUM:" if(p != NULL) //搜索成功 { p = strstr(p+1, "\",\""); //搜索"," //開始 if(p != NULL) { p1 = strstr(p+3, "\","); //搜索",//結束 if(p1 != NULL) { p+=3; //跳過"," if(p[0] == '+') //如果是+開頭,則跳過加號 { p+=3; //跳過+86 } else if(p[0]=='8' && p[1] == '6') //跳過86 { p+=2; } n = p1 - p; //計算電話號碼長度 if(n > 15) n = 15; //限制號碼長度為15字節 for(i = 0;i < n;i ++) { pPhoneNumber[i] = p[i]; //復制電話號碼 } pPhoneNumber[i] = '\0'; //添加結束符 SIMCOM_GSM_debug("本機號碼:%s\r\n",pPhoneNumber); return TRUE; } } } else { pPhoneNumber[0] = '\0'; SIMCOM_GSM_debug("本機號碼:為空,沒有設置\r\n"); return TRUE; } } SIMCOM_Ready(pHandle); //等待就緒 pHandle->pDelayMS(1000); //失敗延時1秒后重試 retry --; }while(retry); return FALSE; } /************************************************************************************************************************* * 函數 : bool SIMCOM_GetBookNumber(SIMCOM_HANDLE *pHandle, u8 index, char pPhoneNumber[16]) * 功能 : 從電話簿獲取一個電話號碼(不能用於SIM7000) * 參數 : pHandle:句柄;index:電話號碼所有,1-255;CenterPhone:電話號碼存儲緩沖區指針 * 返回 : FALSE:通信失敗;TRUE:通信成功 * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2013-10-20 * 最后修改時間 : 2016-06-15 * 說明 : 用於從電話簿讀取一個電話號碼,常用語電信卡SIM2000C模塊存儲本機號碼到第一個索引 *************************************************************************************************************************/ bool SIMCOM_GetBookNumber(SIMCOM_HANDLE *pHandle, u8 index, char pPhoneNumber[16]) { u8 i,n; u32 cnt; char *p,*p1; u8 retry = SIMCOM_DEFAULT_RETRY; //重試次數 u8 *pData; char buff[32]; if(index < 1) return FALSE; //索引從1開始 do { //+CPBR: 1,"152778787878",129,"Phone" sprintf(buff,"AT+CPBR=%d",index); SIMCOM_SendAT(pHandle, buff); //發送"AT+CPBR=1",獲取號碼 pHandle->pClearRxData(); //清除接收計數器 if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 30, 600)) //等待響應,超時600MS { p = strstr((const char*)pData, "+CPBR:"); //搜索字符"+CPBR:" if(p != NULL) //搜索成功 { p = strstr(p+1, ",\""); //搜索," //開始 if(p != NULL) { p1 = strstr(p+2, "\","); //搜索",//結束 if(p1 != NULL) { p+=2; //跳過," if(p[0] == '+') //如果是+開頭,則跳過加號 { p+=3; //跳過+86 } else if(p[0]=='8' && p[1] == '6') //跳過86 { p+=2; } n = p1 - p; //計算電話號碼長度 if(n > 15) n = 15; //限制號碼長度為15字節 for(i = 0;i < n;i ++) { pPhoneNumber[i] = p[i]; //復制電話號碼 } pPhoneNumber[i] = '\0'; //添加結束符 SIMCOM_GSM_debug("號碼:%s\r\n",pPhoneNumber); return TRUE; } } } else { pPhoneNumber[0] = '\0'; SIMCOM_GSM_debug("號碼:為空\r\n"); return TRUE; } } SIMCOM_Ready(pHandle); //等待就緒 pHandle->pDelayMS(1000); //失敗延時1秒后重試 retry --; }while(retry); return FALSE; } /************************************************************************************************************************* * 函數 : int SIMCOM_GetSignal(SIMCOM_HANDLE *pHandle) * 功能 : 獲取信號強度 * 參數 : pHandle:句柄 * 返回 : <0:獲取失敗;0-31:信號強度; * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2013-10-21 * 最后修改時間 : 2013-10-21 * 說明 : 無 *************************************************************************************************************************/ int SIMCOM_GetSignal(SIMCOM_HANDLE *pHandle) { u8 temp; u32 cnt; char *p; u8 retry = SIMCOM_DEFAULT_RETRY; //重試次數 u8 *pData; do { //+CSQ: 27,0 //+CSQ: 5,0 //+CSQ: 16,99 SIMCOM_SendAT(pHandle,"AT+CSQ"); //發送"AT++CSQ",獲取號碼 pHandle->pClearRxData(); //清除接收計數器 if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 20, 400)) //等待響應,超時400MS { p = strstr((const char*)pData, "+CSQ:"); //搜索字符"+CSQ:" if(p != NULL) //搜索成功 { if(p[7] != ',' && p[8] != ',') p[8] = '\0'; temp = atoi(&p[6]); return temp; } break; } SIMCOM_Ready(pHandle); //等待就緒 pHandle->pDelayMS(1000); //失敗延時1秒后重試 retry --; }while(retry); return -1; } /************************************************************************************************************************* * 函數 : bool SIMCOM_GetCIMI(SIMCOM_HANDLE *pHandle, char pCIMI[16]) * 功能 : 獲取SIM卡CIMI號碼(SIM卡唯一id,必須存在) * 參數 : pHandle:句柄;pCIMI:CIMI緩沖區,長15字節 * 返回 : FALSE:通信失敗;TRUE:通信成功 * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2017-11-16 * 最后修改時間 : 2018-03-24 * 說明 : 用於獲取卡唯一CIMI編號,防止某些卡無法讀取本機號碼,這個與卡號一一對應 *************************************************************************************************************************/ bool SIMCOM_GetCIMI(SIMCOM_HANDLE *pHandle, char pCIMI[16]) { u32 cnt; u8 retry = SIMCOM_DEFAULT_RETRY; //重試次數 u8 *pData; do { //460041037206894 SIMCOM_SendAT(pHandle, "AT+CIMI"); //發送"AT+CIMI" pHandle->pClearRxData(); //清除接收計數器 if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 20, 200)) //等待響應,超時200MS { if(pData[0]!='\r' || pData[1]!='\n') continue; memcpy(pCIMI, &pData[2], 15); //跳過前面\r\n pCIMI[15] = 0; //添加結束符 SIMCOM_GSM_debug("獲取CIMI成功:%s\r\n", pCIMI); return TRUE; } SIMCOM_Ready(pHandle); //等待就緒 pHandle->pDelayMS(1000); //失敗延時1秒后重試 retry --; }while(retry); return FALSE; } /************************************************************************************************************************* * 函數 : bool SIM7000C_GetNB_APN(SIMCOM_HANDLE *pHandle, char pAPN[17]) * 功能 : 獲取SIM7000C NBIOT 接入點 * 參數 : pHandle:句柄;pAPN:接入點緩沖區 * 返回 : TRUE:成功;FALSE:失敗 * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2018-01-16 * 最后修改時間 : 2018-01-16 * 說明 : 必須是NBIOT模式才能使用 *************************************************************************************************************************/ bool SIM7000C_GetNB_APN(SIMCOM_HANDLE *pHandle, char pAPN[17]) { u32 cnt; char *p; u8 retry = SIMCOM_DEFAULT_RETRY; //重試次數 u8 *pData; u8 i; do { //+CGNAPN: 1,"ctnb" SIMCOM_SendAT(pHandle, "AT+CGNAPN"); //發送AT指令 pHandle->pClearRxData(); //清除接收計數器 if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 10, 2000)) //等待響應,超時2000MS { p = strstr((const char*)pData, "+CGNAPN: 1,\""); //搜索字符+CGNAPN: 1," if(p != NULL) //搜索成功 { p += strlen("+CGNAPN: 1,\""); for(i = 0;i < 17;i ++) { if(p[i] == '\"') //結束符號位 ” { pAPN[i] = 0; if(i == 0) break; //太短了 return TRUE; } pAPN[i] = p[i]; } } } SIMCOM_Ready(pHandle); //等待就緒 pHandle->pDelayMS(1000); //失敗延時1秒后重試 retry --; }while(retry); return FALSE; }
//SIMCOM_GSM.h
/************************************************************************************************************* * 文件名: SIMCOM_GSM.h * 功能: SIMCOM GSM相關接口 * 作者: cp1300@139.com * 創建時間: 2015-02-15 * 最后修改時間: 2018-03-23 * 詳細: *************************************************************************************************************/ #ifndef _SIMCOM_GSM_H_ #define _SIMCOM_GSM_H_ #include "system.h" #include "simcom.h" bool SIMCOM_NetworkConfig(SIMCOM_HANDLE *pHandle, SIMCOM_MODE_TYPE ModeType, NETWORK_CONFIG_TYPE *pConfig); //SIMCOM網絡配置 SIM_CARD_STATUS SIMCOM_GetCPIN(SIMCOM_HANDLE *pHandle); //獲取SIM卡狀態 SIMCOM_NETSTATUS SIM900_GetGSMNetworkStatus(SIMCOM_HANDLE *pHandle); //獲取GSM網絡注冊狀態 SIMCOM_NETSTATUS SIMCOM_GetDataNetworkStatus(SIMCOM_HANDLE *pHandle); //獲取數據網絡注冊狀態 bool SIMCOM_ModuleInit(SIMCOM_HANDLE *pHandle); //初始化SIMCOM模塊基本配置(不允許失敗) bool SIMCOM_GetModuleInfo(SIMCOM_HANDLE *pHandle, SIMCOM_INFO *pInfo); //獲取模塊的相關信息 bool SIMCOM_COPS(SIMCOM_HANDLE *pHandle, char pCOPS_Buff[SIMCOM_INFO_SIZE]); //獲取運營商名稱 SIMCOM_NETMODE_TYPE SIM7XXX_GetNetworkMode(SIMCOM_HANDLE *pHandle); //獲取SIM7XXX系列模塊網絡制式 bool SIMCOM_HardwarePowerUP(SIMCOM_HANDLE *pHandle, bool isTest); //SIMCOM模塊硬件開機 bool SIMCOM_HardwarePowerDOWN(SIMCOM_HANDLE *pHandle, bool isTest); //SIMCOM模塊硬件關機 SIMCOM_MODE_TYPE SIMCOM_GetMode(SIMCOM_HANDLE *pHandle); //獲取SIMCOM模塊的型號 int SIMCOM_GetSignal(SIMCOM_HANDLE *pHandle); //獲取信號強度 bool SIMCOM_GetBookNumber(SIMCOM_HANDLE *pHandle, u8 index, char pPhoneNumber[16]); //從電話簿獲取一個電話號碼(不能用於SIM7000) bool SIMCOM_GetPhoneNumber(SIMCOM_HANDLE *pHandle, char pPhoneNumber[16]); //獲取本機號碼(會去掉前面的86,限制長度15位,不能用於SIM7000,SIM2000以及電信卡) bool SIMCOM_GetServeNumber(SIMCOM_HANDLE *pHandle, char pPhoneNumber[16]); //獲取短信服務中心號碼(會去掉前面的86,限制長度15位,不能用於SIM7000,SIM2000以及電信卡) bool SIMCOM_GetCIMI(SIMCOM_HANDLE *pHandle, char pCIMI[16]); //獲取SIM卡CIMI號碼(SIM卡唯一id,必須存在) bool SIM7000C_GetNB_APN(SIMCOM_HANDLE *pHandle, char pAPN[17]); //獲取SIM7000C NBIOT 接入點 #endif /*_SIMCOM_GSM_H_*/
//SIMCOM_USER.c
/************************************************************************************************************* * 文件名: SIMCOM_USER.c * 功能: SIMCOM用戶層函數 * 作者: cp1300@139.com * 創建時間: 2015-02-15 * 最后修改時間: 2018-03-23 * 詳細: *************************************************************************************************************/ #include "system.h" #include "usart.h" #include "string.h" #include "ucos_ii.h" #include "SIMCOM_USER.h" #include "SIMCOM_GSM.h" #include "SIMCOM_GPRS.h" #include "SIMCOM_AT.h" #include "SIMCOM.h" bool g_SIMC0M_USER_Debug = TRUE; //應用層指令調試狀態 //調試開關 #define SIMCOM_USER_DBUG 1 #if SIMCOM_USER_DBUG #include "system.h" #define SIMCOM_USER_debug(format,...) {if(g_SIMC0M_USER_Debug){uart_printf(format,##__VA_ARGS__);}} #else #define SIMCOM_USER_debug(format,...) /\ / #endif //SIMCOM_USER_DBUG const char *const SIMCOM_NETWORK_NAME[18] = {"未注冊","GSM","GPRS","EGPRS (EDGE)","WCDMA","HSDPA only(WCDMA)","HSUPA only(WCDMA)","HSPA (HSDPA and HSUPA, WCDMA)", "LTE","TDS-CDMA","TDS-HSDPA only","TDS-HSUPA only","TDS- HSPA (HSDPA and HSUPA)","CDMA","EVDO","HYBRID (CDMA and EVDO)","1XLTE(CDMA and LTE)","未知,錯誤"}; /************************************************************************************************************************* * 函數 : bool SIMCOM_Init(SIMCOM_HANDLE *pHandle, bool (* pSendData)(u8 *pDataBuff, u16 DataLen), int (* pReadData)(u8 **pDataBuff, u8 ByteTimeOutMs, u16 TimeOutMs, u16 *pReceiveDelay), void (*pClearRxData)(void), void (*pSetDTR_Pin)(u8 Level), void (*pSetPWRKEY_Pin)(u8 Level), u8 (*pGetSTATUS_Pin)(void), u8 (*pGetDCD_Pin)(void), void (*pDelayMS)(u32 ms), void (*pIWDG_Feed)(void) * 功能 : 初始化SIMCOM句柄接口 * 參數 : pSl651_Handle:句柄; pSendCallBack:發送回調函數(pDataBuff:發送數據緩沖區,DataLen:發送數據長度) pReadCallBack:接收數據回調函數,會等待直到數據被寫入到接收緩沖區(pDataBuff:接收數據緩沖區,ByteTimeOut:等待的字節超時時間,單位ms,TimeOut:數據包超時時間,單位ms) pClearRxData:清除接收緩沖區函數,用於清除接收數據緩沖區數據 pSetDTR_Pin:DTR引腳電平控制-用於控制sleep模式或者退出透傳模式 pSetPWRKEY_Pin:PWRKEY開機引腳電平控制-用於開機 pGetSTATUS_Pin:獲取STATUS引腳電平-用於指示模塊上電狀態 pGetDCD_Pin:獲取DCD引腳電平-高電平AT指令模式,低電平為透傳模式 pDelayMS:系統延時函數 pIWDG_Feed:清除系統看門狗(可以為空) * 返回 : 無 * 依賴 : TRUE:成功,FALSE:失敗 * 作者 : cp1300@139.com * 時間 : 2018-03-24 * 最后修改時間 : 2018-03-24 * 說明 : 除pIWDG_Feed接口可以為空,其余接口均不能為空,否則程序會崩潰 *************************************************************************************************************************/ bool SIMCOM_Init(SIMCOM_HANDLE *pHandle, bool (* pSendData)(u8 *pDataBuff, u16 DataLen), //發送數據接口,如果發送失敗,返回FALSE,成功返回TRUE; int (* pReadData)(u8 **pDataBuff, u8 ByteTimeOutMs, u16 TimeOutMs, u16 *pReceiveDelay), //接收數據接口,返回數據長度,如果失敗返回<=0,成功,返回數據長度 void (*pClearRxData)(void), //清除接收緩沖區函數,用於清除接收數據緩沖區數據 void (*pSetDTR_Pin)(u8 Level), //DTR引腳電平控制-用於控制sleep模式或者退出透傳模式 void (*pSetPWRKEY_Pin)(u8 Level), //PWRKEY開機引腳電平控制-用於開機 u8 (*pGetSTATUS_Pin)(void), //獲取STATUS引腳電平-用於指示模塊上電狀態 u8 (*pGetDCD_Pin)(void), //獲取DCD引腳電平-高電平AT指令模式,低電平為透傳模式 void (*pDelayMS)(u32 ms), //系統延時函數 void (*pIWDG_Feed)(void) //清除系統看門狗(可以為空) ) { if(pHandle == NULL) { DEBUG("無效的句柄!\r\n"); return FALSE; } //所需變量 pHandle->SimcomModeType = SIMCOM_INVALID; //模塊型號 pHandle->TelecomCarr[0] = 0; //運營商名稱 memset(&pHandle->SIMCOM_Info, 0, sizeof(SIMCOM_INFO)); //SIMCOM通信模塊相關信息結構體 memset(&pHandle->NetworkConfig, 0, sizeof(NETWORK_CONFIG_TYPE)); //網絡模式設置 pHandle->NetworkMode = SIMCOM_NETMODE_NULL; //當前網絡制式 //底層通信接口 pHandle->pSendData = pSendData; //發送數據接口,如果發送失敗,返回FALSE,成功返回TRUE; pHandle->pReadData = pReadData; //接收數據接口,返回數據長度,如果失敗返回<=0,成功,返回數據長度 pHandle->pClearRxData = pClearRxData; //清除接收緩沖區函數,用於清除接收數據緩沖區數據 pHandle->pSetDTR_Pin = pSetDTR_Pin; //DTR引腳電平控制-用於控制sleep模式或者退出透傳模式 pHandle->pSetPWRKEY_Pin = pSetPWRKEY_Pin; //PWRKEY開機引腳電平控制-用於開機 pHandle->pGetSTATUS_Pin = pGetSTATUS_Pin; //獲取STATUS引腳電平-用於指示模塊上電狀態 pHandle->pGetDCD_Pin = pGetDCD_Pin; //獲取DCD引腳電平-高電平AT指令模式,低電平為透傳模式 //系統接口 pHandle->pDelayMS = pDelayMS; //系統延時函數 pHandle->pIWDG_Feed = pIWDG_Feed; //清除系統看門狗(可以為空) //內部狀態定義 pHandle->s_isInitStatus = FALSE; //用於記錄模塊初始化狀態,復位或上電后變為無效 //檢查是否有接口為空 if(pHandle->pSendData==NULL || pHandle->pReadData==NULL || pHandle->pClearRxData==NULL || pHandle->pSetDTR_Pin==NULL || pHandle->pSetPWRKEY_Pin==NULL || pHandle->pGetSTATUS_Pin==NULL || pHandle->pGetDCD_Pin==NULL || pHandle->pDelayMS==NULL) { DEBUG("錯誤,有回調接口為空!\r\n"); return FALSE; } return TRUE; } /************************************************************************************************************************* * 函數 : void SIMCOM_PrintfModel(SIMCOM_HANDLE *pHandle, SIMCOM_MODE_TYPE ModeType, const char **pModeInof) * 功能 : 顯示並打印模塊型號 * 參數 : pHandle:句柄;ModeType:模塊型號;pModeInof:返回模塊型號信息(不需要可以為空) * 返回 : 無 * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2017-10-17 * 最后修改時間 : 2018-03-24 * 說明 : *************************************************************************************************************************/ void SIMCOM_PrintfModel(SIMCOM_HANDLE *pHandle, SIMCOM_MODE_TYPE ModeType, const char **pModeInof) { switch(ModeType) { case SIMCOM_SIM900 : //默認為SIM900 { if(pModeInof!=NULL) *pModeInof = "SIM900系列";//通信模塊型號 uart_printf("[DTU]通信模塊為SIM900\r\n"); }break; case SIMCOM_SIM800 : //SIM800 { if(pModeInof!=NULL) *pModeInof = "SIM800系列"; //通信模塊型號 uart_printf("[DTU]通信模塊為SIM800\r\n"); }break; case SIMCOM_SIM2000 : //SIM2000 { if(pModeInof!=NULL) *pModeInof = "SIM2000系列"; //通信模塊型號 uart_printf("[DTU]通信模塊為SIM2000\r\n"); }break; case SIMCOM_SIM7600 : //SIM7600 { if(pModeInof!=NULL) *pModeInof = "SIM7600系列"; //通信模塊型號 uart_printf("[DTU]通信模塊為SIM7600\r\n"); }break; case SIMCOM_SIM868: //SIM868 { if(pModeInof!=NULL) *pModeInof = "SIM868系列"; //通信模塊型號 uart_printf("[DTU]通信模塊為SIM868模塊\r\n"); }break; case SIMCOM_SIM7000C: //SIM7000C { if(pModeInof!=NULL) *pModeInof = "SIM7000C系列"; //通信模塊型號 uart_printf("[DTU]通信模塊為SIM7000C\r\n"); }break; case LYNQ_L700: //LYNQ_L700 { if(pModeInof!=NULL) *pModeInof = "L700系列"; //通信模塊型號 uart_printf("[DTU]通信模塊為L700模塊\r\n"); }break; case SIMCOM_INVALID : //無效則默認 { if(pModeInof!=NULL) *pModeInof = "未知"; //通信模塊型號 uart_printf("[DTU]通信模塊未知!\r\n"); }break; } } /************************************************************************************************************************* * 函數 : SIMCOM_USER_ERROR SIMCOM_RegisNetwork(SIMCOM_HANDLE *pHandle, u16 Retry, u16 NetworkDelay,const char **pModeInof) * 功能 : SIMCOM模塊上電初始化並注冊網絡 * 參數 : pHandle:句柄;Retry:初始化重試次數>0;NetworkDelay:注冊網絡延時時間,單位S;pModeInof:返回模塊型號信息(不需要可以為空) * 返回 : SIMCOM_USER_ERROR * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2014-08-18 * 最后修改時間 : 2018-03-24 * 說明 : 用於通信模塊上電並初始化操作 *************************************************************************************************************************/ SIMCOM_USER_ERROR SIMCOM_RegisNetwork(SIMCOM_HANDLE *pHandle, u16 Retry, u16 NetworkDelay,const char **pModeInof) { SIMCOM_NETSTATUS NetStatus; SIMCOM_MODE_TYPE ModeType = SIMCOM_INVALID; //初始化模塊型號無效 SIMCOM_NETMODE_TYPE NetworkMode = SIMCOM_NETMODE_NULL; //初始化為未知模式 SIMCOM_USER_ERROR Error = SIMCOM_NULL_ERROR; //初始化狀態 u16 pcnt,cnt; u8 NotCnt,SeaCnt,TurCnt,UnkCnt,ErrCnt; bool isCart = FALSE; u8 SIM_NotReadyCnt = 0; //SIM卡未准備就緒計數器 Retry += 1; //重試次數至少1次 //模塊上電 for(pcnt = 0;pcnt < Retry;pcnt ++) //上電循環 { SIM_NotReadyCnt = 0; //SIM卡未准備就緒計數器復位 if(pHandle->pIWDG_Feed!=NULL) pHandle->pIWDG_Feed(); //喂狗 if(pHandle->pGetSTATUS_Pin()==SIMCOM_L_LEVEL) //模塊沒有上電 { pHandle->s_isInitStatus = FALSE; //模塊沒有初始化 SIMCOM_USER_debug("[SIMCOM]:模塊沒有上電!\r\n"); if(SIMCOM_HardwarePowerUP(pHandle, TRUE) == TRUE) //上電 { SIMCOM_USER_debug("[SIMCOM]:開機成功!\r\n"); if(SIMCOM_TestAT(pHandle, 50) != TRUE) //發送AT測試命令 { if(pModeInof!=NULL) *pModeInof = "模塊未知"; SIMCOM_USER_debug("[SIMCOM]:通信錯誤,串口錯誤!\r\n"); } } else { if(pModeInof!=NULL) *pModeInof = "模塊未知"; SIMCOM_USER_debug("[SIMCOM]:開機失敗!\r\n"); Error = SIMCOM_POWER_UP_ERROR; //開機失敗 } } //上電完畢后初始化模塊 if(pHandle->pGetSTATUS_Pin() == SIMCOM_H_LEVEL) { //模塊初始化網絡 if(NetworkDelay == 0) NetworkDelay = 0xffff; //為0,一直等待 NotCnt=SeaCnt=TurCnt=UnkCnt=ErrCnt=0; //初始化注冊狀態計數器為0 //獲取模塊型號 if(ModeType == SIMCOM_INVALID) { SIMCOM_SetParametersReturnBool(pHandle, "ATE 0", SIMCOM_DEFAULT_RETRY, 110, "\r\n關閉AT回顯模式失敗!\r\n"); pHandle->pDelayMS(500); ModeType = SIMCOM_GetMode(pHandle); //獲取模塊型號 SIMCOM_PrintfModel(pHandle, ModeType, pModeInof); //打印顯示通信模塊型號 } //型號獲取成功了,更新信息 if(ModeType!=SIMCOM_INVALID) { pHandle->SimcomModeType = ModeType; //上電初始化設置通信模塊型號 } //根據模塊類型進行初始化,如果是SIM7000C,需要選擇工作在GSM模式還是NBIOT模式 if(SIMCOM_NetworkConfig(pHandle, ModeType, &pHandle->NetworkConfig)==FALSE) { uart_printf("[DTU]初始化通信模塊網絡模式失敗了!\r\n"); } //初始化獲取網絡信息 for(cnt = 0;cnt < NetworkDelay;cnt ++) { if(pHandle->pGetSTATUS_Pin()==SIMCOM_L_LEVEL) { Error = SIMCOM_POWER_UP_ERROR; //異常斷電 uart_printf("[DTU]異常斷電了,請檢查供電是否穩定!\r\n"); break; //模塊沒有上電,初始化 } if(ModeType == SIMCOM_INVALID) { SIMCOM_SetParametersReturnBool(pHandle, "ATE 0", SIMCOM_DEFAULT_RETRY, 110, "\r\n關閉AT回顯模式失敗!\r\n"); pHandle->pDelayMS(500); ModeType = SIMCOM_GetMode(pHandle); //獲取模塊型號 pHandle->SimcomModeType = ModeType; //上電初始化設置通信模塊型號 SIMCOM_PrintfModel(pHandle, ModeType, pModeInof); //打印顯示通信模塊型號 } if(isCart == FALSE) //卡未檢測到,則一直重新檢測 { if(SIMCOM_GetCPIN(pHandle)==SIM_READY) { isCart = TRUE; //卡檢測成功 uart_printf("\r\nSIM卡准備就緒!\r\n"); } else { uart_printf("\r\nSIM卡未准備就緒!\r\n"); Error = SIMCOM_SIM_NOT_REALYE; //卡未就緒 } } //2018-01-18 增加SIM7000C NB模式網絡注冊狀態獲取支持 if((ModeType == SIMCOM_SIM7000C) && (pHandle->NetworkConfig.NB_EnableMode==1)) //如果是SIM7000C,並且開啟了NB模式 { NetStatus = SIMCOM_GetDataNetworkStatus(pHandle); //獲取數據網絡網絡注冊狀態 } else { NetStatus = SIM900_GetGSMNetworkStatus(pHandle); //獲取GSM網絡注冊狀態 } SIMCOM_USER_debug("[DTU]網絡注冊狀態%d!\r\n",NetStatus); //一直出現網絡未注冊以及注冊拒絕,重啟,有些卡會先出現拒絕,然后出現注冊成功 switch(NetStatus) { case SIMCOM_NET_NOT : { NotCnt++; //2017-09-09 增加如果連續15次未檢測到卡,並且未注冊,則直接退出,返回未插卡 if(SIMCOM_GetCPIN(pHandle)==SIM_NOT_READY) { Error = SIMCOM_SIM_NOT_REALYE; //卡未就緒 SIM_NotReadyCnt ++; //SIM卡未准備就緒計數器增加 } else { SIM_NotReadyCnt = 0; //SIM卡未就緒計數器復位 } }break; //未注冊 case SIMCOM_NET_ROA : //已經注冊,但是漫游 case SIMCOM_NET_YES : //已經注冊 { SIM_NotReadyCnt = 0; //SIM卡未就緒計數器復位 if(pHandle->s_isInitStatus == FALSE)//模塊沒有初始化 { if(SIMCOM_ModuleInit(pHandle) == FALSE) //上電后初始化模塊基本配置 { SIMCOM_USER_debug("[DTU]初始化失敗!\r\n"); if(isCart==TRUE) Error = SIMCOM_INIT_ERROR; //卡初始化成功了,才返回初始化錯誤 goto reset; } } //獲取模塊信息 if( SIMCOM_GetModuleInfo(pHandle, &pHandle->SIMCOM_Info) == TRUE) //獲取模塊的相關信息 { SIMCOM_USER_debug("\r\n制造商:%s\r\n",pHandle->SIMCOM_Info.Manu); SIMCOM_USER_debug("模塊型號:%s\r\n",pHandle->SIMCOM_Info.Model); SIMCOM_USER_debug("軟件版本:%s\r\n",pHandle->SIMCOM_Info.Ver); SIMCOM_USER_debug("模塊序列號:%s\r\n",pHandle->SIMCOM_Info.IMEI); } else { SIMCOM_USER_debug("\r\n獲取模塊信息失敗!\r\n"); } //獲取運營商信息 if(SIMCOM_COPS(pHandle, pHandle->TelecomCarr) == TRUE) //獲取運營商名稱 { SIMCOM_USER_debug("運營商信息:%s\r\n", pHandle->TelecomCarr); } else { SIMCOM_USER_debug("獲取運營商信息失敗!\r\n"); } //如果是SIM7600 SIM7000C模塊,則需要獲取網絡制式 switch(ModeType) { case SIMCOM_SIM7600: case SIMCOM_SIM7000C: { NetworkMode = SIM7XXX_GetNetworkMode(pHandle); //獲取SIM7XXX系列模塊網絡制式 pHandle->NetworkMode = NetworkMode; //記錄全局網絡制式,必須在獲取短信中心號碼之前進行獲取,因為電信卡無短信中心號碼用於初始化 if(NetworkMode > 16) { SIMCOM_USER_debug("網絡制式:獲取失敗\r\n"); } else { SIMCOM_USER_debug("網絡制式:%s\r\n",SIMCOM_NETWORK_NAME[NetworkMode]); } }break; default: //2G { pHandle->NetworkMode = SIMCOM_NETMODE_GSM; //其它2G模塊默認GSM網絡 }break; } Error = SIMCOM_INIT_OK; //初始化成功 return Error; //已經注冊並初始化了 } case SIMCOM_NET_SEA : SeaCnt++;break; //未注冊,正在搜索 case SIMCOM_NET_TUR : TurCnt++;break; //注冊被拒絕 case SIMCOM_NET_UNK : UnkCnt++;break; //未知 default : ErrCnt++;break; //錯誤 } if((TurCnt > 60) || (UnkCnt > 20) || (ErrCnt > 20)) //注冊被拒絕,或者錯誤 { if(isCart==TRUE) Error = SIMCOM_REG_ERROR; //卡初始化成功了,才返回初注冊失敗 SIMCOM_USER_debug("[DTU]模塊重啟!\r\n"); if(SIMCOM_HardwarePowerDOWN(pHandle, TRUE) == FALSE) { SIMCOM_USER_debug("[DTU]:關機失敗!\r\n"); } break; } //SIM卡未就緒次數過多 if(SIM_NotReadyCnt > 16) { uart_printf("[DTU]:多次檢測到卡未就緒!模塊重啟!\r\n"); if(SIMCOM_HardwarePowerDOWN(pHandle, TRUE) == FALSE) { SIMCOM_USER_debug("[DTU]:關機失敗!\r\n"); } break; } //延時 pHandle->pDelayMS(800); if(pHandle->pIWDG_Feed!=NULL) pHandle->pIWDG_Feed(); //喂狗 } //網絡注冊失敗或模塊初始化失敗 reset: if(SIMCOM_HardwarePowerDOWN(pHandle, TRUE) == TRUE) //關閉電源 { uart_printf("[DTU]:網絡初始化失敗,模塊關機成功!\r\n"); } else { uart_printf("[DTU]:網絡初始化失敗,模塊關機失敗!\r\n"); } } else { Error = SIMCOM_POWER_UP_ERROR; //開機失敗 } } //顯示錯誤信息 switch(Error) { case SIMCOM_INIT_OK : //初始化成功 { uart_printf("[DTU]:模塊上電或初始成功!\r\n"); }break; case SIMCOM_POWER_UP_ERROR : //上電錯誤 { uart_printf("[DTU]:模塊上電錯誤!\r\n"); }break; case SIMCOM_REG_ERROR : //注冊出錯(超時) { uart_printf("[DTU]:模塊注冊網絡出錯(超時)!\r\n"); }break; case SIMCOM_INIT_ERROR : //初始化配置錯誤 { uart_printf("[DTU]:模塊初始化配置出錯!\r\n"); }break; case SIMCOM_SIM_NOT_REALYE : //SIM卡未就緒導致上電失敗 { uart_printf("[DTU]:模塊SIM卡未就緒!\r\n"); }break; default: { uart_printf("[DTU]:未知的錯誤!\r\n"); }break; } return Error; } /************************************************************************************************************************* * 函數 : bool SIMCOM_PhoneMessageNumberInitialize(SIMCOM_HANDLE *pHandle, u8 retry) * 功能 : SIMCOM 初始化獲取短信中心號碼以及本機號碼,信號強度,CIMI(結果存放在句柄pHandle中) * 參數 : pHandle:句柄;Retry:初始化重試次數>0 * 返回 : TRUE成功,FALSE:失敗 * 依賴 : 底層 * 作者 : cp1300@139.com * 時間 : 2014-08-18 * 最后修改時間 : 2018-03-24 * 說明 : 用於網絡初始化之后進行初始化獲取相關信息,需要提前初始化網絡模塊型號以及網絡制式 短信中心號碼存放在:pHandle->ServiceCenterPhoneNumber; 電話號碼存放在:pHandle->LocalPhoneNumber; 信號強度存放在:pHandle->Singal; SIM卡CIMI號碼存放在pHandle->SIM_CIMI; 2016-06-15:SIM2000C使用電信SIM卡時,過快讀取本機號碼會失敗,增加延時,確保讀取成功 2016-11-16:增加獲取短信中心號碼延時 2017-12-05:NBIO 模塊不讀取電話號碼 *************************************************************************************************************************/ bool SIMCOM_PhoneMessageNumberInitialize(SIMCOM_HANDLE *pHandle, u8 retry) { u8 i; //重試計數器 int Singal; bool status; bool isReadServerNumber = TRUE; //是否需要獲取短信中心號碼,電信卡無需獲取 //測試AT指令 SIMCOM_Ready(pHandle); if(SIMCOM_TestAT(pHandle, 20) != TRUE) { return FALSE; } retry += 1; //獲取短信中心號碼 if(pHandle->SimcomModeType == SIMCOM_SIM2000) //電信模塊無需獲取短信中心號碼 { isReadServerNumber = FALSE; } else if(pHandle->SimcomModeType == LYNQ_L700) //L700 NBIOT 無需獲取短信中心號碼 { isReadServerNumber = FALSE; } else if(pHandle->SimcomModeType==SIMCOM_SIM7000C) //SIM7000C { isReadServerNumber = FALSE; //sim7000不支持 } else if(pHandle->SimcomModeType==SIMCOM_SIM7600) //SIM7600 { switch(pHandle->NetworkMode) //查看網絡制式,如果是CDMA(電信卡)則不需要獲取短信中心號碼 { case SIMCOM_NETMODE_CDMA ://CDMA case SIMCOM_NETMODE_EVDO ://EVDO case SIMCOM_NETMODE_HYBRID ://HYBRID (CDMA and EVDO) case SIMCOM_NETMODE_1XLTE ://1XLTE(CDMA and LTE) { isReadServerNumber = FALSE; }break; } } if(isReadServerNumber) //需要獲取短信中心號碼 { for(i = 0;i < retry;i ++) { if(SIMCOM_GetServeNumber(pHandle, pHandle->ServiceCenterPhoneNumber) == TRUE) //獲取短信服務中心號碼成功 { if(pHandle->ServiceCenterPhoneNumber[0] == 0) { SIMCOM_USER_debug("短信中心號碼為空\r\n"); } else { SIMCOM_USER_debug("短信中心號碼:%s\r\n",pHandle->ServiceCenterPhoneNumber); } break; } else { SIMCOM_WaitSleep(pHandle, 100); SIMCOM_Ready(pHandle); pHandle->pDelayMS(1000); } } if(i==retry) return FALSE; } else { pHandle->pDelayMS(2000); //等待2s鍾 strcpy(pHandle->ServiceCenterPhoneNumber, "13800818500"); //短信中心號碼-固定值,防止為空 SIMCOM_USER_debug("[缺省]短信中心號碼:%s\r\n",pHandle->ServiceCenterPhoneNumber); } //獲取信號強度 for(i = 0;i < retry;i ++) { Singal = SIMCOM_GetSignal(pHandle); //獲取信號強度 if((Singal > 0) && (Singal!=99)) { pHandle->Singal = (u8)Singal; SIMCOM_USER_debug("信號強度 <%02d>!\r\n" ,Singal); break; } else { pHandle->Singal = 0; //沒有讀取到,延時2秒 pHandle->pDelayMS(2000); //等待2s鍾 } SIMCOM_WaitSleep(pHandle, 100); SIMCOM_Ready(pHandle); pHandle->pDelayMS(1000); //等待1s鍾 } //獲取本機號碼 for(i = 0;i < retry;i ++) { if(pHandle->NetworkMode == LYNQ_L700) //L700 NBIOT 無法獲取 { pHandle->pDelayMS(1000); //等待1s鍾 pHandle->LocalPhoneNumber[0] = 0; return TRUE; } else if(pHandle->NetworkMode == SIMCOM_SIM7000C) //SIM7000C 無法獲取 { pHandle->pDelayMS(1000); //等待1s鍾 pHandle->LocalPhoneNumber[0] = 0; return TRUE; } else if(pHandle->SimcomModeType==SIMCOM_SIM7600) //SIM7600,SIM7000C { switch(pHandle->NetworkMode) //查看網絡制式,如果是CDMA(電信卡)則不需要獲取短信中心號碼 { case SIMCOM_NETMODE_CDMA ://CDMA case SIMCOM_NETMODE_EVDO ://EVDO case SIMCOM_NETMODE_HYBRID ://HYBRID (CDMA and EVDO) case SIMCOM_NETMODE_1XLTE ://1XLTE(CDMA and LTE) { status = SIMCOM_GetBookNumber(pHandle, 1, pHandle->LocalPhoneNumber); //從電話簿中讀取一個電話號碼 }break; default: //其他制式可以讀取 { status = SIMCOM_GetPhoneNumber(pHandle, pHandle->LocalPhoneNumber); //讀取本機號碼 }break; } } else if(pHandle->SimcomModeType == SIMCOM_SIM2000) //SIM2000 { status = SIMCOM_GetBookNumber(pHandle, 1, pHandle->LocalPhoneNumber); //從電話簿中讀取一個電話號碼 } else //其它模塊 { status = SIMCOM_GetPhoneNumber(pHandle, pHandle->LocalPhoneNumber); //讀取本機號碼 } if(status== TRUE) //獲取本機號碼成功 { pHandle->LocalPhoneNumber[15] = 0; if(pHandle->LocalPhoneNumber[0] == 0) { SIMCOM_USER_debug("本機號碼為空\r\n"); } else { SIMCOM_USER_debug("本機號碼:%s\r\n",pHandle->LocalPhoneNumber); } break; } else { SIMCOM_WaitSleep(pHandle, 100); SIMCOM_Ready(pHandle); pHandle->pDelayMS(2000); //等待2s鍾 } } if(i==retry) return FALSE; //獲取SIM卡CIMI號碼 for(i = 0;i < retry;i ++) { //獲取SIM卡CIMI號碼(SIM卡唯一id,必須存在) if(SIMCOM_GetCIMI(pHandle, pHandle->SIM_CIMI) == TRUE) break; SIMCOM_WaitSleep(pHandle, 100); SIMCOM_Ready(pHandle); pHandle->pDelayMS(1000); //等待1s鍾 } if(i==retry) return FALSE; return TRUE; }
//SIMCOM_USER.h
/************************************************************************************************************* * 文件名: SIMCOM_USER.h * 功能: SIMCOM用戶層函數 * 作者: cp1300@139.com * 創建時間: 2015-02-15 * 最后修改時間: 2018-03-23 * 詳細: *************************************************************************************************************/ #ifndef _SIMCOM_SUER_H_ #define _SIMCOM_SUER_H_ #include "system.h" #include "simcom.h" //SIMCOM 初始化錯誤 typedef enum { SIMCOM_INIT_OK = 0, //初始化成功 SIMCOM_POWER_UP_ERROR = 1, //上電錯誤 SIMCOM_REG_ERROR = 2, //注冊出錯(超時) SIMCOM_INIT_ERROR = 3, //初始化配置錯誤 SIMCOM_SIM_NOT_REALYE = 4, //SIM卡未就緒導致上電失敗 SIMCOM_NULL_ERROR = 255 //狀態無效 }SIMCOM_USER_ERROR; //API //初始化SIMCOM句柄接口 bool SIMCOM_Init(SIMCOM_HANDLE *pHandle, bool (* pSendData)(u8 *pDataBuff, u16 DataLen), //發送數據接口,如果發送失敗,返回FALSE,成功返回TRUE; int (* pReadData)(u8 **pDataBuff, u8 ByteTimeOutMs, u16 TimeOutMs, u16 *pReceiveDelay), //接收數據接口,返回數據長度,如果失敗返回<=0,成功,返回數據長度 void (*pClearRxData)(void), //清除接收緩沖區函數,用於清除接收數據緩沖區數據 void (*pSetDTR_Pin)(u8 Level), //DTR引腳電平控制-用於控制sleep模式或者退出透傳模式 void (*pSetPWRKEY_Pin)(u8 Level), //PWRKEY開機引腳電平控制-用於開機 u8 (*pGetSTATUS_Pin)(void), //獲取STATUS引腳電平-用於指示模塊上電狀態 u8 (*pGetDCD_Pin)(void), //獲取DCD引腳電平-高電平AT指令模式,低電平為透傳模式 void (*pDelayMS)(u32 ms), //系統延時函數 void (*pIWDG_Feed)(void) //清除系統看門狗(可以為空) ); SIMCOM_USER_ERROR SIMCOM_RegisNetwork(SIMCOM_HANDLE *pHandle, u16 Retry, u16 NetworkDelay,const char **pModeInof);//SIMCOM模塊上電初始化並注冊網絡 bool SIMCOM_PhoneMessageNumberInitialize(SIMCOM_HANDLE *pHandle, u8 retry); //SIMCOM 初始化獲取短信中心號碼以及本機號碼,信號強度,CIMI(結果存放在句柄pHandle中) #endif /*_SIMCOM_SUER_H_*/
//底層相關接口,自己根據自己的平台進行開發的接口
//發送數據接口 static bool GPRS_UART_SendData(u8 DataBuff[], u16 DataLen) { UARTx_SendData(SIMCOM_UART_CH, DataBuff, DataLen); return TRUE; } //接收數據接口 static int GPRS_UART_ReadData(u8 **pDataBuff,u8 ByteTimeOutMs, u16 TimeOutMs, u16 *pReceiveDelayMs) { u32 cnt = 0; u16 TempTime; if(ByteTimeOutMs < 1) ByteTimeOutMs = 1; //字節超時時間,2個幀之間的間隔最小時間 TimeOutMs /= ByteTimeOutMs; TimeOutMs += 1; TempTime = TimeOutMs; while(TimeOutMs --) { cnt = UARTx_GetRxCnt(SIMCOM_UART_CH); OSTimeDlyHMSM(0,0,0,ByteTimeOutMs);; if((cnt > 0) && (cnt == UARTx_GetRxCnt(SIMCOM_UART_CH))) { if(pReceiveDelayMs!=NULL) //需要返回延時 { *pReceiveDelayMs = (TempTime-TimeOutMs)*ByteTimeOutMs; } *pDataBuff = g_SIMCOM_Buff; //接收緩沖區 return cnt; } #if SYS_WDG_EN_ IWDG_Feed(); //喂狗 #endif } return 0; } //清除接收緩沖區 static void GPRS_UART_ClearData(void) { UARTx_ClearRxCnt(SIMCOM_UART_CH); //清除串口緩沖區 }
///////////////////////////////////////////////////////////////////////////////////////////// //SIM900/SIM800通信支持 //GSM模塊相關定義 #define SIMCOM_UART_CH UART_CH3 //串口3 #define SIMCOM_UART_BAUD 115200 //波特率 #define SIMCOM_UART_BUFF_SIZE (1024*4) //接收緩沖區大小 //相關控制引腳 __inline void SIMCOM_SetDTR(u8 Level) {(PGout(4)=Level);} //DTR __inline void SIMCOM_SetPWRKEY(u8 Level) {(PGout(3)=Level);} //PWRKEY __inline u8 SIMCOM_GetSTATUS(void) {return PGin(5)?1:0;} //STATUS __inline u8 SIMCOM_GetDCD(void) {return PDin(11)?1:0;} //DCD-上拉輸入,高電平AT指令模式,低電平為透傳模式 //引腳初始化 __inline void SIMCOM_IO_Init(void) { SYS_DeviceClockEnable(DEV_GPIOD, TRUE); //使能GPIOD時鍾 SYS_DeviceClockEnable(DEV_GPIOG, TRUE); //使能GPIOG時鍾 SYS_GPIOx_Init(GPIOG, BIT3|BIT4, OUT_PP, SPEED_2M); //推挽輸出 SYS_GPIOx_OneInit(GPIOD, 11, IN_IPU, IN_NONE); //DCD 上拉輸入 SYS_GPIOx_OneInit(GPIOG, 5, IN_IPD, IN_NONE); //STATUS 下拉輸入 }
另外還有一個看門狗清除的回調函數
//喂獨立看門狗 __inline void IWDG_Feed(void) {IWDG->KR=0XAAAA;}
//實現了以上的接口就可以調用了
//下面是應用層調用,使用了ucos的一個任務
SIMCOM_HANDLE g_SIMCOM_Handle; //SIMCOM通信模塊句柄 u8 g_SIMCOM_Buff[SIMCOM_UART_BUFF_SIZE+1]; //串口接收緩沖區 static bool GPRS_UART_SendData(u8 DataBuff[], u16 DataLen); //發送數據接口 static int GPRS_UART_ReadData(u8 **pDataBuff,u8 ByteTimeOutMs, u16 TimeOutMs, u16 *pReceiveDelayMs); //接收數據接口 static void GPRS_UART_ClearData(void); //清除接收緩沖區 //GPRS通信任務 void GPRS_Task(void *pdata) { const char *pModeInof; UARTx_Init(SIMCOM_UART_CH, SIMCOM_UART_BAUD, ENABLE); //初始化串口 UARTx_SetRxBuff(SIMCOM_UART_CH, g_SIMCOM_Buff, SIMCOM_UART_BUFF_SIZE); //設置串口接收緩沖區 SIMCOM_IO_Init(); //SIMCOM相關IO初始化 OSTimeDlyHMSM(0,0,0,20); //初始化SIMCOM句柄接口 SIMCOM_Init(&g_SIMCOM_Handle, GPRS_UART_SendData, //發送數據接口,如果發送失敗,返回FALSE,成功返回TRUE; GPRS_UART_ReadData, //接收數據接口,返回數據長度,如果失敗返回<=0,成功,返回數據長度 GPRS_UART_ClearData, //清除接收緩沖區函數,用於清除接收數據緩沖區數據 SIMCOM_SetDTR, //DTR引腳電平控制-用於控制sleep模式或者退出透傳模式 SIMCOM_SetPWRKEY, //PWRKEY開機引腳電平控制-用於開機 SIMCOM_GetSTATUS, //獲取STATUS引腳電平-用於指示模塊上電狀態 SIMCOM_GetDCD, //DCD-上拉輸入,高電平AT指令模式,低電平為透傳模式 SYS_DelayMS, //系統延時函數 IWDG_Feed //清除系統看門狗(可以為空) ); while(1) { SIMCOM_RegisNetwork(&g_SIMCOM_Handle, 6, 60, &pModeInof);//SIMCOM模塊上電初始化並注冊網絡 //SIMCOM 初始化獲取短信中心號碼以及本機號碼,信號強度,CIMI(結果存放在句柄pHandle中) if(SIMCOM_PhoneMessageNumberInitialize(&g_SIMCOM_Handle, 3) == FALSE) { uart_printf("\r\n警告:初始化獲取相關信息失敗!\r\n"); } OSTimeDlyHMSM(0,5,0,20); } }
//以上代碼實現了通信模塊的初始化,開機,聯網,讀取本機號碼,中心站號碼,SIMI碼,信號等操作,感興趣的朋友可以依照此模板進行后續的開發,使用底層分離的方式可以讓代碼解耦便於在各個平台上面移植,同時增加了穩定性。
//下面是串口打印的信息,命令執行的很快,我使用的是SIM7600CE模塊,全網通4G,初始化非常快,每個文件都有定義調試開關,可以動態使用一個變量控制開關,也可以使用宏定義控制調試信息開關。
SIMCOM(26B)-> SIMCOM_SIM7600CE OK OK 返回成功! [DTU]通信模塊為SIM7600 SIMCOM(22B)-> +CPIN: READY OK OK 返回成功! SIM卡准備就緒! SIMCOM(20B)-> +CREG: 0,1 OK OK 返回成功! SIMCOM(6B)-> OK OK 返回成功! [DTU]網絡注冊狀態1! SIMCOM(6B)-> OK OK 返回成功! SIMCOM(6B)-> OK OK 返回成功! SIMCOM(6B)-> OK OK 返回成功! SIMCOM(6B)-> OK OK 返回成功! SIMCOM(6B)-> OK OK 返回成功! SIMCOM(6B)-> OK OK 返回成功! SIMCOM(6B)-> OK OK 返回成功! SIMCOM(22B)-> +CPIN: READY OK OK 返回成功! SIM卡准備就緒! SIMCOM(6B)-> OK OK 返回成功! SIMCOM(6B)-> OK OK 返回成功! SIMCOM(6B)-> OK OK 返回成功! SIMCOM(6B)-> OK OK 返回成功! SIMCOM(6B)-> OK OK 返回成功! SIMCOM(6B)-> OK OK 返回成功! SIMCOM(35B)-> OK SIMCOM INCORPORATED OK OK 返回成功! SIMCOM(26B)-> SIMCOM_SIM7600CE OK OK 返回成功! SIMCOM(34B)-> +GMR: LE11B02SIM7600CE-A OK OK 返回成功! SIMCOM(25B)-> 861477030032237 OK OK 返回成功! 制造商:OK 模塊型號:SIMCOM_SIM7600CE 軟件版本:LE11B02SIM7600CE-A 模塊序列號:861477030032237 SIMCOM(42B)-> +COPS: 0,0,"CHINA MOBILE CMCC",7 OK OK 返回成功! 運營商信息:CHINA MOBILE CMCC SIMCOM(22B)-> +CNSMOD: 0,8 OK OK 返回成功! 網絡制式:LTE SIMCOM(6B)-> OK OK 返回成功! SIMCOM(6B)-> OK OK 返回成功! SIMCOM(37B)-> +CSCA: "+8613800100569",145 OK OK 返回成功! 短信中心號碼:13800100569 短信中心號碼:13800100569 SIMCOM(21B)-> +CSQ: 20,99 OK OK 返回成功! 信號強度 <20>! SIMCOM(41B)-> +CNUM: "","1064838905852",129 OK OK 返回成功! 本機號碼:1064838905852 本機號碼:1064838905852 SIMCOM(25B)-> 460040389005852 OK OK 返回成功! 獲取CIMI成功:460040389005852