What is Arduino? 怎么是”Arduino”呢?

Schools are using Arduino nowadays in their digital technology classes. It is now up to us, parents and grandparents, to understand what our children or grandchildren are saying in this technological age. This article is therefore aimed at giving us a catch-up session in this computer age.

Arduino refers to the hardware electronic board with the software called Arduino IDE that is used to program the electronic board. Arduino is designed to make electronics readily accessible to the general public. To read more on Arduino, click on this link: https://www.techopedia.com/definition/27874/arduino

如今,学校在其数字技术课程中使用Arduino。现在,我们,父母和祖父母,必须了解我们的孩子或孙子在这个技术时代所说的话。因此,本文旨在让我们在这个计算机时代迎头赶上。Arduino指的是带有称为Arduino IDE的软件的硬件电子板,该软件用于对电子板进行编程。 Arduino旨在使电子产品易于为大众所用。要了解有关Arduino的更多信息,请单击以下链接https://www.techopedia.com/definition/27874/arduino

(Maori) I tenei ra, kei te whakamahia e te kura a Arduino i roto i aana akoranga hangarau matihiko. Na, ko taatau, nga matua me nga tupuna, me maarama ki nga korero a a taatau tamariki mokopuna ranei i tenei waa hangarau. Na reira, ko te whainga a tenei tuhinga kia mau taatau ki tenei ao rorohiko. Arduino e pa ana ki tetahi poari hiko taputapu me te raupaparorohiko e kiia ana ko Arduino IDE, e whakamahia ana hei whakamahere i te poari hiko. Ko te whainga a Arduino kia ngawari te whakamahi i nga hua hiko mo te marea. Hei ako atu mo Arduino, paatohia te hono i raro nei.

The Arduino School project requires the student to design a temperature and humidity monitor for grain growers in order to prevent crop damage by excessive watering. The student is required to use (1) an Arduino Nano Unit; (2) a LED to represent moisture level; (3) a moisture sensor stake; and (4) the Arduino IDE to program the logic of the circuit.

Arduino学校项目要求学生为谷物种植者设计温度和湿度监控器,以防止因过度浇水对农作物造成损害。要求学生使用(1)Arduino纳米单元; (2)代表湿度水平的LED; (3)湿度传感器桩; (4)Arduino IDE对电路的逻辑进行编程。
Ko te kaupapa o te Kaupapa Arduino kei roto i te Kura kia hoahoahia e te akonga he punaha hei tirotiro i nga taumata ahotea me te haumākū o nga kai hei ahuwhenua ki te aukati i nga raru o te waipuke mai i te waipuke. Me whakamahi e te akonga (1) tetahi waeine Nano Arduino; (2) he LED hei tohu i te taumata haumākū; (3) he papu makuku; me te (4) te Arduino IDE hei whakamahere i te ihirangi huringa.

Let us listen to Paul McWhorter on YouTube in his three lessons for Arduino beginners. Lesson # 1: https://youtu.be/fJWR7dBuc18. Lesson # 2: https://youtu.be/9uHZB7-T_XA Lesson # 3: https://youtu.be/CfdaJ4z4u4w

Arduino is a free platform that we can used for building electronics projects. Arduino consists of both a physical programmable circuit board (referred to as a microcontroller) and a piece of software called the IDE (Integrated Development Environment) that runs on your computer, used to write and upload computer code to the physical board.

