最近在使用SIMCOM的通信模块,GSM模块SIM800以及NB-IOT模块SIM7020c,遇到一些小的问题,在这里做一个记录。
底层参考了https://blog.csdn.net/cp1300/article/details/79686460
两个模块封装可以兼容,模块上电初始化并注册网络大部分底层程序一致,从模块上电到PS业务附着成功SIM800较SIM7020c时间要长,SIM800有透传模式,SIM7020c没有透传模式,虽然手册上说明两种模块都可以进行TCP/IP连接,但是在使用时发现SIM7020c不能建立TCP连接,原因未知。
部分不能兼容的AT指令:
SIM800: AT+CREG? //获取网络注册状态
AT+CIPMODE=1 //开启透传模式
SIM7020c:AT+CGREG? //获取网络注册状态
在SIM800进入透传模式后大部分AT指令会被认为是数据被传输,但是仍可以进行如下设置进行UDP服务器连接:
AT+CSTT=\"CMNET\" //设置为APN为CMNET
AT+CIICR //建立无线链路
AT+CIFSR //获得本地IP地址 (实际使用时,在建立UDP连接时,如果省略这步操作会失败)
/*************************************************************************************************************************
* 函数 : uint8_t SIMCOM_UDP_ServerCnt(SIMCOM_HANDLE *pHandle)
* 功能 : 连接UDP服务器函数
* 参数 :
* 返回 : 连接建立状态
* 依赖 : 无
* 作者 :
* 时间 : 2018-12-23
* 最后修改时间 : 2018-12-23
* 说明 :
*************************************************************************************************************************/
int RSSI_sim=0;
uint8_t SIMCOM_UDP_ServerCnt(SIMCOM_HANDLE *pHandle)
{
// int Singal=0;
uint8_t retry;
//配置服务器IP地址 格式: "AT+CIPSTART=\"UDP\",\"47.104.137.129\",\"20030\""
const char *Server = "AT+CIPSTART=\"UDP\",\"47.104.137.129\",\"20030\""; //IP登录服务器
retry = SIMCOM_DEFAULT_RETRY;
while(retry)
{
if(SIM800_GetGPRSAdhereStatus(pHandle)!=1)
{
}
else break;
pHandle->pDelayMS(1000); //延时1秒
retry --;
}
if(retry==0)
{
printf("\r\nGPRS附着失败\r\n");
return 0;
}
RSSI_sim = SIMCOM_GetSignal(pHandle); //获取信号强度
pHandle->Singal = (uint8_t)RSSI_sim;
#if SIMCOM_USER_DBUG
printf("信号强度 <%02d>!\r\n" ,RSSI_sim);
#endif
if(SIMCOM_SetParametersReturnbool(pHandle, "AT+CSTT=\"CMNET\"", 1, 510, "\r\n设置为CMNET失败\r\n") == 0)return 0;
if(SIMCOM_SetParametersReturnbool(pHandle, "AT+CIICR", 1, 510, "\r\n 建立无线链路失败\r\n") == 0)return 0;
LED2_OFF();
SIMCOM_SetParametersReturnbool(pHandle, "AT+CIFSR", 0, 510, "\r\n");
if(SIMCOM_SetParametersReturnbool(pHandle,(char*)Server, 1, 310, "\r\n建立UDP连接失败\r\n") == 0)return 0;
// LED2_ON();
return 1;
}
在透传模式下可以直接通过串口发送数据:
/*************************************************************************************************************************
* 函数 : uint8_t SIMCOM_GSM_Transparent_Send(SIMCOM_HANDLE *pHandle,uint8_t *databuf,uint16_t datalen)
* 功能 : 发送数据
* 参数 : pHandle:SIMCOM句柄;datalen最长512
* 返回 : 连接建立状态
* 依赖 : 无
* 作者 :
* 时间 : 2018-12-23
* 最后修改时间 : 2018-12-23
* 说明 :
*************************************************************************************************************************/
uint8_t SIMCOM_GSM_Transparent_Send(SIMCOM_HANDLE *pHandle,uint8_t *databuf,uint16_t datalen)
{
pHandle->pSendData((uint8_t *)databuf, datalen);
pHandle->pClearRxData(); //清除接收计数器
HAL_UART_Receive_IT(&SIMCOM_UART_CH,(uint8_t *)g_SIMCOM,1);
}
对于SIM7020c,由于不支持透传模式,需要先建立UDP socket再发送和接收UDP数据
/*************************************************************************************************************************
* 函数 : uint8_t SIMCOM_EstablishSocket(SIMCOM_HANDLE *pHandle)
* 功能 : 建立Socket
* 参数 : pHandle:SIMCOM句柄;
* 返回 : 连接建立状态
* 依赖 : 无
* 作者 :
* 时间 : 2018-12-23
* 最后修改时间 : 2018-12-23
* 说明 :
*************************************************************************************************************************/
uint8_t SIMCOM_NB_EstablishSocket(SIMCOM_HANDLE *pHandle)
{
//配置服务器IP地址 格式:"AT+CSOCON=0,20030,\"47.104.137.122\""
const char *Server = "AT+CSOCON=0,20030,\"47.92.243.222\""; //IP登录服务器
uint8_t retry;
retry = SIMCOM_DEFAULT_RETRY; //重试次数
RSSI_sim = SIMCOM_GetSignal(pHandle); //获取信号强度
pHandle->Singal = (uint8_t)RSSI_sim;
#if SIMCOM_USER_DBUG
printf("信号强度 <%02d>!\r\n" ,RSSI_sim);
#endif
SIMCOM_SetParametersReturnbool(pHandle, "AT+CSOCL=0", SIMCOM_DEFAULT_RETRY, 110, "\r\n删除socket失败!\r\n");
while(retry)
{
//设置重试次数为2次,并且发送延时为120ms
if(SIMCOM_SetParametersReturnbool(pHandle, "AT+CSOC=1,2,1", 0, 110, "\r\n创建socket失败!\r\n") == 0) //重试次数为1
{
}
else
{
break;
}
pHandle->pDelayMS(1000); //延时1秒
retry --;
}
if(retry==0)
return 0;
retry = SIMCOM_DEFAULT_RETRY;
while(retry)
{
//设置重试次数为2次,并且发送延时为120ms
if(SIMCOM_SetParametersReturnbool(pHandle, (char*)Server, 0, 110, "\r\n创建连接失败!\r\n") == 0)
{
}
else
break;
pHandle->pDelayMS(1000); //延时1秒
retry --;
}
if(retry==0)
return 0;
else
return 1;
}
通过已建立的socket发送数据需要将数据嵌入到AT指令进行发送,
/*************************************************************************************************************************
* 函数 : uint8_t SIMCOM_Send(SIMCOM_HANDLE *pHandle,uint8_t *databuf,uint16_t datalen)
* 功能 : 发送数据
* 参数 : pHandle:SIMCOM句柄;databuf待发送数据;datalen最长255
* 返回 : 连接建立状态
* 依赖 : 无
* 作者 :
* 时间 : 2018-12-23
* 最后修改时间 : 2018-12-23
* 说明 :
*************************************************************************************************************************/
char Sdatabuff[512];
char Atbuff[560];
uint8_t SIMCOM_NB_Send(SIMCOM_HANDLE *pHandle,uint8_t *databuf,uint8_t datalen)
{
uint32_t cnt;
uint8_t retry;
uint8_t *pData;
uint16_t i;
retry = 2; //重试次数
for(i=0;ipClearRxData(); //清除接收计数器
// do
// {
SIMCOM_SendAT(pHandle,Atbuff); //发送AT命令
pHandle->pClearRxData(); //清除接收计数器
if(AT_RETURN_OK == SIMCOM_GetATResp(pHandle, &pData, &cnt, "OK", 5, 100)) //等待响应,超时10s
{
pHandle->pClearRxData(); //清除接收计数器
HAL_UART_Receive_IT(&SIMCOM_UART_CH,(uint8_t *)g_SIMCOM,1);
return 1;
}
// SIMCOM_Ready(pHandle); //等待就绪
// pHandle->pDelayMS(1000); //延时1秒
// retry --;
// }while(retry);
// pHandle->pClearRxData(); //清除接收计数器
return 0;
}
需要注意的是发送数据后模块会立刻返回AT指令响应,如果在应用中采用中断的形式接收串口数据,那么会马上产生接收中断,这时如果服务器有应答数据或下发数据会再产生接收中断,在处理接收数据时需要注意。通过校验“+CSONMI”确认是下发的数据。下发数据是字符串形式,需进行转换。
unsigned char Rx_SIMCOM[256];
unsigned char Rx_SIMCOM_len;
uint8_t Rx_Simdata_check(void)
{
uint16_t s_len;
uint16_t hex_temp;
uint8_t i,j;
char *p;
p = strstr(g_SIMCOM_Buff, "+CSONMI:");
if(p != NULL)
{
// printf("%s",g_SIMCOM_Buff);
for(i=0;i<4;i++)
{
if(p[11+i]==',')
{
p[11+i] = '\0';
break;
}
}
Rx_SIMCOM_len=atoi(&p[11])/2;
for(j=0;j