nRF52832上的无线漏水传感器,DIY项目

向哈勃(Habr)DIY或DIY自己动手部分的所有读者致以问候! 今天我想谈谈我的下一个项目,本文将介绍电池供电的漏水检测器。 与以前的项目一样,该设备在nRF52832微控制器上运行。 该传感器共有三个版本,在所有三个版本中均使用现成的模块以及nRF52832,在本文中,我们将讨论使用HOLYIOT的YJ-17103模块的中间版本。



流体检测器在芯片SN74LVC1G00上实现。 Datashit 。 我将简要描述电路设计和工作原理。 1号传感器电极接地,2号传感器电极通过100 Ohm电阻器连接到SN74LVC1G00芯片的A和B脚,通过1M电阻器连接的3.3V也连接到该线路,电容也添加到电路中。 当微电路A和B的支路上没有液体接触时,分别连接到MK支路(通过编程配置为通过内置比较器检测中断)的支路Y上的逻辑单元为逻辑零。 一旦与液体接触,并且支脚A和B处于低电平,SN74LVC1G00微电路的支脚Y上的信号也将反转,这将导致中断,从而将MK从睡眠中移除。 将来,芯片SN74LVC1G00可能会替换为芯片SN74LVC1G14 | Datashit ,也许不是:)。 没有计划通过内置比较器从MK支路检测流体。

像我所有其他项目一样,这也是一个Arduino项目,并且与过去一年中的所有项目(大约)一样,该项目也是为Mysensors项目而设计的。 与其他文章一样,我将在本文中稍微涉及Mysensors主题。

Mysensors是开发人员的开源社区。 该协议由社区开发,以创建无线电和有线网络。 该项目最初是为Arduino平台开发的。 标准的Mysensors网络由一个闸门(网关),重新变压器和终端设备(节点)组成。 在一个网络中,最多可以有254个设备,每个设备可以配备多达254个传感器,传感器,执行单元。 使用UD控制器执行网络操作,数据处理,脚本执行以及在其他设备中进行交互。 某些控制器(Majordomo)支持与多个网络和Mysensors(多门)配合使用,因此,与一个控制器控制的网络相比,网络可能更多。

支持的硬件平台 :Linux / Raspberry Pi / Orange Pi | ATMega 328P | ESP8266 | ESP32 | nRF5x(Cortex M0,M4)| Arduino Zero(Cortex M0)中使用的Atmel SAMD |德州仪器TI.com.cn Teensy3(MK66FX1M0VMD18)| STM32F1。

支持的无线电发射器 :NRF24L01 | RFM69 | RFM95(LoRa)| nRF5x

支持的有线通信类型 :RS485

门与控制器之间支持的通信 :MQTT | 串行USB | 无线网络 以太网| GSM

回到泄漏传感器。 该设备由CR2430,CR2450或CR2477电池供电。 睡眠功耗小于3μA。 传输速度-250Kbps,10-15ms。 传输时的功耗不超过8mA。 理论上,单个电池的电池寿命大约等于电池的自放电时间。 当然,实际上,所有事情都不那么乐观,因为需要进行注册,演示,定期发送电量水平,因此电池寿命更接近该值-自放电时间/ 2 :)。 电源直接由电池供电,电池电量直接由VDD引脚控制。 传感器中安装了RGB LED,以指示传感器在网络中的注册,指示服务模式和指示泄漏检测。 自然地,LED可以完全不使用或部分不使用。

器件板是根据LUT方法制造的,用于进一步制造。 因此,从此选项的细微差别来看,这是增加了走线的宽度,增加了走线之间的距离,增加了层间过渡的区域(以便更方便地钻孔)以及由于电路板的小面积而没有填充空白区域。 后来,选择了生产订单。



设备外壳分为两部分。 顶盖上有用于安装电路板的地方,下半部分(浴室)有2个用于钢制接触螺钉的孔(可以使用螺钉头的硅胶密封剂进行密封,也可以不要求密封)和两个用于按钮的管子(复位和模式)。 在ANICUBIC PHOTON SLA 3D打印机上完成打印。 在印刷之后,砂纸320和1000被处理以适合盖子和主体底部的接头。





传感器照片















测试码
wl_standart_test.ino