Arduino是一个免费平台,可用于构建电子项目。 Arduino由物理可编程电路板(称为微控制器)和称为IDE(集成开发环境)的软件组成,该软件在您的计算机上运行,​​用于将计算机代码写入和上传到物理板上。
Ko te Arduino he papa koreutu ka taea te whakamahi mo te hanga kaupapa hiko. Kei roto i te Arduino tetahi poari araahiko e taea ana te whakamaarama (e kiia ana ko te microcontroller) me tetahi raupaparorohiko e kiia ana ko te IDE (Taiao Whakawhanake Whakahiato) kei runga i to rorohiko, e whakamahia ana ki te tuhi me te tuku i te waehere rorohiko ki te papa a-tinana.
ABOUT THIS SCHOOL PROJECT written by Paul Brace:  [Technical Programming Codes indicated below can be skipped if you are not familiar with the Arduino Programming Language called Arduino IDE (Integrated Development Environment).]
关于Paul Brace撰写的本学校项目:[如果您不熟悉称为Arduino IDE(集成开发环境)的Arduino编程语言,则可以跳过以下所示的技术编程代码。] 我在扩展项目时遇到了两个问题:
M TENEI KOTAHI KOTAHI KOREUTU i tuhia e Paul Brace: [Ko nga Waehere Papatono Hangarau e whakaatu ana i raro ake nei ka taea te peke mena kaore koe i mohio ki te Reo Papatono Arduino e kiia ana ko te Arduino IDE (Taiao Whakawhanake Whakauru). I raru ahau i etahi take e rua me te whakawhanui ake i te kaupapa:

I encountered a couple of issues with extending the project:

  • Initially I added an array to store the temperature history int tempHistory[96]; this worked well, however as soon as I added a second array to sore the humidity history int humidHistory[96] the program would no longer run. It compiled and uploaded but did not even run setup(). Even though it appeared that there was plenty of spare program and variable space, the only conclusion I could come to was that it was running out of memory. Hence, I changed track and am now storing the history in EPROM.
  • In the linked project I reduced the power consumed to increase battery life by invoking a sleep mode. The issue with this is that it stops the timers being triggered and hence millis() does not advance during the sleep period. This was an issue as I wanted to store the readings every 15 minutes (96 per day) and there was no way of tracking elapsed time while sleeping. Hence I have removed the code to activate sleep mode. As removing sleep mode will reduce battery life, I added battery monitoring so I know when the battery is getting low.
  • Finally, I added a screen saver displaying the battery level that is moved every 10 seconds.
最初,我添加了一个数组来存储温度历史记录int tempHistory [96];这项工作很好,但是,一旦我添加了第二个数组以使湿度历史记录和intHistory [96]冲突,该程序将不再运行。它编译并上传,但甚至没有运行setup()。即使看起来有很多备用程序和可变空间,我唯一能得出的结论是它内存不足。因此,我更改了曲目,现在将历史记录存储在EPROM中。
在链接的项目中,我通过调用睡眠模式降低了功耗以延长电池寿命。这样做的问题是它停止了计时器的触发,因此在睡眠期间millis()不会前进。这是一个问题,因为我想每15分钟(每天96个)存储读数,并且无法跟踪睡眠时的经过时间。因此,我删除了激活睡眠模式的代码。由于取消睡眠模式会减少电池寿命,因此我添加了电池监控功能,因此我知道何时电池电量不足。 最后,我添加了一个屏幕保护程序,该屏幕保护程序显示每10秒移动一次的电池电量。
最后,我添加了一个屏幕保护程序,该屏幕保护程序显示每10秒移动一次的电池电量。
I te timatanga i taapirihia e au he kohinga hei penapena i te hitori o te temahana hītori [96]; he pai te mahi o tenei, engari i te wa ka taapirihia e au te rua o nga waahanga ki te whakamamae i te hitori o te haumanu int lembHistory [96] kaore te kaupapa e rere. I whakahiatohia me te tukuatu engari kaore i pai te whakahaere tatū (). Ahakoa i kitea he nui nga hotaka koreutu me nga waahi rereke, ko te mutunga noa ka taea e au ko te mahara kua ngaro. No reira, i huri au i te huarahi me te penapena i nga hitori o te EPROM.
I roto i te kaupapa honohono i whakaitihia e au te kaha ki te whakapiki i te ora o te paahiko ma te tono i tetahi momo moe. Ko te take ki tenei ko te whakamutu i te timatatanga o nga tohu mahi na reira kaore e neke whakamua nga millis () i te wa moe. He take tenei i te hiahia ahau ki te penapena i nga panui ia 15 meneti (96 ia ra) kaore he huarahi hei whai i te waa kua moe i te wa e moe ana ahau. No reira kua tangohia e ahau te waehere hei whakahohe i te aratau moe. Ka rite ki te tango i te aratau moe ka whakaiti i te ora o te puhiko, ka taapirihia e au te tirotiro i te papahiko kia mohio ai au ka iti te puhiko.
Hei whakamutunga, ka taapirihia e au he kaitiaki mata e whakaatu ana i te taumata puhiko e nekehia ana ia 10 hēkona.

=============================

The code uses the following libraries:

#include <DHT.h>            // This is the DHT sensor library by Adafruit

                            // required for the OLED display 

#include <SPI.h>            // Synchronous serial data protocol library

#include <Wire.h>           // IC2 communications library

#include <Adafruit_GFX.h>   // Adafruit Graphics Core Library

#include <Adafruit_SSD1306.h>  // SSD1306 library for Monochrome 128×64 and 128×32 OLEDs 

#include <EEPROM.h>         // Library to support writing to and reading from EPROM

And these fonts from the Adafruit Graphics Core Library:

#include <Fonts/FreeMonoBold9pt7b.h> 

#include <Fonts/FreeSans9pt7b.h>

The main areas of interest in the code:

In loop() check to see if screensaver mode needs to be activated or the bitmap moved.

// Check if the time since last display of data started is greater than

 // the time set to keeo the display showing

 if ((millis() - timeDisplay) > keepDisplayFor) {

   // If so in screen save mode

   // Set flag to indicate data not being displayed

   displaying = false;      

   // Check if we need to move the bitmap

   if ((millis() - lastMoved) > moveEvery) {

     // Update time last moved

     lastMoved = millis();

     // Dislpay battery bitmap in random position

     DrawScreenSave(random(10, 110), random(10, 45));

   }

 }

The Programming Codes (IDE Language) are shown below:

Temp/Humid monitor with graphs and battery monitor using Arduino IDE

/*   The Arduino IDE Program written by Paul Brace April 2021

     Temperature and humidity monitor with minimum and maximum monitoring,

       graph and battery monitor

     Board - Arduino Pro Mini/Nano or Uno r3 tested

     Display - OLED 128×64 IC2

     A screensaver kicks in after the period set in keepDisplayFor.

     Screensaver is a bitmap that represents the state of the battery charge

     and is respositioned after the period set in moveEvery.

     The mode button is used to activate the diplsya and show the readings

        and to circulate from the temperature, to temperature graph, humidity and humidity graph.

     The reset button is used to reset the minimum and maximum values.

     The graph displays show the temperature and humidity recording for the last 24 hour period

     Note on using the 3.7v rechargeable battery.

      The Nano specification is that it requires a 5v supply, however

      for this project it runs perfectly well on a 3.7v rechargeable battery

      with the supply connected to the 5v pin.

      It is also safe to recharge when in use as the voltage will only increase to 4.2v

*/

// Include drivers

// DHT_sensor_library

#include <DHT.h>            // This is the DHT sensor library by Adafruit

                            // required for the OLED display

#include <SPI.h>            // Synchronous serial data protocol library

#include <Wire.h>           // IC2 communications library

#include <Adafruit_GFX.h>   // Adafruit Graphics Core Library

#include <Adafruit_SSD1306.h>  // SSD1306 library for Monochrome 128×64 and 128×32 OLEDs 

#include <Fonts/FreeMonoBold9pt7b.h>  // Include fonts to be used

#include <Fonts/FreeSans9pt7b.h>

#include <EEPROM.h>          // Library to support writing to and reading from EPROM

#define DATA_PIN 4                    // Pin used to collect data from the DHT

#define DHTTYPE DHT11                 // DHT Type  

//#define DHTTYPE DHT22               // If you have a DHT22 comment the DHT11 and

                                      // uncomment DHT22

// Create the sensor object and assign pin

DHT dht(DATA_PIN, DHTTYPE);

#define SCREEN_WIDTH 128 // OLED display width, in pixels

#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// The pins for I2C are defined by the Wire-library.

// On an arduino UNO/Nano and Pro Mini: A4(SDA), A5(SCL)

// On an arduino MEGA 2560:             20(SDA), 21(SCL)

// On an arduino LEONARDO:              2(SDA),  3(SCL), …

#define OLED_RESET   -1 // Reset pin # (or -1 if no reset on display)

#define SCREEN_ADDRESS 0x3C // See datasheet for Address (Yours could be 0x3D)

// Create object for the SSD1306 display connected to I2C (SDA, SCL pins)

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define MODE_BUTTON 2             // Activate display and switched between temperature, graph and humidity

#define RESET_BUTTON 3            // If pressed when data displayed resets min and max settings

float temp;       //Current temperature

float humid;      //Current humidity

float minTemp;    //The minimum temperature recorded

float maxTemp;    //The maximum temperature recorded

float minHumid;   //The minimum humidity recorded

float maxHumid;   //The maximum humidity recorded

unsigned long lastReadingUpdate;  // Time readings last updated

// Battery Monitor

#define MONITOR_PIN A0              // Pin used to monitor supply voltage

const float voltageDivider = 4.0;   // Used to calculate the actual voltage fRom the monitor pin reading

                                    // Using 1m and 330k ohm resistors dividS the voltage by approx 4

                                    // You may wany to substitute actual values of resistors in an equation (R1 + R2)/R2

                                    // E.g. (1000 + 330)/330 = 4.03

                                    // Alternatively take the voltage reading across the battery and from the joint between 

                                    // the 2 resistors to ground and divide one by the other to get the value.

// Variables for History stored in EPROM

// First version stored history in arrays but program would not run as may have 

//    run out of memory even though there appeared to be memory to spare

// 1 day’s history is stored 96 readings at 15 minute intervals so each 

//   EPROM position is written once per day.

// EPROM has a limited life of approx 100,000 writes per postion so as we  

//   are writin to each postion once a day the EPROM should last 100,000 days (274 years!)

const int intSize = sizeof(int);      // Size of int to calculate storage location

const int tempStart = 0;              // Start postion of temperature history - length = 96 * intSize

const int humidStart = 100 * intSize; // Start postion of humidity

int histPointer = - 1;                  // Last last postion updated (-1 means no history yet stored)

unsigned long histUpdated;            // time last updated

unsigned long interval = 900000ul;   //(15 * 60 * 1000); 15 minutes in milliseconds

enum mode {

  dispTemp,        // Temperature currently displayed

  dispTempGraph,   // Temperature history graph displayed

  dispHumid,       // Humidity currently displayed

  dispHumidGraph   // Humidity history graph displayed

};

mode currentMode;   // Current display setting

bool displaying;                         // True if currently displaying data

unsigned long timeDisplay;               // Time started to display, or last button pressed

unsigned long keepDisplayFor = 15000;    // Number of milliseconds before enter screensave mode

unsigned long lastMoved;                 // Time last moved screensave bitmap

                                         // The battery indicator is displayed as the screensaver

unsigned long moveEvery = 10000;         // Number of milliseconds between moves

// Arrows used to indicate maximum and minimum

static const unsigned char PROGMEM upArrow[] {

  B00000000,

  B00011000,

  B00111100,

  B01111110,

  B11111111,

  B00011000,

  B00011000,

  B00011000

};

static const unsigned char PROGMEM downArrow[] {

  B00011000,

  B00011000,

  B00011000,

  B11111111,

  B01111110,

  B00111100,

  B00011000,

  B00000000

};

// Battery indicator bitmaps

static const unsigned char PROGMEM full[] {

  B00001110,B00000000,

  B00001110,B00000000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000

};

static const unsigned char PROGMEM three4[] {

  B00001110,B00000000,

  B00001110,B00000000,

  B11111111,B11100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000

};

static const unsigned char PROGMEM half[] {

  B00001110,B00000000,

  B00001110,B00000000,

  B11111111,B11100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000

};

static const unsigned char PROGMEM one4[] {

  B00001110,B00000000,

  B00001110,B00000000,

  B11111111,B11100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000,

  B11111111,B11100000

};

static const unsigned char PROGMEM empty[] {

  B00001110,B00000000,

  B00001110,B00000000,

  B11111111,B11100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B10000000,B00100000,

  B11111111,B11100000

};

void setup() {

  minTemp = 99;    //Set to a figure that is going to be too high

  maxTemp = -9;    //Set to a figure that is going to be too low

  minHumid = 99;   //Set to a figure that is going to be too high

  maxHumid = -9;   //Set to a figure that is going to be too low

  pinMode(MODE_BUTTON, INPUT_PULLUP);  // Use INPUT_PULLUP - will go LOW when button pressed

  pinMode(RESET_BUTTON, INPUT_PULLUP);

  analogReference(INTERNAL);     // Sets the reference voltage for the analog pins to 1.1v

  pinMode(MONITOR_PIN, INPUT);   // Set input on pin used to monitor the voltage

  // Start sensor

  dht.begin();

  // Initialise display

  display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);

  display.setTextColor(WHITE);

  currentMode = dispTemp;

  displaying = true;

  timeDisplay = millis();   // Set so initially displays for set period

  histUpdated = millis();   // First update will be interval after startup

  lastMoved = millis();     // Time bitmap last moved

  clearEEPROM();            // Clear EPROM ready to start storing history

}

