基于中移物联MN316 OPENCPU和奥松AHT20的无线温湿度传感器完整代码

简介:

MN316是中移物联委托上海芯翼定制的一款低功耗的NBIOT的SOC,支持NB R14版本,休眠功耗实测可以达到1ua以下。

该代码实现完整的温湿度读取,并通过LWM2M上传到onenet平台,同时支持电池电压和RSSI定时上传。

温湿度上传频率可以修改,电压和RSSI值上传仅在每日凌晨0点到1点之间上传。

同时实现了FOTA功能。

该代码完善过程中踩了无数个坑,已经针对各种可能产生的议程情况做了健壮处理,目前已在成熟的产品上经过超过一年的测试。

AHT20驱动文件:

/**
 *  @file    ds_sdrv_aht20.c
 *  @brief   传感器驱动_温湿度传感器AHT20
 *  @copyright copyright © 2022 WUXI DOES IOT. All rights reserved.
 *  @author by Liuhuali
 *  @date 2022/07/17
 */
#include "ds_sdrv_aht20.h"
#include "cm_i2c.h"
#include "stdio.h"
#include "cm_os.h"
#include "ds_common.h"

#ifndef min
#define min(A,B) ((A) <= (B) ? (A) : (B))
#endif

#ifndef max
#define max(A,B) ((A) < (B) ? (B) : (A))
#endif

#define SENSOR_DEV_ADDR   	0x38
#define SENSOR_I2C_ID	    CM_I2C_DEV_1
/**
 * \breif 通过I2C向传感器写数据
 * 
 * \param [in] addr:寄存器地址,范围0-0x7fff
 * \param [in] data:待写入数据头指针
 * \param [in] len: 待写入数据长度
 * 
 * \return  0:成功,其他:失败
 *
 */
static int aht20i2c_write(uint16_t addr, int8_t* data, int len)
{
	int8_t tmp[8] = {0};
	int ret = -1;
	uint8_t i = 0;
	uint8_t count = 0;
	int send_count = 0;

	while(len > 0)
	{
		tmp[0] = (addr >> 8) & 0xff;
		tmp[1] = addr & 0xff;

        if (((send_count + 6) / 64)  > 0)
        {
            count = 64 - send_count;
            for(i = 0; i < count; i++)
                tmp[i+2] = *data++;

        }
        else
        {
            count = min(8, (len + 2));
            
            for(i = 0; i < (count - 2); i++)
                tmp[i+2] = *data++;
        }

	
		/*连续从该地址写入长度为len的数据*/
	  // ds_printf("i2c write addr(r)\r\n");
		ret = cm_i2c_write(SENSOR_I2C_ID , SENSOR_DEV_ADDR, tmp, count);
		if(ret< 0)
		{
			//ds_printf("i2c write addr err(r):0x%x\r\n", addr);
			return ret;
		}
		

		
        if (((send_count + 6) / 64)  > 0)
        {
            addr += (64 - send_count);
            len -= (64 - send_count);
            send_count = 0;
        }
        else
        {
            addr += 6;
            len -= 6;
            send_count += 6;
        }
        
		osDelay(5);
	}

	return 0;
}


/**
 * \brief 通过I2C读传感器数据
 *
 * \param [in] addr:地址,范围0-0x7fff
 * \param [in] data:读取数据存放地址,需事先分配内存
 * \param [in] len: 待读取数据长度
 *
 * \return  0:成功,其他:失败
 */
static int aht20i2c_read(uint16_t addr, int8_t* data, int len)
{
	int8_t tmp[2] = {0};
	uint8_t count = 0;
	int ret = -1;

	while(len > 0)
	{
		tmp[0] = (addr >> 8) & 0xff;
		tmp[1] = addr & 0xff;
		/*写入地址*/
		//ds_printf("i2c read addr(w)\r\n");
		ret = cm_i2c_write(SENSOR_I2C_ID, SENSOR_DEV_ADDR, tmp, 2);
		if(ret < 0)
		{
			//ds_printf("i2c read addr err(w):0x%x\r\n", addr);
			return ret;
		}
	
		/*连续从该地址读取长度为len的数据*/
		//ds_printf("i2c read addr(r)\r\n");
		count = min(8, len);
		ret = cm_i2c_read(SENSOR_I2C_ID, SENSOR_DEV_ADDR, data, count);
		if(ret < 0)
		{
			//ds_printf("i2c read addr err(r):0x%x\r\n", addr);
			return ret;
		}
		
		addr += 8;
		len -= 8;
		data += 8;
		osDelay(5);
	}

	return 0;	
}





