NB-IoT 智能门磁传感器原型设计(MCU 主控)

更新时间Invalid date

概况

智能门磁传感器在智能安防领域扮演着重要的角色,应用的场合也越来越多。离家后不确定家中门窗是否关闭?不妨打开手机确认一下。文介绍如何使用涂鸦三明治开发板快速完成一个基于 NB-IoT 通信模组的低功耗智能门磁传感器产品原型,实现 门磁电池电量 两个基础功能。

MCU 方案与 SoC 方案不同,传感器和联网模组的驱动代码写在 MCU 中,您可以自行开发 MCU 代码,拥有更多的可玩性。涂鸦三明治开发板门磁传感套件中,传感器板干簧管根据开合状态输出高低电平给 MCU 控制板,MCU 通过串口 与 NB-IoT 通信板连接,使用涂鸦智能 App 配网。您可以将门磁状态展现在手机端,并与其他智能设备联动。本教程中:

  • MCU 型号为 STM32G071RB
  • Demo 例程以 Keil(MDK-ARM)为开发环境,使用 STM32CubeMX 配置生成初始化代码

物料清单

硬件 (3)
  • 涂鸦三明治 NB-IoT 通信板(NM1)

    数量:1

    配合 MCU 使用,提供联网能力。查看详情

  • 涂鸦三明治门磁传感器功能板

    数量:1

    通过磁铁靠近或远离干簧管使干簧管通断产生的高低电平信号来判断当前的门窗磁状态是开启或关闭。查看详情

  • NUCLEO-G71RB

    数量:1

