Termômetro e higrômetro no ATMEGA 328P-MU - Elevando o nível de desenvolvimento do Arduino

Hoje eu quero compartilhar um dos meus projetos do Arduino. Era uma vez, não muito tempo atrás, em algum lugar da Internet, eu descobri o Arduino. Eu entrei neste negócio muito rapidamente, o nível de entrada não é alto. Depois de algum tempo, já tendo coletado um monte de sensores, os sensores de uma casa inteligente começaram a me pegar pensando que, de alguma forma, tudo estava fora de si. Módulos, grandes caixas lisas, um monte de fios e cola quente :). Olhando para a minha caixa com um sensor de temperatura e, por exemplo, para o sensor de temperatura da mesma Xiaomi, percebi que queria parecer com a Xiaomi, mas ao mesmo tempo que você podia reprogramar como a minha em uma caixa medindo 10cm por 6cm com fios e adesivo hotmelt. E provavelmente o início dos meus projetos de arduino DIY em placas PCB foi lançado.

No artigo de hoje, falaremos sobre um sensor de temperatura e umidade baseado no processador atmega328p-mu. Esta é uma versão “menor” (um analógico absoluto) do processador atmega328p-au (Arduino Uno, Pro Mini, Nano), conhecido por todos os desenvolvedores de arduino. Se alguém leu meus artigos antes, eles sabem que eu prefiro Mysensors. O que é isso Essa é uma biblioteca muito simples e bem projetada e, o que é importante, bem descrita para o Arduino IDE (e não apenas) para criar redes de rádio IOT em frequências de 2,4 GHz, 915, 868, 433 MHz, bem como redes com fio na interface 485, talvez nem todas mencionadas. O protocolo está em constante evolução, algo está sendo adicionado o tempo todo.

A primeira coisa que foi feita foi o próprio sensor na placa PCB. Fiz isso sem olhar para o caso, de acordo com o princípio, o principal é fabricar um sensor e imprimi-lo de alguma forma ... sim, não faça isso :). De fato, o sensor em si é o mesmo arduinka Pro Mini, o módulo de rádio nRF24l01, o sensor de temperatura e umidade SHT20, apenas sem fios e cola quente. Entre os "sinos e assobios", esta é uma unidade flash SPI externa para piscar no ar (o carregador de inicialização DualOptibut é necessário para a operação, depois parei de colocá-los (unidades flash) nas placas, pois não há firmware no ar e metade da bateria) e o "microfone criptográfico" ATSHA204A, por assim dizer, a cheio kit de hardware (em Mysensors, para ativar assinaturas, criptografia, etc., basta especificar o #def necessário no início do esboço).



O próprio painel foi criado no programa Diptrace, depois de assistir aos tutoriais em vídeo no YouTube, a princípio parecia algo "infernal", mas, na realidade, acabou não sendo tão difícil. Encomendei pranchas na China em jlcpcb.com, 2 dólares, de qualquer cor e, após 2 semanas, você já tem 10 peças de "sua própria criação" em suas mãos :).





O próximo passo foi o desenvolvimento do corpo. Oh, isso acabou sendo o mesmo problema. Em geral, não procurei maneiras fáceis, decidi dominar o Solid Works. Como se viu, isso não é nada parecido com o Deeptrace. No entanto, eu recomendo este editor para estudo. O processo de aprendizado durou um mês assistindo a vídeo aulas no YouTube e repetindo a lição no editor. No processo de desenvolvimento do caso, ficou claro que fazer uma placa de dispositivo sem levar em consideração os parâmetros do caso futuro é uma péssima decisão, da série em que inserimos os manípulos em nossas próprias rodas. De acordo com os resultados das versões da placa, três foram lançadas, levando em consideração a instalação da placa no caso, e acho que essa não é a última opção.

No início do desenvolvimento do edifício, a idéia era imprimi-lo em uma impressora 3D FDM, mas quanto mais dentro da floresta, mais ficou claro que ele não era capaz de reproduzir toda a minha lista de desejos. Quando esse entendimento chegou, eu já aprendi sobre outra tecnologia de impressão 3D - SLA. Sem pensar duas vezes e impressionado com a qualidade da impressão, foi emitida a lista de desejos no Ali - ANYCUBIC Photon . (Link ana Ali, não publicidade, não afiliado, ... apenas um link).