uint8_t AHT20_Read_Status(void)//读取AHT10的状态寄存器
{
    uint8_t Byte_first;
    aht20i2c_read(0x00,&Byte_first, 1);

	return Byte_first;
}

uint8_t AHT20_Read_Cal_Enable(void)
{
    uint8_t val = 0;//ret = 0,

    val = AHT20_Read_Status();
    if((val & 0x68) == 0x08)  //判断NOR模式和校准输出是否有效
        return 1;
    else
        return 0;
}

void AHT20_Read_CTdata(uint32_t *ct) //读取AHT20的温度和湿度数据
{
    uint32_t RetuData = 0;
	uint16_t cnt = 0;
    uint8_t Data[10];   //待测试
    uint8_t tmp[10];    //待测试

    tmp[0] = 0x33;
    tmp[1] = 0x00;
    aht20i2c_write(StartTest, tmp, 2);  //读取状态位
	osDelay(80);//等待80ms

    cnt = 0;
	while(((AHT20_Read_Status()&0x80) == 0x80))//等待忙状态结束
	{
        osDelay(1);
        if(cnt++ >= 100)
        {
            break;
        }
	}

    aht20i2c_read(0x00,Data, 7);

	RetuData = 0;
    RetuData = (RetuData|Data[1]) << 8;
	RetuData = (RetuData|Data[2]) << 8;
	RetuData = (RetuData|Data[3]);
	RetuData = RetuData >> 4;
	ct[0] = RetuData;

    RetuData = 0;
	RetuData = (RetuData|Data[3]) << 8;
	RetuData = (RetuData|Data[4]) << 8;
	RetuData = (RetuData|Data[5]);
	RetuData = RetuData&0xfffff;
	ct[1] = RetuData;
}

uint8_t count;
uint8_t AHT20_Init(void)
{
    uint8_t tmp[10];   //待测试

    osDelay(40);

    tmp[0] = 0x08;
    tmp[1] = 0x00;
	  aht20i2c_write(INIT, tmp, 2);  //P0 口中断不使能

    osDelay(50);
    count = 0;

    while(AHT20_Read_Cal_Enable() == 0)//需要等待状态字status的Bit[3]=1时才去读数据。如果Bit[3]不等于1 ,发软件复位0xBA给AHT10,再重新初始化AHT10,直至Bit[3]=1
    {
        aht20i2c_write(SoftReset, tmp, 0);
        osDelay(200);

        aht20i2c_write(INIT, tmp, 2);

        count++;
        if(count >= 5)
            return 0;
        osDelay(10);
    }
    return 1;
}

uint8_t get_sensordata(float *sensor_vlu)
{uint8_t ret=0;
 int x=10;
 uint32_t CT_data[2];
 float hum_value,tem_value;

    cm_i2c_cfg_t config = 
	{
		CM_I2C_ADDR_TYPE_7BIT,
		CM_I2C_MODE_MASTER, //目前仅支持模式
		CM_I2C_CLK_100KHZ
	};//master模式,(100KHZ)
 
 int32_t reti2c = cm_i2c_open(SENSOR_I2C_ID, &config);
    if(reti2c != 0)
    {
      ds_printf("i2c init err,ret=%d\n", ret);
      goto i2c_stop;
    }
           
                
ret = AHT20_Init();
    if(ret == 0)
    {
                              //  while(x--)
    {   
      ds_printf("AHT20传感器初始化错误:%d\n",ret);
   //  osDelay(300);
     goto i2c_stop;
     }
    }
                   
                        
                    /*读取 AHT20 传感器数据*/
 while(AHT20_Read_Cal_Enable() == 0)
{
        AHT20_Init();//如果为0再使能一次
        osDelay(30);
}
AHT20_Read_CTdata(CT_data);  //读取温度和湿度
hum_value = (float)CT_data[0] * 100 /1048576;  //计算得到湿度值
tem_value= (float)CT_data[1] *200 /1048576- 50;//计算得到温度值
sensor_vlu[0]=hum_value;
sensor_vlu[1]=tem_value;

ret=1;
 i2c_stop:
{
       cm_i2c_close(SENSOR_I2C_ID);
       return ret;
 }

}

 onenet通信相关封装文件:

/**
 *  @file    dslib_onenet.c
 *  @brief   大襄物联(doesiot)onenet封装
 *  @copyright copyright © 2022 WUXI DOES IOT. All rights reserved.
 *  @author by liuhuali
 *  @date 2022/7/8
 */

 

 /****************************************************************************
 * 包含头文件
 ****************************************************************************/
#include "cm_onenet.h"
#include "cm_sys.h"
#include "custom_main.h"
#include "stdio.h"
#include "string.h"
#include "cm_os.h"
/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/


/****************************************************************************
 * Private Types
 ****************************************************************************/

/****************************************************************************
 * Private Function Prototypes
 ****************************************************************************/
 
 
/****************************************************************************
 * Private Data
 ****************************************************************************/
 //static const char user_ver[] = "V1.0.0";
 
/****************************************************************************
 * Private Functions
 ****************************************************************************/

static int is_ref = 0;//Onenet是否注册
static int reconecttimes=0;//重连
static int havefail=0;//重连
static int ack0=0;//确认
static int ack1=0;//确认
static int ack2=0;//确认
static int ack3=0;//确认
unsigned char ds_fota_start=0;
/**
 *  \brief FOTA版本号获取,版本号仅支持数字、字母、‘.’、‘_’,长度≤16字节
 *  
 *  \param [out] version 版本号
 *  \return None
 *  
 *  \details 此函数原型在静态库中为弱引用,用户在进行fota升级时定义为强引用,并自行添加版本号
 */
void cm_fota_get_version(char version[])
{
    if(version == NULL)
    {
        return;
    }

    memcpy(version, user_ver, sizeof(user_ver));
}
/**
 *  \brief 状态事件上报
 *  
 *  \param [in] event 事件
 *  \return None
 *  
 *  \details More details
 */
static void cot_event_cb(int event)
{
    ds_printf("event:%d\n",event);
    switch(event)
    {
        case CM_CIS_EVENT_REG_SUCCESS: 
        {
            is_ref = 1;
          int  reboot_times=0;   //重启次数归零
         cm_flash_write(FLASH_REG_REBOOT_TIMES,&reboot_times,sizeof(int));//把重启次数写入FLASH
            ds_printf("onenet register ok\n");
        }
        break;
        case CM_CIS_EVENT_BOOTSTRAP_FAILED:
        {
            is_ref = 0;
            ds_printf("onenet bootstrap fail\n");
         
           ds_reboot(1);
         
            havefail=1;
            
        }
        break;
        case CM_CIS_EVENT_REG_FAILED:
        {
            is_ref = 0;
            ds_printf("onenet register fail\n");
            ds_reboot(2);
   
            havefail=1;
            
        }
        break;
        case CM_CIS_EVENT_UNREG_DONE:
        {
            is_ref = 0;
            ds_printf("onenet unregister done\n");
   
        }
        break;
        case CM_CIS_EVENT_FIRMWARE_DOWNLOADING:
        {
            ds_printf("onenet fota downloading\n");
            ds_fota_start=1; //收到FOTA更新信息,则延迟休眠
        }
        break;
        case CM_CIS_EVENT_FIRMWARE_DOWNLOAD_FAILED:
        {
            ds_printf("onenet fota download fail\n");
            ds_fota_start=0; //收到FOTA更新信息,则延迟休眠
        }
        break;
        case CM_CIS_EVENT_FIRMWARE_DOWNLOADED:
        {
            ds_printf("onenet fota downloaded\n");
            ds_fota_start=1;
        }
        break;
        case CM_CIS_EVENT_FIRMWARE_UPDATING:
        {
            ds_printf("onenet fota updating\n");
            ds_fota_start=1;
        }
        break;
        case CM_CIS_EVENT_FIRMWARE_UPDATE_SUCCESS:
        { ds_fota_start=0;
        	/* 系统在开机时通知该事件,该时刻uart不能保证初始化完成,故demo从log口打印该消息 */
            cm_log_printf(0, "onenet fota update success\n");
        }
        break;
        case CM_CIS_EVENT_FIRMWARE_UPDATE_FAILED:
        { ds_fota_start=0;
        	/* 系统在开机时通知该事件,该时刻uart不能保证初始化完成,故demo从log口打印该消息 */
            ds_printf(0, "onenet fota update fail\n");
        }
        break;
        case CM_CIS_EVENT_FIRMWARE_UPDATE_OVER:
        {ds_fota_start=0;
            ds_printf("onenet fota update over\n");
        }
        break;
        default:
        break;
    }
    
}

