📜 ⬆️ ⬇️

Thermometer & Hygrometer on ATMEGA 328P-MU - Raising the level of arduino developments

Today I want to share one of my Arduino projects. Once, not so long ago, I learned about Arduino somewhere on the Internet. I joined this business pretty quickly, the level of entry there is not high. After some time, having already gathered a bunch of sensors, sensors for a smart home, it began to catch itself at the thought that something like this was all wrong. Modules, large plain boxes, a bunch of wires and glue :). Looking at my box with a temperature sensor and, for example, the temperature sensor of the same Xiaomi, I understood that I wanted to look like Xiaomi but at the same time that I could reprogram it like mine in a box measuring 10 cm by 6 cm with wires and hot melt. And then that was probably the beginning of my DIY arduino projects on PCB boards.

In today's article we will focus on the temperature and humidity sensor based on the atmega328p-mu processor. This is the “smaller” version (absolute analogue) of the atmega328p-au processor (Arduino Uno, Pro Mini, Nano) izvetnom to all arduinschiki. If someone has read my articles before, he knows that I prefer Mysensors. What is it? It is very simple and well-developed and what is equally important is the perfectly described library under Arduino IDE (and not only) for creating IOT radio networks at 2.4 GHz, 915, 868, 433 MHz frequencies, as well as wired networks on the 485 interface, maybe not all mentioned, TK protocol is constantly evolving, all the time something is added.

The first thing that was done is the sensor itself on the PCB board. I did without looking at the case, according to the principle, the main thing is to make a sensor, and as for the case, I’ll print something, ... yes, don’t do so :). In fact, the sensor itself is the same Arduinka Pro Mini, the nRF24l01 radio module, SHT20 temperature and humidity sensor, only without wires and hot melt. From the “bells and whistles” this is an external SPI flash drive for flashing through the air (you need the DualOptibut bootloader to work, later I stopped putting them (flash drives) on the boards, there are no pair of firmware in the air and half a battery) and a cryptto mic ATSHA204A for full Iron kit (in Mysensors, it is enough to simply specify the #def in the beginning of the sketch to activate signatures, encryption, and so on).
')


The fee itself was done in the program Diptreis, after watching video tutorials on YouTube, at first it seemed like something “hellish”, but in fact it turned out to be not that difficult. I ordered the boards in China on the jlcpcb.com website, 2 bucks, any color, and after 2 weeks you already get 10 pieces of “your creation” in your hands :).





The next stage was the development of the hull. Oh, it turned out to be another problem. In general, I did not look for easy ways, I decided to master Solid Works. As it turned out, this is not at all like with Diptreys. Nevertheless, I still recommend this particular editor for the study. The learning process lasted for a month of leisurely watching video tutorials on YouTube and repeating lesson materials in the editor. In the process of developing the case, it became clear what the device board should do without taking into account the parameters of the future case is a bad decision, from the series we put the sticks into our own wheels. According to the results of the board versions, three came out considering the installation of the board in the case, and I think this is not the last option.

At the beginning of the development of the case, the idea was to print it on an FDM 3D printer, but the farther into the forest it became clearer that it could not reproduce all my wishes. By the time this understanding came, I already learned about another 3D printing technology - SLA. Without thinking and impressed with the quality of the print, an Alike Wishlist was issued - ANYCUBIC Photon . (Link to Ali, not advertising, not affiliate, ... just a link).

I will write right away, now, on the basis of my experience at the time of this writing, ... oh, and this is such a wonderful thing! The body that was designed in the editor, of course, was not printed the first time and there were a lot of improvements. Well, on the other probably does not happen. As a result, I got the result that I wanted. Quite a miniature device, a good DIY case with very accurate detailing, buttons, fonts, everything was presented in my head. Added a magnet to the back cover, now it can be easily attached to iron surfaces.

















These are attempts to print the same model on an FDM printer:





Since the device turned out to be small, but it is still Arduinka, I was puzzled by the output of miniature connectors for programming. And accordingly, a small adapter was made to the connectors for convenient connection with the programmer and the TTL converter.



Everything was purchased on Ali (yes, it’s not only the Arduino modules)

SMD tantalum capacitor 4.7uF - 4.7uF | 10v | 10% - C1
SMD ceramic capacitor 100nF | Y5V - 100nF | 50v | + 80-20% - C2, C3, C4, C5, C6, C7
LED - LED SIDE - D1
Pin Header Female - 2x3P | 6pin | 1.27mm - J1, J2
SMD resistor 20K Ohm - 20K | 5% - R1
SMD resistor 4.7K Ohm - 4.7K | 5% - R2, R3, R4
SMD resistor 470K Ohm - 470 | 1% - R5
SMD resistor 1M Ohm - 1M | 1% - R6
SMD resistor 18K Ohm - 18K | 5% - R7
SMD resistor 10K Ohm - 10K | 5% - R8
4-pin SMD side button - SW1, SW2
512-Kbit, 1.65V SPI Serial Flash Memory - AT25DF512C-SSHN-B - U1
Mini NRF24L01 + 2.4GHz 1.27MM RF - nRF24l01 1.27 SMD - U2
ATMEGA328P-MU QFN32 - U3
CRYPTO AUTHENTICATION, 1 WIRE - ATSHA204A-STUCZ-T - U4
Humidity and Temperature Sensor IC - SHT20 - U5
BATTERY HOLDER FOR CR2477-1 - L-KLS5-CR2477-1 - U6

The program code is quite simple. An example of the DFRobot library was used to work with the SHT20 sensor. In principle, any sketch, for any sensor, you can take 5 minutes to sketch in order to work on the network Mysensors.

Code listing
#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/452234/


All Articles