Vou escrever agora, agora, com base na minha experiência no momento em que escrevo, ... oh, isso é legal, é legal !!! O caso que foi projetado no editor, é claro, e não foi impresso pela primeira vez, e houve muitas melhorias. Bem, provavelmente não é o contrário. Como resultado, obtive o resultado que queria. Um dispositivo em miniatura, um bom estojo de bricolage com detalhes muito precisos, botões, fontes, tudo como representado na cabeça. Um ímã foi adicionado à tampa traseira, agora ele pode ser facilmente montado em superfícies de ferro.

















Estas são tentativas de imprimir o mesmo modelo em uma impressora FDM:





Como o dispositivo acabou sendo pequeno, mas ainda é um arduinka, fiquei perplexo com a saída de conectores em miniatura para programação. E, consequentemente, foi feito um pequeno adaptador para os conectores para uma conexão conveniente com o programador e o conversor TTL.



Tudo foi comprado no Ali (sim, não existem apenas módulos completos do arduino)

Capacitor de tântalo SMD 4.7uF - 4.7uF | 10v 10% - C1
Capacitor cerâmico SMD 100nF | Y5V - 100nF | 50v + 80-20% - C2, C3, C4, C5, C6, C7
LED - LADO DO LED - D1
Pin Header Female - 2x3P | 6 pinos | 1,27 mm - J1, J2
Resistor SMD 20K Ohm - 20K | 5% - R1
Resistor SMD de 4.7K Ohm - 4.7K | 5% - R2, R3, R4
Resistor SMD de 470K Ohm - 470 | 1% - R5
Resistor SMD 1M Ohm - 1M | 1% - R6
Resistor SMD de 18K Ohm - 18K | 5% - R7
Resistor SMD 10K Ohm - 10K | 5% - R8
Botão lateral SMD de 4 pinos - SW1, SW2
Memória Flash Serial SPI de 512 Kbit, 1,65 V - AT25DF512C-SSHN-B - U1
Mini NRF24L01 + 2,4 GHz 1,27 MM RF - nRF24l01 1,27 SMD - U2
ATMEGA328P-MU QFN32 - U3
AUTENTICAÇÃO CRIPTO, 1 FIO - ATSHA204A-STUCZ-T - U4
IC do sensor de umidade e temperatura - SHT20 - U5
SUPORTE PARA BATERIA PARA CR2477-1 - L-KLS5-CR2477-1 - U6

O código do programa é bastante simples. Um exemplo da biblioteca DFRobot foi usado para trabalhar com o sensor SHT20. Em princípio, qualquer rascunho, para qualquer sensor, pode ser transformado em um rascunho para trabalho na rede Mysensors em 5 minutos.

Listagem de código
#include <Wire.h>
#include "DFRobot_SHT20.h"
DFRobot_SHT20    sht20; // https://github.com/DFRobot/DFRobot_SHT20

#define MY_DEBUG
//#define MY_DISABLED_SERIAL
#define MY_RADIO_RF24
#define MY_PASSIVE_NODE
#define MY_NODE_ID 200
#define MY_PARENT_NODE_ID 0
#define MY_PARENT_NODE_IS_STATIC
#define MY_TRANSPORT_UPLINK_CHECK_DISABLED
//#define MY_OTA_FIRMWARE_FEATURE
//#define MY_SIGNING_ATSHA204
//#define MY_SIGNING_ATSHA204_PIN A3
//#define MY_SIGNING_REQUEST_SIGNATURES

#define TEMP_SENS_ID 1
#define HUM_SENS_ID 2
#define SETTING_LED_SENS_ID 100
#define DELAY_TIME_SENS_ID 101
#define BATTARY_SEND_SENS_ID 102
#define BATTARY_DATA_SENS_ID 103

#define BAT_COOF 3.04
#define BAT_MIN 195
#define BAT_MAX 295
#define ON 1
#define OFF 0

