手把手教你玩转NB-IoT -- 第五弹:上报数据之智慧路灯

NB的老王 发表于 2018/12/20 12:54:43 2018/12/20
【摘要】 写在前面:相关API调用流程:LiteOS API方式接入 这部分的通过单片机搭载华为LiteOS操作系统,并移植了可兼容所有AT指令型的AT框架程序, 调用AT框架的API接口实现快速连接华为Oceanconnect平台。 并能实时...

写在前面:相关API调用流程:

图片1.png

LiteOS API方式接入                                                                

       这部分的通过单片机搭载华为LiteOS操作系统,并移植了可兼容所有AT指令型的AT框架程序,
    调用AT框架的API接口实现快速连接华为Oceanconnect平台。    
    并能实时接收平台下发的命令,实现对设备的控制,以下讲解调用API实现的方式。

Step 1 分析主程序

   int main(void)
   {
     UINT32 uwRet = LOS_OK;
     HardWare_Init();
     uwRet = LOS_KernelInit();
     if (uwRet != LOS_OK)
     {
       return LOS_NOK;
     }
     uwRet = creat_data_collection_task();
     if (uwRet != LOS_OK)
     {
       return LOS_NOK;
     }
     uwRet = creat_data_report_task();
     if (uwRet != LOS_OK)
     {
        return LOS_NOK;
     }
     LOS_Start();
  }
  • 主程序主要包括初始化硬件外设、初始化内核、创建传感器数据采集任务、创建数据上报任务,接下来讲详细讲解主要部分的实现方式。

Step 2初始化硬件

    VOID HardWare_Init(VOID)
    {
      HAL_Init();
      /* Configure the system clock */
      SystemClock_Config();
      /* Initialize all configured peripherals */
      dwt_delay_init(SystemCoreClock);
      MX_GPIO_Init();
      MX_USART1_UART_Init();
      printf("Welcome to IoT-Club, This is EVB-M1 Board.\r\n");
    }
  • 首先调用 HAL_Init() 初始化HAL库;SystemClock_Config(),用于系统时钟的配置;再调用MX_GPIO_Init()
    初始化相应的GPIO;最后初始化单片机debug串口。

Step 3创建传感器采集任务

    VOID data_collection_task(VOID)
    {
      UINT32 uwRet = LOS_OK;
      short int Lux;
      Init_BH1750();
      while (1)
      {
        printf("This is data_collection_task !\r\n");
        Lux=(int)Convert_BH1750();
        printf("\r\n******************************BH1750 Value is  %d\r\n",Lux);
        sprintf(BH1750_send.Lux, "%5d", Lux); 
        uwRet=LOS_TaskDelay(1000);
        if(uwRet !=LOS_OK)
        return;
      }
    }

这部分为传感器数据采集部分,首先是通过Init_BH1750() 函数初始化光照传感器BH1750所对应的单片机管脚及传感器。

   void Init_BH1750(void)
    {
      I2C_InitGPIO();
      Cmd_Write_BH1750(0x01);
    }

通过 Convert_BH1750() 函数采集传感器数据

    float Convert_BH1750(void)
    {
      Start_BH1750();
      LOS_TaskDelay(180);
      Read_BH1750();
      result=BUF[0];
      result=(result<<8)+BUF[1];
      result_lx=(float)(result/1.2);
      return result_lx;
    }

最后将传感器数据以字符串的形式存入到数组中,用于发送到平台上。

    sprintf(BH1750_send.Lux, "%5d", Lux);

Step 4创建数据上报任务

    VOID data_report_task(VOID)
    {
      UINT32 uwRet = LOS_OK;
      #define AT_DTLS 0
      #if AT_DTLS
         sec_param_s sec;
         sec.pskid = "868744031131026";
         sec.psk = "d1e1be0c05ac5b8c78ce196412f0cdb0";
            
      #endif
         printf("\r\n=====================================================");
         printf("\r\nSTEP1: Init NB Module( NB Init )");
         printf("\r\n=====================================================\r\n");
            
      #if AT_DTLS
         los_nb_init((const int8_t*)"180.101.147.115",(const int8_t*)"5684",&sec);
      #else
         los_nb_init((const int8_t*)"180.101.147.115",(const int8_t*)"5683",NULL);
      #endif
         printf("\r\n=====================================================");
         printf("\r\nSTEP2: Register Command( NB Notify )");
         printf("\r\n=====================================================\r\n");
         los_nb_notify("+NNMI:",strlen("+NNMI:"),nb_cmd_data_ioctl,OC_cmd_match);
         LOS_TaskDelay(3000);
         printf("\r\n=====================================================");
         printf("\r\nSTEP3: Report Data to Server( NB Report )");
         printf("\r\n=====================================================\r\n");
         while(1)
         {
           if(los_nb_report((const char*)(&BH1750_send),sizeof(BH1750_send))>=0)
           printf("ocean_send_data OK!\n");
           else
             {
              printf("ocean_send_data Fail!\n"); 
             }
           uwRet=LOS_TaskDelay(1000);
           if(uwRet !=LOS_OK)
           return;
        }
    }

这部分程序主要包括连接平台、注册下发命令的回调函数以及上报数据到平台,以下将讲解如何实现这三部分。

  • 1)连接平台
    连接平台的方式分为加密和非加密两种,通过#define AT_DTLS来实现连接方式的选择,定义为0时为非加密,
    此教程以非加密为例讲解,实现程序如下

     #define AT_DTLS 0
    #if AT_DTLS
        sec_param_s sec;
        sec.pskid = "868744031131026";
        sec.psk = "d1e1be0c05ac5b8c78ce196412f0cdb0";
    #endif
        printf("\r\n=====================================================");
        printf("\r\nSTEP1: Init NB Module( NB Init )");
        printf("\r\n=====================================================\r\n");
    #if AT_DTLS
        los_nb_init((const int8_t*)"139.159.140.34",(const int8_t*)"5684",&sec);
    #else
        los_nb_init((const int8_t*)"139.159.140.34",(const int8_t*)"5683",NULL);
    #endif