void loop() {

  // Check if the time since last display of data started is greater than

  // the time set to keeo the display showing

  if ((millis() - timeDisplay) > keepDisplayFor) {

    // If so in screen save mode

    displaying = false;               // Flag to indicate data not being displayed

    // Check if we need to move the bitmap

    if ((millis() - lastMoved) > moveEvery) {

      // Update time last moved

      lastMoved = millis();

      // Dislpay battery bitmap in random position

      DrawScreenSave(random(10, 110), random(10, 45));

    }

  }

  // Update the readings every 2 seconds

  if ((millis() - lastReadingUpdate) > 2000ul) {

    // Get readings, update minimum and maximum values

    lastReadingUpdate = millis();

    humid = dht.readHumidity();                   // read humidity

    temp = dht.readTemperature();                 // read temperature

    if (temp < minTemp)

      minTemp = temp;

    if (temp > maxTemp)

      maxTemp = temp;

    if (humid < minHumid)

      minHumid = humid;

    if (humid > maxHumid)

      maxHumid = humid;

    if (displaying) {

      // Update display if data being displayed

      switch (currentMode) {

        case dispTemp:

          ShowTemperature();

          break;

        case dispTempGraph:

          ShowGraph();

          break;

        case dispHumid:

          ShowHumidity();

          break;

        case dispHumidGraph:

          ShowGraph();

          break;

      }

    }

  }

  // Check if any buttons have been pressed

  CheckButtons();

  // If history update interval has passed, update history

  if ((millis() - histUpdated) >= interval)

    UpdateHistory();

  delay(150);           // Short pause before continuing

}