/**
 *  @brief 用户注册OneNET FOTA通知事件(未连接平台前,连接平台后该注册的函数失效)
 *  
 *  @return None
 *  
 *  @details 此函数由用户实现,切勿更改函数声明
 */
void user_onenet_event_register(void)
{
    cm_onenet_event_register(cot_event_cb);
}

/**
 *  \brief notify上报回调函数
 *  
 *  \param [in] ack_id notify的ack_id
 *  \return None
 *  
 *  \details 用户自行实现
 */
static void cot_notify_cb(int ack_id)
{
    //TODO
    ds_printf("ack_id:%d\n",ack_id);
    if(ack_id==1 || ack_id==11)
    ack0=1;
    if(ack_id==2 || ack_id==12)
    ack1=1;
    if(ack_id==3)
    ack2=1;
    if(ack_id==4)
    ack3=1;

}


/**
 *  \brief 平台read操作正确回调函数,需用户实现
 *
 *  \param [in] mid 操作消息的ID
 *  \param [in] objid 被操作的object ID
 *  \param [in] insid 被操作的instance ID
 *  \param [in] resid 被操作的resource ID
 *  \return None
 *
 */
static void cot_read_cb(int mid, int objid, int insid, int resid)
{
    //TODO
    //...
    (void)objid;
    (void)insid;
    (void)resid;
    //根据传入的objid_insid_resid决定需上传的数据
    ds_printf("mid:%d objid:%d insid:%d resid:%d\n",mid, objid, insid, resid);

    if (3 == objid && 0 == insid && 9 == resid)
    {
        //OneNET FOTA平台在发起下载升级包和发起升级指令前会获取设备电量信息,此为反馈平台当前电量为100%
        cm_onenet_read(mid, objid, insid, resid, 3, "100", 1);//返回表示该操作结果数据,示例资源类型为int型
    }
    else
    {
        cm_onenet_read(mid, objid, insid, resid, 3, "10", 1);//返回表示该操作结果数据,示例资源类型为int型
    }
}


/**
 *  \brief 平台write操作回调函数,需用户实现
 *  
 *  \param [in] mid 操作消息的ID
 *  \param [in] objid 被操作的object ID
 *  \param [in] insid 被操作的instance ID
 *  \param [in] resid 被操作的resource ID
 *  \param [in] type 写资源的类型,如该资源未曾被notify或read,皆作opaque类型处理
 *  \param [in] flag 多条写指令上报时消息标识 1、第一条消息; 2、中间消息; 0、最后一条消息
 *  \param [in] len 数据长度
 *  \param [in] data 被写入的数据
 *  \return None
 *  
 *  \details More details
 */
