物联网实战--驱动篇之(九)NB-IOT(BC260)

目录

一、NB-IOT简介

二、NB-IOT要素

三、代码详解

四、平台端


一、NB-IOT简介

实际上,就是NB-Iot彻底引爆了物联网的,大概2018年左右,NB推广如火如荼,同时广域网、低功耗的LPWAN网络也逐渐传开,现在回头来看,还是有些过火了,实际上还是得结合市场的。目前NB的主要市场还是在市政领域,水表、气表、停车场地磁等等,基本上是政企推动的;技术上,NB和LoRa有交集,但是更多的互补关系。NB在推广上主要的是电信,移动也算还好,联通就比较少看到了,因为NB基站需要重新部署,涉及到投入产出的问题,就目前来看,电信应该县级城市都有覆盖了。

在使用上,我之前主要还是使用电信的,电信刚开始只有电信IOT平台,开账号得企业,比较麻烦,说实话也不好用,后面电信又出了个AEP平台,这个整体体验还不错,所以我们这里也以AEP为主,驱动程序也主要还是框架,像移动的onenet和阿里平台还没具体实现,有时间再慢慢完善。AEP网址在这儿,自己去注册https://sso.ctwing.cn/login?service=https%3A%2F%2Fwww.ctwing.cn%2Flogin%2Fcas#/

二、NB-IOT要素

NB要素主要有以下几个:

IMEI--模块识别码,平台一般当作身份信息;

ICCID--20位的卡号,装NB卡了才有;

NB卡--这个需要联系客户经理给你开卡,跟我们平时的4G卡外形一样,但有本质区别,不能通用,其中电信NB卡一般是按次收费,一般2万次/年,算下来差不多半小时发送一次,够用了,移动一般是一年360M,具体套餐由费用决定,要跟客户经理商谈;

模块费用:我们这里的模块型号是移远的BC260Y,支持电信跟移动,模组+外设元器件估计也是要20+的,我这里购买成品模块,36块,NB卡10块,购买可以参考这里https://item.taobao.com/item.htm?_u=kpfmfmg80d4&id=675137321790&skuId=5031188443830&spm=a1z09.2.0.0.67002e8d7mF2cG

低功耗:这里暂时没有涉及低功耗,因为这个最好用具体项目讲解比较好理解,NB的低功耗比较特别,不仅跟模块配置有关,还跟NB卡有关,不同的APN对应不同的低功耗水平,简单讲就是唤醒后多久进入睡眠是卡决定的,不过这里不同厂家可能不一样,仅做参考。

三、代码详解

整个流程跟4G类似,差别在于,NB一般对接中间平台,如电信AEP、移动onenet,在平台上编辑插件对设备消息进行解析,解析完后推送给你自己的平台,整个流程也没有很轻松,刚开始电信的NB只能对接电信IOT平台,刚开始bug又很多,使用起来确实不太畅快。

硬件连接上,使用串口2,波特率是9600,我采购的模块电源是3.3V的,STM32的PA2接模块RX,PA3接模块TX。

这里的流程需要根据不同的平台分开定义,我们先看AEP的,在网络注册流程中,只要卡没问题,模块会自己注册,我们只要不断查询注册状态即可,注册成功一般会返回

+CEREG: 0,1

主要是后面的1这个状态值,有时候是5,是这两个值就可以认为注册成功了。

网络没问题之后,就要根据不同平台走连接流程了,AEP相对比较简单,如下图所示,IP和端口都是固定的,这里用的是LWM2M协议,COAP的端口是5682,连接成功后就可以进行数据收发了。