float humd;
float temp;
float oldhumd;
float oldtemp;
float tempThreshold = 0.5;
float humThreshold = 10.0;
static uint32_t lightMillis;
static uint32_t previousMillis;
uint32_t send_batteryTime;
uint32_t w_battetyTime = 0;
static uint8_t led_pin = 4;
static uint8_t mode_pin = 2; // interrupt
uint32_t delayTime;
int8_t battery;
int8_t old_battery;
uint8_t set_led;
boolean sleep_mode;
boolean configMode = 0;
int8_t timer_status = 0;
bool flag_mode_button = 0;
bool sleep_flag = 0;
bool listen_flag = 0;

#include <MySensors.h>

MyMessage msg_temp(TEMP_SENS_ID, V_TEMP);
MyMessage msg_hum(HUM_SENS_ID, V_HUM);
MyMessage msg_setting_led(SETTING_LED_SENS_ID, V_VAR1);
MyMessage msg_delay_time(DELAY_TIME_SENS_ID, V_VAR1);
MyMessage msg_battary_send(BATTARY_SEND_SENS_ID, V_VAR1);
MyMessage powerMsg(BATTARY_DATA_SENS_ID, V_VAR1);

void preHwInit()
{
  pinMode(led_pin, OUTPUT);
  digitalWrite(led_pin, OFF);
  pinMode(mode_pin, INPUT_PULLUP);
}

void before()
{
  set_led = loadState(100);
  if (set_led > 1) {
    set_led = 1;
    saveState(100, set_led);
  }
  delayTime = loadState(101);
  if (delayTime > 60) {
    delayTime = 3;
    saveState(101, delayTime);
  }
  send_batteryTime = loadState(102);
  if (send_batteryTime > 48) {
    send_batteryTime = 6;
    saveState(102, send_batteryTime);
  }


  digitalWrite(led_pin, ON);
}


void presentation()
{
  sendSketchInfo("Temp & Hum Sensor CR2477", "1.0");
  wait(100);
  present(TEMP_SENS_ID, S_TEMP, "TEMPERATURE DATA");
  wait(100);
  present(HUM_SENS_ID, S_HUM, "HUMIDITY DATA");
  wait(100);
  present(SETTING_LED_SENS_ID, S_CUSTOM, "LED MODE");
  wait(100);
  present(DELAY_TIME_SENS_ID, S_CUSTOM, "DELAY TIME/MIN");
  wait(100);
  present(BATTARY_SEND_SENS_ID, S_CUSTOM, "BATTERY SEND TIME/H");
  wait(100);
  present(BATTARY_DATA_SENS_ID, S_CUSTOM, "BATTERY DATA");
}

void setup()
{
  //attachInterrupt(0, configListener, RISING);
  digitalWrite(led_pin, OFF);
  wait(500);
  digitalWrite(led_pin, ON);
  wait(75);
  digitalWrite(led_pin, OFF);
  wait(50);
  digitalWrite(led_pin, ON);
  wait(75);
  digitalWrite(led_pin, OFF);
  wait(50);
  digitalWrite(led_pin, ON);
  wait(75);
  digitalWrite(led_pin, OFF);
  TRANSPORT_DEBUG(PSTR("MyS: OPERATING MODE\n"));
  wait(100);
  readBatLev();
  wait(100);
  sht20.initSHT20();
  wait(100);
  send_data();
  wait(100);
  send(msg_delay_time.set(delayTime));
  wait(100);
  send(msg_setting_led.set(set_led));
  wait(100);
  send(msg_battary_send.set(send_batteryTime));
}

