我是靠谱客的博主 冷酷信封,最近开发中收集的这篇文章主要介绍【第六章】STM32单片机+NB-IoT模组BC95采集温湿度数据发到电信平台(下),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

相关信息

设备接入方式:CoAP非加密方式

 

应用开发

串口助手AT命令对接平台

这部分内容是通过电脑串口调试软件,手动发AT指令,直接发给NB-IoT模块。NB模块返回的信息,直接到电脑串口调试软件。一步一步动手操作,实现连接OceanConnect平台。采用的通讯协议是CoAP协议。

Step 1 配置对接平台地址

指令:AT+NCDP=<ip_addr>[,<port>]

<ip_addr>:填写平台设备接入地址

<port>:填写接入方式的端口号

例:AT+NCDP= 139.159.140.34,5683

Step 2 软件重启模组

指令:AT+NRB    //配置完配置对接平台地址后需要重启模块才能生效

REBOOTING

0???

REBOOT_CAUSE_APPLICATION_AT

Neul

OK

Step 3 检查是否入网成功

指令:AT+CGATT?

+CGATT:1 //返回1表示入网成功,返回0入网失败,300s后依然为0,则重启模组

 

OK

Step 4 发送数据

指令:AT+NMGS=<length>,<data>

<length>:数据长度

<data>:数据(十六进制格式)

例:AT+NMGS=8,31322E3132332E34  //上报数据

OK

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_main_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.rn");

	
}

首先调用 HAL_Init() 初始化HAL库;SystemClock_Config(),用于系统时钟的配置;再调用MX_GPIO_Init()

初始化相应的GPIO;最后初始化单片机debug串口。

Step 3创建传感器采集任务

VOID data_collection_task(VOID)
{
	UINT32 uwRet = LOS_OK;
	
	DHT11_Init();									//初始化传感器

	while (1)
  {

		printf("This is data_collection_task !rn");
		
		    if(DHT11_Read_TempAndHumidity(&DHT11_Data)==SUCCESS)
    {
			printf("读取DHT11成功!-->湿度为%.1f %RH ,温度为 %.1f℃ n",DHT11_Data.humidity,DHT11_Data.temperature);
    }
    else
    {
      printf("读取DHT11信息失败n");
			DHT11_Init();      
    }
		sprintf(DHT11_send.temp, "%.1f", DHT11_Data.temperature);
		sprintf(DHT11_send.hum, "%.1f", DHT11_Data.humidity);

		uwRet=LOS_TaskDelay(2000);
		if(uwRet !=LOS_OK)
		return;
	
  }
}

这部分为传感器数据采集部分,首先是通过DHT11_Init();函数初始化温湿度传感器DHT11所对应的单片机管脚及传感器。

/**
  * 函数功能: DHT11 初始化函数
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
void DHT11_Init ( void )
{
  DHT11_Dout_GPIO_CLK_ENABLE();
  
	DHT11_Mode_Out_PP();
	
	DHT11_Dout_HIGH();  // 拉高GPIO
}

通过 DHT11_Read_TempAndHumidity函数采集传感器数据

/**
  * 函数功能: 一次完整的数据传输为40bit,高位先出
  * 输入参数: DHT11_Data:DHT11数据类型
  * 返 回 值: ERROR:  读取出错
  *           SUCCESS:读取成功
  * 说    明:8bit 湿度整数 + 8bit 湿度小数 + 8bit 温度整数 + 8bit 温度小数 + 8bit 校验和 
  */