cpp 复制代码
/*		
================================================================================
描述 : 注册流程
输入 : 
输出 : 
================================================================================
*/
void drv_bc260_reg_process(void)
{
  static u32 last_sec_time=0, wait_time=2;
  u32 now_sec_time=drv_get_sec_counter();
  if(now_sec_time-last_sec_time>wait_time)
  {
    switch(g_sBc260Work.state)
    {
      case BC260_STATE_START:
      {
        drv_bc260_send_at("QRST=1");//复位模块  
        g_sBc260Work.state=BC260_STAT_INIT;
        wait_time=5;
        break;
      }
      case BC260_STAT_INIT:
      {
        drv_bc260_send_at("CSQ");
        delay_os(200);
        drv_bc260_send_at("QSCLK=0");//禁用休眠模式
        delay_os(200);
        drv_bc260_send_at("CSCON=1");//使能信令连接状态上报
        g_sBc260Work.state=BC260_STAT_CEREG;
        wait_time=2;
        break;
      }    
      case BC260_STAT_CEREG://网络注册状态
      { 
        drv_bc260_send_at("CEREG?");//查询
        wait_time=2;
        break;
      }       
      case BC260_STAT_AEP_INIT:
      { 
        drv_bc260_send_at("NNMI=1");//将数据接收模式设置为直吐模式
        delay_os(200);
        drv_bc260_send_at("NCFG=0,86400");//配置生命周期时间,秒
        g_sBc260Work.state=BC260_STAT_AEP_CONNECT;
        wait_time=2;
        break;
      }
      case BC260_STAT_AEP_CONNECT://连接到服务器
      { 
        drv_bc260_send_at("NCDPOPEN=\"221.229.214.202\",5683");
        wait_time=3;
        break;
      }     

      case BC260_STAT_OK:
      { 
        if(g_sBc260Work.imei_buff[0]==0)
        {
          drv_bc260_send_at("CGSN=1");
          delay_os(200);
        }
        else if(g_sBc260Work.iccid_buff[0]==0)
        {
          drv_bc260_send_at("QCCID");
          delay_os(200);          
        }
        else
        {
          drv_bc260_send_at("CSQ");
        }
        
        wait_time=5;
        break;
      }       
    }
    
    last_sec_time=drv_get_sec_counter();
  }
  
}

数据解析也是匹配关键字,具体如下:

cpp 复制代码
/*		
================================================================================
描述 : 十六进制字符串转字节数组
输入 : 
输出 : 
================================================================================
*/
void hex_str_to_array(char *hex_str, char *out_array, u16 array_len)
{
  for(u16 i=0; i<array_len; i++)
  {
    sscanf(hex_str+i*2, "%02hhX", &out_array[i]);
  }
}

/*		
================================================================================
描述 : 接收处理
输入 : 
输出 : 
================================================================================
*/
void drv_bc260_recv_process(void)
{
	u16 recv_len;
	char *pData=NULL;
	
	if(g_sBc260Work.pUART->iRecv>0)
	{
		recv_len=0;
		while(recv_len<g_sBc260Work.pUART->iRecv)
		{
			recv_len=g_sBc260Work.pUART->iRecv;
			delay_ms(5);
		}
		char *pBuff=(char*)g_sBc260Work.pUART->pBuff;
		printf("bc260 recv=%s\n", g_sBc260Work.pUART->pBuff);
    
    if( (pData=strstr(pBuff, "+NNMI: "))!=NULL )//AEP接收到数据
    {
      pData+=strlen("+NNMI: ");
      u16 data_len=atoi(pData);
      if( (pData=strstr(pData, ","))!=NULL && data_len<100)
      {
        pData+=1;
        char data_buff[100]={0};
        hex_str_to_array(pData, data_buff, data_len);
        printf_hex("data=", (u8*)data_buff, data_len);
        if(g_sBc260Work.fun_recv_parse!=NULL)
        {
          g_sBc260Work.fun_recv_parse((u8*)data_buff, data_len);
        }
      }
    }
    else if((pData=strstr(pBuff, "+QLWEVTIND: "))!=NULL )
    {
      pData+=strlen("+QLWEVTIND: ");
      u8 type=atoi(pData);
      if(type==3)//AEP服务器订阅成功
      {
        g_sBc260Work.state=BC260_STAT_OK;
      }
    }
    else if((pData=strstr(pBuff, "+CEREG: "))!=NULL )
    {
      pData+=strlen("+CEREG: ");
      pData+=2;
      u8 state=atoi(pData);
      if(state==1 || state==5)//网络已注册
      {
        switch(g_sBc260Work.server_type)
        {
          case BC260_SERVER_ONENET://移动OneNet
          {
            
            break;
          }
          case BC260_SERVER_CHINANET_IOT://电信IOT
          {
            
            break;
          }
          case BC260_SERVER_CHINANET_AEP://电信AEP
          {
            g_sBc260Work.state=BC260_STAT_AEP_INIT;//进入AEP的初始化
            break;
          }
          case BC260_SERVER_ALI://阿里平台
          {
            
            break;
          }          
        }
        
      }
    }    
    else if((pData=strstr(pBuff, "+CSQ: "))!=NULL )
    {
      pData+=strlen("+CSQ: ");
      g_sBc260Work.rssi=atoi(pData);
      printf("***rssi=%d\n", g_sBc260Work.rssi);
    }    
    else if((pData=strstr(pBuff, "+CGSN: "))!=NULL )
    {
      pData+=strlen("+CGSN: ");
      memcpy(g_sBc260Work.imei_buff, pData, 15);
      printf("***imei=%s\n", g_sBc260Work.imei_buff);
    }      
    else if((pData=strstr(pBuff, "+QCCID: "))!=NULL )
    {
      pData+=strlen("+QCCID: ");
      memcpy(g_sBc260Work.iccid_buff, pData, 20);
      printf("***iccid=%s\n", g_sBc260Work.imei_buff);
    }  

    UART_Clear(g_sBc260Work.pUART);
  }

}