static void cot_write_cb(int mid, int objid, int insid, int resid, int type, int flag, int len, char *data)
{
    //TODO
    //...
    (void)objid;
    (void)insid;
    (void)resid;
    (void)resid;
    (void)type;
    (void)flag;
    (void)len;
    (void)data;

    ds_printf("objid:%d insid:%d resid:%d type:%d flag:%d len:%d data:%s\n",objid,insid,resid,type,flag,len,data);
   int wakeup_period=3;
   sscanf(data,"%x",&wakeup_period);
   rtc_sleep_periord=wakeup_period*60;
   ds_printf("周期:%d\n",wakeup_period);
   cm_flash_write(WAKE_UP_PERIOD,&wakeup_period,sizeof(int));//把重启次数写入FLASH
    cm_onenet_result(mid, CM_RESULT_204_CHANGED, 0);//操作正确完成返回204
}


/**
 *  \brief 平台excute操作回调函数,需用户实现
 *  
 *  \param [in] mid 操作消息的ID
 *  \param [in] objid 被操作的object ID
 *  \param [in] insid 被操作的instance ID
 *  \param [in] resid 被操作的resource ID
 *  \param [in] len 数据长度
 *  \param [in] data 被写入的数据
 *  \return None
 *  
 *  \details More details
 */
static void cot_execute_cb(int mid, int objid, int insid, int resid, int len, char *data)
{
    //TODO
    //...
    (void)objid;
    (void)insid;
    (void)resid;
    (void)len;
    (void)data;
    ds_printf("mid:%d objid:%d insid:%d resid:%d len:%d len:%s\n",mid, objid, insid, resid, len, data);
    cm_onenet_result(mid, CM_RESULT_204_CHANGED, 0);//操作正确完成返回204
}


/**
 *  \brief 平台discover操作回调函数,需用户实现
 *  
 *  \param [in] mid 操作消息的ID
 *  \param [in] objid 被操作的object ID
 *  \return None
 *  
 *  \details More details
 */
static void cot_discover_cb(int mid, int objid)
{
    //TODO
    //...
    ds_printf("discover mid:%d objid:%d \n", mid, objid);
    if(objid == 3303)
    {
        cm_onenet_discover(mid, 9, "5700");//返回将用到的资源列表
    }
    else if(objid == 3)
    {
        cm_onenet_discover(mid, 9, "26261");//返回将用到的资源列表
    }
      else if(objid == 3304)
   {
        cm_onenet_discover(mid, 9, "5700");//返回将用到的资源列表
   }
    else if(objid == 3316)
    {
        cm_onenet_discover(mid, 9, "5700");//返回将用到的资源列表
    }
    else if(objid == 4)
    {
        cm_onenet_discover(mid, 9, "2");//返回将用到的资源列表
    }
}


/**
 *  \brief 平台observe操作回调函数,需用户实现
 *  
 *  \param [in] mid 操作消息的ID
 *  \param [in] objid 被操作的object ID
 *  \param [in] insid 被操作的instance ID
 *  \param [in] resid 被操作的resource ID
 *  \return None
 *  
 *  \details More details
 */
static void cot_observe_cb(int mid, int observe, int objid, int insid, int resid)
{
    //TODO
    //...
    ds_printf("%d_%d_%d: %d\n", objid, insid, resid, observe);
    cm_onenet_result(mid, CM_RESULT_205_CONTENT, 1);//操作正确完成返回204
}


/**
 *  \brief 平台设置策略参数请求回调函数,需用户实现
 *  
 *  \param [in] mid 操作消息的ID
 *  \param [in] objid 被操作的object ID
 *  \param [in] insid 被操作的instance ID
 *  \param [in] resid 被操作的resource ID
 *  \param [in] len 数据长度
 *  \param [in] parameter 策略参数,格式如:pmin=xxx; pmax=xxx; gt=xxx; lt=xxx; stp=xxx
 *              pmin: int类型,上传数据的最小时间间隔
 *              pmax: int类型,上传数据的最大时间间隔
 *              gt: double类型,当数据大于该值上传
 *              lt: double类型,当数据小于该值上传
 *              stp:double类型,当两个数据点相差大于或者等于该值上传
 *  \return None
 *  
 *  \details More details
 */
