Sensor de vazamento de água sem fio no nRF52832, projeto DIY

Saudações a todos os leitores da seção faça você mesmo ou faça você mesmo em Habr! Hoje eu quero falar sobre o meu próximo projeto, este artigo será sobre um detector de vazamento de água a bateria. Como nos projetos anteriores, este dispositivo é executado no microcontrolador nRF52832. Existem três versões deste sensor, nas três versões são utilizados módulos prontos com nRF52832; neste artigo, falaremos sobre a versão intermediária que usa o módulo YJ-17103 da HOLYIOT.



O detector de fluido é implementado no chip SN74LVC1G00 | Datashit . Descreverei brevemente o design do circuito e o princípio de operação. O eletrodo do sensor n ° 1 está conectado ao terra, o eletrodo do sensor n ° 2 está conectado às pernas A e B do chip SN74LVC1G00 através de um resistor de 100 Ohm, 3,3V através de um resistor de 1M também é conectado a esta linha, uma capacitância também é adicionada ao circuito. Quando não há contato com o líquido nas pernas do microcircuito A e B, a unidade lógica, respectivamente, na perna Y conectada à perna MK (configurada programaticamente para detectar interrupções através do comparador embutido) é lógica zero. Assim que o contato com o líquido ocorre e as pernas A e B são baixas, o sinal na perna Y do microcircuito SN74LVC1G00 também é invertido, o que causará uma interrupção e, por sua vez, removerá o MK do sono. No futuro, o chip SN74LVC1G00 poderá ser substituído pelo chip SN74LVC1G14 | Datashit , e talvez não :). A detecção de fluido das pernas MK através do comparador embutido não está planejada.

Como todos os meus outros projetos, este também é um projeto do Arduino e, como todos os projetos do ano passado (aproximadamente), este também foi feito para o projeto Mysensors. Como nos meus outros artigos, abordarei um pouco o assunto dos Mysensors neste artigo.

Mysensors é uma comunidade de desenvolvedores de código aberto. Este protocolo é desenvolvido pela comunidade para criar redes de rádio e com fio. O projeto foi desenvolvido originalmente para a plataforma Arduino. Uma rede padrão de Mysensors consiste em um gate (gateway), retransformadores e dispositivos finais (nós). Em uma rede, pode haver até 254 dispositivos, cada um dos dispositivos pode ser equipado com até 254 sensores, sensores e unidades de atuação. A operação de rede, processamento de dados, execução de scripts e interação em outros dispositivos é realizada usando o controlador UD. Alguns dos controladores (Majordomo) suportam o trabalho com várias redes e Mysensors (multi-gate), portanto, pode haver muito mais redes do que uma controlada por um controlador.

Plataformas de hardware suportadas : Linux / Raspberry Pi / Orange Pi | ATMega 328P | ESP8266 ESP32 nRF5x (córtex M0, M4) | Atmel SAMD usado no Arduino Zero (Cortex M0) | Teensy3 (MK66FX1M0VMD18) | STM32F1.

Transmissores de rádio suportados : NRF24L01 | RFM69 RFM95 (LoRa) | nRF5x

Tipo de comunicação com fio suportada : RS485

Comunicação suportada entre o portão e o controlador : MQTT | USB serial | Wifi | Ethernet GSM

De volta ao sensor de vazamento. O dispositivo é alimentado por baterias CR2430, CR2450 ou CR2477. O consumo de sono é inferior a 3μA. Velocidade de transmissão - 250Kbps, 10-15ms. O consumo de energia no momento da transmissão não é superior a 8mA. Teoricamente, a duração da bateria em uma única bateria é aproximadamente igual ao tempo de autodescarga da bateria. Na prática, é claro, tudo é menos otimista, já que há um registro, apresentação, envio periódico do nível de carga, para que a vida útil da bateria seja mais próxima do valor - tempo de autodescarga / 2 :). A energia é fornecida diretamente da bateria, o nível da bateria é controlado diretamente do pino do VDD. Um LED RGB está instalado no sensor para indicar o registro do sensor na rede, para indicar os modos de serviço e para detectar a detecção de vazamentos. Naturalmente, o LED não pode ser usado de todo ou em parte.

A placa do dispositivo foi fabricada para sua fabricação posterior, de acordo com o método LUT. Portanto, a partir das nuances desta opção, é um aumento da largura dos trilhos, maiores distâncias entre os trilhos, maiores áreas para transições entre camadas (para uma perfuração mais conveniente dos furos), ausência de preenchimento de áreas vazias devido à pequena área da placa. Mais tarde, uma opção foi feita para um pedido em produção.



A caixa do dispositivo foi projetada em duas partes. A tampa superior com locais para montagem da placa e a parte inferior (banho) com 2 furos para os parafusos de contato de aço (é possível vedar com selante de silicone para a cabeça do parafuso ou não é necessário) e dois tubos para botões (reset e modos) na placa. A impressão foi feita em uma impressora ANICUBIC PHOTON SLA 3D. Após a impressão, as lixas 320 e 1000 foram processadas para encaixar as juntas da tampa e da parte inferior do corpo.





Fotos do sensor















Código de teste
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 


O nRF52832 é configurado de forma programática para operar no modo de baixa energia (modo DC-DC) O MC é acordado do modo de suspensão por um sinal do microcircuito SN74LVC1G00 por meio do comparador LPCOMP interno. O dispositivo também possui um botão de relógio para implementar modos de serviço, como emparelhamento, redefinição do dispositivo etc. O botão é acionado no mesmo pé MK do detector de vazamento. Ambas as linhas são separadas por diodos Schottky. O chip SN74LVC1G00 no modo de monitoramento não consome nada. O gerenciamento de energia do microcircuito é realizado a partir das pernas do MK.

No momento, o desenvolvimento de um controlador para vazamento de água com o qual esses sensores devem funcionar está quase terminado.

Vídeo mostrando o sensor de vazamento


Projeto Github
(arquivos gerber, software, modelos de casos, lista de componentes)

Um lugar onde você está sempre feliz em ajudar todos que desejam se familiarizar com os MYSENSORS (instalar placas, trabalhar com microcontroladores nRF5 no ambiente IDE do Arduino, dicas sobre como trabalhar com o protocolo mysensors, discutir novos projetos de direitos autorais - telegrama chat @mysensors_rus .

Source: https://habr.com/ru/post/pt460177/


All Articles