uint8_t DHT11_Read_TempAndHumidity(DHT11_Data_TypeDef *DHT11_Data)
{  
  uint8_t temp;
  uint16_t humi_temp;
  
	/*输出模式*/
	DHT11_Mode_Out_PP();
	/*主机拉低*/
	DHT11_Dout_LOW();
	/*延时18ms*/
	Delay_ms(18);	
	/*总线拉高 主机延时30us*/
	DHT11_Dout_HIGH(); 

	DHT11_Delay(30);   //延时30us

	/*主机设为输入 判断从机响应信号*/ 
	DHT11_Mode_IPU();

	/*判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行*/   
	if(DHT11_Data_IN()==GPIO_PIN_RESET)     
	{
    /*轮询直到从机发出 的80us 低电平 响应信号结束*/  
    while(DHT11_Data_IN()==GPIO_PIN_RESET);

    /*轮询直到从机发出的 80us 高电平 标置信号结束*/
    while(DHT11_Data_IN()==GPIO_PIN_SET);

    /*开始接收数据*/   
    DHT11_Data->humi_high8bit= DHT11_ReadByte();
    DHT11_Data->humi_low8bit = DHT11_ReadByte();
    DHT11_Data->temp_high8bit= DHT11_ReadByte();
    DHT11_Data->temp_low8bit = DHT11_ReadByte();
    DHT11_Data->check_sum    = DHT11_ReadByte();

    /*读取结束,引脚改为输出模式*/
    DHT11_Mode_Out_PP();
    /*主机拉高*/
    DHT11_Dout_HIGH();
    
    /* 对数据进行处理 */
    humi_temp=DHT11_Data->humi_high8bit*100+DHT11_Data->humi_low8bit;
    DHT11_Data->humidity =(float)humi_temp/100;
    
    humi_temp=DHT11_Data->temp_high8bit*100+DHT11_Data->temp_low8bit;
    DHT11_Data->temperature=(float)humi_temp/100;    
    
    /*检查读取的数据是否正确*/
    temp = DHT11_Data->humi_high8bit + DHT11_Data->humi_low8bit + 
           DHT11_Data->temp_high8bit+ DHT11_Data->temp_low8bit;
    if(DHT11_Data->check_sum==temp)
    { 
      return SUCCESS;
    }
    else 
      return ERROR;
	}	
	else
		return ERROR;
	
}

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

sprintf(DHT11_send.temp, "%.1f", DHT11_Data.temperature);
sprintf(DHT11_send.hum, "%.1f", DHT11_Data.humidity);

Step 3创建数据上报任务

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("rn=====================================================");

    printf("rnSTEP1: Init NB Module( NB Init )");

    printf("rn=====================================================rn");

#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("rn=====================================================");

    printf("rnSTEP2: Register Command( NB Notify )");

    printf("rn=====================================================rn");

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

    LOS_TaskDelay(3000);

    printf("rn=====================================================");

    printf("rnSTEP3: Report Data to Server( NB Report )");

    printf("rn=====================================================rn");

              while(1)

       {

            if(los_nb_report((const char*)(&DHT11_send),sizeof(DHT11_send))>=0)        //发送数据到平台    
                printf("ocean_send_data OK!n");                                                  //发生成功
        else                                                                                  //发送失败
            {
                printf("ocean_send_data Fail!n"); 
            }



             uwRet=LOS_TaskDelay(1000);

              if(uwRet !=LOS_OK)

              return;

       }

}

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

连接平台

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

#define AT_DTLS 0

#if AT_DTLS

    sec_param_s sec;

    sec.pskid = "868744031131026";

    sec.psk = "d1e1be0c05ac5b8c78ce196412f0cdb0";

#endif

    printf("rn=====================================================");

    printf("rnSTEP1: Init NB Module( NB Init )");

    printf("rn=====================================================rn");

#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;

    //if(port == NULL)

        //return -1;

    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 %dn",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;

}

 

​​​​​​​注册下发命令回调函数

注册下发命令回调函数可实现对平台下发命令的快速相应并处理

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,"rn+NNMI:%d,%srn",&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:%sn",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;

}

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

​​​​​​​上报数据

            while(1)

     {



        if(los_nb_report((const char*)(&DHT11_send),sizeof(DHT11_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+NQMGSr";

    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;

}

 

最后

以上就是冷酷信封为你收集整理的【第六章】STM32单片机+NB-IoT模组BC95采集温湿度数据发到电信平台(下)的全部内容,希望文章能够帮你解决【第六章】STM32单片机+NB-IoT模组BC95采集温湿度数据发到电信平台(下)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(41)

评论列表共有 0 条评论

立即
投稿
返回
顶部