static void cot_parameter_cb(int mid,int objid, int insid, int resid, int len, char *parameter)
{
    //TODO
    //...
    (void)objid;
    (void)insid;
    (void)resid;
    (void)len;
    (void)parameter;
    cm_onenet_result(mid, CM_RESULT_204_CHANGED, 0);//操作正确完成返回204
}







int open_onenet(void)
{  
   
    
    int onenet_retry_times=0;    //登录onenet尝试次数
    //登录ONENET
    {
        cm_cot_cb_t callback;
        callback.onRead = (cot_read_cb_t)cot_read_cb;
        callback.onWrite = (cot_write_cb_t)cot_write_cb;
        callback.onExec = (cot_execute_cb_t)cot_execute_cb;
        callback.onObserve = (cot_observe_cb_t)cot_observe_cb;
        callback.onParams = (cot_params_cb_t)cot_parameter_cb;
        callback.onEvent = (cot_event_cb_t)cot_event_cb;
        callback.onNotify = (cot_notify_cb_t)cot_notify_cb;
        callback.onDiscover = (cot_discover_cb_t)cot_discover_cb;
        
        cm_onenet_init();//初始化任务

      
        cm_onenet_create("183.230.40.40", 0, &callback);//创建设备

        if(cm_pm_get_power_on_reason()==0 || cm_pm_get_power_on_reason()==5 || cm_pm_get_power_on_reason()==2)
       {  
        cm_onenet_add_obj(3303, 1, (unsigned char*)"1", 0, 0);   //增加温度传感器
        cm_onenet_add_obj(3304, 1, (unsigned char*)"1", 0, 0);   //增加湿度传感器
        cm_onenet_add_obj(3, 1, (unsigned char*)"1", 0, 0);   //更新频率
         cm_onenet_add_obj(3316, 1, (unsigned char*)"1", 0, 0);//增加电压传感器
        cm_onenet_add_obj(4, 1, (unsigned char*)"1", 0, 0);      //增加通信链路监视
     
        cm_onenet_discover(3, 9, "26261");                     //更新频率属性
        cm_onenet_discover(3303, 9, "5700");                     //增加温度测量值属性
        cm_onenet_discover(3304, 9, "5700");                     //增加温度测量值属性
        cm_onenet_discover(3316, 9, "5700");                     //增加电压测量值属性
        cm_onenet_discover(4, 9, "2");                           //增加信号强度属性
       
          cm_onenet_close(2);//注销连接
          osDelay(500);
       int netrst= cm_onenet_open(30, 86400);                                //尝试打开ONENET,超时60秒,生命周期2000秒
        ds_printf("open onenet  %d\n",netrst);
       if(netrst>0) //如果打开失败,则退出,返回0
       { 
     
       ds_reboot(3);
        ds_printf("open onenet  failed!\n");
       return 0;
       
       }

       int openonentcts=0;
       while(!is_ref)     //等待20秒
       {
         osDelay(50);
       if(openonentcts<400)
       openonentcts++;
       else
       break;
       }
       
       ds_printf("connect time:%ld!\n",openonentcts*50);
        if(!is_ref) //ONENET超时
        {   ds_printf("连接ONENET超时\n");
   
       ds_reboot(4);
            return 0;
        }
        else
        {
         ds_printf("连接用时%ldms\n",openonentcts*50);
      
         if(cm_pm_get_power_on_reason()==0 || cm_pm_get_power_on_reason()==5 || cm_pm_get_power_on_reason()==2)
        osDelay(7000);//等待服务器发现资源
        return 1;
        }
       }
 
    }

}

int close_onenet(void)    //关闭ONENET
{
    
        cm_onenet_close(2);//注销连接
        cm_onenet_del_obj(3303);//释放obj订阅的资源
        cm_onenet_del_obj(3304);//释放obj订阅的资源
        cm_onenet_del_obj(3316);
        cm_onenet_del_obj(3);
        cm_onenet_close(4);//清理设备
        ds_printf("close onenet\n");
   return 1;
}




