【第六章】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.\r\n");}
首先调用 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 !\r\n");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;} elsereturn 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_DTLSsec_param_s sec;sec.pskid = "868744031131026";sec.psk = "d1e1be0c05ac5b8c78ce196412f0cdb0";#endifprintf("\r\n=====================================================");printf("\r\nSTEP1: Init NB Module( NB Init )");printf("\r\n=====================================================\r\n");#if AT_DTLSlos_nb_init((const int8_t*)"180.101.147.115",(const int8_t*)"5684",&sec);#elselos_nb_init((const int8_t*)"180.101.147.115",(const int8_t*)"5683",NULL);#endifprintf("\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*)(&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_DTLSsec_param_s sec;sec.pskid = "868744031131026";sec.psk = "d1e1be0c05ac5b8c78ce196412f0cdb0";#endifprintf("\r\n=====================================================");printf("\r\nSTEP1: Init NB Module( NB Init )");printf("\r\n=====================================================\r\n");#if AT_DTLSlos_nb_init((const int8_t*)"139.159.140.34",(const int8_t*)"5684",&sec);#elselos_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);elsenb_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;}
注册下发命令回调函数
注册下发命令回调函数可实现对平台下发命令的快速相应并处理
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;elsereturn -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+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;}
【第六章】STM32单片机+NB-IoT模组BC95采集温湿度数据发到电信平台(下)相关推荐
- stm32代码_ME3616 NB-IoT模组对接OneNET教程以及STM32代码
前言 本文讲解所有采用MT2625设计的NB-IoT模组ME3616对接OneNET,适用所有所有采用MT2625设计的NB-IoT模组. MT2625内置OneNET SDK,采用CoAP+LwM2 ...
- 第二章 零差云控关节模组内部构造
零差云控关节模组 https://www.zeroerr.cn/download/eRob.html 获取零差云控最新资料 第一章 单模组的使用 第二章 零差云控关节模组内部构造 第三章 IGH及pr ...
- IoT模组使用笔记(二):EC21、EC200指令流程、设置休眠、升级模组、切换运营商等
五.EC20.BC20等模组指令和问题 5.1 EC20 5.1.1 注册网络失败. 5.1.2 TCP连接指令流程: 5.2 BC20 5.2.1 上电指令流程 5.3 EC21-KL 5.3.1 ...
- 第一章 零差云控关节模组介绍
零差云控关节模组 第一章 零差云控关节模组介绍 第二章 电机拆解 第三章 IGH及preempt-rt的安装 第四章 命令行读取电机的信息 第五章 机械臂的组装及控制 文章目录 零差云控关节模组 @[ ...
- M5311nbiot 模组入坑 (接入华为物联平台)
M5311nbiot 模组入坑 (接入华为物联平台) 华为平台创建 进入华为物联网开发平台 开发中心 首先创建项目>进入产品开发(自定义一个产品)>Profile定义(属性和命令下达)&g ...
- 【第二章】NB-IoT模组BC95入网测试
硬件工具:BC95开发板 购买地址 .................................................................................. ...
- STM32单片机串口空闲中断+DMA接收不定长数据
在上一篇文章STM32单片机串口空闲中断接收不定长数据中介绍了利用串口空闲中断接收不定长数据,这种方式有一个问题就是串口每接收到一个字节就会进入一次中断,如果发送的数据比较频繁,那么串口中断就会不停打 ...
- mqtt 串口_移柯L620模组使用MQTT协议连接移动OneNet云平台
点击上方蓝色字体,关注我们 1 硬件基础 最近调测移柯L620 NB-IoT模组, 特申请调测L620开发板(L620_ EVB),其专门为评估和测试L620模块而设计的,用于帮助开发人员进行开发.调 ...
- NBIOT模组BC95功耗控制的问题
对于选择NBIOT的应用,相信功耗控制才是最核心的问题,针对该问题谈谈看法. 首先,收集网络上一些比较有价值的信息给大家参考,然后再结合项目实际情况写写自己的经验. 网络资源如下: (1)移远-BC9 ...
最新文章
- 大数据入门级学习路线
- 01ts简介和相关配置
- wxWidgets:wxSingleChoiceDialog类用法
- 如何在ASP.NET Core中使用SignalR构建与Angular通信的实时通信应用程序
- 论文浅尝 | 利用推理链进行视觉问题回答
- opencv roberts算子_边缘检测 Roberts算子
- InceptionNet与mobileNet
- php 实用 函数,PHP实用函数9
- kali Linux渗透测试教程.pdf
- OpenSTF手机设备管理平台-------二次开发
- 批处理版音视频播放器(甲兵时代原创批处理)(上)
- SQLMap中tamper的简介
- 使用csss实现切角矩形,切角矩形,切角边框
- Mysql上线长时间以后重新发起请求报错
- 3dsmax2022版本找不到漫反射和环境光解决
- 流畅的Python读书笔记
- Selenium自动化测试网页加载太慢怎么办
- WebRTC源码研究(7)创建简单的HTTPS服务
- 【运维实战】1.FastDFS分布式的文件存储系统入门介绍与实践
- wcdma matlab程序,一种基于MATLAB的WCDMA信号仿真方法.doc