Embedded programming

Helpful links: RP's Programming languages Debugging Passing by value

Book: The pragmatic programmer

 

 

Assignment

group assignment: demonstrate and compare the toolchains and development workflows for available embedded architectures

individual assignment: browse through the data sheet for your microcontroller write a program for a microcontroller, and simulate its operation, to interact (with local input &/or output devices) and communicate (with remote wired or wireless connections) extra credit: test it on a development board extra credit: try different languages &/or development environments

 

 

Wokwi in VSCode

Wokwi is an online Electronics simulator that can be used it to simulate Arduino, ESP32, STM32, and many other popular boards, parts and sensors. I will be using it for this weeks assignment and therefore want to set it up as an extention to VSCode

Is a simulatior. I can pic the ESP32 - C3

Download Pulseview

If you create your own function in VSCode - it must be called function(); - must be forward declared: void funtion(): at the top

Here is a guide on how to: set up Wokwi with VSCode

In the extentions I found the Wokwi simulator and installed it.

Extention

I then Clicked on the search bar, clicked F1, searched for Wokwi and clicked wokwi: start simulator. Then a small warning window popped up on the bottom right hand side of my screen and I clicked Get your Licence key. Clicked open on the window that popped up and got transfered to the Wokwi site.

On the site I saw that it is possible to get a 30 day free version of this extention. For now I don't know if it is possible to extend it, but I think so. The site says that the extention is free for non-commercial use so my guess is that it is possible to generate a new key after 30 days. After creating my account I recieved a key that got importet to Visual Studio Code when I got guided back to it.

WokwiKey

 

 

Notes: Thursday meeting

On Thursday we got an introduction to embedded programming by Leo: FabLab Enschede

The goal of this week: Have something functional.

There are different coding languages: C: c stands for code. It was developed by people who understood the chip. This way of coding is less safe because you need to build in your own safety structures. C++: Arduino IDE, based on C, uses many layers of abstraction. Rust: Supposedly the next C - more secure, will not allow you to write bad code // not very mature for microcontrollers, used mostly for applications MicroPython: Cleaner and easier to read/understand The downside is that this does not work on all microcontrollers RTOSor Real Time Operating System: runs on ESP32, raspberryPi ++, not on old AVRs. Dual core - you write on core-1, not core-0 (not possible) Zephyr: Scalable, optimised, secure, multiple hardware architechtures(using a HAL)

Useful words and notes

Safety: In terms of overriding, safety nets to avoind this and corruption

Compiler: Translates HUC(human understandable code) to binary code

Programmer: Transfer the binary code to the microcontroller

Bootloader:

  • Runs at start of computer
  • Do not use with new AVRs
  • Eats away part of the Memory
  • No bootloader: more space, but limits in other aspects depending on the boo=tloader in question

Space:

  • All about memory
  • Small microcontroller 8kb

Arduino: Bootloader connects microcontroller and IDE

Microcontrollers:

  • Loops, can run 1 program at a time

How to select microcontroller:

  • How many I/O ports do you need? HIGH/LOW (1/0) Digital pin
  • What other pins are needed? (ADC converts voltage, DAC(Digital to analog converter) converts binary to voltage, SPI, I2C, I2S, UART: serial communication, timers++)
  • Power consumtion / speed
  • Operating voltage needed, also for parts
  • Environmental impact
  • Cost
  • Registers: MC only understands binary
  • Abstracted away, you can find it in the datasheet. Register names are in Arduino IDE translated into their own more readable code. Ex: PIN_MODE

Test:

  • Troubleshooting
    • Code + logging
      • use serialPrint (write good description)
    • LEDs

Powering:

  • Historcally: 5V
  • Now: More 3.3V
  • If too high: smoke and frustration

Input devices:

  • 95% are related to voltage.
  • Analog sinal = voltage

Pins:

  • IO pins: HIGH/LOW (1/0) Digital pin
  • ADC (Analog to Digital converter) converts voltage
  • DAC (Digital to analog converter) converts binary to voltage
  • UART: serial communication

LEDs:

  • Always blinking
  • No LEDs in chickeCoops

Multiplexer: possible to use a small MCU - split one pin into many more.

Arduino:

  • DevBoard - UNO: 20 years old
  • toolchains
  • Software Library
  • IDE
  • Bootloader
  • Header Harware resourses claimed:

Common commands: - pinMode() - analogRead() - analogWrite() - digitalRead() - digitalWrite() - Serial.begin() - Serial.print()

Xiao-boards

  • Seeed Studio
  • bootloader already on the board
  • Can use adruino libraries