int update_sensor_value(char *temp_value,char *humi_value,char *bat_value) //上传传感器数据
{
int wait_tms=1000;

if(cm_pm_get_power_on_reason()==0 || cm_pm_get_power_on_reason()==5 || cm_pm_get_power_on_reason()==2)
{
   open_onenet();
}
else
{
if(cm_onenet_is_open()==0)
{ wait_tms=100;
ds_printf("查询网络状态成功!\n");
while (!is_ref)
{
   osDelay(300);
   if(wait_tms>=0)
   wait_tms--;
   else
   break;
}
if(!is_ref)
{ds_printf("等待网络状态字超时!\n");
    ds_reboot(15);
}
ds_printf("网络状态%d\n",is_ref);
}
else
{
ds_printf("查询网络状态失败!\n");
ds_reboot(5);
return 0;
}
}

if(is_ref)
{   char rssi = 0; //信号强度
    char ber = 0;  //误码率

    struct tm cur_time ={0};
    cm_rtc_get_time_tm(&cur_time); //获取当前时间

     ds_printf("开始数据更新\n");
     cm_cereg_state_t cereg_state = {0};
    cm_modem_get_csq(&rssi, &ber);
    cm_modem_get_cereg_state(&cereg_state);
    char rssistr[]="00";
    sprintf(rssistr,"%d",rssi);
 //   osDelay(5000);
     ds_printf("开始更新温度\n");

      int ack_base_1=1;
      int ack_base_2=2;
       if(cm_pm_get_power_on_reason()==2)
    {
     ack_base_1=11;
     ack_base_2=12;
    }
    int rstnot0=cm_onenet_notify(3303, 0, 5700, 4, temp_value, 1, ack_base_1, 0);//更新温度
    
    int wttms=0;

    if(rstnot0==0)   //上报数据函数执行成功!
    {
    while(ack0!=1)  //等待ACK;15000MS超时
    {
    osDelay(10);
    wttms++;
    if(wttms>150)
    break;;
    }
    ds_printf("更新用时%d\n",wttms*10);
    }

    ds_printf("开始更新湿度\n");
    int rstnot1=cm_onenet_notify(3304, 0, 5700, 4, humi_value, 1, ack_base_2, 0); //更新湿度 

     wttms=0;
     if(rstnot1==0)   //上报数据函数执行成功!
    {
    while(ack1!=1)  //等待ACK;15000MS超时
    {
    osDelay(10);
    wttms++;
    if(wttms>200)
    break;;
    }
    ds_printf("更新用时%d\n",wttms*10);
    }

      if(cur_time.tm_hour<1 || cm_pm_get_power_on_reason()==5 || cm_pm_get_power_on_reason()==2 || cm_pm_get_power_on_reason()==0)//每天零点更新电池电压和信号
    {
    ds_printf("开始更新电池电压\n" );
    int rstnot2=cm_onenet_notify(3316, 0, 5700, 4, bat_value, 1, 3, 0); //更新电池电压 
      wttms=0;
     if(rstnot2==0)   //上报数据函数执行成功!
    {
    while(ack2!=1)  //等待ACK;15000MS超时
    {
    osDelay(10);
    wttms++;
    if(wttms>200)
    break;;
    }
    ds_printf("更新用时%d\n",wttms*10);
    }
    ds_printf("开始更新信号强度\n");
    int rstnot3=cm_onenet_notify(4, 0, 2, 3, rssistr, 1, 4, 0); //更新信号强度 
    wttms=0;
     if(rstnot3==0)   //上报数据函数执行成功!
    {
    while(ack3!=1)  //等待ACK;15000MS超时
    {
    osDelay(10);
    wttms++;
    if(wttms>200)
    break;;
    }
    ds_printf("更新用时%d\n",wttms*10);
    }
    osDelay(6000);   //延迟6秒等待FOTA更新或者其他指令
    }


    if(rstnot0!=0 || ack0!=1)
    {ds_printf("第二次更新温度\n");
        rstnot0=cm_onenet_notify(3303, 0, 5700, 4, temp_value, 1, ack_base_1, 0);//第二次尝试更新温度
     wttms=0;

    if(rstnot0==0)   //上报数据函数执行成功!
    {
    while(ack0!=1)  //等待ACK;15000MS超时
    {
    osDelay(10);
    wttms++;
    if(wttms>150)
    break;;
    }
    ds_printf("更新用时%d\n",wttms*10);
    }
    }
    if(rstnot1!=0 || ack1!=1)
    {ds_printf("第二次更新温度\n");
        rstnot0=cm_onenet_notify(3304, 0, 5700, 4, humi_value, 1, ack_base_2, 0);//第二次尝试更新温度
     wttms=0;
     if(rstnot1==0)   //上报数据函数执行成功!
    {
    while(ack1!=1)  //等待ACK;15000MS超时
    {
    osDelay(10);
    wttms++;
    if(wttms>200)
    break;;
    }
    ds_printf("更新用时%d\n",wttms*10);
    }
    }

cm_onenet_update(86400,0);//更新生命周期
osDelay(3000);

}

return 1;
}