void loop()
{
  if (configMode == 0) {



    if (sleep_flag == 0) {
      timer_status = sleep(digitalPinToInterrupt(mode_pin), FALLING, delayTime * 60 * 1000, false);
      //timer_status = sleep(digitalPinToInterrupt(mode_pin), RISING, delayTime * 60 * 1000, false);
      sleep_flag = 1;
    }
    if (timer_status == -1) {

      w_battetyTime = w_battetyTime + (delayTime * 60 * 1000);

      if (w_battetyTime >= send_batteryTime * 60 * 60 * 1000) {
        readBatLev();
        w_battetyTime = 0;
      }
      send_data();
      sleep_flag = 0;
    }
    if (timer_status == 0) {
      if (digitalRead(2) == LOW && flag_mode_button == 0) //  
      {
        flag_mode_button = 1;
        previousMillis = millis();
        wait(50);
      }
      if (digitalRead(2) == LOW && flag_mode_button == 1) {
        if ((millis() - previousMillis > 0) && (millis() - previousMillis <= 2000)) {
          if (millis() - lightMillis > 50)    {
            lightMillis = millis();
            digitalWrite(led_pin, !digitalRead(led_pin));
          }
        }
        if ((millis() - previousMillis > 2000) && (millis() - previousMillis <= 2500)) {
          digitalWrite(led_pin, OFF);
        }
        if ((millis() - previousMillis > 2500) && (millis() - previousMillis <= 4500)) {
          if (millis() - lightMillis > 25)    {
            lightMillis = millis();
            digitalWrite(led_pin, !digitalRead(led_pin));
          }
        }
        if (millis() - previousMillis > 4500) {
          digitalWrite(led_pin, OFF);
        }
      }
      if (digitalRead(2) == HIGH && flag_mode_button == 1) //   
      {
        if ((millis() - previousMillis > 0) && (millis() - previousMillis <= 2000)) {
          configMode = !configMode;
          flag_mode_button = 0;
          TRANSPORT_DEBUG(PSTR("MyS: CONFIGURATION MODE\n"));
          sleep_flag = 0;
          digitalWrite(led_pin, OFF);
        }
        if ((millis() - previousMillis > 2000) && (millis() - previousMillis <= 2500)) {
          flag_mode_button = 0;
          sleep_flag = 0;
        }
        if ((millis() - previousMillis > 2500) && (millis() - previousMillis <= 4500))
        {
          flag_mode_button = 0;
          sleep_flag = 0;
          digitalWrite(led_pin, OFF);
        }
        if (millis() - previousMillis > 4500) {
          flag_mode_button = 0;
          sleep_flag = 0;
          wait(50);
        }
      }
    }
  } else {
    if (listen_flag == 0) {
      RF24_startListening();
      listen_flag = 1;
    }
    if (millis() - lightMillis > 1000) {
      lightMillis = millis();
      digitalWrite(led_pin, !digitalRead(led_pin));
    }
    if (digitalRead(2) == LOW && flag_mode_button == 0) //  
    {
      flag_mode_button = 1;
      //previousMillis = millis();
      wait(50);
    }
    if (digitalRead(2) == LOW && flag_mode_button == 1) {
      
    }
    if (digitalRead(2) == HIGH && flag_mode_button == 1) //   
    {
       
      configMode = !configMode;
      listen_flag = 0;
      flag_mode_button = 0;
      TRANSPORT_DEBUG(PSTR("MyS: OPERATING MODE\n"));
      digitalWrite(led_pin, OFF);
      wait(50);
    }
  }
}



