简介:
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模块。
如有问题可以私信。