// Read the monitor pin and calculate the voltage

float BatteryVoltage(){

  float reading = analogRead(MONITOR_PIN);

  // Calculate voltage - reference voltage is 1.1v

  return 1.1 * (reading/1023) * voltageDivider;

}

void DrawScreenSave(int x, int y){

      // Get battery voltage and display approprate bitmap

      display.clearDisplay();

      float voltage = BatteryVoltage();

      if (voltage > 3.6)

        display.drawBitmap(x, y, full, 16, 16, WHITE);

      else

        if (voltage > 3.5)

          display.drawBitmap(x, y, three4, 16, 16, WHITE);

        else

          if (voltage > 3.4)

            display.drawBitmap(x, y, half, 16, 16, WHITE);

        else

          if (voltage > 3.3)

            display.drawBitmap(x, y, one4, 16, 16, WHITE);

          else

            display.drawBitmap(x, y, empty, 16, 16, WHITE);

      /* Debug code to display reading and voltage for checking

      display.setCursor(random(0,96), random(15,35));

      display.print(voltage);

      float reading = analogRead(MONITOR_PIN);

      display.setCursor(random(0,75), random(45,60));

      display.print(reading);*/

      display.display();

}

void UpdateHistory() {

  histUpdated += interval;

  // Use a circular list

  // Increment to next element in EPROM and circulate back to 0 if end

  // of list reached

  histPointer++;

  if (histPointer > 95)

    histPointer = 0;

  saveTemperature(histPointer, int(temp));

  saveHumidity(histPointer, int(humid));

}