bool button_flag; bool send_flag; bool detection; bool nosleep; byte timer; bool AckG; bool AckB; bool AckL; bool PRESENT_ACK; bool flag_lq; unsigned long SLEEP_TIME = 172800000; //48 hours //unsigned long SLEEP_TIME = 3600000; //1 hour unsigned long oldmillis; unsigned long newmillis; unsigned long interrupt_time; unsigned long SLEEP_TIME_W; uint16_t currentBatteryPercent; uint16_t batteryVoltage = 0; uint16_t battery_vcc_min = 2300; uint16_t battery_vcc_max = 3000; int16_t linkQuality; #define MY_DISABLED_SERIAL #define MY_RADIO_NRF5_ESB #define MY_RF24_PA_LEVEL (NRF5_PA_MAX) //#define MY_PASSIVE_NODE #define MY_NODE_ID 86 #define MY_PARENT_NODE_ID 0 #define MY_PARENT_NODE_IS_STATIC #define MY_TRANSPORT_UPLINK_CHECK_DISABLED #define INTR_PIN 3 //(PORT0, gpio 5) #include <MySensors.h> // see https://www.mysensors.org/download/serial_api_20 #define W_L_SENS_CHILD_ID 0 #define LINK_QUALITY_CHILD_ID 253 MyMessage sensMsg(W_L_SENS_CHILD_ID, V_VAR1); //MyMessage voltMsg(CHILD_ID_VOLT, V_VOLTAGE); void preHwInit() { pinMode(POWER_PIN, OUTPUT); digitalWrite(POWER_PIN, HIGH); wait(3000); pinMode(RED_LED, OUTPUT); digitalWrite(RED_LED, HIGH); pinMode(GREEN_LED, OUTPUT); digitalWrite(GREEN_LED, HIGH); pinMode(BLUE_LED, OUTPUT); digitalWrite(BLUE_LED, HIGH); pinMode(PIN_BUTTON, INPUT); pinMode(W_L_SENS, INPUT); //pinMode(24, OUTPUT); //pinMode(20, OUTPUT); } void before() { NRF_POWER->DCDCEN = 1; NRF_UART0->ENABLE = 0; digitalWrite(BLUE_LED, LOW); sleep(50); digitalWrite(BLUE_LED, HIGH); } void presentation() { sendSketchInfo("EFEKTA ST WL Sensor", "1.1"); present(W_L_SENS_CHILD_ID, S_CUSTOM, "SWITCH STATUS"); present(LINK_QUALITY_CHILD_ID, S_CUSTOM, "LINK_QUALITY"); } void setup() { digitalWrite(BLUE_LED, LOW); wait(100); digitalWrite(BLUE_LED, HIGH); wait(200); digitalWrite(BLUE_LED, LOW); wait(100); digitalWrite(BLUE_LED, HIGH); lpComp(); detection = false; SLEEP_TIME_W = SLEEP_TIME; wait(100); sendBatteryStatus(); wait(100); send(sensMsg.set(detection), 1); wait(2000, 1, V_VAR1); } void loop() { if (nosleep == 0) { oldmillis = millis(); sleep(SLEEP_TIME_W); } if (detection) { if (digitalRead(PIN_BUTTON) == 1 && button_flag == 0 && digitalRead(W_L_SENS) == 0) { //back side button detection button_flag = 1; nosleep = 1; } if (digitalRead(PIN_BUTTON) == 1 && button_flag == 1 && digitalRead(W_L_SENS) == 0) { digitalWrite(GREEN_LED, LOW); wait(10); digitalWrite(GREEN_LED, HIGH); wait(50); } if (digitalRead(PIN_BUTTON) == 0 && button_flag == 1 && digitalRead(W_L_SENS) == 0) { nosleep = 0; button_flag = 0; digitalWrite(GREEN_LED, HIGH); lpComp_reset(); } if (digitalRead(W_L_SENS) == 1 && digitalRead(PIN_BUTTON) == 0) { //sens detection newmillis = millis(); interrupt_time = newmillis - oldmillis; SLEEP_TIME_W = SLEEP_TIME_W - interrupt_time; send(sensMsg.set(detection), 1); wait(3000, 1, V_VAR1); if (AckG == 1) { while (timer < 10) { timer++; digitalWrite(BLUE_LED, LOW); wait(20); digitalWrite(BLUE_LED, HIGH); wait(30); } timer = 0; AckG = 0; wait(200); } else { while (timer < 10) { timer++; digitalWrite(RED_LED, LOW); wait(20); digitalWrite(RED_LED, HIGH); wait(30); } timer = 0; send(sensMsg.set(detection), 1); wait(3000, 1, V_VAR1); if (AckG == 1) { while (timer < 10) { timer++; digitalWrite(BLUE_LED, LOW); wait(20); digitalWrite(BLUE_LED, HIGH); wait(30); } timer = 0; AckG = 0; } else { while (timer < 10) { timer++; digitalWrite(RED_LED, LOW); wait(20); digitalWrite(RED_LED, HIGH); wait(30); } timer = 0; } lpComp_reset(); } } if (SLEEP_TIME_W < 60000) { SLEEP_TIME_W = SLEEP_TIME; sendBatteryStatus(); } } else { //if (detection == -1) { SLEEP_TIME_W = SLEEP_TIME; sendBatteryStatus(); } } void receive(const MyMessage & message) { if (message.type == V_VAR1) { if (message.sensor == W_L_SENS_CHILD_ID) { if (mGetCommand(message) == 1) { if (message.isAck()) { AckG = 1; } else { } } } } if (message.type == I_BATTERY_LEVEL) { if (message.sensor == 255) { if (mGetCommand(message) == 3) { if (message.isAck()) { AckB = 1; } else { } } } } if (message.type == V_VAR1) { if (message.sensor == 255) { if (mGetCommand(message) == 1) { if (message.isAck()) { AckL = 1; } else { } } } } } void sendBatteryStatus() { wait(100); batteryVoltage = hwCPUVoltage(); wait(20); if (batteryVoltage > battery_vcc_max) { currentBatteryPercent = 100; } else if (batteryVoltage < battery_vcc_min) { currentBatteryPercent = 0; } else { currentBatteryPercent = (100 * (batteryVoltage - battery_vcc_min)) / (battery_vcc_max - battery_vcc_min); } sendBatteryLevel(currentBatteryPercent, 1); wait(3000, C_INTERNAL, I_BATTERY_LEVEL); if (AckB == 1) { AckB = 0; flag_lq = 1; } else { sendBatteryLevel(currentBatteryPercent, 1); wait(3000, C_INTERNAL, I_BATTERY_LEVEL); if (AckB == 1) { AckB = 0; flag_lq = 1; } } //send(powerMsg.set(batteryVoltage), 1); //wait(2000, 1, V_VAR1); //sleep(10000); // if (flag_lq == 1) { linkQuality = calculationRxQuality(); wait(50); sendSignalStrength(linkQuality, 1); wait(2000, 1, V_VAR1); if (AckL == 1) { AckL = 0; } else { sendSignalStrength(linkQuality, 1); wait(2000, 1, V_VAR1); if (AckL == 1) { AckG = 0; } } flag_lq = 0; } } void lpComp() { NRF_LPCOMP->PSEL = INTR_PIN; NRF_LPCOMP->ANADETECT = 1; NRF_LPCOMP->INTENSET = B0100; NRF_LPCOMP->ENABLE = 1; NRF_LPCOMP->TASKS_START = 1; NVIC_SetPriority(LPCOMP_IRQn, 15); NVIC_ClearPendingIRQ(LPCOMP_IRQn); NVIC_EnableIRQ(LPCOMP_IRQn); } void s_lpComp() { if ((NRF_LPCOMP->ENABLE) && (NRF_LPCOMP->EVENTS_READY)) { NRF_LPCOMP->INTENCLR = B0100; } } void r_lpComp() { NRF_LPCOMP->INTENSET = B0100; } #if __CORTEX_M == 0x04 #define NRF5_RESET_EVENT(event) \ event = 0; \ (void)event #else #define NRF5_RESET_EVENT(event) event = 0 #endif void lpComp_reset () { s_lpComp(); detection = false; NRF_LPCOMP->EVENTS_UP = 0; r_lpComp(); } //****************************** very experimental ******************************* bool sendSignalStrength(const int16_t level, const bool ack) { return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_SET, V_VAR1, ack).set(level)); } int16_t calculationRxQuality() { int16_t nRFRSSI_temp = transportGetReceivingRSSI(); int16_t nRFRSSI = map(nRFRSSI_temp, -85, -40, 0, 100); if (nRFRSSI < 0) { nRFRSSI = 0; } if (nRFRSSI > 100) { nRFRSSI = 100; } return nRFRSSI; } //****************************** very experimental ******************************* extern "C" { void LPCOMP_IRQHandler(void) { detection = true; NRF5_RESET_EVENT(NRF_LPCOMP->EVENTS_UP); NRF_LPCOMP->EVENTS_UP = 0; MY_HW_RTC->CC[0] = (MY_HW_RTC->COUNTER + 2); } } 

