700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 【第六章】STM32单片机+NB-IoT模组BC95采集温湿度数据发到电信平台(下)

【第六章】STM32单片机+NB-IoT模组BC95采集温湿度数据发到电信平台(下)

时间:2019-09-08 11:19:42

相关推荐

【第六章】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(_nmgr, 0, 30);if (readlen > 0){HexStrToStr(tmpbuf, _nmgr,readlen*2);}AT_LOG("cmd is:%s\n",_nmgr);if(strcmp(_nmgr,"ON")==0){HAL_GPIO_WritePin(Light_GPIO_Port,Light_Pin,GPIO_PIN_RESET);}if(strcmp(_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;}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。