此部分通调用los_nb_init函数初始化模组,等待连接网络,设置平台对接地址实现对接平台。三个参数分别为设备对接IP、设备对接>端口以及加密的PSK码。【注意】不同平台的设备对接地址不同,请以自己平台为准

    int los_nb_init(const int8_t* host, const int8_t* port, sec_param_s* psk)    
    {
        int ret;
        int timecnt = 0;
        at.init();
        nb_reboot();
        LOS_TaskDelay(2000);
        if(psk != NULL)//encryption v1.9
        {
          if(psk->setpsk)
          nb_send_psk(psk->pskid, psk->psk);
          else
          nb_set_no_encrypt();
        }
        while(1)
        {
          ret = nb_hw_detect();
          printf("call nb_hw_detect,ret is %d\n",ret);
          if(ret == AT_OK)
          break;
          //LOS_TaskDelay(1000);
        }
        //nb_get_auto_connect();
        //nb_connect(NULL, NULL, NULL);
        while(timecnt < 120)
        {
          ret = nb_get_netstat();
          nb_check_csq();
          if(ret != AT_FAILED)
          {
            ret = nb_query_ip();
            break;
          }
          //LOS_TaskDelay(1000);
          timecnt++;
        }
        if(ret != AT_FAILED)
        {
           nb_query_ip();
        }
        ret = nb_set_cdpserver((char *)host, (char *)port);
        return ret;
    }
  • 2)注册下发命令回调函数
    注册下发命令回调函数可实现对平台下发命令的快速相应并处理

    los_nb_notify("+NNMI:",strlen("+NNMI:"),nb_cmd_data_ioctl,OC_cmd_match);

第一个参数为要匹配数据字段,第二个参数为匹配字段的长度、第三个参数为命令回调的执行函数、第四个为注册字段的匹配函数。

    int32_t nb_cmd_data_ioctl(void* arg, int8_t  * buf, int32_t len)    
    {
        int readlen = 0;
        char tmpbuf[1064] = {0};
        if (NULL == buf || len <= 0)
        {
          AT_LOG("param invailed!");
          return -1;
        }
        sscanf((char *)buf,"\r\n+NNMI:%d,%s\r\n",&readlen,tmpbuf);
        memset(bc95_net_data.net_nmgr, 0, 30);
        if (readlen > 0)
        {
          HexStrToStr(tmpbuf,  bc95_net_data.net_nmgr,readlen*2);
        }
        AT_LOG("cmd is:%s\n",bc95_net_data.net_nmgr);
        if(strcmp(bc95_net_data.net_nmgr,"ON")==0) 
        {
          HAL_GPIO_WritePin(Light_GPIO_Port,Light_Pin,GPIO_PIN_RESET);
        }
        if(strcmp(bc95_net_data.net_nmgr,"OFF")==0) 
        {
          HAL_GPIO_WritePin(Light_GPIO_Port,Light_Pin,GPIO_PIN_SET);
        }
    /*******************************END**********************************************/
        return 0;
    }

命令回调处理函数主要实现命令的解析以及实现控制相应的设备,此处以控制LED灯为例

  int32_t OC_cmd_match(const char *buf, char* featurestr,int len)
    {
      if(strstr(buf,featurestr) != NULL)
      return 0;
      else
      return -1;
    }

注册字段匹配函数用于验证数据是否与注册字段匹配/

  • 3)上报数据

    while(1)
    {
      if(los_nb_report((const char*)(&BH1750_send),sizeof(BH1750_send))>=0)
      {
       printf("ocean_send_data OK!\n");
      }
      
      else
      {
       printf("ocean_send_data Fail!\n"); 
      }
      uwRet=LOS_TaskDelay(1000);
      if(uwRet !=LOS_OK)
      return;
    }

上报数据调用的API为los_nb_report填入的参数为数据与数据长度,这个函数里封装了发送coap消息的AT指令以及查询发送的消息量<的AT指令

int32_t nb_send_payload(const char* buf, int len)
    {
        char *cmd1 = "AT+NMGS=";
        char *cmd2 = "AT+NQMGS\r";
        int ret;
        char* str = NULL;
        int curcnt = 0;
        int rbuflen;
        static int sndcnt = 0;
        if(buf == NULL || len > AT_MAX_PAYLOADLEN)
        {
          AT_LOG("payload too long");
          return -1;
        }
        memset(tmpbuf, 0, AT_DATA_LEN);
        memset(wbuf, 0, AT_DATA_LEN);
        str_to_hex(buf, len, tmpbuf);
        memset(rbuf, 0, AT_DATA_LEN);
        snprintf(wbuf, AT_DATA_LEN,"%s%d,%s%c",cmd1,(int)len,tmpbuf,'\r');
        ret = at.cmd((int8_t*)wbuf, strlen(wbuf), "OK", NULL,NULL);
        if(ret < 0)
          return -1;
        ret = at.cmd((int8_t*)cmd2, strlen(cmd2), "SENT=", rbuf,&rbuflen);
        if(ret < 0)
          return -1;
        str = strstr(rbuf,"SENT=");
        if(str == NULL)
          return -1;
        sscanf(str,"SENT=%d,%s",&curcnt,wbuf);
        if(curcnt == sndcnt)
          return -1;
        sndcnt = curcnt;
        return ret;
}

        


        


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:cloudbbs@huaweicloud.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。