MyBoardNRF5.h

 #ifndef _MYBOARDNRF5_H_ #define _MYBOARDNRF5_H_ #ifdef __cplusplus extern "C" { #endif // __cplusplus #define PINS_COUNT (32u) #define NUM_DIGITAL_PINS (32u) #define NUM_ANALOG_INPUTS (8u) #define NUM_ANALOG_OUTPUTS (8u) #define PIN_LED1 (27) #define PIN_LED2 (25) #define PIN_LED3 (26) #define RED_LED (PIN_LED1) #define GREEN_LED (PIN_LED2) #define BLUE_LED (PIN_LED3) #define PIN_BUTTON (14) #define W_L_SENS (8) #define POWER_PIN (7) #define PIN_SERIAL_RX (12) #define PIN_SERIAL_TX (11) #ifdef __cplusplus } #endif #endif 


nRF52832通过编程配置为工作在低功耗模式(DC-DC模式)下,通过内部LPCOMP比较器从SN74LVC1G00微电路发出的信号将MC从休眠状态唤醒。 该设备还具有一个时钟按钮,用于实现服务模式,例如设备配对,重置设备等。 该按钮与检漏仪缠绕在同一MK脚上。 两条线都由肖特基二极管隔开。 处于监视模式的芯片SN74LVC1G00不消耗任何能量。 微电路的电源管理是从MK的分支进行的。

目前,这些传感器应与之一起工作的漏水控制器的开发工作即将完成。

显示泄漏传感器的视频


Github项目
(gerber文件,软件,案例模型,组件列表)

在这里,您总是乐于帮助想要了解MYSENSORS的每个人(安装板,在Arduino IDE环境中使用nRF5微控制器,使用mysensors协议的技巧,讨论新的版权项目- 电报聊天@mysensors_rus

Source: https://habr.com/ru/post/zh-CN460177/


All Articles