Sensor sem fio de temperatura, umidade e pressão atmosférica no nRF52832

Saudações a todos os leitores Habr! O artigo de hoje será sobre um sensor de temperatura, umidade e pressão atmosférica com uma bateria de longa duração. O sensor funciona no microcontrolador nRF52832 ( folha de dados ). Para obter temperatura, umidade e pressão atmosférica, foi utilizada a folha de dados do sensor BME280. O sensor é alimentado por baterias CR2430 / CR2450 / CR2477. O consumo no modo de transmissão é 8mA, no modo de suspensão 5mA. Então, sobre o pedido.


Este é um projeto do Arduino, o programa está escrito no IDE do Arduino.A biblioteca Adafruit Industries é usada para operar o sensor BME280 - sensores do github | github BME280 . Para trabalhar com placas nRF52832, o IDE do Ardeino usou o projeto Sandeep Mistry - github . A transferência de dados para o controlador da Smart House é realizada de acordo com o protocolo Mysensors - github boards | protocolo | biblioteca .

A placa do sensor foi desenvolvida no programa Diptrace. As dimensões da placa são 36,8 mm x 25 mm.



Lista de componentes utilizados
  • C1 - cap0603 100nF
  • C2 - cap0603 100nF
  • R1 - res0603 332
  • R2 - res0603 85b
  • R3 - res0603 113
  • R4 - res0603 912
  • R5 - res0603 113
  • R6 - res0603 512
  • R7 - res0603 512
  • RGBL1 - led0805 rgb
  • SWD - PPHF 2x3 6p 1,27 mm
  • U1 - YJ-16048 nRF52832
  • U2 - BME280
  • CONNECT - interruptor táctil KLS7-TS5401
  • RESET - botão do relógio KLS7-TS5401
  • Suporte de bateria KW-BS-2450-2-SMT
  • Comutador dsc0012


A taxa foi encomendada através do jlcpcb.com - US $ 2 por 5 peças em qualquer cor.





Link para o arquivo morto com arquivos gerber

O sensor funciona de acordo com o protocolo Mysensors. É fácil adicionar qualquer dispositivo à rede Mysensors. Vejamos o exemplo desse sensor, omitirei a explicação do código do sensor BME280, nada muda ao trabalhar com a rede Mysensors.

#define MY_DEBUG //   #define MY_RADIO_NRF5_ESB //   (  rfm69, rfm95, nrf24l01, nrf51-52) #define MY_RF24_PA_LEVEL (NRF5_PA_MAX) //    #define MY_DISABLED_SERIAL //   #define MY_PASSIVE_NODE //   (   mysensors), PASSIVE        ,   , ,  #define MY_NODE_ID 1 //     #define MY_PARENT_NODE_ID 0 //       //#define MY_PARENT_NODE_IS_STATIC //  PARENT_NODE        //#define MY_TRANSPORT_UPLINK_CHECK_DISABLED //      #include <MySensors.h> // -  MySensors #define TEMP_CHILD_ID 0 //     #define HUM_CHILD_ID 1 //     #define BARO_CHILD_ID 2 //      #define CHILD_ID_VOLT 254 //      MyMessage voltMsg(CHILD_ID_VOLT, V_VOLTAGE); //       MyMessage temperatureMsg(TEMP_CHILD_ID, V_TEMP); //      MyMessage humidityMsg(HUM_CHILD_ID, V_HUM); //      MyMessage pressureMsg(BARO_CHILD_ID, V_PRESSURE); //      
Apresentação de sensores e sensores no controlador de uma casa inteligente:

  sendSketchInfo("BME280 Sensor", "1.0"); //  ,   present(CHILD_ID_VOLT, S_MULTIMETER, "Battery"); //    ,  ,  present(TEMP_CHILD_ID, S_TEMP, "TEMPERATURE [C or F]"); //   ,  ,  present(HUM_CHILD_ID, S_HUM, "HUMIDITY [%]"); //   ,  ,  present(BARO_CHILD_ID, S_BARO, "PRESSURE [hPa or mmHg]"); //    ,  ,  