Other IDES

  • Eclipse
  • Atmel Studio
  • Visual studio code

Tips:

  • Always put an LED on the board
  • Use variables that fit the processor

 

 

Programming software

Arduino IDE

Arduino IDE has some preinstalled boards, but sometimes its necessary to install thhe right board. This is done by pressing file --> preferences --> there you can add boards by clicking on the small icon next to `Additional moard manager URLs. We were provided with these URLs to add to the program:

  https://descartes.net/package_drazzy.com_index.json,
  https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json,
  https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json,
  https://raw.githubusercontent.com/qbolsee/ArduinoCore-fab-sam/master/json/package_Fab_SAM_index.json

board maanger

XIAO-RP2040 and LEDs

Is a baord we used in the introduction. There is more specified info about further down in the comparason section.

To test that a board is working and it is possible to upload to it we used the example code Blink. This can be found under file --> examples --> 01.Basics

After loading the sketch plug in the board (if that's not already done), select the correct board at the top of the page, and upload.

Heres some info about the XIAO-RP2040s built in LEDs:

The board has 5 LEDs on the board. There are 3 on the top right side. These are in the colors Red, Blue, and Green, and can be controlled individually. Underneath them there is a stronger red LED and finally at the centre base of the board there is a Neopixel.

When programming these lights it is important to note that for the LEDs HIGH means OFF, and LOW means ON.

LEDs work with Puls Width Modulation or PWM. THis means that they are always turning off and on. When the LED is dimmer it just means that is has a longer interval of being off in comparason to on.

Here is how to set up the use of the built in RGB-LEDs on the board:

  void setup() {
        // initialize digital pins for LEDs as outputs.
        pinMode(PIN_LED_R, OUTPUT);
        pinMode(PIN_LED_G, OUTPUT);
        pinMode(PIN_LED_B, OUTPUT);
        // Turn off LEDs
        digitalWrite(PIN_LED_R, HIGH);
        digitalWrite(PIN_LED_G, HIGH);
        digitalWrite(PIN_LED_B, HIGH);

  }

This setup function only runc once: when the program starts up after that it moves on to the loop function which it keeps looping through. That is were an animation of the lights can be made. Dylan was talking about a breathing exesise he likes to do where you breathe in for 4 sec, hold for 7 sec and breathe out for 8 sec. I tried to make a simple guide for this.

  void loop() {
        // Breathe in
        digitalWrite(PIN_LED_G, LOW);  // turn the blue LED on 
        delay(4000);                   // wait for a second
        digitalWrite(PIN_LED_G, HIGH); // turn the blue LED off 
        delay(10);                   // wait for a second

        // Hold breath
        digitalWrite(PIN_LED_R, LOW);  // turn the red LED on 
        delay(7000);                   // wait for a second
        digitalWrite(PIN_LED_R, HIGH); // turn the red LED off 
        delay(10);                   // wait for a second

        //Breathe out
        digitalWrite(PIN_LED_B, LOW); // turn the LED off 
        delay(8000);                   // wait for a second
        digitalWrite(PIN_LED_B, HIGH); // turn the LED off 
        delay(10);                   // wait for a second

        }

The Neopixel LED is a bit different. TO use it we installed the library FastLED, and then using the examplecode from that library, also called Blink, we programmed it. Nothing happened. That is because in order to use that pin we need to enable it. In the datasheet ww could see that the NEOPIXEL is pin 12, but the enable ping for it is pin 11. We therefore started the code by setting pin 11 to HIGH.

  #include <FastLED.h>

  // How many leds in your strip?
  #define NUM_LEDS 1

  // build in neopixel pin XIAORP-2040
  #define DATA_PIN 12

  // Define the array of leds
  CRGB leds[NUM_LEDS];

  void setup() { 
        // Set Enable pin to output
        pinMode(11, OUTPUT);

        // Set Enable to on - this will enable the led on the board.
        digitalWrite(11, HIGH);

        // GRB ordering is assumed
        FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);

        }

  void loop() {

        // Turn the LED on, then pause
        leds[0] = CRGB::Navy; // prepares data
        FastLED.show(); // Sends data
        delay(500);

        // Now turn the LED off, then pause
        leds[0] = CRGB::Black; // prepares data
        FastLED.show(); // sends data
        delay(500);
  }

Troubleshooting It could be that the wrong bootloader is installed on the board. To boot it hold the B button, and whilst holding that in click the E button, and release the B button again. The board will then show up as a usb device on the computer and the new bootloader can be dropped in there. Some programs will tell you if the bootloader is wrong and ask if they should cahnge it for you. This happened when I plugged my board into the Arduino IDE.

bootloader_aarduino

 

 

PlatformIO and Visual studio Code

Slides for Platfor IO and VSC by Leo Kuiper

What is platfor IO: A plugin to VSC, IDE Frameowrk: C/C++

Cross-platform IDE which supports many different C/C++ software development kits (SDKs, called Frameworks in platformIO) and includes a lot of sophisticated developer tools.

Why use it? - It works good - Can do more then Arduino IDE - Can work with extentions. - c/c++ --> intellisesce --> autocomplete! - Git directly for the editor - Github copolot --> Use copolot AI to help you to program code - Copilot is now free! - PlatformIO adds embedded programming to VSC

SDK Software Developement kit - framework - why? - Not start from scratch - Toolbox with libraries that work, and expample codes, debugging ect. - ESP32: SDK: IDF - RP: PicoSKD

Steps: - Install extention: PlatformIO IDE

install PlatformIO

  • Install extention: C/C++

When using a windows computer there are some issues that arises. This is beacuse there is a limit to how long the path can be io platform IO. I therefore had to open my terminal as administraitor and typ in this:

windows platformio command

Then go into the platformio.ini file and delete what is there and replace it with:

preferences_platformio

 

 

MicroPython

Reset the board in the same way as mentioned in the Arduino IDE section: hold B and click E. The microcontroller mimics a usb drive: Look for the RPI-RP2-file, It is now in Bootloader mode: any bootloader can me loaded on.

Go to micropython website, install bootloader Download PICO and drag in onto the thumbdrive. It will now dissapear and the bootloader is installed.

Micropyton has an operating system.

Xiao wiki

Oficcial Raspberry pi PicoExtention VSC: code in C/C++, but the Pico SDK framework. Note that Arduino libraries do not work with this micropython

You can upload a file to micropython, but it needs a specific name in order to be booted when powered up again. THe file bust be named boot.py

There are 2 ways to upoad a to your microcontroller: * Upload project: uploads all the files from your project - Upload file: only the file (creates trouble if you are using extra libraries)

 

 

Data sheets!!

After this intro it's time to look at the datasheets of the board I'll be using. Eventually I think I will need my boards to communicate with each other. Even if I do not need that application now, it would be a good option to have. At Waag we were given 2 microcontrolles: XIAO-RP2040 and XIAO-ESP32-C3

To get more familiar with tham I went through this collected datasheet for the XIAO-series Systems-on-Modules User manual.

Xiao means Tiny in Chinese which is fitting to these modules as the boards are small. This makes them great for wearable projects. All the modules in the Xiao series has the same pinouts.

In the assignment it said to look into the datasheet of one board, but since I'm not sure what the difference is between the two we were given I was happy to find a guid with info of both of them. To my delight the first section of the sheet had a selection guide comparing all of the XIAO SoM boards: (and its green!)

xiao comparason

When comparing the RP2040 and ESP32-C3 for my final project which will hopefully result in a few mechanical arms it looks as though I will be using the RP2040, but lets keep reading before makign a desition.

 

 

XIAO-RP2040

Datasheet

rp2040 pinout

Power Consumption: 28.9 mA

Operating Voltage and Supply Voltage: Operating Voltage is 5V (Type C)

Bootloader: Standard Bootloader for common PC port identification, UF2 Bootloader for CircuitPython usage of PC port identification

Programming Languages: Arduino, MicroPython, and CircuitPython

Clock: There is a build in crystal oscillator which provides a precise, stable clock reference.

 

 

XIAOESP32-C3

Datasheet

esp32c3 pinout 1 esp32c3 pinout 2

Power Consumption: 25.7mA (Low power model: <44uA)

Operating Voltage and Supply Voltage: Type C: 5V, Battery: 3.7V Li-On

Charging current: 380mA±30mA

Bootloader: Standard Bootloader for common PC port identification

Programming Languages: Arduino

esp_battery

How to power the XIAOESP32-C3 by battery:

  • Make sure to use a proper battery that meets the specifications
  • There is a safety built in that will allow the board to be connected to computer via data cable whilst powered by battery.
  • There will be no LED indication when the board is powered by battery, unless it is written into the code.

 

 

Comparason

To make an easier overview here is a comparason of the two:

XIAO-RP2040 XIAOESP32-C3
Processor RP2040 ESP32C3
RAM 264 KB SRAM 400 KB SRAM
Flash(chip) No 4MB
Flash(onboard) 2MB 4MB
Build-in-sensors No No
PWM/analog pins 11/4 11/4
I2C/UART/SPI Yes Yes
Bluetooth No Yes
WiFi No Yes
Reset button Yes Yes
Boot Button Yes Yes
User LED Yes No
Battery Charge LED No Yes
Battery Charge IC No Yes
Low power mode No <44μA
Arduino Yes Yes
CircuitPyton Yes No
MicroPython Yes No
Product life 3+ years 3+ years
Power consumption 28.9 mA 25.7mA
Operating Voltage 5V 5v / 3.7V

 

 

Project: Humidify my house

Now that I've looked at the boards I think I will use the XIAOESP32-C3 for this weeks assignment. It can only be programmed using arduino or C++, but that's alright for me. I also like to have the opportunity to connect it wirelesly with other boards if needed. I have therefore decided to make the base for a humidifier in my house. My plan is to make a humidifier that ac ctivates whenever the humidity drops below 40%, and realses different sents based on what time of day it is.

himidifier illustration

For this I plan to use a DHT22 humitity and temperature sensor, a 16x2 LCD display with IC2 adapter, relays, ultrasonic mistmakers and a XIAOESP32-C3.

I'm testing this out in wokwi. First I needed to add the Liquid Crystal library. THat can be done by navigating to the library manager on the top left part of the screen and seraching fo rthe needed library. In this case it automatically added both the Licuid crystal library and the one for Liquid crystal I2C, which is what I am using.

LCD library

From the data sheets I can see that the LCD screen connected through the I2C has 4 pins. GND, VCC, SDA and SCL. By looking at the datasheet from XIAOESP32-C3 I see that the SDA pin goes to pin 4 and SCL to pin 5.

16x2 LCD display with IC2 adapter

Model I2C Serial Interface 1602 LCD Module
Power supply 5V
Display Type Negative white on Blue backlight.
I2C Address 0x38-0x3F (0x3F default)
Interface I2C to 4bits LCD data and control lines
Contrast Adjustment built-in Potentiometer

First code:

  // Include the library
  #include <LiquidCrystal_I2C.h>

  // Add the lcd
  LiquidCrystal_I2C lcd(0x27, 16, 2);

  void setup() {
  // Initalise the LCD
  lcd.init();
  // Turn on the LCD backlight
  lcd.backlight();
  // Put text on the LCD
  lcd.print("Hello World!");
  }

  void loop() {

  }

In the wokwi simulator the first attemt looks like this:

LCD hello world

Now that the LCD screen is hooked up correctly it's time to add a humifidier.

First some info about the DHT22 sensor.

Humidity sensor

Model DHT22
Power supply 3.3-6V DC
Output signal digital signal via single-bus
Operating range humidity 0-100%RH; temperature -40~80Celsius
Accuracy humidity +-2%RH(Max +-5%RH); temperature <+-0.5Celsius
Long-term Stability +-0.5%RH/year
Sensing period Average: 2s
Interchangeability fully interchangeable

I started by adding the library DHT22. The sensor has 4 legs. the 1st is VCC, 2nd in DATA (here the signal will come through), 3rd is NULL, and the 4th is GND.

In the datasheet I read that when the sensor is powered I need to wait 1 second before sending any data to it. I therefore add a delay (1000) in void setup. And that One capacitor valued 100nF can be added between VDD and GND for wave filtering. I cannot find this component in wokwi, but will make a note of it for the schimatic and the practical setup. For the practical set up it's also worth to not that this sensor will need to be kept out ofstron light and UV light since this will affect the preformance.

Wokwi was being very slow and could not upload the code so I therefore dicided to test it out on a breadboard. I wiered everything up and plugged the board in and suddenly there was a burt smell. I had put the sensor the wrong way around and inverted the polarities. Sam told me he had had the same issue when using this sensor it the university. Sloppy wiring by me.

burns_dht

I want to code my project in PlatforIO in Visual Studio Code. I open a new project and add the DHT sensor library form Adafruit.

Here is my first test code for the humidity sensor:

  // include arduino
  #include <Arduino.h>

  // include library for DHT22
  #include <DHT.h>

  // Define humidifier pin
  #define DHTpin 2 // GPI02 XIAO ESP32-C3
  #define DHTTYPE DHT11 // DHT 22 (AM2302)
  DHT dht(DHTpin,DHTTYPE); // Initialise HDT senor

  // Variables

  float humidity;     // stores humidity value
  float temperature;  // stores temperature value

  void setup() {
  Serial.begin(9600); // serial communication
  dht.begin(); // Communication with sensor

  delay(1000); // delay 1 sec to allow sensor to start up
  }

  void loop() {


  // Read data and store it to the variables humidity and temperature
  hum = dht.readHumidity();
  temp = dht.readTemperature();

  // Print temp and humidity values to serial monitor
  Serial.print("Humidity: ");
  Serial.print(hum);
  Serial.print(" %, Temperature: ");
  Serial.print(temp);
  Serial.print(" Celcius");

  // Delay -- 2 sec -- the sensor samples are every 2 sec
  delay(2000);

  }

I had to exchange the DHT22 for a DHT11, an older version since i burnt through the other one. Sam had a good tip for me: Keep a finger on the sensor when you plug it in. If it gets warm quikly unplug it. THen it can still be saved. And also always check the wiring.

I got some faults: * hum and temp not identified. I had changed them from temperature and humidity in the void loop, but not when they were declared. * Could not read sertial monitor: I had not chosen the correct USBPORT and needed to change the baud rate to 9600. This also did not help, but by looking ina forum I saw that I needed to declare

  monitor_speed = 9600

in the platformio.ini file.

I then tried againg and there is still a problem with finding the port for the serial monitor. I tried holding Boot and clicking Enable whilst holding boot. Still did not work. So I decided to try to upload the code from arduino IDE.

It uploaded fine after installing the DHT library, however the serial monitor only displayed the values nan:

nan values

Time to look at the datasheet for the DHT11

I tried switching the sensor out for another DHT22, but it still sais NAN as values. Sam came over to help me and we switched the sensor with one of his and then it worked. Turns out the sensors I used were broken. THe new code had some serial prints to help keep track of if the sensor has started and are looping:

  // include arduino
  #include <Arduino.h>

  // include library for DHTmodule
  #include <DHT.h>

  // Define humidifier pin
  #define DHTpin D3           // GPI02 XIAO ESP32-C3
  #define DHTTYPE DHT11      // DHT 11
  DHT dht(DHTpin, DHTTYPE);  // Initialise HDT senor

  // Variables

  float hum;   // stores humidity value
  float temp;  // stores temperature value

  void setup() {
  Serial.begin(9600);  // serial communication
  dht.begin();         // Communication with sensor
  Serial.println("started"); // to see if its started
  delay(1000);  // delay 1 sec to allow sensor to start up
  }

  void loop() {
  // Delay -- 2 sec -- the sensor samples are every 2 sec
  delay(2000);  
  // to see if its looping
  Serial.println("loop");

  // Read data and store it to the variables humidity and temperature
  hum = dht.readHumidity();
  temp = dht.readTemperature();

  // Print temp and humidity values to serial monitor
  Serial.print("Humidity: ");
  Serial.print(hum);
  Serial.print(" %, Temperature: ");
  Serial.print(temp);
  Serial.println(" Celcius");


  }

Now to combine the 2 codes so far:

  // include library for DHT22 and LCD
  #include <DHT.h>
  #include <LiquidCrystal_I2C.h>

  // Define humidifier pin
  #define DHTpin D3           // GPI02 XIAO ESP32-C3
  #define DHTTYPE DHT11      // DHT 22 (AM2302)
  DHT dht(DHTpin, DHTTYPE);  // Initialise HDT senor

  // Variables

  float hum;   // stores humidity value
  float temp;  // stores temperature value

  // Add the lcd
  LiquidCrystal_I2C lcd(0x27, 16, 2);

  void setup() {
  Serial.begin(9600);  // serial communication
  dht.begin();         // Communication with sensor
  Serial.println("started");
  delay(1000);  //delay 1 sec tod allow sensor to start up

  // Initalise the LCD
  lcd.init();
  // Turn on the LCD backlight
  lcd.backlight();
  // Put text on the LCD
  lcd.print("Hello World!"); 
  }

  void loop() {
  delay(2000);
  Serial.println("loop");

  // Read data and store it to the variables humidity and temperature
  hum = dht.readHumidity();
  temp = dht.readTemperature();

  // Print temp and humidity values to serial monitor
  Serial.print("Humidity: ");
  Serial.print(hum);
  Serial.print(" %, Temperature: ");
  Serial.print(temp);
  Serial.println(" Celcius");

  // Delay -- 2 sec -- the sensor samples are every 2 sec
  }

I now have a working display and a sensor that reads the temperature and humidity. Lets display that on the LCD:

display humidity

Here is the next part of the code. Here there are 3 relays added, with this code it is possible to check that the relays, humidity sensor and the lcd screen works:

  // include library for DHT22 and LCD
  #include <DHT.h>
  #include <LiquidCrystal_I2C.h>

  // Define humidifier pin
  #define DHTpin D3           // GPI02 XIAO ESP32-C3
  #define DHTTYPE DHT11      // DHT 22 (AM2302)
  DHT dht(DHTpin, DHTTYPE);  // Initialise HDT senor

  // Variables

  float hum;   // stores humidity value
  float temp;  // stores temperature value

  // Add the lcd
  LiquidCrystal_I2C lcd(0x27, 16, 2);

  // intergers for relays
  int R_1 = D10;
  int R_2 = D9;
  int R_3 = D8;

  void setup() {
  Serial.begin(9600);  // serial communication
  dht.begin();         // Communication with sensor
  Serial.println("started");


  // Initalise the LCD
  lcd.init();
  // Turn on the LCD backlight
  lcd.backlight();
  // Put text on the LCD
  lcd.print("Hello World!");

  pinMode(R_1, OUTPUT);
  pinMode(R_2, OUTPUT);
  pinMode(R_3, OUTPUT);

  delay(1000);  //delay 1 sec tod allow sensor to start up
  }

  void loop() {
  delay(2000);
  Serial.println("loop");

  // Read data and store it to the variables humidity and temperature
  hum = dht.readHumidity();
  temp = dht.readTemperature();

  // Print temp and humidity values to serial monitor
  Serial.print("Humidity: ");
  Serial.print(hum);
  Serial.print(" %, Temperature: ");
  Serial.print(temp);
  Serial.println(" Celcius");

  lcd.clear(); // clear the LCD screen 
  lcd.setCursor(0,0);
  lcd.print("Temp: ");
  lcd.print(temp);

  lcd.setCursor(0,1);
  lcd.print(" Hum: ");
  lcd.print(hum);

  digitalWrite(R_1, HIGH);
  delay(1000);
  digitalWrite(R_2, HIGH);
  delay(1000);
  digitalWrite(R_3, HIGH);
  delay(1000);
  digitalWrite(R_1, LOW);
  delay(1000);
  digitalWrite(R_2, LOW);
  delay(1000);
  digitalWrite(R_3, LOW);
  delay(1000);


  }

Onto the main part: Its time to make the code do what I want it to do. The ideal humidity in a house is between 40% and 60%. As long as the humidity in the house is under 60% there should not be a risk of mold forming. I will therefore set the module to start humidifying at 45% and stop at 55%. If humidity is over 60% then the display should write: Open a window!!

  if (hum > 60){
  lcd.clear(); // clear the LCD screen 
  lcd.setCursor(0,0);
  lcd.print("Open a window!!");
  }

Ideally this humidifier will have 4 separate chambers which each are active at differents times of day. I therefore need to use some kind of clock. I remember reading that the ESP32 has a built in clock.

I first install the library "esp32time". I am using this as my guide.

I added to the code :

      #include <ESP32Time.h>

      ESP32Time rtc(3600);

      void setup(){
            rtc.setTime(30, 54, 14, 18, 2, 2025);  // 18th Feb 2025 14:54:30
      }

      void loop(){
            Serial.println(rtc.getHour(true));      //  (int)     15    (0-23) 
      }

I can now see the number 15 printed in the serial monitor indicating that we are in hour 15 of the day. This number can be used to change which of the relays are activated when the humidity changes. I had to invert the values for the Relays so that HIGH means off and LOW means on. Here is the final code:

  // include library for DHT22 and LCD
  #include <DHT.h>
  #include <LiquidCrystal_I2C.h>
  #include <ESP32Time.h>

  // Define humidifier pin
  #define DHTpin D3           // GPI02 XIAO ESP32-C3
  #define DHTTYPE DHT11      // DHT 22 (AM2302)
  DHT dht(DHTpin, DHTTYPE);  // Initialise HDT senor

  // Variables

  float hum;   // stores humidity value
  float temp;  // stores temperature value

  // Add the lcd
  LiquidCrystal_I2C lcd(0x27, 16, 2);

  // intergers for relays
  int R_1 = D10;
  int R_2 = D9;
  int R_3 = D8;
  int R_4 = D7;

  ESP32Time rtc(3600);

  void setup() {
        Serial.begin(9600);  // serial communication
        dht.begin();         // Communication with sensor
        Serial.println("started");

        // Initalise the LCD
        lcd.init();
        // Turn on the LCD backlight
        lcd.backlight();
        // Put text on the LCD
        lcd.print("Hello World!");

        pinMode(R_1, OUTPUT);
        pinMode(R_2, OUTPUT);
        pinMode(R_3, OUTPUT);
        pinMode(R_4, OUTPUT);

        // set time
        rtc.setTime(30, 54, 14, 18, 2, 2025);  // 18th Feb 2025 14:54:30

        delay(1000);  //delay 1 sec tod allow sensor to start up
  }

  void loop() {
        delay(2000);
        Serial.println("loop");
        Serial.println(rtc.getHour(true));      //  (int)     15    (0-23)

        // Read data and store it to the variables humidity and temperature
        hum = dht.readHumidity();
        temp = dht.readTemperature();

        // Print temp and humidity values to serial monitor
        Serial.print("Humidity: ");
        Serial.print(hum);
        Serial.print(" %, Temperature: ");
        Serial.print(temp);
        Serial.println(" Celcius");

        lcd.clear(); // clear the LCD screen 
        lcd.setCursor(0,0);
        lcd.print("Temp: ");
        lcd.print(temp);

        lcd.setCursor(0,1);
        lcd.print(" Hum: ");
        lcd.print(hum);

        if (hum > 60){
              lcd.clear(); // clear the LCD screen 
              lcd.setCursor(0,0);
              lcd.print("Open a window!!");
              digitalWrite(R_1, HIGH);
              digitalWrite(R_2, HIGH);
              digitalWrite(R_3, HIGH);
              digitalWrite(R_4, HIGH);
        }

        if (hum <= 55 && rtc.getHour(true) >= 0 && rtc.getHour(true) <= 5) {
              digitalWrite(R_1, LOW);
              digitalWrite(R_2, HIGH);
              digitalWrite(R_3, HIGH);
              digitalWrite(R_4, HIGH);
        }

        if (hum <= 55 && rtc.getHour(true) >= 6 && rtc.getHour(true) <= 11 ) {
              digitalWrite(R_1, HIGH);
              digitalWrite(R_2, LOW);
              digitalWrite(R_3, HIGH);
              digitalWrite(R_4, HIGH);
        }

        if (hum <= 55 && rtc.getHour(true) >= 12 && rtc.getHour(true) <= 17) {
              digitalWrite(R_1, HIGH);
              digitalWrite(R_2, HIGH);
              digitalWrite(R_3, LOW);
              digitalWrite(R_4, HIGH);
        }

        if (hum <= 55 && rtc.getHour(true) >= 18 && rtc.getHour(true) <= 23) {
              digitalWrite(R_1, HIGH);
              digitalWrite(R_2, HIGH);
              digitalWrite(R_3, HIGH);
              digitalWrite(R_4, LOW);
        }

        if (hum >= 56) {
              digitalWrite(R_1, HIGH);
              digitalWrite(R_2, HIGH);
              digitalWrite(R_3, HIGH);
              digitalWrite(R_4, HIGH);
        }

  }

Now I can test it out properly. I know from last time I worked with the humidity modules that they need to be powered separatley from the microcontroller. I have also rearnt that I need to surpass the button on the module. I have been talking with Sam on how to do it and i have an idea. I first tried soldering the button so it's always pressed, but that ended up making a beeping sound the whole time. I also realise that I don't really have time to finish the physical computing part of this this week, but that's okay since the focus in embedded programming.

I do however have time to change the code a bit. Since having the button pressed for a longer time causes a beeping sound it is better to have it pressed once to initialise humidification and then pressed again to stop. This means that the code needs to change. Sam was a great help in making sense of this.

This change means the microcontroller needs to keep track of wether a button has been pressed or not in order to know if it will turn the humidifier on or off. I added booleans for the 4 relays to know if the button is true (clicked and on) or false (clicked and off)

bool R_button_1 false
bool R_button_2 false
bool R_button_3 false
bool R_button_4 false

I then created a rest function to be called in the beginning of each of the if statements. This is to make sure all the humidifiers are off to begin with to avoind muldiple being on at the same time.

Going back to the if statements related to humidity and time of day. Now that reset function is called in the beginning of each loop I could remove some of the digitalWrites. Now the relay presses the button ofr half a second and changes the boolean for that part to true.

  if (hum <= 40 && rtc.getHour(true) >= 0 && rtc.getHour(true) <= 5) {
        reset();
        digitalWrite(R_1, LOW);
        delay(500);
        digitalWrite(R_1, HIGH);
        R_button_1 = true;
  }

So here is the final code!

  // include library for DHT22 and LCD
  #include <DHT.h>
  #include <LiquidCrystal_I2C.h>
  #include <ESP32Time.h>

  // Define humidifier pin
  #define DHTpin D3           // GPI02 XIAO ESP32-C3
  #define DHTTYPE DHT11      // DHT 22 (AM2302)
  DHT dht(DHTpin, DHTTYPE);  // Initialise HDT senor

  // Variables

  float hum;   // stores humidity value
  float temp;  // stores temperature value

  // Add the lcd
  LiquidCrystal_I2C lcd(0x27, 16, 2);

  // intergers for relays
  int R_1 = D10;
  int R_2 = D9;
  int R_3 = D8;
  int R_4 = D7;


  bool R_button_1 false
  bool R_button_2 false
  bool R_button_3 false
  bool R_button_4 false

  ESP32Time rtc(3600);

  void setup() {
  Serial.begin(9600);  // serial communication
  dht.begin();         // Communication with sensor
  Serial.println("started");

  // Initalise the LCD
  lcd.init();
  // Turn on the LCD backlight
  lcd.backlight();
  // Put text on the LCD
  lcd.print("Hello World!");

  pinMode(R_1, OUTPUT);
  pinMode(R_2, OUTPUT);
  pinMode(R_3, OUTPUT);
  pinMode(R_4, OUTPUT);

  // set time
  rtc.setTime(30, 54, 14, 18, 2, 2025);  // 18th Feb 2025 14:54:30

  delay(1000);  //delay 1 sec tod allow sensor to start up
  }

  void loop() {
  delay(2000);
  Serial.println("loop");
  Serial.println(rtc.getHour(true));      //  (int)     15    (0-23)

  // Read data and store it to the variables humidity and temperature
  hum = dht.readHumidity();
  temp = dht.readTemperature();

  // Print temp and humidity values to serial monitor
  Serial.print("Humidity: ");
  Serial.print(hum);
  Serial.print(" %, Temperature: ");
  Serial.print(temp);
  Serial.println(" Celcius");

  lcd.clear(); // clear the LCD screen 
  lcd.setCursor(0,0);
  lcd.print("Temp: ");
  lcd.print(temp);

  lcd.setCursor(0,1);
  lcd.print(" Hum: ");
  lcd.print(hum);

  if (hum > 60){
  lcd.clear(); // clear the LCD screen 
  lcd.setCursor(0,0);
  lcd.print("Open a window!!");
  digitalWrite(R_1, HIGH);
  digitalWrite(R_2, HIGH);
  digitalWrite(R_3, HIGH);
  digitalWrite(R_4, HIGH);
  }

  if (hum <= 40 && rtc.getHour(true) >= 0 && rtc.getHour(true) <= 5) {
  reset();
  digitalWrite(R_1, LOW);
  delay(500);
  digitalWrite(R_1, HIGH);
  R_button_1 = true;
  }

  if (hum <= 30 && rtc.getHour(true) >= 6 && rtc.getHour(true) <= 11 ) {
  reset();
  digitalWrite(R_2, LOW);
  delay(500);
  digitalWrite(R_2, HIGH);
  R_button_2 = true;
  }

  if (hum <= 40 && rtc.getHour(true) >= 12 && rtc.getHour(true) <= 17) {
  reset();
  digitalWrite(R_3, LOW);
  delay(500);
  digitalWrite(R_3, HIGH);
  R_button_3 = true;
  }

  if (hum <= 40 && rtc.getHour(true) >= 18 && rtc.getHour(true) <= 23) {
  reset();
  digitalWrite(R_4, LOW);
  delay(500);
  digitalWrite(R_4, HIGH);
  R_button_4 = true;
  }

  if (hum >= 56) {
  reset();
  }

  }


  void reset(){
  if (R_button_1 = true){
  digitalWrite(R_1, LOW);
  delay(500);
  digitalWrite(R_1, HIGH);
  R_button_1 = false;
  }

  if (R_button_2 = true){
  digitalWrite(R_2, LOW);
  delay(500);
  digitalWrite(R_2, HIGH);
  R_button_1 = false;
  }

  if (R_button_2 = true){
  digitalWrite(R_3, LOW);
  delay(500);
  digitalWrite(R_3, HIGH);
  R_button_1 = false;
  }

  if (R_button_3 = true){
  digitalWrite(R_4, LOW);
  delay(500);
  digitalWrite(R_4, HIGH);
  R_button_1 = false;
  }

  }