这里比较特殊的是,跟ESP8266和AIR780相比,NB返回的数据是十六进制的字符串,需要转换,以上的hex_str_to_array()函数可以看下,对于发送也是如此,要把字节数组转成字符串,具体如下:

cpp 复制代码
/*		
================================================================================
描述 :
输入 : 
输出 : 
================================================================================
*/
void drv_bc260_send_data(u8 *buff, u16 len)
{
  if(g_sBc260Work.state!=BC260_STAT_OK)
    return;
  
	static char send_buff[200]={0};
	if(len*2+10<sizeof(send_buff))
	{
		memset(send_buff, 0, sizeof(send_buff));
		sprintf(send_buff, "AT+NMGS=%d,", len);
    for(u16 i=0; i<len; i++)
    {
      char temp_buff[5]={0};
      sprintf(temp_buff, "%02X", buff[i]);
      strcat(send_buff, temp_buff);
    }
    strcat(send_buff, "\r\n");
//    printf("send data=%s\n", send_buff);
		drv_bc260_uart_send(send_buff);	
	}  
}

应用数据接收后依然采用回调函数的方式进行处理,自己应用层去定义和注册,跟之前的WIFI和4G都差不多。

软件方面基本上就这些了,对于AEP平台没有很复杂,后面有时间再继续完善Onenet等其它平台的流程。应用层其实就是初始化+主程序循环了。

这里我在user_app.c里加了点测试代码,这样就可以随时发送测试了。

四、平台端

平台端注册完后要创建产品,具体流程可以参考文档,

注意点是协议要选LWM2M,然后添加设备的IMEI要是你测试模块的IMEI,这样才能收得到数据,整体页面如下:

设备上线后指示灯会由灰转绿色,数据查看和指令设置如下图所示,点击后会有响应显示。

数据格式可以选择16进制,便于观察;指令下发直接输入就行了,但是下发后模块一般不会马上收到,需要在模块主动上报数据后一个区间内才收的到,这也是低功耗的代价了,以后具体项目再深入讲解。

由上图可知,主动发送后大概过了10秒才收到刚才下发的指令。

NB设备端的整个开发流程大概就是这样了,平台端还有个物模型,就是解析插件,用来解析数据,具体可以看教程https://www.ctwing.cn/sbgl/539#see,这里贴出以前做过的示例:

驱动程序:https://download.csdn.net/download/ypp240124016/89180826

文档资料:https://download.csdn.net/download/ypp240124016/89181042

本项目的交流QQ群:701889554

相关推荐
BY组态2 小时前
【技术分析】Ricon组态系统的模块化架构设计
物联网·iot·web组态·组态
BY组态4 小时前
【教程】如何使用Ricon组态系统快速构建监控画面
物联网·iot·web组态·组态
BY组态6 小时前
【对比分析】Ricon组态系统 vs 传统组态软件
运维·物联网·web组态·组态
zhaoshuzhaoshu1 天前
BLE(蓝牙低功耗)连接过程详解
物联网·蓝牙·无线
搜佛说1 天前
下一代跨语言原生操作系统商业计划书
物联网·软件工程
BY组态1 天前
Ricon组态系统在实际项目中的应用案例分享
物联网·web组态·组态
Zevalin爱灰灰1 天前
零基础入门学用物联网(ESP8266) 第一部分 基础知识篇(五)
单片机·物联网·嵌入式·esp8266
Web3_Daisy1 天前
Token 分红机制详解:实现逻辑、激励结构与风险分析
大数据·人工智能·物联网·web3·区块链
BY组态1 天前
从零开始:Ricon组态系统快速入门指南
运维·物联网·web组态·组态
次旅行的库1 天前
MQTT学习笔记
数据库·笔记·物联网·学习