Transferência de dados para o controlador doméstico inteligente:
 send(voltMsg.set(batteryVoltage)); //       mW sendBatteryLevel(currentBatteryPercent); //       % send(temperatureMsg.set(temperature, 1)); //    ,  1    send(humidityMsg.set(humidity, 0)); //    ,  0    send(pressureMsg.set(pressure, 0)); //    ,  0    


Código do programa Arduino
 #include <Wire.h> #include <SPI.h> #include <Adafruit_Sensor.h> #include <Adafruit_BME280.h> //#define MY_DEBUG #define MY_RADIO_NRF5_ESB #define MY_RF24_PA_LEVEL (NRF5_PA_MAX) #define MY_DISABLED_SERIAL #define MY_PASSIVE_NODE #define MY_NODE_ID 1 #define MY_PARENT_NODE_ID 0 //#define MY_PARENT_NODE_IS_STATIC //#define MY_TRANSPORT_UPLINK_CHECK_DISABLED #include <MySensors.h> bool sleep_flag; bool metric = true; bool last_sent_value; uint16_t currentBatteryPercent; uint16_t lastBatteryPercent = 1000; uint16_t battery_vcc_min = 2150; uint16_t battery_vcc_max = 2950; uint16_t batteryVoltage; uint16_t battery_alert_level = 25; uint32_t default_sleep_time = 60000; uint32_t SLEEP_TIME; uint32_t newmillisforbatt; uint32_t battsendinterval = 3600000; float tempThreshold = 0.5; float humThreshold = 5; float presThreshold = 1; float pres_mmThreshold = 1; float temperature; float pressure; float pressure_mm; float humidity; float lastTemperature = -1; float lastHumidity = -1; float lastPressure = -1; float lastPressure_mm = -1; #define SEALEVELPRESSURE_HPA (1013.25) Adafruit_BME280 bme; #define TEMP_CHILD_ID 0 #define HUM_CHILD_ID 1 #define BARO_CHILD_ID 2 #define CHILD_ID_VOLT 254 MyMessage voltMsg(CHILD_ID_VOLT, V_VOLTAGE); MyMessage temperatureMsg(TEMP_CHILD_ID, V_TEMP); MyMessage humidityMsg(HUM_CHILD_ID, V_HUM); MyMessage pressureMsg(BARO_CHILD_ID, V_PRESSURE); void preHwInit() { pinMode(21, INPUT); pinMode(25, OUTPUT); digitalWrite(25, HIGH); pinMode(26, OUTPUT); digitalWrite(26, HIGH); pinMode(27, OUTPUT); digitalWrite(27, HIGH); } void before() { NRF_POWER->DCDCEN = 1; NRF_NFCT->TASKS_DISABLE = 1; NRF_NVMC->CONFIG = 1; NRF_UICR->NFCPINS = 0; NRF_NVMC->CONFIG = 0; if (NRF_SAADC->ENABLE) { NRF_SAADC->TASKS_STOP = 1; while (NRF_SAADC->EVENTS_STOPPED) {} NRF_SAADC->ENABLE = 0; while (NRF_SAADC->ENABLE) {} } pinMode(BLUE_LED, OUTPUT); pinMode(RED_LED, OUTPUT); digitalWrite(BLUE_LED, HIGH); digitalWrite(RED_LED, HIGH); digitalWrite(27, LOW); } void setup() { digitalWrite(27, HIGH); bme_initAsleep(); wait(100); sendBatteryStatus(); wait(100); } void presentation() { sendSketchInfo("EFEKTA BME280 Sensor", "1.2"); present(CHILD_ID_VOLT, S_MULTIMETER, "Battery"); present(TEMP_CHILD_ID, S_TEMP, "TEMPERATURE [C or F]"); present(HUM_CHILD_ID, S_HUM, "HUMIDITY [%]"); present(BARO_CHILD_ID, S_BARO, "PRESSURE [hPa or mmHg]"); } void loop() { wait(10); bme.takeForcedMeasurement(); wait(100); sendData(); if (millis() - newmillisforbatt >= battsendinterval) { sleep_flag = 1; sendBatteryStatus(); } if (sleep_flag == 0) { sleep(SLEEP_TIME); sleep_flag = 1; } } void blinky(uint8_t pulses, uint8_t repit, uint8_t ledColor) { for (int x = 0; x < repit; x++) { if (x > 0) { sleep(500); } for (int i = 0; i < pulses; i++) { if (i > 0) { sleep(100); } digitalWrite(ledColor, LOW); wait(20); digitalWrite(ledColor, HIGH); } } } void sendBatteryStatus() { wait(20); batteryVoltage = hwCPUVoltage(); wait(2); if (batteryVoltage > battery_vcc_max) { currentBatteryPercent = 100; } else if (batteryVoltage < battery_vcc_min) { currentBatteryPercent = 0; } else { if (lastBatteryPercent == 1000) { currentBatteryPercent = (100 * (batteryVoltage - battery_vcc_min)) / (battery_vcc_max - battery_vcc_min) + 5; } else { currentBatteryPercent = (100 * (batteryVoltage - battery_vcc_min)) / (battery_vcc_max - battery_vcc_min) - 5; } } sendBatteryLevel(currentBatteryPercent); wait(100); if (lastBatteryPercent < battery_alert_level) { blinky(3, 1, RED_LED); } else { blinky((last_sent_value == true ? 2 : 1), 1, BLUE_LED); } sleep_flag = 0; newmillisforbatt = millis(); } void sendData() { temperature = bme.readTemperature(); wait(20); humidity = bme.readHumidity(); wait(20); pressure = bme.readPressure() / 100.0F; if (!metric) { temperature = temperature * 9.0 / 5.0 + 32.0; } else { pressure = pressure * 0.75006375541921; } CORE_DEBUG(PSTR("MY_TEMPERATURE: %d\n"), (int)temperature); CORE_DEBUG(PSTR("MY_HUMIDITY: %d\n"), (int)humidity); CORE_DEBUG(PSTR("MY_PRESSURE: %d\n"), (int)pressure); if (abs(temperature - lastTemperature) >= tempThreshold) { send(temperatureMsg.set(temperature, 1)); lastTemperature = temperature; sleep(1000); } if (abs(humidity - lastHumidity) >= humThreshold) { send(humidityMsg.set(humidity, 0)); lastHumidity = humidity; sleep(1000); } if (abs(pressure - lastPressure) >= presThreshold) { send(pressureMsg.set(pressure, 0)); lastPressure = pressure; sleep(1000); } sleep_flag = 0; } void bme_initAsleep() { if (! bme.begin(&Wire)) { while (1); } bme.setSampling(Adafruit_BME280::MODE_FORCED, Adafruit_BME280::SAMPLING_X1, // temperature Adafruit_BME280::SAMPLING_X1, // pressure Adafruit_BME280::SAMPLING_X1, // humidity Adafruit_BME280::FILTER_OFF ); wait(1000); } 


A carcaça do sensor foi desenvolvida no editor 3D:



Foi impresso em uma impressora ANYCUBIC FOTON 3D, foi utilizada resina branca do mesmo fabricante, a espessura da camada foi escolhida média - 50 microns. O tempo de impressão do estojo e da capa é de 3 horas.








A rede MySensors na qual o sensor está funcionando se comunica com o sistema da casa inteligente da Magordomo. O sensor registrado no módulo Maysensors Majordomo é assim:




Teste de vídeo



Para aqueles que querem fazer o mesmo por si mesmos, o artigo fornece links para tudo o que você precisa.

Um lugar onde você está sempre feliz em ajudar todos os 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 - @mysensors_rus

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


All Articles