手把手教你玩转NB-IoT -- 第五弹:上报数据之智慧路灯
写在前面:相关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
- 点赞
- 收藏
- 关注作者
评论(0)