// Clear area we are using for storage

void clearEEPROM()

{

  for (int i = 0 ; i < 200 * intSize ; i++) {

    if(EEPROM.read(i) != 0)                     //skip already “empty” addresses

    {

      EEPROM.write(i, 0);                       //write 0 to address i

    }

  }

}

void saveTemperature(int postion, int value){

  EEPROM.put(tempStart + postion * intSize, value);

}

void saveHumidity(int postion, int value){

  EEPROM.put(humidStart + postion * intSize, value);

}

int getTemperature(int postion){

  int value = 0;

  EEPROM.get(tempStart + postion * intSize, value);

  return value;

}

int getHumidity(int postion){

  int value = 0;

  EEPROM.get(humidStart + postion * intSize, value);

  return value;

}

// Routine to display numbers aligned and with sign

void dispNumber(int y, float value, bool tDisp) {

  if (value < 10.0 && value > 0.0)

    display.setCursor(72, y);

  else

    display.setCursor(60, y);

  display.print(value);

  if (tDisp)

    display.print(“c”);

  else

    display.print(“%”);

}

// Routine to display graph

void ShowGraph() {

  // Calculate scale

  int histValue;

  int minimum = 99;

  int maximum = -9;

  float yScale;

  for (int  i = 0; i < 96; i++) {

    if (currentMode == dispTempGraph)

      histValue = getTemperature(i);

    else

      histValue = getHumidity(i);

    if (histValue < minimum)

      minimum = histValue;

    if (histValue > maximum)

      maximum = histValue;

  }

  if ((maximum - minimum) != 0)

    yScale = 63.0 / (maximum - minimum);

  else

    yScale = 1;

  // Display axis data

  display.clearDisplay();

  display.setFont();

  display.setTextSize(1);

  display.setCursor(0, 54);

  display.print(minimum);

  if (currentMode == dispTempGraph)

    display.print(“c”);

  else

    display.print(“%”);

  display.setCursor(0, 0);

  display.print(maximum);

  if (currentMode == dispTempGraph)

    display.print(“c”);

  else

    display.print(“%”);

  display.setCursor(0, 25);

  if (currentMode == dispTempGraph)

    display.print(“Temp.”);

  else

    display.print(“Humid.”);

  // Graph list from histPointer + 1 circulating to histPointer

  int pos = histPointer + 1;

  int priorPos;

  int histValuePrior;

  // Count 1 less than list as stating at point 2

  for (int i = 1; i < 96; i++) {

    pos++;

    if (pos > 95)

      pos = 0;

    if (pos > 0)

      priorPos = pos - 1;

    else

      priorPos = 95;

    if (currentMode == dispTempGraph) {

      histValuePrior = getTemperature(priorPos);

      histValue = getTemperature(pos);

    }

    else {

      histValuePrior = getHumidity(priorPos);

      histValue = getHumidity(pos);

    }    

    display.drawLine(32 + i - 1, 63 - (histValuePrior - minimum) * yScale,

                     32 + i, 63 - (histValue - minimum) * yScale, SSD1306_WHITE);

  }

  display.display();

}