主文件:

/**
 *  @file    custom_main.c
 *  @brief   OpenCPU用户业务
 *  @copyright copyright © 2022 WUXI DOES IOT. All rights reserved.
 *  @author by Liuhuali
 *  @date 2022/07/08
 */


#include "stdlib.h"
#include "stdio.h"
#include "cm_os.h"
#include "cm_uart.h"
#include "custom_main.h"
#include "cm_common.h"
#include "cm_i2c.h"




/**
 *  \brief OpenCPU用户程序入口
 *  
 *  \return None
 *  
 *  \details 用户业务循环
 */
static void custom_task_loop(void* arg)
{//cm_modem_set_cfun(0);
    CM_UNUSED(arg);
   uint32_t batvol ;


    if(ds_ready()) //如果系统初始化成功
    {
     if(cm_pm_get_power_on_reason()==5 || cm_pm_get_power_on_reason()==0 || cm_pm_get_power_on_reason()==2)
     osDelay(2000); 

     sensor_power_turn_on();
     osDelay(500); //等待10000ms
      float th_vlaue[2];
      get_sensordata(th_vlaue);
      sensor_power_turn_off();//关闭传感器电源
      osDelay(500);
  
     // if(get_sensordata(th_vlaue))
     {sensor_power_turn_off();//关闭传感器电源
      uint32_t batvol ;
      cm_adc_vbat_read(&batvol);
      char tem_vlstr[]="0000.00";
      char hum_vlstr[]="0000.00";
      char bat_vlstr[]="0000.00";
      float2str(th_vlaue[1],tem_vlstr);
      float2str(th_vlaue[0],hum_vlstr);
      float2str((float)batvol/1000,bat_vlstr);
    
    if(ds_net_ready()) //网络是否准备好
    {
   
    update_sensor_value(tem_vlstr,hum_vlstr,bat_vlstr);
   
    }  


     }

    }

   if(ds_fota_start==1)
   {int delaytms=200;
   ds_printf("等待升级完成\n");
   while(delaytms>0 && ds_fota_start==1)
   {ds_printf("...\n");
   delaytms--;
    osDelay(100);
   }


   }
  
   enter_psm_sleep();
    osThreadExit();
}

/**
 *  \brief OpenCPU版本程序入口
 *  
 *  \return 空
 *  
 *  \details 仅用于创建OC线程,请勿修改此函数名
 */
void cm_opencpu_entry(void)
{

    osThreadAttr_t attr = {
        .name = "OpenCPU-CUSTOM",
        .priority = osPriorityNormal1,
        .stack_size = 1024,//WORD,size = 1024*4
    };

    osThreadNew(custom_task_loop, NULL, (const osThreadAttr_t *)&attr);
}

资源里有完整的工程文件,下载后可以直接用自带的编译批处理进行编译。硬件可以选择市面上常见MN316模块。

如有问题可以私信。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值