void receive(const MyMessage & message)
{
  if (message.sensor == SETTING_LED_SENS_ID) {
    if (message.type == V_VAR1) {
      if (message.getByte() <= 1) {
        set_led = message.getBool();
        saveState(100, set_led);
        send(msg_setting_led.set(set_led));
        if (set_led == 0) {
          TRANSPORT_DEBUG(PSTR("MyS: STATUS LED: OFF\n"));
        }
        if (set_led == 1) {
          TRANSPORT_DEBUG(PSTR("MyS: STATUS LED: ON\n"));
          if (set_led == 1) {
            digitalWrite(led_pin, ON);
            wait(50);
            digitalWrite(led_pin, OFF);
          }
        }
      }
    }
  }
  if (message.sensor == DELAY_TIME_SENS_ID) {
    if (message.type == V_VAR1) {
      if (message.getULong() <= 60 && message.getULong() != 0) {
        delayTime = message.getULong();
        saveState(101, delayTime);
        send(msg_delay_time.set(delayTime));
        TRANSPORT_DEBUG(PSTR("MyS: THE NEW INTERVAL TEMP&HUM SEND VALUE IS SET: %d MIN.\n"), delayTime);
        if (set_led == 1) {
          digitalWrite(led_pin, ON);
          wait(50);
          digitalWrite(led_pin, OFF);
        }
      } else if (message.getULong() > 60) {
        delayTime = 60;
        saveState(101, delayTime);
        send(msg_delay_time.set(delayTime));
        TRANSPORT_DEBUG(PSTR("MyS: THE NEW INTERVAL TEMP&HUM SEND VALUE IS SET: %d MIN.\n"), delayTime);
        if (set_led == 1) {
          digitalWrite(led_pin, ON);
          wait(50);
          digitalWrite(led_pin, OFF);
        }
      } else if (message.getULong() == 0) {
        delayTime = 1;
        saveState(101, delayTime);
        send(msg_delay_time.set(delayTime));
        TRANSPORT_DEBUG(PSTR("MyS: THE NEW INTERVAL TEMP&HUM SEND VALUE IS SET: %d MIN.\n"), delayTime);
        if (set_led == 1) {
          digitalWrite(led_pin, ON);
          wait(50);
          digitalWrite(led_pin, OFF);
        }
      }
    }
  }
  if (message.sensor == BATTARY_SEND_SENS_ID) {
    if (message.type == V_VAR1) {
      if (message.getULong() <= 168) {
        send_batteryTime = message.getULong();
        saveState(102, send_batteryTime);
        send(msg_battary_send.set(send_batteryTime));
        TRANSPORT_DEBUG(PSTR("MyS: THE NEW INTERVAL BATTERY SEND IS SET: %d HOUR\n"), send_batteryTime);
        if (set_led == 1) {
          digitalWrite(led_pin, ON);
          wait(50);
          digitalWrite(led_pin, OFF);
        }
      }
    }
  }
}

void send_data()
{
  humd = sht20.readHumidity();
  temp = sht20.readTemperature();
  int t_humd = (int)humd;
  int t_temp = (int)temp;
  if (abs(temp - oldtemp) >= tempThreshold) {
    send(msg_temp.set(temp, 1));
    oldtemp = temp;
    if (set_led == 1) {
      digitalWrite(led_pin, ON);
      wait(50);
      digitalWrite(led_pin, OFF);
    }
  }
  wait(100);
  if (abs(humd - oldhumd) >= humThreshold) {
    send(msg_hum.set(humd, 1));
    oldhumd = humd;
    if (set_led == 1) {
      digitalWrite(led_pin, ON);
      wait(50);
      digitalWrite(led_pin, OFF);
    }
  }
  TRANSPORT_DEBUG(PSTR("MyS: DATA - TEMPERATURE: %d, HUMIDITY %d\n"), t_temp, t_humd);
}


void readBatLev() {
  ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX0);
  wait(100);
  RF24_startListening();
  wait(200);
  ADCSRA |= _BV(ADSC);
  while (bit_is_set(ADCSRA, ADSC));
  uint8_t low  = ADCL;
  uint8_t high = ADCH;
  long temp = (high << 8) | low;
  float vcc = temp * 1.1 / 1023 * BAT_COOF * 100;
  battery = map((int)vcc, BAT_MIN, BAT_MAX, 0, 100);
  if (battery < 0) {
    battery = 0;
  }
  if (battery > 100) {
    battery = 100;
  }
  TRANSPORT_DEBUG(PSTR("MyS: BATTERY LEVEL: %d, PREVIUS BATTERY LEVEL: %d\n"), battery, old_battery);
  TRANSPORT_DEBUG(PSTR("MyS: BATTERY LEVEL ADC: %d\n"), temp);

  /*
    if (old_battery != battery) {
      if (battery < old_battery) {
        old_battery = battery;
        wait(100);
        sendBatteryLevel(battery);
        wait(100);
        send(powerMsg.set(temp));
        TRANSPORT_DEBUG(PSTR("MyS: SEND BATTERY LEVEL\n"));
      } else {
        battery = old_battery;
      }
    }
  */
  wait(100);
  sendBatteryLevel(battery);
  wait(100);
  send(powerMsg.set(temp));
  TRANSPORT_DEBUG(PSTR("MyS: SEND BATTERY LEVEL\n"));
}


:


:


( ), Mysensors( Mysensors )



. , , , 3d www.openhardware.io. , Mysensors — t.me/mysensors_rus.

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


All Articles