步骤

  • 第 1 步:硬件连接

    本次使用的涂鸦三明治开发板门磁传感套件主要包含:

    • 门磁传感器功能板,板载两路干簧管一路触发输出为低,一路触发输出为高,您可以根据实际情况选用。

    • NB-IoT MCU 通信板,板载涂鸦 NM1 模组,负责智能化连接。模组已烧录通用固件,MCU 对接涂鸦串口协议,即可使用模组+App+云涂鸦一站式智能化服务。

    • MCU控制板,采用ST官方 NUCLEO-G071RB 开发板,负责传感数据接收和模组通讯控制。

      将三明治开发板套件控制板、通讯板、功能板拼接组装,实物效果如下图。

      硬件链接图
  • 第 2 步:例程环境

    软件开发过程主要使用 STM32CubeMX 来配置初始化 MCU,以 Keil5 为开发环境实现 MCU 与传感器和模组协议对接。首先调通 MCU 和模组的通讯,可以实现 App 配网,MCU 数据传输到 App。

  • 第 3 步:创建工程和产品

    您可以根据以下步骤,快速在涂鸦 IoT 平台上开发一个智能门磁。
    1. 进入 涂鸦智能IoT平台

    2. 参考 选品类创建产品 创建一款门磁产品。其中产品属性如下:

      • 开发方式:自定义方案
      • 联网方式:NB-IoT
      • 功耗类型:PSM
        image.png
    3. 根据页面提示选择产品的标准功能和自定义功能。功能选择 门磁电池电量,本DEMO例程只支持这两个基本功能,如需其它功能需要自行实现。

      image.png

    4. 选择您喜欢的面板,第一次开始调试也可以选择为开发调试面板,便于调试,后面也可以更换面板。

    5. 面板选择完后,进入 硬件开发 阶段,在页面拉到最下面,下载开发资料。

      image.png

    6. 硬件测试。

      下载到 MCU 开发包后,使用开发包中的涂鸦模组调试助手,您可以使用助手模拟 MCU 模式,配合调试模组通讯板,验证模组是否通讯正常,同时也可以熟悉涂鸦串口协议提高对接效率。确定通信板正常可用的,可以跳过此步骤。若调试过程中对协议收发有疑问,也可以使用此助手协助查看正确数据交互格式。 使用步骤可参考 涂鸦模组调试助手使用说明

  • 第 4 步:移植 MCU SDK

    在使用 STM32CubeMX 生产初始化工程代码后,即可开始移植 MCU_SDK。本章节简单介绍了移植过程和功能实现,将 mcu_sdk 中的文件加入工程后,编译根据报错提示,进行修改。如需查看详细的移植调试教程,请参考 MCU SDK 移植

    1. uart_transmit_output() 函数按照 #error 中的提示信息处理,处理后注释掉。

      mcusdk移植1.png

    2. 完善 uart_receive_input()函数按照#error中的提示信息处理,处理后注释掉。
      mcusdk移植2.1.png

    3. nbiot_uart_service()函数按照#error中的提示信息处理,处理后注释掉。

      涂鸦技术文档示意图
    4. nbiot_protocol_init()函数按照#error中的提示信息处理,处理后注释掉。

      image.png

    接下来便是all_data_update()函数,该函数会自动上报系统中所有 DP 信息,您不要调用该函数。

  • 第 5 步:编写嵌入式程序

    1. 新建一个 user_func.h 文件,在其中定 + 义一个结构体,用来记录门磁设备的各种状态。
    // 传感器上报标志
    typedef enum{
    	STATE_IDLE         = 0,
    	STATE_DOOR_NEED_UP = 1	
    }sensor_state_t;
    
    // 门开关状态
    typedef enum{
    	STATE_CLOSE         = 0,
    	STATE_OPEN          = 1	
    }door_state_t;
    
    typedef struct{
        door_state_t door_state;         
    	sensor_state_t sensor_state;
    	unsigned char door_up_lock;      // 门状态上报锁
    	unsigned char remaining_power;   // 设备剩余电量,单位百分比
    }device_status_t;
    
    1. 在新建的user_func.c文件中实现一些自定义的功能函数,同时在nbiot.h文件中添加头文件#include "user_func.h"

    2. main.c文件中,添加头文件 #include "nbiot.h"

      MCU上电启动后,进入while(1){}循环前,除了常规的配置IO口、串口、ADC以外还需要执行的:

      nbiot_protocol_init();
      
      // 使能低功耗模式时钟
      __HAL_RCC_PWR_CLK_ENABLE();
      
      // 初始化NB模组唤醒脚的电平
      HAL_GPIO_WritePin(GPIOA,GPIO_PIN_10,GPIO_PIN_SET);
      

      ​ 在while(1){}循环内:

      while (1)
      {
          nbiot_uart_service();
           
          power_detect_poll();
          
          user_sensor_up_poll();
      }
      
      • nbiot_uart_service()是SDK提供的串口数据处理函数,解析并处理NB-IoT模组返回的数据。

      • power_detect_poll()是电池电量检测函数,在函数内通过ADC采样和换算得出大概的剩余电量并保存。由您自行实现。

      • user_sensor_up_poll()是传感器上报任务处理函数,根据NB模组的设备状态等多种因素判读是否做上报数据发送处理以及是否需要让MCU进入STOP低功耗模式。由您自行实现。

      void user_sensor_up_poll(void)
      {	
      	// 	当NB模组为已绑定连接状态且门状态上报锁打开的情况下。门状态上报锁在收到模组上报成功回码后会打开
      	if((NB_STATE_DEVICE_BINDED == mcu_get_nbiot_work_state()) && (device_status_s.door_up_lock)) {
      
      		// 判读有未处理的门状态上报任务,开始向NB模组发送上报数据。
      		if(STATE_DOOR_NEED_UP == device_status_s.sensor_state) {
      			device_status_s.sensor_state = STATE_IDLE;
                  mcu_dp_bool_update(DPID_DOORCONTACT_STATE, device_status_s.door_state);
      			device_status_s.door_up_lock = 0;				
      		} else {
      			
      			// 判断剩余电量是否低于电量上报阈值,发送电量上报数据并降低阈值
      			if (device_status_s.remaining_power <= power_threshold) {
      				mcu_dp_value_update(DPID_BATTERY_PERCENTAGE, device_status_s.remaining_power);
      				if(power_threshold >= 25) {
      					power_threshold -= 25;	
      				}
      			}
      
      			// 打开NB模组PSM休眠锁
      			mcu_set_nbiot_sleeplock(0);
      			// MCU进入低功耗模式
      			enter_lowpower_mode();							
      		}
      	}
      }
      

      实现进入和退出低功耗模式两个函数:

      void enter_lowpower_mode()
      {	
      	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_10,GPIO_PIN_SET);
      
      	lowpower_gpio_init();
      
      	HAL_ADC_Stop(&hadc1);
      	HAL_ADC_DeInit(&hadc1);
      
      	HAL_UART_DeInit(&huart3);
      
      	// HAL_TIM_Base_DeInit(&htim3);
      
      	// 关闭时钟
      	__HAL_RCC_DMA1_CLK_DISABLE();
      	__HAL_RCC_GPIOB_CLK_DISABLE();
      	__HAL_RCC_GPIOC_CLK_DISABLE();
      	__HAL_RCC_GPIOC_CLK_DISABLE();          
      	__HAL_RCC_GPIOD_CLK_DISABLE();
      	__HAL_RCC_GPIOF_CLK_DISABLE();
      
      	HAL_SuspendTick();
      	// 进入stop模式	
      	HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON,PWR_STOPENTRY_WFI);
      }
      
      void leave_lowpower_mode()
      {
      	SystemClock_Config();
      
      	MX_GPIO_Init();
      
      	// MX_TIM3_Init();
      
      	MX_USART3_UART_Init();
      	__HAL_UART_ENABLE_IT(&huart3, UART_IT_RXNE);
      
      	MX_ADC1_Init();
      	HAL_ADC_Start(&hadc1);
      
      	// 拉低引脚唤醒NB模组
      	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_10,GPIO_PIN_RESET);
      
      	// 传感器需要上报门开关状态
      	device_status_s.sensor_state = STATE_DOOR_NEED_UP;
      }
      


      MCU的Stop低功耗模式主要由中断来唤醒,所以需要在中断回调函数中调用nbiot_uart_service()并记录门的开关状态:

      void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
      {
      	leave_lowpower_mode();
      	device_status_s.door_state = STATE_OPEN;
      }
      
      
      void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
      {
      	leave_lowpower_mode();
      	device_status_s.door_state = STATE_CLOSE;
      }
      

      ​由于NB模组从PSM模式中唤醒需要重新连接涂鸦云,唤醒时第一次门状态上报会失败,所以需要在模组连接成功并返回工作状态回码时重新发送一次上报状态,即在system.c文件下data_handle函数的工作状态回码处理case中添加代码实现:

      // 工作状态	
      case NBIOT_STATE_CMD:
          nbiot_work_state = nbiot_uart_rx_buf[offset + DATA_START];
          nbiot_uart_write_frame(NBIOT_STATE_CMD,0);
      
      
      	if (STATE_DOOR_NEED_UP == mcu_get_nbiot_work_state()) {	
              mcu_dp_bool_update(DPID_DOORCONTACT_STATE, device_status_s.door_state);
              device_status_s.sensor_state = STATE_IDLE;
      	}
      break;
      

      ​在system.c文件下data_handle函数的上报回码处理case中添加代码:

      
      case STATE_UPLOAD_CMD: 
      	// 判断result的值,确认收到模组返回的信息后,打开门状态上报锁,准备下一次上报
          device_status_s.door_up_lock=1;
      break;
      
  • 第 6 步:(可选)场景联动

    产品功能调试通过后,App 端已经可以接收到门磁感器的数据。智能传感器最大的应用场景是用来收集传感数据来和其它产品进行联动。如果您已经拥有了其他涂鸦生态设备或开发板,可以在 App 端实现场景联动功能的配置。详细步骤,请参考 场景联动设置

    场景联动.png

小结

基于涂鸦智能 IoT 平台,您可以使用三明治开发板、STM32CubeMX、Keil开发环境,快速搭建一款智能门磁传感器产品原型。
那么现在用这套方案就可以解决在办公室找坑位的问题了!
组装:
image.png
image.png
image.png
成品:
image.png
现在足不离工位就可以清楚的查看坑位情况了。
image.png