void ShowTemperature() {

  display.clearDisplay();

  display.setTextSize(1);

  display.setFont(&FreeSans9pt7b);  // Font used for text

  display.setCursor(0, 15);

  display.print(“Temp:”);

  display.drawBitmap(20, 35 - 9, upArrow, 8, 8, WHITE);

  display.drawBitmap(20, 55 - 9, downArrow, 8, 8, WHITE);

  display.setFont(&FreeMonoBold9pt7b);  // Font used for numbers

  dispNumber(15, temp, true);

  dispNumber(35, maxTemp, true);

  dispNumber(55, minTemp, true);

  display.display();

}

void ShowHumidity() {

  display.clearDisplay();

  display.setTextSize(1);

  display.setFont(&FreeSans9pt7b);  // Font used for text

  display.setCursor(0, 15);

  display.print(“Humid:”);

  display.drawBitmap(20, 35 - 9, upArrow, 8, 8, WHITE);

  display.drawBitmap(20, 55 - 9, downArrow, 8, 8, WHITE);

  display.setFont(&FreeMonoBold9pt7b);    // Font used for numbers

  dispNumber(15, humid, false);

  dispNumber(35, maxHumid, false);

  dispNumber(55, minHumid, false);

  display.display();

}

void DisplayLowBattery(){

  display.clearDisplay();

  display.setTextSize(1);

  display.setFont(&FreeSans9pt7b);  // Font used for text

  display.setCursor(48, 20);

  display.print(“Low”);

  display.setCursor(35, 40);

  display.print(“Battery”);

  display.display();

  delay(2000);

}

