手把手教你玩转NB-IoT -- 第五弹:上报数据之智慧路灯
【摘要】 写在前面:相关API调用流程:LiteOS API方式接入 这部分的通过单片机搭载华为LiteOS操作系统,并移植了可兼容所有AT指令型的AT框架程序, 调用AT框架的API接口实现快速连接华为Oceanconnect平台。 并能实时...
写在前面:相关API调用流程:
LiteOS API方式接入
这部分的通过单片机搭载华为LiteOS操作系统,并移植了可兼容所有AT指令型的AT框架程序,
调用AT框架的API接口实现快速连接华为Oceanconnect平台。
并能实时接收平台下发的命令,实现对设备的控制,以下讲解调用API实现的方式。
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();
}
主程序主要包括初始化硬件外设、初始化内核、创建传感器数据采集任务、创建数据上报任务,接下来讲详细讲解主要部分的实现方式。
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串口。
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);
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;
}
烧录程序并打开串口助手可看到以下结果:
日志输出串口波特率为115200
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
作者其他文章
评论(0)