概述
相关信息
设备接入方式: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.rn");
}
首先调用 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 !rn");
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;
}
else
return 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_DTLS
sec_param_s sec;
sec.pskid = "868744031131026";
sec.psk = "d1e1be0c05ac5b8c78ce196412f0cdb0";
#endif
printf("rn=====================================================");
printf("rnSTEP1: Init NB Module( NB Init )");
printf("rn=====================================================rn");
#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("rn=====================================================");
printf("rnSTEP2: Register Command( NB Notify )");
printf("rn=====================================================rn");
los_nb_notify("+NNMI:",strlen("+NNMI:"),nb_cmd_data_ioctl,OC_cmd_match);
LOS_TaskDelay(3000);
printf("rn=====================================================");
printf("rnSTEP3: Report Data to Server( NB Report )");
printf("rn=====================================================rn");
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_DTLS
sec_param_s sec;
sec.pskid = "868744031131026";
sec.psk = "d1e1be0c05ac5b8c78ce196412f0cdb0";
#endif
printf("rn=====================================================");
printf("rnSTEP1: Init NB Module( NB Init )");
printf("rn=====================================================rn");
#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;
//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);
else
nb_set_no_encrypt();
}
while(1)
{
ret = nb_hw_detect();
printf("call nb_hw_detect,ret is %dn",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,"rn+NNMI:%d,%srn",&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:%sn",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;
}
注册字段匹配函数用于验证数据是否与注册字段匹配/
上报数据
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+NQMGSr";
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单片机+NB-IoT模组BC95采集温湿度数据发到电信平台(下)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复