void CheckButtons() {

  // If the mode or reset button has been pressed pin will go LOW

  // Check if mode button pressed if so show data or switch mode between displays

  if (digitalRead(MODE_BUTTON) == LOW) {

    timeDisplay = millis();           // Reset so remains display for reset period after switching mode

    if (!displaying) {

      displaying = true;              // Set so displays data

      // Check level of battery

      float voltage = BatteryVoltage();

      if (voltage < 3.3)

        DisplayLowBattery();

      currentMode = dispTemp;

      ShowTemperature();

      delay(1000);

      return;

    }

    // If already displaying move to next display

    switch (currentMode) {

      case dispTemp:

        currentMode = dispTempGraph;

        ShowGraph();

        break;

      case dispTempGraph:

        currentMode = dispHumid;

        ShowHumidity();

        break;

      case dispHumid:

        currentMode = dispHumidGraph;

        ShowGraph();

        break;

      case dispHumidGraph:

        currentMode = dispTemp;

        ShowTemperature();

        break;

    }

    delay(1000);                     // Give time to release button

  }

  // Check if reset button pressed

  // Is the system displaying?

  // If so the reset min and max values

  if (displaying) {

    if (digitalRead(RESET_BUTTON) == LOW) {

      maxTemp = -9;

      minTemp = 99;

      maxHumid = -9;

      minHumid = 99;

      delay(1000);                     // Give time to release button

    }

  }

We first check if the system has been displaying data for longer than the time set to keep it showing. timeDisplay is the millis() elapsed at the point the button was pressed to activate the display, or to change screens.

if ((millis() - timeDisplay) > keepDisplayFor)…

If this time has passed then we make sure the flag is set to indicate that we are not displaying data and check if the time elapsed since we last moved the bitmap exceeds moveEvery, if it has, then we call the routine to display the battery bitmap in a random place each time to avoid burn in.

The system then checks if 2 seconds has elapsed since the last set of readings were taken and, if they have, refreshes the readings and update the minimum and maximum values.

if ((millis() - lastReadingUpdate) > 2000ul) …

If the system is displaying then a switch statement is used to call the routine to present the currently selected data screen, followed by a call to the routine to check if a button has been pressed.

  • Mode button (pin 2) activates the display if not currently in display mode. If in display mode then it circulates through the 4 displays using a switch statement.
  • Reset button (pin 3) will reset the value of the minimum and maximum readings if data is currently being displayed.

Finally, if 15 minutes have elapsed since the last record in the history data was updated, the system calls the routine to store the current readings in the history.

Checking the battery voltage

We use an Analog Input pin to read the voltage. As we are running from a 3.7v volt battery, we need to adjust the reference voltage used by the pin as otherwise it would be comparing the voltage to itself. The statement analogReference(INTERNAL) sets the pin to compare the input voltage to a regulated 1.1v. We therefore need to reduce the voltage on the input pin to less than 1.1v for this to work. This is done by dividing the voltage using 2 resistors, 1m and 330k ohms. This divides the voltage by approximately 4 so when the battery is fully charged, which is 4.2v, the voltage at the pin input is 4.2/4 = 1.05v.

// Read the monitor pin and calculate the voltage

float BatteryVoltage(){

 float reading = analogRead(MONITOR_PIN);

 // Calculate voltage - reference voltage is 1.1v

 return 1.1 * (reading/1023) * voltageDivider;

}

The function BatterVoltage(), reads the analog pin, which will range from 0 for 0 volts to 1, 023 for 1.1v and using this reading calculates the actual voltage coming form the battery.

The DrawScreenSave() function calls this then selects the appropriate bitmap to display based on the following:

  • If voltage is greater then 3.6v - full
  • Voltage between 3.5 and 3.6v - 3/4
  • Voltage between 3.4 and 3.5v - half
  • Voltage between 3.3 and 3.4v - 1/4
  • Voltage < 3.3v - empty

Storing the history

As mentioned above, I initially stored the history in arrays but it appears this caused memory issues. I am therefore storing the data in the EPROM in 96 locations for each, temperature and history, in a circular list. The EEPROM library provides the functions to manage data here.

The history is stored as integers which take 2 bytes each on the Arduino. The pointer histPointer for the address of the data ranges from 0 to 95 and then back to 0. tempStart and humidStart store the start locations of each list and each location is simply the start location + the position * 2.

Displaying the graphs

The graph routines first obtain the minimum and maximum values in the history, calculate the scale and then plot the graph using line draw from the oldest value (histPointer + 1) to the latest stored at histPointer.

On/Off switch

If you wish to add an on/off switch insert this in the wire from the charger module OUT+ to the Arduino board. This will allow you to charge the battery with the unit switched off.

Regulating the battery charging

The TP4056 charger used includes a regulating resistor of 1.1K ohm that provides a charge at a rate of 1, 000mAh. This is really too high for the 1, 000mAh battery used which should be charged at a maximum of 500mAh. It is fiddly, but you can remove the board mounted resistor (R3), or I find it easier to break it by scraping a knife across it as this leaves the post to solder to, and solder on an external resistor to reduce the current. Here is the table showing resistor values and current produced. (Check with a meter that you are still reading the correct resistance across the connection as it is easy to short these and this could cause damage.)

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.