You are on page 1of 1991

110 Fun Projects with Arduino

1) Arduino Hacking STEM Electroconductivity


Meter

COMPONENTS AND SUPPLIES

biodegradable straw
× 1

coffee stir stick × 2


stainless steel wire (28 gauge,
17cm) × 2

pin-ended alligator clips


× 2

Resistor 100 ohm


× 1

Arduino UNO & Genuino UNO


× 1

USB-A to B Cable
× 1
NECESSARY TOOLS AND MACHINES
scissors

Wire Stripper & Cutter, 18-10 AWG /


0.75-4mm² Capacity Wires

Hot glue gun (generic)

Tape, Clear

ruler
APPS AND ONLINE SERVICES
Microsoft Data Streamer

Arduino IDE

Microsoft Excel

ABOUT THIS PROJECT

This project aimed to meet the requirements of the


science fair that happened in my city Our
electroconductivity sensor was designed as a simple
way to measure the amounts of dissolved substances
in different water samples. It can also be used as a
(short-term) soil moisture sensor!
This sensor is made of two wires separated by an air
gap. The air gap allows us to test how well a material
or substance conducts electricity.
Build an Electroconductivity Meter
Mark your straw at 14 cm. Cut at your mark.

Next, mark both of your coffee stir sticks at 13 cm and


make cuts.

Using your hot glue gun, run a thin line of glue along
the length of one of your stir sticks.
Quickly press the sticks together until the glue has
cooled.

Measure and cut two lengths of 17 cm stainless steel


wire. Straighten out the wires the best you can.

Place the wire on the stir stick so that it is centered


and the ends extend about 1.75 cm beyond the stir
stick.
Center your other wire opposite the first. Tape the
wires onto the stir sticks.

Tape the middle and opposite ends of the sticks to


hold the wire in place keeping the wires centered on
the sticks.

Push the stir sticks with wire into your 14 cm straw.


Measure to make sure your wires stick out of the end
of the straw at the 1.5 cm mark.

Dab some hot glue inside both ends of the straw.

Measure and cut your other length of straw at 4 cm


Cut the 4cm straw in half, then dab some hot glue on
the end and...

... attach to the end of the straw! This will act as a


shield guard for the sensor wire ends.

Bend the longer ends of the wire as shown in the


photo above. This gives the alligator clips a better
connection once attached.
Attach alligator clips to the bent wires. Awesome!
You’ve completed the EC sensor. You care now ready
to connect to your microcontroller.
Connect your alligator clips to the Arduino Uno as
shown in the Attachments section.
If you are comfortable writing Arduino code, use the
analog input pins to measure the voltage changes
across the EC sensor. You are also welcome to use our
sketch which is provided in the Attachments section.

SCHEMATICS

A Fritzing Diagram showing the electrical connections


from the EC Sensor wires to the Arduino analog input
pin A0.
CODE

// CONSTANTS / SETTINGS

const byte POWER_PIN = 2; // Digital pin to use for powering


pulse circuit
const byte EC_PIN = A0; // Analog pin used to read EC Meter
volage

const int READ_DURATION = 100; // Amount of time to take


reading for (ms)
const int READ_INTERVAL = 6000; // Amount of time between
readings (ms)

const String SERIAL_OUTPUT_DELIMITER = ","; // Cordoba expects


a comma-delimited string
const int SERIAL_OUTPUT_INTERVAL = 175; // Amount of time
between serial outputs

// TIMESTAMPS
unsigned long currentTime = 0;
unsigned long readStartTime = 0; // Time that the EC Meter read
process starts
unsigned long lastOutputTime = 0; // Time of last serial output

// SENSORS

float ecMeterReading = 0;
float ecMeterVoltage = 0;

void setup() {
Serial.begin( 9600 );

pinMode( POWER_PIN , OUTPUT );


}

void loop() {
currentTime = millis();

// Read Sensors
// Check for start read time
if ( currentTime - readStartTime >= READ_INTERVAL ){ // Initialize
EC Meter read sequence
readStartTime = currentTime; // Set start time
}
else if ( currentTime - READ_DURATION <= readStartTime ) // Power
Up / Read
{
startPower( POWER_PIN ); // Start charging solution
delay(250); // Delay until fully charged
readSensors(); // Take sensor readings
delay(250);
} else { // Power Down
stopPower( POWER_PIN ); // Stop charging and let
solution depolarize
}

writeToSerial();
}

/*
------------------------------------------------------------------------------------------
-------------
SENSOR/ARDUINO PROCESSING
------------------------------------------------------------------------------------------
-------------
*/

void startPower( byte pin ){


digitalWrite( pin , HIGH );
}

void stopPower ( byte pin ){


digitalWrite( pin , LOW );
}

void readSensors() {
ecMeterReading = analogRead( EC_PIN ); // read the voltage from
the EC Meter
ecMeterVoltage = ecMeterReading * 5.0;
ecMeterVoltage = ecMeterVoltage / 1024;
}

/*
------------------------------------------------------------------------------------------
-------------
OUTGOING SERIAL DATA TO EXCEL PROCESSING CODE
------------------------------------------------------------------------------------------
-------------
*/

void writeToSerial()
{
// Ignore if not within output interval
if ( currentTime - lastOutputTime < SERIAL_OUTPUT_INTERVAL ) {
return;
}
Serial.print( ecMeterVoltage , 4 );
Serial.print( SERIAL_OUTPUT_DELIMITER );

Serial.println();

lastOutputTime = currentTime;
}

2) Arduino Cockroach Laser Killer


COMPONENTS AND SUPPLIES

Arduino Nano R3
× 1

SG90 Micro-servo motor


× 1
LDR sensor × 1

Resistor 10k ohm


× 1

Jumper wires (generic)


× 1

Breadboard (generic)
The 170 points breadboard × 1

9V battery (generic)
× 1

9V Battery Clip
× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

If you feel terrified about cockroaches...


You problem is now solved with " Cockroach Laser
Killer!
No more embarrassing excuses to run off from them!

Okay...this is a simple LDR and Servo interaction. Geta


laser pen and "shoot" at the target. LDR activates a servo
motor to drop your target down. 3 seconds later it goes
up again for another shot.
The main issue is to set the correct threshold of the LDR
sensor and avoid unwanted movements due to light
conditions.
A
7cm x 7cm box.
The inital setup. When energized, the servo lifts the
target.
The target arised and the laser gun!
Creepy!
In the box with a smal breadboard.

SCHEMATICS
CODE

/*
Project - Interaction LDR x Servo
*/
#include <Servo.h>

Servo servo1; // Servo object

int pinServo = 2; // variable to store the servo position


int triggerPoint = 970; //trigger point to start servo
byte sensor = A0;
int sensorValue;

void setup() {
pinMode(pinServo, OUTPUT);
servo1.attach(pinServo); // attaches the servo pin
servo1.write(155);// tell servo to go to "up" position
delay(200);
pinMode(sensor, INPUT);
}

void loop() {
sensorValue = analogRead(sensor);
if (sensorValue > triggerPoint){
servo1.write(75); // tell servo to go to "down" position
delay(3000);
servo1.write(155);
delay(200);
}
}//End loop
3) Controlled Board Eraser Using Arduino and
1Sheeld

COMPONENTS AND SUPPLIES


Android device × 1
Arduino UNO & Genuino UNO
× 1

1Sheeld
× 1

Micro Metal DC motor kit


× 2

L298 Dual H-Bridge Motor


Driver × 1

Magnetic Disk
× 2

LED (generic)
× 1
NECESSARY TOOLS AND MACHINES

Magnetic Board Eraser

ABOUT THIS PROJECT

Are you tired of erasing the board every time you use it.
Have you ever thought of erasing the whole board while
you are sitting in your place. The automatic board eraser
is a normal magnetic board eraser with motors and
wheels that can easily erase and clean your board using
your mobile phone. Just leave it mounted on the board
and use it when you need to erase.

Why did i decide to make it ?

Most of the people nowadays use white boards in classes


or meeting rooms. They write a lot and erase every time
when they finish. There are some disadvantages from
erasing the whole board physically with your hand, like
wasting some time, doing effort, not professional in
some meetings for important people to do it themselves
and it the eraser makes your hands more dirty after using
it. Moreover, some people find it hard to reach all the
parts of the board especially when it is mounted on a
high distance from the ground. As a result, I decided to
build a small magnetic automated board eraser with
wheels so i could control it easily from my mobile phone
to erase the board from my place.

How Does it work?

After connecting all the hardware components and


uploading the code to the arduino and 1sheeld start
opening the 1sheeld mobile application and connect it to
the 1sheeld board via Bluetooth. Then you have to select
the shields that we will use; they are the game pad shield
and accelerometer shield. Put the eraser on the board and
open the game pad shield and start using the four arrow
directions to move up, down, left or right. An LED will
be high when the magnetic eraser moves on the board to
start erasing words. Another way to control this eraser is
to open the accelerometer shield and hold the phone in
your hand. If you want to move up tilt your hand in the
front direction to make the Y < -5, so the eraser will
move up. If you want to move down tilt your hand in the
backward direction to make the Y < 6, so the eraser will
move down. Furthermore, if you want to move right tilt
your hand in the right direction to make the x < -6, so the
eraser will move in the right direction and finally If you
want to move left tilt your hand in the left direction to
make the x > 6, so the eraser will move in the left
direction. Now your board will be easily controlled to
erase the whole board without doing any effort.

Images of hardware Components

Magnetic Board Eraser


Micro metal DC motors and wheels
Motor Driver L289n
Motors connected to motor driver
1sheeld Board
Gloves used to control the board eraser using mobile
accelerometer
Top view of the Eraser

Game pad used to control the eraser


Magnetic Board Eraser Final Prototype

SCHEMATICS
CODE

#define CUSTOM_SETTINGS
#define INCLUDE_GAMEPAD_SHIELD
#define INCLUDE_LED_SHIELD
#define INCLUDE_ACCELEROMETER_SENSOR_SHIELD

float x, y, z;

/* Include 1Sheeld library. */


#include <OneSheeld.h>

/* A name for the LED on pin 7. */


const int ledPin = 13;

/* Pin configuration of the Seeedstudio's motor shield. */


int motorAPin1 = 8;
int motorAPin2 = 11;
int motorBPin1 = 12;
int motorBPin2 = 7;
int motorASpeedPin = 9;
int motorBSpeedPin = 10;

void setup()
{
/* Start communication. */
OneSheeld.begin();
/* Set the LED pin as output. */
pinMode(ledPin, OUTPUT);

/* Seeedstudio's motor shield initialization. */


pinMode(motorAPin1, OUTPUT); // IN1 of motor A
pinMode(motorAPin2, OUTPUT); // IN2 of motor A
pinMode(motorBPin1, OUTPUT); // IN3 of motor B
pinMode(motorBPin2, OUTPUT); // IN4 of motor B
pinMode(motorASpeedPin, OUTPUT); // Speed of motor A
pinMode(motorBSpeedPin, OUTPUT); // Speed of Motor B
}

void loop()

{ x=AccelerometerSensor.getX();
y=AccelerometerSensor.getY();
z=AccelerometerSensor.getZ();

/* If up is pressed, move the car forward. */


if (GamePad.isUpPressed()|| y < -5)
{
analogWrite(motorASpeedPin, 255);
analogWrite(motorBSpeedPin, 255);
digitalWrite(motorAPin1, LOW);
digitalWrite(motorAPin2, HIGH);
digitalWrite(motorBPin1, LOW);
digitalWrite(motorBPin2, HIGH);
digitalWrite(ledPin, HIGH);
}
/* If down is pressed, move the car backwards. */
else if (GamePad.isDownPressed()|| y > 6)
{
analogWrite(motorASpeedPin, 255);
analogWrite(motorBSpeedPin, 255);
digitalWrite(motorAPin1, HIGH);
digitalWrite(motorAPin2, LOW);
digitalWrite(motorBPin1, HIGH);
digitalWrite(motorBPin2, LOW);
digitalWrite(ledPin, HIGH);

}
/* If right is pressed, turn the car to the right. */
else if (GamePad.isRightPressed() || x < -6)
{
analogWrite(motorASpeedPin, 255);
analogWrite(motorBSpeedPin, 255);
digitalWrite(motorAPin1, LOW);
digitalWrite(motorAPin2, HIGH);
digitalWrite(motorBPin1, HIGH);
digitalWrite(motorBPin2, LOW);
digitalWrite(ledPin, HIGH);

}
/* If left is pressed, turn the car to the left. */
else if (GamePad.isLeftPressed()|| x > 6)
{
analogWrite(motorASpeedPin, 255);
analogWrite(motorBSpeedPin, 255);
digitalWrite(motorAPin1, HIGH);
digitalWrite(motorAPin2, LOW);
digitalWrite(motorBPin1, LOW);
digitalWrite(motorBPin2, HIGH);
digitalWrite(ledPin, HIGH);

}
/* If nothing is pressed stop all motors. */
else
{
analogWrite(motorASpeedPin, 0);
analogWrite(motorBSpeedPin, 0);
digitalWrite(ledPin, LOW);
}

}
4) Arduino Automatic Room Light Controller with
Bidirectional Visitor

COMPONENTS AND SUPPLIES


Arduino UNO & Genuino UNO × 1
Relay (generic)
× 1

Resistor 100 ohm


× 1

Infrared Module
× 1

Adafruit Standard LCD - 16x2


White on Blue
× 1

General Purpose Transistor NPN


× 1

Breadboard (generic)
× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

The project of “Digital visitor counter” is based on the


interfacing of some components such as sensors,
motors etc. with Arduino microcontroller. This
counter can count people in both directions. This
circuit can be used to count the number of persons
entering a hall/mall/home/office in the entrance gate
and it can count the number of persons leaving the hall
by decrementing the count at the same gate or an exit
gate, and that depends upon sensor placement in the
mall/hall. It can also be used at gates of parking areas
and other public places.
This project is divided into four parts: sensors,
controller, counter display and gate. The sensor would
observe an interruption and provide an input to the
controller which would run the counter increment or
decrement depending on the entering or exiting of
people. And counting is displayed on a 16x2 LCD
through the controller.
SCHEMATICS
CODE

#include<LiquidCrystal.h>
LiquidCrystal lcd(13,12,11,10,9,8);
#define in 14
#define out 19
#define relay 2
int count=0;
void IN()
{
count++;
if(count>=10)
{
count=10;
}
lcd.clear();
lcd.print("Person In Room:");
lcd.setCursor(0,1);
lcd.print(count);
delay(1000);
}
void OUT()
{
count--;
if(count<=0)
{
count=0;
}
lcd.clear();
lcd.print("Person In Room:");
lcd.setCursor(0,1);
lcd.print(count);
delay(1000);
}
void setup()
{
lcd.begin(16,2);
lcd.print("Visitor Counter");
delay(2000);
pinMode(in, INPUT);
pinMode(out, INPUT);
pinMode(relay, OUTPUT);
lcd.clear();
lcd.print("Person In Room:");
lcd.setCursor(0,1);
lcd.print(count);
}
void loop()
{

if(digitalRead(in))
IN();
if(digitalRead(out))
OUT();

if(count<=0)
{
lcd.clear();
digitalWrite(relay, LOW);
lcd.clear();
lcd.print("Nobody In Room");
lcd.setCursor(0,1);
lcd.print("Light Is Off");
delay(200);
}
else
digitalWrite(relay, HIGH);

5) Arduino a Neonate Incubator Approach


COMPONENTS AND SUPPLIES

Arduino Nano R3
× 1

ABOUT THIS PROJECT

This project is an aproach to understand how neonate


incubator works. !!WARNING!! IT IS NOT
SUPOUSED TO TAKE CARE OF ANY KIND OF
LIFE, the purpose here is to understand the basics and
get your project as better as possible, and of course
have fun with it!!
This was made to represent the idea of low cost
medical devices for a diploma work.
The main goal of this incubator is to mantain the
temperature between a max and min temperature
range, this temperature range can be managed with a
5-button control. The airflow is created with help of
two fans that keep air flowing (two fans works at
small velocity but one of them has an increased
velocity switch in case of overwarming airflow), a
ceramic warmer, a servo motor to open and close a
gate that lets overwarmed air to flow outside the
system, temperature and humidity sensors, a power
supply and of course, our good Arduino Nano.
An upside view of the system
Here is the ceramic warmer, some sensors and the
servo controlled gate
Here you can see the place in which the air is warmed,
a Lm35 temperature sensor is in the top of the box
This project will be divided in several small projects
in order to explain how to build each specific part that
need special attention as the power controller and the
button controller.

SCHEMATICS

Simplified diagram
This diagram content the following:
1. 220V cable
2. Power source 220v to 24V @ 4A
3. Arduino Nano
4. I2C 20x4 LCD
5. Power controller for fans and warmer
6. 5-button control
7. Ceramic warmer
8. Lm 35 temperature sensor
9. DHT22 humidity and temperature sensor
10. 12V computer fan
11. Small servo motor.
12. Big plastic box
Arduino diagram
The Arduino connections to peripherals.
Power management
The two independent lines were made experimentally
to check if the helped to avoid some noises, but they
did not :) So you can use just one.

Amplification stages and voltage follower


Voltage follower is used to have better signal from
thermistors and the OpAmps to expand the Lm35
readable range in Arduino
5-button module
Here is a simple 5-button controller
Power control of fans and ceramic warmer
CODE

#include <LCD.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SimpleDHT.h>
#include "RTClib.h"
#include <dht.h>
#include <Servo.h>

Servo myservo;

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); //Set the


LCD I2C address

//Digitals
const int pin1DHT22 = 2; //Sensor humedad 1
const int Warmer = 3; //Relay 3
const int Fan_1 = 6; //Relay 6 // Fan High
const int buzzer = 4; //Piezo sounder
const int button1 = 9;
const int button2 = 10;
const int button3 = 11;
const int button4 = 12;
const int button5 = 13;

//Analogs
const int inPinTh_1 = A1; //Termistor 2
const int tempPin_1 = A2; //lm35_1
const int tempPin_2 = A3; //lm35_2

SimpleDHT22 dht22_1;
RTC_DS1307 RTC;
int temp_1, temp_2, DHT22Temp_1;
int errorSense_1, errorSense_2, count_1, count_2, count_3 = 0;

int menuScreen, menuScreenUseAlarm, menuScreenMode,


menuScreenTempAlarm, menuScreenTemp, menuScreenHumid, mode,
modeAlarm, manualSettings = 0;
bool back, next, select, up, down = 0;

float Temp1_Neonate, Temp2_Neonate, averageTemp_Neonate, lm35_1,


lm35_2, coefWarmer, midleRangeTemp = 0;
int pursuedHigherT = 373;
int pursuedLowerT = 365;

float upperTemp = 35;


float lowerTemp = 34;
float lowerTempComp = 0;

float upperTempAlarm = 37.5;


float lowerTempAlarm = 36.5;
float lowerTempCompAlarm = 0;

unsigned long currentMillis;


unsigned long previousMillis = 0; // last time update
long interval = 1000; // interval at which to do something (milliseconds)

unsigned long currentMillis_1;


unsigned long previousMillis_1 = 0; // last time update
long interval_1 = 2000; // interval at which to do something (milliseconds)

void setup()
{
myservo.attach(1);
myservo.write(122); //Para flujo sobrecalentado
delay(250);
myservo.write(70); //Flujo normal
delay(250);
myservo.write(122);
delay(250);
myservo.write(70);
Wire.begin();
RTC.begin();
pinMode(Fan_1, OUTPUT);
pinMode(Warmer, OUTPUT);
pinMode(back, INPUT);
pinMode(next, INPUT);
pinMode(select, INPUT);
pinMode(up, INPUT);
pinMode(down, INPUT);

pinMode(buzzer, OUTPUT);
digitalWrite(buzzer, LOW);

digitalWrite(Fan_1, LOW);
digitalWrite(Warmer, LOW);

lcd.begin(20, 4); // initialize the lcd for 20 chars 4 lines and turn on
backlight
lcd.backlight();
menuScreen_0();
menuScreen_1();
RTC.adjust(DateTime(__DATE__, __TIME__));
// Check to see if the RTC is keeping time. If it is, load the time from your
computer.
if (! RTC.isrunning()) {
lcd.print("Change clock battery");
// This will reflect the time that your sketch was compiled
RTC.adjust(DateTime(__DATE__, __TIME__));
}
}

void loop()
{
currentMillis = millis();
buttonState();

switch (menuScreen) {
case 0:
menuScreen_UseAlarm();
break;
case 1:
menuScreen_SetAlarm();
break;
case 2:
menuScreen_Mode();
break;
case 3:
Screen_Auto_intro();
break;
case 4:
menuScreen_Temp();
break;
case 5:
Alarms();
currentMillis = millis();
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
Screen_Auto();
}
break;
case 6:
Alarms();
currentMillis = millis();
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
Screen_Manual();
}
break;
}

void mainScreen()
{
currentMillis_1 = millis();

lcd.setCursor(0, 0);
lcd.print("Baby T "); lcd.print(averageTemp(), 1); lcd.print((char)223);
//lcd.print("C");
lcd.setCursor(13, 0);
lcd.print("WarmerT");
lcd.setCursor(0, 1);
lcd.print("Case T "); lcd.print(templm35_1(), 1); lcd.print((char)223); //
Temp case lm35 1
lcd.setCursor(14, 1);
lcd.print(templm35_2(), 1); lcd.print((char)223); // Temp warmer lm35 2
lcd.setCursor(0, 2);
lcd.print("Cham T ");
if (currentMillis_1 - previousMillis_1 > interval_1) { // Importante para dar
ciclo de espera a los sensores de humidificacion
previousMillis_1 = currentMillis_1; lcd.print(DHT22TempRead_1(), 1);
lcd.print((char)223);
}
lcd.setCursor(0, 3);
lcd.print("Man. mode");
RelojParaPantallaSerial();

void RelojParaPantallaSerial()
{
DateTime now = RTC.now();
lcd.setCursor(12, 3);
if (now.hour() < 10 ) {
lcd.print("0");
lcd.print(now.hour(), DEC);
}
else {
lcd.print(now.hour(), DEC);
}
lcd.print(':');
if (now.minute() < 10) {
lcd.print("0");
lcd.print(now.minute(), DEC);
}
else {
lcd.print(now.minute(), DEC);
}
lcd.print(':');
if (now.second() < 10) {
lcd.print("0");
lcd.print(now.second());
}
else {
lcd.print(now.second(), DEC);
}
}

void DHT22Sensor_1() // DHT22 sampling rate is 0.5HZ.


{
count_1 ++;
if (count_1 > 1) { //Sets counting of 2 seconds
count_1 = 0;
byte temperature_1 = 0;
byte humidity_1 = 0;
int err_1 = dht22_1.read(pin1DHT22, &temperature_1, &humidity_1,
NULL);
if (err_1 != SimpleDHTErrSuccess) {
errorSense_1 ++;
if (errorSense_1 > 2) { // Here we set the number of errors allowed untill
display an error
lcd.setCursor(10, 2);
lcd.print("Error"); lcd.print(err_1); delay(1000);
return;
}
return;
}
errorSense_1 = 0; // Reset the counter if the errors in a row are not
higher than errors allowed untill display an error
DHT22Temp_1 = ((int)temperature_1);
count_1 = 0;
}
}
int DHT22TempRead_1()
{
DHT22Sensor_1();
return DHT22Temp_1;
}

float temperature_Neonate() // CREAR ERROR DE TEMP


{
float val1 = 0;
for (int i = 0; i < 5; i++) {
val1 = val1 + analogRead(inPinTh_1);
delay(2);
}
Temp2_Neonate = val1 / 5;
return Temp2_Neonate;
}

float templm35_1()
{
float val2 = 0;
for (int i = 0; i < 5; i++) {
val2 = val2 + analogRead(tempPin_1);
delay(2);
}
lm35_1 = val2 / 5;
lm35_1 = mapf(lm35_1, 284.5, 323, 30, 37);
return lm35_1;
}

float templm35_2()
{
float val3 = 0;
for (int i = 0; i < 5; i++) {
val3 = val3 + analogRead(tempPin_2);
delay(2);
}
lm35_2 = val3 / 5;
lm35_2 = mapf(lm35_2, 284.5, 323, 30, 37);
return lm35_2;
}

double mapf(double x, double in_min, double in_max, double out_min,


double out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

float averageTemp() // Average was with two thermometers


{
averageTemp_Neonate = temperature_Neonate();
averageTemp_Neonate = mapf(averageTemp_Neonate, 284.5, 323, 30, 37);
return averageTemp_Neonate;
}

int int_templm35_1()
{
int intlm35_1 = templm35_1();
return intlm35_1;
}

int int_tempcase()
{
int int_templm35_1_0 = templm35_1() * 10;
return int_templm35_1_0;
}

int int_templm35_2()
{
int intlm35_2 = templm35_2();
return intlm35_2;
}

int int_templm35_2_0()
{
int int_templm35_2_0 = templm35_2() * 10;
return int_templm35_2_0;
}
////////////////////////////////////////////////////

void menuScreen_0 ()
{
lcd.setCursor(0, 1);
lcd.print(" The Baby Warmer.");
delay(1000);
lcd.setCursor(0, 3);
lcd.print("Welcome!");
delay(500);
lcd.setCursor(15, 3);
lcd.print("V 1.3");
delay(1000);
lcd.clear();
}

void menuScreen_1()
{
lcd.setCursor(0, 0);
lcd.print("The following menu");
lcd.setCursor(0, 1);
lcd.print("will help you to set");
lcd.setCursor(0, 2);
lcd.print("the incubator system");
delay(3000);
lcd.clear();
}

void menuScreen_UseAlarm()
{
switch (menuScreenUseAlarm) {
case 0:
lcd.setCursor(0, 0);
lcd.print("Activate neonate");
lcd.setCursor(0, 1);
lcd.print("temp. alarm?");
if (modeAlarm == 0) {
lcd.setCursor(0, 2);
lcd.print("->");
}
else if (modeAlarm == 1) {
lcd.setCursor(0, 3);
lcd.print("->");
}
lcd.setCursor(2, 2);
lcd.print("No");
lcd.setCursor(2, 3);
lcd.print("Yes");
if (back) {
back = 0;
}
else if (next) {
if (modeAlarm == 0) {
menuScreen = 2;
}
else if (modeAlarm == 1) {
menuScreen = 1;
}
lcd.clear();
delay(500);
next = 0;
}
else if (select) {
if (modeAlarm == 0) {
menuScreen = 2;
}
else if (modeAlarm == 1) {
menuScreen = 1;
}
lcd.clear();
delay(500);
select = 0;
}
else if (up) {
modeAlarm = modeAlarm - 1;
if (modeAlarm < 0) {
modeAlarm = 1;
}
delay(100);
lcd.setCursor(0, 2);
lcd.print(" ");
lcd.setCursor(0, 3);
lcd.print(" ");
up = 0;
}
else if (down) {
modeAlarm = modeAlarm + 1;
if (modeAlarm > 1) {
modeAlarm = 0;
}
delay(100);
lcd.setCursor(0, 2);
lcd.print(" ");
lcd.setCursor(0, 3);
lcd.print(" ");
down = 0;
}
break;
}
}

void menuScreen_SetAlarm()
{
switch (menuScreenTempAlarm) {
case 0:
lcd.setCursor(0, 0);
lcd.print("Set the upper range");
lcd.setCursor(0, 1);
lcd.print("T=");
lcd.setCursor(3, 1);
lcd.print(upperTempAlarm, 1);
lcd.print((char)223);
lcd.print("C");
lcd.setCursor(0, 2);
lcd.print("Press select to");
lcd.setCursor(0, 3);
lcd.print("continue...");
if (back) {
back = 0;
lcd.clear();
delay(500);
menuScreen = 0;
}
else if (next) {
lowerTempCompAlarm = upperTempAlarm - 0.5;
lowerTempAlarm = upperTempAlarm - 0.5;
menuScreenTempAlarm = 1;
lcd.clear();
delay(500);
next = 0;
}
else if (select) {
lowerTempCompAlarm = upperTempAlarm - 0.5;
lowerTempAlarm = upperTempAlarm - 0.5;
menuScreenTempAlarm = 1;
lcd.clear();
delay(500);
select = 0;
}
else if (up) {
if (int_upperTempAlarm() >= 375) {
upperTempAlarm = 37.5;
lcd.setCursor(9, 1);
lcd.print(" MAX TEMP");
delay(1000);
lcd.setCursor(9, 1);
lcd.print(" ");
return;
}
upperTempAlarm = upperTempAlarm + 0.1;
lcd.setCursor(3, 1);
lcd.print(upperTempAlarm, 1);
up = 0;
}
else if (down) {
if (int_upperTempAlarm() <= 320) {
upperTempAlarm = 32;
lcd.setCursor(10, 1);
lcd.print("MIN RANGE");
delay(1000);
lcd.setCursor(9, 1);
lcd.print(" ");
return;
}
upperTempAlarm = upperTempAlarm - 0.1;
lcd.setCursor(3, 1);
lcd.print(upperTempAlarm, 1);
down = 0;
}
break;

case 1:
lcd.setCursor(0, 0);
lcd.print("Set the lower range");
lcd.setCursor(0, 1);
lcd.print("T=");
lcd.setCursor(3, 1);
lcd.print(lowerTempAlarm, 1);
lcd.print((char)223);
lcd.print("C");
lcd.setCursor(0, 2);
lcd.print("Press select to");
lcd.setCursor(0, 3);
lcd.print("continue...");

if (back) {
menuScreenTempAlarm = 0;
lcd.clear();
delay(200);
back = 0;
}
else if (next) {
menuScreenTempAlarm = 2;
next = 0;
lcd.clear();
delay(500);
}
else if (select) {
menuScreenTempAlarm = 2;
select = 0;
lcd.clear();
delay(500);
}
else if (up) {
if (int_lowerTempAlarm() >= (int_upperTempAlarm() - 5)) {
lowerTempAlarm = lowerTempCompAlarm;
lcd.setCursor(9, 1);
lcd.print(" MIN RANGE");
delay(1000);
lcd.setCursor(9, 1);
lcd.print(" ");
return;
}
lowerTempAlarm = lowerTempAlarm + 0.1;
lcd.setCursor(3, 1);
lcd.print(lowerTempAlarm, 1);
up = 0;
}
else if (down) {
if (int_lowerTempAlarm() <= 280) {
lowerTempAlarm = 28;
lcd.setCursor(10, 1);
lcd.print("MIN TEMP");
delay(1000);
lcd.setCursor(9, 1);
lcd.print(" ");
return;
}
lowerTempAlarm = lowerTempAlarm - 0.1;
lcd.setCursor(3, 1);
lcd.print(lowerTempAlarm, 1);
down = 0;
}
break;

case 2:
lcd.setCursor(0, 0);
lcd.print("Upper limit: ");
lcd.setCursor(0, 1);
lcd.print("T=");
lcd.setCursor(3, 1);
lcd.print(upperTempAlarm, 1);
lcd.print((char)223);
lcd.print("C");
lcd.setCursor(0, 2);
lcd.print("Lower limit:");
lcd.setCursor(0, 3);
lcd.print("T=");
lcd.setCursor(3, 3);
lcd.print(lowerTempAlarm, 1);
lcd.print((char)223);
lcd.print("C");
lcd.setCursor(9, 3);
lcd.print(" Continue?");
if (back) {
menuScreenTempAlarm = 1;
lcd.clear();
delay(200);
back = 0;
}
else if (next) {
menuScreen = 2;
next = 0;
lcd.clear();
delay(500);
}
else if (select) {
menuScreen = 2;
select = 0;
lcd.clear();
delay(500);
}
else if (up) {
up = 0;
}
else if (down) {
down = 0;
}
}

void menuScreen_Mode()
{
switch (menuScreenMode) {
case 0:
lcd.setCursor(0, 0);
lcd.print("Select the mode:");

if (mode == 0) {
lcd.setCursor(0, 2);
lcd.print("->");
}
else if (mode == 1) {
lcd.setCursor(0, 3);
lcd.print("->");
}
lcd.setCursor(2, 2);
lcd.print("Skin mode aut.");
lcd.setCursor(2, 3);
lcd.print("Temp setting man.");
if (back) {
back = 0;
lcd.clear();
delay(500);
menuScreenTempAlarm = 0;
menuScreen = 0;
}
else if (next) {
if (mode == 0) {
menuScreen = 3;
}
else if (mode == 1) {
menuScreen = 4;
}
lcd.clear();
delay(500);
next = 0;
}
else if (select) {
if (mode == 0) {
menuScreen = 3;
}
else if (mode == 1) {
menuScreen = 4;
}
lcd.clear();
delay(500);
select = 0;
}
else if (up) {
mode = mode - 1;
if (mode < 0) {
mode = 1;
}
delay(100);
lcd.setCursor(0, 2);
lcd.print(" ");
lcd.setCursor(0, 3);
lcd.print(" ");
up = 0;
}
else if (down) {
mode = mode + 1;
if (mode > 1) {
mode = 0;
}
delay(100);
lcd.setCursor(0, 2);
lcd.print(" ");
lcd.setCursor(0, 3);
lcd.print(" ");
down = 0;
}
break;
}
}

void Screen_Auto_intro()
{
lcd.setCursor(0, 0);
lcd.print("This mode will try");
lcd.setCursor(0, 1);
lcd.print("to stabilize the");
lcd.setCursor(0, 2);
lcd.print("neonate temperature");
lcd.setCursor(0, 3);
lcd.print("between 36.5 & 37.3");
delay(3000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("The supervision of");
lcd.setCursor(0, 1);
lcd.print("the neonate is ");
lcd.setCursor(0, 2);
lcd.print("mandatory at small");
lcd.setCursor(0, 3);
lcd.print("lapses. 5~10 mins");
delay(3000);
lcd.clear();
menuScreen = 5;
}

void menuScreen_Temp()
{

switch (menuScreenTemp) {
case 0:
lcd.setCursor(0, 0);
lcd.print("Set the upper range");
lcd.setCursor(0, 1);
lcd.print("T=");
lcd.setCursor(3, 1);
lcd.print(upperTemp, 1);
lcd.print((char)223);
lcd.print("C");
lcd.setCursor(0, 2);
lcd.print("Press select to");
lcd.setCursor(0, 3);
lcd.print("continue...");
if (back) {
back = 0;
menuScreen = 0;
}
else if (next) {
lowerTempComp = upperTemp - 1;
lowerTemp = upperTemp - 1;
menuScreenTemp = 1;
lcd.clear();
delay(500);
next = 0;
}
else if (select) {
lowerTempComp = upperTemp - 1;
lowerTemp = upperTemp - 1;
menuScreenTemp = 1;
lcd.clear();
delay(500);
select = 0;
}
else if (up) {
if (int_upperTemp() >= 370) {
upperTemp = 37;
lcd.setCursor(9, 1);
lcd.print(" MAX TEMP");
delay(1000);
lcd.setCursor(9, 1);
lcd.print(" ");
return;
}
upperTemp = upperTemp + 0.1;
lcd.setCursor(3, 1);
lcd.print(upperTemp, 1);
up = 0;
}
else if (down) {
if (int_upperTemp() <= 310) {
upperTemp = 31;
lcd.setCursor(10, 1);
lcd.print("MIN RANGE");
delay(1000);
lcd.setCursor(9, 1);
lcd.print(" ");
return;
}
upperTemp = upperTemp - 0.1;
lcd.setCursor(3, 1);
lcd.print(upperTemp, 1);
down = 0;
}
break;

case 1:
lcd.setCursor(0, 0);
lcd.print("Set the lower range");
lcd.setCursor(0, 1);
lcd.print("T=");
lcd.setCursor(3, 1);
lcd.print(lowerTemp, 1);
lcd.print((char)223);
lcd.print("C");
lcd.setCursor(0, 2);
lcd.print("Press select to");
lcd.setCursor(0, 3);
lcd.print("continue...");
if (back) {
menuScreenTemp = 0;
lcd.clear();
delay(200);
back = 0;
}
else if (next) {
menuScreenTemp = 2;
next = 0;
lcd.clear();
delay(500);
}
else if (select) {
menuScreenTemp = 2;
select = 0;
lcd.clear();
delay(500);
}
else if (up) {
if (int_lowerTemp() >= (int_upperTemp() - 10)) {
lowerTemp = lowerTempComp;
lcd.setCursor(9, 1);
lcd.print(" MIN RANGE");
delay(1000);
lcd.setCursor(9, 1);
lcd.print(" ");
return;
}
lowerTemp = lowerTemp + 0.1;
lcd.setCursor(3, 1);
lcd.print(lowerTemp, 1);
up = 0;
}
else if (down) {
if (int_lowerTemp() <= 300) {
lowerTemp = 30;
lcd.setCursor(10, 1);
lcd.print("MIN TEMP");
delay(1000);
lcd.setCursor(9, 1);
lcd.print(" ");
return;
}
lowerTemp = lowerTemp - 0.1;
lcd.setCursor(3, 1);
lcd.print(lowerTemp, 1);
down = 0;
}
break;

case 2:
lcd.setCursor(0, 0);
lcd.print("Upper limit: ");
lcd.setCursor(0, 1);
lcd.print("T=");
lcd.setCursor(3, 1);
lcd.print(upperTemp, 1);
lcd.print((char)223);
lcd.print("C");
lcd.setCursor(0, 2);
lcd.print("Lower limit:");
lcd.setCursor(0, 3);
lcd.print("T=");
lcd.setCursor(3, 3);
lcd.print(lowerTemp, 1);
lcd.print((char)223);
lcd.print("C");
lcd.setCursor(9, 3);
lcd.print(" Continue?");
if (back) {
menuScreenTemp = 1;
lcd.clear();
delay(200);
back = 0;
}
else if (next) {
menuScreen = 6;
next = 0;
lcd.clear();
delay(500);
}
else if (select) {
menuScreen = 6;
select = 0;
lcd.clear();
delay(500);
}
else if (up) {
up = 0;
}
else if (down) {
down = 0;
}
}

void Screen_Auto() {
Screen_Auto_S();
warmerParameters_Auto();
}

void Screen_Auto_S()
{
currentMillis_1 = millis();

lcd.setCursor(0, 0);
lcd.print("Baby T "); lcd.print(averageTemp(), 1); lcd.print((char)223);
//lcd.print("C");
lcd.setCursor(13, 0);
lcd.print("WarmerT");
lcd.setCursor(0, 1);
lcd.print("Case T "); lcd.print(templm35_1(), 1); lcd.print((char)223); //
Temp case lm35 1
lcd.setCursor(14, 1);
lcd.print(templm35_2(), 1); lcd.print((char)223); // Temp warmer lm35 2
lcd.setCursor(0, 2);
lcd.print("Purs Baby T ");
lcd.print("37.3"); lcd.print((char)223);
lcd.setCursor(0, 3);
lcd.print("Aut. mode");
RelojParaPantallaSerial();

void Screen_Manual()
{
mainScreen();
warmerParameters_Manual();
}

void warmerParameters_Auto()
{
switch (manualSettings) {
case 0:
if (int_tempcase() <= int_lowerTemp()) {
digitalWrite(Warmer, HIGH);
}
else if (int_tempcase() > int_lowerTemp()) {
manualSettings++;
digitalWrite(Warmer, LOW);
}

case 1:
if (int_tempcase() <= pursuedLowerT) {
digitalWrite(Warmer, HIGH);
delay(400);
digitalWrite(Warmer, LOW);
delay(300);
}
else if (int_tempcase() >= pursuedHigherT) {
digitalWrite(Warmer, LOW);
digitalWrite(Fan_1, HIGH);
myservo.write(122); //Para flujo sobrecalentado
delay(2500); //Variable de tiempo de
enfriamiento, a mas tiempo, mas frio
digitalWrite(Fan_1, LOW);
myservo.write(70);
delay(1000);
}
}
}

void warmerParameters_Manual()
{
switch (manualSettings) {
case 0:
if (int_tempcase() <= int_lowerTemp()) {
digitalWrite(Warmer, HIGH);

}
else if (int_tempcase() > int_lowerTemp()) {
manualSettings++;
digitalWrite(Warmer, LOW);
}

case 1:
if (int_tempcase() <= int_upperTemp()) {
digitalWrite(Warmer, HIGH);
delay(400);
digitalWrite(Warmer, LOW);
delay(300);
}
else if (int_tempcase() >= int_upperTemp()) {
digitalWrite(Warmer, LOW);
digitalWrite(Fan_1, HIGH);
myservo.write(122); //Para flujo sobrecalentado
delay(2500); //Variable de tiempo de
enfriamiento, a mas tiempo, mas frio
digitalWrite(Fan_1, LOW);
myservo.write(70);
delay(1000);
}
}
}

void Alarms()
{
if (modeAlarm == 1)
{
if (averageTemp() < lowerTempAlarm || averageTemp() >
upperTempAlarm)
{
digitalWrite(buzzer, HIGH);
delay(150);
digitalWrite(buzzer, LOW);
delay(100);

}
}
else {
digitalWrite(buzzer, LOW);
}
}

void buttonState()
{
back = digitalRead(button1);
next = digitalRead(button2);
select = digitalRead(button3);
up = digitalRead(button4);
down = digitalRead(button5);

if (back == HIGH) {
delay(150);
}

if (next == HIGH) {
delay(150);
}
if (select == HIGH) {
delay(150);
}

if (up == HIGH) {
delay(150);
}

if (down == HIGH) {
delay(150);
}
}

int int_upperTemp()
{
int int_upperTemp = upperTemp * 10;
return int_upperTemp;
}

int int_lowerTemp()
{
int int_lowerTemp = lowerTemp * 10;
return int_lowerTemp;
}

int int_midleRangeTemp()
{
int int_midleRangeTemp = midleRangeTemp * 10;
return int_midleRangeTemp;
}

int int_coefWarmer()
{
int int_coefWarmer = coefWarmer * 10;
return int_coefWarmer;
}

int int_upperTempAlarm()
{
int int_upperTempAlarm = upperTempAlarm * 10;
return int_upperTempAlarm;
}

int int_lowerTempAlarm()
{
int int_lowerTempAlarm = lowerTempAlarm * 10;
return int_lowerTempAlarm;
}
6) Arduino Customizable Geiger Muller Counter
COMPONENTS AND SUPPLIES

Arduino UNO & Genuino UNO


Can be any arduino device, × 1
does not have to be UNO

DC-DC 1.5-3V to 300-400V × 1


380V High Voltage Boost Step-
up Voltage Inverter Module
Ideal final voltage is 400V, but
can be from 350-450V (the
power range of the GM tube).
STS-5 Geiger Muller Tube
I found mine on ebay (less
expensive). Be aware that you
× 1
will likely have to buy from the
Ukraine and it won't arrive for
probably 2-3 weeks.
SunFounder IIC I2C TWI Serial
2004 20x4 LCD Module Shield
for Arduino Uno Mega2560
Flexibility on the unit. I used
× 1
this LED display as had fewer
wires involved going into it.
Get a 20x4 and you will be
fine.
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)
Needed to create device matching to
circuit board. Also required to solder the
capacitor to the voltage transformer.
Breadboard, 270 Pin
My final project employed a solderable
self-assembled circuit board, but if one is
interested in a less permanent project, I
found this to work as well.

ABOUT THIS PROJECT

AS NOTED BY THE WORK OF ADNOVEA, THIS


DEVICE USES HIGH VOLTAGES (400 V) THAT
ARE DANGEROUS. WHILE CURRENTS ARE
LOW, ANY AMOUNT OF CURRENT OR
VOLTAGE INTRODUCED TO THE HUMAN BODY
CAN INDUCE AN ARRHYTHMIA IN THE HEART
THAT CAN STOP IT AND LEAD TO DEATH.
PEOPLE WHO BUILD THIS PRODUCT SHOULD
HAVE SOME EXPERIENCE WITH ELECTRONICS
AND BE EXTREMELY MINDFUL OF
APPROPRIATE SAFETY PRECAUTIONS WHILE
USING THE HIGH VOLTAGE ASPECT OF THE
CIRCUIT.
My goal was to take the work of AdNovea and create
a Geiger Muller counter that I had more freedom to
program as I desired (the AdNovea work employed
scripts that I was unable to find the appropriate
program to modify). This would permit a user to both
better understand the physics of the tube, but also
create such a device that meets their project
desires/needs.
For the project, I simplified the circuit diagram from
AdNovea to make something more for what I was
looking for: a personal counter that shows the counts,
but not getting too complicated with ethernet
connections and connection to national networks. I
experimented with Bluetooth modules and buzzers and
these can work with it, though I chose not to use them
as I wanted more of a background radiation counter I
could refer to when I wanted.
The construction is very straight forward (refer to
circuit diagram). The only difficult aspects of this
project was obtaining some of the parts (the GM tube
and the high voltage converter). I purchased both of
these items for little money on Ebay, but both were
being sold from far away (the Ukraine and China
respectively) so it took 3-4 weeks to receive the items.
I started with assembling the circuit on a bread board
to best evaluate the circuit and where I could
manipulate it to my desires. I assembled it per
AdNovea's diagram, but left out the buzzer, ethernet
module, and resistor leading to the GM tube (I was not
getting sufficient current to the tube with that circuit
design that prevented it from working). I then soldered
it all onto a circuit board.

I have an Arduino uno cited here as what I used, but


you could probably save space in a container by using
a nano. I used electrical tape to attach the GM tube to
the circuit board to save space as well as to cover the
terminals on the voltage transformer to improve
safety. As I have limited equipment to play around and
drill holes with a plastic container to make something
pretty like what AdNovea had, I used the cardboard
box that I was given when I first purchased my
Arduino circuit kit.

I did cut a hole in the top of the box so the LED


display could fit snugly in there (and I further
reinforced this with tape).
I also cut a hole in the side of the box to permit a USB
cord to come in and power the device.
I attempted 9V batteries to start, but as expected, the
batteries did not last long. Finally I put additional
electric tape around the box/circuit board as needed at
points where the circuit may come in contact with the
cardboard to protect against fire and losing signal.
The program I have designed for my project takes the
counts collected by the GM tube every 30 seconds
multiplied by 2 to provide an estimated counts per
minute (measuring unit of GM tubes). I then used
metric system conversions to report uSv/hr that is a
more widely used reference measurement. As the
device continues to run through this code, I had it
report the average of the measurements that
progressively were collected along with the standard
error (SD / sqrt(n)). Statistically I chose standard error
as ultimately what is collected is a sample from the
mean background radiation levels making SE the more
appropriate measure. Unfortunately due to the
memory limitations of the Arduino, I was only able to
create an array of measurements of 100 items

SCHEMATICS
CODE

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
unsigned long counts; //variable for GM Tube events
unsigned long previousMillis; //variable for measuring time
float averageCPM;
float sdCPM;
int currentCPM;
float calcCPM;
LiquidCrystal_I2C lcd(0x27, 20, 4);
float CPMArray[100];

#define LOG_PERIOD 30000 // count rate (in milliseconds)

void setup() { //setup


counts = 0;
currentCPM = 0;
averageCPM = 0;
sdCPM = 0;
calcCPM = 0;
lcd.init();
lcd.backlight();
Serial.begin(9600);
pinMode(2, INPUT);
attachInterrupt(digitalPinToInterrupt(2), impulse, FALLING); //define
external interrupts
}

void loop() { //main cycle


lcd.setCursor(0,2);
lcd.print("CPM Count: ");
lcd.print(counts);
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > LOG_PERIOD) {
previousMillis = currentMillis;
CPMArray[currentCPM] = counts * 2;
lcd.clear();
lcd.setCursor(0,0);
lcd.print("uSv/hr: ");
lcd.print(outputSieverts(CPMArray[currentCPM]));
counts = 0;
averageCPM = 0;
sdCPM = 0;
//calc avg and sd
for (int x=0;x<currentCPM+1;x++) {
averageCPM = averageCPM + CPMArray[x];
}
averageCPM = averageCPM / (currentCPM + 1);
for (int x=0;x<currentCPM+1;x++) {
sdCPM = sdCPM + sq(CPMArray[x] - averageCPM);
}
sdCPM = sqrt(sdCPM / currentCPM) / sqrt(currentCPM+1);

Serial.println("Avg: " + String(averageCPM) + " +/- " + String(sdCPM) + "


ArrayVal: " + String(CPMArray[currentCPM]));
currentCPM = currentCPM + 1;
displayAverageCPM();
}
}

void impulse() {
counts++;
}
void displayAverageCPM() {
lcd.setCursor(0,1);
lcd.print("Avg: ");
lcd.print(outputSieverts(averageCPM));
lcd.print("+/-");
lcd.print(outputSieverts(sdCPM));
}
float outputSieverts(float x) {
float y = x * 0.0057;
return y;
}
7) Arduino WKR1000 Weather Station
COMPONENTS AND SUPPLIES

Arduino MKR1000
× 1

Adafruit TSL2561 Luminosity


Sensor × 1

Adafruit BMP180 Barometric


Pressure/Temperature × 1

OLED display I2C


× 1

SparkFun Level Shifter Board


× 1

Sharp GP2Y1010AU0F
× 1

Soil Moisture Sensor × 1


Breadboard (generic)
× 1

Jumper wires (generic)


× 1
APPS AND ONLINE SERVICES
Arduino IDE

myDevices Cayenne

ABOUT THIS PROJECT


The OLED display shows the temperature, pressure and
dust. The Arduino MKR1000 is connected to the
Cayenne over MQTT.
Connecting the Arduino MKR1000 to Cayenne:
Add new: Device/Widget
Bring Your Own Thing
Add code to Username, Password and Client ID
Add code to SSID and Password from your Wi-Fi
Upload code to the Arduino MKR1000
Wait for board to connect
Add Widgets:
Add new: Device/Widget
Custom Widgets
Select a widget that you need
Enter the name of the widget
Select device, Virtual Pin, Pin number
Select Data, Unit, Icon
Add Widget

SCHEMATICS
CODE

#define CAYENNE_PRINT Serial // Comment this out to disable prints and


save space
#include <CayenneMQTTMKR1000.h>

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_BMP085_U.h>
#include <Adafruit_TSL2561_U.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#define BAROMETER_PIN V1
#define TEMPERATURE_PIN V2
#define LIGHT_PIN V3
#define DUST_PIN V4
#define MOISTURE_PIN V5

float temperature;
float pressure;
float voltage;
int moisture;

int measuringPin = A1;


int ledPin = 2;
const int timeMeasuring = 280;
const int timeStabilization = 40;
const int timeSleep = 9680;
float voltageAnalog = 0;
float voltageConversion = 0;
float dustiness = 0;
Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10180);
const int address = TSL2561_ADDR_FLOAT;
Adafruit_TSL2561_Unified tsl = Adafruit_TSL2561_Unified(address,
12345);

// WiFi network info.


char ssid[] = "SSID";
char wifiPassword[] = "Password";

// Cayenne authentication info. This should be obtained from the Cayenne


Dashboard.
char username[] = "Username";
char password[] = "Password";
char clientID[] = "ClientID";

unsigned long lastMillis = 0;

void setup()
{
Serial.begin(9600);
Cayenne.begin(username, password, clientID, ssid, wifiPassword);
pinMode(ledPin,OUTPUT);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
if (!bmp.begin())
{
CAYENNE_LOG("No BMP sensor detected");
while (1);
}
if (!tsl.begin())
{
CAYENNE_LOG("No TSL2561 detected");
while (1);
}

tsl.enableAutoRange(true);
/* Changing the integration time gives you better sensor resolution (402ms
= 16-bit data) */
tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS); /* fast
but low resolution */
// tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS); /*
medium resolution and speed */
// tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS); /* 16-
bit data but slowest conversions */
}

void loop()
{
Cayenne.loop();

//Publish data every 10 seconds (10000 milliseconds). Change this value to


publish at a different interval.
if (millis() - lastMillis > 10000) {
lastMillis = millis();
//Write data to Cayenne here. This example just sends the current uptime in
milliseconds.
Cayenne.virtualWrite(0, lastMillis);

sensors_event_t event;
tsl.getEvent(&event);
bmp.getPressure(&pressure);
bmp.getTemperature(&temperature);

digitalWrite(ledPin,LOW);
delayMicroseconds(timeMeasuring);
voltageAnalog = analogRead(measuringPin);
delayMicroseconds(timeStabilization);
digitalWrite(ledPin,HIGH);
delayMicroseconds(timeSleep);

voltageConversion = voltageAnalog * 2 * (3,3 / 1024.0);


dustiness = (0.17 * voltageConversion - 0.1)*1000;

moisture = analogRead(A2);
Cayenne.luxWrite(LIGHT_PIN, event.light);
Cayenne.hectoPascalWrite(BAROMETER_PIN, pressure);
Cayenne.celsiusWrite(TEMPERATURE_PIN, temperature);
Cayenne.virtualWrite(DUST_PIN, dustiness);
Cayenne.virtualWrite(MOISTURE_PIN, map(moisture, 1023, 0, 0, 100));

}
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.println(temperature);
display.setCursor(40, 0);
display.println("C");
display.setCursor(0, 10);
display.println(pressure);
display.setCursor(55, 10);
display.println("Pa");
display.setCursor(0, 20);
display.println(dustiness);
display.setCursor(45, 20);
display.println("ug/m3");
display.display();

}
8) Arduino Due TIC TAC TOE with Touchscreen

COMPONENTS AND SUPPLIES


Arduino Due
× 1

2,8 zoll TFT LCD with × 1


touchscreen
Jumper wires (generic)
× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

About
Hello, I want to share my work on the project from
nickthegreek82: arduino-touch-tic-tac-toe-game.
You need:
the Adafruit Library
the GFX Library
and the URTouch Library
Wiring
The wiring is as following for the touch-screen:
Touch -> Arduino Due
T_IRQ -> 22
T_DO -> 24
T_DIN -> 26
T_CS -> 28
T_CLK -> 30
For the display:
Display -> Arduino Due
SDO -> A.25
LED -> 3.3V
SCK -> A.27
SDI -> A.26
DC -> 9
RESET -> 8
CS -> 10
GND -> GND
VCC -> 3.3V

SCHEMATICS
CODE

/////////////////////////////////////////////
// 2.8" TOUCH SCREEN TIC TAC TOE //
// //
// //
// //
// //
/////////////////////////////////////////////

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <URTouch.h>

#define TFT_RST 8
#define TFT_DC 9
#define TFT_CS 10
#define TOUCH_ORIENTATION LANDSCAPE

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

Adafruit_GFX_Button buttons[9];

URTouch myTouch(30, 28, 26, 24, 22);

char start[10] = {"Gamestart"};


char you[4] = {"YOU"};
char cpu[4] = {"CPU"};
char again[7] = {"Again?"};
int player;
int difficulty=8;
unsigned short int x,y,b; // position touch
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF

int board[]={0,0,0,0,0,0,0,0,0};// holds position data 0 is blank, 1 human, 2


is computer
unsigned turn;

const unsigned char circle[]PROGMEM={


0b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0
x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x
0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0
x0,0x0,0x0,0x0,0x7,0xf8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f,0xff,0x80,0x0,
0x0,0x0,0x0,0x0,0x3,0xff,0xff,0xf0,0x0,0x0,0x0,
0x0,0x0,0xf,0xff,0xff,0xfc,0x0,0x0,0x0,0x0,0x0,0x1f,0xff,0xff,0xfe,0x0,0x
0,0x0,0x0,0x0,0x7f,0xf0,0x3,0xff,0x80,0x0,0x0,0x0,0x0,0xff,0x80,0x0,0x7
f,0xc0,0x0,0x0,0x0,0x1,0xfe,0x0,0x0,0x1f,0xe0,0x0,0x0,
0x0,0x3,0xf8,0x0,0x0,0x7,0xf0,0x0,0x0,0x0,0x7,0xf0,0x0,0x0,0x3,0xf8,0x
0,0x0,0x0,0xf,0xe0,0x0,0x0,0x1,0xfc,0x0,0x0,0x0,0xf,0xc0,0x0,0x0,0x0,0x
fc,0x0,0x0,0x0,0x1f,0x80,0x0,0x0,0x0,0x7e,0x0,0x0,
0x0,0x3f,0x0,0x0,0x0,0x0,0x3f,0x0,0x0,0x0,0x3e,0x0,0x0,0x0,0x0,0x1f,0x
0,0x0,0x0,0x7e,0x0,0x0,0x0,0x0,0x1f,0x80,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,
0xf,0x80,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0xf,0x80,0x0,
0x0,0xf8,0x0,0x0,0x0,0x0,0x7,0xc0,0x0,0x0,0xf8,0x0,0x0,0x0,0x0,0x7,0xc
0,0x0,0x0,0xf8,0x0,0x0,0x0,0x0,0x7,0xc0,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0
x3,0xc0,0x0,0x1,0xf0,0x0,0x0,0x0,0x0,0x3,0xe0,0x0,
0x1,0xf0,0x0,0x0,0x0,0x0,0x3,0xe0,0x0,0x1,0xf0,0x0,0x0,0x0,0x0,0x3,0xe
0,0x0,0x1,0xf0,0x0,0x0,0x0,0x0,0x3,0xe0,0x0,0x1,0xf0,0x0,0x0,0x0,0x0,0
x3,0xe0,0x0,0x1,0xf0,0x0,0x0,0x0,0x0,0x3,0xe0,0x0,
0x1,0xf0,0x0,0x0,0x0,0x0,0x3,0xe0,0x0,0x1,0xf0,0x0,0x0,0x0,0x0,0x3,0xe
0,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x3,0xc0,0x0,0x0,0xf8,0x0,0x0,0x0,0x0,0
x7,0xc0,0x0,0x0,0xf8,0x0,0x0,0x0,0x0,0x7,0xc0,0x0,
0x0,0xf8,0x0,0x0,0x0,0x0,0x7,0xc0,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0xf,0x8
0,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0xf,0x80,0x0,0x0,0x7e,0x0,0x0,0x0,0x0,0
x1f,0x80,0x0,0x0,0x3e,0x0,0x0,0x0,0x0,0x1f,0x0,0x0,
0x0,0x3f,0x0,0x0,0x0,0x0,0x3f,0x0,0x0,0x0,0x1f,0x80,0x0,0x0,0x0,0x7e,0
x0,0x0,0x0,0xf,0xc0,0x0,0x0,0x0,0xfc,0x0,0x0,0x0,0xf,0xe0,0x0,0x0,0x1,0
xfc,0x0,0x0,0x0,0x7,0xf0,0x0,0x0,0x3,0xf8,0x0,0x0,
0x0,0x3,0xf8,0x0,0x0,0x7,0xf0,0x0,0x0,0x0,0x1,0xfe,0x0,0x0,0x1f,0xe0,0
x0,0x0,0x0,0x0,0xff,0x80,0x0,0x7f,0xc0,0x0,0x0,0x0,0x0,0x7f,0xf0,0x3,0x
ff,0x80,0x0,0x0,0x0,0x0,0x1f,0xff,0xff,0xfe,0x0,0x0,0x0,
0x0,0x0,0xf,0xff,0xff,0xfc,0x0,0x0,0x0,0x0,0x0,0x3,0xff,0xff,0xf0,0x0,0x0
,0x0,0x0,0x0,0x0,0x7f,0xff,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xf8,0x0,0x
0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0
x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x
0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
};
const unsigned char x_bitmap[]PROGMEM={
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0
x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x
0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0
x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x
0,0x0,0x3,0xff,0xff,0xc0,0x1,0xff,0xff,0xe0,0x0,
0x1,0xff,0xff,0xe0,0x1,0xff,0xff,0xc0,0x0,0x1,0xff,0xff,0xf0,0x3,0xff,0xff,
0xc0,0x0,0x0,0xff,0xff,0xf0,0x7,0xff,0xff,0x80,0x0,0x0,0xff,0xff,0xf8,0x7,
0xff,0xff,0x80,0x0,0x0,0x7f,0xff,0xf8,0xf,0xff,0xff,0x0,0x0,
0x0,0x3f,0xff,0xfc,0xf,0xff,0xfe,0x0,0x0,0x0,0x3f,0xff,0xfe,0x1f,0xff,0xfe,
0x0,0x0,0x0,0x1f,0xff,0xfe,0x1f,0xff,0xfc,0x0,0x0,0x0,0x1f,0xff,0xff,0x3f,
0xff,0xfc,0x0,0x0,0x0,0xf,0xff,0xff,0x7f,0xff,0xf8,0x0,0x0,
0x0,0xf,0xff,0xff,0xff,0xff,0xf8,0x0,0x0,0x0,0x7,0xff,0xff,0xff,0xff,0xf0,0
x0,0x0,0x0,0x3,0xff,0xff,0xff,0xff,0xe0,0x0,0x0,0x0,0x3,0xff,0xff,0xff,0xf
f,0xe0,0x0,0x0,0x0,0x1,0xff,0xff,0xff,0xff,0xc0,0x0,0x0,
0x0,0x1,0xff,0xff,0xff,0xff,0xc0,0x0,0x0,0x0,0x0,0xff,0xff,0xff,0xff,0x80,
0x0,0x0,0x0,0x0,0xff,0xff,0xff,0xff,0x80,0x0,0x0,0x0,0x0,0x7f,0xff,0xff,0
xff,0x0,0x0,0x0,0x0,0x0,0x3f,0xff,0xff,0xfe,0x0,0x0,0x0,
0x0,0x0,0x3f,0xff,0xff,0xfe,0x0,0x0,0x0,0x0,0x0,0x1f,0xff,0xff,0xfc,0x0,0
x0,0x0,0x0,0x0,0x1f,0xff,0xff,0xfc,0x0,0x0,0x0,0x0,0x0,0x1f,0xff,0xff,0xf
c,0x0,0x0,0x0,0x0,0x0,0x3f,0xff,0xff,0xfe,0x0,0x0,0x0,
0x0,0x0,0x3f,0xff,0xff,0xfe,0x0,0x0,0x0,0x0,0x0,0x7f,0xff,0xff,0xff,0x0,0
x0,0x0,0x0,0x0,0xff,0xff,0xff,0xff,0x80,0x0,0x0,0x0,0x0,0xff,0xff,0xff,0xf
f,0x80,0x0,0x0,0x0,0x1,0xff,0xff,0xff,0xff,0xc0,0x0,0x0,
0x0,0x1,0xff,0xff,0xff,0xff,0xc0,0x0,0x0,0x0,0x3,0xff,0xff,0xff,0xff,0xe0,0
x0,0x0,0x0,0x3,0xff,0xff,0xff,0xff,0xe0,0x0,0x0,0x0,0x7,0xff,0xff,0xff,0xf
f,0xf0,0x0,0x0,0x0,0xf,0xff,0xff,0xff,0xff,0xf8,0x0,0x0,
0x0,0xf,0xff,0xff,0xff,0xff,0xf8,0x0,0x0,0x0,0x1f,0xff,0xff,0x7f,0xff,0xfc,
0x0,0x0,0x0,0x1f,0xff,0xfe,0x3f,0xff,0xfc,0x0,0x0,0x0,0x3f,0xff,0xfc,0x3f,
0xff,0xfe,0x0,0x0,0x0,0x3f,0xff,0xfc,0x1f,0xff,0xfe,0x0,0x0,
0x0,0x7f,0xff,0xf8,0x1f,0xff,0xff,0x0,0x0,0x0,0xff,0xff,0xf8,0xf,0xff,0xff,
0x80,0x0,0x0,0xff,0xff,0xf0,0x7,0xff,0xff,0x80,0x0,0x1,0xff,0xff,0xe0,0x7
,0xff,0xff,0xc0,0x0,0x1,0xff,0xff,0xe0,0x3,0xff,0xff,0xc0,0x0,
0x3,0xff,0xff,0xc0,0x3,0xff,0xff,0xe0,0x0,0x3,0xff,0xff,0xc0,0x1,0xff,0xff,
0xe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0
x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0
x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x
0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
};

void setup()
{
myTouch.InitTouch();
myTouch.setPrecision(PREC_HI);
tft.begin();
tft.setRotation(3);
}

void loop()
{
int board[9] = {0,0,0,0,0,0,0,0,0};

drawStartScreen();
do{
myTouch.read();
x = myTouch.getX(); //Get touch point
y = myTouch.getY();
delay(100);
}while(!(buttons[0].contains(x,y)));

tft.fillScreen(BLACK);
//Draw white frame
tft.drawRect(0,0,320,240,WHITE);
//Print "Tic Tac Toe" Text
tft.setCursor(30,30);
tft.setTextColor(WHITE);
tft.setTextSize(4);
tft.print("Tic Tac Toe");
//Print "YouTube!" text
tft.setCursor(30,100);
tft.setTextColor(GREEN);
tft.setTextSize(4);
tft.print("Who begins");
//Create Red Button
// create buttons // x, y, w, h, outline, fill, text
buttons[0].initButton(&tft, 100,200,80,40,WHITE, RED, WHITE,
you, 2);
buttons[0].drawButton();
// create buttons // x, y, w, h, outline, fill, text
buttons[1].initButton(&tft, 200,200,80,40,WHITE, RED, WHITE,
cpu, 2);
buttons[1].drawButton();
b=1;
do{
myTouch.read();
x = myTouch.getX(); //Get touch point
y = myTouch.getY();
if (buttons[0].contains(x,y))
{
b=0;
player = 1;
tft.fillScreen(BLACK);
//Draw white frame
tft.drawRect(0,0,320,240,WHITE);
tft.setCursor(30,30);
tft.setTextColor(WHITE);
tft.setTextSize(2);
tft.print("Ok, you begin.");
delay(2000);
}
if(buttons[1].contains(x,y))
{
b=0;
player = 2;
tft.fillScreen(BLACK);
//Draw white frame
tft.drawRect(0,0,320,240,WHITE);
tft.setCursor(30,30);
tft.setTextColor(WHITE);
tft.setTextSize(2);
tft.print("Ok, CPU begins.");
delay(2000);
}
}while(b);

tft.fillScreen(BLACK);
tft.drawRect(0,0,319,240,WHITE);

drawVerticalLine(125);
drawVerticalLine(195);
drawHorizontalLine(80);
drawHorizontalLine(150);

for(turn = 0; turn < 9 && win(board) == 0; ++turn) {


if((turn+player) % 2 == 0)
computerMove(board);
else {
//draw(board);
playerMove(board);
}
}
switch(win(board)) {
case 0:
Serial.println("It's a draw.\n");
break;
case 1:
//draw(board);
Serial.println("You lose.\n");
break;
case -1:
Serial.println("You win!\n");
break;
}
do{}while(myTouch.dataAvailable()==false);
//x = map(tp.y, 930, 88, 0, 480);
//y = map(tp.x, 908, 125, 0, 320);
//delay(250);}
}
void drawHorizontalLine(int y)
{
int i=0;
for(i=0;i<7;i++)
{
tft.drawLine(60,y+i,270,y+i,WHITE);
}
}

void drawVerticalLine(int x)
{
int i=0;
for(i=0;i<7;i++)
{
tft.drawLine(x+i,20,x+i,220,WHITE);
}
}
void drawStartScreen()
{
tft.fillScreen(BLACK);

//Draw white frame


tft.drawRect(0,0,319,240,WHITE);

//Print "Tic Tac Toe" Text


tft.setCursor(30,100);
tft.setTextColor(WHITE);
tft.setTextSize(4);
tft.print("Tic Tac Toe");

//Print "YouTube!" text


tft.setCursor(80,30);
tft.setTextColor(GREEN);
tft.setTextSize(4);
tft.print("Arduino");

buttons[0].initButton(&tft, 160,200,200,40,WHITE, RED, WHITE, start, 2);


buttons[0].drawButton();

void drawCircle(int x, int y)


{
drawBitmap(x,y,circle,65,65,RED);
}

void drawX(int x, int y)


{
drawBitmap(x,y,x_bitmap,65,65,BLUE);
}
void drawBitmap(int16_t x, int16_t y,
const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) {

int16_t i, j, byteWidth = (w + 7) / 8;
uint8_t byte;

for(j=0; j<h; j++) {


for(i=0; i<w; i++) {
if(i & 7) byte <<= 1;
else byte = pgm_read_byte(bitmap + j * byteWidth + i / 8);
if(byte & 0x80) tft.drawPixel(x+i, y+j, color);
}
}
}
void computerMove(int board[9]) {
int move = -1;
int score = -2;
int i;
for(i = 0; i < 9; ++i) {
if(board[i] == 0) {
board[i] = 1;
int tempScore = -minimax(board, -1, 0);
board[i] = 0;
if(tempScore > score) {
score = tempScore;
move = i;
}
}
}
//returns a score based on minimax tree at a given node.
board[move] = 1;
drawCpuMove(move);
delay(100);
}

void playerMove(int board[9]) {


int move = 0;
b = 1;
do{
if (myTouch.dataAvailable() == true)
{
myTouch.read();
x = myTouch.getX(); //Get touch point
y = myTouch.getY();

if((x>55 && x<125)&& (y>0 && y<80)) //0


{
if(board[0]==0)
{
move=0;
b=0;
}
}
else if((x>125 && x<195) && (y>0 && y<80)) //1
{
if(board[1]==0)
{
move=1;
b=0;
}
}
else if((x>195&&x<265)&& (y>0 && y<80)) //2
{
if(board[2]==0)
{
move=2;
b=0;
}
}

else if((x>55 && x<125)&& (y>80 && y<155)) //3


{
if(board[3]==0)
{
move=3;
b=0;
}
}

else if((x>125 && x<195)&& (y>80 && y<155)) //4


{
if(board[4]==0)
{
move=4;
b=0;
}
}

else if((x>195&&x<265)&& (y>80 && y<155)) //5


{
if(board[5]==0)
{
move=5;
b=0;
}
}

else if((x>55 && x<125)&& (y>155 && y<235)) //6


{
if(board[6]==0)
{
move=6;
b=0;
}
}

else if((x>125 && x<195)&& (y>155 && y<235)) //7


{
if(board[7]==0)
{
move=7;
b=0;
}
}

else if((x>195&&x<265)&& (y>155 && y<235)) //8


{
if(board[8]==0)
{
move=8;
b=0;
}
}

}
}while(b);
board[move] = -1;
drawPlayerMove(move);
delay(100);
}
int win(const int board[9]) {
//list of possible winning positions
unsigned wins[8][3] = {{0,1,2},{3,4,5},{6,7,8},{0,3,6},{1,4,7},{2,5,8},
{0,4,8},{2,4,6}};
int winPos;
for(winPos = 0; winPos < 8; ++winPos) {
if(board[wins[winPos][0]] != 0 && board[wins[winPos][0]] ==
board[wins[winPos][1]] && board[wins[winPos][0]] ==
board[wins[winPos][2]])
return board[wins[winPos][2]];
}
return 0;
}

int minimax(int board[9], int player, int depth) {


//check the positions for players
int winner = win(board);
if(winner != 0) return winner*player;

int move = -1;


int score = -2;
int i;
for(i = 0; i < 9; ++i) {

if(board[i] == 0) {
board[i] = player;
int thisScore=0;
if (depth<difficulty){
thisScore = -minimax(board, player*-1,depth+1);
}

if(thisScore > score) {


score = thisScore;
move = i;
}
//choose the worst move for opponent
board[i] = 0;
}
}
if(move == -1) return 0;
return score;
}
void drawCpuMove(int move)
{
switch(move)
{
case 0: drawCircle(55,15); break;
case 1: drawCircle(130,15); break;
case 2: drawCircle(205,15); break;
case 3: drawCircle(55,85); break;
case 4: drawCircle(130,85); break;
case 5: drawCircle(205,85); break;
case 6: drawCircle(55,155); break;
case 7: drawCircle(130,155);break;
case 8: drawCircle(205,155);break;
}
}

void drawPlayerMove(int move)


{
switch(move)
{
case 0: drawX(55,15); break;
case 1: drawX(130,15); break;
case 2: drawX(205,15); break;
case 3: drawX(55,85); break;
case 4: drawX(130,85); break;
case 5: drawX(205,85); break;
case 6: drawX(55,155); break;
case 7: drawX(130,155);break;
case 8: drawX(205,155);break;
}
}
9) Oled Display with Arduino 101

COMPONENTS AND SUPPLIES

Arduino 101 & Genuino 101


× 1
OLED 128X64 × 1

Rotary potentiometer (generic)


× 1

Jumper wires (generic)


× 1

USB-A to B Cable
× 1

Breadboard (generic)
× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

Months ago I bought my Arduino 101 and wanted to


connect my shields and modules that I used in Arduino
One, but there were always problems with the libraries
and there were many headaches. I was looking for
information on the internet and could not find my
answers.
Today I finally found the way to connect my OLED
screen of 0.96 inches with Arduino 101 and I want to
share my discovery with this tutorial, since it could help
many people with the same problem as me.
Materials
To do this tutorial, we need materials, in this case we
will use an Arduino 101, the OLED screen with the
model SSD1306 of resolution 128X64 pixels, cables, a
potentiometer and a protoboard.

Code
Then open Arduino IDE and copy and paste the next
code:
#include <Arduino.h>
#include <U8g2lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
U8G2_SSD1306_128X64_NONAME_F_SW_I2C
u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /*
reset=*/ U8X8_PIN_NONE); // All Boards without
Reset of the Display
int a=0; //variable of value of analog read pin
char taco[4];//variable to send text to the oled display
void setup(void) {
u8g2.begin();// Oled display begins
}
void loop(void) {
a=analogRead(A0); //read potentiometer value
sprintf(taco,"%04d",a); //convert potentiometer value to
string
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_inr38_mf); // choose a
suitable font
u8g2.drawStr(0,60,taco); // write something to the
internal memory
u8g2.sendBuffer(); // transfer internal memory to
the display
delay(1000);
For everything to work we must download the library
u8g2.
After uploading the code, and having connected the
potentiometer to the Arduino plate, the value of the
potentiometer can be seen in the display, from 0 to 1023,
as shown below.
SCHEMATICS
CODE

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /*
clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); // All
Boards without Reset of the Display

int a=0; //variable of value of analog read pin


char taco[4];//variable to send text to the oled display
void setup(void) {
u8g2.begin();// Oled display begins
}

void loop(void) {
a=analogRead(A0); //read potentiometer value
sprintf(taco,"%04d",a); //convert potentiometer value to string
u8g2.clearBuffer(); // clear the internal
memory
u8g2.setFont(u8g2_font_inr38_mf); // choose a suitable font
u8g2.drawStr(0,60,taco); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal
memory to the display
delay(1000);
}

10) Arduino Ask the Magic 8 Ball


COMPONENTS AND SUPPLIES

Resistor 10k ohm


× 2

Resistor 221 ohm


× 2
SparkFun Pushbutton switch × 1
12mm

Rotary potentiometer (generic)


× 1

Arduino LCD Screen


× 1

Jumper wires (generic)


× 21

Arduino UNO & Genuino UNO


× 1

Breadboard (generic)
× 1

USB-A to Micro-USB Cable × 1


NECESSARY TOOLS AND MACHINES
Arduino Materia 101
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

The purpose of this project was to create a Magic 8


Ball - Arduino style. We were able to do so by
modifying the Crystal Ball project in the Arduino
starter kit. The goal was to create a micro controller
that generates 20 random responses to the user's
statement and then switches to another response when
a switch button is pressed.
Why
Magic 8 Balls are one of the many fortune telling toys
that are popular with children. It was originally
developed in 1950. It returns 20 different statements
like "It is certain" in response to questions that
individuals ask. Magic 8 Balls are unique because can
be used by anyone, not just a fortune teller.
How It Works
The LCD display originally shows "Ask the Magic 8
ball!". The user then asks a question and presses the
button switch. The display then shifts to one of the 20
responses and then displays "Ask another question!".
The user can continue pressing the switch until all of
their questions are answered.
How to Make It
Follow the Arduino Project 11 - Crystal Ball in the
Arduino starter kit in order to construct the initial
circuit. Replace the tilt sensor with a button switch
and add a 220 ohm resistor two spaces in front of the
button switch. Alter the code so that when the button
is pressed, the Magic 8 ball returns one of the 20
responses and then displays "Ask another question!".
This alteration includes removing the code about the
tilt sensor and replacing it with an if statement (if the
switch is being pressed then return the statement +
"Ask another question!"). Change the code to reflect
what you want the magic 8 ball's response to be.
During this step you can utilize the delay function to
keep a message on the LCD display for a certain
amount of time. In between each of the 20 cases make
sure to include a break to differentiate between each
case.

SCHEMATICS
CODE

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int switchPin = 6;
int switchState = 0;
//declaring the variable for the switch
int reply;
void setup() {
pinMode(0, INPUT);
//power source for switch
lcd.begin(16, 2);
pinMode(switchPin, INPUT);
lcd.print("Ask the Magic");
lcd.setCursor(0,1);
lcd.print("8 ball!");
//welcome message
}
void loop(){
switchState = digitalRead(switchPin);
{
if(switchState == HIGH){
//when the switch is pressed
reply = random(8);
//return a random case
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("");
lcd.setCursor(0,1);
switch(reply){
case 0:
lcd.begin(16, 2);
lcd.print("It is");
lcd.setCursor(0,1);
lcd.print("certain :)");
delay (2500);
//maintain the first message
lcd.clear();
//clear the first message
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
//print the second message
break;
//next case
case 1:
lcd.begin(16, 2);
lcd.print("As I see it,");
lcd.setCursor(0,1);
lcd.print("yes :)");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 2:
lcd.begin(16, 2);
lcd.print("Reply hazy");
lcd.setCursor(0,1);
lcd.print("try again :/");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 3:
lcd.begin(16, 2);
lcd.print("Don't count");
lcd.setCursor(0,1);
lcd.print("on it :(");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 4:
lcd.begin(16, 2);
lcd.print("It is");
lcd.setCursor(0,1);
lcd.print("decidedly so :)");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 5:
lcd.begin(16, 2);
lcd.print("Most");
lcd.setCursor(0,1);
lcd.print("likely :)");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 6:
lcd.begin(16, 2);
lcd.print("Ask again");
lcd.setCursor(0,1);
lcd.print("later :/");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 7:
lcd.begin(16, 2);
lcd.print("My reply is");
lcd.setCursor(0,1);
lcd.print("no :(");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 8:
lcd.begin(16, 2);
lcd.print("Without a");
lcd.setCursor(0,1);
lcd.print("doubt :)");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 9:
lcd.begin(16, 2);
lcd.print("Outlook good :)");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 10:
lcd.begin(16, 2);
lcd.print("Better not tell");
lcd.setCursor(0,1);
lcd.print("you now :/");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 11:
lcd.begin(16, 2);
lcd.print("My sources");
lcd.setCursor(0,1);
lcd.print("say no :(");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 12:
lcd.begin(16, 2);
lcd.print("Yes");
lcd.setCursor(0,1);
lcd.print("definitely :)");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 13:
lcd.begin(16, 2);
lcd.print("Yes :)");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 14:
lcd.begin(16, 2);
lcd.print("Cannot");
lcd.setCursor(0,1);
lcd.print("predict now :/");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 15:
lcd.begin(16, 2);
lcd.print("Outlook not");
lcd.setCursor(0,1);
lcd.print("so good :(");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 16:
lcd.begin(16, 2);
lcd.print("You may rely");
lcd.setCursor(0,1);
lcd.print("on it :)");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 17:
lcd.begin(16, 2);
lcd.print("Signs point");
lcd.setCursor(0,1);
lcd.print("to yes :)");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 18:
lcd.begin(16, 2);
lcd.print("Concentrate and");
lcd.setCursor(0,1);
lcd.print("ask again :/");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
case 19:
lcd.begin(16, 2);
lcd.print("Very");
lcd.setCursor(0,1);
lcd.print("doubtful :(");
delay (2500);
lcd.clear();
lcd.print("Ask another");
lcd.setCursor(0,1);
lcd.print("question!");
break;
}
}
}
}

11) Arduino Calculator


COMPONENTS AND SUPPLIES
Arduino UNO & Genuino UNO
× 1

RGB LCD Shield Kit, 16x2


Character Display
× 1
Jumper wires (generic) × 1

9V battery (generic)
× 1

Breadboard (generic)
× 1

ABOUT THIS PROJECT

At the end of this project you will know how to use


a 16x2 LCD and Keypad with Arduino and also how
easy it is to program for them using the readily available
libraries. You will also understand how to program your
Arduino for accomplishing a particular task.
Materials Required:
Arduino Uno (Any version will work)
16×2 LCD Display
4×4 Keypad

9V Battery
Breadboard and Connecting wires
D0
1st pin of the keyboard
D1
2nd pin of the keyboard
D2
3rd pin of the keyboard
D3
4th pin of the keyboard
D4
5th pin of the keyboard
D5
6th pin of the keyboard
D6
7th pin of the keyboard
D7
8th pin of the keyboard
D8
Register select pin of LCD (pin 4)
D9
Enable pin of LCD (pin 6)
D10
Data pin 4 (pin 11)
D11
Data pin 4 (pin 11)
D12
Data pin 4 (pin 11)
D13
Data pin 4 (pin 11)
+5V
Connected to Vdd pin of LCD (pin 2)
Ground
Connected to Vss, Vee and RW pin of LCD (pin 1, 3 and
5)
Some Arduino boards might show an error while
uploading program if there are anything connected to pin
0 and pin1, so if you experience any just remove the
keypad while uploading the program.
Once your connections are done your hardware will look
something like this below
SCHEMATICS
CODE

*
* Arduino Keypad calculator Program
*/

#include <LiquidCrystal.h> //Header file for LCD from


https://www.arduino.cc/en/Reference/LiquidCrystal
#include <Keypad.h> //Header file for Keypad from
https://github.com/Chris--A/Keypad

const byte ROWS = 4; // Four rows


const byte COLS = 4; // Three columns

// Define the Keymap


char keys[ROWS][COLS] = {

{'7','8','9','D'},

{'4','5','6','C'},

{'1','2','3','B'},

{'*','0','#','A'}

};

byte rowPins[ROWS] = { 0, 1, 2, 3 };// Connect keypad ROW0, ROW1,


ROW2 and ROW3 to these Arduino pins.
byte colPins[COLS] = { 4, 5, 6, 7 }; // Connect keypad COL0, COL1 and
COL2 to these Arduino pins.
Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS,
COLS ); // Create the Keypad

const int rs = 8, en = 9, d4 = 10, d5 = 11, d6 = 12, d7 = 13; //Pins to which


LCD is connected
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

long Num1,Num2,Number;
char key,action;
boolean result = false;

void setup() {
lcd.begin(16, 2); //We are using a 16*2 LCD display
lcd.print("DIY Calculator"); //Display a intro message
lcd.setCursor(0, 1); // set the cursor to column 0, line 1
lcd.print("-CircuitDigest"); //Display a intro message

delay(2000); //Wait for display to show info


lcd.clear(); //Then clean it
}

void loop() {

key = kpd.getKey(); //storing pressed key value in a char

if (key!=NO_KEY)
DetectButtons();

if (result==true)
CalculateResult();

DisplayResult();
}

void DetectButtons()
{
lcd.clear(); //Then clean it
if (key=='*') //If cancel Button is pressed
{Serial.println ("Button Cancel"); Number=Num1=Num2=0; result=false;}

if (key == '1') //If Button 1 is pressed


{Serial.println ("Button 1");
if (Number==0)
Number=1;
else
Number = (Number*10) + 1; //Pressed twice
}

if (key == '4') //If Button 4 is pressed


{Serial.println ("Button 4");
if (Number==0)
Number=4;
else
Number = (Number*10) + 4; //Pressed twice
}

if (key == '7') //If Button 7 is pressed


{Serial.println ("Button 7");
if (Number==0)
Number=7;
else
Number = (Number*10) + 7; //Pressed twice
}

if (key == '0')
{Serial.println ("Button 0"); //Button 0 is Pressed
if (Number==0)
Number=0;
else
Number = (Number*10) + 0; //Pressed twice
}

if (key == '2') //Button 2 is Pressed


{Serial.println ("Button 2");
if (Number==0)
Number=2;
else
Number = (Number*10) + 2; //Pressed twice
}

if (key == '5')
{Serial.println ("Button 5");
if (Number==0)
Number=5;
else
Number = (Number*10) + 5; //Pressed twice
}

if (key == '8')
{Serial.println ("Button 8");
if (Number==0)
Number=8;
else
Number = (Number*10) + 8; //Pressed twice
}

if (key == '#')
{Serial.println ("Button Equal");
Num2=Number;
result = true;
}

if (key == '3')
{Serial.println ("Button 3");
if (Number==0)
Number=3;
else
Number = (Number*10) + 3; //Pressed twice
}

if (key == '6')
{Serial.println ("Button 6");
if (Number==0)
Number=6;
else
Number = (Number*10) + 6; //Pressed twice
}

if (key == '9')
{Serial.println ("Button 9");
if (Number==0)
Number=9;
else
Number = (Number*10) + 9; //Pressed twice
}

if (key == 'A' || key == 'B' || key == 'C' || key == 'D') //Detecting Buttons on
Column 4
{
Num1 = Number;
Number =0;
if (key == 'A')
{Serial.println ("Addition"); action = '+';}
if (key == 'B')
{Serial.println ("Subtraction"); action = '-'; }
if (key == 'C')
{Serial.println ("Multiplication"); action = '*';}
if (key == 'D')
{Serial.println ("Devesion"); action = '/';}

delay(100);
}

void CalculateResult()
{
if (action=='+')
Number = Num1+Num2;

if (action=='-')
Number = Num1-Num2;
if (action=='*')
Number = Num1*Num2;

if (action=='/')
Number = Num1/Num2;
}

void DisplayResult()
{
lcd.setCursor(0, 0); // set the cursor to column 0, line 1
lcd.print(Num1); lcd.print(action); lcd.print(Num2);

if (result==true)
{lcd.print(" ="); lcd.print(Number);} //Display the result

lcd.setCursor(0, 1); // set the cursor to column 0, line 1


lcd.print(Number); //Display the result
}
12) Arduino DIY Benchtop Ph Meter

COMPONENTS AND SUPPLIES


Arduino UNO & Genuino UNO × 1

Atlas Scientific Gravity™


Analog pH Sensor
× 1

Atlas Scientific Consumer Grade


pH Probe
× 1

20x4 LCD Module


× 1

158x90x60mm enclosure
× 1

Mini breadboard
× 1

Resistor 220 ohm


× 1

Resistor 1k ohm × 1
11mm standoffs and screws
(provided with the pH sensor) × 4

Jumper wires
× 1

Acrylic sheet (plexiglass)


× 1
NECESSARY TOOLS AND MACHINES
Drill, drill bits, drywall cutter bits, files,
screwdrivers, benchtop vise, band saw, glue
gun and glue stick, soldering iron and solder,
digital caliper, ruler
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

In this project, we will be making a benchtop pH


meter using the Gravity analog pH circuit and probe
from Atlas Scientific and an Arduino Uno. Readings
will be displayed on a liquid crystal display (LCD).
Note:
- This meter was developed on a Windows computer.
It was not tested on Mac.
- The enclosure is not waterproof.
Step 1: Prepare Housing
Safety : Remember to take care when handling
tools/machinery and to wear proper safety gear such
as goggles, gloves, and respirators.
The housing used is an ABS plastic enclosure. It has
to be modified for the pH meter.
Cut opening for the LCD
a) The LCD is placed in the top portion (cover) of the
enclosure. Center a 98x40mm rectangle on the cover.
b) Put the piece in the vise and drill a 3.2mm (1/8")
pilot hole in the rectangle that was marked off.
c) Use this pilot hole as the start point for the 3.2mm
(1/8") drywall cutting bit. Since this a small job, we
will use the bit on the hand drill rather than a drywall
cutting machine. Work on the inside of the rectangle
instead of the lines as it may be a bit difficult to cut in
a straight manner with this bit on the drill.
d) Next, use a hand file to remove the excess material
and shape the rectangle to the required size.

Cut openings for BNC connector and Arduino ports


The openings for the BNC connector and Arduino
ports are on the side of the bottom portion of the
enclosure.
a) Using the dimensions provided below, mark the
center point for the circle and outlines for the two
rectangles.
b) Put the piece in the vice and cut the openings. The
circular opening is made using drill bits. The
rectangular ones are made by following a similar
process used to make the opening for the LCD.

Outfit the base plate to mount components


The base plate is used to mount the Arduino, pH
sensor and mini breadboard. 3.2mm thick acrylic sheet
is used.
a) Using a band saw, cut the acrylic sheet to
135x62.5mm.
b) Mark off the positions for the four holes as shown
below. Drill 2.38mm (3/32") diameter holes.
Countersink the holes on one side of the plate to a
depth of 3mm and diameter of 4.4mm (11/64"). This is
necessary to keep a flat under-surface when the screws
are inserted to hold the standoffs.
c) Attach the 11mm standoffs using the provided
screws. The pH sensor comes with 4 standoffs and
screws. Use two of them for the Arduino.

Step 2: Install Electronics in Housing


a) Insert the base plate into the bottom portion of the
housing. Keep in position with screws or hot glue.
b) Mount the pH sensor on the base plate. Secure to
standoffs with screws.
c) Mount the Arduino Uno onto the base plate. Secure
to standoffs with screws.

d) Add the mini breadboard onto the base plate.


e) Solder the header pins to the LCD (pins provided).
Insert LCD into the top portion of the housing and use
some hot glue to keep the screen in place.
Step 3: Wire Electronics Together

Wire the components are shown in the schematic


above.
Use the mini breadboard for the 1kΩ and 220Ω and
for distributing the Arduino's 5V and ground pins.
The two resistors are used to set the screen contrast.
Datasheets
Gravity pH sensor, pH probe
Step 4: Finalize Assembly
After the wiring has been completed:
a) Put the top and bottom portions of the housing
together using the provided screws.
b) Connect the probe to the BNC connector.
Step 5: Upload Code Onto Arduino Uno
The code for this project makes use of customized
libraries and header files. You will have to add them to
your Arduino IDE to use the code. The steps below
include the process of making this addition to the IDE.
a) Connect the Arduino to your computer and open the
IDE. The IDE can be downloaded from this LINK if
you do not have it. Go to Tools -> Board -> Select
Arduino/Genuino Uno. Go to Tools -> Port -> select
the port where the Arduino is connected to.
b) Add Liquid Crystal Display library: In the IDE go
to Sketch -> Include library -> Manage libraries. In
the search bar of the Library Manager enter
"liquidcrystal". Look for the package titled
"LiquidCrystal Built-in by Arduino, Adafruit". It may
or may not be installed. If not, select the package and
click on install.
c) Add Atlas Gravity sensor library: Download the zip
file from the following LINK. The file will be saved
as "Atlas_gravity.zip". In the IDE go to Sketch ->
Include library -> Add.ZIP Library. Locate the
"Atlas_gravity.zip" file and select to add.
d) Next, we have to add the code for the pH meter.
Copy the code from this LINK onto the IDE work
panel.
e) Compile and upload the code to the Arduino.
f) The pH readings will then be displayed on the LCD.
You can also view the readings on the serial monitor.
To open the serial monitor, go to Tools -> Serial
Monitor or press Ctrl+Shift+M on your keyboard. Set
the baud rate to 9600 and select "Carriage return".
Step 6: Calibrate pH Sensor
Note: If you plan on using an external power supply
for the Arduino, connect it to the Arduino before
doing the calibration. This will ensure that the
reference levels are appropriately set, which will aid
in the correct calibration.
This pH meter can be calibrated to one, two or three-
points calibration. Standard buffer solutions (pH 4, 7
and 10) are required
The serial monitor is used for the calibration process.
The user will be able to observe the gradual change in
readings as they come to stabilization and send the
appropriate commands.
Calibration data are stored in the EEPROM of the
Arduino.
Calibration commands
Low-point: cal, 4
Mid-point: cal, 7
High-point: cal, 10
Clear calibration: cal, clear
Steps
a) Remove the soaker bottle and rinse off the pH
probe.
b) Pour some of the pH 4 solution into a cup. Ensure
that there is enough to cover the sensing area of the
probe.
c) Place the probe in the cup and stir it around to
remove trapped air. Observe the readings on the serial
monitor. Let the probe sit in the solution until the
readings stabilize (small movement from one reading
to the next is normal)
d) After the readings stabilize, enter the command cal,
4 into the serial monitor. Calibration to pH 4 is now
complete.
Repeat steps a-d for pH7 and pH10. Remember to
rinse the probe as you proceed to different buffer
solutions.
What about temperature compensation?
The sensor used in this project has an accuracy of +/-
0.2%. The pH meter will operate within this accuracy
in the temperature range of 7 - 46°C. Outside of this
range, the meter will have to be modified for temp
compensation. Note: The pH probe can be subjected to
a range of 1 − 60 °C.

SCHEMATICS
CODE

/*
Once uploaded, open the serial monitor, set the baud rate to 9600 and
append "Carriage return"
The code allows the user to observe real time pH readings as well as
calibrate the sensor.
One, two or three-point calibration can be done.

Calibration commands:
low-point: "cal,4"
mid-point: "cal,7"
high-point: "cal,10"
clear calibration: "cal,clear"
*/

#include "ph_grav.h" //header file for Atlas Scientific


gravity pH sensor
#include "LiquidCrystal.h" //header file for liquid crystal
display (lcd)

String inputstring = ""; //a string to hold incoming data


from the PC
boolean input_string_complete = false; //a flag to indicate have we
received all the data from the PC
char inputstring_array[10]; //a char array needed for string
parsing
Gravity_pH pH = A0; //assign analog pin A0 of
Arduino to class Gravity_pH. connect output of pH sensor to pin A0
LiquidCrystal pH_lcd(2, 3, 4, 5, 6, 7); //make a variable pH_lcd
and assign arduino digital pins to lcd pins (2 -> RS, 3 -> E, 4 to 7 -> D4 to
D7)

void setup() {
Serial.begin(9600); //enable serial port
pH_lcd.begin(20, 4); //start lcd interface and define lcd
size (20 columns and 4 rows)
pH_lcd.setCursor(0,0); //place cursor on screen at
column 1, row 1
pH_lcd.print("--------------------"); //display characters
pH_lcd.setCursor(0,3); //place cursor on screen at
column 1, row 4
pH_lcd.print("--------------------"); //display characters
pH_lcd.setCursor(5, 1); //place cursor on screen at
column 6, row 2
pH_lcd.print("pH Reading"); //display "pH Reading"
if (pH.begin()) { Serial.println("Loaded EEPROM");}
Serial.println(F("Use commands \"CAL,4\", \"CAL,7\", and \"CAL,10\" to
calibrate the circuit to those respective values"));
Serial.println(F("Use command \"CAL,CLEAR\" to clear the calibration"));
}

void serialEvent() { //if the hardware serial port_0


receives a char
inputstring = Serial.readStringUntil(13); //read the string until we see
a <CR>
input_string_complete = true; //set the flag used to tell if we
have received a completed string from the PC
}

void loop() {

if (input_string_complete == true) { //check if data received


inputstring.toCharArray(inputstring_array, 30); //convert the string to a
char array
parse_cmd(inputstring_array); //send data to pars_cmd function
input_string_complete = false; //reset the flag used to tell if we
have received a completed string from the PC
inputstring = ""; //clear the string
}
Serial.println(pH.read_ph()); //output pH reading to serial
monitor
pH_lcd.setCursor(8, 2); //place cursor on screen at
column 9, row 3
pH_lcd.print(pH.read_ph()); //output pH to lcd
delay(1000);
}

void parse_cmd(char* string) { //For calling calibration


functions
strupr(string); //convert input string to uppercase

if (strcmp(string, "CAL,4") == 0) { //compare user input string


with CAL,4 and if they match, proceed
pH.cal_low(); //call function for low point calibration
Serial.println("LOW CALIBRATED");
}
else if (strcmp(string, "CAL,7") == 0) { //compare user input string
with CAL,7 and if they match, proceed
pH.cal_mid(); //call function for midpoint calibration
Serial.println("MID CALIBRATED");
}
else if (strcmp(string, "CAL,10") == 0) { //compare user input string
with CAL,10 and if they match, proceed
pH.cal_high(); //call function for highpoint calibration
Serial.println("HIGH CALIBRATED");
}
else if (strcmp(string, "CAL,CLEAR") == 0) { //compare user input
string with CAL,CLEAR and if they match, proceed
pH.cal_clear(); //call function for clearing calibration
Serial.println("CALIBRATION CLEARED");
}
}

13) Arduino Reaction Timer


COMPONENTS AND SUPPLIES
LED (generic)
× 2

SparkFun Pushbutton switch


12mm
× 2

DFRobot I2C 16x2 Arduino × 1


LCD Display Module

Slide Switch
× 1

Resistor 10k ohm


× 2

Battery Holder, 3 x AAA


× 1

Arduino Micro & Genuino


Micro
× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)

ABOUT THIS PROJECT

I discovered the code somewhere on the Internet and


tried it.
All my family loved the game and I decided to
assemble it in a funny case to be able to play.
The work is now finished and it is into the hands of
my kids.
It is a very basic project but in a kind of case which
hides all elements.
Here are some pictures:
This is how it looks. The BIG button is a hit button
and the small red one on top is "start"

I
was able to shrink the system and program only an
Atmega328P chip. Runs on 3 AAA.
Press Start

Round 1 of 5
Round 2 of 5

Average result calculation and showing. The "verdict"


Please do not hesitate to ask me questions if needed.
SCHEMATICS
CODE

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define btnSTART 5
#define btnHIT 7
#define ledTrigger 9
LiquidCrystal_I2C lcd(0x23,20,4);

void setup() {
lcd.init();
lcd.backlight();
pinMode(btnSTART, INPUT_PULLUP);
pinMode(btnHIT, INPUT_PULLUP);
pinMode(ledTrigger, OUTPUT);
digitalWrite(ledTrigger, LOW);
lcd.print("Salut Famille!");
delay(2000);
lcd.clear();
randomSeed(analogRead(0));
}

void loop() {
long timeReaction;
long timeTotal = 0;
lcd.print("Press START!");
while (digitalRead(btnSTART)) {}
delay(10);
while (!digitalRead(btnSTART)) {}
lcd.clear();
lcd.print("Jouez!!!");
delay(1000);
for (int i = 0; i < 5; i++) {
delay(random(500, 5000));
timeReaction = millis();
digitalWrite(ledTrigger, HIGH);
while (digitalRead(btnHIT)) {}
timeReaction = millis() - timeReaction;
timeTotal += timeReaction;
delay(10);
while (!digitalRead(btnHIT)) {}
digitalWrite(ledTrigger, LOW);
lcd.clear();
lcd.print(i + 1);
lcd.print(": ");
lcd.print(timeReaction);
delay(1000);
}
lcd.clear();
lcd.print("Moyenne = ");
lcd.print(timeTotal/5);
delay(10000);
lcd.clear();
}
14) Arduino Quizmo

COMPONENTS AND SUPPLIES


Arduino UNO & Genuino UNO
× 1

Adafruit Standard LCD - 16x2 × 1


White on Blue
Adafruit 4x3 Keypad
× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

This project is related to developing a handy gadget to


help kids practice basic arithmetic operations. I
decided to make it as my kids were very lazy to look
into the books and come back very soon saying that
they have done it (specially multiplication tables).
This gadget randomly asks different questions and
evaluate kids performance.
For this you need a 4x3 keypad to interact with the
gadget and an LCD to show you results.
Once you have setup brightness using the rehestat, you
can note down the values and replace it with fixed
resistors or keep it there if you want the user to adjust
brightness as per his/her comfort.
Power up Arduino and it will ask you what kind of
quiz you want to take. Selec appropriate option and it
will start. Once you have input your answer, you need
to press * in order to submit and let the gadeget check
your answer. In order to finish the quiz or take next
one, press # and main menu will appear again. You
can increase the difficulty level from the code by
changing the maximum range of random number
generator. This gadget currently produces random
questions by using numbers from 1 to 12.

SCHEMATICS
CODE

#include <Keypad.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

long rand1,rand2,ans,ans1,opr,score,total;
char selec,selec1;
boolean quiz=false;
String stringTwo;

const byte ROWS = 4; //four rows


const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
byte rowPins[ROWS] = {10, 9, 8, 7}; //connect to the
row pinouts of the keypad
byte colPins[COLS] = {6,1,0}; //connect to the
column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys),
rowPins, colPins, ROWS, COLS );

void setup(){
lcd.begin(16, 2);
mk_menu();
keypad.addEventListener(keypadEvent);
}

void loop(){
selec = keypad.getKey();
while (selec==NO_KEY){
selec = keypad.getKey();
}
lcd.print(selec);
delay(500);
if (selec!=NO_KEY){
switch(selec){
case '1':
quiz=true;
opr=1;
quiz_sum();
break;
case '2':
quiz=true;
opr=2;
quiz_subt();
break;
case '3':
quiz=true;
opr=3;
quiz_mult();
break;
}
}
}

void mk_menu(){
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("1)+ 2)- 3)x");
lcd.setCursor(0, 1);
lcd.print("Choose: ");
}
void quiz_sum(){
lcd.clear();
lcd.setCursor(0, 0);
rand1=random(1,99);
rand2=random(1,99);
lcd.print("Find ");
lcd.print(rand1);
lcd.print("+");
lcd.print(rand2);
lcd.print("?");
ans1=rand1+rand2;
selec1 = keypad.getKey();
while (selec1==NO_KEY){
selec1 = keypad.getKey();
}
while (quiz){
while (selec1==NO_KEY){
selec1 = keypad.getKey();
}
switch(selec1){
case NO_KEY:
break;
default:
lcd.print(selec1);
stringTwo.concat(selec1);
ans=stringTwo.toInt();
//lcd.print(stringTwo);
selec1=NO_KEY;
break;
}
}
}

void quiz_subt(){
lcd.clear();
lcd.setCursor(0, 0);
rand1=random(1,99);
rand2=random(1,99);
lcd.print("Find ");
if(rand1>=rand2){
lcd.print(rand1);
lcd.print("-");
lcd.print(rand2);
ans1=rand1-rand2;
}
else if(rand1<rand2){
lcd.print(rand2);
lcd.print("-");
lcd.print(rand1);
ans1=rand2-rand1;
}
lcd.print("?");
selec1 = keypad.getKey();
while (selec1==NO_KEY){
selec1 = keypad.getKey();
}
while (quiz){
while (selec1==NO_KEY){
selec1 = keypad.getKey();
}
switch(selec1){
case NO_KEY:
break;
default:
lcd.print(selec1);
stringTwo.concat(selec1);
ans=stringTwo.toInt();
//lcd.print(stringTwo);
selec1=NO_KEY;
break;
}
}
}

void quiz_mult(){
lcd.clear();
lcd.setCursor(0, 0);
rand1=random(1,12);
rand2=random(1,12);
lcd.print("Find ");
lcd.print(rand1);
lcd.print("x");
lcd.print(rand2);
lcd.print("?");
ans1=rand1*rand2;
selec1 = keypad.getKey();
while (selec1==NO_KEY){
selec1 = keypad.getKey();
}
while (quiz){
while (selec1==NO_KEY){
selec1 = keypad.getKey();
}
switch(selec1){
case NO_KEY:
break;
default:
lcd.print(selec1);
stringTwo.concat(selec1);
ans=stringTwo.toInt();
//lcd.print(stringTwo);
selec1=NO_KEY;
break;
}
}
}

void chk_ans(){
lcd.clear();
if (ans1==ans){
lcd.clear();
lcd.print("Correct");
score=score+1;
}
else {
lcd.clear();
lcd.print("Incorrect");
}
}
void keypadEvent(KeypadEvent key){
switch (keypad.getState()){
case PRESSED:
if (key == '*') {
chk_ans();
total=total+1;
stringTwo="";
delay(400);
if(opr==1){
quiz_sum();
}
else if(opr==2){
quiz_subt();
}
else if(opr==3){
quiz_mult();
}
}
else if (key == '#') {
quiz=false;
stringTwo="";
lcd.clear();
lcd.print("Your Score: ");
lcd.print(score);
lcd.print("/");
lcd.print(total);
delay(1500);
score=0;
total=0;
mk_menu();
loop();
}
break;
}
}

15) Arduino Model Train Control


COMPONENTS AND SUPPLIES
Arduino UNO & Genuino UNO
Or any compatible (i used × 1
sainsmart mega 2560)

Arduino Motor Shield R3


× 1

LED white
× 2
Photo resistor × 2

Resistor 10k ohm


× 2

Resistor 330 ohm


× 2

ABOUT THIS PROJECT

Like many people, my wish is a nice model train,


therefore I made a nice layout plan, bought a starter set,
made a table etc. It takes a long time, of course, to build
a complicated layout and in the meantime you want to
(test)ride on the track you have so far.
You can of course do so just with your transformer, but
if you do not pay attention you drive off the track. And
model trains are fragile, a drop on the floor will do
damage. So the plan is a back and forth automation.
Something like this: Arduino-railroad.
All due respect to the maker but if you pop each time
against a fence and reverse the motor directly, it will
damage the train or the gear at some time.
I figured two gates with an LED and an LDR will sense
the train.

Gate of LED and LDR


And let the Arduino decelerate, reverse and accelerate
the train.
The train blocks the light

SCHEMATICS
CODE

/*
Train control
This code is developed to "test" drive
a model train between two gates made of a LED and LDR.

Parts required:
1 - arduino uno/mega or compatible
1 - arduino motor shield R3
2 - Led brite white (5mm)
2 - Ldr (A 9013 photo resistor 5mm)
2 - 10K resistor
2 - 220 Ohm resistor
1 - model train

Created 4 October 2016


by Kitemasters

This code is part of the public domain


*/
// --------CONSTANTS (won't change)---------------

int sens_L_Pin = A4; // the pin number for ldr L


int sens_R_Pin = A5; // the pin number for ldr R
int led_L_Pin = 4; // the pin number for the L LED
int led_R_Pin = 5; // the pin number for the R LED
int motor_Pin = 3; // the pin number for the motor speed
int brake_Pin = 9; // the pin number for the motor brake
int direction_Pin = 12; // the pin number for the motor
direction
int current_sens_Pin = A0; // the pin number for the current
sensor
int read_sens_Interval = 200; // millisecs between reading sensors
int motor_Acc_Interval = 100; // millisecs between acceleration
steps
int motor_Dec_Interval = 10; // millisecs between deceleration
steps

//------------ VARIABLES (will change)---------------------

unsigned long currentMillis = 0; // stores the value of millis() in


each iteration of loop()
unsigned long previous_sens_Millis = 0; // will store the last time
sensors are read
unsigned long previous_Acc_Millis = 0; // will store time of last
acceleration step
unsigned long previous_Dec_Millis = 0; // will store time of last
deceleration step

int sensLreading = 0; // declare variable and set value for


left sensor reading
int sensRreading = 0; // declare variable and set value for
right sensor reading
int max_Speed = 200; // declare variable and set value for
maximum Speed (0 to 255)
int Speed = 0; // declare variable and set value for
current Speed (0 to 255)
boolean direct = HIGH; // declare variable and set value for
direction to HIGH (HIGH = left)

#define STATE_START 1 // declare value 0 to be


STATE_START
#define STATE_RUN 2 // declare value 1 to be
STATE_RUN
#define STATE_DECELERATE 3 // declare value 2 to be
STATE_DECELERATE
#define STATE_TURN 4 // declare value 3 to be
STATE_TURN
#define STATE_ACCELERATE 5 // declare value 4 to be
STATE_ACCELERATE
int state = STATE_START; // declare variable "state" and set
value to STATE_START

//========================================

void setup() {

Serial.begin(9600);

pinMode(led_L_Pin, OUTPUT); // set led_L_Pin as output


pinMode(led_R_Pin, OUTPUT); // set led_R_Pin as output
pinMode(motor_Pin, OUTPUT); // set motor_Pin as output
pinMode(brake_Pin, OUTPUT); // set brake_Pin as output
pinMode(direction_Pin, OUTPUT); // set direction_Pin as output
pinMode(sens_L_Pin, INPUT); // set sens_L_Pin as input
pinMode(sens_R_Pin, INPUT); // set sens_R_Pin as input
pinMode(current_sens_Pin, INPUT); // set current_sens_Pin as
input

}
//========================================

void loop() {

currentMillis = millis(); // store the latest value of millis()


read_sens(); // read the sensors

switch (state) // state switch


{
case STATE_START:
Start();
break;

case STATE_ACCELERATE:
Accelerate();
break;

case STATE_DECELERATE:
Decelerate();
break;

case STATE_TURN:
Turn();
break;

case STATE_RUN:
break;
}
}
//========================================

void read_sens() {

if (currentMillis - previous_sens_Millis >= read_sens_Interval) { // time is


up, so read sensors
previous_sens_Millis = currentMillis; // because shooter
and Koepel told me so.// save the time we last read sensors
sensLreading = analogRead(sens_L_Pin); // read left ldr
(high value means the light is off or blockt)
sensRreading = analogRead(sens_R_Pin); // read right ldr
(high value means the light is off or blockt)

if (sensLreading > 200 && direct == HIGH) { // if conditions


are throu, the train reached left gate***
digitalWrite(led_L_Pin, LOW); // turn left LED off
digitalWrite(led_R_Pin, HIGH); // turn right LED on
state = STATE_DECELERATE; // set state to
"decelerate"
previous_Dec_Millis = currentMillis; // set
previous_Dec_Millis to current time
}

if (sensRreading > 200 && direct == LOW) { // if conditions


are throu, the train reached right gate***
digitalWrite(led_R_Pin, LOW); // turn right LED off
digitalWrite(led_L_Pin, HIGH); // turn left LED on
state = STATE_DECELERATE; // set state to
"decelerate"
previous_Dec_Millis = currentMillis; // set
previous_Dec_Millis to current time
}
}
}
//========================================

void Start() {

digitalWrite(led_L_Pin, HIGH); // turn left led on


digitalWrite(brake_Pin, LOW); // Disengage the
Brake
digitalWrite(direction_Pin, direct); // Establishes
direction of the train
state = STATE_ACCELERATE; // set state to
"accelerate"
previous_Acc_Millis = currentMillis; // set
previous_Acc_Millis to current time
}
//========================================

void Accelerate() {

if (currentMillis - previous_Acc_Millis >= motor_Acc_Interval) { //


check interval time
previous_Acc_Millis = currentMillis; // because shooter
and Koepel told me so.//last time of acceleration step
Speed = Speed + 1; // add 1 to speed
analogWrite(motor_Pin, Speed); // send Speed to
motor_Pin
if (Speed == max_Speed) { // if speed reach max
speed
state = STATE_RUN; // set state to "run"
}
}
}
//========================================

void Decelerate() {
if (currentMillis - previous_Dec_Millis >= motor_Dec_Interval) { //
check interval time
previous_Dec_Millis = currentMillis; // because shooter
and Koepel told me so.//last time of acceleration step
Speed = Speed - 1; // subtract 1 of speed
analogWrite(motor_Pin, Speed); // send Speed to
motor_Pin
if (Speed == 0) { // if speed reach 0
state = STATE_TURN; // set state to "turn"
}
}
}
//========================================

void Turn() {

if (direct == HIGH) { // flip direction


direct = LOW;
digitalWrite(direction_Pin, direct); // establishes right
direction of train
}
else {
direct = HIGH;
digitalWrite(direction_Pin, direct); // establishes left
direction of train
}
state = STATE_ACCELERATE; // set state to
"accelerate"
previous_Acc_Millis = currentMillis; // set
previous_Acc_Millis to current time
}
//========================================END
16) Arduino LED Rotation Display
COMPONENTS AND SUPPLIES
Arduino UNO & Genuino UNO
Or any compatible (i used × 1
sainsmart mega 2560)
ABOUT THIS PROJECT

For the development of this project it is necessary:


* 1 x 12V DC Motor
* 10 x RGB LEDs or LED diode
* Arduino board
* configuration
* 9V battery
* Photo diode
Let's begin:
photo diode refistruje when it crossed over the LEDs and
thus knows that he visited one round.

On the motor shaft you find the card that is attached


Arduino control unit "MEGA 2650".
On the Arduino Mega little need to connect shield with
RGB LEDs.

Shield with RGB LEDs containing 10 LEDs which is


connected to a GND pins are distributed across the board
to the contacts that go to pins 24 to 52 in the Arduino
Mega
Coupled looks like
SCHEMATICS
CODE

Arduino code Led diode

/*Arduino team politehnika


Led display vazdušni
*/
int StartPin=A0;
int t=1700;
void setup(){
pinMode(2,OUTPUT); pinMode(3,OUTPUT);
pinMode(4,OUTPUT); pinMode(5,OUTPUT);
pinMode(6,OUTPUT); pinMode(11,OUTPUT);
pinMode(8,OUTPUT); pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
}
void loop(){
int val=analogRead(StartPin);
while(val < 200){
O();
A();
C();

val=analogRead(StartPin);
}
}
void A(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,0,0,0,0,0,0,0);
signal(1,0,1,1,1,1,1,1,1);
signal(0,1,1,1,0,1,1,1,1);
signal(0,1,1,1,0,1,1,1,1);
signal(1,0,1,1,0,1,1,1,1);
signal(1,1,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void B(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,0,0,0,1);
signal(0,0,0,0,0,1,1,1,0);
signal(0,1,1,1,0,1,1,1,0);
signal(0,1,1,1,0,1,1,1,0);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void C(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,1,1,0);
signal(0,1,1,1,1,1,1,1,0);
signal(0,1,1,1,1,1,1,1,0);
signal(0,1,1,1,1,1,1,1,0);
signal(1,0,0,0,0,0,0,0,1);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void D(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,0,0,0,0,0,1,1);
signal(1,0,1,1,1,1,1,0,1);
signal(0,1,1,1,1,1,1,1,0);
signal(0,1,1,1,1,1,1,1,0);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void E(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,1,1,0);
signal(0,1,1,1,0,1,1,1,0);
signal(0,1,1,1,0,1,1,1,0);
signal(0,1,1,1,0,1,1,1,0);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void Fa(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,1,1,1);
signal(0,1,1,0,1,1,1,1,1);
signal(0,1,1,0,1,1,1,1,1);
signal(0,1,1,0,1,1,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void G(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,0,1,1,1);
signal(1,0,1,1,1,0,0,0,1);
signal(0,1,1,1,1,0,1,1,0);
signal(0,1,1,1,1,0,1,1,0);
signal(0,1,1,1,1,1,1,1,0);
signal(1,0,0,0,0,0,0,0,1);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void H(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,0,0,1,1,1,1);
signal(1,1,1,0,0,1,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void I(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,1,1,0);
signal(0,0,0,0,0,0,0,0,0);
signal(0,1,1,1,1,1,1,1,0);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void J(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,0,0,1);
signal(0,1,1,1,1,1,1,1,0);
signal(0,1,1,1,1,1,1,1,0);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void K(){//LOW=1 HIGH=0
signal(1,1,1,1,1,1,1,1,1);
signal(0,0,0,1,1,1,0,0,0);
signal(1,1,1,0,1,0,1,1,1);
signal(1,1,1,1,0,1,1,1,1);
signal(1,1,1,1,0,1,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void L(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,0);
signal(1,1,1,1,1,1,1,1,0);
signal(1,1,1,1,1,1,1,1,0);
signal(1,1,1,1,1,1,1,1,0);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void M(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,0,0,0,0,0,0,0,0);
signal(0,1,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,1,1,1);
signal(1,0,0,0,1,1,1,1,1);
signal(0,1,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,1,1,1);
signal(1,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void N(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,0,1);
signal(1,1,1,1,1,1,0,1,1);
signal(1,1,1,1,1,0,1,1,1);
signal(1,1,1,1,0,1,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void O(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(0,1,1,1,1,1,1,1,0);
signal(0,1,1,1,1,1,1,1,0);
signal(0,1,1,1,1,1,1,1,0);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void P(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,0,0,0,0,1,1,1,1);
signal(0,1,1,1,1,0,1,1,1);
signal(0,1,1,1,1,0,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void R(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,0);
signal(1,0,0,0,0,1,1,0,1);
signal(0,1,1,1,1,0,0,1,1);
signal(0,1,1,1,1,0,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void S(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void T(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,0,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(0,1,1,1,1,1,1,1,1);
signal(0,0,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void U(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,0,0,0,0,0,0,1,1);
signal(1,1,1,1,1,1,1,0,1);
signal(1,1,1,1,1,1,1,1,0);
signal(1,1,1,1,1,1,1,1,0);
signal(1,1,1,1,1,1,1,0,1);
signal(1,0,0,0,0,0,0,1,1);
signal(1,1,1,1,1,1,1,1,1);
delay(t);
}
void V(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,0,0,0,1,1,1,1,1);
signal(1,1,1,1,1,0,1,1,1);
signal(1,1,1,1,1,1,1,0,1);
signal(1,1,1,1,1,1,1,1,0);
signal(1,1,1,1,1,1,1,0,1);
signal(1,1,1,1,1,0,1,1,1);
signal(0,0,0,0,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
}
void Z(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,1,0,1);
signal(0,0,1,1,1,1,1,0,1);
signal(0,1,0,1,1,1,1,0,1);
signal(0,1,1,0,1,1,1,0,1);
signal(0,1,1,1,0,1,1,0,1);
signal(0,1,1,1,1,0,0,0,1);
signal(1,1,1,1,1,1,1,1,1);
}

void signal(int a,int b,int c,int d,int e,int f,int p,int k,int n){
/*Napomena 1=LOW 0=HIGH*/
if(a==1)digitalWrite(2,LOW);
else digitalWrite(2,HIGH);
if(b==1)digitalWrite(3,LOW);
else digitalWrite(3,HIGH);
if(c==1)digitalWrite(4,LOW);
else digitalWrite(4,HIGH);
if(d==1)digitalWrite(5,LOW);
else digitalWrite(5,HIGH);
if(e==1)digitalWrite(6,LOW);
else digitalWrite(6,HIGH);
if(f==1)digitalWrite(11,LOW);
else digitalWrite(11,HIGH);
if(p==1)digitalWrite(8,LOW);
else digitalWrite(8,HIGH);
if(k==1)digitalWrite(9,LOW);
else digitalWrite(9,HIGH);
if(n==1)digitalWrite(10,LOW);
else digitalWrite(10,HIGH);
delay(t);
}

Arduino code RGB led

/*Arduino team politehnika


Led display vazdušni
*/
int StartPin=A0;
int t=2000;
void setup(){
//Red pins leds dioda
pinMode(28,OUTPUT); pinMode(45,OUTPUT);
pinMode(33,OUTPUT); pinMode(46,OUTPUT);
pinMode(34,OUTPUT); pinMode(51,OUTPUT);
pinMode(39,OUTPUT); pinMode(52,OUTPUT);
pinMode(40,OUTPUT);
//Green pins leds dioda
pinMode(29,OUTPUT); pinMode(42,OUTPUT);
pinMode(30,OUTPUT); pinMode(47,OUTPUT);
pinMode(35,OUTPUT); pinMode(48,OUTPUT);
pinMode(36,OUTPUT); pinMode(53,OUTPUT);
pinMode(41,OUTPUT);
//Blue pins leds dioda
pinMode(26,OUTPUT); pinMode(43,OUTPUT);
pinMode(31,OUTPUT); pinMode(44,OUTPUT);
pinMode(32,OUTPUT); pinMode(49,OUTPUT);
pinMode(37,OUTPUT); pinMode(50,OUTPUT);
pinMode(38,OUTPUT);
}
void loop(){
int val=analogRead(StartPin);
while(val < 200){
O();
AAA();
CC();

val=analogRead(StartPin);
}
}
void A(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,0,0,0,0,0,0,0);
signal(1,0,1,1,1,1,1,1,1);
signal(0,1,1,1,0,1,1,1,1);
signal(0,1,1,1,0,1,1,1,1);
signal(1,0,1,1,0,1,1,1,1);
signal(1,1,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void B(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,0,0,0,1);
signal(0,0,0,0,0,1,1,1,0);
signal(0,1,1,1,0,1,1,1,0);
signal(0,1,1,1,0,1,1,1,0);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void C(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,1,1,0);
signal(0,1,1,1,1,1,1,1,0);
signal(0,1,1,1,1,1,1,1,0);
signal(0,1,1,1,1,1,1,1,0);
signal(1,0,0,0,0,0,0,0,1);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void D(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,0,0,0,0,0,1,1);
signal(1,0,1,1,1,1,1,0,1);
signal(0,1,1,1,1,1,1,1,0);
signal(0,1,1,1,1,1,1,1,0);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void E(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,1,1,0);
signal(0,1,1,1,0,1,1,1,0);
signal(0,1,1,1,0,1,1,1,0);
signal(0,1,1,1,0,1,1,1,0);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void Fa(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,1,1,1);
signal(0,1,1,0,1,1,1,1,1);
signal(0,1,1,0,1,1,1,1,1);
signal(0,1,1,0,1,1,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void G(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,0,1,1,1);
signal(1,0,1,1,1,0,0,0,1);
signal(0,1,1,1,1,0,1,1,0);
signal(0,1,1,1,1,0,1,1,0);
signal(0,1,1,1,1,1,1,1,0);
signal(1,0,0,0,0,0,0,0,1);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void H(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,0,0,1,1,1,1);
signal(1,1,1,0,0,1,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void I(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,1,1,0);
signal(0,0,0,0,0,0,0,0,0);
signal(0,1,1,1,1,1,1,1,0);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void J(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,0,0,1);
signal(0,1,1,1,1,1,1,1,0);
signal(0,1,1,1,1,1,1,1,0);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void K(){//LOW=1 HIGH=0
signal(1,1,1,1,1,1,1,1,1);
signal(0,0,0,1,1,1,0,0,0);
signal(1,1,1,0,1,0,1,1,1);
signal(1,1,1,1,0,1,1,1,1);
signal(1,1,1,1,0,1,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void L(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,0);
signal(1,1,1,1,1,1,1,1,0);
signal(1,1,1,1,1,1,1,1,0);
signal(1,1,1,1,1,1,1,1,0);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void M(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,0,0,0,0,0,0,0,0);
signal(0,1,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,1,1,1);
signal(1,0,0,0,1,1,1,1,1);
signal(0,1,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,1,1,1);
signal(1,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void N(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,0,1);
signal(1,1,1,1,1,1,0,1,1);
signal(1,1,1,1,1,0,1,1,1);
signal(1,1,1,1,0,1,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void O(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(0,1,1,1,1,1,1,1,0);
signal(0,1,1,1,1,1,1,1,0);
signal(0,1,1,1,1,1,1,1,0);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void P(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,0,0,0,0,1,1,1,1);
signal(0,1,1,1,1,0,1,1,1);
signal(0,1,1,1,1,0,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void R(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,0);
signal(1,0,0,0,0,1,1,0,1);
signal(0,1,1,1,1,0,0,1,1);
signal(0,1,1,1,1,0,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void S(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void T(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,0,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,1,1,1);
signal(0,0,0,0,0,0,0,0,0);
signal(0,1,1,1,1,1,1,1,1);
signal(0,0,1,1,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void U(){
signal(1,1,1,1,1,1,1,1,1);
signal(1,0,0,0,0,0,0,1,1);
signal(1,1,1,1,1,1,1,0,1);
signal(1,1,1,1,1,1,1,1,0);
signal(1,1,1,1,1,1,1,1,0);
signal(1,1,1,1,1,1,1,0,1);
signal(1,0,0,0,0,0,0,1,1);
signal(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void V(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,0,0,0,1,1,1,1,1);
signal(1,1,1,1,1,0,1,1,1);
signal(1,1,1,1,1,1,1,0,1);
signal(1,1,1,1,1,1,1,1,0);
signal(1,1,1,1,1,1,1,0,1);
signal(1,1,1,1,1,0,1,1,1);
signal(0,0,0,0,1,1,1,1,1);
signal(1,1,1,1,1,1,1,1,1);
}
void Z(){
signal(1,1,1,1,1,1,1,1,1);
signal(0,1,1,1,1,1,1,0,1);
signal(0,0,1,1,1,1,1,0,1);
signal(0,1,0,1,1,1,1,0,1);
signal(0,1,1,0,1,1,1,0,1);
signal(0,1,1,1,0,1,1,0,1);
signal(0,1,1,1,1,0,0,0,1);
signal(1,1,1,1,1,1,1,1,1);
}
void AA(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(1,1,0,0,0,0,0,0,0);
signal1(1,0,1,1,1,1,1,1,1);
signal1(0,1,1,1,0,1,1,1,1);
signal1(0,1,1,1,0,1,1,1,1);
signal1(1,0,1,1,0,1,1,1,1);
signal1(1,1,0,0,0,0,0,0,0);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void BB(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(1,1,1,1,1,0,0,0,1);
signal1(0,0,0,0,0,1,1,1,0);
signal1(0,1,1,1,0,1,1,1,0);
signal1(0,1,1,1,0,1,1,1,0);
signal1(0,0,0,0,0,0,0,0,0);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void CC(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(0,1,1,1,1,1,1,1,0);
signal1(0,1,1,1,1,1,1,1,0);
signal1(0,1,1,1,1,1,1,1,0);
signal1(0,1,1,1,1,1,1,1,0);
signal1(1,0,0,0,0,0,0,0,1);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void DD(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(1,1,0,0,0,0,0,1,1);
signal1(1,0,1,1,1,1,1,0,1);
signal1(0,1,1,1,1,1,1,1,0);
signal1(0,1,1,1,1,1,1,1,0);
signal1(0,0,0,0,0,0,0,0,0);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void EE(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(0,1,1,1,1,1,1,1,0);
signal1(0,1,1,1,0,1,1,1,0);
signal1(0,1,1,1,0,1,1,1,0);
signal1(0,1,1,1,0,1,1,1,0);
signal1(0,0,0,0,0,0,0,0,0);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void FF(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(0,1,1,1,1,1,1,1,1);
signal1(0,1,1,0,1,1,1,1,1);
signal1(0,1,1,0,1,1,1,1,1);
signal1(0,1,1,0,1,1,1,1,1);
signal1(0,0,0,0,0,0,0,0,0);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void GG(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(1,1,1,1,1,0,1,1,1);
signal1(1,0,1,1,1,0,0,0,1);
signal1(0,1,1,1,1,0,1,1,0);
signal1(0,1,1,1,1,0,1,1,0);
signal1(0,1,1,1,1,1,1,1,0);
signal1(1,0,0,0,0,0,0,0,1);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void HH(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(0,0,0,0,0,0,0,0,0);
signal1(1,1,1,0,0,1,1,1,1);
signal1(1,1,1,0,0,1,1,1,1);
signal1(0,0,0,0,0,0,0,0,0);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void II(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(0,1,1,1,1,1,1,1,0);
signal1(0,0,0,0,0,0,0,0,0);
signal1(0,1,1,1,1,1,1,1,0);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void JJ(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(0,1,1,1,1,1,0,0,1);
signal1(0,1,1,1,1,1,1,1,0);
signal1(0,1,1,1,1,1,1,1,0);
signal1(0,0,0,0,0,0,0,0,0);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void KK(){//LOW=1 HIGH=0
signal1(1,1,1,1,1,1,1,1,1);
signal1(0,0,0,1,1,1,0,0,0);
signal1(1,1,1,0,1,0,1,1,1);
signal1(1,1,1,1,0,1,1,1,1);
signal1(1,1,1,1,0,1,1,1,1);
signal1(0,0,0,0,0,0,0,0,0);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void LL(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(1,1,1,1,1,1,1,1,0);
signal1(1,1,1,1,1,1,1,1,0);
signal1(1,1,1,1,1,1,1,1,0);
signal1(1,1,1,1,1,1,1,1,0);
signal1(0,0,0,0,0,0,0,0,0);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void MM(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(1,0,0,0,0,0,0,0,0);
signal1(0,1,1,1,1,1,1,1,1);
signal1(0,1,1,1,1,1,1,1,1);
signal1(1,0,0,0,1,1,1,1,1);
signal1(0,1,1,1,1,1,1,1,1);
signal1(0,1,1,1,1,1,1,1,1);
signal1(1,0,0,0,0,0,0,0,0);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void NN(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(0,0,0,0,0,0,0,0,0);
signal1(1,1,1,1,1,1,1,0,1);
signal1(1,1,1,1,1,1,0,1,1);
signal1(1,1,1,1,1,0,1,1,1);
signal1(1,1,1,1,0,1,1,1,1);
signal1(0,0,0,0,0,0,0,0,0);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void OO(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(0,0,0,0,0,0,0,0,0);
signal1(0,1,1,1,1,1,1,1,0);
signal1(0,1,1,1,1,1,1,1,0);
signal1(0,1,1,1,1,1,1,1,0);
signal1(0,0,0,0,0,0,0,0,0);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void PP(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(1,0,0,0,0,1,1,1,1);
signal1(0,1,1,1,1,0,1,1,1);
signal1(0,1,1,1,1,0,1,1,1);
signal1(0,0,0,0,0,0,0,0,0);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void RR(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(1,1,1,1,1,1,1,1,0);
signal1(1,0,0,0,0,1,1,0,1);
signal1(0,1,1,1,1,0,0,1,1);
signal1(0,1,1,1,1,0,1,1,1);
signal1(0,0,0,0,0,0,0,0,0);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
/*void SS(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(1,1,1,1,1,1,1,1,1);
signal1(1,1,1,1,1,1,1,1,1);
signal1(1,1,1,1,1,1,1,1,1);
signal1(1,1,1,1,1,1,1,1,1);
signal1(1,1,1,1,1,1,1,1,1);
signal1(1,1,1,1,1,1,1,1,1);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}*/
void TT(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(0,0,1,1,1,1,1,1,1);
signal1(0,1,1,1,1,1,1,1,1);
signal1(0,0,0,0,0,0,0,0,0);
signal1(0,1,1,1,1,1,1,1,1);
signal1(0,0,1,1,1,1,1,1,1);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void UU(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(1,0,0,0,0,0,0,1,1);
signal1(1,1,1,1,1,1,1,0,1);
signal1(1,1,1,1,1,1,1,1,0);
signal1(1,1,1,1,1,1,1,1,0);
signal1(1,1,1,1,1,1,1,0,1);
signal1(1,0,0,0,0,0,0,1,1);
signal1(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void VV(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(0,0,0,0,1,1,1,1,1);
signal1(1,1,1,1,1,0,1,1,1);
signal1(1,1,1,1,1,1,1,0,1);
signal1(1,1,1,1,1,1,1,1,0);
signal1(1,1,1,1,1,1,1,0,1);
signal1(1,1,1,1,1,0,1,1,1);
signal1(0,0,0,0,1,1,1,1,1);
signal1(1,1,1,1,1,1,1,1,1);
}
void ZZ(){
signal1(1,1,1,1,1,1,1,1,1);
signal1(0,1,1,1,1,1,1,0,1);
signal1(0,0,1,1,1,1,1,0,1);
signal1(0,1,0,1,1,1,1,0,1);
signal1(0,1,1,0,1,1,1,0,1);
signal1(0,1,1,1,0,1,1,0,1);
signal1(0,1,1,1,1,0,0,0,1);
signal1(1,1,1,1,1,1,1,1,1);
}

void AAA(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(1,1,0,0,0,0,0,0,0);
signal2(1,0,1,1,1,1,1,1,1);
signal2(0,1,1,1,0,1,1,1,1);
signal2(0,1,1,1,0,1,1,1,1);
signal2(1,0,1,1,0,1,1,1,1);
signal2(1,1,0,0,0,0,0,0,0);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void BBB(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(1,1,1,1,1,0,0,0,1);
signal2(0,0,0,0,0,1,1,1,0);
signal2(0,1,1,1,0,1,1,1,0);
signal2(0,1,1,1,0,1,1,1,0);
signal2(0,0,0,0,0,0,0,0,0);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void CCC(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(0,1,1,1,1,1,1,1,0);
signal2(0,1,1,1,1,1,1,1,0);
signal2(0,1,1,1,1,1,1,1,0);
signal2(0,1,1,1,1,1,1,1,0);
signal2(1,0,0,0,0,0,0,0,1);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void DDD(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(1,1,0,0,0,0,0,1,1);
signal2(1,0,1,1,1,1,1,0,1);
signal2(0,1,1,1,1,1,1,1,0);
signal2(0,1,1,1,1,1,1,1,0);
signal2(0,0,0,0,0,0,0,0,0);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void EEE(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(0,1,1,1,1,1,1,1,0);
signal2(0,1,1,1,0,1,1,1,0);
signal2(0,1,1,1,0,1,1,1,0);
signal2(0,1,1,1,0,1,1,1,0);
signal2(0,0,0,0,0,0,0,0,0);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void FFF(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(0,1,1,1,1,1,1,1,1);
signal2(0,1,1,0,1,1,1,1,1);
signal2(0,1,1,0,1,1,1,1,1);
signal2(0,1,1,0,1,1,1,1,1);
signal2(0,0,0,0,0,0,0,0,0);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void GGG(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(1,1,1,1,1,0,1,1,1);
signal2(1,0,1,1,1,0,0,0,1);
signal2(0,1,1,1,1,0,1,1,0);
signal2(0,1,1,1,1,0,1,1,0);
signal2(0,1,1,1,1,1,1,1,0);
signal2(1,0,0,0,0,0,0,0,1);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void HHH(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(0,0,0,0,0,0,0,0,0);
signal2(1,1,1,0,0,1,1,1,1);
signal2(1,1,1,0,0,1,1,1,1);
signal2(0,0,0,0,0,0,0,0,0);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void III(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(0,1,1,1,1,1,1,1,0);
signal2(0,0,0,0,0,0,0,0,0);
signal2(0,1,1,1,1,1,1,1,0);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void JJJ(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(0,1,1,1,1,1,0,0,1);
signal2(0,1,1,1,1,1,1,1,0);
signal2(0,1,1,1,1,1,1,1,0);
signal2(0,0,0,0,0,0,0,0,0);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void KKK(){//LOW=1 HIGH=0
signal2(1,1,1,1,1,1,1,1,1);
signal2(0,0,0,1,1,1,0,0,0);
signal2(1,1,1,0,1,0,1,1,1);
signal2(1,1,1,1,0,1,1,1,1);
signal2(1,1,1,1,0,1,1,1,1);
signal2(0,0,0,0,0,0,0,0,0);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void LLL(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(1,1,1,1,1,1,1,1,0);
signal2(1,1,1,1,1,1,1,1,0);
signal2(1,1,1,1,1,1,1,1,0);
signal2(1,1,1,1,1,1,1,1,0);
signal2(0,0,0,0,0,0,0,0,0);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void MMM(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(1,0,0,0,0,0,0,0,0);
signal2(0,1,1,1,1,1,1,1,1);
signal2(0,1,1,1,1,1,1,1,1);
signal2(1,0,0,0,1,1,1,1,1);
signal2(0,1,1,1,1,1,1,1,1);
signal2(0,1,1,1,1,1,1,1,1);
signal2(1,0,0,0,0,0,0,0,0);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void NNN(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(0,0,0,0,0,0,0,0,0);
signal2(1,1,1,1,1,1,1,0,1);
signal2(1,1,1,1,1,1,0,1,1);
signal2(1,1,1,1,1,0,1,1,1);
signal2(1,1,1,1,0,1,1,1,1);
signal2(0,0,0,0,0,0,0,0,0);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void OOO(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(0,0,0,0,0,0,0,0,0);
signal2(0,1,1,1,1,1,1,1,0);
signal2(0,1,1,1,1,1,1,1,0);
signal2(0,1,1,1,1,1,1,1,0);
signal2(0,0,0,0,0,0,0,0,0);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void PPP(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(1,0,0,0,0,1,1,1,1);
signal2(0,1,1,1,1,0,1,1,1);
signal2(0,1,1,1,1,0,1,1,1);
signal2(0,0,0,0,0,0,0,0,0);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void RRR(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(1,1,1,1,1,1,1,1,0);
signal2(1,0,0,0,0,1,1,0,1);
signal2(0,1,1,1,1,0,0,1,1);
signal2(0,1,1,1,1,0,1,1,1);
signal2(0,0,0,0,0,0,0,0,0);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void SSS(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(1,1,1,1,1,1,1,1,1);
signal2(1,1,1,1,1,1,1,1,1);
signal2(1,1,1,1,1,1,1,1,1);
signal2(1,1,1,1,1,1,1,1,1);
signal2(1,1,1,1,1,1,1,1,1);
signal2(1,1,1,1,1,1,1,1,1);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void TTT(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(0,0,1,1,1,1,1,1,1);
signal2(0,1,1,1,1,1,1,1,1);
signal2(0,0,0,0,0,0,0,0,0);
signal2(0,1,1,1,1,1,1,1,1);
signal2(0,0,1,1,1,1,1,1,1);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void UUU(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(1,0,0,0,0,0,0,1,1);
signal2(1,1,1,1,1,1,1,0,1);
signal2(1,1,1,1,1,1,1,1,0);
signal2(1,1,1,1,1,1,1,1,0);
signal2(1,1,1,1,1,1,1,0,1);
signal2(1,0,0,0,0,0,0,1,1);
signal2(1,1,1,1,1,1,1,1,1);
delayMicroseconds(t);
}
void VVV(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(0,0,0,0,1,1,1,1,1);
signal2(1,1,1,1,1,0,1,1,1);
signal2(1,1,1,1,1,1,1,0,1);
signal2(1,1,1,1,1,1,1,1,0);
signal2(1,1,1,1,1,1,1,0,1);
signal2(1,1,1,1,1,0,1,1,1);
signal2(0,0,0,0,1,1,1,1,1);
signal2(1,1,1,1,1,1,1,1,1);
}
void ZZZ(){
signal2(1,1,1,1,1,1,1,1,1);
signal2(0,1,1,1,1,1,1,0,1);
signal2(0,0,1,1,1,1,1,0,1);
signal2(0,1,0,1,1,1,1,0,1);
signal2(0,1,1,0,1,1,1,0,1);
signal2(0,1,1,1,0,1,1,0,1);
signal2(0,1,1,1,1,0,0,0,1);
signal2(1,1,1,1,1,1,1,1,1);
}

void signal(int a,int b,int c,int d,int e,int f,int p,int k,int n){
/*Napomena 1=LOW 0=HIGH*/
if(a==1)digitalWrite(52,LOW);
else digitalWrite(52,HIGH);
if(b==1)digitalWrite(51,LOW);
else digitalWrite(51,HIGH);
if(c==1)digitalWrite(46,LOW);
else digitalWrite(46,HIGH);
if(d==1)digitalWrite(45,LOW);
else digitalWrite(45,HIGH);
if(e==1)digitalWrite(40,LOW);
else digitalWrite(40,HIGH);
if(f==1)digitalWrite(39,LOW);
else digitalWrite(39,HIGH);
if(p==1)digitalWrite(34,LOW);
else digitalWrite(34,HIGH);
if(k==1)digitalWrite(33,LOW);
else digitalWrite(33,HIGH);
if(n==1)digitalWrite(28,LOW);
else digitalWrite(28,HIGH);
delayMicroseconds(t);
}

void signal1(int a,int b,int c,int d,int e,int f,int p,int k,int n){
/*Napomena 1=LOW 0=HIGH*/
if(a==1)digitalWrite(53,LOW);
else digitalWrite(53,HIGH);
if(b==1)digitalWrite(48,LOW);
else digitalWrite(48,HIGH);
if(c==1)digitalWrite(47,LOW);
else digitalWrite(47,HIGH);
if(d==1)digitalWrite(42,LOW);
else digitalWrite(42,HIGH);
if(e==1)digitalWrite(41,LOW);
else digitalWrite(41,HIGH);
if(f==1)digitalWrite(36,LOW);
else digitalWrite(36,HIGH);
if(p==1)digitalWrite(35,LOW);
else digitalWrite(35,HIGH);
if(k==1)digitalWrite(30,LOW);
else digitalWrite(30,HIGH);
if(n==1)digitalWrite(29,LOW);
else digitalWrite(29,HIGH);
delayMicroseconds(t);
}

void signal2(int a,int b,int c,int d,int e,int f,int p,int k,int n){
/*Napomena 1=LOW 0=HIGH*/
if(a==1)digitalWrite(50,LOW);
else digitalWrite(50,HIGH);
if(b==1)digitalWrite(49,LOW);
else digitalWrite(49,HIGH);
if(c==1)digitalWrite(44,LOW);
else digitalWrite(44,HIGH);
if(d==1)digitalWrite(43,LOW);
else digitalWrite(43,HIGH);
if(e==1)digitalWrite(38,LOW);
else digitalWrite(38,HIGH);
if(f==1)digitalWrite(37,LOW);
else digitalWrite(37,HIGH);
if(p==1)digitalWrite(32,LOW);
else digitalWrite(32,HIGH);
if(k==1)digitalWrite(31,LOW);
else digitalWrite(31,HIGH);
if(n==1)digitalWrite(26,LOW);
else digitalWrite(26,HIGH);
delayMicroseconds(t);
}
17) Arduino Fast IR Game with Any Remote Control
COMPONENTS AND SUPPLIES
Arduino Nano R3
It also worked with an UNO × 1

Adafruit Standard LCD - 16x2


White on Blue
× 1
with I2C connection

IR receiver (generic) × 1
Jumper wires (generic)
× 11

Any Remote Control


× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

I didn't use the IR receiver until this project, so I decided


to make the control via remote control. It was also
important for me to make the program learn which keys
you want to use. So you don not have to figure out what
kind of value you need for all the keys you use and put it
in the code. You just teach the game once you started it
which key ist up, down, left and so on. Well, you have to
do this every time you reset the board...
You can see a level 3 gameplay. An 'arrow down' coming
from the left. Push the key for 'arrow down'
Everytime you hit a wrong key, the symbol went to the
other side of the screen or you hit the key while the
symbol is behind a fence the score gets less. Otherwise
the score goes up.

Left corner shows level, right corner shows Score. Score


less then 0 means 'Game Over'
SCHEMATICS

I did not find an LCD with I2C board (LCD 1602 +


I2C HD44780 Modul). So I just made a shematic. My
IR Diode (VS1838B LIRC) is connected like in this
sheme, but make shure you make the right
connection!! (Data: orange, GND: black, VCC: red).
You can use an Arduino Nano or Uno.
CODE
#include <IRremote.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
char up = 3;
char down = 1;
char ok = 2;

// Define 3 characters for the LCD Display


byte up1[8] = {
B00100,
B01110,
B10101,
B00100,
B00100,
B00100,
B00100,
B00100
};

byte down1[8] = {
B00100,
B00100,
B00100,
B00100,
B00100,
B10101,
B01110,
B00100
};

byte ok1[8] = {
B01110,
B01010,
B01110,
B10000,
B10100,
B11000,
B10100,
B10010
};

int RECV_PIN = 11; // IR Sensor on Pin 11


char* howtoplay[23] = {
"> FAST IR GAME <",
" Press key ",
"You have to", // if you don't want this howToPlay you can delete from
here ...
"press the key,",
"that you see on",
"the screen, when",
"it is beetween",
"the fences (#).",
"It ist getting",
"faster and there",
"will be symbols",
"that you do not",
"have to hit!",
"Try to get to",
"Level 10 and win",
"the game. Before",
"you start, you",
"have to define",
"the keys on your",
"remote control",
"to play the game", // ... until here. Leave the last lines for propper work!
" Have fun !!",
""
};

String keyNames[] = {"up", "down", "right", "left", "ok", "+", "-", "#",
"*"};
String keySymb[] = {"", "", "", "", "", "", "", "", ""};
long keys[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int keycount = 7;

int lev;
int xpos = 1;
int xadd = 1;
int xleft;
int xright;
int xstart = 0;
int xend = 15;

int actSym = 0;
int score; // All together score
int scorePerLev; // Symbols in actual level
int scoreNextLev = 50; // Symbols until next level

int gameState = -1;

bool pressed = false;

IRrecv irrecv(RECV_PIN);
decode_results results;

LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16
chars and 2 line display

void setup()
{
Serial.begin(9600);
lcd.init(); // initialize the lcd
lcd.backlight();
lcd.createChar(up, up1);
lcd.createChar(down, down1);
lcd.createChar(ok, ok1);
keySymb[0] = "\3";
keySymb[1] = "\1";
keySymb[2] = "\176";
keySymb[3] = "\177";
keySymb[4] = "\2";
keySymb[5] = "+";
keySymb[6] = "-";
keySymb[7] = "#";
keySymb[8] = "*";

irrecv.enableIRIn(); // Start the receiver


info(); //howtoplay show once at the start, can be removed when you know
how to play
randomSeed(analogRead(1));
}

void loop()
{

// define keys only once


// gameState= -1
// ################################
if (gameState == -1) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Define Keys to");
lcd.setCursor(0, 1);
lcd.print("play the game...");
delay(3000);
pressed = false;
for (int i = 0; i < keycount; i++) { // 0 und 5
pressed = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Key for:");
lcd.print(keyNames[i]);
while (pressed != true) {
if (irrecv.decode(&results)) {
keys[i] = results.value;
lcd.setCursor(0, 1);
lcd.print(" ok!");
Serial.println(keys[i]);
delay(500);
irrecv.resume(); // Receive the next value
pressed = true;
}
}
pressed = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Repaet key!");
lcd.print(keyNames[i]);
irrecv.resume();
while (pressed != true) {
if (irrecv.decode(&results)) {
if (keys[i] == results.value) {
lcd.setCursor(0, 1);
lcd.print("is the same!");
delay(500);
pressed = true;
} else {
lcd.setCursor(0, 1);
lcd.print("wrong!");
delay(500);
lcd.setCursor(0, 1);
lcd.print(" ");
}
irrecv.resume();
}
}
}
gameState = 0; // ok to select level
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Keys done!");
delay(2000);
}

// Select Level
// gameState=0
//###########################
if (gameState == 0) {
lev = 1;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Select Level+ok");
lcd.setCursor(0, 1);
lcd.print("Level: ");
lcd.print(lev);
irrecv.resume();
pressed = false;
Serial.println("Level");
Serial.println(pressed);
while (pressed != true) {
if (irrecv.decode(&results)) {
Serial.println(results.value);
if (results.value == keys[0]) lev++;
if (results.value == keys[1]) lev--;
if (results.value == keys[4]) pressed = true;
if (lev < 1) lev = 1;
if (lev > 10) lev = 10;
lcd.setCursor(7, 1);
lcd.print(lev);
lcd.print(" ");
irrecv.resume();
}
delay(250);
}
lcd.setCursor(0, 0);
lcd.print("Ok! Play in ");
delay(2000);
lcd.clear();
gameState = 1; // Main gameplay
score = 0;
scorePerLev = 0;
keycount = 7;
xleft = 4;
xright = 11;
drawField("");
irrecv.resume();
Serial.println("Level Set");
}

// Main Game
// gameState=1
//###############################
if (gameState == 1) {
xpos = 0;
xadd = 1;
int k = 0;
bool rightkey = false;
pressed = false;
actSym = floor(random(0, keycount));
while (pressed != true) {
Serial.println(xpos);
if (irrecv.decode(&results)) {
for (int i = 0; i < keycount; i++) {
if (results.value == keys[i]) {
rightkey = true;
k = i;
}
}
if (rightkey == true) {
scorePerLev++;
if (xpos <= xleft || xpos >= xright) {
score = score - (4 + lev);
// negativ sound
}
if (actSym == k) {
lcd.setCursor(xpos, 1);
lcd.print(" ");
score++;
drawField("");
changeDirection();
} else {
score = score - (2 + lev);
drawField(" :( ");
// negativ sound
}
actSym = floor(random(0, keycount));
rightkey = false;
}
delay(10);
irrecv.resume();
if (scorePerLev == scoreNextLev) {
scorePerLev = 0;
lev++;
drawField("");
if (lev < 11) {
lcd.setCursor(0, 1);
lcd.print("Next level!");
waitForOK();
// Check for score and display message here later
lcd.setCursor(0, 1);
lcd.print(" ");
} else {
gameState = 5;
pressed = true;
}
}
}
lcd.setCursor(xpos, 1);
lcd.print(" ");
xpos = xpos + xadd;
if (xpos == xend + 1 || xpos == xstart - 1) {
if (actSym < 7) {
score = score - (2 * (lev + 5));
drawField(" :( ");
} else {
drawField("");
}
changeDirection();
actSym = floor(random(0, keycount));
// negativ sound
}
lcd.setCursor(xpos, 1);
lcd.print(keySymb[actSym]);
delay(200 - (lev * 10));
if (score < 0) {
gameState = 9;
pressed = true;
}
} // Main Game loop End

}
// Win
// ##################
if (gameState == 5) {
// positiv sound
lcd.setCursor(0, 1);
lcd.print("You win the Game");
lcd.setCursor(0, 0);
lcd.print("Bravo! ");
waitForOK();
gameState = 0;
}

// Game Over
// ##################
if (gameState == 9) {
// negativ sound
for (int i = 0; i < 5; i++) {
lcd.setCursor(0, 1);
lcd.print(" ");
delay(200);
lcd.setCursor(0, 1);
lcd.print(" Game over! ");
delay(300);
}
waitForOK();
gameState = 0;
}

void info () {
int i = 0;
while (howtoplay[i] != "") {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(howtoplay[i]);
lcd.setCursor(0, 1);
lcd.print(howtoplay[i + 1]);
delay(300);
waitForKey();
i++;
}
irrecv.resume();
}

void drawField(String empty) {


Serial.println("drawField");
int SCur;
if (empty == "") empty = " ";
lcd.setCursor(0, 0);
lcd.print("################");
if (lev > 3) {
xleft = floor(random(4, 7));
xright = xleft + 7;
if (lev > 6) xright = xleft + 6;
if (lev > 9) xright = xleft + 5;
}
if (lev > 4) keycount = 8;
if (lev > 6) keycount = 9;
lcd.setCursor(xleft + 1, 0);
lcd.print(empty.substring(0, xright - xleft - 1));
lcd.setCursor(0, 0);
lcd.print("L");
lcd.print(lev);
if (score < 1000) SCur = 13;
if (score < 100) SCur = 14;
if (score < 10) SCur = 15;
if (score < 0) SCur = 14;
lcd.setCursor(SCur, 0);
lcd.print(score);
}

void changeDirection() {
xpos = xstart;
xadd = 1;
if (lev > 3) {
int dir = floor(random(0, 2));
if (dir == 1) {
xpos = xend;
xadd = -1;
}
}
}

void waitForKey () {
bool press = false;
irrecv.resume();
while (press == false) {
if (irrecv.decode(&results)) {
if (results.value != 0) press = true;
irrecv.resume();
delay(200);
}
}
}

void waitForOK() {
delay(1000);
bool press = false;
irrecv.resume();
while (press == false) {
if (irrecv.decode(&results)) {
if (results.value == keys[4]) press = true;
irrecv.resume();
delay(200);
}
}
}
18) Arduino DIY PH Dosing Pump
COMPONENTS AND SUPPLIES

Arduino UNO & Genuino UNO


× 1

pH UP/pH DOWN Solution


× 1

Resistor 4.75k ohm × 2


5 pin header
× 2

Atlas Scientific Peristaltic Pump


Kit
× 2

Atlas Scientific pH Sensor Kit


× 1

Breadboard (generic)
× 1

Male/Male Jumper Wires


× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

We will be making a pH dosing system. It has the


capability of maintaining the sample within a defined
pH range, in this case, 8-8.5. If the readings go out of
range, small amounts of either pH UP or pH
DOWN solution is automatically added to the sample
until the readings return within the limits. The pH
level will be monitored by the EZO pH sensor while
the UP/DOWN solutions will be dispensed
using peristaltic pumps. Operation is via I2C protocol
and readings are displayed on the Arduino serial
monitor
Step 1: Pre-assembly Requirements
a) Calibrate pH sensor and pumps.
b) Set the pH sensor and pumps protocol to I2C and
each device needs a unique I2C address. In accordance
with the sample code for this project, the following
addresses are used: pH sensor address is 99, pump for
pH UP solution is 103 and pump for pH DOWN
solution is 104. For information on how to change
between modes and set addresses, refer to this LINK.
The calibration and the switch to I2C MUST be done
before implementing the sensors into this project.
Step 2: Assemble Hardware

Connect the hardware as shown in the schematic.


The peristaltic pump has two power lines. The line
that goes to the Arduino's 5V pin is for the circuitry
attached to the pump while the external 12V supply is
for the pump itself. The five pin headers are used to
mount the data cables of the pumps to the breadboard
after which jumper wires make the appropriate
connections to the Arduino.
The two 4.7kΩ resistors serve as pull up resistors for
the SDA (Serial Data) and SCL (Serial Clock) lines.
Step 3: Load Program onto Arduino
The code for this project makes use of a customized
library and header file for the EZO circuits in I2C
mode. You will have to add them to your Arduino IDE
in order to use the code. The steps below include the
process of making this addition to the IDE.
a) Download Ezo_I2c_lib, a zip folder from GitHub
onto your computer.
b) On your computer, open the Arduino IDE (You can
download the IDE from HERE if you do not have it).
c) In the IDE, go to Sketch -> Include Library ->
Add.ZIP Library -> Select the Ezo_I2c_lib folder you
just downloaded. The appropriate files are now
included.
d) Copy the code from pH_dosing_pump onto your
Arduino work panel. You can also access this code
from the Ezo_I2c_lib folder downloaded above.
e) Compile and upload the pH_dosing_pump code to
your Arduino UNO.
f) Readings are displayed on the serial monitor. To
open the serial monitor, go to Tools -> Serial
Monitor or press Ctrl+Shift+M on your keyboard. Set
the baud rate to 9600 and select "Carriage return". The
pH readings should display and the pumps will be
triggered accordingly to dispense pH UP and pH
DOWN solution. Remember this sample code takes
into consideration the pH between 8-8.5, so the pumps
will only turn on when out of this range.

SCHEMATICS
CODE

/*

It was tested on an Arduino UNO.


Real time pH monitoring is done using the EZO pH
sensor and two EZO PMP. The pumps dispense pH UP
and pH DOWN solutions into the sample and they are
triggered in accordance with the current pH reading.
The goal is to maintain the pH level of the sample
between 8 and 8.5
The sensors must be calibrated and switched to I2C
mode before using this code. The ability to send
commands to the sensors is not incorporated here.
After uploading the code to your arduino, open the serial
monitor, set the baud rate to 9600 and select "Carriage
return". The pH dosing system is now active.*/

#include <Ezo_i2c.h> //include the EZO I2C library


from https://github.com/Atlas-Scientific/Ezo_I2c_lib
#include <Wire.h> //include arduinos i2c library
Ezo_board PH = Ezo_board(99, "PH");
//creat a PH circuit object, whose address is 99 and name
is "PH"
Ezo_board PMP_UP = Ezo_board(103,
"PMP_UP"); //create a pump circuit object,
whose address is 103 and name is "PMP_UP". This
pump dispenses pH up solution.
Ezo_board PMP_DOWN = Ezo_board(104,
"PMP_DOWN"); //create a pump circuit object,
whose address is 104 and name is "PMP_DOWN". This
pump dispenses pH down solution.

bool reading_request_phase = true;


//selects our phase

uint32_t next_poll_time = 0;
//holds the next time we receive a response, in
milliseconds
const unsigned int response_delay = 1000;
//how long we wait to receive a response, in milliseconds

void setup() {
Wire.begin(); //start the I2C
Serial.begin(9600); //start the
serial communication to the computer
}
void loop() {
if (reading_request_phase) { //if
were in the phase where we ask for a reading

//send a read command. we use this command instead of


PH.send_cmd("R");
//to let the library know to parse the reading
PH.send_read_cmd();

next_poll_time = millis() + response_delay;


//set when the response will arrive
reading_request_phase = false; //switch
to the receiving phase
}
else { //if were in the
receiving phase
if (millis() >= next_poll_time) { //and its
time to get the response

receive_reading(PH); //get the


reading from the PH circuit
Serial.print(" ");

if (PH.get_last_received_reading() <= 8)
{ //test condition against pH reading
Serial.println("PH LEVEL LOW,PMP_UP = ON");
PMP_UP.send_cmd_with_num("d,", 0.5); //if
condition is true, send command to turn on pump (called
PMP_UP) and dispense pH up solution, in amounts of
0.5ml. Pump turns clockwise.
}
else {
PMP_UP.send_cmd("x"); //if
condition is false, send command to turn off pump
(called PMP_UP)
}

if (PH.get_last_received_reading() >= 8.5)


{ //test condition against pH reading
Serial.println("PH LEVEL HIGH,PMP_DOWN = ON");
PMP_DOWN.send_cmd_with_num("d,", -0.5);
//if condition is true, send command to turn on pump
(called PMP_DOWN) and dispense pH down solution,
in amounts of 0.5ml. Pump turns counter-clockwise.
}
else {
PMP_DOWN.send_cmd("x"); //if
condition is false, send command to turn off pump
(called PMP_DOWN)
}

Serial.println();
reading_request_phase = true; //switch
back to asking for readings
}
}
}

void receive_reading(Ezo_board &Sensor)


{ // function to decode the reading after the
read command was issued

Serial.print(Sensor.get_name()); Serial.print(": "); //


print the name of the circuit getting the reading

Sensor.receive_read_cmd(); //get
the response data and put it into the [Sensor].reading
variable if successful

switch (Sensor.get_error()) { //switch


case based on what the response code is.
case Ezo_board::SUCCESS:
Serial.print(Sensor.get_last_received_reading());
//the command was successful, print the reading
break;

case Ezo_board::FAIL:
Serial.print("Failed "); //means the
command has failed.
break;

case Ezo_board::NOT_READY:
Serial.print("Pending "); //the
command has not yet been finished calculating.
break;

case Ezo_board::NO_DATA:
Serial.print("No Data "); //the sensor
has no data to send.
break;
}
}
19) Arduino Simple Lap Counter for Swimming
COMPONENTS AND SUPPLIES
Magconn Developer Kit
× 1

Arduino Nano R3
× 1

USB Li-Po Battery Charger × 1


PCBA
Li-Po Battery 900mAh
× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

Now the weather here is very hot because it is


summer. I went to the pool with my primary school
son to avoid the heat, and I saw people swimming
several times on the swimming track. How many laps
did they turn? When you learn to swim, count how
many turns you have made to measure your
momentum. But most people forget the count. There is
a wrist watch or a finger counter, but it is a little
uncomfortable when swimming. When swimming, it is
better not to do anything. I made an intuitively
waterproof lap-counter. Simply press it to go up once.
I would like to implement many functions, but step by
step.
Materials
There are some great conditions. The first is battery
use, the second is waterproof, and the third is
convenience. The battery should be rechargeable.
Because you do not have to open the case when it's
completely discharged. So I found connectors and
switches that are waterproof. The case recycled the
phone accessary case. I think that it was good to
recycle when I finished.
Assembling the Case
The lap-counter has a waterproof toggle switch and a
waterproof Magconn connector. I bought the Lithium-
Polymer battery and Lithium-rechargeable PCBA that
I had inexpensively. The back side of the Samsung
mobile phone case was machined to match the
Magconn connector, and the magnet was attached and
closed with epoxy. I added four more because I think
one magnet is not enough. The connector is closed
with epoxy and glue.
Build Circuit
I built a circuit on the breadboard and implemented
the behavior. The counter is fine. The four corners of
the switch are for height adjustment. After confirming
that it works well, I put it in the case and finished it
with silicon. When using glue gun, be careful because
case may melt at high temperature.
Waterproofing should be good. It was made better than
I thought. I was worried about the phone case, but the
recycle case became the key point.
Waterproof Test
I tried the waterproof test in the water of the pool.
There is a magnet on the back of the case, and if there
is an iron plate on the outside, it attaches
unconditionally. When there is no iron plate, a sucker
plate can be used.

SCHEMATICS
CODE

const byte numeral[10] = {


//ABCDEFG dp//
B11111100, //0
B01100000, //1
B11011010, //2
B11110010, //3
B01100110, //4
B10110110, //5
B00111110, //6
B11100000, //7
B11111110, //8
B11100110, //9
};

// dp, G, F, E, D, C, B, A
const int segmentPins[8] = { 9,8,7,6,5,4,3,2 };
const int nbrDigits = 2;
const int digitPins[nbrDigits] = { 12,13 };
const int buttonPin = 11;
int buttonState; // the current reading from the input pin
int lastButtonState = HIGH; // the previous reading from the input pin
unsigned long lastDebounceTime = 0; // the last time the output pin was
toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the
output flickers
int value = -1;

void setup()
{
for(int i=0; i<8; i++)
{
pinMode(segmentPins[i], OUTPUT);
}
for(int i=0; i<nbrDigits; i++)
{
pinMode(digitPins[i], OUTPUT);
digitalWrite(digitPins[i], 1);
}
pinMode(buttonPin, INPUT);
digitalWrite(buttonPin, HIGH); //
}

void loop()
{
int reading = digitalRead(buttonPin);
if (reading != lastButtonState) { // reset the debouncing timer
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading != buttonState) {
buttonState = reading;

if (buttonState == HIGH) {
value = value + 1;
}
}
}
lastButtonState = reading;
showNumber(value);
}

void showNumber(int number)


{
if(number == 0)
showDigit(0, nbrDigits-1);
else
{
for(int digit = nbrDigits-1; digit>=0; digit--)
{
if (number>0)
{
showDigit(number%10, digit);
number = number/10;
}
}
}
}

void showDigit(int number, int digit)


{
//boolean isBitSet;
digitalWrite(digitPins[digit],0); //1
for (int segment = 1; segment <8 ; segment++) //segment A ~ dp
{
boolean isBitSet = bitRead(numeral[number], segment); //byte
numeral[number] segment
digitalWrite(segmentPins[segment], isBitSet);
}
//isBitSet = !isBitSet
delay(5);
digitalWrite(digitPins[digit], 1);
}
20) Arduino Add Animated Lighting to Your Projects
COMPONENTS AND SUPPLIES

Arduino Nano R3
× 1

NeoPixel strip
× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

Simple DIY Animated Marquee Lighting


This a simple tutorial to add animated lighting to your
arcade cabinet or other projects. It can be used for
(back-)lighting marquees and many other purposes.
You will need an Arduino Nano (or compatible board),
a strip of NeoPixels, and 3 wires.

Short Setup
Hardware: Solder three wires from the Arduino Nano
to the NeoPixel strip: 5V, digital signal (I chose pin 2
on the Arduino) and ground.
Tip: Use a piece of heat shrink to tie the cables
together, especially the led strip (make sure the solder
connections are covered). This will prevent the solder
connections from coming loose.
Code: Set the number of LEDs of the connected strip
in the sketch code, upload it to the Arduino and test it.
I used a 'walking', flashing and pulsing animation in
the sketch, only using the color white. You can adjust
the code to do all sorts of animations and use many
colors. Or just use simple a backlight, whatever you
prefer.
The build: I cut 2 pieces of cardboard which fit snugly
in my cabinet. One piece is used as the background to
glue the neopixel strip on. The other strip is placed flat
behind the bottom of the marquee to prevent light
from the neopixels shining down directly. Afterward I
had to cut off some small edges to make it fit my
cabinet.
I put a few pieces of gaffa tape on the cardboard to
make them black. I glued the neopixel strip on the
cardboard and taped the wires and nano to the back of
the cardboard.
Put the 2 parts in the cabinet and attach a USB cable
from the nano to a 5V power source. In my cabinet it
is connected to a USB port of a Raspberry Pi.
Then place the stock marquee back or create your own
to customize your build. I created a simple one,
printed it on photo paper and cut it to fit the marquee.
Tip: The end result will be even better if you have
your design printed on film by a professional printing
company.
Libraries
The sketch needs one library:
Adafruit NeoPixel library
SCHEMATICS
CODE

/*
*************************************************************
*********
* Marquee lighting with Neopixels by ericBcreator
* simple script for lighting an (arcade) marquee
*************************************************************
*********
*
* components:
* - Neopixel strip
* - Arduino Nano
*
* This code is free for personal use, not for commercial purposes.
* Please leave this header intact.
*/

//
// include the libraries
//

#include <Adafruit_NeoPixel.h>

#define PIN
2
// define the pin the strip is
connected to

//
// setup variables and initialize the neopixel strip
//

int numOfLeds =
11;
// the numbers of leds on the strip
int minBrightness =
80;
// the minimum brightness of the pulsing and flashing (0-255)
int maxBrightness =
255;
// the maximum brightness of the pulsing and flashing (0-255)
int walkingLedsDelay =
250; //
the delay in ms for the walking leds
int flashDelay =
250;
// the delay in ms for the flashing leds
int numOfFlashLoops =
3;
// the number of times the leds flash
int numOfPulseLoops =
10;
// the number of times the leds puls from min to max
int pulseDelay =
20;
// the delay in ms when pulsing from min to max and
vice verse

Adafruit_NeoPixel strip = Adafruit_NeoPixel(numOfLeds, PIN);

//
// setup
//

void setup() {
strip.begin();
}

//
// main loop
//

void loop() {
walkingLeds();
// show the walking leds
flashLeds();
// flash the leds

for (int i = 0; i < numOfPulseLoops; i++) // puls the leds


pulseBrightness();
}

//
// functions
//

void walkingLeds() {
setLedColorsToZero();
strip.setBrightness(maxBrightness);
strip.show();

for (int x = numOfLeds; x > 0; x--) {


strip.setPixelColor(x, strip.Color(255, 255, 255));
strip.show();
delay(walkingLedsDelay );
strip.setPixelColor(x, 0);
strip.show();
}
}

void flashLeds() {
setLedColors();

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


strip.setBrightness(maxBrightness);
strip.show();
delay(flashDelay );

strip.setBrightness(minBrightness);
strip.show();
delay(flashDelay );
}
}
void pulseBrightness() {
setLedColors();

for (int i = minBrightness; i < maxBrightness; i++) {


strip.setBrightness(i);
strip.show();
delay(pulseDelay);
}

for (int i = maxBrightness; i > minBrightness; i--) {


strip.setBrightness(i);
strip.show();
delay(pulseDelay);
}
}

void setLedColors() {
for (int x = 0; x < numOfLeds; x++)
strip.setPixelColor(x, strip.Color(255, 255, 255));
}

void setLedColorsToZero() {
for (int x = 0; x < numOfLeds; x++)
strip.setPixelColor(x, strip.Color(0, 0, 0));
}

21) Arduino 8X8 Matrix LED Snake Game


COMPONENTS AND SUPPLIES
PHPoC Shield for Arduino
× 1

Arduino UNO & Genuino


UNO
× 1

Adafruit 8x8 Bi-color LED × 1


Matrix

Jumper wires (generic)


× 1

ABOUT THIS PROJECT


It is the snake game on the 8x8 matrix LED by
smartphone motion.
When user tilts the smartphone to one of 4 directions,
the direction value is sent to Arduino through HTML5
WebSocket. Then the snake changes its direction.
SCHEMATICS

LED ----- PHPoC Shield


VCC ----- 5V
GND ----- GND
SDA ----- A4(SDA)
SCL ----- A5(SCL)
CODE

Arduino Source code

/***************************************************
This is a library for our I2C LED Backpacks

Designed specifically to work with the Adafruit LED Matrix backpacks


----> http://www.adafruit.com/products/872
----> http://www.adafruit.com/products/871
----> http://www.adafruit.com/products/870

These displays use I2C to communicate, 2 pins are required to


interface. There are multiple selectable I2C addresses. For backpacks
with 2 Address Select pins: 0x70, 0x71, 0x72 or 0x73. For backpacks
with 3 Address Select pins: 0x70 thru 0x77
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!

Written by Limor Fried/Ladyada for Adafruit Industries.


BSD license, all text above must be included in any redistribution
****************************************************/

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_LEDBackpack.h>
#include "SPI.h"
#include "Phpoc.h"

PhpocServer server(80);

// LED face
static const uint8_t PROGMEM
smile_bmp[] =
{ B00111100,
B01000010,
B10100101,
B10000001,
B10100101,
B10011001,
B01000010,
B00111100 },
frown_bmp[] =
{ B00111100,
B01000010,
B10100101,
B10000001,
B10011001,
B10100101,
B01000010,
B00111100 };
// direction
const int TOP = 0;
const int RIGHT = 1;
const int BOTTOM = 2;
const int LEFT = 3;

// Snake
const int MAX_SNAKE_LENGTH = 15;

// Variables
Adafruit_BicolorMatrix matrix = Adafruit_BicolorMatrix(); // Display
int direction = TOP; // direction of movement
int snakeX[MAX_SNAKE_LENGTH]; // X-coordinates of
snake
int snakeY[MAX_SNAKE_LENGTH]; // Y-coordinates of
snake
int snakeLength = 1; // nr of parts of snake
unsigned long prevTime = 0; // for gamedelay (ms)
unsigned long delayTime = 500; // Game step in ms

int fruitX, fruitY;


unsigned long fruitPrevTime = 0;
unsigned long fruitBlinkTime = 1000/250;
int fruitLed = LED_RED;
int matrixColor;

void setup(){
Serial.begin(9600);
while(!Serial)
;

Phpoc.begin(PF_LOG_SPI | PF_LOG_NET);
server.beginWebSocket("snake");

Serial.print("WebSocket server address : ");


Serial.println(Phpoc.localIP());

Serial.println("Game is started.");
randomSeed(analogRead(0));
// Init led matrix
matrix.begin(0x70);
matrix.setRotation(3);

// init snake
snakeX[0] = 4;
snakeY[0] = 7;
for(int i=1; i<MAX_SNAKE_LENGTH; i++)
snakeX[i] = snakeY[i] = -1;

makeFruit();

printString("S");
}

void loop(){
checkButtons();

unsigned long currentTime = millis();


if(currentTime - prevTime >= delayTime)
{
nextstep();
prevTime = currentTime;
}

draw();
}

void checkButtons(){

// wait for a new client:


PhpocClient client = server.available();

if (client)
{
if (client.available() > 0)
{
// read the bytes incoming from the client:
char thisChar = client.read();

if(thisChar == '0')
direction = TOP;
if(thisChar == '1')
direction = LEFT;
if(thisChar == '2')
direction = RIGHT;
if(thisChar == '3')
direction = BOTTOM;
}
}
}

void draw(){
matrix.clear();
drawSnake();
drawFruit();
matrix.writeDisplay();
}

void drawSnake(){
for(int i=0; i<snakeLength; i++)
matrix.drawPixel(snakeX[i], snakeY[i], LED_GREEN);
}

void drawFruit(){
if(inPlayField(fruitX, fruitY)){
unsigned long currenttime = millis();
if(currenttime - fruitPrevTime >= fruitBlinkTime)
{
fruitLed = (fruitLed == LED_RED) ? LED_OFF : LED_RED;
fruitPrevTime = currenttime;
}
matrix.drawPixel(fruitX, fruitY, fruitLed);
}
}

boolean inPlayField(int x, int y){


return (x>=0) && (x<8) && (y>=0) && (y<8);
}

void nextstep(){
for(int i = snakeLength; i > 0; i--)
{
if((direction == RIGHT) && (snakeX[0]-snakeLength == 7))
snakeX[0] = -1;
else if((direction == LEFT) && (snakeX[0]+ snakeLength == 0))
snakeX[0] = 8;
else
snakeX[i] = snakeX[i-1];

if((direction == TOP) && (snakeY[0]+snakeLength == 0))


snakeY[0] = 8;
else if((direction == BOTTOM) && (snakeY[0]-snakeLength == 7))
snakeY[0] = -1;
else
snakeY[i] = snakeY[i-1];
}

switch(direction)
{
case TOP:
snakeY[0] = snakeY[0]-1;
break;
case RIGHT:
snakeX[0] = snakeX[0]+1;
break;
case BOTTOM:
snakeY[0] = snakeY[0]+1;
break;
case LEFT:
snakeX[0]=snakeX[0]-1;
break;
}

if((snakeX[0] == fruitX) && (snakeY[0] == fruitY))


{
snakeLength++;
if(snakeLength < MAX_SNAKE_LENGTH)
makeFruit();
else
fruitX = fruitY = -1;

}
snakeCheck();
}

void makeFruit(){
int x, y;
x = random(0, 8);
y = random(0, 8);
while(isPartOfSnake(x, y)){
x = random(0, 8);
y = random(0, 8);
}
fruitX = x;
fruitY = y;
}

boolean isPartOfSnake(int x, int y){


for(int i=0; i<snakeLength-1; i++)
{
if((x == snakeX[i]) && (y == snakeY[i]))
return true;
}
return false;
}

void snakeCheck(){
for(int i=1; i<snakeLength; i++)
{
// snake touches itself
if((snakeX[0] == snakeX[i]) && (snakeY[0] == snakeY[i]))
userLose();
}
if (snakeLength == MAX_SNAKE_LENGTH)
userWin();
}

void userLose(){
Serial.println("Game Over");
printString("O");

matrix.clear();
matrix.drawBitmap(0, 0, frown_bmp, 8, 8, LED_RED);
matrix.writeDisplay();
delay(1000);

snakeLength = 1;
setup();
loop();
}

void userWin(){
Serial.println("You Win");
printString("W");

matrix.clear();
matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_GREEN);
matrix.writeDisplay();
delay(1000);

snakeLength = 1;
setup();
loop();
}

void printString(String str){


String matrixComment;

matrix.setTextWrap(false); // we dont want text to wrap so it scrolls nicely


matrix.setTextSize(1);

if (str == "O")
{
matrixComment = "Game Over!";
matrixColor = LED_RED;
}
else if (str == "W")
{
matrixComment = "You Win!";
matrixColor = LED_GREEN;
}
else if (str == "S")
{
matrixComment = "Go!";
matrixColor = LED_YELLOW;
}
else
matrixColor = LED_YELLOW;

matrix.setTextColor(matrixColor);

for (int8_t x=7; x>=-60; x--)


{
matrix.clear();
matrix.setCursor(x,0);
matrix.print(matrixComment);
matrix.writeDisplay();
delay(70);
}
}

PHPoC Shield source code

<!DOCTYPE html>
<html>
<head>
<title>PHPoC Shield - Snake Game</title>
<meta name="viewport" content="width=device-width,
initial-scale=0.7, maximum-scale=0.7">
<style>
body { font-family: verdana, Helvetica, Arial, sans-serif,
gulim; font-weight: bold; text-align: center; }
h1 { font-size: 25pt; }
h2 { font-size: 15pt; }
#remote { margin:0 auto; width: 500px; background:
#333; border-radius: 2%; }
.direct {
display: inline-block; width: 100px; height: 100px;
font-size: 50px; color: white; line-height: 90px;
background: #eee; margin: 8px; border-radius: 10%;
text-align: center; font-weight: bold;
margin: 10px 60px;
}
</style>
<script>
var ws;
var button;

function init()
{
if(ws == null)
{
ws = new WebSocket("ws://<?echo
_SERVER("HTTP_HOST")?>/snake", "text.phpoc");
document.getElementById("ws_state").innerHTML =
"CONNECTING";

ws.onopen = ws_onopen;
ws.onclose = ws_onclose;
ws.onmessage = ws_onmessage;
}
else
ws.close();
}
function connect_onclick()
{
if(ws == null)
{
var ws_host_addr = "<?echo
_SERVER("HTTP_HOST")?>";
//var debug = document.getElementById("debug");

if((navigator.platform.indexOf("Win") != -1) &&


(ws_host_addr.charAt(0) == "["))
{
// network resource identifier to UNC path name
conversion
ws_host_addr = ws_host_addr.replace(/[\[\]]/g, '');
ws_host_addr = ws_host_addr.replace(/:/g, "-");
ws_host_addr += ".ipv6-literal.net";
}

//debug.innerHTML = "<br>" + navigator.platform + " "


+ ws_host_addr;
ws = new WebSocket("ws://" + ws_host_addr +
"/snake", "text.phpoc");

document.getElementById("ws_state").innerHTML =
"CONNECTING";

ws.onopen = ws_onopen;
ws.onclose = ws_onclose;
ws.onmessage = ws_onmessage;
}
else
ws.close();
}
function ws_onopen()
{
document.getElementById("ws_state").innerHTML = "
<font color='blue'>CONNECTED</font>";
document.getElementById("bt_connect").innerHTML =
"Disconnect";
}
function ws_onclose()
{
document.getElementById("ws_state").innerHTML = "
<font color='gray'>CLOSED</font>";
document.getElementById("bt_connect").innerHTML =
"Connect";

ws.onopen = null;
ws.onclose = null;
ws.onmessage = null;
ws = null;
}
function ws_onmessage(e_msg)
{
e_msg = e_msg || window.event; // MessageEvent

alert("msg : " + e_msg.data);


}

var beta = 0;
var gamma = 0;
var resolution = 2;

if (window.DeviceOrientationEvent)
{
window.addEventListener('deviceorientation',
orientationUpdate, true);
}
function orientationUpdate(event)
{

if(Math.abs((event.beta - beta)) > resolution)


beta = event.beta;

if(Math.abs((event.gamma - gamma)) > resolution)


gamma = event.gamma;

//var debug = document.getElementById("debug");


//debug.innerHTML = beta + "/" + gamma;

for (i=0; i<4; i++)


{
button = document.getElementById(i);
button.style.backgroundColor = "grey";
}

if (beta < 0) // top


{
button = document.getElementById(0);
button.style.backgroundColor = "#E9FF26";
ws.send("0");
}
else if (gamma < -35 && beta < 50) // left
{
button = document.getElementById(1);
button.style.backgroundColor = "#E9FF26";
ws.send("1");
}
else if (gamma > 35 && beta < 50) // right
{
button = document.getElementById(2);
button.style.backgroundColor = "#E9FF26";
ws.send("2");
}
else if (beta > 60) // bottom
{
button = document.getElementById(3);
button.style.backgroundColor = "#E9FF26";
ws.send("3");
}

}
window.onload = init;
</script>
</head>

<body>
<h1>Snake Game</h1>
<br /><br />
<div id="remote">
<div class="direct" id="0">↑</div><br />
<div class="direct" id="1">←</div>
<div class="direct" id="2">→</div><br />
<div class="direct" id="3">↓</div>
</div>
<br /><br />
<h2>WebSocket <font id="ws_state"
color="gray">CLOSED</font></h2>
<button id="bt_connect" type="button"
onclick="connect_onclick();">Connect</button>
<span id="debug"></span>
</body>
</html>
22) Arduino Eco Smart Container
COMPONENTS AND SUPPLIES

Arduino 101 & Genuino 101


× 1

SparkFun Inventor's Kit for


Arduino 101
× 1

Raspberry Pi Zero Wireless


× 1

DHT22 Temperature Sensor


× 1

Seeed Grove starter kit plus for


Intel Edison
× 1

Jumper wires (generic) × 1


Ultrasonic Sensor - HC-SR04
(Generic)
× 1

SparkFun Soil Moisture Sensor


(with Screw Terminals)
× 1

Breadboard (generic)
× 1

Li-Ion Battery 1000mAh


× 1

USB-A to B Cable
× 1

USB-A to Micro-USB Cable × 1


NECESSARY TOOLS AND MACHINES
Hot glue gun (generic)
APPS AND ONLINE SERVICES
Blynk

Arduino IDE

ABOUT THIS PROJECT


Material
1. SparkFun Inventor's Kit for Arduino 101
SparkFun Inventor's Kit for Arduino 101
This material was given to me by the sponsors of the
contest, I thank you for the trust and support. This
material contains the plate you use and the
temperature sensor TMP36 that I use to measure the
temperature.
To test the circuits you were using, use the Arduino
and Breadboard Holder. The arduino 101.
2. Grove Shield
This shield is perfect for prototyping and connecting
components exclusive to the Grove platform.
3. Grove LCD I2C
This screen can be connected through the I2C port of
the Arduino 101 and you can change the color of the
lighting and it has a very nice design.
4. Raspberry pi zero w

This board has all the advantages of raspberry pi zero


but with the addition of bluetooth 4.0 connectivity and
wi-fi, use it to receive arduino sensor values by means
of bluetooth. Programming in Node Js was a very
enjoyable, intuitive and effective experience.
5. DHT22
This digital sensor of humidity and temperature is
very used and has good results, this one uses it to
measure the temperature and humidity near the central
device that is the raspberry pi zero w.
6. Ultrasonic sensor
This sensor I used to measure the level of trash in the
trash can, had good results, but probably in an update
can be changed by a sensor or infrared sensor in my
opinion seem more reliable but in my country it is
difficult to achieve components as sensors.
7. Moisture sensor
This sensor used it to measure the level of humidity in
the earth, any high reading of humidity means that
there could be rain or some flood and that could be a
problem for the garbage of that place, sends a warning
to the application.
8. Solar battery bank
Any project needs power, my prototype I put this
power bank of 12000mAh, which also recharges solar,
ideally would have a panel built especially for my
prototype. But this device worked great. I used 2 for
raspberry pi zero w and arduino 101 in my smart trash
can.
9. Arduino 101 6-Axis Acelerometer and Gyroscope
To know if my trash can had fallen, or someone threw
it on the floor. Use the accelerometer and gyroscope
included in the Arduino 101. It was easy to implement
and send the data to the central base.
Results
In the physical aspect of the prototype I will show
some images and explain the why of each thing.
Below we have the top of the trash can that has the
LCD grove that has a nice message for people who use
it and leave their waste and also has as information the
time and a word, "ON" which means that the system is
Connected to the central unit which is the raspberry pi
zero wy "OFF" means that it is disconnected.

Below is the finished prototype, on the outside only


the LCD is visible on the top and on the back you can
see the power bank with its solar panel, so this device
is autonomous and sustainable with the environment.

To prove that the arduino data was reaching the


raspberry pi zero, I made the latter by programming in
node JS, print the value of each sensor per console in
Putty and below my results.
To implement the SMS notifications for my project I
had to investigate on the internet a lot and everything I
gathered in the tutorial in which I leave the link below.
https://www.hackster.io/alexis-santiago-allende/sms-
alerts-for-arduino-101-ble-e7184d
Also to connect arduino 101 with the raspberry pi zero
w by bluetooth of low energy carry out the following
tutorial, in which I leave to information that I found
and as I did the process. In this final project was to
unite these two previous examples and make slight
modifications to obtain the desired operation.
https://www.hackster.io/alexis-santiago-
allende/arduino-101-connects-with-raspberry-pi-zero-
w-63adc0
Blynk App
Below you can see how the application looks
aesthetically, at the top of the application you can see
small boxes that are widgets, two of which enable
notifications, one of them is the one that activates the
events of the Blynk application and the Last is a bin
viewer at the moment. In the central part you can see 4
very beautiful displays of temperature and humidity.
One pair is from the arduino 101 and the other are
from the raspberry pi zero w, with my prototype you
can add more visualization widgets and more sensors
but only use the ones that had available.
In the lower part you can see the trash level display
next to 2 general purpose buttons. That could be used
to control any item at a distance as lights from the
central unit. The use of this hardware together with
Blynk gives many possibilities.
Notifications examples:
There are two types of notifications implemented,
notifications specific to the application and those that
are through the Twilio SMS service. Here below we
have the temperature notification, when the
temperature is higher than a threshold, this sends a
notification. In the project notification is also given
when the trash can is full.
Temperature notification
Notifications are also given when the central device is
disconnected or there is a connection failure.
Offline notifications
Apart from the notifications of the app, under the
same cases, or if the previous notifications do not
work, we have the notifications by SMS that in my
opinion are more effective, below I leave the example
of when the trash can is full.
SMS notification

SCHEMATICS
CODE

Main code arduino

#include <CurieBLE.h>
#include "CurieIMU.h"
#include <Wire.h>
#include "rgb_lcd.h"
#include <CurieTime.h>

BLEPeripheral blePeripheral;//BLE Peripheral Device (Arduino Device)


BLEService demo111("19b10000-e8f2-537e4f6c-d104768a1214"); // BLE
demo111 Service
// BLE sensor rate Characteristic"
BLEUnsignedIntCharacteristic sensor1("19b10001-e8f2-537e4f6c-
d104768a1214", BLERead | BLENotify);
// BLE sensor rate Characteristic"
BLEUnsignedIntCharacteristic sensor2("19b10002-e8f2-537e4f6c-
d104768a1214", BLERead | BLENotify);
// BLE sensor rate Characteristic"
BLEUnsignedIntCharacteristic sensor3("19b10003-e8f2-537e4f6c-
d104768a1214", BLERead | BLENotify);
// BLE sensor rate Characteristic"
BLEUnsignedIntCharacteristic sensor4("19b10004-e8f2-537e4f6c-
d104768a1214", BLERead | BLENotify);
//Ble palabra sensor Characteristic
BLECharacteristic palabra("19b10005-e8f2-537e4f6c-d104768a1214",
BLERead | BLENotify,10);
// BLE demo111 buttons Characteristic - custom 128-bit UUID, read and
writable by central
BLEUnsignedCharCharacteristic buttons("19b10006-e8f2-537e4f6c-
d104768a1214", BLERead | BLEWrite);
rgb_lcd lcd;
const int colorR = 198;
const int colorG = 78;
const int colorB = 25;
int lastOrientation = - 1; // previous orientation (for comparison)
long previousMillis = 0; // last time the sensor was checked, in ms
const int green = 13; // pin to use for the green light
const int red = 11;// pin to use for the red light
boolean a = LOW, b = LOW; //Control variables
int temp=0;
long distancia;
long tiempo;
int orientation;
int valor=0,nivel=0,ndistancia;

void setup() {
Serial.begin(9600);
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
lcd.setRGB(colorR, colorG, colorB);
// Print a message to the LCD.
setTime(16, 56, 24, 3, 07, 2017);
lcd.print("Have a nice day!");
lcd.setCursor(12, 1);
lcd.print("Off");
pinMode(green, OUTPUT); // use the LED on pin 13 as an output
pinMode(red, OUTPUT);
pinMode(9, OUTPUT); /*activación del pin 9 como salida: para el pulso
ultrasónico*/
pinMode(8, INPUT);
CurieIMU.begin();
CurieIMU.setAccelerometerRange(2);
// set the local name peripheral advertises
blePeripheral.setLocalName("Demo111");
// set the UUID for the service this peripheral advertises
blePeripheral.setAdvertisedServiceUuid(demo111.uuid());

// add service and characteristic


blePeripheral.addAttribute(demo111);
blePeripheral.addAttribute(buttons);
blePeripheral.addAttribute(sensor1);
blePeripheral.addAttribute(sensor2);
blePeripheral.addAttribute(sensor3);
blePeripheral.addAttribute(sensor4);
blePeripheral.addAttribute(palabra);

// assign event handlers for connected, disconnected to peripheral


blePeripheral.setEventHandler(BLEConnected,
blePeripheralConnectHandler);
blePeripheral.setEventHandler(BLEDisconnected,
blePeripheralDisconnectHandler);

// assign event handlers for characteristic


buttons.setEventHandler(BLEWritten, switchCharacteristicWritten);

// sensors.setEventHandler(BLEWritten, switchCharacteristicWritten);
// set an initial value for the characteristic
buttons.setValue(0);
sensor1.setValue(0);
sensor2.setValue(0);
sensor3.setValue(0);
sensor4.setValue(0);
// advertise the service
blePeripheral.begin();
Serial.println(("Bluetooth device active, waiting for connections..."));
}

void loop() {
// poll peripheral
blePeripheral.poll();
digitalWrite(9,LOW); /* Por cuestión de estabilización del sensor*/
delayMicroseconds(5);
digitalWrite(9, HIGH); /* envío del pulso ultrasónico*/
delayMicroseconds(10);
tiempo=pulseIn(8, HIGH); /* Función para medir la longitud del pulso
entrante. Mide el tiempo que transcurrido entre el envío
del pulso ultrasónico y cuando el sensor recibe el rebote, es decir: desde que
el pin 12 empieza a recibir el rebote, HIGH, hasta que
deja de hacerlo, LOW, la longitud del pulso entrante*/
distancia= int(0.017*tiempo); /*fórmula para calcular la distancia
obteniendo un valor entero*/

char clockTime[8];
//use sprintf to create a time string of the hour, minte and seconds
sprintf(clockTime, "%02d:%02d:%02d", hour(), minute(), second());
//set cursor to column 0, row 0
lcd.setCursor(2, 1);
//print the date string over lcd
lcd.print(clockTime);

long currentMillis = millis();


// if 1s have passed, check the sensor:
if (currentMillis - previousMillis >= 1000) {
previousMillis = currentMillis;
updateSensor();
}

orientation = - 1; // the board's orientation


String orientationString; // string for printing description of orientation

// read accelerometer:
int x = CurieIMU.readAccelerometer(X_AXIS);
int y = CurieIMU.readAccelerometer(Y_AXIS);
int z = CurieIMU.readAccelerometer(Z_AXIS);

// calculate the absolute values, to determine the largest


int absX = abs(x);
int absY = abs(y);
int absZ = abs(z);

if ( (absZ > absX) && (absZ > absY)) {


// base orientation on Z
if (z > 0) {
orientationString = "up";
orientation = 0;
} else {
orientationString = "down";
orientation = 1;
}
} else if ( (absY > absX) && (absY > absZ)) {
// base orientation on Y
if (y > 0) {
orientationString = "digital pins up";
orientation = 2;
} else {
orientationString = "analog pins up";
orientation = 3;
}
} else {
// base orientation on X
if (x < 0) {
orientationString = "connector up";
orientation = 4;
} else {
orientationString = "connector down";
orientation = 5;
}
}

// if the orientation has changed, print out a description:


if (orientation != lastOrientation) {
Serial.println(orientationString);
lastOrientation = orientation;
}

void blePeripheralConnectHandler(BLECentral& central) {


// central connected event handler
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Have a nice day!");
Serial.print("Connected event, central: ");
Serial.println(central.address());
lcd.setCursor(12, 1);
lcd.print("On");
}

void blePeripheralDisconnectHandler(BLECentral& central) {


// central disconnected event handler
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Have a nice day!");
Serial.print("Disconnected event, central: ");
Serial.println(central.address());
lcd.setCursor(12, 1);
lcd.print("Off");
}

void switchCharacteristicWritten(BLECentral& central,


BLECharacteristic& characteristic) {
// central wrote new value to characteristic, update LED
Serial.print("Characteristic event, written: ");
Serial.print(buttons.value());
if (buttons.value() == 1 && a == LOW) { // 1 in ASCII

Serial.print("LED on");
digitalWrite(green, HIGH); // will turn the LED on
a = HIGH;
} else if (buttons.value() == 1 && a == HIGH) { //when 1 was read again
(second time)

Serial.println("LED off");
digitalWrite(green, LOW); // will turn the LED off
a = LOW;
}
else if (buttons.value() == 2 && b == LOW) { // 1 in ASCII
Serial.print("LED on");
digitalWrite(red, HIGH); // will turn the LED on
b = HIGH;
} else if (buttons.value() == 2 && b == HIGH) { //when 1 was read again
(second time)

Serial.println("LED off");
digitalWrite(red, LOW); // will turn the LED off
b = LOW;
}

void updateSensor() {
temp=analogRead(A0);//dht.readTemperature();//read temperature
valor=analogRead(A1);
nivel = map(valor, 0, 1023, 100, 0);
ndistancia = map(distancia, 38, 2, 0, 100);
float sensorLevel = temp*(3.3/1023);
int temp1=(sensorLevel-0.5)*100;
sensor1.setValue(temp1);//send temperature value
sensor2.setValue(distancia);//send distance value
sensor3.setValue(orientation);//send orientation value
sensor4.setValue(nivel);//send percentage of hummidity value
Serial.println(temp1);
Serial.println(distancia);
Serial.println(orientation);
Serial.println(nivel);

}
Main code Node JS

//Blynk
var Blynk = require('blynk-library');

var AUTH = 'adea86da8f774157b6a4997a6ed18a08';

var blynk = new Blynk.Blynk(AUTH);


var v1 = new blynk.VirtualPin(1);
var v9 = new blynk.VirtualPin(9);
var v8 = new blynk.VirtualPin(8);
var v7 = new blynk.VirtualPin(7);
var v6 = new blynk.VirtualPin(6);
var v5 = new blynk.VirtualPin(5);
var v4 = new blynk.VirtualPin(4);
var v3 = new blynk.VirtualPin(3);

//Bluetooth low energy


var noble = require('noble');

// Search only for the Service UUID of the device


(remove dashes)
var serviceUuids =
['19b10000e8f2537e4f6cd104768a1214'];

// Search only for the led charateristic


var characteristicUuids =
['19b10001e8f2537e4f6cd104768a1214','19b10002e8f25
37e4f6cd104768a1214','19b10003e8f2537e4f6cd104768
a1214','19b10004e8f2537e4f6cd104768a1214','19b1000
5e8f2537e4f6cd104768a1214','19b10006e8f2537e4f6cd
104768a1214'];

var sensor1=0;
var sensor2=0;
var sensor3=0;
var sensor4=0;
var temperatura=0;
var humedad=0;
var boton=0;
var contador1=0,contador2=0,contador3=0,contador4=0;

//Twilio
const twilio = require('twilio')
var accountSid =
'AC4c3a664e0475a08a4e0fdbd016555a70';
var authToken = '22ee6e5fe596967997a2d1a57d6d73eb';

const phone = new twilio(accountSid, authToken);

const sendMessage = () => {


phone.messages.create({
to: "+526462378678",
from: "+12818266123 ",
body: 'WARNING!!!!!! take care, please review your
Blynk app now!!!!!',
})
}
//Reading DHT22
var sensor = require('node-dht-sensor');
//Final
v1.on('write', function(param) {
boton=param[0];

});

v9.on('read', function() {
v9.write(new Date().getSeconds());
});

v8.on('read', function() {
v8.write(sensor1);
});

v7.on('read', function() {
v7.write(humedad);
});

v6.on('read', function() {
v6.write(temperatura);
});

v5.on('read', function() {
v5.write(sensor2);
});
v4.on('read', function() {
v4.write(sensor3);
});

v4.on('read', function() {
v4.write(sensor4);
});

// start scanning when bluetooth is powered on


noble.on('stateChange', function(state) {
if (state === 'poweredOn') {
noble.startScanning(serviceUuids);
} else {
noble.stopScanning();
}
});

//Reading sensor
setInterval(function() {
sensor.read(22, 21, function(err, temperature, humidity)
{
if (!err) {
temperatura=temperature.toFixed(1);
humedad= humidity.toFixed(1);

}
});
}, 1000);

// Search for BLE peripherals


noble.on('discover', function(peripheral) {
peripheral.connect(function(error) {
console.log('connected to peripheral: ' +
peripheral.uuid);
// Only discover the service we specified above
peripheral.discoverServices(serviceUuids,
function(error, services) {
var service = services[0];
console.log('discovered service');

service.discoverCharacteristics(characteristicUuids,
function(error, characteristics) {
console.log('discovered characteristics');
// Assign Characteristic
var sensor1Characteristic = characteristics[1];
var sensor2Characteristic = characteristics[2];
var sensor3Characteristic = characteristics[3];
var sensor4Characteristic = characteristics[4];
//var botonCharacteristic = characteristics[4];

setInterval(function() {

sensor1Characteristic.read(function(error, data) {
// data is a buffer
console.log('Temperature is: ' + data.readUInt8(0));
sensor1=data.readUInt8(0);
if (data.readUInt8(0)>=32 && contador1===0) {
sendMessage();
contador1=1;
}
else if(data.readUInt8(0)<=30 && contador1==1){
contador1=0;

});

sensor2Characteristic.read(function(error, data) {
// data is a buffer
console.log('Trash percent is: ' + data.readUInt8(0));
sensor2=data.readUInt8(0);
if (data.readUInt8(0)<=4 && contador2===0) {
sendMessage();
contador2=1;
}
else if(data.readUInt8(0)>=30 && contador2==1){
contador2=0;

}
});
sensor3Characteristic.read(function(error, data) {
// data is a buffer
console.log('Orientation: ' + data.readUInt8(0));
sensor3=data.readUInt8(0);
if (data.readUInt8(0)!=2 && contador3===0) {
sendMessage();
contador3=1;
}
else if(data.readUInt8(0)==2 && contador3==1){
contador3=0;

}
});

sensor4Characteristic.read(function(error, data) {
// data is a buffer
console.log('Humidity: ' + data.readUInt8(0));
sensor4=data.readUInt8(0);
if (data.readUInt8(0)>=90 && contador4===0) {
sendMessage();
contador4=1;
}
else if(data.readUInt8(0)<=30 && contador4==1){
contador4=0;
}
});

}, 1000);

// var bufferToSend = new Buffer(1);


// bufferToSend.writeUInt8(boton);
// console.log(bufferToSend);
// botonCharacteristic.write(bufferToSend, false);
// setInterval(function() {
//bufferToSend.writeUInt8(1); // you can pass this any
integer, we just do this to alternate 0/1
// botonCharacteristic.write(bufferToSend, false);
// }, 1000);
});
});
});
});
23) Arduino Without External Clock Ctystal on
Atmega328

COMPONENTS AND SUPPLIES


Arduino UNO & Genuino UNO
To program the ATmega chip
× 1
on the breadboard. You can use
FTDI Breakout Board also.
Microchip Atmega328
× 1
Breadboard (generic) × 1

Jumper wires (generic)


× 1

SparkFun FTDI 232RL USB to


Serial Converter
× 1
If not using Arduino Uno, then,
use this.
Capacitor 100 nF
To be used if using FTDI USB × 1
to Serial Breakout.
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT


An Arduino consists of many components like: a
linear regulator, USB to Serial microcontroller, debug
LED, power LED, reset button, RX & TX LED,
crystal oscillator, etc. But a minimal circuit can have
just the brain of the Arduino UNO, that is, an
ATmega328p microcontroller (Reducing Arduino
Power Consumption). You can assume this one is an
extended version of that project.
Making a Minimal Arduino UNO on a Breadboard
Most people are successful in making Arduino with
minimal circuitry, but use the 16 MHz crystal. We can
remove that, too, along with 22 pF capacitors. You can
configure the ATmega328 to use its internal 8 MHz
RC oscillator as a clock source.
Install Support for Hardware Configuration
Download this hardware configuration
archive: breadboard-1-6-x.zip, Breadboard1-5-
x.zip or Breadboard1-0-x.zip depending on
which IDE you use.
Create a "hardware" sub-folder in your Arduino
sketchbook folder (whose location you can find
in the Arduino preferences dialog). If you've
previously installed support for additional
hardware configuration, you may already have a
"hardware" folder in your sketchbook.
Move the breadboard folder from the zip archive
to the "hardware" folder of your Arduino
sketchbook.
Restart the Arduino software.
You should see "ATmega328 on a breadboard (8
MHz internal clock)" in the Tools > Board menu.
Once you've done this, you can burn the bootloader
and upload programs onto your ATmega328.
Putting Stuff on Breadboard
Get all the stuff listed above. Moreover, keep a pin
mapping of the ATmega328P handy while making the
circuit.
ATmega328p pin mapping.
Using ATmega Without UNO Bootloader
First of all, we need to burn the bootloader to the
ATmega chip if you bought a blank microcontroller
having no bootloader, so that it can be a
programmable entity.
Refer to the schematics and place the ATmega
chip in the breadboard.
Open the ArduinoISP firmware (in Examples) to
your Arduino board.
Select the items in the Tools > Board and Serial
Port menus that correspond to the board you are
using as the programmer (not the board being
programmed).
Upload the ArduinoISP sketch.
Select the item in the Tools > Board menu and be
sure to select "ATmega328 on a breadboard
(8MHz internal clock)" when burning the
bootloader.
Select the Arduino as ISP in the Tools >
Programmer menu.
Use the Burn Boot-loader command in
the Tools menu.
Skip step 2 if you have done step 1.
2. Using ATmega with UNO boot-loader
If the ATmega is already boot-loaded, then just put it
in the breadboard and we can proceed programming
the ATmega328p microcontroller.
3. Programming the ATmega chip (using other
Arduino)
Remove the microcontroller of the Arduino you
are using as the programmer.
Refer to the schematics and pin mapping and
connect the Rx and Tx of programmer
Arduino to Tx and Rx of the breadboard
Arduino respectively.
Connect RESET of programmer
Arduino to RESET of breadboard Arduino.
Connect GND and VCC of breadboard
Arduino to GND and VCC on programmer
Arduino.
Select the item in the Tools > Board menu and be
sure to select "ATmega328 on a breadboard
(8MHz internal clock)".
Check the port and click on "upload".
Plug out the connections and now you can power it
with a battery for months depending on the kind of
project.
4. Programming the ATmega chip (using FTDI USB to
Serial Adapter)
Curious what all the pin outs are for on the FT232RL
breakout board? Simply flip it over! In this situation
I'll be using VCC (to supply 5V from the USB port to
your board), GND, TXD, and RXD. [Refer to
schematics]
FTDI 232RL Breakout board pinouts.
This board comes without the headers when
bought from market. So, solder the male header
and plug it in the breadboard.
Connect Rx of ATmega chip to Tx of board
and Tx of ATmega chip to Rx of the board.
Connect Vcc and GND to the power rails on the
breadboard.
Plug the USB mini type - B and connect it with
your computer and upload the sketch using the
Arduino IDE but always remember to select
"ATmega328 on a breadboard (8MHz internal
clock)". It will take power from the USB but
after disconnecting the USB, you can plug the
battery terminals to the power rails of
breadboard.
And the Arduino is ready.

SCHEMATICS

Using an Arduino board to burn the bootloader onto


an ATmega on a breadboard (w/o an external clock)
Uploading sketches to an ATmega on a
breadboard(using another Arduino).
Uploading sketches to an ATmega on a
breadboard(using FTDI 232RL Driver)
Ignore the capacitors(except 10nF cap), resistors and
the clock crystal.
CODE

// This sketch turns the Arduino into a AVRISP


// using the following arduino pins:
//
// Pin 10 is used to reset the target microcontroller.
//
// By default, the hardware SPI pins MISO, MOSI and
SCK pins are used
// to communicate with the target. On all Arduinos, these
pins can be found
// on the ICSP/SPI header:
//
// MISO . . 5V (!) Avoid this pin on Due, Zero...
// SCK . . MOSI
// . . GND
//
// On some Arduinos (Uno,...), pins MOSI, MISO and
SCK are the same pins
// as digital pin 11, 12 and 13, respectively. That is why
many tutorials
// instruct you to hook up the target to these pins. If you
find this wiring
// more practical, have a define
USE_OLD_STYLE_WIRING. This will work even
// even when not using an Uno. (On an Uno this is not
needed).
//
// Alternatively you can use any other digital pin by
configuring software ('BitBanged')
// SPI and having appropriate defines for PIN_MOSI,
PIN_MISO and PIN_SCK.
//
// IMPORTANT: When using an Arduino that is not 5V
tolerant (Due, Zero, ...)
// as the programmer, make sure to not expose any of the
programmer's pins to 5V.
// A simple way to accomplish this is to power the
complete system (programmer
// and target) at 3V3.
//
// Put an LED (with resistor) on the following pins:
// 9: Heartbeat - shows the programmer is running
// 8: Error - Lights up if something goes wrong (use
red if that makes sense)
// 7: Programming - In communication with the slave
//

#include "Arduino.h"
#undef SERIAL

#define PROG_FLICKER true

// Configure SPI clock (in Hz).


// E.g. for an attiny @128 kHz: the datasheet states that
both the high
// and low spi clock pulse must be > 2 cpu cycles, so take
3 cycles i.e.
// divide target f_cpu by 6:
// #define SPI_CLOCK (128000/6)
//
// A clock slow enough for an attiny85 @ 1MHz, is a
reasonable default:

#define SPI_CLOCK (1000000/6)


// Select hardware or software SPI, depending on SPI
clock.
// Currently only for AVR, for other archs (Due, Zero,...),
// hardware SPI is probably too fast anyway.

#if defined(ARDUINO_ARCH_AVR)

#if SPI_CLOCK > (F_CPU / 128)


#define USE_HARDWARE_SPI
#endif

#endif

// Configure which pins to use:

// The standard pin configuration.


#ifndef ARDUINO_HOODLOADER2

#define RESET 10 // Use pin 10 to reset the target


rather than SS
#define LED_HB 9
#define LED_ERR 8
#define LED_PMODE 7

// Uncomment following line to use the old Uno style


wiring
// (using pin 11, 12 and 13 instead of the SPI header) on
Leonardo, Due...

// #define USE_OLD_STYLE_WIRING

#ifdef USE_OLD_STYLE_WIRING

#define PIN_MOSI 11
#define PIN_MISO 12
#define PIN_SCK 13

#endif

// HOODLOADER2 means running sketches on the


atmega16u2
// serial converter chips on Uno or Mega boards.
// We must use pins that are broken out:
#else

#define RESET 4
#define LED_HB 7
#define LED_ERR 6
#define LED_PMODE 5

#endif

// By default, use hardware SPI pins:


#ifndef PIN_MOSI
#define PIN_MOSI MOSI
#endif

#ifndef PIN_MISO
#define PIN_MISO MISO
#endif

#ifndef PIN_SCK
#define PIN_SCK SCK
#endif

// Force bitbanged SPI if not using the hardware SPI


pins:
#if (PIN_MISO != MISO) || (PIN_MOSI != MOSI) ||
(PIN_SCK != SCK)
#undef USE_HARDWARE_SPI
#endif

// Configure the serial port to use.


//
// Prefer the USB virtual serial port (aka. native USB
port), if the Arduino has one:
// - it does not autoreset (except for the magic baud rate
of 1200).
// - it is more reliable because of USB handshaking.
//
// Leonardo and similar have an USB virtual serial port:
'Serial'.
// Due and Zero have an USB virtual serial port:
'SerialUSB'.
//
// On the Due and Zero, 'Serial' can be used too,
provided you disable autoreset.
// To use 'Serial': #define SERIAL Serial

#ifdef SERIAL_PORT_USBVIRTUAL
#define SERIAL SERIAL_PORT_USBVIRTUAL
#else
#define SERIAL Serial
#endif

// Configure the baud rate:

#define BAUDRATE 19200


// #define BAUDRATE 115200
// #define BAUDRATE 1000000

#define HWVER 2
#define SWMAJ 1
#define SWMIN 18
// STK Definitions
#define STK_OK 0x10
#define STK_FAILED 0x11
#define STK_UNKNOWN 0x12
#define STK_INSYNC 0x14
#define STK_NOSYNC 0x15
#define CRC_EOP 0x20 //ok it is a space...

void pulse(int pin, int times);

#ifdef USE_HARDWARE_SPI
#include "SPI.h"
#else

#define SPI_MODE0 0x00

class SPISettings {
public:
// clock is in Hz
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t
dataMode) : clock(clock){
(void) bitOrder;
(void) dataMode;
};

private:
uint32_t clock;

friend class BitBangedSPI;


};

class BitBangedSPI {
public:
void begin() {
digitalWrite(PIN_SCK, LOW);
digitalWrite(PIN_MOSI, LOW);
pinMode(PIN_SCK, OUTPUT);
pinMode(PIN_MOSI, OUTPUT);
pinMode(PIN_MISO, INPUT);
}

void beginTransaction(SPISettings settings) {


pulseWidth = (500000 + settings.clock - 1) /
settings.clock;
if (pulseWidth == 0)
pulseWidth = 1;
}

void end() {}

uint8_t transfer (uint8_t b) {


for (unsigned int i = 0; i < 8; ++i) {
digitalWrite(PIN_MOSI, (b & 0x80) ? HIGH : LOW);
digitalWrite(PIN_SCK, HIGH);
delayMicroseconds(pulseWidth);
b = (b << 1) | digitalRead(PIN_MISO);
digitalWrite(PIN_SCK, LOW); // slow pulse
delayMicroseconds(pulseWidth);
}
return b;
}

private:
unsigned long pulseWidth; // in microseconds
};

static BitBangedSPI SPI;

#endif

void setup() {
SERIAL.begin(BAUDRATE);

pinMode(LED_PMODE, OUTPUT);
pulse(LED_PMODE, 2);
pinMode(LED_ERR, OUTPUT);
pulse(LED_ERR, 2);
pinMode(LED_HB, OUTPUT);
pulse(LED_HB, 2);
}

int error = 0;
int pmode = 0;
// address for reading and writing, set by 'U' command
unsigned int here;
uint8_t buff[256]; // global block storage

#define beget16(addr) (*addr * 256 + *(addr+1) )


typedef struct param {
uint8_t devicecode;
uint8_t revision;
uint8_t progtype;
uint8_t parmode;
uint8_t polling;
uint8_t selftimed;
uint8_t lockbytes;
uint8_t fusebytes;
uint8_t flashpoll;
uint16_t eeprompoll;
uint16_t pagesize;
uint16_t eepromsize;
uint32_t flashsize;
}
parameter;

parameter param;
// this provides a heartbeat on pin 9, so you can tell the
software is running.
uint8_t hbval = 128;
int8_t hbdelta = 8;
void heartbeat() {
static unsigned long last_time = 0;
unsigned long now = millis();
if ((now - last_time) < 40)
return;
last_time = now;
if (hbval > 192) hbdelta = -hbdelta;
if (hbval < 32) hbdelta = -hbdelta;
hbval += hbdelta;
analogWrite(LED_HB, hbval);
}

static bool rst_active_high;

void reset_target(bool reset) {


digitalWrite(RESET, ((reset && rst_active_high) ||
(!reset && !rst_active_high)) ? HIGH : LOW);
}

void loop(void) {
// is pmode active?
if (pmode) {
digitalWrite(LED_PMODE, HIGH);
} else {
digitalWrite(LED_PMODE, LOW);
}
// is there an error?
if (error) {
digitalWrite(LED_ERR, HIGH);
} else {
digitalWrite(LED_ERR, LOW);
}

// light the heartbeat LED


heartbeat();
if (SERIAL.available()) {
avrisp();
}
}

uint8_t getch() {
while (!SERIAL.available());
return SERIAL.read();
}
void fill(int n) {
for (int x = 0; x < n; x++) {
buff[x] = getch();
}
}
#define PTIME 30
void pulse(int pin, int times) {
do {
digitalWrite(pin, HIGH);
delay(PTIME);
digitalWrite(pin, LOW);
delay(PTIME);
} while (times--);
}

void prog_lamp(int state) {


if (PROG_FLICKER) {
digitalWrite(LED_PMODE, state);
}
}

uint8_t spi_transaction(uint8_t a, uint8_t b, uint8_t c,


uint8_t d) {
SPI.transfer(a);
SPI.transfer(b);
SPI.transfer(c);
return SPI.transfer(d);
}

void empty_reply() {
if (CRC_EOP == getch()) {
SERIAL.print((char)STK_INSYNC);
SERIAL.print((char)STK_OK);
} else {
error++;
SERIAL.print((char)STK_NOSYNC);
}
}

void breply(uint8_t b) {
if (CRC_EOP == getch()) {
SERIAL.print((char)STK_INSYNC);
SERIAL.print((char)b);
SERIAL.print((char)STK_OK);
} else {
error++;
SERIAL.print((char)STK_NOSYNC);
}
}

void get_version(uint8_t c) {
switch (c) {
case 0x80:
breply(HWVER);
break;
case 0x81:
breply(SWMAJ);
break;
case 0x82:
breply(SWMIN);
break;
case 0x93:
breply('S'); // serial programmer
break;
default:
breply(0);
}
}

void set_parameters() {
// call this after reading paramter packet into buff[]
param.devicecode = buff[0];
param.revision = buff[1];
param.progtype = buff[2];
param.parmode = buff[3];
param.polling = buff[4];
param.selftimed = buff[5];
param.lockbytes = buff[6];
param.fusebytes = buff[7];
param.flashpoll = buff[8];
// ignore buff[9] (= buff[8])
// following are 16 bits (big endian)
param.eeprompoll = beget16(&buff[10]);
param.pagesize = beget16(&buff[12]);
param.eepromsize = beget16(&buff[14]);
// 32 bits flashsize (big endian)
param.flashsize = buff[16] * 0x01000000
+ buff[17] * 0x00010000
+ buff[18] * 0x00000100
+ buff[19];

// avr devices have active low reset, at89sx are active


high
rst_active_high = (param.devicecode >= 0xe0);
}

void start_pmode() {

// Reset target before driving PIN_SCK or PIN_MOSI

// SPI.begin() will configure SS as output,


// so SPI master mode is selected.
// We have defined RESET as pin 10,
// which for many arduino's is not the SS pin.
// So we have to configure RESET as output here,
// (reset_target() first sets the correct level)
reset_target(true);
pinMode(RESET, OUTPUT);
SPI.begin();
SPI.beginTransaction(SPISettings(SPI_CLOCK,
MSBFIRST, SPI_MODE0));
// See avr datasheets, chapter "SERIAL_PRG
Programming Algorithm":

// Pulse RESET after PIN_SCK is low:


digitalWrite(PIN_SCK, LOW);
delay(20); // discharge PIN_SCK, value arbitrally chosen
reset_target(false);
// Pulse must be minimum 2 target CPU clock cycles
// so 100 usec is ok for CPU speeds above 20KHz
delayMicroseconds(100);
reset_target(true);

// Send the enable programming command:


delay(50); // datasheet: must be > 20 msec
spi_transaction(0xAC, 0x53, 0x00, 0x00);
pmode = 1;
}

void end_pmode() {
SPI.end();
// We're about to take the target out of reset
// so configure SPI pins as input
pinMode(PIN_MOSI, INPUT);
pinMode(PIN_SCK, INPUT);
reset_target(false);
pinMode(RESET, INPUT);
pmode = 0;
}

void universal() {
uint8_t ch;

fill(4);
ch = spi_transaction(buff[0], buff[1], buff[2], buff[3]);
breply(ch);
}

void flash(uint8_t hilo, unsigned int addr, uint8_t data) {


spi_transaction(0x40 + 8 * hilo,
addr >> 8 & 0xFF,
addr & 0xFF,
data);
}
void commit(unsigned int addr) {
if (PROG_FLICKER) {
prog_lamp(LOW);
}
spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF,
0);
if (PROG_FLICKER) {
delay(PTIME);
prog_lamp(HIGH);
}
}

unsigned int current_page() {


if (param.pagesize == 32) {
return here & 0xFFFFFFF0;
}
if (param.pagesize == 64) {
return here & 0xFFFFFFE0;
}
if (param.pagesize == 128) {
return here & 0xFFFFFFC0;
}
if (param.pagesize == 256) {
return here & 0xFFFFFF80;
}
return here;
}

void write_flash(int length) {


fill(length);
if (CRC_EOP == getch()) {
SERIAL.print((char) STK_INSYNC);
SERIAL.print((char) write_flash_pages(length));
} else {
error++;
SERIAL.print((char) STK_NOSYNC);
}
}

uint8_t write_flash_pages(int length) {


int x = 0;
unsigned int page = current_page();
while (x < length) {
if (page != current_page()) {
commit(page);
page = current_page();
}
flash(LOW, here, buff[x++]);
flash(HIGH, here, buff[x++]);
here++;
}

commit(page);

return STK_OK;
}

#define EECHUNK (32)


uint8_t write_eeprom(unsigned int length) {
// here is a word address, get the byte address
unsigned int start = here * 2;
unsigned int remaining = length;
if (length > param.eepromsize) {
error++;
return STK_FAILED;
}
while (remaining > EECHUNK) {
write_eeprom_chunk(start, EECHUNK);
start += EECHUNK;
remaining -= EECHUNK;
}
write_eeprom_chunk(start, remaining);
return STK_OK;
}
// write (length) bytes, (start) is a byte address
uint8_t write_eeprom_chunk(unsigned int start,
unsigned int length) {
// this writes byte-by-byte,
// page writing may be faster (4 bytes at a time)
fill(length);
prog_lamp(LOW);
for (unsigned int x = 0; x < length; x++) {
unsigned int addr = start + x;
spi_transaction(0xC0, (addr >> 8) & 0xFF, addr & 0xFF,
buff[x]);
delay(45);
}
prog_lamp(HIGH);
return STK_OK;
}
void program_page() {
char result = (char) STK_FAILED;
unsigned int length = 256 * getch();
length += getch();
char memtype = getch();
// flash memory @here, (length) bytes
if (memtype == 'F') {
write_flash(length);
return;
}
if (memtype == 'E') {
result = (char)write_eeprom(length);
if (CRC_EOP == getch()) {
SERIAL.print((char) STK_INSYNC);
SERIAL.print(result);
} else {
error++;
SERIAL.print((char) STK_NOSYNC);
}
return;
}
SERIAL.print((char)STK_FAILED);
return;
}

uint8_t flash_read(uint8_t hilo, unsigned int addr) {


return spi_transaction(0x20 + hilo * 8,
(addr >> 8) & 0xFF,
addr & 0xFF,
0);
}

char flash_read_page(int length) {


for (int x = 0; x < length; x += 2) {
uint8_t low = flash_read(LOW, here);
SERIAL.print((char) low);
uint8_t high = flash_read(HIGH, here);
SERIAL.print((char) high);
here++;
}
return STK_OK;
}

char eeprom_read_page(int length) {


// here again we have a word address
int start = here * 2;
for (int x = 0; x < length; x++) {
int addr = start + x;
uint8_t ee = spi_transaction(0xA0, (addr >> 8) & 0xFF,
addr & 0xFF, 0xFF);
SERIAL.print((char) ee);
}
return STK_OK;
}

void read_page() {
char result = (char)STK_FAILED;
int length = 256 * getch();
length += getch();
char memtype = getch();
if (CRC_EOP != getch()) {
error++;
SERIAL.print((char) STK_NOSYNC);
return;
}
SERIAL.print((char) STK_INSYNC);
if (memtype == 'F') result = flash_read_page(length);
if (memtype == 'E') result = eeprom_read_page(length);
SERIAL.print(result);
}

void read_signature() {
if (CRC_EOP != getch()) {
error++;
SERIAL.print((char) STK_NOSYNC);
return;
}
SERIAL.print((char) STK_INSYNC);
uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00);
SERIAL.print((char) high);
uint8_t middle = spi_transaction(0x30, 0x00, 0x01,
0x00);
SERIAL.print((char) middle);
uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00);
SERIAL.print((char) low);
SERIAL.print((char) STK_OK);
}
//////////////////////////////////////////
//////////////////////////////////////////

////////////////////////////////////
////////////////////////////////////
void avrisp() {
uint8_t ch = getch();
switch (ch) {
case '0': // signon
error = 0;
empty_reply();
break;
case '1':
if (getch() == CRC_EOP) {
SERIAL.print((char) STK_INSYNC);
SERIAL.print("AVR ISP");
SERIAL.print((char) STK_OK);
}
else {
error++;
SERIAL.print((char) STK_NOSYNC);
}
break;
case 'A':
get_version(getch());
break;
case 'B':
fill(20);
set_parameters();
empty_reply();
break;
case 'E': // extended parameters - ignore for now
fill(5);
empty_reply();
break;
case 'P':
if (!pmode)
start_pmode();
empty_reply();
break;
case 'U': // set address (word)
here = getch();
here += 256 * getch();
empty_reply();
break;
case 0x60: //STK_PROG_FLASH
getch(); // low addr
getch(); // high addr
empty_reply();
break;
case 0x61: //STK_PROG_DATA
getch(); // data
empty_reply();
break;

case 0x64: //STK_PROG_PAGE


program_page();
break;

case 0x74: //STK_READ_PAGE 't'


read_page();
break;

case 'V': //0x56


universal();
break;
case 'Q': //0x51
error = 0;
end_pmode();
empty_reply();
break;
case 0x75: //STK_READ_SIGN 'u'
read_signature();
break;

// expecting a command, not CRC_EOP


// this is how we can get back in sync
case CRC_EOP:
error++;
SERIAL.print((char) STK_NOSYNC);
break;

// anything else we will return STK_UNKNOWN


default:
error++;
if (CRC_EOP == getch())
SERIAL.print((char)STK_UNKNOWN);
else
SERIAL.print((char)STK_NOSYNC);
}
}
24) Arduino Sun Tracking Solar System
COMPONENTS AND SUPPLIES

Arduino UNO & Genuino


UNO
× 1

Analog Devices LDR Sensor


× 1

Solderless Breadboard Full × 1


Size
solar panel
× 1

SG90 Micro-servo motor


× 2

Jumper wires (generic)


× 1

Resistor 1k ohm
× 4
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT


It seems you can'twalk down the street these days
without coming across a solar panel. You canfind them
for mobile charging in rural areas, as well as simple little
sidewalkpath lights. Solar is easy to use, readily
available, and inexpensive.
Every panel you seein your day to day life is in a fixed
position. While this approach isextremely simple and
meets the needs of most small applications, it
isn'tproducing as much energy as it could be.
Our tracker isa dual axis tracker , meaningit tracks in
both X and Y. To put it into even more simple terms, it
goes left, right, up, and down. This means once you have
your tracker set up you willnever need to change or
adjust anything, since anywhere the sun moves
yourtracker will follow.
SCHEMATICS
CODE

#include<Servo.h> // library for servo motor

Servo s; // define Vertival servo


Servo sh; // define horizontal servo
int start1 = 90; // initially starting from 90 degree
int start2 = 90;
int L1 = A0; //for read data from LDR1
int L2 = A1; //for read data from LDR2
int L3 = A2; //for read data from LDR3
int L4 = A3; //for read data from LDR4
int a = 15;

void setup()
{
s.attach(9); //connect vertical servo to pin 9 of arduino
sh.attach(10); //connect horizontal servo to pin 10 of arduino
pinMode(L1, INPUT); //define LDR as input
pinMode(L2, INPUT);
pinMode(L3, INPUT);
pinMode(L4, INPUT);
s.write(start1); //it will start servo from 90 when we reset system
sh.write(start2);
delay(2000);
}
void loop()
{
int LDR1 = analogRead(L1); //read value from LDR
int LDR2 = analogRead(L2);
int LDR3 = analogRead(L3);
int LDR4 = analogRead(L4);
int plus14 =(LDR1+LDR4); //average of two corner LDR
int plus23 =(LDR2+LDR3);
int plus12 =(LDR1+LDR2);
int plus34 =(LDR3+LDR4);
int diff1= abs(plus14 - plus23); // difference to take proper value
int diff2= abs(plus23 - plus14);
int diff3= abs(plus12 - plus34);
int diff4= abs(plus34 - plus12);

if((diff1 <= a) || (diff2 <= a))


{
//difference is less then 15 so do nothing
}
else
{
if(plus14 > plus23) //move vertical servo in lessthen 90 degree
{
start2= --start2;
}
if(plus14 < plus23)
{
start2 = ++start2; //move vertical servo in greaterthen 90 degree
}
}
if(plus12 > plus34 )
{
start1= --start1; // move horizontal servo in lessthen 90 degree
}
if(plus12 < plus34)
{
start1= ++start1; //move horizontal servo in greaterthen 90 degree
}
s.write(start1);
sh.write(start2);
delay(100);
}
25) Arduino Max 30102 Heart Rate Monitor on LCD
COMPONENTS AND SUPPLIES

Arduino Nano R3
× 1

MAX 30102 Heart rate monitor


× 1

Adafruit RGB Backlight LCD - × 1


16x2
Rotary potentiometer (generic)
× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT


This is a simple heart rate monitor made with a
MAX30102 sensor module. I wrote a simple code
based on Arduino libraries and values are shown on a
16x2 LCD screen. The first row displays averge beats
per minute, and the second row shows the value of the
reflected infrared beam. This value should be constant
to make readings more accurate.Our tracker isa dual
axis tracker, meaningit tracks in both X and Y. To put it
into even more simple terms, it goes left, right, up, and
down. This means once you have your tracker set up you
willnever need to change or adjust anything, since
anywhere the sun moves yourtracker will follow.
SCHEMATICS
CODE

/*
Optical Heart Rate Detection (PBA Algorithm) using the MAX30105
Breakout

This is a demo to show the reading of heart rate or beats per minute (BPM)
using
a Penpheral Beat Amplitude (PBA) algorithm.

It is best to attach the sensor to your finger using a rubber band or other
tightening
device. Humans are generally bad at applying constant pressure to a thing.
When you
press your finger against the sensor it varies enough to cause the blood in
your
finger to flow differently which causes the sensor readings to go wonky.

Hardware Connections (Breakoutboard to Arduino):


-5V = 5V (3.3V is allowed)
-GND = GND
-SDA = A4 (or SDA)
-SCL = A5 (or SCL)
-INT = Not connected
The MAX30105 Breakout can handle 5V or 3.3V I2C logic. We recommend
powering the board with 5V
but it will also run at 3.3V.
*/

#include <Wire.h>
#include "MAX30105.h"
#include <LiquidCrystal.h>

#include "heartRate.h"

MAX30105 particleSensor;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

const byte RATE_SIZE = 4; //Increase this for more averaging. 4 is good.


byte rates[RATE_SIZE]; //Array of heart rates
byte rateSpot = 0;
long lastBeat = 0; //Time at which the last beat occurred

float beatsPerMinute;
int beatAvg;

void setup()
{
Serial.begin(9600);

lcd.begin(16, 2);
Serial.println("Initializing...");

// Initialize sensor
if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port,
400kHz speed
{
Serial.println("MAX30105 was not found. Please check wiring/power. ");
while (1);
}
Serial.println("Place your index finger on the sensor with steady pressure.");
particleSensor.setup(); //Configure sensor with default settings
particleSensor.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to
indicate sensor is running
particleSensor.setPulseAmplitudeGreen(0); //Turn off Green LED
}

void loop()
{
long irValue = particleSensor.getIR();

if (checkForBeat(irValue) == true)
{
//We sensed a beat!
long delta = millis() - lastBeat;
lastBeat = millis();

beatsPerMinute = 60 / (delta / 1000.0);

if (beatsPerMinute < 255 && beatsPerMinute > 20)


{
rates[rateSpot++] = (byte)beatsPerMinute; //Store this reading in the array
rateSpot %= RATE_SIZE; //Wrap variable

//Take average of readings


beatAvg = 0;
for (byte x = 0 ; x < RATE_SIZE ; x++)
beatAvg += rates[x];
beatAvg /= RATE_SIZE;
}
}

Serial.print("IR=");
Serial.print(irValue);
Serial.print(", BPM=");
Serial.print(beatsPerMinute);
Serial.print(", Avg BPM=");
Serial.print(beatAvg);

if (irValue < 50000)


Serial.print(" No finger?");

Serial.println();

lcd.setCursor(0,0);
lcd.print("BPM: ");
lcd.print(beatAvg);

lcd.setCursor(0,1);
lcd.print(" IR: ");
lcd.print(irValue);
}

26) Rainfall Measured Using Arduino


COMPONENTS AND SUPPLIES

water sensor
× 1

Arduino UNO & Genuino


UNO
× 1
ABOUT THIS PROJECT
SCHEMATICS
CODE

#include <LiquidCrystal.h>
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup () {
// initialize serial communication at 9600 bits per second:
Serial.begin (9600);}
void loop() {
// read the input on analog pin 0:
int value = analogRead(A0);
lcd.setCursor(0, 7);
if (value > 500) {
Serial.println("Very heavy Rain");
lcd.print("Very heavy rain");}
else if ((value > 300) && (value <= 500)) {
Serial.println("AVERAGE Rain");
lcd.print("Average Rain");
lcd.print(" "); }
else{
Serial.println("Dry Weather");
lcd.print("Dry Wather");
lcd.print(" ");}
delay(100);}

27) Arduino Touchless Mouse


COMPONENTS AND SUPPLIES
Bitcraze Flow breakout
× 1

Arduino Leonardo
× 1

ABOUT THIS PROJECT


This project implements a touchless mouse.
The Bitcraze flow breakout contains an optical flow
sensor that is able to sense how things are moving in
front of it and a ranging sensor to sense the distance to
the nearest object. The flow sensor is essentially an
optical mouse sensor fitted with a lens focused to
track objects far away.
The touchless mouse can detect that a hand is
approaching and detect how it is moving, the
movements are translated into mouse movements by
an Arduino.
By using an Arduino Leonardo (or any other USB
device-compatible Arduino) this project is seen as a
regular mouse so it works out of the box on any
computer.
Hardware setup
The flow deck is connected to two busses of the
Arduino:
The PMW3901 optical tracking sensor is
connected to the SPI bus
The VL53 ranging sensor is connected to the i2C
bus
We also need to power the flow deck, this is done by
connecting it to the 5V and GND pin of the Arduino.
Note that on Arduino Leonardo, the SPI bus is only
accessible on the ICSP pin header.
Required library
The two sensors require libraries to work. Using
the Arduino IDE Library manager we load the two
libraries:
VL53L0x for the ranging sensor
Bitcraze_pmw3901 for the optical flow sensor

When an object is detected by the ranging sensor, at a


distance between 80mm and 200mm, the movement
measured by the flow sensor is sent as mouse
movement. When the detected object is below 50mm
we press the mouse button. The reason to keep 50mm
to 80mm without motion detection and click is to
make sure that the mouse is clicking without any
movement: without this gap the mouse was always
moving a bit when the hand goes down to click.
SCHEMATICS
CODE

#include "Bitcraze_PMW3901.h"
#include <Wire.h>
#include <VL53L0X.h>
#include <Mouse.h>

VL53L0X rangeSensor;

// Using digital pin 10 for chip select


Bitcraze_PMW3901 flow(10);

void setup() {
Serial.begin(9600);
// Initialize flow sensor
if (!flow.begin()) {
Serial.println("Initialization of the flow sensor failed");
while(1) { }
}
// Initialize range sensor
Wire.begin();
rangeSensor.init();
rangeSensor.setTimeout(500);
// Initialize Mouse
Mouse.begin();
}

int16_t deltaX,deltaY;

void loop() {
// Get motion count since last call
flow.readMotionCount(&deltaX, &deltaY);
// Get single range measurement
float range = rangeSensor.readRangeSingleMillimeters();

// Send motion as mouse movement when the hand is between 80 and


200mm
if (range < 200 && range > 80) {
Mouse.move(deltaX, -deltaY, 0);
}

// Press the left mouse button when the hand is bellow 50mm
if (range < 50) {
Mouse.press();
} else {
Mouse.release();
}
}
28) Arduino Ankle Air Guitar Pedal
COMPONENTS AND SUPPLIES

Arduino Nano R3
any arduino is okay, im thinking on using
tinyduino × 1

mpc41010
× 1
digital potenciometer
SparkFun Triple Axis Accelerometer Breakout × 1
- ADXL335
any analogoutput accelerometer is okay
stereo audio jack 6,5 mm female adapter
× 1

stereo audio jack 6,5 mm cable


× 1

RGB Diffused Common Cathode


just for fun, no needed
× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT


We need to weld the correct things, so follow along.
The current interest in dubstep was growing, and I was
ready to spend 40€ on one expression pedal for
my boss synthesizer when I remembered I was an
electronics nerd.
Then science occurred.
At first, I thought about drilling a shoe and gluing the
electronics inside, but I did not have a pair of shoes to
spare. So, I ended up purchasing a hair band and
stitching thread.
First steps with the MPC digital potentiometers
family:
We have a lot of types to choose from, but I picked
this one - the MPC41010.
MPC41010: single potentiometer, 10k ohm
MPC41050: single potentiometer, 50k ohm
MPC41100: single potentiometer, 100k ohm
MCP42010: two independent potentiometers,
10k ohm
MCP42050: two independent potentiometers,
50k ohm
MCP42100: two independent potentiometers,
100k ohm
More things about them here. Important things that
you need to know for hacking this device:
You can do similar things with other digital
potentiometers. (like the COM-10613, more
info)
The resistance is 0 to 10k ohms divided in 255
steps with each step of 39 ohms. (MATH!)
Serial communication: just use #include
<SPI.h>.

What I learned with the prototype:


When the device is reset, the human needs to set
the flat and the top values for adjusting the range
of movement.
It would be nice to implement a function that
chooses between the axis which had the wider
range of variation. This would be useful so that
you don't have to mind the position of the
accelerometer; you could put it in upside-down, on
the bass top, on your wrist, etc.
Maybe I need to implement a logarithmic
behaviour for the resistance values.
I need to take care of the 0 level because it
is highly instable.
Building the stereo jack 6,5 mm cable
Keep in mind I am poor. So for 4€, I bought the
components (couple of male jack endings and 1 meter of
cable).
We need to weld the correct things, so follow the scheme
and use some hot-shrink tube to do a fine job.
SCHEMATICS
CODE

#include <SPI.h>
#define debug //comment this line if you´re not gonna use the serial data
with the arduino ide

#define CS 10 //chipselect

#define accelerometerX A0//analogpins for the accelerometer


#define accelerometerY A1
#define accelerometerZ A2

#define RED 6 //rgb pins


#define GREEN 3
#define BLUE 5

//MCP41010 chip´s connection


// 39ohms per step of the
//CS 10 U vcc
//SCK 13 serial clock PBO--UPRESISTOR
//SI 11 serial imput PWO INRESISTOR
//gnd PAO--BOTTOMRESISTOR

int datarray[18]={0,0,0,0,0,0,1023,1023,1023,0,0,0,0,0,0};
int smoothingarray[15]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int rgb[3];
int i=0,chipvalue=0;
int ResistorValue=0;
void setup() {
//
//pinMode (GREEN, OUTPUT);//GREEN RGB (PWM)
//pinMode (BLUE, OUTPUT);//BLUE
//pinMode (RED, OUTPUT);//RED
//digitalWrite(GREEN, HIGH);//setting the led off at the begining
//digitalWrite (BLUE, HIGH);//
//digitalWrite (RED, HIGH);//

pinMode (CS, OUTPUT);//chipselect for the MCP41010 chip


pinMode (13, OUTPUT);//things are happening led
pinMode (accelerometerX, INPUT);//acelerometer´s inputs
pinMode (accelerometerY, INPUT);//
pinMode (accelerometerZ, INPUT);//
SPI.begin();
MCP41010Write(0);//init value horizontal foot

#ifdef debug
Serial.begin(9600);
#endif
}

void loop() {
datarray[0]=analogRead(accelerometerX);
datarray[1]=analogRead(accelerometerY);
datarray[2]=analogRead(accelerometerZ);

comparemaxmin(datarray);

detectRange(datarray);

ResistorValue=map(datarray[datarray[15]],datarray[datarray[15]+6]+20,dat
array[datarray[15]+3]-10,0,255);//+20 to the min and -10 to the max for
preventing unreachable edges

chipvalue =constrain(ResistorValue,0,255);

MCP41010Write(smoothing(chipvalue));

// //map(value, fromLow, fromHigh, toLow, toHigh)


// for(i=0;i<=2;i++){
// rgb[i]=map(datarray[i],datarray[i+6],datarray[i+3],0,255);
// }
////analogWrite(GREEN, rgb[0]);//EL LED DA PROBLEMAS DE
LECTURA ruido/////////////////////7
////analogWrite (BLUE, rgb[1]);//
////analogWrite (RED, rgb[2]);//

#ifdef debug
Serial.print("//RawReadings: ");
Serial.print(datarray[0]);
Serial.print(" ");
Serial.print(datarray[1]);
Serial.print(" ");
Serial.print(datarray[2]);

Serial.print(" /max ");


Serial.print(datarray[3]);
Serial.print(" ");
Serial.print(datarray[4]);
Serial.print(" ");
Serial.print(datarray[5]);

Serial.print(" /min ");


Serial.print(datarray[6]);
Serial.print(" ");
Serial.print(datarray[7]);
Serial.print(" ");
Serial.print(datarray[8]);

Serial.print(" //GAP :");


Serial.print(datarray[9]);
Serial.print(" ");
Serial.print(datarray[10]);
Serial.print(" ");
Serial.print(datarray[11]);

// Serial.print("/?? ");
// Serial.print(datarray[12]);
// Serial.print(" ");
// Serial.print(datarray[13]);
// Serial.print(" ");
// Serial.print(datarray[14]);

Serial.print(" //axis choose ");


Serial.print(datarray[15]);

Serial.print(" //chip value ");


Serial.print(chipvalue);

Serial.println();
#endif
delay(100);//delay for stability
}

void comparemaxmin(int datarray[])


{
for(i=0;i<=2;i++)
datarray[i+3]=max(datarray[i],datarray[i+3]);

for(i=0;i<=2;i++)
datarray[i+6]=min(datarray[i],datarray[i+6]);

void detectRange(int datarray[18])


{
for(i=0;i<=2;i++)
{
datarray[i+9]=abs(abs(datarray[i+3])-abs(datarray[i+6]));
}
if(datarray[9]>=datarray[10]&&datarray[9]>=datarray[11])//choosing the
axis with the wider range
datarray[15]=0;
if(datarray[10]>=datarray[9]&&datarray[10]>=datarray[11])
datarray[15]=1;
if(datarray[11]>=datarray[9]&&datarray[11]>=datarray[10])
datarray[15]=2;
}

void MCP41010Write(byte value) //speaking protocol with the mcp chip


{
// Note that the integer value passed to this subroutine
// is cast to a byte

digitalWrite(CS,LOW);
SPI.transfer(B00010001); // This tells the chip to set the pot
SPI.transfer(value); // This tells it the pot position
digitalWrite(CS,HIGH);
}

int smoothing(int data){


int result,j;

for(j=0;j<=14;j++){
smoothingarray[j] = smoothingarray[j+1];
}
smoothingarray[14]= data;

result=
(smoothingarray[0]+smoothingarray[1]+smoothingarray[2]+smoothingarray
[3]+smoothingarray[4])/5;
constrain(result,0,255);
return result;
}

29) Arduino Word Clock


COMPONENTS AND SUPPLIES

Arduino UNO & Genuino


UNO
× 1
any microcontroller will do

Real Time Clock (RTC) × 1


Texas Instruments 74hc595
× 1
shift register
STMicroelectronics uln2803a
× 1
darlington array
led strip
× 1

ic holders 16pin x3 and 18pin


x3 × 1

12v power supply


× 1
NECESSARY TOOLS AND MACHINES
mount board

acrylic board
APPS AND ONLINE SERVICES
Arduino IDE

rtc library

ABOUT THIS PROJECT


Introduction
All you need is an arduino and a RTC. I have removed
the switches and other hardware. Since DS1307 is
pretty stable, it does not require frequent time
changes! It will also keep the time even if there is a
power failure, thanks to its internal 3v battery. This
battery will last for years.
So even if you are going on a vacation, just turn off
the clock and the time will be running accurate when
you turn it back on!
I have made the code as simple as possible! It just
reads time from the RTC and updates the shift
registers.
Step 1: Collecting the Parts –
ELECTRONICS COMPONENTS USED
Main parts
Arduino or just atmega328p as i have used
(standalone) x1
RTC (Real Time Clock) DS1307 x1
Shift registers 74hc595 x3
ULN2803a Darlington Transistor Arrays as LED
drivers x3
LED strip I have used white...approx 2m
16 pin IC socket x3
18 pin IC socket x3
12v power source may be battery or wall adapter
Miscellaneous
Proto board / general PCB board
Connecting wires
Male header pins
Jumper wires- female-female
basic soldering
FRAME AND STENCIL
Mount board / thick cardboard
Glue, Tape
Scissors, Paper cutter
Acrylic Board (translucent white) / Plexi glass
Snickering of Words
Step 2: Making the Connections....
Follow the simple circuit diagram shown above.
I have used a standalone arduino which I can program
with FTDI cables, but any arduino board can be used
!!For this project even though we control 22
individual LED arrays, we just use 5 I/O pins from the
arduino ie.- 3 for shift Registors and 2 for RTC
module.
Using shift resistors is a great way to increase the i/o
pins.
Important thing about ULN2803a Drivers -
This IC is a darlington pair.
Hence connect all the cathodes [positive terminals] of
the LEDs to the source and the anodes
[negative/ground] to the respective output terminals of
the driver!
Step 3: Building the Frame
Here I have used mount board for the construction...
It is easy to cut, bend and handle the mount board. It
is also has less strength.
Any material like wood, plastic, metal etc. can be
used.
Cut a piece of mount board the size of the front
Board with words.
Make a rough sketch of the words and their
alignment on the board.
Cut strips of mount board of size may be 1.5 cm..
This is to make compartments, the size of the
words. this will prevent the light from one word
to diffuse and illuminate the surrounding words.
Place the strips horizontally after each line of
words and vertically in between the words; make
small boxes for each of the word.
Finally make a box that will sneakily fit the
electronics, the LED board, anti-diffusion boxes
and the outermost board with words stickered on
to it.
Step 4: Connecting the LEDs
I'm using the LED strip in this project. It is easy to
operate. It can be cut for desired length, no need of
soldering each and every led to make an array. LED
Strips also come with a peel-off sticker at the back.
Just cut the required length of the strip depending on
the size of the word and stick it on the LED board (
mount board). Remember that most of the led strips
have connectors at an interval of 3 LEDs. So you have
to cut at the indicated points only. Therefore even the
smallest word will have 3 LEDs.
You can even use the standard LEDs, solder them for
desired number of LEDs. Remember to use the
resistor for each array that you make. the value of the
resistor depends on the specifications of the LEDs
used. You can check here for further info, LED
calc or this one.
Connect all the Positive terminals of the LED strip
together. This is the common Vcc for the leds.
You can see that i have connected it using thin copper
wire. Then Connect wires for all the individual ground
terminals for each word and bring it back to connect it
to the driver.
Step 5: The Codes
The originalcode itself is well commented and easily
understandable.
The #define section allots the pins on the shift register
for individual words. They will be updated each time
when the time changes.
The void WriteLEDs function updates the shift regesters
through the data pin.
The void self-test function blinks all the LED words in a sequence so that you
know everythingis working correctly. i.e. for
troubleshooting.
The void displaytime function will check the time with the RTC
chip and see which words to be illuminated accordingly.
The rest can be easily made out by the code itself.
GitHub

Step 6: Finishing It Off.


Place all the controller boards; arduino and circuit
which contains shift registers, RTC chip and LED
drivers.
Connect the LED arrays of each word to the
respective pin of the driver.
Place the LED board inside the casing and fix it
in place...
The main outer stencil is made by sticking the
words onto any acrylic or plastic.
Make a hole at the back for fixing the clock for
using a nail.

SCHEMATICS
CODE

/*

RTClib information---
SDA pin -----> A4 / D18
SCL pin -----> A5 / D19
*/

#include <string.h>
#include <Wire.h>
#include"RTClib.h"

// Display output pin assignments


#define MINUTES Display1=Display1 | B00000001
#define MTEN Display1=Display1 | B00000010
#define HALF Display1=Display1 | B00000100
#define PAST Display1=Display1 | B00001000
#define THREE Display1=Display1 | B00010000
#define ITIS Display1=Display1 | B00100000
#define TWENTY Display1=Display1 | B01000000
#define TO Display1=Display1 | B10000000

#define TWO Display2=Display2 | B00000001


#define SIX Display2=Display2 | B00000010
#define TWELVE Display2=Display2 | B00000100
#define HFIVE Display2=Display2 | B00001000
#define SEVEN Display2=Display2 | B00010000
#define OCLOCK Display2=Display2 | B00100000
#define ONE Display2=Display2 | B01000000
#define QUARTER Display2=Display2 | B10000000

#define EIGHT Display3=Display3 | B00000001


#define MFIVE Display3=Display3 | B00000010
#define ARDUINO Display3=Display3 | B00000100
#define ELEVEN Display3=Display3 | B00001000
#define HTEN Display3=Display3 | B00010000
#define NINE Display3=Display3 | B00100000
#define FOUR Display3=Display3 | B01000000
#define RBK Display3=Display3 | B10000000

int hour=0, minute=0, second=0;


static unsigned long msTick =0; // the number of Millisecond Ticks since
we last
// incremented the second counter
int selftestmode; // 1 = in self test - flash display
char Display1=0, Display2=0, Display3=0;

// hardware constants
int LEDClockPin=8; // Arduino Pin#8 - Shift register 74HC595 Pin 11
clock
int LEDDataPin=9; // Arduino Pin#9 - Shift register 74HC595 pin 14 Data
int LEDLatchPin=10; // Arduino Pin#10 - Shift register 74HC595 pin 12
Latch

// RTC DEFINE-
RTC_DS1307 RTC ;

void setup()
{
// initialise the hardware
// initialize the appropriate pins as outputs:
pinMode(LEDClockPin, OUTPUT);
pinMode(LEDDataPin, OUTPUT);
pinMode(LEDLatchPin, OUTPUT);

Serial.begin(9600); // setup the serial port to 9600 baud


Wire.begin();
RTC.begin();

// test whether the DS1307 is there


Serial.print("Verifying DS1307 ");

if ( RTC.isrunning()) {
Serial.println("RTC is running.....");
DateTime now = RTC.now();

Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(' ');
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
}

DateTime now = RTC.now();


msTick=millis(); // Initialise the msTick counter

selftest(); // validate the hardware for the user

selftestmode=0;

if ( RTC.isrunning() ) {
// Get the current time and date from the RTC chip

second=now.second();
minute=now.minute();
hour=now.hour();
}

displaytime(); // display the current time


}

void WriteLEDs(){
// Now we write the actual values to the hardware
shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, Display3);
shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, Display2);
shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, Display1);
digitalWrite(LEDLatchPin,HIGH);
//delay(2);
digitalWrite(LEDLatchPin,LOW);

void ledsoff(void) {
Display1=0;
Display2=0;
Display3=0;

void selftest(void){
// start by clearing the display to a known state
ledsoff();
ITIS;
WriteLEDs();
delay(500);
ledsoff();
MTEN;
WriteLEDs();
delay(500);
ledsoff();
HALF;
WriteLEDs();
delay(500);
ledsoff();
TWENTY;
WriteLEDs();
delay(500);
ledsoff();
QUARTER;
WriteLEDs();
delay(500);
ledsoff();
MFIVE;
WriteLEDs();
delay(500);
ledsoff();
MINUTES;
WriteLEDs();
delay(500);
ledsoff();
PAST;
WriteLEDs();
delay(500);
ledsoff();
TO;
WriteLEDs();
delay(500);
ledsoff();
ONE;
WriteLEDs();
delay(500);
ledsoff();
TWO;
WriteLEDs();
delay(500);
ledsoff();
THREE;
WriteLEDs();
delay(500);
ledsoff();
FOUR;
WriteLEDs();
delay(500);
ledsoff();
HFIVE;
WriteLEDs();
delay(500);
ledsoff();
SIX;
WriteLEDs();
delay(500);
ledsoff();
SEVEN;
WriteLEDs();
delay(500);
ledsoff();
EIGHT;
WriteLEDs();
delay(500);
ledsoff();
NINE;
WriteLEDs();
delay(500);
ledsoff();
HTEN;
WriteLEDs();
delay(500);
ledsoff();
ELEVEN;
WriteLEDs();
delay(500);
ledsoff();
TWELVE;
WriteLEDs();
delay(500);
ledsoff();
OCLOCK;
WriteLEDs();
delay(500);
ledsoff();
RBK;
WriteLEDs();
delay(500);
ledsoff();
ARDUINO;
WriteLEDs();
delay(500);
ledsoff();

for(int i=0; i<5; i++)


{
Display1=255;
Display2=255;
Display3=255;
WriteLEDs();
delay(500);
ledsoff();
WriteLEDs();
delay(500);
}

void displaytime(void){

// start by clearing the display to a known state


ledsoff();

// Now, turn on the "It is" leds


ITIS;
Serial.print("It is ");

// now we display the appropriate minute counter


if ((minute>4) && (minute<10)) {
MFIVE;
MINUTES;
Serial.print("Five Minutes ");
}
if ((minute>9) && (minute<15)) {
MTEN;
MINUTES;
Serial.print("Ten Minutes ");
}
if ((minute>14) && (minute<20)) {
QUARTER;
Serial.print("Quarter ");
}
if ((minute>19) && (minute<25)) {
TWENTY;
MINUTES;
Serial.print("Twenty Minutes ");
}
if ((minute>24) && (minute<30)) {
TWENTY;
MFIVE;
MINUTES;
Serial.print("Twenty Five Minutes ");
}
if ((minute>29) && (minute<35)) {
HALF;
Serial.print("Half ");
}
if ((minute>34) && (minute<40)) {
TWENTY;
MFIVE;
MINUTES;
Serial.print("Twenty Five Minutes ");
}
if ((minute>39) && (minute<45)) {
TWENTY;
MINUTES;
Serial.print("Twenty Minutes ");
}
if ((minute>44) && (minute<50)) {
QUARTER;
Serial.print("Quarter ");
}
if ((minute>49) && (minute<55)) {
MTEN;
MINUTES;
Serial.print("Ten Minutes ");
}
if (minute>54) {
MFIVE;
MINUTES;
Serial.print("Five Minutes ");
}

if ((minute <5))
{
switch (hour) {
case 1:
case 13:
ONE;
Serial.print("One ");
break;
case 2:
case 14:
TWO;
Serial.print("Two ");
break;
case 3:
case 15:
THREE;
Serial.print("Three ");
break;
case 4:
case 16:
FOUR;
Serial.print("Four ");
break;
case 5:
case 17:
HFIVE;
Serial.print("Five ");
break;
case 6:
case 18:
SIX;
Serial.print("Six ");
break;
case 7:
case 19:
SEVEN;
Serial.print("Seven ");
break;
case 8:
case 20:
EIGHT;
Serial.print("Eight ");
break;
case 9:
case 21:
NINE;
Serial.print("Nine ");
break;
case 10:
case 22:
HTEN;
Serial.print("Ten ");
break;
case 11:
case 23:
ELEVEN;
Serial.print("Eleven ");
break;
case 0:
case 12:
TWELVE;
Serial.print("Twelve ");
break;
}
OCLOCK;
Serial.println("O'Clock");
}
else
if ((minute < 35) && (minute >4))
{
PAST;
Serial.print("Past ");
switch (hour) {
case 1:
case 13:
ONE;
Serial.println("One ");
break;
case 2:
case 14:
TWO;
Serial.println("Two ");
break;
case 3:
case 15:
THREE;
Serial.println("Three ");
break;
case 4:
case 16:
FOUR;
Serial.println("Four ");
break;
case 5:
case 17:
HFIVE;
Serial.println("Five ");
break;
case 6:
case 18:
SIX;
Serial.println("Six ");
break;
case 7:
case 19:
SEVEN;
Serial.println("Seven ");
break;
case 8:
case 20:
EIGHT;
Serial.println("Eight ");
break;
case 9:
case 21:
NINE;
Serial.println("Nine ");
break;
case 10:
case 22:
HTEN;
Serial.println("Ten ");
break;
case 11:
case 23:
ELEVEN;
Serial.println("Eleven ");
break;
case 0:
case 12:
TWELVE;
Serial.println("Twelve ");
break;
}
}
else
{
// if we are greater than 34 minutes past the hour then display
// the next hour, as we will be displaying a 'to' sign
TO;
Serial.print("To ");
switch (hour) {
case 1:
case 13:
TWO;
Serial.println("Two ");
break;
case 14:
case 2:
THREE;
Serial.println("Three ");
break;
case 15:
case 3:
FOUR;
Serial.println("Four ");
break;
case 4:
case 16:
HFIVE;
Serial.println("Five ");
break;
case 5:
case 17:
SIX;
Serial.println("Six ");
break;
case 6:
case 18:
SEVEN;
Serial.println("Seven ");
break;
case 7:
case 19:
EIGHT;
Serial.println("Eight ");
break;
case 8:
case 20:
NINE;
Serial.println("Nine ");
break;
case 9:
case 21:
HTEN;
Serial.println("Ten ");
break;
case 10:
case 22:
ELEVEN;
Serial.println("Eleven ");
break;
case 11:
case 23:
TWELVE;
Serial.println("Twelve ");
break;
case 0:
case 12:
ONE;
Serial.println("One ");
break;
}
}

void loop()
{
DateTime now = RTC.now();

second=now.second();
minute=now.minute();
hour=now.hour();

//Serial.println("Loop Started");

// Flash the onboard Pin13 Led every 5 sec so we know something is


hapening!
if ( millis() - msTick >5000) {
msTick=millis();

digitalWrite(13,HIGH);
delay(50);
digitalWrite(13,LOW);
delay(50);
digitalWrite(13,HIGH);
delay(50);
digitalWrite(13,LOW);

Serial.print(second);
Serial.print("..");
}

if (second==59) // Update the display every 1 minute...


{
displaytime();
WriteLEDs();
}

30) Arduino Traffic Advisor


COMPONENTS AND SUPPLIES
Arduino Nano R3
× 1

3 mm LED: Yellow
× 8

3 mm LED: Green
× 1

Pushbutton Switch, Momentary


4 pin, small generaic push × 6
button

Resistor 220 ohm


× 6

Hook Up Wire Kit, 22 AWG


× 1
ControlEverything.com Relay × 1
Shield for Particle Photon I²C 8-
Channel SPDT 10-Amp

Adafruit NeoPixel Digital RGB


LED Strip 144 LED, 1m White
× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)

Solder Wire, Lead Free

Wire Stripper & Cutter, 18-10 AWG /


0.75-4mm² Capacity Wires

ABOUT THIS PROJECT


I wanted to see how hard it would be to make this.
this is a traffic advisor controller.
it controls 8 light segments and has a small led readout
to show you what pattern is currently being used.
a power light to show that power is on.
6 buttons that do various actions
button 1: left arrow
button 2: center out
button 3: right arrow
button 4: warning patterns
button 5: switch warning pattern
button 6: turn off lights/ save warning pattern
there are the 3 directional patterns and 10 warning
patterns.
any mode can be activated at any time with no delay.
warning patterns are:
1:even / odd fast flash
2: half and half
3: half and half with fast flash
4: 2 by 2
5: 2 by 2 parallel
6: out flash
7: 3 out center
8: outboard
9:inboard
10: even / odd slow
SCHEMATICS
CODE

#include <EEPROM.h>
int warning_button = A5;
int left_button = 2;
int center_button = 4;
int right_button = 3;
int off_button = A0;
int pattern_button = A2;
int statuslight = 13;
int LEDright[] = {5, 6, 7, 8, 9, 10, 11, 12};
int LEDleft[] = {12, 11, 10, 9, 8, 7, 6, 5};
int centerleft[] = {9, 10, 11, 12};
int centerright[] = {8, 7, 6, 5};
int light = 0;
int counter = 1;
int pattern_count = 0;
int warning_count = EEPROM.read(0);
long lasttimer = 0;
static long timer = 200;
static long timer2 = 300;
static long switch_timer = 4000;
#define LEFTside 0x0
#define RIGHTside 0x1
byte whichLED = LEFTside;
byte LEFT_state = LOW;
byte RIGHT_state = LOW;
unsigned long switchDelay = 1000;
unsigned long switchDelay2 = 500;
unsigned long strobeDelay = 75;
unsigned long strobeWait = strobeDelay;
unsigned long waitUntilSwitch = switchDelay;
unsigned long sequenceStartTime;
//----------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
for (int i = 0; i < 8; i++) {
pinMode(LEDright[i], OUTPUT);
}
pinMode(statuslight, OUTPUT);
pinMode(warning_button, INPUT_PULLUP);
pinMode(left_button, INPUT_PULLUP);
pinMode(center_button, INPUT_PULLUP);
pinMode(right_button, INPUT_PULLUP);
pinMode(off_button, INPUT_PULLUP);
pinMode(pattern_button, INPUT_PULLUP);
pinMode(12, OUTPUT);
pinMode(11, OUTPUT);
pinMode(10, OUTPUT);
pinMode(9, OUTPUT);
pinMode(8, OUTPUT);
pinMode(7, OUTPUT);
pinMode(6, OUTPUT);
pinMode(5, OUTPUT);
}
//------------------------------------------------------------------------
void loop() {
digitalWrite(13, HIGH);
delayMicroseconds(10); // Approximately 10% duty cycle @ 1KHz
digitalWrite(13, LOW);
delayMicroseconds(1000 - 10);
if (digitalRead(pattern_button) == HIGH)
{
delay(500);
warning_count++;
if (warning_count > 10) {
warning_count = 1;
}
}
if (digitalRead(warning_button) == HIGH)
{
delay(50);
pattern_count = 1;
}
if (digitalRead(left_button) == HIGH)
{
delay(50);
pattern_count = 2;
}
if (digitalRead(center_button) == HIGH)
{
delay(50);
pattern_count = 3;
}
if (digitalRead(right_button) == HIGH)
{
delay(50);
pattern_count = 4;
}
if (digitalRead(off_button) == HIGH)
{
delay(50);
pattern_count = 0;
EEPROM.update(0,warning_count);
}
switch (pattern_count) {
case 0:
pattern_off();
break;
case 1:
traffic_left();
break;
case 2:
traffic_center();
break;
case 3:
traffic_right();
break;
case 4:
traffic_warning();
break;
}
}
void pattern_off() {
for (int i = 0; i <= 7; i++) {
digitalWrite(LEDright[i], LOW);
}
}
void traffic_left() {
unsigned long currenttimer = millis();
if (currenttimer - lasttimer >= timer) {
lasttimer = currenttimer;
for (int i = 0; i <= 7; i++) {
digitalWrite(LEDright[i], LOW);
}
digitalWrite(LEDleft[light], LOW);
light = light + counter;
if (light > 7) {
light = 0;
counter = 1;
}
digitalWrite(LEDleft[light], HIGH);
}
}
void traffic_center() {
unsigned long currenttimer = millis();
if (currenttimer - lasttimer >= timer2) {
lasttimer = currenttimer;
for (int i = 0; i <= 7; i++) {
digitalWrite(LEDright[i], LOW);
}
digitalWrite(centerright[light], LOW);
digitalWrite(centerleft[light], LOW);
light = light + counter;
if (light > 3) {
light = 0;
counter = 1;
}
digitalWrite(centerright[light], HIGH);
digitalWrite(centerleft[light], HIGH);
}
}
void traffic_right() {
unsigned long currenttimer = millis();
if (currenttimer - lasttimer >= timer) {
lasttimer = currenttimer;
for (int i = 0; i <= 7; i++) {
digitalWrite(LEDright[i], LOW);
}
digitalWrite(LEDright[light], LOW);
light = light + counter;
if (light > 7) {
light = 0;
counter = 1;
}
digitalWrite(LEDright[light], HIGH);
}
}
void traffic_warning() {
switch (warning_count) {
case 1:
even_odd_flash();
break;
case 2:
half_half();
break;
case 3:
half_half_flash();
break;
case 4:
two_by_two();
break;
case 5:
two_by_two_parallel();
break;
case 6:
out_flash();
break;
case 7:
one_center();
break;
case 8:
outboard();
break;
case 9:
inboard();
break;
case 10:
even_odd();
break;
}
}
void even_odd_flash() {
for (int i = 0; i <= 7; i++) {
digitalWrite(LEDright[i], LOW);
}
digitalWrite(12, LEFT_state);
digitalWrite(11, RIGHT_state);
digitalWrite(10, LEFT_state);
digitalWrite(9, RIGHT_state);
digitalWrite(8, LEFT_state);
digitalWrite(7, RIGHT_state);
digitalWrite(6, LEFT_state);
digitalWrite(5, RIGHT_state);
if ((long)(millis() - waitUntilSwitch) >= 0) {
LEFT_state = LOW;
RIGHT_state = LOW;
whichLED = !whichLED;
waitUntilSwitch += switchDelay;
}
if ((long)(millis() - strobeWait) >= 0) {
if (whichLED == LEFTside)
LEFT_state = !LEFT_state;
if (whichLED == RIGHTside)
RIGHT_state = !RIGHT_state;
strobeWait += strobeDelay;
}
}
void half_half_flash() {
for (int i = 0; i <= 7; i++) {
digitalWrite(LEDright[i], LOW);
}
digitalWrite(12, LEFT_state);
digitalWrite(11, LEFT_state);
digitalWrite(10, LEFT_state);
digitalWrite(9, LEFT_state);
digitalWrite(8, RIGHT_state);
digitalWrite(7, RIGHT_state);
digitalWrite(6, RIGHT_state);
digitalWrite(5, RIGHT_state);
if ((long)(millis() - waitUntilSwitch) >= 0) {
LEFT_state = LOW;
RIGHT_state = LOW;
whichLED = !whichLED;
waitUntilSwitch += switchDelay2;
}
if ((long)(millis() - strobeWait) >= 0) {
if (whichLED == LEFTside)
LEFT_state = !LEFT_state;
if (whichLED == RIGHTside)
RIGHT_state = !RIGHT_state;
strobeWait += strobeDelay;
}
}
void half_half() {
for (int i = 0; i <= 7; i++) {
digitalWrite(LEDright[i], LOW);
}
long time = millis() - sequenceStartTime;
if (time < 250)
{
digitalWrite(12, HIGH);
digitalWrite(11, HIGH);
digitalWrite(10, HIGH);
digitalWrite(9, HIGH);
digitalWrite(8, LOW);
digitalWrite(7, LOW);
digitalWrite(6, LOW);
digitalWrite(5, LOW);
}
else if (time < 500)
{
digitalWrite(12, LOW);
digitalWrite(11, LOW);
digitalWrite(10, LOW);
digitalWrite(9, LOW);
digitalWrite(8, HIGH);
digitalWrite(7, HIGH);
digitalWrite(6, HIGH);
digitalWrite(5, HIGH);
}
else sequenceStartTime = millis();
}
void out_flash() {
for (int i = 0; i <= 7; i++) {
digitalWrite(LEDright[i], LOW);
}
long time = millis() - sequenceStartTime;
if (time < 150)
{
digitalWrite(12, HIGH);
digitalWrite(11, HIGH);
digitalWrite(10, LOW);
digitalWrite(9, LOW);
digitalWrite(8, LOW);
digitalWrite(7, LOW);
digitalWrite(6, HIGH);
digitalWrite(5, HIGH);
}
else if (time < 300)
{
digitalWrite(12, LOW);
digitalWrite(11, HIGH);
digitalWrite(10, HIGH);
digitalWrite(9, LOW);
digitalWrite(8, LOW);
digitalWrite(7, HIGH);
digitalWrite(6, HIGH);
digitalWrite(5, LOW);
}
else sequenceStartTime = millis();
}
void two_by_two() {
for (int i = 0; i <= 7; i++) {
digitalWrite(LEDright[i], LOW);
}
long time = millis() - sequenceStartTime;
if (time < 150)
{
digitalWrite(12, HIGH);
digitalWrite(11, HIGH);
digitalWrite(10, LOW);
digitalWrite(9, LOW);
digitalWrite(8, LOW);
digitalWrite(7, LOW);
digitalWrite(6, HIGH);
digitalWrite(5, HIGH);
}
else if (time < 300)
{
digitalWrite(12, LOW);
digitalWrite(11, LOW);
digitalWrite(10, HIGH);
digitalWrite(9, HIGH);
digitalWrite(8, HIGH);
digitalWrite(7, HIGH);
digitalWrite(6, LOW);
digitalWrite(5, LOW);
}
else sequenceStartTime = millis();
}
void two_by_two_parallel() {
for (int i = 0; i <= 7; i++) {
digitalWrite(LEDright[i], LOW);
}
long time = millis() - sequenceStartTime;
if (time < 150)
{
digitalWrite(12, HIGH);
digitalWrite(11, HIGH);
digitalWrite(10, LOW);
digitalWrite(9, LOW);
digitalWrite(8, HIGH);
digitalWrite(7, HIGH);
digitalWrite(6, LOW);
digitalWrite(5, LOW);
}
else if (time < 300)
{
digitalWrite(12, LOW);
digitalWrite(11, LOW);
digitalWrite(10, HIGH);
digitalWrite(9, HIGH);
digitalWrite(8, LOW);
digitalWrite(7, LOW);
digitalWrite(6, HIGH);
digitalWrite(5, HIGH);
}
else sequenceStartTime = millis();
}
void one_center() {
for (int i = 0; i <= 7; i++) {
digitalWrite(LEDright[i], LOW);
}
long time = millis() - sequenceStartTime;
if (time < 500)
{
digitalWrite(12, HIGH);
digitalWrite(11, HIGH);
digitalWrite(10, HIGH);
digitalWrite(9, LOW);
digitalWrite(8, HIGH);
digitalWrite(7, LOW);
digitalWrite(6, LOW);
digitalWrite(5, LOW);
}
else if (time < 1000)
{
digitalWrite(12, LOW);
digitalWrite(11, LOW);
digitalWrite(10, LOW);
digitalWrite(9, HIGH);
digitalWrite(8, LOW);
digitalWrite(7, HIGH);
digitalWrite(6, HIGH);
digitalWrite(5, HIGH);
}
else sequenceStartTime = millis();
}
void outboard() {
for (int i = 0; i <= 7; i++) {
digitalWrite(LEDright[i], LOW);
}
long time = millis() - sequenceStartTime;
if (time < 200)
{
digitalWrite(12, HIGH);
digitalWrite(11, HIGH);
digitalWrite(6, LOW);
digitalWrite(5, LOW);
}
else if (time < 400)
{
digitalWrite(12, LOW);
digitalWrite(11, LOW);
digitalWrite(6, HIGH);
digitalWrite(5, HIGH);
}
else sequenceStartTime = millis();
}
void inboard() {
for (int i = 0; i <= 7; i++) {
digitalWrite(LEDright[i], LOW);
}
long time = millis() - sequenceStartTime;
if (time < 200)
{
digitalWrite(11, HIGH);
digitalWrite(10, HIGH);
digitalWrite(9, LOW);
digitalWrite(8, LOW);
digitalWrite(7, HIGH);
digitalWrite(6, HIGH);
}
else if (time < 400)
{
digitalWrite(11, LOW);
digitalWrite(10, LOW);
digitalWrite(9, HIGH);
digitalWrite(8, HIGH);
digitalWrite(7, LOW);
digitalWrite(6, LOW);
}
else sequenceStartTime = millis();
}
void even_odd() {
for (int i = 0; i <= 7; i++) {
digitalWrite(LEDright[i], LOW);
}
long time = millis() - sequenceStartTime;
if (time < 300)
{
digitalWrite(12, HIGH);
digitalWrite(11, LOW);
digitalWrite(10, HIGH);
digitalWrite(9, LOW);
digitalWrite(8, HIGH);
digitalWrite(7, LOW);
digitalWrite(6, HIGH);
digitalWrite(5, LOW);
}
else if (time < 600)
{
digitalWrite(12, LOW);
digitalWrite(11, HIGH);
digitalWrite(10, LOW);
digitalWrite(9, HIGH);
digitalWrite(8, LOW);
digitalWrite(7, HIGH);
digitalWrite(6, LOW);
digitalWrite(5, HIGH);
}
else sequenceStartTime = millis();
}
31) Arduino Word Clock on 8X8 RGB LED Matrix

COMPONENTS AND SUPPLIES


Arduino Nano R3 × 1

Full-color RGB 8x8


LED+Colorful Magic Matrix
Driver shield Colorduino KIT × 1
DIY

Maxim Integrated DS1307 64 x


8, Serial, I²C Real-Time Clock
× 1

SparkFun Pushbutton switch


12mm
× 2

Photo resistor
× 1

Rotary potentiometer (generic)


× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT


Full-color RGB 8x8 LED+Colorful Magic Matrix
Driver shield Colorduino KIT DIY" which is also
known as Funduino, consists of the 8x8 RGB LED
matrix and driver shield (control board with atmega
chip and LED drivers).
This is probably the best project that can be done with
this module. There are many projects on the Internet
that are just pattern generators and nothing more.
Mark Wilson made an intuitive word clock, and even
wrote his own library "chromaduino" which you can
find at GitHub:
https://github.com/funnypolynomial/Chromaduino
It drives the LEDs and receives display information
from a master over I2C.
Now I will try to explain step by step the construction
of this device. First, you have to program the control
board. For this purpose we take Arduino Uno, from
which we extract the Atmega chip, and connect with
the control board in the following way:
GND-GND, 5V-VCC, RX(D0)-RXD, TX(D1)-TXD
and RESET-DTR (Arduino-Control board)
In Arduino IDE we choose the appropriate serial port
and Duemilanove board and upload chromaduino.ino
library. This will program the ATmega on the
Funduino/Colorduino board. The matrix is placed on
the control board in a way that pin 1 on the matrix
goes to Blue pin 1 on the board.
Next, we need to program the Arduino Nano (master)
board, and on it, through the I2C protocol connect
Colorduino and DS3231 Real-time clock module as
described in the scheme below. There are also two
buttons ("Adj" and "Set") connected to the analog
inputs A2 and A3 that are used to set the clock:
- Pressing Adj cycles through color modes: RGB, reds,
greens, blues, white(ish) and random. Unless the
current time is on the hour, in which case it toggles
showing NONE/EVEN
- Pressing and holding Set sets the display dimming,
first the ambient level to "DIM AT" then the
brightness to "DIM TO"
- Pressing Set and Adj cycles through display off and
alternate faces
- Holding Set at power on runs the LED matrix demo
- Holding Adj at power on runs the clock in demo
mode
- Holding Set and Adj at power on resets the clock
configuration
The clock contains two Clock faces. The first face
("Half Ten") shows the time as MINUTES TO HOUR
or MINUTES OF HOUR, for example, FIFTEEN TO
TEN (at 9:45) or FIFTEEN OF TEN (at 10:15). The
second face ("Ten Thirty") simply shows the time as
HOUR MINUTES, for example, TEN FIFTEEN (at
10:15).
I made the letter plates at a local graphic design
company where I printed faces on a transparent plastic
plate, and for better visibility, I put a sheet of white
paper between a plastic grid and a letter plate. I have
printed the plastic grid on my 3D printer.
SCHEMATICS
CODE

#include "arduino.h"
#include <avr/pgmspace.h>
#include <Wire.h>
#include <EEPROM.h>
#include "PINS.h"
#include "RTC.h"
#include "LDR.h"
#include "LEDS.h"
#include "BTN.h"
#include "CFG.h"
#include "CLK.h"

/*
A "word clock" showing the time on one of two 8x8
character grids:
TWENONTY or THRTWONE
FIFVTEEN TWELEVEN
HALFMTOF ENEIGHTI
FOURFIVE SIXSEVEN
SIXSEVEN FOURFIVE
EIGHTHRI THIRTWEN
TWELEVEN MFIFORTY
ONETWOEE EFIVTEEN

Driving an 8x8 RGB LED matrix.

Mark Wilson
15 Dec 2016 - Initial version
*/

//#define _DEBUG

void setup()
{
#ifdef _DEBUG
Serial.begin(38400);
Serial.println("wordclok");
#endif

pins.setup();
digitalWrite(PINS::STD_LED, HIGH);
rtc.setup();
#ifndef _DEBUG
randomSeed(rtc.getSeed());
#endif
ldr.setup();
leds.setup();
cfg.setup();
clk.setup();
digitalWrite(PINS::STD_LED, LOW);
}

void loop()
{
clk.loop();
}
32) Arduino Indoor NeoPixel Thermometer
COMPONENTS AND SUPPLIES
Arduino UNO & Genuino
UNO
× 1

NeoPixel
× 1

LCD readout
× 1

TMP36 sensor
× 1

Resistor 1k ohm × 1
470 ohm resistor
× 1

Rotary potentiometer (generic)


× 1

Simple momentary switch


× 1

F to M jumper wires
× 1
for the LCD
M to M Jumpers
× 1
for everything else
Breadboard (generic)
× 1

ABOUT THIS PROJECT


This is a quick, intermediate Arduino project that
takes a temperature reading from a TMP36 , reads it
onto an LCD screen and gives an "Analog" readout on
a Neopixel stick that changes color and number of
lights lit every 10 degrees Fahrenheit. It's easily
customizable as NeoPixels can be coded in many ways
so the NeoPixel stick can change size and colors every
which way a maker would want it to.
Step 1: Gather Components
For this build you will need an Arduino (any one will
do, I used Uno), NeoPixels (can be found here) an
LCD screen (I used this one) a TMP36 sensor (or
comparable, I used this inexpensive one from Adafruit
) a 1k ohm resistor, a 470 ohm resistor, a
potentiometer, a simple momentary switch, F to M
jumper wires (for the LCD) and M to M Jumpers (for
everything else) and a breadboard.

Step 2: Construct Circuit


Fritzing View of Circuit
From the fritzing diagram the circuit looks a little
confusing but it's actually relatively simple. What is
important to take note is you're going to want the
TMP36 on a separate circuit from the rest of the
project because some noise that's caused by the Pixels
messes up the voltage readout from the TMP36 and in
turn the temperature reading. When it comes to the
Pixels a bit a soldering is going to have to happen.
You're going to want to use 4 plain, everyday headers,
and solder them directly onto the NeoPixel stick. It's
absolutely imperative that you get the pin out correct
on this otherwise you'll have to de and resolder the
headers and trust me, the copper pads on the
NeoPixels do not like being resoldered and while
NeoPixels are not the most expensive component in
the world, several sticks that are rendered unusable
because the copper pads have been taken off add up
very quickly. To solder you will want a good iron and
a solder with a thin gauge. A pair of "third hands" are
especially useful in this project as the headers can be
tricky to solder onto the stick straight if the stick is
lying on the table.
How I set up the pixels and header in the Third hand
NeoPixel PinOut
I included a photo with the proper pin order, the side
with "DIN" goes to the breadboard/Arduino and the
side "DOUT" goes to other pixels or just the air. You
can use any number of NeoPixels, the one at the
Studio has 4 sticks for an especially prominent read
out that would be ideal if you were to enclose it in a
laser cut acrylic display (possibly stay tuned). On the
other hand, and as seen in one of the photos, I have a
smaller one using only one stick that works just fine at
home that you could then also turn into a wall
mounted display with a very quick enclosure. That's
one of the things with NeoPixels that make them
great, it doesn't take much code to make them fit
almost any size or form factor.
The pin out from the Arduino goes as follows:
A0 to Vout on TMP36
3.3V to TMP36 PWR Rail
AREF to TMP36 PWR Rail //AREF takes a
reference voltage and gives a more accurate
reading than just taking //straight from the
source, you'll see why this is important on the
next page
GND to TMP36 GND rail
5V to Primary PWR rail
other GND to Primary GND rail
13 to pin 4 on LCD
12 to momentary switch //while not necessary I
included a momentary switch that, when pressed
will switch //between Celsius and Fahrenheit
readout on the LCD
11 to pin 6 on LCD
6 to 470 ohm resistor leading to DIN on
NeoPixels //resistor prevents surges and damage
to the pixel stick
5 to pin 11 on LCD
4 to pin 12 on LCD
3 to pin 13 on LCD
2 to pin 14 on LCD
Other pinouts on LCD Screen
LCD pin 1 to one leg of potentiometer leading to
Primary GND rail
LCD pin 2 to one leg of potentiometer leading to
Primary PWR rail
LCD pin 3 to middle leg or "wiper" of
potentiometer //this controls contrast on the
screen
LCD pin 5 to primary GND rail
LCD pin 15 to primary PWR rail
LCD pin 16 to primary GND rail
The rest of the circuit is pretty self explanatory and
clear on the Fritzing Diagram, just remember to keep
the TMP36 and Primary circuits separate.
SCHEMATICS
CODE

#include <LiquidCrystal.h>
#include <Adafruit_NeoPixel.h>

// Create a variable that will store the temperature value


int TMPin = 0;
const int button = 12;
int lastColor = -1;

#define aref_voltage 3.3


#define PIN 6

/*
Param 1 == number of pixels
Param 2 == Arduino pin attached to din
Param 3 == pixel type flags, add together as needed
NE0_KHZ800 800 KHZ bitstream (avg neopix)
NE0_GRB wired for GRB bitstream
*/
Adafruit_NeoPixel strip = Adafruit_NeoPixel(32, PIN,
NEO_GRB + NEO_KHZ800); //call Neopixels, 32
pixels in all, on pin 6, RGB system and 800 KHZ
LiquidCrystal lcd(13, 11, 5, 4, 3, 2); //call LCD display
void setup()
{
lcd.begin(16,2); //initialize LCD screen 16 by 2
strip.begin(); //begin neo pixel strip
strip.show(); //initialize strip
Serial.begin(9600);// serial monitor access
pinMode(button, INPUT); //button for celsius
analogReference(EXTERNAL); //analog reference for
use with TMP36
}

void loop()
{
double temperature;
double temp;
double tempF;

temp = tempMeasure(temperature); //call tempMeasure


function
tempF = (temp * 9.0/5.0 + 32); //take reading from
tempMeasure and convert to faharenheit

while(digitalRead(button) == false) //button is depressed


readout is in Celsius
{
Serial.println(temp); //prints in serial monitor
lcd.print(temp); //prints on LCD screen
lcd.setCursor(0,1); //sets cursor
delay(2000); //2 seconds between readings
lcd.clear(); //clear LCD after 2 seconds
}

pixelCaseF(tempF); //call pixelCase function that


controls lights
Serial.println(tempF); //print in serial
lcd.print(tempF); //print temp in F on LCD
lcd.setCursor(0,1); //set cursor
delay(2000); //take reading every 2 seconds
lcd.clear(); //clear LCD

}//end loop

double tempMeasure(double temperature)


{
// -----------------
// Read temperature
// -----------------

int reading = analogRead(TMPin); //voltage reading


double voltage = reading * aref_voltage; //take initial
reading and multiply by 3.3 ref voltage for arduino

voltage /= 1024.0; //divide reading by 1024 to map

temperature = (voltage - 0.5) * 100; //converts 10mv per


degree with 500 mV offset to (voltage - 500mV) * 100)

return temperature; //return temperature to top level


method

}//end tempMeasure

void pixelCaseF(double tempF)


/*
This method controls the neo-pixel for the "analog"
readout on the thermometer. With every temperature
group, the number of pixels lit changes along with the
color
*/

{
int i;
strip.setBrightness(64);
strip.show();
if (tempF >= 90.05)//if above 90 degrees, strip is red and
entire strip is lit
{
strip.clear();
for(int i=0;i <= 32;i++)
{
strip.setPixelColor(i, strip.Color(255,0,0));
}
}
else if (tempF < 90.2 && tempF >= 80.05) //if 90 >
tempF >= 80 orange and strip is partially lit up to 29th
pixel
{
strip.clear();
for(int i=0;i <= 28;i++)
{
strip.setPixelColor(i, strip.Color(255,128,0));
}
}
else if (tempF < 80.02 && tempF >= 70.5)// if 80 >
tempF >= 70 yellow-green and strip is lit up to 25th
pixel
{
strip.clear();
for(int i = 0; i <= 24; i++)
{
strip.setPixelColor(i,strip.Color(204,255,0));
}
}
else if (tempF < 70 && tempF >= 60.5)// if 70 > tempF
>= 60 green and strip is lit up to 21st pixel
{
strip.clear();
for(int i = 0; i<= 20; i++)
{
strip.setPixelColor(i,strip.Color(0,255,0));
}
}
else if (tempF < 60.02 && tempF >= 50.5) //if 60 >
tempF >= 50 blue and strip is lit up to 17th pixel
{
strip.clear();
for(int i = 0; i <= 16; i++)
{
strip.setPixelColor(i,strip.Color(0,0,255));
}
}
else if (tempF < 50.02 && tempF >= 40.5) //if 50 >
tempF >= 40 aqua and strip is lit to 13th pixel
{
strip.clear();
for(int i = 0; i <= 12; i++)
{
strip.setPixelColor(i, strip.Color(0,255,255));
}
}
else if (tempF < 40.02 && tempF >= 32.5) //if 40 >
tempF >= 32 fuschia and strip is lit to 9th pixel
{
strip.clear();
for(int i = 0; i <= 8; i++)
{
strip.setPixelColor(i, strip.Color(153, 51,255));
}
}
else if (tempF < 32.5) //temp < freezing white and strip
is lit to 5th pixel
{
strip.clear();
for(i = 0;i <= 4; i++)
{
strip.setPixelColor(i, strip.Color(255,255,255));
}//end for
}

strip.show(); //update color change

}//end pixelCase
33) Arduino LCD Video Game
COMPONENTS AND SUPPLIES

Breadboard (generic)
× 1

Jumper wires (generic)


× 1
Arduino UNO & Genuino UNO × 1

USB-A to B Cable
× 1

Rotary potentiometer (generic)


× 1

Analog joystick (Generic)


× 1

Buzzer
× 1

Adafruit Standard LCD - 16x2


White on Blue
× 1
APPS AND ONLINE SERVICES

Arduino IDE

ABOUT THIS PROJECT

This is a project that is based on a video game that I


found on the internet. This project has many features
such as a buzzer for beeping when your character
collides or jumps over obstacles. Also, to give it a
video game feeling, it has a joystick (must have a
button) because you simply press down on the
joystick's button to jump. This video game is about
you guessed it! (A man running and jumping over
obstacles and avoiding them.) The object of this game
is about getting as many points as possible (one point
for every second you are on the course and avoiding
the obstacles).

SCHEMATICS
CODE

#include <LiquidCrystal.h>

#define PIN_BUTTON 2
#define PIN_AUTOPLAY 1
#define PIN_BUZZER 8
#define PIN_READWRITE 10
#define PIN_CONTRAST 12

#define SPRITE_RUN1 1
#define SPRITE_RUN2 2
#define SPRITE_JUMP 3
#define SPRITE_JUMP_UPPER '.' // Use the '.' character for the head
#define SPRITE_JUMP_LOWER 4
#define SPRITE_TERRAIN_EMPTY ' ' // User the ' ' character
#define SPRITE_TERRAIN_SOLID 5
#define SPRITE_TERRAIN_SOLID_RIGHT 6
#define SPRITE_TERRAIN_SOLID_LEFT 7

#define HERO_HORIZONTAL_POSITION 1 // Horizontal position of


hero on screen

#define TERRAIN_WIDTH 16
#define TERRAIN_EMPTY 0
#define TERRAIN_LOWER_BLOCK 1
#define TERRAIN_UPPER_BLOCK 2

#define HERO_POSITION_OFF 0 // Hero is invisible


#define HERO_POSITION_RUN_LOWER_1 1 // Hero is running on lower
row (pose 1)
#define HERO_POSITION_RUN_LOWER_2 2 // (pose
2)
#define HERO_POSITION_JUMP_1 3 // Starting a jump
#define HERO_POSITION_JUMP_2 4 // Half-way up
#define HERO_POSITION_JUMP_3 5 // Jump is on upper row
#define HERO_POSITION_JUMP_4 6 // Jump is on upper row
#define HERO_POSITION_JUMP_5 7 // Jump is on upper row
#define HERO_POSITION_JUMP_6 8 // Jump is on upper row
#define HERO_POSITION_JUMP_7 9 // Half-way down
#define HERO_POSITION_JUMP_8 10 // About to land

#define HERO_POSITION_RUN_UPPER_1 11 // Hero is running on upper


row (pose 1)
#define HERO_POSITION_RUN_UPPER_2 12 // (pose
2)

LiquidCrystal lcd(11, 9, 6, 5, 4, 3);


static char terrainUpper[TERRAIN_WIDTH + 1];
static char terrainLower[TERRAIN_WIDTH + 1];
static bool buttonPushed = false;

void initializeGraphics(){
static byte graphics[] = {
// Run position 1
B01100,
B01100,
B00000,
B01110,
B11100,
B01100,
B11010,
B10011,
// Run position 2
B01100,
B01100,
B00000,
B01100,
B01100,
B01100,
B01100,
B01110,
// Jump
B01100,
B01100,
B00000,
B11110,
B01101,
B11111,
B10000,
B00000,
// Jump lower
B11110,
B01101,
B11111,
B10000,
B00000,
B00000,
B00000,
B00000,
// Ground
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
// Ground right
B00011,
B00011,
B00011,
B00011,
B00011,
B00011,
B00011,
B00011,
// Ground left
B11000,
B11000,
B11000,
B11000,
B11000,
B11000,
B11000,
B11000,
};
int i;
// Skip using character 0, this allows lcd.print() to be used to
// quickly draw multiple characters
for (i = 0; i < 7; ++i) {
lcd.createChar(i + 1, &graphics[i * 8]);
}
for (i = 0; i < TERRAIN_WIDTH; ++i) {
terrainUpper[i] = SPRITE_TERRAIN_EMPTY;
terrainLower[i] = SPRITE_TERRAIN_EMPTY;
}
}

// Slide the terrain to the left in half-character increments


//
void advanceTerrain(char* terrain, byte newTerrain){
for (int i = 0; i < TERRAIN_WIDTH; ++i) {
char current = terrain[i];
char next = (i == TERRAIN_WIDTH-1) ? newTerrain : terrain[i+1];
switch (current){
case SPRITE_TERRAIN_EMPTY:
terrain[i] = (next == SPRITE_TERRAIN_SOLID) ?
SPRITE_TERRAIN_SOLID_RIGHT : SPRITE_TERRAIN_EMPTY;
break;
case SPRITE_TERRAIN_SOLID:
terrain[i] = (next == SPRITE_TERRAIN_EMPTY) ?
SPRITE_TERRAIN_SOLID_LEFT : SPRITE_TERRAIN_SOLID;
break;
case SPRITE_TERRAIN_SOLID_RIGHT:
terrain[i] = SPRITE_TERRAIN_SOLID;
break;
case SPRITE_TERRAIN_SOLID_LEFT:
terrain[i] = SPRITE_TERRAIN_EMPTY;
break;
}
}
}

bool drawHero(byte position, char* terrainUpper, char* terrainLower,


unsigned int score) {
bool collide = false;
char upperSave = terrainUpper[HERO_HORIZONTAL_POSITION];
char lowerSave = terrainLower[HERO_HORIZONTAL_POSITION];
byte upper, lower;
switch (position) {
case HERO_POSITION_OFF:
upper = lower = SPRITE_TERRAIN_EMPTY;
break;
case HERO_POSITION_RUN_LOWER_1:
upper = SPRITE_TERRAIN_EMPTY;
lower = SPRITE_RUN1;
break;
case HERO_POSITION_RUN_LOWER_2:
upper = SPRITE_TERRAIN_EMPTY;
lower = SPRITE_RUN2;
break;
case HERO_POSITION_JUMP_1:
case HERO_POSITION_JUMP_8:
upper = SPRITE_TERRAIN_EMPTY;
lower = SPRITE_JUMP;
break;
case HERO_POSITION_JUMP_2:
case HERO_POSITION_JUMP_7:
upper = SPRITE_JUMP_UPPER;
lower = SPRITE_JUMP_LOWER;
break;
case HERO_POSITION_JUMP_3:
case HERO_POSITION_JUMP_4:
case HERO_POSITION_JUMP_5:
case HERO_POSITION_JUMP_6:
upper = SPRITE_JUMP;
lower = SPRITE_TERRAIN_EMPTY;
break;
case HERO_POSITION_RUN_UPPER_1:
upper = SPRITE_RUN1;
lower = SPRITE_TERRAIN_EMPTY;
break;
case HERO_POSITION_RUN_UPPER_2:
upper = SPRITE_RUN2;
lower = SPRITE_TERRAIN_EMPTY;
break;
}
if (upper != ' ') {
terrainUpper[HERO_HORIZONTAL_POSITION] = upper;
collide = (upperSave == SPRITE_TERRAIN_EMPTY) ? false : true;
}
if (lower != ' ') {
terrainLower[HERO_HORIZONTAL_POSITION] = lower;
collide |= (lowerSave == SPRITE_TERRAIN_EMPTY) ? false : true;
}

byte digits = (score > 9999) ? 5 : (score > 999) ? 4 : (score > 99) ? 3 : (score
> 9) ? 2 : 1;

// Draw the scene


terrainUpper[TERRAIN_WIDTH] = '\0';
terrainLower[TERRAIN_WIDTH] = '\0';
char temp = terrainUpper[16-digits];
terrainUpper[16-digits] = '\0';
lcd.setCursor(0,0);
lcd.print(terrainUpper);
terrainUpper[16-digits] = temp;
lcd.setCursor(0,1);
lcd.print(terrainLower);

lcd.setCursor(16 - digits,0);
lcd.print(score);

terrainUpper[HERO_HORIZONTAL_POSITION] = upperSave;
terrainLower[HERO_HORIZONTAL_POSITION] = lowerSave;
return collide;
}

// Handle the button push as an interrupt


void buttonPush() {
buttonPushed = true;
}

void setup(){
pinMode(PIN_READWRITE, OUTPUT);
digitalWrite(PIN_READWRITE, LOW);
pinMode(PIN_CONTRAST, OUTPUT);
digitalWrite(PIN_CONTRAST, LOW);
pinMode(PIN_BUTTON, INPUT);
digitalWrite(PIN_BUTTON, HIGH);
pinMode(PIN_AUTOPLAY, OUTPUT);
digitalWrite(PIN_AUTOPLAY, HIGH);
pinMode(PIN_BUZZER,OUTPUT);//initialize the buzzer pin as an output
digitalWrite(PIN_BUZZER, LOW);

// Digital pin 2 maps to interrupt 0


attachInterrupt(0/*PIN_BUTTON*/, buttonPush, FALLING);

initializeGraphics();

lcd.begin(16, 2);
}

void loop(){
static byte heroPos = HERO_POSITION_RUN_LOWER_1;
static byte newTerrainType = TERRAIN_EMPTY;
static byte newTerrainDuration = 1;
static bool playing = false;
static bool blink = false;
static unsigned int distance = 0;

if (!playing) {
drawHero((blink) ? HERO_POSITION_OFF : heroPos, terrainUpper,
terrainLower, distance >> 3);
if (blink) {
lcd.setCursor(0,0);
lcd.print("Press Start");
}
delay(250);
blink = !blink;
if (buttonPushed) {

initializeGraphics();
heroPos = HERO_POSITION_RUN_LOWER_1;
playing = true;
buttonPushed = false;
distance = 0;
}
return;
}

// Shift the terrain to the left


advanceTerrain(terrainLower, newTerrainType ==
TERRAIN_LOWER_BLOCK ? SPRITE_TERRAIN_SOLID :
SPRITE_TERRAIN_EMPTY);
advanceTerrain(terrainUpper, newTerrainType ==
TERRAIN_UPPER_BLOCK ? SPRITE_TERRAIN_SOLID :
SPRITE_TERRAIN_EMPTY);

// Make new terrain to enter on the right


if (--newTerrainDuration == 0) {
if (newTerrainType == TERRAIN_EMPTY) {
newTerrainType = (random(3) == 0) ? TERRAIN_UPPER_BLOCK :
TERRAIN_LOWER_BLOCK;
newTerrainDuration = 2 + random(10);
} else {
newTerrainType = TERRAIN_EMPTY;
newTerrainDuration = 10 + random(10);
}
}

if (buttonPushed) {
if (heroPos <= HERO_POSITION_RUN_LOWER_2) heroPos =
HERO_POSITION_JUMP_1;
buttonPushed = false;
digitalWrite(PIN_BUZZER,HIGH);
}

if (drawHero(heroPos, terrainUpper, terrainLower, distance >> 3)) {


playing = false; // The hero collided with something. Too bad.
for (int i = 0; i <= 2; i++) {
digitalWrite(PIN_BUZZER, HIGH);
delay(100);
digitalWrite(PIN_BUZZER, LOW);
delay(100);
}
} else {
if (heroPos == HERO_POSITION_RUN_LOWER_2 || heroPos ==
HERO_POSITION_JUMP_8) {
heroPos = HERO_POSITION_RUN_LOWER_1;
} else if ((heroPos >= HERO_POSITION_JUMP_3 && heroPos <=
HERO_POSITION_JUMP_5) &&
terrainLower[HERO_HORIZONTAL_POSITION] !=
SPRITE_TERRAIN_EMPTY) {
heroPos = HERO_POSITION_RUN_UPPER_1;
} else if (heroPos >= HERO_POSITION_RUN_UPPER_1 &&
terrainLower[HERO_HORIZONTAL_POSITION] ==
SPRITE_TERRAIN_EMPTY) {
heroPos = HERO_POSITION_JUMP_5;
} else if (heroPos == HERO_POSITION_RUN_UPPER_2) {
heroPos = HERO_POSITION_RUN_UPPER_1;
} else {
++heroPos;
}
++distance;

digitalWrite(PIN_AUTOPLAY,
terrainLower[HERO_HORIZONTAL_POSITION + 2] ==
SPRITE_TERRAIN_EMPTY ? HIGH : LOW);
}
delay(100);
digitalWrite(PIN_BUZZER,LOW);
}

34) Arduino Turn Your RC Car to Bluetooth RV Car


COMPONENTS AND SUPPLIES

SparkFun Arduino Pro Mini 328


- 3.3V/8MHz
× 1

Texas Instruments Dual H- × 1


Bridge motor drivers L293D
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

Step 1: Getting the right chassis


Part List
ProMini
L293d module
hc-05
Rc car
Getting the right chassis
To choose chassis is a question about drive mechanism
there are many drive mechanism.
Lets talk about the two most popular mechanism.
Differential Drive What is Differential drive?
The term differential means difference between two
entities, in the context of robotics it is just the speed
difference between two motors.Based on this speed
difference, a robot can be moved in any direction on a
2D layout.
When two motors are connected to wheels in one
line,opposite to each other(Just like a pair of wheels
connected to a single shaft) the speed with which each
motor rotates determines the direction of motion.
When both the wheels rotate at the same speed the
difference between the motors is Zero. This makes the
robot move forward in a straight line.The robot can
move in reverse direction if the direction of rotation of
both the motors are reversed. This will again be in a
straight line if the speed difference is zero. Now
changing the speed of any one motor will result in
movement in a direction away from the straight line.
For example, reducing the speed of the right motor
will result in a speed difference and hence change in
direction.The resultant force is such that the robot
turns right. This direction change can be controlled to
required angle by further reducing the speed of the
motor.Slower is the right motor, sharper is the turn to
right. This is exactly the same for Left turn.
As a conclusion, Slower right motor, sharper right
turn. Slower left motor Sharper left turn. Below are
some scenarios which explains working of differential
drive mechanism. M1 and M2 are motors which drive
wheels on left and right respectively.
Steer Type Drive
What is Steer type drive ?
The car type drive is the most common in real world
but not in robot world. It is characterized by a pair of
driving wheels and a separate pair of steering wheels
The translation and rotation are independent of each
other. But translation and rotation are interlinked
hence this system faces severe path planning problem.
Four wheels are more efficient compared to three or
two wheels. The first two of the four wheels can be
used to steer and the next two to drive the robot.
Balancing a four wheeled robot is never an issue.
Most everyday cars we use are four wheeled and the
example is enough to prove its existence and
capabilities.
Disadvantages Of Car Type Drive : The turning
mechanism must be accurately controlled. A slight
inaccuracy may cause large odometry errors The
system is Non – Holonomic hence path planning is
extremely difficult as well as inaccurate There are no
direct directional actuators
So its better to use differential drive due to its
simplicity and easy to use.
Step 2: Controlling the motors
To control the motor we need something that
something called the motor driver.
What is a Motor Driver?
A motor driver is a little current amplifier; the
function of motor drivers is to take a low-current
control signal and then turn it into a higher-current
signal that can drive a motor.
There are many motor drivers out of which I am using
l293d motor driver module.
L293D is a Motor driver integrated circuit which is
used to drive DC motors rotating in either direction. It
is a 16-pin IC which can control a set of two DC
motors simultaneously. The L293D uses 5V for its
own power and external power source is needed to
drive the motors, which can be up to 36V and draw up
to 600mA. The L293D works on the concept of typical
H-bridge, a circuit which allows the high voltage to be
flown in either direction. In a single L293D IC there
are two H-bridge circuits which can rotate two DC
motors independently.
Pin description of L293d
1Enable pin for Motor 1; active high Enable 1,2 2
Input 1 for Motor 1 Input 1 3 Output 1 for Motor 1
Output 1 4 Ground (0V) Ground 5 Ground (0V)
Ground 6 Output 2 for Motor 1 Output 2 7 Input 2 for
Motor 1 Input 2 8 Supply voltage for Motors; 9-12V
(up to 36V) Vcc 2 9 Enable pin for Motor 2; active
high Enable 3,4 10 Input 1 for Motor 1 Input 3 11
Output 1 for Motor 1 Output 3 12 Ground (0V)
Ground 13 Ground (0V) Ground 14 Output 2 for
Motor 1 Output 4 15 Input2 for Motor 1 Input 4 16
Supply voltage; 5V (up to 36V) Vcc 1
Step 3: About the App
There are many apps to control I made with one .The
logic is very simple all the button sends a character
when pressed through Bluetooth and the arduino
processes it.
Character Functions
X Null state F Forward Motion B Backward Motion L
Turn Left R Turn Right
Step 4: Connection all the part
Connections are simple
here are the connection as follows
The Bluetooth Module
Hc-05 Arduino Vcc 5v Gnd Gnd Rx Tx Tx Rx
The Motor Driver
Motor Driver Arduino pin 2 8 pin 7 7 pin 10 6 pin 4 9
pin 3 and 6 Motor 1 pin 11 and pin 14 Motor 2 pin 1
5v pin 9 5v

SCHEMATICS
CODE
void setup() {
Serial.begin(9600);
pinMode(8, OUTPUT);
pinMode(7, OUTPUT);
pinMode(9, OUTPUT);
pinMode(6, OUTPUT);
pinMode(5, OUTPUT);
pinMode(4, OUTPUT);
digitalWrite(4,LOW);

digitalWrite(5,LOW);

// the loop function runs over and over again forever


void loop() {
var=Serial.read();
if(var=='F')
{
digitalWrite(6,LOW);
digitalWrite(7,HIGH);
digitalWrite(8,LOW);
digitalWrite(9,HIGH);

} if(var=='H')
{ digitalWrite(frled1,HIGH);
}
if(var=='B')
{
analogWrite(speeden,150);

digitalWrite(6,HIGH);
digitalWrite(7,LOW);
digitalWrite(8,HIGH);
digitalWrite(9,LOW);
digitalWrite(bcled1,HIGH);

}
if(var=='X')
{digitalWrite(9,LOW);
digitalWrite(8,LOW);
digitalWrite(7,LOW);
digitalWrite(6,LOW);
digitalWrite(frled1,LOW);
digitalWrite(bcled1,LOW

);

}
if(var=='L')
{digitalWrite(6,LOW);
digitalWrite(7,LOW);
digitalWrite(8,HIGH);
digitalWrite(9,LOW);
}
if(var=='R')
{digitalWrite(6,HIGH);
digitalWrite(7,LOW);
digitalWrite(8,LOW);
digitalWrite(9,LOW);;
}
}
35) Arduino Digital Dice
COMPONENTS AND SUPPLIES
Breadboard (generic)
× 1

Jumper wires (generic)


× 1
Adafruit Standard LCD - 16x2 × 1
White on Blue

USB-A to B Cable
× 1

Arduino UNO & Genuino UNO


× 1

Rotary potentiometer (generic)


× 1

SparkFun Pushbutton switch


12mm
× 1
ABOUT THIS PROJECT

This project was based on the idea that I had become


bored of my normal standard game dice. So, to fix my
boredom, I decided to use my Arduino LCD and
standard push button (with a breakout board) and I had
the Arduino read the state of the signal pin on the
button board to high or low (high if button not
depressed) (low if not). Depending on the state it
would either stay on the main screen or show that the
dice are rolling and then print out two random
numbers from 1-6 (like a dice).

SCHEMATICS
CODE

#include <LiquidCrystal.h>
long randNumber;
int Led = 13; //define LED port
int Shock = 2; //define shock port
int val;//define digital variable val
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 8, 9, 10, 11, 12 );
byte customChar[] = {
B00000,
B00000,
B11111,
B11001,
B10101,
B10011,
B11111,
B00000
};
void setup()
{

lcd.begin(16, 2);
lcd.createChar(0, customChar);
lcd.home();
pinMode(Led, OUTPUT); //define LED as a output port
randomSeed(analogRead(0));
pinMode(Shock, INPUT); //define shock sensor as a output port
lcd.write(byte( 0));
lcd.print("Digital dice");
lcd.write(byte( 0));
delay(1000);
}

void loop()
{

val = digitalRead(Shock); //read the value of the digital interface 3 assigned


to val
if (val == LOW) //when the shock sensor have signal do the following
{
lcd.clear();
lcd.print("Rolling dice...");
delay(4000);
lcd.clear();
lcd.setCursor(0, 0);
randNumber = random(1,7);
lcd.print("Dice 1 = ");
lcd.print(randNumber);

lcd.setCursor(0, 1);
randNumber = random(1,7);
lcd.print("Dice 2 = ");
lcd.print(randNumber);

delay(150);
}
36)Arduino I2S Theremin
COMPONENTS AND SUPPLIES
Arduino MKR Zero
× 1

Breadboard (generic)
× 1
Jumper wires (generic) × 1

Adafruit MAX98357A
× 1

Speaker: 3W, 4 ohms


× 1

RobotGeek Slider
× 2
APPS AND ONLINE SERVICES
Arduino IDE

Arduino Web Editor

ABOUT THIS PROJECT

Arduino I2S library


The new Arduino I2S library allows you to send and
receive digital audio data on the I2S bus. This
example aims to show how to use this library to drive
an I2S DAC to reproduce sound computed within the
Arduino sketch.
For more information about the library and how it
works read the library page.
I2S Connections
The I2S DAC used in this example needs only 3 wires
for the I2S bus (plus power supply). Connections for
the I2S on the Arduino MKRZero are the following:
SD (Serial Data) on pin A6;
SCK (Serial Clock) on pin 2;
FS (Frame or Word Select) on pin 3;
How it works
A theremin has basically two controls:
pitch
volume
In this example these two parameters are changed
moving two slide potentiometers, but you can modify
it to read them using for example a ping sensor! In this
way your theremin will be more realistic!
The two potentiometers are wired in a voltage divider
fashion, so moving them you will get
(from analogRead()) values in the range 0 - 1023.
These values are then mapped to between the
minimum and maximum frequency and the minimum
and maximum volume.
The sound sent on the I2S bus is a simple sine whose
frequency and amplitude is changed according to the
potentiometers reading.
SCHEMATICS
CODE

*
This code is based on Adafruit's work
https://github.com/adafruit/Adafruit_ZeroI2S/blob/master/examples/tone_ge
nerator/tone_generator.ino

Make an I2S Theremin using an Arduino MKRZero, an I2S DAC and two
slider potentiometers!
*/
#include <I2S.h>

const int maxFrequency = 5000; //maximum generated frequency


const int minFrequency = 220; //minimum generated frequency
const int maxVolume = 100; //max volume of the generated frequency
const int minVolume = 0; //min volume of the generated frequency

const int sampleRate = 44100; //samplerate of the generated frequency


const int wavSize = 256; //buffer size
short sine[wavSize]; //buffer in which the sine values are stored

const int frequencyPin = A0; //pin connected to the pot who determines the
frequency of the signal
const int amplitudePin = A1; //pin connected to the pot who determines the
amplitude of the signal

const int button = 6; //pin connected to the button to put the frequency as
output

void setup() {
Serial.begin(9600); //configue the serial ort
// Initialize the I2S transmitter.
if (!I2S.begin(I2S_PHILIPS_MODE, sampleRate, 16)) {
Serial.println("Failed to initialize I2S!");
while (1);
}
generateSine(); // fill buffer with sine values
pinMode(button, INPUT_PULLUP); //put the button pin in input pullup
}

void loop() {
if (digitalRead(button) == LOW) {
float frequency = map(analogRead(frequencyPin), 0, 1023, minFrequency,
maxFrequency); //map frequency
int amplitude = map(analogRead(amplitudePin), 0, 1023, minVolume,
maxVolume); //map amplitude
playWave(frequency, 0.1, amplitude); //play sound
//print values on serial
Serial.print("Frequency = ");
Serial.println(frequency);
Serial.print("Amplitude = ");
Serial.println(amplitude);
}
}

void generateSine() {
for (int i = 0; i < wavSize; ++i) {
sine[i] = ushort(float(100) * sin(2.0 * PI * (1.0 / wavSize) * i)); //100 is
used to not have small numbers
}
}

void playWave(float frequency, float seconds, int amplitude) {


// Play back the provided waveform buffer for the specified
// amount of seconds.
// First calculate how many samples need to play back to run
// for the desired amount of seconds.
unsigned int iterations = seconds * sampleRate;
// Then calculate the 'speed' at which we move through the wave
// buffer based on the frequency of the tone being played.
float delta = (frequency * wavSize) / float(sampleRate);
// Now loop through all the samples and play them, calculating the
// position within the wave buffer for each moment in time.
for (unsigned int i = 0; i < iterations; ++i) {
short pos = (unsigned int)(i * delta) % wavSize;
short sample = amplitude * sine[pos];
// Duplicate the sample so it's sent to both the left and right channel.
// It appears the order is right channel, left channel if you want to write
// stereo sound.
while (I2S.availableForWrite() < 2);

I2S.write(sample);
I2S.write(sample);
}
}
37) Voice Control Home Automation System Using
Arduino and HC-05

COMPONENTS AND SUPPLIES


Arduino UNO & Genuino
UNO
× 1
HC-05 Bluetooth Module × 1

Jumper wires (generic)


× 1

Two AC Bulbs(Red,Yellow)
× 1

Relay (generic)
× 1
Using 4 Channel Relay
APPS AND ONLINE SERVICES

Arduino IDE

Android IoTBoys (Android App)

ABOUT THIS PROJECT

We are showing voice control home automation


system to control appliances with own voice
command. To accomplish this project using an
Android app IoTBoys that is available on google play
store. Controlling two AC bulbs (Red, Yellow) using 4
channel relay board.
SCHEMATICS
CODE

String voice;
int RED = 2;
int YELLOW = 3;
void RedOn(){
digitalWrite (RED, LOW);
}
void RedOff(){
digitalWrite (RED, HIGH);
}
void YellowOn(){
digitalWrite (YELLOW, LOW);
}
void YellowOff(){
digitalWrite (YELLOW, HIGH);
}
void allon() {
digitalWrite (RED, LOW);
digitalWrite (YELLOW, LOW);
}
void alloff() {
digitalWrite (RED, HIGH);
digitalWrite (YELLOW, HIGH);
}
void setup() {
Serial.begin(9600);
pinMode(RED, OUTPUT);
pinMode(YELLOW, OUTPUT);
digitalWrite (RED, HIGH);
digitalWrite (YELLOW, HIGH);
}
void loop() {
while(Serial.available()) {
delay(10);
char c=Serial.read();
if(c=='#')
{
break;
}
voice += c;
}
if (voice.length() > 0) {
Serial.println(voice);
if (voice == "on" || voice== "all on")
{
allon() ;
}
else if (voice == "off" || voice=="all off")
{
alloff() ;
}
else if(voice =="red" || voice =="red on"){
RedOn();
}
else if(voice =="red off"){
RedOff();
}
else if(voice =="yellow" || voice =="yellow on"){
YellowOn();
}
else if(voice =="yellow off"){
YellowOff();
}
voice="";
}
}
38) Arduino A Geiger Counter Simulator
COMPONENTS AND SUPPLIES

Arduino UNO & Genuino UNO


× 1

Ultrasonic Sensor - HC-SR04 × 1


(Generic)
Relay Module (Generic)
This will be used just to make
some noise when the relay
× 1
switched from on to off and
viceversa. Then, you shouldn't
use a solid state relay.
APPS AND ONLINE SERVICES

Arduino IDE

Android IoTBoys (Android App)

ABOUT THIS PROJECT

Introduction and motivation


When teaching about radioactivity, one needs to
explain the main features of this phenomenon. Some
radioactive samples (i.e., alpha and beta emitters) emit
electrically charged particles that, when pass through a
Geiger counter, make it react with an internal spark
whose noise can be heard like a sort of "click". In
order to characterise the radioactive sample, one needs
to measure the number of particles emitted per unit
time (i.e. the frequency of the "clicks"). Such a
number, manifestly, increase while the distance
between the radioactive source and the Geiger counter
decreases, because the latter intercepts more and more
particles as the source gets closer to it.
Making experiments in a classroom is the best way to
let students fix the lesson in their minds. However,
making experiments with radioactive sources in a
classroom can be dangerous. Then, why not to
simulate them?
The basic idea
Of course one can use a "virtual" laboratory, but a real
piece of hardware is much more effective. Then, I
realised a Geiger counter simulator that works this
way: an ultrasonic sensor measure the distance of any
obstacle in the vicinity of the simulator; a relay is
triggered with a probability that depends on the
distance. The "click" is produced by the relay
switching from on to off and vice versa.
Of course, the simulator turns any obstacle in a
"radioactive source". However, a clever positioning of
the sensor relative to the obstacle make you control
wether the simulator should "click" or not.
Building the simulator
First of all, assemble the system according to the
schematic. Keep the wires long enough such that you
can then insert the whole system inside a cardboard
tube (I use those around which the kitchen paper is
rolled up). Before inserting the system inside make
two holes close to one end of the cylinder, such that
the speaker and the microphone of the ultrasonic
sensor can pass through them (see the picture).
Load the sketch into the Arduino memory. The loop()
starts obtaining the distance between the sensor and an
obstacle (if any). To do that you should trigger the
sensor with a positive pulse whose duration is at least
10 us (done by the trigger() function). Upon triggering
the sensor, it returns a positive pulse after a time T
proportional to the time needed to the ultrasonic
pulses to be reflected by the obstacle. In order to
suppress the effects of spurious reflections, we
average 15 measurements.
From the average d we derive the number t=1000/d^2.
Given that d ranges from about 2 cm to 400 cm, t
ranges from almost 0 to about 250. We can then draw
a (pesudo-)random number r uniformly distributed
between 0 and 1000 and check if r < t. That happens
with a probability of t/1000, ranging from almost 0 to
250/1000=25%. If that happens we switch the relay
from on to off or viceversa, based on the last status
stored in the appropriate variable.
As a result, the relay clicks with a probability that
depends on the distance of an obstacle from the
sensor. When no objects are in front of the sensor the
system is silent (it may click randomly from time to
time, but this behaviour is typical of a Geiger counter
because of natural radioactivity, cosmic rays or just
noise). Putting something pretending to be radioactive
in from of the sensor makes the Geiger simulator react
with a clicking frequency increasing when the source
gets closer.
Using the device
To effectively use the device while teaching, you can
approach any object to the system taking care not to
place it in front of the sensor. The Geiger does not
click and the object is then classified as non
radioactive.
You can then approach another object pretending it is
a radioactive source. If you put the object in front of
the sensor, the system starts clicking and the
frequency of the clicks increases while the distance
decreases (that's because a larger number of particles
emitted from the source can pass through the
detector).
It is also possible to turn a non radioactive material
into a radioactive one putting it in the vicinity of a
radioactive source (activation). So you can put the
(pretended) radioactive source close to the non
radioactive material for a while, then you move the
latter close to the sensor...et voilà...you activated it.
In fact my Geiger simulator was proven to be very
effective with my class and reactions were enthusiast.
Someone also thought that I really made experiments
with real radioactive materials.

SCHEMATICS
CODE

#define CLIK 8
#define ECHO 2
#define TRIG 3

#define c 340.e-6 // the speed of sound

void setup() {
pinMode(CLIK, OUTPUT);
pinMode(ECHO, INPUT);
pinMode(TRIG, OUTPUT);
digitalWrite(TRIG, LOW);
digitalWrite(CLIK, LOW);
}
void trigger() {
/* trigger the sensor */
digitalWrite(TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG, LOW);
}
float measure() {
/* measure the distance between the sensor and the obstacle */
float d = 0.;
for (int i = 0; i < 15; i++) {
trigger();
unsigned long T = pulseIn(ECHO, HIGH);
d += c*T/2.;
}
return d;
}
int status = HIGH; // the current status of the relay
void loop() {
float d = measure();
unsigned long trigger = 1000./(d*d);
unsigned long r = random(1000);
if (r < trigger) {
digitalWrite(CLIK, status);
if (status == HIGH) {
status = LOW;
} else {
status = HIGH;
}
}
}

39) Arduino Based Collision Detection Warning


System
COMPONENTS AND SUPPLIES
Arduino UNO & Genuino
UNO
× 1

ultrasonic sensor HR SC-04


× 1

LED (generic) × 2
Buzzer
× 1

Resistor 10k ohm


× 2

ABOUT THIS PROJECT

This is an Arduino-based collision detection warning


system. This kind of system is the fastest growing safety
feature in automotive industries. Such a system enables
vehicles to identify the chances of collision and give
visual and audio warning to driver, so that the driver can
take necessary action to avoid collision. This project
idea is based on an Arduino controller and the whole
project will give you very good understanding of how
this system works. The step-by-step method is explained
so that you can make this system. The hardware
connection, pin information and Arduino program is
explained clearly.
Step 1: Please gather the following
items
Computer: This is required to write program and
flash program to the controller. Also, you need to
install Arduino IDE which is available free on the
Arduino website download section.
Controller: I used Arduino micro-controller. This
you can get from an online seller like Amazon, etc.
Sensor: I used HR SC-04 ultrasonic sensor.
Piezo Buzzer: I used Piezo buzzer to make the
audio warning.
LED: There are two colors of LED I used - red and
blue.
Wires: Jumper wires are required to make
hardware connections. You need to use all types of
jumper wires like male-male, female-female and
female-male.
Step 2: Connect all hardware
The hardware you gather in first step, now connect all of
them to the controller through wires.
Sensor to controller pin information
The sensor has four pins: VCC, Trig, Echo, and GND.
Connect:
VCC pin to 5V on controller
GND pin to GND on controller
Trig pin to pin-7 on controller
Echo pin to pin-4 on controller
Piezo Buzzer to controller pin information
Piezo buzzer has two pins:
Connect one pin to pin-10 on controller
Connect another pin to GND on controller
Red LED to controller pin information
The red LED has two pins:
Connect one pin to pin-2 on controller
Connect another pin to GND on controller
Blue LED to controller pin information
The blue LED has two pins:
Connect one pin to pin-13 on controller
Connect another pin to GND on controller
Controller to Computer connection information
You have a USB data cable that you get with buying the
Arduino. With this data cable, you connect the computer
to the Arduino board. Now launch Arduino IDE. After
connecting the computer, you must select the board and
port from the menu. Please see the attached screen shot
for the help.
Step 3: Write the program
In the previous step, we defined pin information for the
hardware. Now, that info we'll use to write program
instructions. Launch Arduino IDE and try to write the
program by yourself. Otherwise you can directly use my
program or download the .ino format file attached.
While copying this code, you have to be careful because
some characters used in the program cannot be paste
while writing this on particular medium. Better to
download .ino format file.
////Collision Warning System////
//// Year 2017 ////
//// Vijendra Kumar////
const int trigPin = 7;
const int echoPin = 4;
int buzz = 10;
long duration;
int distance;
// the setup function runs once when you press reset or
power the board
void setup() {
// initialize digital pin 13 as an output.
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(13, OUTPUT);
pinMode(2, OUTPUT);
Serial.begin(9600);
}
// the loop function runs over and over again forever
void loop()
{
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time
in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculating the distance
distance= duration*0.034/2;
// Prints the distance on the Serial Monitor
if(distance <= 50 && distance >= 20)
{
digitalWrite(13, HIGH);
// digitalWrite(13, LOW);
// turn the LED on (HIGH is the voltage level)
}
else
{
digitalWrite(13, LOW); // turn the LED off by making
the voltage LOW
// wait for a second
}
if(distance <= 20)
{
digitalWrite(2, HIGH);
tone(buzz, 2000);
delay(100);
noTone(buzz);
delay(100);
tone(buzz, 2000);
delay(100);
noTone(buzz);
delay(100);
tone(buzz, 2000);
delay(100);
noTone(buzz);
tone(buzz, 2000);
delay(100);
noTone(buzz);
delay(100);
}
else
{
digitalWrite(2, LOW); // turn the LED off by making the
voltage LOW
// wait for a second
}
}

Step 4: Flash the Arduino board


After making all the connections, we are ready to upload
the program to the Arduino board. Please see the
attached image for reference.

Step 5: How this system works


Let me explain for you how this system works. I defined
three different zones:
Zone 1: No warning
Zone 2: Only visual warning (in this zone, driver
has to pay attention)
Zone 3: Both visual and audio warning (driver has
to take necessary action to avoid collision)
SCHEMATICS

Please use this pin information. You can change pin


number as per yours but in that case you have to
change code also.
Arduino based collision detection warning system
Please follow this schematic to connect hardware to
board and pin numbers.
CODE

const int trigPin = 7;


const int echoPin = 4;
int buzz = 10;
long duration;
int distance;

// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin 13 as an output.
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(13, OUTPUT);
pinMode(2, OUTPUT);
Serial.begin(9600);
}

// the loop function runs over and over again forever


void loop()
{
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculating the distance
distance= duration*0.034/2;
// Prints the distance on the Serial Monitor
if(distance <= 50 && distance >= 20)
{
digitalWrite(13, HIGH);
// digitalWrite(13, LOW);
// turn the LED on (HIGH is the voltage level)

else
{
digitalWrite(13, LOW); // turn the LED off by making the voltage LOW
// wait for a second
}

if(distance <= 20)


{
digitalWrite(2, HIGH);

tone(buzz, 2000);
delay(100);
noTone(buzz);
delay(100);

tone(buzz, 2000);
delay(100);
noTone(buzz);
delay(100);

tone(buzz, 2000);
delay(100);
noTone(buzz);

tone(buzz, 2000);
delay(100);
noTone(buzz);
delay(100);
}

else
{
digitalWrite(2, LOW); // turn the LED off by making the voltage LOW
// wait for a second
}
}

40) Arduino GPS Data Logger Real Time Curve Max


Height and Max Speed
COMPONENTS AND SUPPLIES

Arduino UNO & Genuino UNO


arduino uno × 1

Jumper (Busbar), Jumper Leads × 1


Set
Arduino Proto Shield
× 1

1.8" TFT SPI LCD Screen with


MicroSD Socket × 1
or another with SD card
u-blox gps neo 6m
× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)

Solder Wire, Lead Free

Wire Stripper & Cutter, 18-10 AWG /


0.75-4mm² Capacity Wires

ABOUT THIS PROJECT

I practice aeromodelling and I like to know the speed


and altitude of my planes. unfortunately, commercial
GPS data loggers are very expensive.
So I decided to make a GPS data logger based on
Arduino for a cost less than 50€.
My first prototype is based on Arduino Uno R3 with a
Sainsmart ST7735 screen with integrated SD card and
a NEO 6M V2 GPS module.
In the second project I would use an Arduino Nano
with an SSD1306 OLED screen, the same GPS
module, and a micro SD card. The weight with case
should be around 40 grams and can easily be
integrated into a medium-sized aircraft (size L 50 mm
X l 30mm X H 22mm).

SCHEMATICS
CODE

gps data logger Arduino


#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#define cs 10
#define dc 9
#define rst 8
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, rst);
static const int RXPin = 4, TXPin = 3; //GPS communication
static const uint32_t GPSBaud = 9600;

#define OLED_RESET 5

TinyGPSPlus gps;
SoftwareSerial ss(RXPin, TXPin);

int x=80;
int xh=80;
int maxhigh=0;
int maxspeed = 0, speed1 = 0;
int high1 = 0;;

void setup()
{

Serial.begin(9600);
ss.begin(GPSBaud);
tft.initR(INITR_GREENTAB);
tft.fillScreen(ST7735_BLACK);
tft.setCursor(5, 58);
tft.setTextSize(1);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.print("initilisation");

void loop()
{

tft.setTextSize(1);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);

// affichage des informations a chaque bonne reception satellite


while (ss.available() > 0){
gps.encode(ss.read());
if (gps.location.isUpdated()){

cadre();

tft.setCursor(5, 44);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.print("Latitude :");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(gps.location.lat(), 6);
tft.setCursor(5, 58);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.print("Longitude :");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(gps.location.lng(), 6);
//affichage ecran date
tft.setCursor(5, 7);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.print("date : ");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(gps.date.day());
tft.print(" ");
tft.print(gps.date.month());
tft.print(" ");
tft.print(gps.date.year());

//affichage ecran heure


tft.setCursor(5, 20);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.print("heure : ");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(gps.time.hour()+1);
tft.print(" ");
tft.print(gps.time.minute());
tft.print(" ");
tft.print(gps.time.second());
tft.print(" ");
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.setCursor(3, 30);
//affichage ecran altitude
tft.setCursor(5, 80);
tft.print("H m :");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print (gps.altitude.meters(),0);
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(" ");
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.setCursor(5, 95);
hmax();
tft.print("Hmax :");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(maxhigh);
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(" ");
courbeh();

//affichage ecran vitesse


tft.setCursor(5, 115);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.print("V act: ");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print (gps.speed.kmph(),0);
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(" ");
tft.setCursor(5, 130);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
vmax();
tft.print("vmax: ");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(maxspeed);
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(" ");
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
courbe();
//affichage ecran nombre de satellites
tft.setCursor(5, 147);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.print("nombre de Sat : ");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(gps.satellites.value());
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(" ");

// Horizontal Dim. of Precision (100ths-i32)


Serial.print("HDOP = ");
Serial.println(gps.hdop.value());

smartDelay(400);

}
}
}
// delai pour une bonne recption
static void smartDelay(unsigned long ms)
{
unsigned long start = millis();
do
{
while (ss.available())
gps.encode(ss.read());
} while (millis() - start < ms);
}
void cadre() {
// affichage ecran
//cadre
tft.drawLine(0,0,130,0,ST7735_RED);
tft.drawLine(0,1,130,1,ST7735_RED);
tft.drawLine(0,158,130,158,ST7735_RED);
tft.drawLine(0,142,130,142,ST7735_RED);
tft.drawLine(0,141,130,141,ST7735_RED);
tft.drawLine(0,107,130,107,ST7735_RED);
tft.drawLine(0,108,130,108,ST7735_RED);

tft.drawLine(80,108,80,140,ST7735_RED);
tft.drawLine(81,109,81,140,ST7735_RED);

tft.drawLine(80,70,80,108,ST7735_RED);
tft.drawLine(81,70,81,108,ST7735_RED);

tft.drawLine(0,159,130,159,ST7735_RED);
tft.drawLine(0,0,0,156,ST7735_RED);
tft.drawLine(1,1,1,157,ST7735_RED);
tft.drawLine(127,0,127,156,ST7735_RED);
tft.drawLine(126,0,126,156,ST7735_RED);
tft.drawLine(0,35,130,35,ST7735_RED);
tft.drawLine(0,36,130,36,ST7735_RED);
tft.drawLine(0,70,130,70,ST7735_RED);
tft.drawLine(0,71,130,71,ST7735_RED);

void courbe() {

int nouvelleValeur;

// converison vitesse max (350 km/h) en pixel


nouvelleValeur = map((gps.speed.kmph()), 0, 150, 137, 110); // car l'cran a
64 pixels de haut

x++;
tft.drawPixel(x,nouvelleValeur,ST7735_CYAN);
if (x>123) {
x=80;
tft.fillRect(82,110,43,30,ST7735_BLACK);

}
}
void courbeh() {

int nouvelleValeurh;

// converison vitesse max (350 km/h) en pixel


nouvelleValeurh = map((gps.altitude.meters()), 0, 1000, 104, 72); // car
l'cran a 64 pixels de haut

xh++;

tft.drawPixel(xh,nouvelleValeurh,ST7735_CYAN);
if (xh>123) {
xh=80;
tft.fillRect(82,72,43,35,ST7735_BLACK);

}
}
void vmax() {
// calcul vitese maximum
speed1 = (gps.speed.kmph());
if ( speed1 > maxspeed) {
maxspeed = speed1;
}
}
void hmax() {
// calcul altitude maximum
high1 = (gps.altitude.meters());
if ( high1 > maxhigh) {
maxhigh = high1;
}
}

sauvegarde SD
#include <SPI.h>
#include<SD.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#define cs 10
#define dc 9
#define rst 8
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, rst);
static const int RXPin = 4, TXPin = 3; //GPS communication
static const uint32_t GPSBaud = 9600;
const int cs_sd=4;
#define OLED_RESET 5

TinyGPSPlus gps;
SoftwareSerial ss(RXPin, TXPin);

int x=80;
int xh=80;
int maxhigh=0;
int maxspeed = 0, speed1 = 0;
int high1 = 0;;

void setup()
{

Serial.begin(9600);
ss.begin(GPSBaud);
tft.initR(INITR_GREENTAB);
tft.fillScreen(ST7735_BLACK);
tft.setCursor(5, 58);
tft.setTextSize(1);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.print("initilisation");
tft.setCursor(5, 70);
tft.print("init SD");
delay(1000);
if(!SD.begin(cs_sd)) //Condition vrifiant si la carte SD est prsente dans
l'appareil
{
tft.setCursor(5, 82);
tft.print("Defaut SD");
return;
}
tft.setCursor(5, 82);
tft.print("Carte SD OK");

delay(1000);
tft.fillScreen(ST7735_BLACK);

File data = SD.open("donnees.txt",FILE_WRITE); // Ouvre le


fichier "donnees.txt"
data.println(""); data.println("Dmarrage acquisition"); // Ecrit dans ce
fichier
data.close();

void loop()
{

tft.setTextSize(1);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);

// affichage des informations a chaque bonne reception satellite


while (ss.available() > 0){
gps.encode(ss.read());
if (gps.location.isUpdated()){

cadre();

tft.setCursor(5, 44);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.print("Latitude :");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(gps.location.lat(), 6);
tft.setCursor(5, 58);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.print("Longitude :");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(gps.location.lng(), 6);

//affichage ecran date


tft.setCursor(5, 7);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.print("date : ");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(gps.date.day());
tft.print(" ");
tft.print(gps.date.month());
tft.print(" ");
tft.print(gps.date.year());

String Date=String(gps.date.day())+(" ")+(gps.date.month())+(" ")+


(gps.date.year());
//affichage ecran heure
tft.setCursor(5, 20);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.print("heure : ");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(gps.time.hour()+1);
tft.print(" ");
tft.print(gps.time.minute());
tft.print(" ");
tft.print(gps.time.second());
tft.print(" ");
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.setCursor(3, 30);

String Temps=String(gps.time.hour()+1)+(" ")+(gps.time.minute())+(" ")+


(gps.time.second());

//affichage ecran altitude


tft.setCursor(5, 80);
tft.print("H m :");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print (gps.altitude.meters(),0);
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(" ");
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.setCursor(5, 95);
hmax();
tft.print("Hmax :");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(maxhigh);
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(" ");
courbeh();
//affichage ecran vitesse
tft.setCursor(5, 115);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.print("V act: ");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print (gps.speed.kmph(),0);
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(" ");
tft.setCursor(5, 130);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
vmax();
tft.print("vmax: ");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(maxspeed);
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(" ");
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
courbe();

//affichage ecran nombre de satellites


tft.setCursor(5, 147);
tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
tft.print("nombre de Sat : ");
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(gps.satellites.value());
tft.setTextColor(ST7735_CYAN,ST7735_BLACK);
tft.print(" ");

// Horizontal Dim. of Precision (100ths-i32)


Serial.print("HDOP = ");
Serial.println(gps.hdop.value());
smartDelay(400);

// Ecriture des donnes dans le fichier texte


File data=SD.open("donnees.txt",FILE_WRITE);
data.println(Date + " " + Temps + " " + String(gps.location.lat(), 6)+"
"+String(gps.location.lng(), 6)+(" ")+String(gps.altitude.meters(),0)+("
")+String(maxhigh)+(" ")+String(gps.speed.kmph(),0)+("
")+String(maxspeed));
data.close();

}
}
}
// delai pour une bonne recption
static void smartDelay(unsigned long ms)
{
unsigned long start = millis();
do
{
while (ss.available())
gps.encode(ss.read());
} while (millis() - start < ms);
}
void cadre() {
// affichage ecran
//cadre
tft.drawLine(0,0,130,0,ST7735_RED);
tft.drawLine(0,1,130,1,ST7735_RED);
tft.drawLine(0,158,130,158,ST7735_RED);
tft.drawLine(0,142,130,142,ST7735_RED);
tft.drawLine(0,141,130,141,ST7735_RED);
tft.drawLine(0,107,130,107,ST7735_RED);
tft.drawLine(0,108,130,108,ST7735_RED);

tft.drawLine(80,108,80,140,ST7735_RED);
tft.drawLine(81,109,81,140,ST7735_RED);
tft.drawLine(80,70,80,108,ST7735_RED);
tft.drawLine(81,70,81,108,ST7735_RED);

tft.drawLine(0,159,130,159,ST7735_RED);
tft.drawLine(0,0,0,156,ST7735_RED);
tft.drawLine(1,1,1,157,ST7735_RED);
tft.drawLine(127,0,127,156,ST7735_RED);
tft.drawLine(126,0,126,156,ST7735_RED);
tft.drawLine(0,35,130,35,ST7735_RED);
tft.drawLine(0,36,130,36,ST7735_RED);
tft.drawLine(0,70,130,70,ST7735_RED);
tft.drawLine(0,71,130,71,ST7735_RED);

void courbe() {

int nouvelleValeur;

// converison vitesse max (350 km/h) en pixel


nouvelleValeur = map((gps.speed.kmph()), 0, 150, 137, 110); // car l'cran a
64 pixels de haut

x++;

tft.drawPixel(x,nouvelleValeur,ST7735_CYAN);
if (x>123) {
x=80;
tft.fillRect(82,110,43,30,ST7735_BLACK);

}
}
void courbeh() {

int nouvelleValeurh;
// converison vitesse max (350 km/h) en pixel
nouvelleValeurh = map((gps.altitude.meters()), 0, 1000, 104, 72); // car
l'cran a 64 pixels de haut

xh++;

tft.drawPixel(xh,nouvelleValeurh,ST7735_CYAN);
if (xh>123) {
xh=80;
tft.fillRect(82,72,43,35,ST7735_BLACK);

}
}
void vmax() {
// calcul vitese maximum
speed1 = (gps.speed.kmph());
if ( speed1 > maxspeed) {
maxspeed = speed1;
}
}
void hmax() {
// calcul altitude maximum
high1 = (gps.altitude.meters());
if ( high1 > maxhigh) {
maxhigh = high1;
}
}
41) Arduino Doorbell
COMPONENTS AND SUPPLIES
Arduino MKR1000
× 2
NECESSARY TOOLS AND MACHINES
3D Printer (generic)
APPS AND ONLINE SERVICES
Arduino IoT Cloud

Arduino Web Editor

ABOUT THIS PROJECT

The Doorbell is a great example of how to connect your


devices to Arduino Cloud and make them talk to each
other.
The Doorbell allows you to open the door from
everywhere as long as a WiFi network is available.
The project is composed of two part: the transmitter and
the receiver. The transmitter is the one that actually
opens the door and it is connected to it. The receiver is
the device that rings and that you can use to open the
door from everywhere.
Understanding Arduino Cloud
Arduino Cloud is a simple tool to connect your
Arduino/Genuino boards to the internet and to each other
through an mqtt communication.
Mqtt is a machine-to-machine connectivity protocol that
allows publishers and subscribers to exchange messages.
The connection between two different devices happens
when one device subscribes to the topic in which the
other one is publishing information.
Getting Started with Arduino Cloud
If this is the first time you are using Arduino Cloud we
highly encourage to follow the getting started guide.
Following a few simple configurations steps you will be
given a basic Arduino sketch to start your project.
In the example's code is important to understand how to
publish and how to receive messages.
In order to publish a message we will use:
client.publish("/username/device1/topic", "text");
While the username and the device name were defined
before, the topic can be named as we like, it is where our
messages will be published.
The text field is the message we want to publish in a
string format.
In order to receive a message we first have to subscribe
to a topic, where some other device is publishing:
client.subscribe("/username2/device2/ChannelName2");
Those fields have to be filled with the credential of the
transmitter device.
Now we receive messages and read them using this
code:

void messageReceived(String topic, String payload, char


* bytes, unsigned int length) {
Serial.println(payload)
}
The Receiver
Now we can start building up our project.
We want the receiver to play a song when the right
message is received and to send the "open" message
when the button is pressed.
To do so we need to connect to our board a button, a
speaker and an sd breakout board.

In order to make it play we need the AudioZero library.


For better quality the Audio file to store on the SD card
must be in the .wav format with 88200 Hz, 8-bit
unsigned PCM mono quality. This type of file can be
easily obtained using audio programs like audacity.
The Transmitter
Please note that for this example we presume our door is
already connected to a relay that can lock and unlock the
door by switching on and off.
What remains to do is simply to connect our board to
this relay and to the front door button.
SCHEMATICS

Receiver

Transmitter
CODE

Doorbell Receiver

#include <SPI.h>
#include <WiFi101.h>
#include <WiFiSSLClient.h>
#include <MQTT.h>
#include <SD.h>
#include <AudioZero.h>

///////please enter your sensitive data in the Secret tab/arduino_secrets.h


/////// Wifi Settings ///////
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

// Arduino Cloud settings and credentials


const char userName[] = SECRET_USER_NAME;
const char deviceName[] = SECRET_DEVICE_NAME;
const char deviceId[] = SECRET_DEVICE_ID;
const char devicePsw[] = SECRET_DEVICE_PSW;

int status = WL_IDLE_STATUS;


volatile bool buttonPressed = false;

MQTTClient client;
WiFiSSLClient net;

void setup() {
Serial.begin(9600);
WiFi.begin(ssid, pass);
client.begin("mqtt-dev.arduino.cc", 8883, net);
connect();
client.subscribe("/tommasltrz/DoorbellTransmitter/bell");
// setup SD-card
Serial.print("Initializing SD card...");
if (!SD.begin(6)) {
Serial.println(" failed!");
while (true);
}
Serial.println(" done.");

pinMode(4, INPUT);
attachInterrupt(4, buttonPressedCallback, RISING);
}

void connect() {
Serial.print("checking wifi...");
while ( status != WL_CONNECTED) {
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network:
status = WiFi.begin(ssid, p);
delay(4000);
}

Serial.println("connecting...");
while (!client.connect(deviceName, deviceId, devicePsw)) {
Serial.print(".");
}
Serial.println("connected!");
}

void loop() {
client.loop();

if (buttonPressed) {
client.publish("/tommasltrz/DoorbellReciever/bell", "open");
Serial.println("publishing up");
buttonPressed = false;
delay(1000);
}
}

void messageReceived(String topic, String payload, char * bytes, unsigned


int length) {
if (payload.equals("ring")) {
AudioZero.begin(2 * 44100); // 44100kHz stereo => 88200 sample rate
File myFile = SD.open("test.wav"); // open wave file from sdcard
if (!myFile) {
Serial.println("error opening test.wav");
while (true);
}
Serial.print("Playing");
AudioZero.play(myFile);
Serial.println("End");
AudioZero.end();
}
}

void buttonPressedCallback() {
buttonPressed = true;
}

Doorbel Transmitter

#include <SPI.h>
#include <WiFi101.h>
#include <WiFiSSLClient.h>
#include <MQTTClient.h>

///////please enter your sensitive data in the Secret tab/arduino_secrets.h


/////// Wifi Settings ///////
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

// Arduino Cloud settings and credentials


const char userName[] = SECRET_USER_NAME;
const char deviceName[] = SECRET_DEVICE_NAME;
const char deviceId[] = SECRET_DEVICE_ID;
const char devicePsw[] = SECRET_DEVICE_PSW;

int status = WL_IDLE_STATUS;


volatile bool buttonPressed = false;

MQTTClient client;
WiFiSSLClient net;

void setup() {
Serial.begin(9600);
WiFi.begin(ssid, password);
client.begin("mqtt-dev.arduino.cc", 8883, net);
connect();
client.subscribe("/tommasltrz/DoorbellReciever/bell");

pinMode(4, INPUT);
pinMode (6, OUTPUT);
attachInterrupt(4, buttonPressedCallback, RISING);
digitalWrite(6, LOW);

}
void connect() {
Serial.print("checking wifi...");
while ( status != WL_CONNECTED) {
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
status = WiFi.begin(ssid, password);
delay(4000);
}

Serial.println("connecting...");
while (!client.connect(deviceName, deviceId, devicePsw)) {
Serial.print(".");
}
Serial.println("connected!");
}
void loop() {
client.loop();

if (buttonPressed) {
client.publish("/tommasltrz/DoorbellTransmitter/bell", "ring");
Serial.println("publishing up");
buttonPressed = false;
delay(1000);
}

}
void messageReceived(String topic, String payload, char * bytes, unsigned
int length) {
if (payload.equals("open")) {
digitalWrite(6, HIGH);
delay(1000);
digitalWrite(6, LOW);
buttonPressed = false;
}
}
void buttonPressedCallback() {
buttonPressed = true;
}

42) PinBall Table on Arduino


COMPONENTS AND SUPPLIES
Arduino UNO & Genuino UNO
× 1

RobotGeek 180 Degree Robot


Servo
× 1

LED (generic)
× 1

Breadboard (generic)
× 1

ABOUT THIS PROJECT

Step 1
The first thing I made was the wooden housing. Then I
decorate the body.
I glued the body of the game table.
Step 2
After that, it was necessary to strengthen the housing
wall qualitatively. I used glue, nails and screws.
This action can be done either now or later, but I did it at
first. I glued down the right side. I measured the height -
it was 13 cm, and the lowest part body - 11 cm. The
higher the slope, the more difficult you will run the iron
(or another material ball). The body length received 50
cm.
Invisible player hardware component.
Designing and painting most of the board.
Step 3
Production of some of the details on the 3D printer.
Opening holes on the upper platform. I have made but
not yet connected the first actuator.
The Circuit
Wiring
The sensors
SCHEMATICS
CODE

main game

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C myDisplay(0x27,16,2);

#define greenLED 2
#define yellowLED 3
#define redLED 4
#define sensor1 8
#define sensor2 9
#define sensor3 10
#define sensor4 11
#define sensor5 12
#define sensor6 13

void setup()
{
myDisplay.init();
myDisplay.backlight();
myDisplay.print("PLAY!");
delay(2000);
myDisplay.setCursor(0,0);
myDisplay.print(" ");
myDisplay.setCursor(6,0);
myDisplay.print("GO GO GO");
delay(2000);
myDisplay.setCursor(0,0);
myDisplay.print(" ");

Serial.begin(9600);
pinMode(sensor1, INPUT);
pinMode(sensor2, INPUT);
pinMode(sensor3, INPUT);
pinMode(sensor4, INPUT);
pinMode(sensor5, INPUT);
pinMode(sensor6, INPUT);
pinMode(greenLED, OUTPUT);
pinMode(yellowLED, OUTPUT);
pinMode(redLED, OUTPUT);

digitalWrite(greenLED, LOW);
digitalWrite(yellowLED, LOW);
digitalWrite(redLED, LOW);

int i=0;
void loop() {
if (digitalRead(sensor1)==HIGH){
i=i+20;
myDisplay.clear();
myDisplay.setCursor(5,0);
myDisplay.print("+20!");
digitalWrite(greenLED, HIGH);
delay(2000);
digitalWrite(greenLED, LOW);
myDisplay.clear();
}

if (digitalRead(sensor2)==HIGH){
i=i+50;
myDisplay.clear();
myDisplay.setCursor(5,0);
myDisplay.print("+50!");
digitalWrite(greenLED, HIGH);
digitalWrite(yellowLED, HIGH);
delay(2000);
digitalWrite(greenLED, LOW);
digitalWrite(yellowLED, LOW);
myDisplay.clear();
}

if (digitalRead(sensor3)==HIGH){
i=i+100;
myDisplay.clear();
myDisplay.setCursor(5,0);
myDisplay.print("+100!");
digitalWrite(greenLED, HIGH);
digitalWrite(yellowLED, HIGH);
digitalWrite(redLED, HIGH);
delay(2000);
digitalWrite(greenLED, LOW);
digitalWrite(yellowLED, LOW);
digitalWrite(redLED, LOW);
myDisplay.clear();
}

if (digitalRead(sensor4)==HIGH){
i=i+20;
myDisplay.clear();
myDisplay.setCursor(5,0);
myDisplay.print("+20!");
digitalWrite(greenLED, HIGH);
delay(2000);
digitalWrite(greenLED, LOW);
myDisplay.clear();
}

if (digitalRead(sensor5)==HIGH){
i=i+50;
myDisplay.clear();
myDisplay.setCursor(5,0);
myDisplay.print("+50!");
digitalWrite(greenLED, HIGH);
digitalWrite(yellowLED, HIGH);
delay(2000);
digitalWrite(greenLED, LOW);
digitalWrite(yellowLED, LOW);
myDisplay.clear();
}

if (digitalRead(sensor6)==HIGH){
i=i+100;
myDisplay.clear();
myDisplay.setCursor(5,0);
myDisplay.print("+100!");
digitalWrite(greenLED, HIGH);
digitalWrite(yellowLED, HIGH);
digitalWrite(redLED, HIGH);
delay(2000);
digitalWrite(greenLED, LOW);
digitalWrite(yellowLED, LOW);
digitalWrite(redLED, LOW);
myDisplay.clear();
}

if (i>=500){
myDisplay.clear();
myDisplay.setCursor(4,0);
myDisplay.print("YOU WIN!");
for (int j=0; j<=15; j=j+1){
digitalWrite(greenLED, HIGH);
digitalWrite(yellowLED, HIGH);
digitalWrite(redLED, HIGH);
delay(100);
digitalWrite(greenLED, LOW);
digitalWrite(yellowLED, LOW);
digitalWrite(redLED, LOW);
delay(100);
}
i=0;
myDisplay.clear();
myDisplay.setCursor(0,0);
myDisplay.print("New Game");
delay(2000);
myDisplay.setCursor(0,0);
myDisplay.print(" ");
myDisplay.setCursor(6,0);
myDisplay.print("GO!");
delay(2000);
myDisplay.setCursor(0,0);
myDisplay.print(" ");
}

myDisplay.setCursor(0,0);
myDisplay.print("Your Score:");
myDisplay.setCursor(0,1);
myDisplay.print(i,DEC);
}
for servo

#include <Servo.h>

#define servopin 5
Servo myservo;

void setup()
{
myservo.attach(servopin);
myservo.write(90);

void loop() {
myservo.write(160);
delay(1000);
myservo.write(30);
delay(1000);
}
43) Arduino RFID Dropbox Logger
COMPONENTS AND SUPPLIES

Arduino Yun
× 1

Jumper wires (generic) × 1


Breadboard (generic)
× 1

RFID Reader Module


× 1
APPS AND ONLINE SERVICES
Arduino Web Editor

Adafruit IO

IFTTT Maker service

ABOUT THIS PROJECT

Have you ever wanted a system that keeps track of the


time at which your employees arrive to work, have you
ever wanted to check the time at which a person enters
your room (I have), this device aims to make all of that
as simple as possible. RFIDDropboxLogger will keep
track of everyone scanning an RFID card using an RFID
module and will write to Dropbox whenever it happens
to keep you updated with all the information. Thanks to
IFTTT, this is all possible and easy to do.

A
Single Component
RFID Module
Result
Functionality
This project will require IFTTT to work, to connect to
IFTTT we will have to use another cloud-based platform
called Adafruit IO. This platform will allow us to easily
connect our Arduino Yún to the Cloud and then to
IFTTT. Here is an image illustrating the process.
The Arduino Yún will monitor the RFID module
searching for a card, when one is detected, the micro
controller will increment the value to send by 1 and then
parse the value to Adafruit IO. Using an IFTTT trigger,
whenever a change in value is detected on Adafruit IO,
(in our case, the variable incrementation) the app will
trigger a Dropbox trigger which will append the time at
which an RFID card had been scanned to a text file.
Note that this operation will last approximately 15
minutes. Here is an image illustrating the code.
Code Overview
If(RFID Card Present) will check if an RFID card is
present.
Increase value will increment the value to send by 1.
Send value will send the incremented value to Adafruit
IO.
An Adafruit IO and IFTTT accounts are required to
create the project, a guide to creating these is in
Constructing the Project below.
Benefits
The user operating this project will benefit in:
Monitoring RFID usage
Monitoring time of RFID usage
Monitoring amount of times the RFID module has
been used
Constructing the Project
Step 1: Required Apparatus
The project requires very few things.
Jumper Wires (Male to Male & Male to Female)
1 Arduino Yún
1 RFID Module (RC522)
1 Breadboard

All the Components


Step 2: Connecting the Circuit
A simple circuit, just connect the RFID module to the
Arduino Yún. Here is an image displaying the project's
schematics.

The Schematics
Step 3: Acknowledging the Code
There are three main parts to the code:
connect to MQTT
search for RFID
send value
Each part will be explained below.
Connect to MQTT
void MQTTConnect()
{
int8_t ret;
if(mqtt.connected()) // if already connected
{
return;
}
if(proDebug == 1)
{
Serial.println("Connecting to Server");
}
while((ret = mqtt.connect()) != 0) // attempt to connect
{
if(proDebug == 1)
{
Serial.print(" Error - ");
Serial.println(mqtt.connectErrorString(ret));
Serial.println(" Attempting Reconnection in 5
seconds");
}
mqtt.disconnect();
delay(5000);
}
if(proDebug == 1)
{
Serial.println(" Success - Connection Established");
Serial.println("Scan Card");
Serial.println("");
}
}
This part of the code will connect the Arduino to MQTT
services on Adafruit IO, this will allow the Arduino Yún
to write to a Feed on Adafruit IO.
Search for RFID
if(!mfrc522.PICC_IsNewCardPresent())
{
return;
}
if(!mfrc522.PICC_ReadCardSerial())
{
return;
}
String content = ""; // string to store card id
// store card id
for(byte i = 0; i < mfrc522.uid.size; i++)
{
// store the card id number in a variable
content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? "
0" : " "));
content.concat(String(mfrc522.uid.uidByte[i], HEX));
}
This part will search for a new RFID card and continue
with the code once one is found, the card's ID is also
collected and stored to a variable though not essential.
Send Value
valueToSend++; // increase value to trigger write
if(proDebug == 1)
{
Serial.print("Publishing ");
Serial.println(valueToSend);
}
Console.println(valueToSend);
if(!sendToDropbox.publish(valueToSend))
{
if(proDebug == 1)
{
Serial.println(F(" Error - Failed to Send Data"));
}
}
else
{
if(proDebug == 1)
{
Serial.println(F(" Success - Data Sent"));
}
}
This part will increase the send value variable by 1 so
that IFTTT can detect a change. Then the value will be
sent to Adafruit IO, after the variable is parsed, the
Arduino will verify that it has been sent.
This loop will repeat continuously allowing cards to be
constantly scanned, it may take about 15 minutes for
IFTTT to check if the value on the Adafruit IO feed has
changed.
Setting up the Variables
Ensure that all variables marked TODO are edited to
preference. Insert your Adafruit IO credentials in the
appropriate sections (configuration illustrated below)
and set proDebug to 1 or 0. Note that mode 1 will enable
debugging and will require connection to a Mac/PC and
the Serial Monitor open to work. Default set to 1.
Libraries
Bridge & Bridge Client - copyright (c) Arduino
LLC under the GNU Lesser General Public
Licence, this library is in the public domain.
Console - copyright (c) 2013 Arduino LLC under
the GNU Lesser General Public Licence, this
library is in the public domain.
SPI - copyright (c) 2015 Hristo Gochkov under the
GNU Lesser General Public Licence, this library is
in the public domain.
MFRC522 - this library is in the public domain.
Adafruit MQTT & Adafruit MQTT Client -
copyright (c) 2015 Adafruit Industries under
the MIT Licence.
Adafruit IO Setup
Step 1: Download libraries
The first thing to do is to open the Arduino Library
manager and search for Adafruit_MQTT_Library, and
then download it.
Step 2: Create an Adafruit IO account
Follow the images below illustrating this process.
Step 3: Configure Adafruit IO
Follow these images to configure feeds for the Adafruit
IO communication with IFTTT.
Click on the feeds button in the menu on the left side of
the page

Click on Actions in the fallowing window


Click on Create a New Feed form the dropdown menu

Call this feed "sendToDropbox"

Repeat the steps to create another feed called


"subscribeA" and you are done
IFTTT Setup
Nearly there, now we have to configure IFTTT to finish
the project off. Use the following steps to configure
IFTTT; if you already have an IFTTT account, you may
skip the first step.
Step 1: Create an IFTTT Account
You can download the IFTTT app
for Apple or Android if you want, the setup in this
tutorial will be done on the app, but it can also be done
on the IFTTT Website. Follow the images below to set
up your account.

Open ifttt.com, Click the Sign Up button at the top right


corner of the page
Choose to Sign Up with Google or Facebook and fallow
the steps provided
Step 2: Create a Trigger
We will use the app for this step as it is slightly easier,
follow the images for the setup.
Open the IFTTT app, Click on My Applets at the bottom
of the screen
Click on the + button at the top right corner of the page
select the + button on the page that opens

On the fallowing page, search for "Adafruit" in the


search bar and click on the trigger below, you will be
instructed to connect to Adafruit, fallow the steps

Chose "Any New Data" on the fallowing window

Click on the Feed Name Box and choose


sendToDropbox, click next when you are done.
Now click the other + button on the opening page

Search for "Dropbox" in the search bar, you will be


instructed to link your Dropbox account, fallow the steps
given

Now click on Append to a text file

Set the name, content and folder path of the file, for
best experience, keep content the same as in image, click
next

Now enable Notifications if you want and you will


receive a notification every time the Applet triggers,
click Finish

Setup
Follow the images below to get the credentials required
for the project.
Open io.adafruit.com, select Dashboards from the left
side menu

Click on a dashboard or create one by selecting Actions |


New Dashboard

Now click on the Key icon at the top right of the page

Copy the Active key and paste it in the required


location in the Arduino Sketch
Obtaining your username is easy, just copy your
username and paste it in the required location int the
Arduino Sketch. Now connect your Arduino Yún to your
Mac/PC and upload the code.
Background
I was recently thinking of a way to track the number of
times an RFID module has been used, and to monitor the
time at which it has. I happened to think about Dropbox
at the same time and decided to create an Arduino Yun
that parses RFID module operation data to a text file on
Dropbox.
The Arduino Yun will monitor the amount of times that
the RFID module has been activated and if set up,
IFTTT will send the user a notification with the number
of times that the module has been activated for.

RFIDDropboxLogger
SCHEMATICS
CODE

#define AIO_SERVER "io.adafruit.com"


#define AIO_SERVERPORT 1883
#define AIO_USERNAME "USERNAME" // TODO
- insert username
#define AIO_KEY "AIO KEY" // TODO - insert
app key

#include <Bridge.h>
#include <Console.h>
#include <BridgeClient.h>
#include <SPI.h>
#include <MFRC522.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"

#define SS_PIN 10
#define RST_PIN 5

uint32_t valueToSend; // the value to send to Adafruit


IO
int proDebug = 1; // TODO - debugging?

BridgeClient client;
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER,
AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);
MFRC522 mfrc522(SS_PIN, RST_PIN);

// Initialise Feeds
Adafruit_MQTT_Publish sendToDropbox =
Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME
"/feeds/sendToDropbox");
Adafruit_MQTT_Subscribe subscribeA =
Adafruit_MQTT_Subscribe(&mqtt,
AIO_USERNAME "/feeds/subscribeA");

void MQTTConnect()
{
int8_t ret;

if(mqtt.connected()) // if already connected


{
return;
}

if(proDebug == 1)
{
Serial.println("Connecting to Server");
}

while((ret = mqtt.connect()) != 0) // attempt to connect


{
if(proDebug == 1)
{
Serial.print(" Error - ");
Serial.println(mqtt.connectErrorString(ret));
Serial.println(" Attempting Reconnection in 5
seconds");
}

mqtt.disconnect();
delay(5000);
}

if(proDebug == 1)
{
Serial.println(" Success - Connection Established");
Serial.println("Scan Card");
Serial.println("");
}
}

void setup()
{
Bridge.begin();
Console.begin();
SPI.begin();

if(proDebug == 1)
{
Serial.begin(9600);
while(!Serial) {};
}

mfrc522.PCD_Init();
delay(500);
mqtt.subscribe(&subscribeA); // start subscription
}

void loop()
{
MQTTConnect(); // connect to service

Adafruit_MQTT_Subscribe *subscription;

if(!mfrc522.PICC_IsNewCardPresent())
{
return;
}
if(!mfrc522.PICC_ReadCardSerial())
{
return;
}

String content = ""; // string to store card id

// store card id
for(byte i = 0; i < mfrc522.uid.size; i++)
{
// store the card id number in a variable
content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ?
" 0" : " "));
content.concat(String(mfrc522.uid.uidByte[i], HEX));
}

valueToSend++; // increase value to trigger write

if(proDebug == 1)
{
Serial.print("Publishing ");
Serial.println(valueToSend);
}

Console.println(valueToSend);

if(!sendToDropbox.publish(valueToSend))
{
if(proDebug == 1)
{
Serial.println(F(" Error - Failed to Send Data"));
}
}
else
{
if(proDebug == 1)
{
Serial.println(F(" Success - Data Sent"));
}
}

if(! mqtt.ping()) // ping to keep server connection alive


{
if(proDebug == 1)
{
Serial.println(F("Error - Ping Failed"));
}
}

delay(500);
}
44) How to Make an Ultrasonic Ruller with Arduino
and HC-SR04

COMPONENTS AND SUPPLIES


Arduino UNO & Genuino UNO × 1
Breadboard (generic)
**Optional** × 1

Ultrasonic Sensor - HC-SR04


(Generic)
× 1
Any ultrasonic sensor would
work.
Jumper wires (generic)
Four would be enough × 4

USB-A to B Cable
This will help you to connect × 1
the laptop with Arduino

Laptop or computer
× 1
APPS AND ONLINE SERVICES
Arduino IDE
To program and upload to your
arduino

ABOUT THIS PROJECT

Well I was sitting at home wondering how to measure


how far away things are without getting up of my
couch. So I took a look at some projects. They were
pretty lit but they didn't have inches and millimetres.

SCHEMATICS

Ultrasonic Ruler
Just wire the:

VCC of Ultrasonic sensor ---> 5V in Arduino


Trig of Ultrasonic sensor ---> Pin 2 in Arduino
Echo of Ultrasonic sensor ---> Pin 4 in Arduino
GND of Ultrasonic sensor ---> To GND in Arduino

And then just copy and paste the code above in your
Arduino IDE. To see the distance just go to Tools ->
Serial Monitor or just put Ctrl+Shift+M or for mac
just Command+Shift+M.

CODE
const int trigPin = 2;
const int echoPin = 4;
void setup() {
Serial.begin(9600);}
void loop()
{
long duration, inches, cm, mm;
pinMode(trigPin, OUTPUT);
digitalWrite(trigPin, LOW);
delayMicroseconds(2000);
digitalWrite(trigPin, HIGH);
delayMicroseconds(1000);
digitalWrite(trigPin, LOW);
pinMode(echoPin, INPUT);
duration = pulseIn(echoPin, HIGH);
inches = microsecondsToInches(duration);
cm = microsecondsToCentimeters(duration);
mm = microsecondsToMillimeters(duration);
Serial.print(inches);
Serial.print("in, ");
Serial.print(cm);
Serial.print("cm, ");
Serial.print(mm);
Serial.print(" mm");
Serial.println();
delay(1000);
}
long microsecondsToInches(long microseconds)
{return microseconds / 74 / 2;}
long microsecondsToCentimeters(long microseconds)
{return microseconds / 29 / 2;}
long microsecondsToMillimeters(long microseconds)
{return microseconds / 2.9 / 2;}

45 Arduino Rural Hack Kit


COMPONENTS AND SUPPLIES

Arduino MKR1000
× 1

Arduino Rural Hack Kit × 1


APPS AND ONLINE SERVICES
Arduino Web Editor

ABOUT THIS PROJECT


The Rural Hack kit.
The Rural Hack Kit is the perfect electronic set to get
you started hacking your farm, garden, or plants on
your balcony.
The kit includes the essentials for monitoring the
environment of our green silent friends: an accurate
soil moisture sensor, a precise digital light sensor
module, and a temperature and humidity sensor.
Moreover, to automate your greenhouse, the kit
features a relay module that you can use to control a
water valve, a fan, or a lamp.
KIT CONTENTS
Humidity Sensor (DHT22)
Log-scale Analog Light Sensor (Ga1a12s202 in
its Adafruit's Flavour)
Soil Moisture Sensor (aka the slim chirp) from
Miceuz
Grove Relay Module from Seeed
Resistors / pushbuttons / connectors
This is the first of a series of tutorial that will teach
how to use the modules in the kit. In this tutorial we
are going to learn how to connect the sensors and
actuators to the Arduino, read their data, and interact
with them.
In the next tutorials you will learn how to connect the
sensor to cloud services and take care of your garden
remotely.
DHT22 humidity and temperature sensor
Sensor Specs
The DHT22 is a digital sensor capable of reading
environmental temperature and humidity.
Low cost
3 to 5V power and I/O
2.5mA max current use during conversion (while
requesting data)
Good for 0-100% humidity readings with 2-5%
accuracy
Good for -40 to 80°C temperature readings
±0.5°C accuracy
No more than 0.5 Hz sampling rate (once every 2
seconds)
Body size 27mm x 59mm x 13.5mm (1.05" x
2.32" x 0.53")
4 pins, 0.1" spacing
Weight (just the DHT22): 2.4g
Connections
Connecting to to the sensor is very easy. As shown in
the picture connect
the first pin to VCC on your board.
The second pin is the data Out pin, connect that
to any digital pin on the board.
leave the third pin disconnected.
connect the forth pin to ground.

Setup & test


Before you can try the sensor you need to install its
library. Search for dht on the library manager and
install the library.
Now you can just upload the test sketch that will get
the data from the sensor and print them to the serial
port.
#include <SimpleDHT.h>
// for DHT22,
// VCC: 5V or 3V
// GND: GND
// DATA: 6
int pinDHT22 = 6;
SimpleDHT22 dht22;
void setup() {
Serial.begin(115200);
}
void loop() {
// start working...
Serial.println("=================================");
Serial.println("Sample DHT22...");
// read without samples.
// @remark We use read2 to get a float data, such as 10.1*C
// if user doesn't care about the accurate data, use read to get a byte data,
such as 10*C.
float temperature = 0;
float humidity = 0;
int err = SimpleDHTErrSuccess;
if ((err = dht22.read2(pinDHT22, &temperature, &humidity, NULL)) !=
SimpleDHTErrSuccess) {
Serial.print("Read DHT22 failed, err="); Serial.println(err);delay(2000);
return;
}
Serial.print("Sample OK: ");
Serial.print((float)temperature); Serial.print(" *C, ");
Serial.print((float)humidity); Serial.println(" RH%");
// DHT22 sampling rate is 0.5HZ.
delay(2500);
}
You can now open the serial monitor and you should
be able to see the temperature and humidity value
printed there.
I2C Soil moisture sensor
The soil moisture sensor provided with the kit is
probably one of the most reliable and at the same time
cheap sensor for DIY soil moisture measurement on
the market.
Classic soil moisture sensor, (the one that look like a
fork with two electrodes) measure resistance between
the two electrodes planted in the soil; High resistance
between the electrodes means that the soil is not
conducting electricity therefore it is probably dry; low
resistance means that the electricity is flowing easily
between the two electrodes, that's what happens when
the sensor is in water or in a wet soil.
The downside of the described techniques is that the
copper on the electrodes quickly get rusty, hence after
a while, the reading from those sensor become not
accurate anymore.
The sensor provided in the kit, uses capacitive sensing
to measure the capacitance of the medium it's
surrounded by: Wet soil for instance has a higher
capacitance than dry soil or air. Instead of electrodes it
features a capacitive antenna that doesn't need to stay
in direct contact with the soil, this protects the sensor
making it's reading reliable and accurate in time.
The sensor can be read via I2C protocol and provides
these features:
Soil moisture sensing
Light sensing
Temperature sensing
Reset chip
I2C address change
Deep sleep
Sensor Specs
Version 2.7.5
Supply voltage 3.3V - 5V
Current consumption: 1.1mA @ 5V, 0.7mA @
3.3V when idle, 14mA @ 5V, 7.8mA @ 3.3V
when taking a measurement. When constantly
polling sensor at full speed, current consumption
averages to 4.5mA @ 5V, 2.8mA @ 3.3V
Operating temperature 0°C - 85°C
Moisture reading drift with temperature - <10%
over full temp range
Don't forget to provide pullups for SCL and SDA
lines
Default I2C address is 0x20 (hex)
Connections
The connection to the sensor is done via i2c,
depending on the board you are using you might have
different pin assigned to I2C;
If you are workng with a MKR1000 connect:
VCC to VCC
GND to GND
SCL to 12
SDA to 11

Setup & test


First of all install the I2CSoilMoistureSensor
Library: open the library manager, search for
I2CSoilMoistureSensor and install the library.
Upload now the example sketch and you should be
able to see the measured data.
#include <I2CSoilMoistureSensor.h>
#include <Wire.h>
I2CSoilMoistureSensor sensor(0x60);
void setup() {
Wire.begin();
Serial.begin(9600);
sensor.begin(); // reset sensor
delay(1000); // give some time to boot up
Serial.print("I2C Soil Moisture Sensor Address: ");
Serial.println(sensor.getAddress(),HEX);
Serial.print("Sensor Firmware version: ");
Serial.println(sensor.getVersion(),HEX);
Serial.println();
}
void loop() {
while (sensor.isBusy()) delay(50); // available since FW 2.3
Serial.print("Soil Moisture Capacitance: ");
Serial.print(sensor.getCapacitance()); //read capacitance register
Serial.print(", Temperature: ");
Serial.print(sensor.getTemperature()/(float)10); //temperature register
Serial.print(", Light: ");
Serial.println(sensor.getLight(true)); //request light measurement, wait and
read light register
sensor.sleep(); // available since FW 2.3
}
GA1A12S202 Log-scale Analog Light Sensor
This very cheap sensor module produced by Adafruit
it’s considerably more accurate that a old fashion
photo-resistor you might have used in other project.
Most light sensors have a linear relationship with light
levels, which means that they're not very sensitive to
changes in darkened areas and 'max' out very easily
when there's a lot of light.
This sensor is logarithmic over a large dynamic range
of 3 to 55,000 Lux, so it has a lot of sensitivity at low
light levels but is also nearly impossible to "max out"
so you can use it indoors or outdoors without changing
code or calibration.
Sensor Specs
Power with 2.3-6V
Onboard 68K load resistor for max 3V analog
output
0.2 grams
0.4” x 0.5" x 0.06" (10mm x 13mm x 1.5mm)
0.1” (2.5mm) mounting hole
Connections
Reading the light intensity with this sensor is is as
easy as reading a analog from an analog sensor.
Just connect the power via the VCC and GND, and
connect the OUT pin to a analog input on your board.
VCC to 3.3V or 5V depending on your board
voltage
OUT to AO on your board
GND to GND on your board

Setup & test


You won’t need any library to use it just read the value
from the A0 pin using analogueRead() function.
Max output value of this sensor is 3.3V, If you are
using a 3.3V board like the mkr1000 you should have
accurate readings out of the box.
A simple conversion from analogue readings to lux is
done in the provided example sketch below.
Upload it to your board and you should be able
accurately measure the light in the room.
/*
Test sketch for the Adafruit Analog Light Sensor
by Bill Earl
for Adafruit Industries
Connect sensor output to Analog Pin 0
Connect VCC to VCC and GND to GND
*/
int sensorPin = A0; // select the input pin for the
potentiometer
float rawRange = 1024; // 3.3v
float logRange = 5.0; // 3.3v = 10^5 lux
void setup()
{
analogReference(EXTERNAL); //
Serial.begin(9600);
Serial.println("Adafruit Analog Light Sensor Test");
}
void loop()
{
// read the raw value from the sensor:
int rawValue = analogRead(sensorPin);
Serial.print("Raw = ");
Serial.print(rawValue);
Serial.print(" - Lux = ");
Serial.println(RawToLux(rawValue));
delay(1000);
}
float RawToLux(int raw)
{
float logLux = raw * logRange / rawRange;
return pow(10, logLux);
}
groove relay
The last important piece of the kit is the relay. The
relay is an electromechanical component that you can
use to control big loads from your Arduino. You can
attach water pumps, fans and basically anything that
can be switched on or off.
!!! watch out !!! connecting big loads like 220V lamps
is dangerous!!! Adopt all the required precautions if
you are working with more than 120V.
the relay provided in the kit can be controlled also by
a 3.3v devices, it is therefore very easy to connect it to
a MKR1000.
Connections
Connecting the relay to the Arduino is very simple,
just connect the 3 wires that come with it to the
Arduino.
VCC to VCC
GND to GND
SIG to pin9 on the Arduino.
The two screw terminal on the module are where you
should attach your load: a fan a pump, a light-strip or
anything else.

Setup & test


To test that everything is working correctly we are just
going to upload a blink sketch on our board.
Every time the led switch on or off you should hear a
mechanical noise inside the relay housing.
int RELAY_PIN=9;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
// initialize digital pin RELAY_BUILTIN as an output.
pinMode(RELAY_PIN, OUTPUT);
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH);
pinMode(RELAY_PIN, HIGH); // open the circuit
delay(1000);
digitalWrite(LED_BUILTIN, LOW); // close the circuit
pinMode(RELAY_PIN, LOW);
delay(1000); // wait for a second
}

SCHEMATICS

/*
-
CODE
#include <I2CSoilMoistureSensor.h>
#include <Wire.h>
#include <SimpleDHT.h>

int pinDHT22 = 6;
SimpleDHT22 dht22;

int sensorPin = A0; // select the input pin for the


ga1a light sensor

I2CSoilMoistureSensor soilMoistureSensor(0x60);
float rawRange = 1024; // 3.3v
float logRange = 5.0; // 3.3v = 10^5 lux

float soilTemperature;
int soilMoisture;

int lightValue;

float airTemperature;
int airHumidity;

void setup() {
Wire.begin();
Serial.begin(9600);
soilMoistureSensor.begin(); // reset sensor
delay(1000); // give some time to boot up
Serial.print("I2C Soil Moisture Sensor Address: ");
Serial.println(soilMoistureSensor.getAddress(),HEX);
Serial.print("Sensor Firmware version: ");
Serial.println(soilMoistureSensor.getVersion(),HEX);
Serial.println();
}

void loop() {

///////////////////////////////////////////////
//get all the data from the soul moisture sensor
///////////////////////////////////////////////
while (soilMoistureSensor.isBusy()) delay(50); //
available since FW 2.3
soilMoisture=soilMoistureSensor.getCapacitance();
soilTemperature=soilMoistureSensor.getTemperature()
/(float)10;
soilMoistureSensor.sleep(); // available since FW 2.3

///////////////////////////////////
//get the data from the dht sensor
///////////////////////////////////

float temperature = 0;
float humidity = 0;
int err = SimpleDHTErrSuccess;

if ((err = dht22.read2(pinDHT22, &temperature,


&humidity, NULL)) != SimpleDHTErrSuccess) {
Serial.print("Read DHT22 failed, err=");
Serial.println(err);delay(2000);
return;
}
airTemperature=(float)temperature;
airHumidity=(float)humidity;

///////////////////////////////////
//get the data from the light sensor
///////////////////////////////////
int rawValue = analogRead(sensorPin);
lightValue=RawToLux(rawValue);

void printValue(){
Serial.print("Soil Moisture Capacitance: ");
Serial.print(", Temperature: ");
Serial.print(", Light: ");
}

float RawToLux(int raw){


float logLux = raw * logRange / rawRange;
return pow(10, logLux);
}

46) Arduino Only Three Pins for a 4X3 Keypad


COMPONENTS AND SUPPLIES
Resistor 330 ohm
× 1

Resistor 1k ohm
× 3
Resistor 3k ohm × 1

4x3 matrix 12 key array switch


keypad × 1

Arduino UNO & Genuino UNO


× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT


Introduction
The aim of this project is to significantly reduce the
number of pins required by a numeric keypad. This is
because we often need many I/O pins compared to those
available on the Arduino Uno or Nanoboards.
The ordinary numerical keypads are structured in matrix:
a 4x3 keypad, requires 4+3 Arduino digital pins.
Numerous libraries are available on the net to use it with
Arduino.
My Solution
The solution I propose is much better because it uses
only three analog inputs, with a circuit like the one
shown in thefollowing figure.
For each column there are only 4 voltage values,
corresponding to each of the 4 keys, plus zero volts in
case no key is pressed. In the equivalent scheme (b) the
R1e indicates one of the four resistors R1-R4, while R2e
is one of the three resistors R5-R7.
Now let's see how to make the four widest possible
intervals. First of all the resistors R2e = R5 = R6 = R7
can be made equal, then we can set R1 = 0 to have the
outputs corresponding to the first line at 5V.
With R2=330 ohm, R3= 1 k ohm, R4= 3 k ohm and R5,
R6, R7= 1 k ohm, the following intervals are obtained
for each output:
As you can see, the intervals on the threeoutputs are the
largest possible and you can use six standard resistors
with atolerance of ±5%. With an extra analogue input
and another resistor, a 4x4keyboard can be used and so
on. The following figure shows the connections
withArduino.

In the diagram the resistor R1 is connected toline 2


because the one on line 1 has drawn it with a wire, so the
resistorreferences have been scaled by one. Pin
assignments can be modified accordingto needs, as long
as they are pin configurable as analog.
Of course, if Arduino is powered at 3.3V, nothing would
change because the ADC converter as default uses the
supplyvoltage and the ADC numbers don’t change.
To test the program, not having a keyboardof this type, I
built it with recycled keys, the figure below shows
myprototype. The 5-pin right connector is used to wire it
to Arduino.
SCHEMATICS
CODE

// limits of keyboard output values:


const int NADCm100[4] = {923,669,412,156};
const int NADCp100[4] = {1123,869,612,356};
const char key[13] = {'1','4','7','C','2','5','8','0','3','6','9','E'};
int keyval[3];
int i,colp,val;

void setup(){
Serial.begin(9600); // used with serial monitor
}

void loop() {
char k;
k = KeyPad();// read keypad
if (k != 'N'){ // a key was pressed
Serial.print("key = ");
Serial.println(k);
delay(500);
}
}

/******** Functions used by program ********/


char KeyPad(){
// read keypad and return the char key
// key = 'N' for none
KeyScan();// read analog keyboard
if (keyval[0]+keyval[1]+keyval[2] < 40) {
return 'N';
}
else { // a key was pressed
delay(10);// antibounce
KeyScan();// reread analog keyboard
for (i=0; i < 3; i++){//identify which column it belongs to
if (keyval[i] > 40){
colp= i;
val= keyval[i];// this is the corresponding value
for (int j=0; j < 4; j++){// identify which key was pressed on the column
if (val >= NADCm100[j] && keyval <= NADCp100[j]){
return key[colp*4+j];
break;
}
}
}
}
}
}

void KeyScan(){// read analog keyboard


keyval[0]= analogRead(A0);
delay(1);
keyval[1]= analogRead(A1);
delay(1);
keyval[2]= analogRead(A2);
delay(1);
}
47) Retro Computing with Arduino Mega and a Z80
Processor
COMPONENTS AND SUPPLIES

Arduino Mega 2560 & Genuino


Mega 2560
× 1

Z80 Processor
× 1
Breadboard (generic) × 1

Jumper wires (generic)


× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT


One day when I tidied up my cellar, I found a Z80
chip from an old computer. In the '80s and '90s, this
processor was very popular, and I dare to say the most
popular processor ever. So I got the idea to breathe
new life into it.
The Z80 has a tinker-friendly 40-pin DIP housing, but
unlike modern tinker-friendly Processors like the
ATmegas, there is no built-in RAM, program flash or
any peripherals. It has only the raw core functionality
of every Processor, which is to make basic
calculations on some bits and bytes.
With a bunch of jumper wires, a small breadboard and
an Arduino Mega that emulates ROM, RAM and serial
IO, I made a fully fledged Z80-based computer!
This is just an academical fun project without any
practical relevance, but it teaches you how
microprocessors still work in detail!
SCHEMATICS
CODE
z80-test.inoC/C++

#include "memory.h"

/*Wiring:
Address Lines:
Arduino Pin 22..29 <---> Z80 A0..A7

Data Lines:
Arduino Pin 49..42 <---> Z80 D0..D7

Control lines:
Arduino Pin 10 <---> Z80 Pin 6 (CLK)
Arduino Pin 19 <---> Z80 Pin 21 (RD)
Arduino Pin 18 <---> Z80 Pin 22 (WR)
Arduino Pin A9 <---> Z80 Pin 19 (MREQ)
Arduino Pin A10 <---> Z80 Pin 20 (IORQ)
Arduino Pin 40 <---> Z80 PIN 26 (RESET)
*/

//Working memory
uint8_t memory[1024];

//Z80 Out
//Port D
#define RD_PIN PD2 //(INT2 - Arduino Pin 19) Z80 Pin21
#define WR_PIN PD3 //(INT3 - Arduino Pin 18) Z80 Pin 22
#define RD ((PIND & (1 << RD_PIN)) == 0)
#define WR ((PIND & (1 << WR_PIN)) == 0)
#define PORT_MASK_D ~((1 << RD_PIN) + ( 1 << WR_PIN));

//Port K
#define MREQ_PIN PK1 //(PCINT17 - Arduino Pin A9) Z80 Pin 19
#define IORQ_PIN PK2 //(PCINT18 - Arduino Pin A10) Z80 Pin 20

#define MREQ ((PINK & (1 << MREQ_PIN)) == 0)


#define IORQ ((PINK & (1 << IORQ_PIN)) == 0)

#define ADDR PINA //A0..A7


#define ADDR_HI (PINC & (PC0 | PC1)) //A8..A9

//Z80 In
//PortB
#define CLK_PIN PB4 //(OC2A) Z80 Pin 6

//Port G
#define INT_PIN PG0 //Z80 Pin 16, Arduino Pin 41
#define RST_PIN PG1 //Z80 PIN 26, Arduino Pin 40
#define WAIT_PIN PG2 //Z80 Pin 24, Arduino Pin 39
#define RESET(b) b == 0 ? PORTG |= (1 << RST_PIN) : PORTG &= ~(1
<< RST_PIN);
#define PORT_MASK_G (1 << INT_PIN) + (1 << RST_PIN) + (1 <<
WAIT_PIN);

// the setup function runs once when you press reset or power the board
void setup() {
Serial.begin(115200);
const long fClk = 1E5;
//Serial.begin(256000);
DDRA = 0x00; //Port A (Addr Low) input
DDRC = 0x00; //Port C (Addr Hi) input
DDRD &= PORT_MASK_D;
DDRK = 0x00; //Port K Input (Z80 sysctl out)
DDRG |= PORT_MASK_G;
PORTG |= PORT_MASK_G;
DDRL = 0xff; //Data Bus
PORTL = 0x00;

//Pin Interrupts
EICRA |= (1 << ISC31) + (0 << ISC30) + (1 << ISC21) + (0 << ISC20);
EIMSK |= (1 << RD_PIN) + (1 << WR_PIN);

//Clock Timer2
DDRB |= (1 << CLK_PIN); //Output
TCCR2A = (0 << COM2A1) + (1 << COM2A0); //Toggle OC2A on
Compare Match
TCCR2A |= (1 << WGM21); //CTC Mode
TCCR2B = (0 << CS22) + (0 << CS21) + (1 << CS20); //No Prescaling
OCR2A = 16E6 / (2 * fClk) - 1;

memset(memory, 0, sizeof(memory));
memcpy(memory, mem, sizeof(mem));

RESET(1);
delay(1);
RESET(0);
}

// the loop is empty, because this is interrupt-driven


void loop() {}

//Read data from Data Bus


inline uint8_t DATA_GET() {
DDRL = 0;
return PINL;
}

//Write data to Data Bus


inline void DATA_PUT(uint8_t d) {
DDRL = 0xff;
PORTL = d;
}
ISR(INT2_vect) {//CPU Reads
//Serial.println(ADDR);
if (MREQ) {
DATA_PUT(memory[ADDR]);
}
}

ISR(INT3_vect) {//CPU Writes


if (MREQ) {
memory[ADDR] = DATA_GET();
}
else {//IORQ
Serial.print((char)DATA_GET());
}
}

memory.hC/C++ code
#ifndef MEMORY_H
#define MEMORY_H

uint8_t mem[] = {
0x21, 0x0a, 0x00, //ld hl, ??
0x0e, 0x00, //ld c, 0
0x06, 0x0c, //ld b, 12
0xed, 0xb3, //otir
0x76, //halt
'H','e','l','l','o', ' ','W','o','r','l','d','\n'
};

#endif

48) Arduino Electronic Chameleon


COMPONENTS AND SUPPLIES

Arduino Nano R3

× 1

Adafruit NeoPixel Ring: WS2812 5050 RGB × 1


LED
TCS 3200 Colour sensor
× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT


Ever wondered how the chameleon changes its colour
through the changes in environmental colours?
There's something called Melanocyte Stimulating
Hormone or MSH. If you want to dig more into this
please follow this link. The stories apart, I wanted to
build ambient lighting system or something like the
chameleon. This looks cool and also it helps eyes. I
had a NeoPixel LED strip and a spare colour sensor.
So I just built my Chameleon (electronic) using
Arduino (microcontroller for everyone) as the brain.
Step 1: Things You Will Need
1. Arduino Nano (any Arduino is fine)
2. Colour Sensor TCS3200
3. NeoPixel LED Strip
4. Jumper wires and power source
Step 2: Brief Intro to Parts
Arduino: Microcontroller which gets the RGB colour
sensor data from TCS 3200 and generates the
respective PWM signal to control the colour of
NeoPixel LED Lights. TCS 3200 Colour Sensor: This
sensor contains an array of photodiodes which respond
differently to different colours hence it gives out the
colour of light falling on the photodiode array. This
data can be used to replicate those colours.Neo Pixel
LED: This can generate a lot of colours based on the
signal given to it. The name of the IC is WS2812B.
Step 3: Connecting Everything

Connection - Reaction..The connection has to be done


in such a way that Arduino has to read the data from 4
different photodiodes in the TCS 3200. And reflect
back those value as data to NeoPixel LEDs to replicate
the same colour. 4 photodiodes on the sensors are
sensitive to 4 different colour combinations. These
produce current signals which are converted into
frequency signals i.e I to F conversionThis is read by
Arduino pins and then given as input to the NeoPixel
LEDs.I don't want to go deep into the working of
sensors. This can be understood by referring the data
sheets of TCS 3200 sensor.
Step 4: Coding
The code for this project is here.
You can download this and unzip the file to find
necessary libraries and code. Please put the libraries
into the libraries folder of Arduino IDE. The compile
the code and upload it.The code is self-explanatory. I
improve my coding by looking at others codes. Any
suggestions to optimise the code are always welcome.
Step 5: Viola... It Works
Here it works. It's now replicating any colours you are
showing it to the sensor. Good applications are
1. Ambient lighting for TVs and PCs, this reduces eye
strain as it mimics maximum colour in your screen.
2. Room lighting
3. Mood lighting
4. You can 3D print a chameleon and place all
electronics to make it as a real 3D printed chameleon.

SCHEMATICS
CODE
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif

// Which pin on the Arduino is connected to the


NeoPixels?
#define PIN 9

// How many NeoPixels are attached to the Arduino?


#define NUMPIXELS 5

Adafruit_NeoPixel pixels =
Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB +
NEO_KHZ800);

int delayval = 333; // delay

#define S0 4
#define S1 5
#define S2 6
#define S3 7
#define sensorOut 8

int frequency = 0;
int Red, Green, Blue;

void setup() {
pinMode(S0, OUTPUT);
pinMode(S1, OUTPUT);
pinMode(S2, OUTPUT);
pinMode(S3, OUTPUT);
pinMode(sensorOut, INPUT);

// Setting frequency-scaling to 20%


digitalWrite(S0,HIGH);
digitalWrite(S1,LOW);

Serial.begin(9600);
pixels.begin(); // This initializes the NeoPixel library.
}

void loop() {
// Setting red filtered photodiodes to be read
digitalWrite(S2,LOW);
digitalWrite(S3,LOW);
// Reading the output frequency
frequency = pulseIn(sensorOut, LOW);
//Remaping the value of the frequency to the RGB
Model of 0 to 255
frequency = map(frequency, 25,72,255,0);
if (frequency < 0) {
frequency = 0;
}
if (frequency > 255) {
frequency = 255;
}
Red= frequency;
// Printing the value on the serial monitor
Serial.print("R= ");//printing name
Serial.print(frequency);//printing RED color frequency
Serial.print(" ");
delay(100);

// Setting Green filtered photodiodes to be read


digitalWrite(S2,HIGH);
digitalWrite(S3,HIGH);
// Reading the output frequency
frequency = pulseIn(sensorOut, LOW);
//Remaping the value of the frequency to the RGB
Model of 0 to 255
frequency = map(frequency, 30,90,255,0);
if (frequency < 0) {
frequency = 0;
}
if (frequency > 255) {
frequency = 255;
}
Green = frequency;
// Printing the value on the serial monitor
Serial.print("G= ");//printing name
Serial.print(frequency);//printing RED color frequency
Serial.print(" ");
delay(100);

// Setting Blue filtered photodiodes to be read


digitalWrite(S2,LOW);
digitalWrite(S3,HIGH);
// Reading the output frequency
frequency = pulseIn(sensorOut, LOW);
//Remaping the value of the frequency to the RGB
Model of 0 to 255
frequency = map(frequency, 25,70,255,0);
if (frequency < 0) {
frequency = 0;
}
if (frequency > 255) {
frequency = 255;
}
Blue = frequency;
// Printing the value on the serial monitor
Serial.print("B= ");//printing name
Serial.print(frequency);//printing RED color frequency
Serial.println(" ");
pixels.setPixelColor(0,
pixels.Color(Red,Green,Blue)); // Moderately bright
green color.
pixels.setBrightness(64);
pixels.show(); // This sends the updated pixel color to
the hardware.
delay(100);
}
49) Door Alarm Sensor with Arduino
COMPONENTS AND SUPPLIES
Arduino Nano Every
× 1

SparkFun Solder-able
Breadboard - Mini
× 1
I will be using a white one.
Buzzer, Piezo × 1

9V battery (generic)
× 1

Male/Female Jumper Wires


× 1

9V Battery Clip
× 1

Reed Switch, SPST-NO


× 1
APPS AND ONLINE SERVICES

Arduino IDE

ABOUT THIS PROJECT


So, in this proyect, we will make a sensor for your
door. We will programe it so that when the door
closes, It plays La Cucaracha. We will use a function called tone.

SCHEMATICS
CODE
int times = 150;
int times2 = 75;
int times3 = 133;

void setup() {
// put your setup code here, to run once:
pinMode(9,INPUT);
pinMode(LED_BUILTIN,OUTPUT);

void loop() {
// put your main code here, to run repeatedly:
int sensorValue = digitalRead(9);

if (sensorValue == HIGH){
digitalWrite(LED_BUILTIN,HIGH);
// Get ready for... LA CUCARACHA
tone(8,261,times2); //First part
delay(times);
tone(8,261,times2);
delay(times);
tone(8,261,times2*1.5);
delay(times);
tone(8,349,times2*2);
delay(times*1.5);
tone(8,440,times2);
delay(times);
tone(8,261,times2);
delay(times);
tone(8,261,times2);
delay(times);
tone(8,261,times2);
delay(times);
tone(8,349,times2*2);
delay(times*1.5);
tone(8,440,times2);
delay(times*2);

tone(8,349,times2); //Second part


delay(times3);
tone(8,349,times2);
delay(times3);
tone(8,329,times2);
delay(times3);
tone(8,329,times2);
delay(times3);
tone(8,293,times2);
delay(times3);
tone(8,293,times2);
delay(times3);
tone(8,261,times2*2);
delay(times*3);
}else{
digitalWrite(LED_BUILTIN,LOW);
}
delay(10);
}
50) Arduino Neopixel Motion Activated Nihht Light

COMPONENTS AND SUPPLIES


Resistor 1k ohm × 1
Ultrasonic Sensor
× 1

Arduino UNO & Genuino UNO


× 1

Jumper wires (generic)


× 1

9V 1A Switching Wall Power


Supply
× 1

NeoPixel strip

ABOUT THIS PROJECT


It's finally working! Took so many code rewrites.
Background
I am new to all of this open source electronics DIY stuff.
I am a moderator for Hackster.io, and as a result, have
become interested in the projects I review. I decided to
make a motion activated night light for my bathroom.
This way I don't have to turn on the bathroom light in the
middle of the night, blinding myself every time go
tinkle.
Introduction
I grabbed code from a few sources and compiled them
together to make the attached code. With Ingo
Lohs help, I saw where I was making a mistake. I was
doing strip.clear, but not strip.show afterwards. Now it
works like a beauty. I used hardware that I had laying
around. No motion sensor was available, hence the
Ultrasonic sensor.
Steps
connect the Ultrasonic sensor Grd to UNO Grd
solder wires to Neopixel Grd, 5v, and Din
plug Neopixel Grd wire to Grd on UNO
join and solder Neopixel 5v wire and Ultrasonic sensor vcc to resistor to
UNO 5v
connect Ultrasonic sensor Trig to UNO pin 2
connect Ultrasonic sensor Echo to UNO pin 3
connect Neopixel Din to UNO pin 12
Upload sketch

Summary
After a few easy connections to the UNO, you have a
pretty night light that will activate when you walk in
front of the Ultrasonic sensor. I hope this has helped
those of you that want to use an Ultrasonic sensor as a
motion detector. Adjust the distance for activation by
altering the "if" loop cm = _____.

SCHEMATICS
CODE
#include <Adafruit_NeoPixel.h>
#define LEDPIN 12 // connect the Data from the strip to this pin on the
Arduino
#define NUMBER_PIEXELS 43// the number of pixels in your LED strip
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMBER_PIEXELS,
LEDPIN, NEO_GRB + NEO_KHZ800);
const int TrigPin = 2;
const int EchoPin = 3;
float cm;
int delayTime = 200;
int wait = 500;
int i = 0;

void setup()
{
Serial.begin(9600);
pinMode(TrigPin, OUTPUT);
pinMode(EchoPin, INPUT);
strip.begin();

}
void loop()
{

digitalWrite(TrigPin, LOW);
delayMicroseconds(2);
digitalWrite(TrigPin, HIGH);
delayMicroseconds(10);
digitalWrite(TrigPin, LOW);
cm = pulseIn(EchoPin, HIGH) / 58.0; //The echo time is converted into cm
cm = (int(cm * 100.0)) / 100.0; //Keep two decimal places
Serial.print("Distance\t=\t");
Serial.print(cm);
Serial.print("cm");
Serial.println();

if (cm <100){

for (int i=0; i<strip.numPixels()-1; i++) {


// starting at i, draw the 7 color rainbow}
// a seven segment rainbow with red on the highest pixel
void rainbow7(uint16_t i, uint16_t wait) ;
int np = strip.numPixels(); // we use the modulo function with this
strip.setPixelColor(i % np, 0, 0, 0); // off
strip.setPixelColor((i+1) % np, 25, 0, 25); // violet
strip.setPixelColor((i+2) % np, 255, 0, 255); // indigo
strip.setPixelColor((i+3) % np, 0, 0, 150); // blue
strip.setPixelColor((i+4) % np, 0, 150, 0); // green
strip.setPixelColor((i+5) % np, 255, 255, 0); // yellow
strip.setPixelColor((i+6) % np, 110, 70, 0); // orange
strip.setPixelColor((i+7) % np, 150, 0, 0); // red
strip.show();
delay(wait);
strip.clear();
strip.show();}}
else{
strip.clear();
strip.show();
}

}
51) Arduino Easy Iot Water Leakage Indicator
COMPONENTS AND SUPPLIES

Arduino UNO & Genuino UNO


× 1

Espressif ESP8266 ESP-01 × 1


SmartThings Samsung
SmartThings Water Leak Sensor
× 1

7805 Voltage Regulator IC


× 1

9v Battery
× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)
APPS AND ONLINE SERVICES
Arduino IDE

EasyIOT Server

ABOUT THIS PROJECT


This project will keep you aware about leakage of
water from pipe or tank. Leaks from pipes, plumbing
fixtures and fittings are a significant source of water
waste for many households. Research has shown that
the typical home can lose 2,000 to 20,000 gallons of
water per year due to leaks. Some leaks are obvious,
such as dripping faucets and leaking water heaters.
Unfortunately, many leaks go undetected for years
because the source of the leak is not visible.
Step 1: Power Supply
Here we will use 9v battery for power supply. We will
need 7805 voltage regulator IC to get 9V. Then from
7805 IC, feed it to Arduino.
Step 2: Connecting ESP266 and powering it

Connect the Arduino’s 3v3 (3.3V) output to ESP8266.


The ESP8266 works with 3.3V and not 5V, so this is
necessary.
Step 3: Connect RX and TX
Connect the RXD pin of the Arduino to the RX pin of
the ESP8266.Connect the TXD pin of the Arduino to
the TX pin of the ESP. When we want two things to talk
to each other over serial, we connect the TX pin of one
to the RX of the other (send goes to receive and the
opposite). Here we do not have the Arduino talk to the
ESP8266 though, our computer is talking to it via the
Arduino.
Step 4: GND and RST
Connect the RES or RESET pin, When you ground the
reset pin, the Arduino works as a dumb USB to serial
connector, which is what we want to talk to the
ESP8266.
Step 5: Connecting Water Leak Sensor
Next we connect Ardino and water sensor. We connect
Arduino VCC and GND to water sensor VCC and
GND. Arduino digital Pin 2 is connected to digital out
pin of water sensor.
Now Upload Code.
Step 6: EasyIOT Server
We have To make Our IOT Server which Can be found
on link here: https://iot-playground.com/download

SCHEMATICS
CODE
#include <Esp8266EasyIoT.h>
#include <SoftwareSerial.h>

Esp8266EasyIoT esp;
SoftwareSerial serialEsp(10, 11);

#define LEAK_PIN 2 // Arduino Digital I/O pin


number
#define CHILD_ID_LEAK 0

Esp8266EasyIoTMsg msgLeak(CHILD_ID_LEAK,
V_DIGITAL_VALUE);
//Esp8266EasyIoTMsg msgHum(CHILD_ID_LEAK,
V_LEAK); // supported in esp >= V1.1 lib

int lastLeakValue = -1;

void setup()
{
serialEsp.begin(9600);
Serial.begin(115200);

Serial.println("EasyIoTEsp init");
esp.begin(NULL, 3, &serialEsp, &Serial);

pinMode(LEAK_PIN, INPUT);

esp.present(CHILD_ID_LEAK, S_LEAK);
}

void loop()
{
esp.process();

// Read digital pin value


int leakValue = digitalRead(LEAK_PIN);
// send if changed
if (leakValue != lastLeakValue) {
Serial.println(leakValue);
esp.send(msgLeak.set(leakValue==0?0:1));
lastLeakValue = leakValue;
}
}

52) Arduino Climate Cube for Greenhouse


COMPONENTS AND SUPPLIES
Arduino MKR1000
You can find a BOM file for × 1
full list of components

1,3" OLED I2C display


× 1

2-channel Opto-isolate Relay × 1


Module
5V DC power supply
× 2

DS3231 clock
× 1

RGB Diffused Common


Cathode
× 1

Limit switch with NO and NC


connection × 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

2 years ago I decided to step to a new level in


controlling micro-climate in our thermal water heated
greenhouses. Before that time for example we did all
airing by opening-closing windows manually. It was a
waste of time, took hours per day! So the "simple" and
clear step was to build automatic micro-climate
control "things" begin with automatic windows
openers.
The physical environment (from big to small):
Production environment (there are 3x2000 m2
different places but basics are the same)
3-phase motor, worm gear unit with two drums
One window faced to North

The other faced South


200 meters long, 10 meters wide and 4 meters
high half-circle production area
Any number (26 in my case) of windows along at
the top of the structure
400 (2x200) meters long, 4mm thick steel
leading wire to attach to the control arms of the
windows. One of the 200m line is the opening
line the other is the closing line.
The leading wire is attached to a 3-phase motor
assembled with a worm gear unit. The steel wire
lines are twisted around the axis of the gear unit
clockwise and counter-clockwise. If the motor
rotates clockwise then one line of wire moves
one direction and the other one moves opposite.
Different rotation is managed by a 3-pole
reversing contactor assembled with a thermal
relay set to the motor's parameters. The contactor
has two 24V AC coils. Coils can be powered
with a 230AC to 24V AC transformer through a
3-way selector switch (OPEN or CLOSE) where
the third position is for the AUTOMATIC
control. For limiting the amount of opening and
closing movement (no to destroy the structure by
the gear) two limit switches have been put near
the steel wire rail.
BIG "How to" questions for automatic micro-climate
control
... How to decide what kind of climate is need
for the plants during 24 hours whole year...?
... How to manage system stability in an airspace
where humidity can be 100%, temperature can be
60 Celsius degree and huge EMI pollution (3-
phase motor, contactor, pumps and relays for
irrigation, etc.) all around...?
... How to protect structure, and parts if
malfunction hits...? Have experienced when a
motor-gear-unit crushes the structure. No one
should see that...
Etc...
A little recollection

Final and stable assembly before Climate Cube


During last 2 years I had several phases of this project.
For example it was a dead end using plastic cases.
High humidity and sunlight can be harmful. All the
1602 and 2004 type LCDs with its HD44780 type
controller have a high sensitivity to any kind of
electromagnetic impact. After a time it just doodled
random things. Not to think for future modifications
can be expensive. Bought many Arduino Nanos
thinking they are just fine but later I built around the
MKR1000 boards. Yes they are much expensive but
for IoT projects being online is essential :) isn't it?
Path believed quite good
After this long prelude lets do the workmanship (from
big to small again).
I need to isolate things as much as possible from
climate. Metal box is the best option i found to
achieve that. I have to separate high voltage things
(Supply Box) from low voltage (MCU Box) things.
Two metal boxes better than one :).

The high voltage box contains the 3-phase input


supply (3 phase + Neutral + Earth). Circuit brakers for
motor/transformer and for MCU in the other box.
Transformer (230V to 24-18-12-6-3V). Reversing
contactor and thermal relay. Input and output cables
from motor to Supply Box, from MCU box to Supply
Box.
The biggest limitation is the physical size of the
controller housing. First it was a headache how to
install everything in a logical manner.
The MCU Box contains the controller aka the Climate
Cube, and an I2C bus expander housing. The
controller have all the stuff what counts here. But first,
the most important thing is I wanted to built it as a
structure of modules to be able to expand, enhance
later and replace parts if necessary. See the wiring
diagram.
MKR1000 has everything (now) i need. Lots of
GPIOs, hardware I2C, WIFI option, and strong
processing ability not to mention it has more program
space than Nanos.
Connection between circuit boards by wires
I use 2-channel opto-isolated relay to switch the 24V
AC circuit to drive the contactors' coil. The relay can
be fully separated from the MCU by giving a
second 5V DC power supply. So the coil of the relay
powered from one power supply (PSU) and the
optocouplers (relay inputs' VCC) are from another
PSU shared with MCU. The two PSUs have been built
with input and output EMI filter circuits. (I did not
find such filtered PSU where 24V AC input available).
A DS3231 clock is installed also. During plant
production there are many scenarios. For example if
there is not enough sunlight for plants to do their
photosynthesis effectively no need to keep hotter air.
The lack of sunlight in the winter (January) not
warmth the air and there is a high chance that
temperature inside is lower than what we wanted so
windows stay closed. If this happens plant cannot get
fresh CO2 rich air. So we need to get some fresh air in
despite the temperature inside still lower what needed.
Of course we don't want to do that in the night when
outer temperature drops minuses. That is why MCU
needs to know what time it is. Because, for the
daylight I need to set checkpoint/time. Example: when
certain conditions appear MCU opens the windows for
5 seconds interval then keep that for 3 minutes than
close them. Air freshening done.
A display is also necessary to set things and inform us.
The 1,3" OLED was the simplest and best for this
project. Uses 3.3V and I2C. Piece of cake.
Keypad was a hard choice. Tried several types
but MPR121 Capacitive keypad won. The 4x4
membrane also in duty elsewhere but uses 8 input. (to
achive only 2 wires using different resistors connected
to its' wires gave hectic readings, so in the end
membrane OK but not with 8 outputs). So the cap.
keypad... Farming is a dirty thing, much have rough
hands and fingers, not to mention gloves. I have to get
used to that capacitive keypad requires clean hand.
There are dedicated switches and a button in duty.
Main switch is a full ON/OFF switch for AC 230V
input. The metal tactile button only switches the Relay
coil ON/OFF (good when debugging needed). And
there is a momentary button also. Pushing it the
display activates for certain seconds and then
deactivates (or pushing it again also deactivates it).
OLED displays have limited lifetime that's the reason
I put it there.
MCU cannot capable of running parallel processes at
the exact same time. To show user what is going on
inside the Cube I also installed an RGB 5MM
(common cathode) LED. You can program which
colour what means in the program loop. For example
in normal 'stand-by' mode when MCU only reads
sensors a blinking green colour indicates everything is
fine "you can go to your work". If freezing hits (not
happened since OLED displays used) blinking stops or
it is just light but not blinks.
The first and most important input is coming from the
temperature sensor. I chose the 1-Wire bus
type DS18B20 sensor. Simple and long range. Range
is needed here, we are talking about 200 meters where
can be so much differences between temperatures. I
managed to reach 50 meters using CAT5 cable.
Sometimes, thanks to the EMI sensor gives 'error'
values but you can filter them easily in the software.
Ready to assembly
In the future under new project names but based on
this very first Climate Cube project i am going to
install more sensors (RH%, LUX, etc.). Optimum
relative humidity for sweet pepper is important
and Si7021 sensor can measure it quite well. The
amount of radiation is also very important to know. If
it is less than the optimum you have to keep cooler
temperature inside, not to turn the growing process
into vegetative stage etc.
The 'What if...' session
There are many dilemmas and 'what if...' type
questions but the main thing is we all exposed to the
changes of weather. All we can do is to adapt our
micro-climate to it. First of all, for optimum
adaptation we need exact data (°C of Air, °C of Soil,
RH%, Soil moisture, Watts/m2° etc.) from our
surroundings. Second, we should know what plants
exact need in certain period of production. Only after
these information we can start to think about what
type of intervention should we take.
Next levels of Climate Cube
I am about to build a 3G based Wi-Fi network in the
area, after that i can monitor, manage etc. the already
installed units. I real IoT based plant production come
alive soon.

SCHEMATICS
CODE
#include <HCMatrixKeypad.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Metro.h>
#include <Wire.h>
#include <Arduino.h>
#include <U8g2lib.h>
#include "RTClib.h"

#define Addrsi 0x40 //Si7021


#define Addrbh 0x23 // BH1750

U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /*
reset=*/ U8X8_PIN_NONE);

#define relayPin0 16 // a 8es kimenetre rakotve az 1 es rele ami a Zaras


#define relayPin1 17 // a 9as kimenetre rakotve a 2 es rele ami a Nyitas

#define HOMERO 0 // A homero bedugva az mcu 2es digitalis bemenetere


es elnevezve HOMEROnek

#define LED 19

/*unsigned long myChannelNumber = 258360;


const char * myWriteAPIKey = "I44H7MK2AYDPZBIJ";
const long ThingspeakDelay = 30000;*/

int kivantHomerseklet = 1800;


int homDiff = 50;

/* --------- METRO time constants ----------------- */


const int idoNyit = 700;
const int idoZar = 500;

const long varNyit= 90000;


const long varZar= 60000;
const int varLed = 700; //3600000=1 ra
const int varHumHomBes = 1923; //3600000=1 ra
const int varBeSug = 571;
const int varLcd = 1000;
/*----------------Keypad-----------------*/

#define DEBOUNCE 100 //100

#define C1 1 // DIO for keypad column 1


#define C2 2 // DIO for keypad column 2
#define C3 3 // DIO for keypad column 3
#define C4 4 // DIO for keypad column 4

#define R1 8 // DIO for keypad row 1


#define R2 7 // DIO for keypad row 2
#define R3 6 // DIO for keypad row 3
#define R4 5 // DIO for keypad row 4

HCMatrixKeypad Keypad(DEBOUNCE, C1, C2, C3, C4, ROWMARKER,


R1, R2, R3, R4);

/*1=14 . . A=11
4=24 . . B=21
7=34
*=44
*/
/*---------------------------------------------------------------------*/

int state0 = HIGH;


int state1 = HIGH;
int ledstate = LOW;

int inPin = 19; // the number of the input pin

int state = LOW; // the current state of the output pin


int previous = HIGH; // the previous reading from the input pin
// the follow variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long time = 0; // the last time the output pin was toggled
long debounce = 200; // the debounce time, increase if the output flickers

int reading; // the current reading from the input pin


const int numReadings = 10;

int readings[numReadings]; // the readings from the analog input


int readIndex = 0; // the index of the current reading
int total = 0; // the running total
int tempCaverage = 0; // the average

OneWire oneWire(HOMERO); // A homero egykabeles onewire bekotest


kapott
DallasTemperature sensors(&oneWire); // megadtuk a homero gyartasi
tipusat es hivatkozunk ra

RTC_DS3231 rtc;

Metro metro0 = Metro(varZar);


Metro metro1 = Metro(varNyit);
Metro ledMetro = Metro(varLed);
Metro metro3 = Metro(varHumHomBes);
Metro metro4 = Metro(varBeSug);
Metro metro5 = Metro(varLcd);
Metro rtcMetro = Metro(1000);
//Metro metro6 = Metro(ThingspeakDelay);

void setup()
{

// Initialise I2C communication as MASTER


//Wire.begin();
u8g2.begin();
Wire.setClock(32000L); //The slowest i2c speed for Mkr1000

// Initialise serial communication, set baud rate = 9600


//Serial.begin(9600);
//u8g2.setFlipMode(1);
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_7x14_tf); // choose a suitable font
u8g2.drawStr(43,10,"PaMon!"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
delay(2000);
u8g2.clearDisplay();

//Start I2C transmission


Wire.beginTransmission(Addrsi);

// Stop I2C transmission


Wire.endTransmission();
delay(300);

// Start I2C Transmission


Wire.beginTransmission(Addrbh);
// Send power on command
Wire.write(0x01);
// Stop I2C Transmission
Wire.endTransmission();
delay(300);

// Start I2C Transmission


Wire.beginTransmission(Addrbh);
// Send continuous -......-low precision measurement command: 0x13
Wire.write(0x10); //0x10- high-continuous measurement;0x11 high0.5 lx
cont mode 120ms time
// Stop I2C Transmission
Wire.endTransmission();
delay(300);
pinMode(LED,OUTPUT);
digitalWrite(LED,ledstate);

rtc.begin();
sensors.begin(); // Elindul a homero
sensors.setResolution(10);

pinMode(relayPin0, OUTPUT);
digitalWrite(relayPin0, HIGH);

pinMode(relayPin1, OUTPUT);
digitalWrite(relayPin1, HIGH);

// initialize the button pin as a input:


pinMode(inPin, INPUT);

// initialize the LED as an output:

u8g2.clearBuffer(); // clear the internal memory


// write something to the internal memory
//u8g2.sendBuffer();

/*u8g2.setCursor(16,2);
u8g2.print("W/m2");

u8g2.setCursor(0,1);
u8g2.print("Par:");
u8g2.setCursor(8,1);
u8g2.print("%");

u8g2.setCursor(10,1);
u8g2.print("Hom:");
u8g2.setCursor(0,3);
u8g2.print("Aj.Hom:");

/*t = rtc.getTime();

if(t.hour<10) {
u8g2.setCursor(5,3);
u8g2.print("0");
u8g2.setCursor(6,3);
u8g2.print(t.hour);
}
else {
u8g2.setCursor(5,3);
u8g2.print(t.hour);
}

if(t.min<10) {
u8g2.setCursor(8,3);
u8g2.print("0");
u8g2.setCursor(9,3);
u8g2.print(t.min);
}
else {
u8g2.setCursor(8,3);
u8g2.print(t.min);
}*/

for (int thisReading = 0; thisReading < numReadings; thisReading++) {


readings[thisReading] = 0;
}

sensors.requestTemperatures();

delay(500);
metro0.reset();
metro1.reset();
ledMetro.reset();
metro3.reset();
metro4.reset();
metro5.reset();

//WiFi.begin(ssid, pass);
//ThingSpeak.begin(client);
//delay(2000);
}

void loop()
{

//

if (state0 == HIGH && state1 == HIGH) {

if (ledMetro.check() == 1) { // check if the metro has passed its interval .


if (ledstate==HIGH) ledstate=LOW;
else ledstate=HIGH;

digitalWrite(LED,ledstate);
}

float tempRaw = sensors.getTempCByIndex(0);


float tempFloat = tempRaw*100;
int tempInt = tempFloat;

// subtract the last reading:


total = total - readings[readIndex];
// read from the sensor:
if(tempInt>0 && tempInt<8000){
int tempC = tempInt;
readings[readIndex] = tempC;
//Serial.println(tempC);
}
// add the reading to the total:
total = total + readings[readIndex];
// advance to the next position in the array:
readIndex = readIndex + 1;

// if we're at the end of the array...


if (readIndex >= numReadings) {
// ...wrap around to the beginning:
readIndex = 0;
}

// calculate the average:


tempCaverage = total / numReadings;
// send it to the computer as ASCII digits
//Serial.println(tempCaverage);
//delay(100);

//Serial.println(sensors.getTempCByIndex(0));
//Serial.println(tempInt);

//Serial.println(tempCaverage);

u8g2.setCursor(0,10);
u8g2.print("Bh:");

u8g2.setCursor(0,24);
u8g2.print("D:");

u8g2.setCursor(0,38);
u8g2.print("Ah:");

u8g2.setCursor(0,52);
u8g2.print("Ido:");

Keypad.Scan();

/* If so the send the key to the serial port


//Serial.print("Number of Key Pressed: ");
//Serial.println(Keypad.Read());
if (Keypad.Read() > 0){
u8g2.setCursor(120,52);
u8g2.print("*");
}
else {
u8g2.setCursor(120,52);
u8g2.print(" ");
}*/

if (Keypad.Read() == 14) {
kivantHomerseklet+=100;
if (kivantHomerseklet == 2600){
kivantHomerseklet = 1600;
}

}
if (Keypad.Read() == 24) {
kivantHomerseklet-=100;
if (kivantHomerseklet == 1500){
kivantHomerseklet = 2500;
}
}

if (Keypad.Read() == 13) {

homDiff+=10;
if (homDiff > 205){
homDiff = 10;
}

}
if (Keypad.Read() == 23) {
homDiff-=10;
if (homDiff < 5){
homDiff = 200;
}
}
if (rtcMetro.check()== 1) {

DateTime now = rtc.now();

Serial.print(now.year());
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(' ');

Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();

u8g2.setCursor(30,52);
u8g2.print(now.hour());

u8g2.setCursor(45,52);
u8g2.print(":");

u8g2.setCursor(54,52);
u8g2.print(now.minute());

int Bh = kivantHomerseklet/100;
u8g2.setCursor(23,10);
u8g2.print(Bh);
if (homDiff > 5 && homDiff < 100) {
u8g2.setCursor(18,24);
u8g2.print("0.");
u8g2.setCursor(34,24);
u8g2.print(homDiff/10);
u8g2.setCursor(42,24);
u8g2.print(" ");

if (homDiff > 95 && homDiff < 200) {


u8g2.setCursor(18,24);
u8g2.print(homDiff);
u8g2.setCursor(26,24);
u8g2.print(".");
u8g2.setCursor(34,24);
u8g2.print(homDiff-100);
u8g2.setCursor(42,24);
u8g2.print(" ");
}
if (homDiff==200) {
u8g2.setCursor(18,24);
u8g2.print(homDiff);
u8g2.setCursor(26,24);
u8g2.print(".");
u8g2.setCursor(34,24);
u8g2.print(homDiff-200);
u8g2.setCursor(42,24);
u8g2.print(" ");
}

u8g2.setCursor(23,38);
u8g2.print(tempRaw,1);
u8g2.setCursor(62,38);
u8g2.print("C");
//Serial.print("Jelenlegi homerseklet: ");
//Serial.println(sensors.getTempCByIndex(0)); // kiirjuk a monitorra a
kapott homersekletet

if (metro3.check()== 1 && state0 == HIGH && state1 == HIGH) {

unsigned int datasi[2];

// Start I2C transmission


Wire.beginTransmission(Addrsi);
// Send humidity measurement command, NO HOLD MASTER
Wire.write(0xF5);
// Stop I2C transmission
Wire.endTransmission();
delay(150);

// Request 2 bytes of data


Wire.requestFrom(Addrsi, 2);

// Read 2 bytes of data


// humidity msb, humidity lsb
if(Wire.available() == 2)
{
datasi[0] = Wire.read();
datasi[1] = Wire.read();
}

// Convert the data


float humidity = ((datasi[0] * 256.0) + datasi[1]);
humidity = ((125 * humidity) / 65536.0) - 6;

// Start I2C transmission


Wire.beginTransmission(Addrsi);
// Send temperature measurement command, NO HOLD MASTER
Wire.write(0xF3);
// Stop I2C transmission
Wire.endTransmission();
delay(150);

// Request 2 bytes of data


Wire.requestFrom(Addrsi, 2);

// Read 2 bytes of data


// temp msb, temp lsb
if(Wire.available() == 2)
{
datasi[0] = Wire.read();
datasi[1] = Wire.read();
}

// Convert the data


float temp = ((datasi[0] * 256.00) + datasi[1]);
float cTemp = ((175.72 * temp) / 65536.00) - 46.85;

unsigned int databh[2];


// Request 2 byte of data
Wire.requestFrom(Addrbh, 2);

// Read 2 bytes of data


// ALS msb, ALS lsb
if(Wire.available() == 2)
{
databh[0] = Wire.read();
databh[1] = Wire.read();
}
//delay(130);

//convert the data


float luxraw = (((databh[0] * 256.0000) + databh[1]) / 1.2000);
float irradiation = (((databh[0] * 256.0000) + databh[1]) / 1.2000)*0.0079;
int lux = irradiation;
/*if(humidity<=0) {
u8g2.setCursor(4,1);
u8g2.print(" 0 ");

}
if(humidity>0 && humidity<100) {
u8g2.setCursor(4,1);
u8g2.print(humidity,0);
u8g2.setCursor(6,1);
u8g2.print(" ");
}
if(humidity>=100 && humidity<=115) {
u8g2.setCursor(4,1);
u8g2.print(humidity,0);
u8g2.setCursor(7,1);
u8g2.print(" ");
}
if(humidity>115) {
u8g2.setCursor(5,1);
u8g2.print("115");
u8g2.setCursor(4,1);
u8g2.print(">");
}

u8g2.setCursor(14,1);
u8g2.print(cTemp, 1);
u8g2.setCursor(19,1);
u8g2.print("C");

if(lux<10) {
u8g2.setCursor(12,2);
u8g2.print(lux);
u8g2.setCursor(13,2);
u8g2.print(" ");
u8g2.setCursor(14,2);
u8g2.print(" ");
}

if(lux>=10 && lux<100) {


u8g2.setCursor(12,2);
u8g2.print(lux);
u8g2.setCursor(14,2);
u8g2.print(" ");

if(lux>=100 && lux<1000) {


u8g2.setCursor(12,2);
u8g2.print(lux);

if(lux>1000) {
u8g2.setCursor(11,2);
u8g2.print(lux);

if(lux<100) {
u8g2.setCursor(7,3);
u8g2.print("18-20 ");
u8g2.setCursor(13,3);
u8g2.print("C");
}

if(lux>=100 && lux<200){


u8g2.setCursor(7,3);
u8g2.print("21-22 ");
u8g2.setCursor(13,3);
u8g2.print("C");
}

if(lux>=200 && lux<300) {


u8g2.setCursor(7,3);
u8g2.print("23-24 ");
u8g2.setCursor(13,3);
u8g2.print("C");
}

if(lux>=300 && lux<400) {


u8g2.setCursor(7,3);
u8g2.print("25-26 ");
u8g2.setCursor(13,3);
u8g2.print("C");
}
if(lux>=400) {
u8g2.setCursor(7,3);
u8g2.print("Arnyek");
u8g2.setCursor(13,3);
u8g2.print(" ");
}*/

// Output data to serial monitor


Serial.print("Ambient Light Luminance :");
Serial.print(irradiation);
Serial.println(" lux");

// Output data to serial monitor


Serial.print("Relative humidity : ");
Serial.print(humidity);
Serial.println(" % RH");
Serial.print("Temperature in Celsius : ");
Serial.print(cTemp);
Serial.println(" C");
Serial.print("LUX: ");
Serial.print(luxraw);
Serial.println(" lx");

//u8g2.setCursor(0,2);
//u8g2.print("Besugarzas:");
}

reading = digitalRead(inPin);

// if the input just went from LOW and HIGH and we've waited long enough
// to ignore any noise on the circuit, toggle the output pin and remember
// the time
if (reading == HIGH && previous == LOW) {
if (state == HIGH)
state = LOW;
else
state = HIGH;
metro5.reset();
}

if (state == HIGH) {
u8g2.sendBuffer();
Serial.println("OLED ON");
metro5.interval(20000);
}

if(metro5.check() == 1 && state == HIGH){


state = LOW;
}

if (state == LOW) {
// if the current state is LOW then the button
// wend from on to off:
u8g2.clearDisplay();
}
previous = reading;

} // closes the display and measuring methods


if ((kivantHomerseklet-homDiff) == tempCaverage ) {
digitalWrite(relayPin0, HIGH);
digitalWrite(relayPin1, HIGH);
}
if ((kivantHomerseklet+homDiff) == tempCaverage) {
digitalWrite(relayPin0, HIGH);
digitalWrite(relayPin1, HIGH);
}
if (((kivantHomerseklet-homDiff) < tempCaverage && tempCaverage <
(kivantHomerseklet+homDiff)) && relayPin0==LOW) {
digitalWrite(relayPin0, HIGH);

}
if (((kivantHomerseklet-homDiff) < tempCaverage && tempCaverage <
(kivantHomerseklet+homDiff)) && relayPin1==LOW) {
digitalWrite(relayPin1, HIGH);
}

if ((tempCaverage < (kivantHomerseklet-homDiff)) && relayPin1==LOW)


{
digitalWrite(relayPin1, HIGH);
}

if ((tempCaverage > (kivantHomerseklet+homDiff)) && relayPin0==LOW)


{
digitalWrite(relayPin0, HIGH);
}

if ((metro0.check() == 1) && (tempCaverage < (kivantHomerseklet-


homDiff))) { // check if the metro has passed its interval .
if (state0==HIGH) {
state0=LOW;
metro0.interval(idoZar); //Zarasi ido
}
else {
state0=HIGH;
metro0.interval(varZar); // if the pin is LOW, set the interval to 1 second.
}
digitalWrite(relayPin0,state0);
}
if ((metro1.check() == 1) && (tempCaverage >
(kivantHomerseklet+homDiff))) { // check if the metro has passed its
interval .
if (state1==HIGH) {
state1=LOW;
metro1.interval(idoNyit); // if the pin is HIGH, set the interval to 0.25
seconds.
}
else {
state1=HIGH;
metro1.interval(varNyit); // if the pin is LOW, set the interval to 1 second.
}
digitalWrite(relayPin1,state1);
}

sensors.requestTemperatures(); // Homerotol beolvassunk a homersekletet

}
53) Arduino CNC Flatbed Pen Plotter
COMPONENTS AND SUPPLIES
Arduino UNO & Genuino UNO
× 1

USB A-B Cable


× 1

5V 1.2A AC-to-DC Adapter × 1


Should be plugged via 2.1mm
center-positive plug to the
Arduino's power jack.
Stepper Motor 28BYJ-48 - 5V
× 4

Driver PCB based on


ULN2003A
It is useful for driving unipolar × 4
stepper motors. Works like
digital amplifier.
M6 Coupling Nut 10 mm Long
Needed to fix rod with motor's × 4
shaft.
M6 Threaded Rod
× 1
1 meter is just fine.
Universal breadboard SYB-46
× 1
Solderless technologies!
20cm Male-to-Male Jumper
Wire Cable 2.54mm × 20

20cm Male-to-Female Jumper


Wire Cable 2.54mm × 40
NECESSARY TOOLS AND MACHINES
Vernier Caliper
Needed for precise and convenient meter
measurement.
Electric Drill
As alternative, electric screwdriver comes
handy, but it's not recommended.
M5 Metal Drill Bit
Needed for making holes in movable
weights for threading.
M6 Metalworking Drill Tap
Needed for threading in these weights.
M2 Metal Drill Bit
Needed for making holes in long nuts.
M3 Metalworking Drill Tap
Needed for threading in these nuts.
Angle Grinder
Needed for cutting and chamfering of
threaded rod with use of cut-off wheel.
Cut-off Wheel
Mechanical Pencil 0.5 mm
Or use any other pen (preferably with very
liquid ink).
Solid (metallic or wooden) flat weight with
size of 1" approx.
https://www.hackster.io/VINTproYKT/cnc-
flatbed-pen-plotter-1780c9/logs/2
APPS AND ONLINE SERVICES
Arduino IDE

AccelStepper library for Arduino


This library provides an object-oriented
interface for 2, 3 or 4 pin stepper motors
and motor drivers.
Inkscape
Extensible vector graphics editor with
Python 2.7.* included. Needed to write
our own CAM extension.
Gcodetools plug-in for Inkscape
Needed to convert vector image to good
G-code.

ABOUT THIS PROJECT

I've decided to construct flatbed pen plotter for my


graduation project in October 2016. Time to think was
enough.
The idea behind this creation is to print precise A4
drawings with nearly any pen: pencil, ball pen, marker
pen, etc.
Flatbed plotter needs linear actuators in all 3 axes.
First of all, I was thinking about belts. But they
spinned out to be really expensive for my project.
That’s why I thought that nothing more quicker to
construct and accurate to move than the lead
screw could help emphasize economic efficiency of
installation. It's because searching for belts and cogs
in our region is bit more challenging.
Since that time I understood
which motors and drivers would be more expedient to
acquire - 28BYJ-48 and PCB based on ULN2003A.
Came to the conclusion that I very have to buy and
test them. I learned that we also need to beware of
untrusted manufacturers.
Power supply
I don’t too much prefer switching power supply (as
from PC) because of its sizes, weight and
electromagnetic influence. It is good for powering big
creations, but not necessary for my small CNC plotter.
Summarizing maximum currents for motors, use of
portable 1 A power supply is enough, so I also can
easily connect it to Arduino’s DC jack. Neat!
Why I chose 28BYJ-48 - 5V?
This unipolar stepper motor easily integrates into CNC
machine - 5V is just fine with usual power supply.
28BYJ-48 consists of four coils, that should be
controlled in order A-AB-B-BC-C-CD-D-DA or vice
versa for counterclockwise rotation. This movement
mode is called half-step, because shaft is magnetized
by two phase after one, by one after two and so on.
Some research helped to find out maximum current for
coils at fast speed - 200 mA, at stop - 250 mA. Let’s
suppose that all four motors are stopped at the same
time - 4 × 250 mA = 1 A. Usual power supply comes
handy as ever. You can also stop powering motors
when you don’t move them.
Some 28BYJ-48 motors have crappy reductor,
because, you know - these cogs. 5 minutes of rotating
showed that I have actually good reductor - number of
steps per revolution on constant speed make exactly
360°. Maybe more hours of work will show real face
of this monster.
Why I chose driver PCB based on ULN2003A?
First of all, what about hacking from unipolar to
bipolar 28BYJ-48, as some people advise, by cutting
middle copper connection leading from red wire under
plastic cap? It's not the bad idea at all. You will get
decent speedup! But it's out of motor's purpose - by
the end, min. 3 H-bridge ICs (like the L293D or
SN754410NE) will be required. There's also modern
A4988 driver with H-bridge for microstepping.
The above boards are not as cheap as chips, because
they have complicated switching systems used for
driving 4-wire bipolar motors.
So, I avoided these tasks and just chose to keep all "as
is" and brought PCBs based on ULN2003A. They cost
me $0.88/each. But you might chose H-bridges and
that’ll be cool.
Testing motors
At the moment, I have run my motors in 2 directions
simultaneously. Every driver PCB converts 4 digital
input signals to high-voltage high-current output for
motor's coils. To control all 3 axes we use 12 digital
pins on the controller. Interesting that Arduino Uno
has 14 pins in total but 2 of them are connected for
serial communication, so we can occupy exactly 12.
For axis X we need to synchronously move columns in
the point where Y starts and in the point where it ends
to compensate the pressure. So there are 2 stepper
motors for axis X, each of which has separated driver
board.
These PCBs have same input signals (from digital pins
2, 3, 4, 5). That's where breadboard can help make
parallel connection. Universal breadboard also has a
big deal for connections to ground and external
voltage.
Each of Y and Z axes require only one stepper motor.
Y uses digital pins 6, 7, 8, 9, Z - 10, 11, 12, 13. All
digital sequences are generated
by AccelStepper library. This one is pretty straight-
forward in controlling any stepper motors. And one of
the best features there is that it can generate signals
for multiple motors at one time.
Installing lead screws
I think about using long nut as threaded bushing. Shaft
of the motor has radius of 5 mm. It can get in M6
threaded hole and be fixed by two tiny (M3) screws by
its chords. So be ready to make these threaded holes in
the nut. Now when nut is fixed on the shaft, we spin
M6 threaded rod in it.
But here I must stop, because we need to consider
some of the preparatory operations, such as
positioning a weight (that is being moved along axis),
making railway and another fasteners on the base -
one for motor, other for end support.
SCHEMATICS
CODE
#include <AccelStepper.h>
#include <MultiStepper.h>

#define MOTORS_MAXSPEED 1500


#define MOTORS_ACCELERATION 100
#define MOTORS_STEPS_PER_REVOLUTION 4096 // 28BYJ-48 in half-
step mode

AccelStepper motorX(AccelStepper::HALF4WIRE, 2, 3, 4, 5);


AccelStepper motorY(AccelStepper::HALF4WIRE, 6, 7, 8, 9);
AccelStepper motorZ(AccelStepper::HALF4WIRE, 10, 11, 12, 13);

MultiStepper motors;

short motors_dir = 1;
int motors_avgSpeed = MOTORS_MAXSPEED;// Average speed

String input = "";

void doCommand(String command, String param) {// Serial commands hub


if (command == "go") {
long steps = param.toInt();
if (steps == 0) steps = MOTORS_STEPS_PER_REVOLUTION;// Make full
revolution by default
_go(steps);
}
else if (command == "stop") _stop();
else if (command == "dir") _dir();
else if (command == "speed") {
float speed = param.toInt();
if (speed == 0) speed = MOTORS_MAXSPEED;// Average speed equals
maximum speed by default
_speed(speed);
}
}

void setup() {
Serial.begin(115200);// Maximum baud rate for Arduino Uno
Serial.println("Запуск");

input.reserve(128);

motorX.setMaxSpeed(MOTORS_MAXSPEED);
motorY.setMaxSpeed(MOTORS_MAXSPEED);
motorZ.setMaxSpeed(MOTORS_MAXSPEED);
motorX.setAcceleration(MOTORS_ACCELERATION);
motorY.setAcceleration(MOTORS_ACCELERATION);
motorZ.setAcceleration(MOTORS_ACCELERATION);
motors.addStepper(motorX);
motors.addStepper(motorY);
motors.addStepper(motorZ);
}

void loop() {
while (Serial.available()) {
input = Serial.readStringUntil('\n');
input.trim();
int input_sp = input.indexOf(' ');// Checking for space character in input
string
String input_command = input;
String input_param;
if (input_sp > 0) {
input_command = input.substring(0, input_sp);
input_param = input.substring(input_sp + 1);
input_param.trim();
}
doCommand(input_command, input_param);
input = "";
}

measureSteps();

motors.run();
}

void _go(long increment) {


if (motorX.speed() == 0) {
motorX.setSpeed(motors_avgSpeed);
motorY.setSpeed(motors_avgSpeed);
motorZ.setSpeed(motors_avgSpeed);
motors.moveTo(motorX.currentPosition() + motors_dir * increment);
Serial.print("Move to ");
Serial.print(motorX.targetPosition());
Serial.print(" (rotate by ");
Serial.print((float)increment /
(float)MOTORS_STEPS_PER_REVOLUTION * 360);
Serial.print("° ");
if (motors_dir < 0) Serial.print("counter");
Serial.print("clockwise");
Serial.println(")");
}
}

void _stop() {
motors.moveTo(motorX.currentPosition());
motorX.setSpeed(0);
motorY.setSpeed(0);
motorZ.setSpeed(0);
motorX.stop();
motorY.stop();
motorZ.stop();
Serial.println("Stopped");
}

void _dir() {
motors_dir = -motors_dir;
if (motors_dir > 0) Serial.println("CW");
else Serial.println("CCW");
}

void _speed(float speed) {


motors_avgSpeed = speed;
Serial.print("Average speed changed to ");
Serial.println(speed);
}

void measureSteps() {
if (motorX.speed() != 0) {
Serial.print("Position: ");
Serial.print(motorX.currentPosition());
Serial.print(" | Speed: ");
Serial.print(motorX.speed());
Serial.println(" steps/s");
}
}

54) Arduino Bracelet Dodges Obstacles


COMPONENTS AND SUPPLIES

Arduino Nano R3

× 1

Ultrasonic Sensor - HC-SR04 (Generic) × 1


Recycled vibrator motor of cell phone
× 1

Recycled cables
× 1

5v Rechargable battery of 2000mAh.


× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)

Fabrics and glue for the lining.

ABOUT THIS PROJECT

This project is about a bracelet that can help anyone to


perceive an obstacle through a small vibration.
In my house I had some components that I used for this
project, and I did not know what to do with them, so I
thought about how those components can help someone
or how they could improve something and after a while of
thinking about what to do with them. I realized that it was
a good idea to make a bracelet that identifies an obstacle,
for people who can not perceive them.
Then I searched the Internet for a bit of this, and I seen
many people who did similar projects, with the same
goal, and I thought it was great to do it with a different
and low cost perspective.
It works in a very simple way. The ultrasonic sensor HC-
SR04 connected to the arduino emits a wave, this wave
when hitting an obstacle returns and receives the sensor,
by means of this we can obtain the distance to which this
is an obstacle of the sensor and we program it so that in a
range from one certain distance, the vibrator motor will
turn on and vibrate.
SCHEMATICS
CODE
#define echo 8
#define trig 7
long duration,distance;

void setup() {

Serial.begin(9600);
pinMode(echo,INPUT);
pinMode(trig,OUTPUT);
pinMode(5,OUTPUT);
}

void loop() {
digitalWrite(trig,LOW);
delayMicroseconds(2);
digitalWrite(trig,HIGH);
delayMicroseconds(10);
digitalWrite(trig,LOW);

duration=pulseIn(echo,HIGH);
distance=(duration/(2*29));

if(distance>=500 || distance<=0){
Serial.println("____");
}
else{
Serial.print(distance);
Serial.println("cm.");
digitalWrite(5,LOW);
}
if(distance<=45 && distance>=1){// distance in which the bracelet vibrates,
you can edit according to your need

digitalWrite(5,HIGH);
Serial.println("Alarm!!!");
}
delay(400);
}

55) IoT Arduino Ball Tracking


COMPONENTS AND SUPPLIES
Arduino Micro & Genuino
Micro
× 1

Servos (Tower Pro MG996R)


× 1

Android device
× 1

SparkFun WiFi Breakout -


CC3000 × 1
APPS AND ONLINE SERVICES
IoT Colored Ball Tracker

IoT WiFi | Bluetooth Rounded Objects


Tracking

ABOUT THIS PROJECT

The advancement and development of high resolution


per frame cameras in recent years motivate both
engineers and students in the research and creation of
applications based on "automated" computer vision
algorithms, a frequent task and used for the tracking of
object movements and position of the object, as well as
its own characteristics, such as object shape, object
color, etc.
In this case, the project is based on the tracking of
moving objects and specific characteristics of these, such
as circular or spherical shapes and color, besides
positioning and movement of these.
The colors that can be detected with this application are:
Red
Orange
Yellow
Green
Blue
Violet
But tracking is not limited just to this type of tracking,
also you can track recognition of the face, eyes, body
parts such as hands, arms, legs, head, etc.
Some areas in which object tracking can be applied are:
Bodies in motion
Vigilance
Recognition of facial gestures
Body movements
Automated navigation
Trajectories performed by objects.
As I mentioned above the tracking is made on circular
colored objects. With regard to the hardware, I do not
have enough elements to make a robotic arm of at least
two servos. I only have one and a smartphone camera a
little outdated with Android operating system.
How does it work:
Run the application. Select WiFi in the menu to register
the target host and port by which the information will be
sent to the WiFi module. And your Arduino can receive
the information and can make the necessary calculations.
Then you can select the color to be tracked or from the
menu select Ball, and begin to track. When it detects the
object of the selected color, the application will begin
sending the necessary data.
Arduino Micro receives information about the object
through a WiFi module, in this case the SparkFun
Breakout Board CC3000 from IT. The communication is
done through UDP sockets client server, the application
in the mobile sends the necessary data (frame size
position for horizontal and vertical servo) to the
microcontroller, so that this can perform the calculations
with the information sent and perform the updates in the
servos, in this case only the horizontal.
SCHEMATICS
CODE
#include <avr/delay.h>

/* servo libs */
#include "_Servo.h"

/* WiFi libs */
#include "CC3000.h"
#include "CC3000_Client.h"
#include "common.h"

Servo servo_x;
Servo servo_y;

void setup()
{
/* add setup code here */
ConnectionInfo connection_info;

// Initialize CC3000 (configure SPI communications)


#ifdef CC3000_DEBUG
Serial.begin(115200);
#endif

// Initialize CC3000 (configure SPI communications)


if(!wifi.init(9)) {
#ifdef CC3000_DEBUG
DEBUGPRINTLN(PSTR("Initialize CC3000 FAIL!"));
#endif
return;
}

else {
//FreeRam();
#ifdef CC3000_DEBUG
DEBUGPRINTLN(PSTR("Initialize CC3000 OK"));
#endif
}

if(!wifi.connect(ap_ssid, ap_security, ap_password, timeout))


{
#ifdef CC3000_DEBUG
DEBUGPRINTLN(PSTR("Error: Could not connect to AP!"));
#endif
}

// Gather connection details and print IP address


if(!wifi.getConnectionInfo(connection_info) )
{
#ifdef CC3000_DEBUG
DEBUGPRINTLN(PSTR("Error: Could not obtain connection details"));
#endif
return;
}

else
{
#ifdef CC3000_DEBUG
DEBUGPRINT(PSTR("IP Address: "));
printIPAddr(connection_info.ip_address);
#endif
}

pin_mode(SERVO_PIN_X, OUTPUT); // declare the LED's pin as output


pin_mode(SERVO_PIN_Y, OUTPUT); // declare the LED's pin as output

servo_x.attach(SERVO_PIN_X);
servo_y.attach(SERVO_PIN_Y);

// center servos
servo_x.write(SERVO_CENTER_X);
servo_y.write(SERVO_CENTER_Y);

_delay_ms(200);
}
void loop()
{

56) Arduino Event Monitor for Independent Senior


Citizens
COMPONENTS AND SUPPLIES

Arduino MKR1000

× 1

ADXL345
× 1

DS18B20
× 1

Photo resistor × 1
3 mm LED: Red

× 1

3 mm LED: Green

× 1

Buzzer

× 1

Resistor 4.75k ohm

× 3

Resistor 1k ohm

× 2

Resistor 10k ohm × 1


Breadboard (generic)

× 1

Jumper wires (generic)

× 1

Li-Ion Battery 100mAh

× 1

ABOUT THIS PROJECT

The aging population of the world presents enormous


financial challenges. There are not enough retirement
facilities to cater the needs of the elderly and costs are
high. The tendency is that elderly people prefer staying
in their own homes for longer. That makes the elderly
more independent and happier, but risks are higher when
they fall or experience health or security problems.
Sometimes that is only discovered hours or days after
the incident.
With this non-invasive system daily events can be
monitored and recorded and a set of rules can be applied
to generate an alarm condition. This includes:
opening and closing doors
switching lights on or off
using electrical appliances
movement in various locations in the house
temperature measurement
panic button
fall detection (monitor worn by elderly)
A summary of this information will be sent to the cloud.
With the monitor app users with access to the service
will be able to monitor various statuses and will be
alerted of emergency situations. These users may include
family, friends, emergency services and health services.

Infrastructure Needed to Provide the Service:


one or more wifi sensor nodes to collect relevant
data
wifi network infrastructure
data cloud storage and service infrastructure
client app to display cloud collected data and
control sensor nodes via the cloud
A number of different sensors are used to accumulate
data for a rules based system, which will send alerts
when events do not follow a normal pattern. These
include, but are not restricted to:
a) accelerometer - vibration (eg. fridge running),
orientation or fall detection (where the device is
worn by the person), objects being moved (sensor
device attached to the object)
b) light sensor - to determine whether lights are on
and/or sun is shining (curtains drawn of not)
c) temperature - to measure room temperature (too
hot or too cold)
d) magnetic switch OR motion monitor contact - to
determine when a door is opened or closed (when
not supposed to) OR lack thereof (which may be an
abnormal condition) OR lack of motion (for a
period of time in a specific time slot)
All these events are time stamped, so that rules can
include time of day, time slots and time span.
A bi-color LED and buzzer is used to communicate
remote messages and as local alarm when the internet is
not available. Messages may include reminders like
medication, time to feed the cat, time for a meal, etc.
The assumption is that a wifi router, which is connected
to the internet, will be available. The wifi sensor node
makes use of DHCP to obtain an IP address.
Cloud Environment
The wifi sensor node currently makes use of a free
subscription to the Microsoft Azure IoT Hub to store
data. Setup and tools will be described in the software
section.
As a proof of concept I used the Azure Device Monitor
software to analyze data and to send commands to my
MKR1000 sensor node via Azure IoT Hub.
I also installed the Azure IoT Suite and had a look at
their example application (more under software).
In future a Windows 10 app will be used to display data
(light level, temperature) and alerts (fall, door open)
from Azure IoT Hub and to send signal commands to
wifi sensor nodes via the hub.
Hardware Setup
Initially I did my prototype on a breadboard, as shown in
the first picture. The second picture shows the
schematic. Towards the end I decided to do a more
permanent setup for testing and I built the circuit on
prototype board, as seen in the project picture. The
Fritzing file is available under uploaded files.
MKR1000 Sensor Node Breadboard

MKR1000 Sensor node Schematic

Upgrade to MKR1000 core version 1.6.4-mkr02, which


contains a crucial fix for a condition that destroys the
bootloader. Install the latest Arduino Wifi101 library.
Setup the Arduino IDE for MKR1000, plug the module
into a usb port and ensure that the correct serial port is
selected. There are good example sketches in Wifi101 to
turn the module into a webclient or webserver. Try these
out to ensure that your board is working properly.
Change ssid and pass to connect to your own wifi router.
Refer to the hardware schematics and component list to
prepare the wifi sensor node. The pinouts are well
documented in the Arduino sketch.
Initially I planned on using Windows Remote Arduino,
which is a Windows 10 environment that uses firmata
protocol to "take over" the Arduino. This would poll
remote sensors from a Windows app. Due to the
unpredictable nature of accelerometer data I decided
against this method, in favor of pushing sensor data to
the cloud. The obvious choice was Microsoft Azure IoT
Hub.
MKR1000 Sensor Node Sketch
I am thrilled to be in the group of 1000 to familiarize
myself with the MKR1000. Initially I worked through
example sketches in the Wifi101 library. After I defined
the goal of my project I made a decision on the sensors
and other components I would use, preferably in stock
items. I collected libraries and examples for LDR light
dependent resistor, DS18B20 temperature sensor,
ADXL345 accelerometer, switch, bi-color LED, buzzer
and tested them individually on a breadboard. I had to
quickly learn Fritzing to do the schematic and
breadboard layout (see hardware setup).
I received lots of help from members on the MKR1000
forum, as well as other hobbyists (see references). At
this stage I had only heard about Azure, but I decided to
use it for cloud data storage anyway. The vast
capabilities of the Azure cloud platform was quite
confusing. Fortunately Mohan Palanisami (mohanp) did
a good article on connecting to Azure IoT Hub. A
"simple C" sample on azure-iot-sdks looked promising,
but it was not that simple after all and I did not like the
100k+ size of my sketch. I noticed that mohanp only
used around 30k, so I decided to use his sketch as basis.
Initially I used the JSON structure in the connect the
dots library examples, but now I am using a very neat
JSON library for generating strings.
In the main loop there are basic local rules for
determining an event condition (temperature changing x
degrees, light level changing y lumens, accelerometer
events, battery voltage falling under 3.3V). When an
event occurs the data gets sent to Azure IoT Hub, where
a secondary set of rules is applied on the data to decide
on an alarm condition (abnormal events in specific time
slots or time spans). Currently this is not implemented,
but the Azure IoT Suite example shows how it can be
done.
Further work needs to be done to decode combinations
of accelerometer "words" (INACTIVITY, ACTIVITY,
TAP, DOUBLE TAP, FALL DETECT) into real life
events (like fall, object moved, vibration stopped).
With the extension of the deadline I managed to add
more functionality:
JSON generation is simplified by using JSON
library calls. The JSON string is also simplified.
Commands received from Azure IoT
Hub via the Device Explorer "messages to device"
tab are executed on the MKR1000. Examples are
beepon/beepoff to turn the buzzer on of off.
Similarly this could in future be used to turn a
relay on/off to control electrical devices.
I moved from the Arduino IDE environment
to Visual Studio with Visual Micro, Azure IoT Hub
and Github extensions. I posted my local library to
Github from here.
Azure Hub Setup
If you are not already using Azure you can subscribe to a
free account. Use the Azure portal to create you own IoT
Hub (mine is called MKR1000hub)
https://azure.microsoft.com/en-
in/documentation/articles/iot-hub-csharp-csharp-
getstarted/.

To enable you to create and explore devices on Azure


install Device Explorer for IoT Hub devices
https://github.com/Azure/azure-iot-
sdks/blob/master/tools/DeviceExplorer/doc/how_to_use
_device_explorer.md.
Configure the Device Explorer by using the IoT Hub
Connection String and Protocol Gateway Hostname
from Azure portal. Go to the Management tab to create
a device. Use this connection string in the MKR1000
sensor node sketch. The Data tab enables you to display
the JSON messages sent to Azure. The Messages to
Device tab enable you to send messages to the
MKR1000 sensor node (as described in the sketch
section).
Azure IoT Suite
An excellent example application monitors and displays
temperature and humidity. That together with the ease of
registering new devices and the rules engine makes it
ideal for my project. I adapted my sketch to send data to
the sample Azure IoT Hub, which according to Device
Explorer worked. The device showed up in the IoT
Device Portal, but the status stayed "pending". More
people complained about getting the same results
sending from Arduino, but could not get any clarity on
solving the problem. I could also not find documentation
on the JSON schema they use. I tried to reverse engineer
it by looking at the sample data in Device Explorer, but I
may still be missing something.
SCHEMATICS

CODE
MKR1000 Azure Sensor Node Sketch

/* MKR1000Azure.ino - MKR1000 Azure IoT HTTP


client with sensors sending data to Azure IoT Suit
example

Tested joepvanwyk 11 Mar 2016 - adapted from


MKRAzure.ino written by Mohan Palanisamy
(http://mohanp.com)
Instructions are here to properly set up the MKR1000 for
SSL connections http://mohanp.com/mkr1000-azure-iot-
hub-how-to/

Additional code used from sample sketches:


------------------------------------------
Connectthedots - DS18B20.ino // temperature
sensor code outputs degrees Centigrade
Bildr - ADXL345_Example.ino // ADXL345
accelerometer statuses INACTIVITY, ACTIVITY, FALL
DETECT, TAP, DOUBLE TAP
Github - JsonGeneratorExample.ino // Benoit
Blanchon's Json library example simplifies JSON
generation parts of mohanp's code

MKR1000 pinouts:
----------------
LDR analog A0 2
Battery voltage A1 3
LED red D0 9
LED green D1 10
DS18B20 signal D2 11
ADXL345 INT1 ?
Buzzer D3 12
Switch D4 13
MKR1000_LED D6 15 // internal LED
ADXL345 SDA D11 21
ADXL345 SCL D12 22

GND 25
Vcc 26
Vin 27

Rules for posting data to Azure:


--------------------------------
1. Temperature changes by more than 0.5 degrees C
2. Accelerometer combination of statuses defines action
3. Light level changes by more than 100 units
4. Battery voltage falls below 3.3V
5. Switch status changes (door open or close)

Copyright (c) Arduino. All rights reserved.


Licensed under the MIT license. See LICENSE file in
the project root for full license information.
*/

#include <SPI.h>
#include <WiFi101.h>
#include <Wire.h>
#include <ADXL345.h>
#include <OneWire.h>
#include <avr/dtostrf.h>
#include <ArduinoJson.h>

// WiFi Network Config


char ssid[] = "wlan-ap"; // your network SSID
(name)
char pass[] = "qwerty123"; // your network
password (use for WPA, or use as key for WEP)

// Device Explorer - Protocol Gateway Hostname


char hostname[] = "RethinkAzureSensorNode.azure-
devices.net";
// IoT Hub Connection String:
HostName=RethinkAzureSensorNode.azure-
devices.net;SharedAccessKeyName=iothubowner;Share
dAccessKey=yypCMvmAHIZDSKN2CYxVilHeliTau42
EvlBd/QmSC9o=
// Device Explorer - Generated SAS
char authSAS[] = "SharedAccessSignature
sr=RethinkAzureSensorNode.azure-
devices.net&sig=g%2bQHMLYInsPrvbmyeC9QRsA6ku
tL8dQTpz5ruR%2b%2fiY0%3d&se=1490453142&skn
=iothubowner";

char feeduri[] =
"/devices/RethinkAzureSuite01/messages/devicebound?
api-version=2016-02-03"; // feed URI
char azurePOST_Uri[] =
"/devices/RethinkAzureSuite01/messages/events?api-
version=2016-02-03"; // feed POST Uri

// message Complete/Reject/Abandon URIs. "etag" will


be replaced with the message id E-Tag recieved from
recieve call.
String azureComplete =
"/devices/RethinkAzureSuite01/messages/devicebound/e
tag?api-version=2016-02-03";
String azureReject =
"/devices/RethinkAzureSuite01/messages/devicebound/e
tag?reject&api-version=2016-02-03";
String azureAbandon =
"/devices/RethinkAzureSuite01/messages/devicebound/e
tag/abandon?&api-version=2016-02-03";

char DeviceID[] = "RethinkAzureSuite01";

char buffer[256]; // JSON data buffer

// Sensor stuff
#define ldrPin A0 // light sensor
#define batPin A1 // battery voltage
#define LED_red 0 // red status led
#define LED_green 1 // green status led
#define DS18S20_Pin 2 // DS18S20 Signal pin
#define Buzzer 3 // sound output
#define swPin 4 // switch input
#define MKR1000_LED 6 // internal LED

float prevtemp = 0;
float prevacc = 0;
float prevlight = 0;
float prevbattery = 0;
int prevswitch = 0;

unsigned long time_last = millis();


unsigned long time_new = millis();
int polltime = 5; // minimum time between sending
to Azure

int status = WL_IDLE_STATUS;

OneWire ds(DS18S20_Pin); // instantiate


temperature object
ADXL345 adxl; // variable adxl is an instance of
the ADXL345 library
WiFiSSLClient client; // instantiate wifi object
void setup()
{

/* serial is for debugging */


Serial.begin(9600);
int i;
while (!Serial) { if (i++ >= 512) break; } // wait
for serial to connect
// setup I/Os
pinMode(LED_red, OUTPUT); // status LED red
digitalWrite(LED_red, HIGH); // high is off
pinMode(LED_green, OUTPUT); // status LED
green
digitalWrite(LED_green, HIGH); // high is off
pinMode(Buzzer, OUTPUT); // sound out
digitalWrite(Buzzer, LOW); // low is off
pinMode(MKR1000_LED, OUTPUT); // internal
LED
pinMode(swPin, INPUT); // external switch

// ADXL345 accelerometer setup


adxl.powerOn();
//set activity/ inactivity thresholds (0-255)
adxl.setActivityThreshold(75); //62.5mg per increment
adxl.setInactivityThreshold(75); //62.5mg per increment
adxl.setTimeInactivity(10); // how many seconds of no
activity is inactive?
//look of activity movement on this axes - 1 == on; 0 ==
off
adxl.setActivityX(1);
adxl.setActivityY(1);
adxl.setActivityZ(1);
//look of inactivity movement on this axes - 1 == on; 0
== off
adxl.setInactivityX(1);
adxl.setInactivityY(1);
adxl.setInactivityZ(1);
//look of tap movement on this axes - 1 == on; 0 == off
adxl.setTapDetectionOnX(0);
adxl.setTapDetectionOnY(0);
adxl.setTapDetectionOnZ(1);
//set values for what is a tap, and what is a double tap (0-
255)
adxl.setTapThreshold(50); //62.5mg per increment
adxl.setTapDuration(15); //625s per increment
adxl.setDoubleTapLatency(80); //1.25ms per increment
adxl.setDoubleTapWindow(200); //1.25ms per increment
//set values for what is considered freefall (0-255)
adxl.setFreeFallThreshold(7); //(5 - 9) recommended -
62.5mg per increment
adxl.setFreeFallDuration(45); //(20 - 70) recommended -
5ms per increment
//setting all interupts to take place on int pin 1
//I had issues with int pin 2, was unable to reset it
adxl.setInterruptMapping(ADXL345_INT_SINGLE_TA
P_BIT, ADXL345_INT1_PIN);
adxl.setInterruptMapping(ADXL345_INT_DOUBLE_T
AP_BIT, ADXL345_INT1_PIN);
adxl.setInterruptMapping(ADXL345_INT_FREE_FALL
_BIT, ADXL345_INT1_PIN);
adxl.setInterruptMapping(ADXL345_INT_ACTIVITY_
BIT, ADXL345_INT1_PIN);
adxl.setInterruptMapping(ADXL345_INT_INACTIVIT
Y_BIT, ADXL345_INT1_PIN);
//register interupt actions - 1 == on; 0 == off
adxl.setInterrupt(ADXL345_INT_SINGLE_TAP_BIT,
1);
adxl.setInterrupt(ADXL345_INT_DOUBLE_TAP_BIT,
1);
adxl.setInterrupt(ADXL345_INT_FREE_FALL_BIT, 1);
adxl.setInterrupt(ADXL345_INT_ACTIVITY_BIT, 1);
adxl.setInterrupt(ADXL345_INT_INACTIVITY_BIT,
1);

//check for the presence of the shield:


if (WiFi.status() == WL_NO_SHIELD) {
// don't continue:
while (true);
}

// attempt to connect to Wifi network:


while (status != WL_CONNECTED) {
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}

void loop()
{
// Check for messages from Azure IoT Hub and process
them
azureHttpMessage();

// Read accelerometer and send to Azure


int acc = getAccelerometer();
if (acc > 0) { // acceleration action sensed
if (wifiConnect()) {
prevacc = acc;
LED_blink(LED_red, 50, 1);
httpRequest("POST", azurePOST_Uri, "", buffer);
// buffer contains JSON data
delay(polltime);
}
}

// Read temperature and send to Azure


float temp = getTemp();
float temp1 = (temp - prevtemp);
if (abs(temp1) > 1) { // temperature changed by
more than 1 degrees C
if (wifiConnect()) {
prevtemp = temp;
LED_blink(LED_red, 50, 2);
httpRequest("POST", azurePOST_Uri, "", buffer);
// buffer contains JSON data
delay(polltime); // minimum poll time in seconds
}
}

// Read lightlevel and send to Azure


float light = getLight();
float light1 = (light - prevlight);
if (abs(light1) > 100) { // light level changed more
than 100 units
if (wifiConnect()) {
prevlight = light;
LED_blink(LED_red, 50, 3);
httpRequest("POST", azurePOST_Uri, "", buffer);
// buffer contains JSON data
delay(polltime); // minimum poll time in seconds
}
}

// Read battery voltage and send to Azure


float battery = getBatteryV();
float battery1 = (battery - prevbattery);
if (abs(battery1) > 100) { // battery voltage
changed more than 0.5V
if (wifiConnect()) {
prevbattery = battery;
LED_blink(LED_red, 50, 4);
httpRequest("POST", azurePOST_Uri, "", buffer);
// buffer contains JSON data
delay(polltime); // minimum poll time in seconds
}
}

int switchstatus = getSwitch();


if (!(switchstatus == prevswitch)) {
if (wifiConnect()) {
prevswitch = switchstatus;
LED_blink(LED_red, 50, 5);
httpRequest("POST", azurePOST_Uri, "", buffer);
// buffer contains JSON data
delay(polltime); // minimum poll time in seconds
}
}

time_new = millis();
if ((time_new - time_last) > 20000) {
LED_blink(LED_green, 50, 2);
time_last = millis();
azureIoTReceiveMessage(); // send Azure request
for message
}
}
/************ Read temperature ************/

float getTemp() {
//returns the temperature from one DS18S20 in
Centigrade
byte data1[12];
byte addr[8];

if (!ds.search(addr)) {
//no more sensors on chain, reset search
ds.reset_search();
return -1000;
}

if (OneWire::crc8(addr, 7) != addr[7]) {
return -1000;
}

if (addr[0] == 0x10) {
//Sensor is a DS18S20
}
else if (addr[0] == 0x28) {
//Sensor is a DS18BS20
}
else
{
return -1000;
}

ds.reset();
ds.select(addr);
ds.write(0x44, 1); // start conversion, with parasite
power on at the end

byte present = ds.reset();


ds.select(addr);
ds.write(0xBE); // Read Scratchpad

for (int i = 0; i < 9; i++) { // we need 9 bytes


data1[i] = ds.read();
}

ds.reset_search();
byte MSB = data1[1];
byte LSB = data1[0];

float tempRead = ((MSB << 8) | LSB); //using two's


compliment
float TemperatureSum = tempRead / 16;
// JSON buffer created
// Create the root of the object tree.
StaticJsonBuffer<256> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["DeviceID"] = DeviceID;
root["Temperature"] =
double_with_n_digits(TemperatureSum, 2);
// Print to buffer
root.printTo(buffer, sizeof(buffer));

return TemperatureSum;

/************ Read accelerometer ************/

int getAccelerometer() {
char action[50]; // strcat needs a character
array
memset(action, '\0', sizeof(action));
int interrupt = 0;

int x, y, z;
adxl.readAccel(&x, &y, &z); //read the accelerometer
values and store them in variables x,y,z
//read interrupts source and look for triggerd actions
byte interrupts = adxl.getInterruptSource();

// freefall
if (adxl.triggered(interrupts, ADXL345_FREE_FALL))
{
strcat(action, "freefall ");
interrupt = 1;
//add code here to do when freefall is sensed
}

//inactivity
if (adxl.triggered(interrupts, ADXL345_INACTIVITY))
{
strcat(action, "inactivity ");
interrupt = 0;
//add code here to do when inactivity is sensed
}

//activity
if (adxl.triggered(interrupts, ADXL345_ACTIVITY)) {
strcat(action, "activity ");
interrupt = 1;
//add code here to do when activity is sensed
}

//double tap
if (adxl.triggered(interrupts,
ADXL345_DOUBLE_TAP)) {
strcat(action, "double tap ");
interrupt = 1;
//add code here to do when a 2X tap is sensed
}

//tap
if (adxl.triggered(interrupts, ADXL345_SINGLE_TAP))
{
strcat(action, "tap ");
interrupt = 1;
//add code here to do when a tap is sensed
}

// JSON buffer created


// Create the root of the object tree.
StaticJsonBuffer<256> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["DeviceID"] = DeviceID;
root["Accelerometer"] = action;
// Print to buffer
root.printTo(buffer, sizeof(buffer));

return interrupt;
}

/************ Read lightlevel ************/

float getLight() {
float lightlevel = analogRead(ldrPin);

// Create the root of the object tree.


StaticJsonBuffer<256> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
// JSON buffer created
root["DeviceID"] = DeviceID;
root["Lightlevel"] = double_with_n_digits(lightlevel, 2);
// Print to buffer
root.printTo(buffer, sizeof(buffer));

return lightlevel;
}

/************ Read battery voltage ************/

float getBatteryV() {
float batteryV = analogRead(batPin);

// Create the root of the object tree.


StaticJsonBuffer<256> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
// JSON buffer created
root["DeviceID"] = DeviceID;
root["Batvolts"] = double_with_n_digits(batteryV, 2);
// Print to buffer
root.printTo(buffer, sizeof(buffer));

return batteryV;
}

/************ Read switch ************/

int getSwitch() {
int swStatus = digitalRead(swPin);
char truefalse[5]; // strcat needs a
character array
memset(truefalse, '\0', sizeof(truefalse));

if (swStatus == 0) {
strcat(truefalse, "OFF");
}
else
{
strcat(truefalse, "ON");
}

// Create the root of the object tree.


StaticJsonBuffer<256> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
// JSON buffer created
root["DeviceID"] = DeviceID;
root["Switch"] = truefalse;
// Print to buffer
root.printTo(buffer, sizeof(buffer));

return swStatus;
}

/********************* Blink
***********************/

void LED_blink(int portnum, int timedelay, int


flashnum) {
for (int i = 0; i < flashnum; i++) {
digitalWrite(portnum, LOW);
delay(timedelay);
digitalWrite(portnum, HIGH);
delay(timedelay);
}
}

//******************* Open WiFi connection


****************/

int wifiConnect() {
// attempt to connect to Wifi network:
while (status != WL_CONNECTED) {
status = WiFi.begin(ssid, pass);
// wait 1 seconds for connection:
delay(1000);
}
return 1;
}

/**************************** Azure related


methods **************************/

/************* this method checks for messages from


the Aure IoT Hub and processes them
***************/
void azureHttpMessage() {
String response = "";
char c;
///read response if WiFi Client is available
while (client.available()) {
c = client.read();
response.concat(c);
}

if (!response.equals(""))
{
//if there are no messages in the IoT Hub Device queue,
Azure will return 204 status code.
if (response.startsWith("HTTP/1.1 204"))
{
//turn off onboard LED
digitalWrite(MKR1000_LED, LOW);
}
else
{
//turn on onboard LED
digitalWrite(MKR1000_LED, HIGH);
// get the ETag from the received message response
String eTag = getHeaderValue(response, "ETag");

// get the payload from the message response


String command = getResponsePayload(response);

azureIoTCompleteMessage(eTag);

if (command == "beepon") {
//turn on buzzer
digitalWrite(Buzzer, HIGH);
}

if (command == "beepoff") {
//turn off buzzer
digitalWrite(Buzzer, LOW);
}
}
}
}

/************* Receive Azure IoT Hub "cloud-to-


device" message ***************/
void azureIoTReceiveMessage()
{
httpRequest("GET", feeduri, "", "");
}

/************* Tells Azure IoT Hub that the message


with the msgLockId is handled and it can be removed
from the queue ***************/

void azureIoTCompleteMessage(String eTag)


{
String uri = azureComplete;
uri.replace("etag", trimETag(eTag));

httpRequest("DELETE", uri, "", "");


}

/************* Azure POST, GET, DELETE requests


***************/

void httpRequest(String verb, String uri, String


contentType, String content)
{
if (verb.equals("")) return;
if (uri.equals("")) return;

// close any connection before send a new request.


// This will free the socket on the WiFi shield
// client.stop();

// if there's a successful connection:


if (client.connect(hostname, 443)) {
client.print(verb); //send POST, GET or DELETE
client.print(" ");
client.print(uri); // any of the URI
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(hostname); //with hostname header
client.print("Authorization: ");
client.println(authSAS); //Authorization SAS
token obtained from Azure IoT device explorer
client.println("Connection: close");

if (verb.equals("POST"))
{
client.print("Content-Type: ");
client.println(contentType);
client.print("Content-Length: ");
client.println(content.length());
client.println();
client.println(content);

}
else
{
client.println();
}
}
}

/************* To get only the message header from


http response ***************/

String getHeaderValue(String response, String


headerName)
{
String headerSection = getHeaderSection(response);
String headerValue = "";
int idx = headerSection.indexOf(headerName);

if (idx >= 0)
{
int skip = 0;
if (headerName.endsWith(":"))
skip = headerName.length() + 1;
else
skip = headerName.length() + 2;

int idxStart = idx + skip;


int idxEnd = headerSection.indexOf("\r\n", idxStart);
headerValue = response.substring(idxStart, idxEnd);
}

return headerValue;
}

/********** Azure IoT sets ETag string enclosed in


double quotes, not in sync with its other endpoints - need
to remove the double quotes ************/
String trimETag(String value)
{
String retVal = value;

if (value.startsWith("\""))
retVal = value.substring(1);

if (value.endsWith("\""))
retVal = retVal.substring(0, retVal.length() - 1);

return retVal;
}

/************* To get all the headers from the HTTP


Response ***************/

String getHeaderSection(String response)


{
int idxHdrEnd = response.indexOf("\r\n\r\n");

return response.substring(0, idxHdrEnd);


}
/************* To get only the message payload from
http response ***************/

String getResponsePayload(String response)


{
int idxHdrEnd = response.indexOf("\r\n\r\n");

return response.substring(idxHdrEnd + 4);


}
Azure sensor dataPlain text

Azure JSON data as viewed in Device Explorer

Receiving events...
26 Mar 2016 10:44:14 PM> Device:
[RethinkAzureSuite01], Data:
[{"DeviceID":"RethinkAzureSuite01","Temperature":24
.44}]
27 Mar 2016 8:40:50 AM> Device:
[RethinkAzureSuite01], Data:
[{"DeviceID":"RethinkAzureSuite01","Temperature":85
.00}]
27 Mar 2016 8:40:50 AM> Device:
[RethinkAzureSuite01], Data:
[{"DeviceID":"RethinkAzureSuite01","Temperature":18
.62}]
27 Mar 2016 8:43:49 AM> Device:
[RethinkAzureSuite01], Data:
[{"DeviceID":"RethinkAzureSuite01","Temperature":19
.69}]
27 Mar 2016 8:49:26 AM> Device:
[RethinkAzureSuite01], Data:
[{"DeviceID":"RethinkAzureSuite01","Temperature":20
.75}]
27 Mar 2016 8:51:44 AM> Device:
[RethinkAzureSuite01], Data:
[{"DeviceID":"RethinkAzureSuite01","Lightlevel":451.
00}]
27 Mar 2016 9:06:44 AM> Device:
[RethinkAzureSuite01], Data:
[{"DeviceID":"RethinkAzureSuite01","Temperature":21
.81}]
27 Mar 2016 9:07:31 AM> Device:
[RethinkAzureSuite01], Data:
[{"DeviceID":"RethinkAzureSuite01","Lightlevel":364.
00}]
27 Mar 2016 9:11:16 AM> Device:
[RethinkAzureSuite01], Data:
[{"DeviceID":"RethinkAzureSuite01","Lightlevel":376.
00}]
27 Mar 2016 9:11:59 AM> Device:
[RethinkAzureSuite01], Data:
[{"DeviceID":"RethinkAzureSuite01","Lightlevel":477.
00}]
27 Mar 2016 9:13:11 AM> Device:
[RethinkAzureSuite01], Data:
[{"DeviceID":"RethinkAzureSuite01","Lightlevel":335.
00}]
27 Mar 2016 9:26:48 AM> Device:
[RethinkAzureSuite01], Data:
[{"DeviceID":"RethinkAzureSuite01","Lightlevel":420.
00}]
27 Mar 2016 9:27:24 AM> Device:
[RethinkAzureSuite01], Data:
[{"DeviceID":"RethinkAzureSuite01","Lightlevel":521.
00}]
27 Mar 2016 9:39:31 AM> Device:
[RethinkAzureSuite01], Data:
[{"DeviceID":"RethinkAzureSuite01","Temperature":20
.75}]
27 Mar 2016 9:51:58 AM> Device:
[RethinkAzureSuite01], Data:
[{"DeviceID":"RethinkAzureSuite01","Lightlevel":398.
00}]
27 Mar 2016 9:52:25 AM> Device:
[RethinkAzureSuite01], Data:
[{"DeviceID":"RethinkAzureSuite01","Switch":"OFF"}]
27 Mar 2016 9:52:34 AM> Device:
[RethinkAzureSuite01], Data:
[{"DeviceID":"RethinkAzureSuite01","Switch":"ON"}]

Commands sent from Device Explorer


Started monitoring feedback for device
RethinkAzureSuite01.
Sent to Device ID: [RethinkAzureSuite01],
Message:"beepon", message Id: 737786cd-50e5-4bca-
bc80-7aeddcc78466
Sent to Device ID: [RethinkAzureSuite01],
Message:"beepoff", message Id: 748fb613-8f06-4bdd-
b228-256d1cfefef2
57) Arduino Washing Machine Timer

COMPONENTS AND SUPPLIES


SparkFun Arduino Pro Mini 328 × 1
- 5V/16MHz

1306 OLED Display


× 1

DFRobot Gravity:Digital Push


Button (Yellow)
× 2

Seeed Grove - 2-Channel SPDT


Relay
× 1

Digilent 5V 2.5A Switching


Power Supply
× 1

SparkFun USB UART Serial


Breakout - CY7C65213
× 1

HC-05 Bluetooth Module × 1


NECESSARY TOOLS AND MACHINES
Soldering iron (generic)

Hot glue gun (generic)

Tape, Double Sided

Tape, Green
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

This is a replacement part for the washing machine I have that has a broken
wash timer. The original timer was a mechanical timer/direction switch,
which can control the washing tub's motor in following manner:
Take x minutes of wash time input from user
Rotate washing tub's motor clockwise for few seconds
Stop motor for few seconds
Rotate wash tub's motor anti-clockwise for few seconds
Stop motor for few seconds
Keep doing last 4 steps until wash timer expires

Hardware
Arduino Pro Mini: Runs code and controls everything
1306 OLED: Show user instruction and timer countdown
Red/Black Push Button: Set timer and start timer
5V Relay Modules: Supply AC power to motor and control direction
5V Adapter: Power the electronic timer
1306 OLED is directly soldered on the pro mini like this:
Arduino Pro Mini + 1306 OLED
2 relays module, 2 push buttons, Arduino Pro Mini + 1306 OLED is
connected on a protoboard like this -

Hardware
Soldering
Programming
Step 1: Get a HC-05 Bluetooth-Serial module and change it's baud rate to
57600 according to this tutorial or this step. To perform this step another
Arduino Uno or a USB to Serial module will be required.
Use following AT commands
AT
AT+UART = 57600,0,0
AT+RESET
Step 2: After the baud rate is changed to 57600, connect
the HC-05 to Arduino pro mini according to following wiring
diagram
Wireless Programming of Arduino Pro mini with HC-05
Step 3: Select board from Arduino IDE, paste the code and click upload.

Selecting appropriate board


I am using Bluetooth serial, because it enables wireless in system field
programmable capabilities, which helped updating the code on pro mini if
needed.
Wiring and Device Operation Explained
Wiring may vary for newer/different washing machine models, so I am
going to explain about my one. Pay attention to the "Sharp" diagram on
bottom-right corner, one WHITE WIRE is coming from mains and going to
the wash timer, one RED WIRE and one BLUE WIRE is coming out of the
wash timer. I have disconnected these 3 wires from the original (faulty)
wash timer and brought out through a hole on the top of the washing
machine.

Wiring Explained
Broken Mechanical Timer/Motor Direction Control Switch
When WHITE WIRE is switched to the RED WIRE motor rotates in
clockwise and when WHITE WIRE is switched to the BLUE WIRE motor
rotates in anticlockwise direction.
This electronic timer made with Arduino pro mini will keep track of wash
time, rotate the wash tub's motor in one direction for 5 seconds by
connecting WHITE and RED wires through one relay contact. Then it will
stop the motor and wait for 5 seconds. After that it will rotate the was tub's
motor in the other direction for 5 seconds by connecting the WHITE and
BLUE wires through the other relay contact. Then it will stop and wait for
another 5 seconds. All these timing sequence can be modified from the code
if necessary.
Following diagram shows how just flipping the AC incoming mains to one
leg or the other leg of the motor's capacitor, direction of the AC motor can
be altered.
AC Induction Motor Direction Control
SCHEMATICS
CODE

#include "U8glib.h"
//SSD1306 oled waveshare(clk,din,cs,d/c,res);
U8GLIB_SSD1306_128X64 u8g(A4,A5,12,11,10);

volatile int rbc = 0;


volatile int bbc = 0;
int sec =0;
int mi = 0;
int motor_rotation = 0;

void setup()
{
u8g.setRot180();
analogReference(INTERNAL);
pinMode(2,INPUT_PULLUP);
pinMode(3,INPUT_PULLUP);
attachInterrupt(0, ISR_SW_RED,FALLING);
attachInterrupt(1, ISR_SW_BLACK,FALLING);
pinMode(5,OUTPUT);
digitalWrite(5,LOW);
pinMode(4,OUTPUT);
digitalWrite(4,LOW);
}

void loop(void)
{

while(!rbc)
{
// show timer set menu
u8g.firstPage();
do {
draw_menu();
} while( u8g.nextPage() );

// show user proper operation message


if (rbc>0 && bbc==0)
{
u8g.firstPage();
do {
draw_message();
} while( u8g.nextPage() );
delay(2000);
rbc=0; //u8g.clear();
}
}

// start timer
if(rbc>0)
{
sec =59;
mi = bbc-1;

while(mi>=0)
{
// show countdown timer message
unsigned long temp = millis()+1000;
while(temp>=millis())
{
u8g.firstPage();
do {
draw_timer();
} while( u8g.nextPage() );
}

sec=sec-1;
if(sec%5==0)
{
control_motor(); // call every 5 sec
}
if (sec <= 0)
{
sec = 59;
mi = mi - 1;
}
}
rbc = 0; bbc = 0;
mi = 0 ; sec = 0;
digitalWrite(5,LOW);digitalWrite(6,LOW);
}
}// end of loop

void draw_menu(void)
{
u8g.setFont(u8g_font_timB24);
if (bbc<10)
{
u8g.drawStr( 22,30,"0");
u8g.setPrintPos(38,30);u8g.print(bbc);
}
else
{
u8g.setPrintPos(22,30);u8g.print(bbc);
}
u8g.drawStr( 54,30,":00");
u8g.setFont(u8g_font_8x13);
u8g.drawStr( 0,62," 'WASHING TIMER'");

u8g.setFont(u8g_font_5x8);
u8g.drawStr( 0,47,"Red:START Black:SET TIME");
}

void draw_message(void)
{
u8g.setFont(u8g_font_8x13);
u8g.drawStr( 0,10," SET WASH TIMER");
u8g.drawStr( 0,23,"FIRST BY PUSHING");
u8g.drawStr( 0,36,"THE BLACK BUTTON");
// u8g.setFont(u8g_font_8x13);
u8g.drawStr( 0,62," 'WASHING TIMER'");

u8g.setFont(u8g_font_5x8);
u8g.drawStr( 0,47,"Red:START Black:SET TIME");

void draw_timer(void)
{

u8g.setFont(u8g_font_timB24);
if (mi<10)
{
u8g.drawStr( 22,30,"0");
u8g.setPrintPos(38,30);u8g.print(mi);
}
else
{
u8g.setPrintPos(22,30);u8g.print(mi);
}

u8g.drawStr( 54,30,":");

if (sec<10)
{
u8g.drawStr( 70,30,"0");
u8g.setPrintPos(86,30);u8g.print(sec);
}
else
{
u8g.setPrintPos(70,30);u8g.print(sec);
}
if(motor_rotation==0)
{
u8g.setFont(u8g_font_5x8);
u8g.drawStr( 0,47," WASHING MOTOR CW Spin");
digitalWrite(5,HIGH);
}

if(motor_rotation==1)
{
u8g.setFont(u8g_font_5x8);
u8g.drawStr( 0,47," WASHING MOTOR STOPPED ");
digitalWrite(5,LOW);digitalWrite(4,LOW);
}

if(motor_rotation==2)
{
u8g.setFont(u8g_font_5x8);
u8g.drawStr( 0,47," WASHING MOTOR CCW Spin");
digitalWrite(4,HIGH);

}
if(motor_rotation==3)
{
u8g.setFont(u8g_font_5x8);
u8g.drawStr( 0,47," WASHING MOTOR STOPPED ");
digitalWrite(5,LOW);digitalWrite(4,LOW);

u8g.setFont(u8g_font_8x13);
u8g.drawStr( 0,62," 'WASHING TIMER'");

void ISR_SW_RED()
{
sei();
rbc++;
cli();
}

void ISR_SW_BLACK()
{
sei();
bbc++;
cli();
}

void control_motor()
{
motor_rotation++;
if(motor_rotation>3)
{
motor_rotation = 0;
}
}

58) Arduino IoT IR Programmable Transcoder TV


Remote on Steroids
COMPONENTS AND SUPPLIES

Arduino Nano R3
× 1

General Purpose Transistor


NPN
× 1
Generic IR LED (940nm) × 2

IR receiver (generic)
× 2

Generic RGB LED


× 1

Resistor 330 ohm


× 4

Espressif Wemos D1 Mini


× 1

NodeMCU ESP8266 Breakout


Board
× 1

Espressif ESP8266 ESP-12E


× 1

resistor 470 Ohm


× 3
Plastic Enclosure (clear lid) × 1

Veroboard
× 1

USB-A to Micro-USB Cable


× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

You when something annoys you so much you just


have to fix it especially if every one else nags you.
Our television remote falls in this category, its a "Dick
Smith" brand unit and has a dodgy intermittent
remote. I've used universal remotes before and even
after hours of programming them they are not so flash.
So what to do? Our Panasonic DVR we use has a more
than adequate universal section built in but in spite of
talking to 100s of other devices our TV is not one of
them. If only it spoke the lingo!
Arduino IR library and Nano on the job
Did you know with a couple of parts you can receive,
analyse and send IR codes with even the smallest
Arduino? So with not much more than the example
sketch you can work out what codes in what protocol
gets sent from your remote for each button. With a
couple more lines of code you can send another code
that you would like substituted for the the first code.
So in no time at all you have built yourself a
transcoder. Receives codes of one remote and re-
transmits them as if from another. "Piece of Pi" or
maybe Arduino? I even put in the start of an overlay
function so I can use all of the remote buttons for the
TV if the original device is off, I used a RGB LED
indicator to show when your in that mode to avoid
user confusion.
Anyhow, all that is left now is to give the remote to
family members to test and suggest while you watch
for bugs.
The circuit
Very simple, due to the IR receiver doing a lot of the
heavy lifting. It has the automatic gain control and
many other items needed to successfully demodulate
the 38 kHz signal that is passed to the Arduino. There
is no current limmit resistor on the two IR LEDs. I
was expecting scorch marks on the couch while testing
but it seems to work fine at 5V with the LEDs I
bought. Trying this was a response to what seemed a
pathetic range at 20 ma, "More power Igor !"
Beta testing, note the recycled mobile phone charger
as a power source
You can see the proof of concept test unit with the
breadboard to the left of our TV. The Arduino Nano is
mounted on a prototype shield to the right. These
prototype shields are neat as no toolkit should be
without one!
Not all beer and Skittles
There are some subtle things at play in the project and
its all in the timing of the reception and transmission
of the new code. but as always "Professor Google" has
most of the answers that you seek.
Worthwhile?
Definitely, I only need one remote which I didn't have
to buy. I can change functionality (Include some
macros) if I wish. Most importantly I learned a lot
about IR remote controls.
But wait there's more... ESP to the rescue!
All the parts for the final build sat on my bench for 12
months, assigned to the back burner after some
success with a soldering iron and the actual TV
remote. In the mean time I learned about the ESP8266.
So when it can to put the unit in a box I thought why
not make it run on a NodeMCU board. So with that
thought in mind the final chapter and build was
started.

The IR transceiver assembly and status LED


Fitting all the bits in the wee box

The finished unit minus a few wires


Other side showing ESP8266 and all the LED's
and IR receiver.
So the software was rearranged and refactored to suit
the new and better IR library for the ESP8266. The tri-
color LED was used as follows. Red flash for IR
transmit, Blue flash for WiFi Receive and Green flash
for IR receive. The Blue LED also flashes fast during
the boot phase as it attempts to login to the WiFi. The
built in LED is used as a confidence meter / heart beat.
The unit has both soft AP and WiFi client, This makes
configuration easier as there is always a configuration
port available.
The remote control page uses some in-line CSS in the
web response to set the style of the form buttons
which form the basis of the remote control page. The
page works nicely on mobile phones due to the
"viewport" command which helps the phone get a
better "perspective" on how it should display the
content. These represent a departure from my usual
web M.O but I am trying to "up skill" a bit.
But wait... how could I build a remote control that has
WiFi with making it programmable via the WiFi and
IR port. So a new web page and interface was
designed so I could capture an IR code and assign it to
a button in the control matrix. In fact you can
reprogram it all via this interface. There is a factory
reset to return it to the original state if you completely
loose your way.

Unit positioned just below the IR receiver on the TV


Final assembled and working unit
Actually I found the virtual remote on a mobile web
page much handier than just a gimmick. Every
member of the family has some sort of device and can
now operate the TV even if the remote has scurried
away into the deepest recesses of the sofa.
TV remote as viewed from my phone
Bottom part of the screen... Pop ups be the digital
equivalent of fingers on the lens
Top of code setup page

Bottom of code setup Page


Hmmm.... works well but could be better. I found
myself wanting more devices on the virtual remote.
There be enough EEPROM memory so lets Implement
3 pages of 48 buttons (4 x 12). This doesn't really
impact the rest of the code and really just increases the
lookup table for the transcode function. So that will no
doubt be the next improvement..
Something Like this maybe ?
Strangely enough the wee transcoder box helped shine
some light on our troublesome TV remote. I was under
the impression it wasn't transmitting at all. However I
noticed the green light flashing (code received) but the
TV not responding. So what curiosity led me to the
setup page where I discovered the remote was sending
the wrong codes! No wonder the TV doesn't respond,
but armed with knowledge a fix may me close at hand.
SCHEMATICS
CODE
// Include the IRremote library header
//
#include <IRremote.h>

#define DECODE_NEC 1
#define TVONOFF 0xFB38C7
#define TVAV 0xFBE817 // signal source
#define TVVOLUP 0xFBD22D
#define TVVOLDN 0xFBF20D
#define TVCHUP 0xFB906F
#define TVCHDN 0xFBA05F
#define TV1PAD 0xFB2AD5
#define TV2PAD 0xFB6897
#define TV3PAD 0xFBA857
#define TV4PAD 0xFB0AF5
#define TV5PAD 0xFB48B7
#define TV6PAD 0xFB8877
#define TV7PAD 0xFB32CD
#define TV8PAD 0xFB708F
#define TV9PAD 0xFBB04F
#define TV0PAD 0xFB30CF
#define TVLNAV 0xFBE21D
#define TVRNAV 0xFBE01F
#define TVUNAV 0xFB58A7
#define TVDNAV 0xFB12ED
#define TVOKNAV 0xFB609F
#define TVAPMENU 0xFB18E7
#define TVEXITNAV 0xFB50AF
#define TVMUTE 0xFB10EF
#define TVPLAY 0xFB5AA5
#define TVPAUSE 0xFB4AB5
#define TVSTOP 0xFBBA45
#define TVWTF 0xFB3AC5
#define TVREW 0xFBAA55
#define TVFF 0xFB7A85
#define TVPREV 0xFB8A75
#define TVNEXT 0xFB9A65
#define TVTEXT 0xFB9A65
#define TVSUBTTL 0xFBFA05
#define TVFREEZE 0xFB9867
#define TVINFO 0xFB1AE5
#define TVRED 0xFB6A95
#define TVGREEN 0xFBEA15
#define TVYELLOW 0xFBF807
#define TVBLUE 0xFBDA25

IRsend irsend;
long PrevCode;
int iMode = 0;
bool bTransmit=false;
bool bRepeat=false;
//-------------------------------------------------------------------
-----------
// Tell IRremote which Arduino pin is connected to the
IR Receiver (TSOP4838)
//
int recvPin = 11;
IRrecv irrecv(recvPin);

//+======================================
=======================================
// Configure the Arduino
//
void setup ( )
{
Serial.begin(115200); // Status message will be sent to
PC at 9600 baud
Serial.println("Start");
pinMode(3,OUTPUT); // IR LED
pinMode(4,OUTPUT); // RGB LED FOR MODE
INDICATOR
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
irrecv.enableIRIn(); // Start the receiver
irrecv.blink13(1);
}

//+======================================
=======================================
// Display IR code
//
void ircode (decode_results *results)
{
// Panasonic has an Address
if (results->decode_type == PANASONIC) {
Serial.print(results->address, HEX);
Serial.print(":");
}

// Print Code
Serial.print(results->value, HEX);
}

//+======================================
=======================================
// Display encoding type
//
void encoding (decode_results *results)
{
switch (results->decode_type) {
default:
case UNKNOWN: Serial.print("UNKNOWN");
break ;
case NEC: Serial.print("NEC"); break ;
case SONY: Serial.print("SONY"); break ;
case RC5: Serial.print("RC5"); break ;
case RC6: Serial.print("RC6"); break ;
case DISH: Serial.print("DISH"); break ;
case SHARP: Serial.print("SHARP"); break ;
case JVC: Serial.print("JVC"); break ;
case SANYO: Serial.print("SANYO"); break ;
case MITSUBISHI: Serial.print("MITSUBISHI");
break ;
case SAMSUNG: Serial.print("SAMSUNG");
break ;
case LG: Serial.print("LG"); break ;
case WHYNTER: Serial.print("WHYNTER");
break ;
case AIWA_RC_T501:
Serial.print("AIWA_RC_T501"); break ;
case PANASONIC: Serial.print("PANASONIC");
break ;
case DENON: Serial.print("Denon"); break ;
}
}

//+======================================
=======================================
// Dump out the decode_results structure.
//
void dumpInfo (decode_results *results)
{
// Check if the buffer overflowed
if (results->overflow) {
Serial.println("IR code too long. Edit IRremoteInt.h and
increase RAWLEN");
return;
}

// Show Encoding standard


Serial.print("Encoding : ");
encoding(results);
Serial.println("");
// Show Code & length
Serial.print("Code : ");
ircode(results);
Serial.print(" (");
Serial.print(results->bits, DEC);
Serial.println(" bits)");
}

//+======================================
=======================================
// Dump out the decode_results structure.
//
void dumpRaw (decode_results *results)
{
// Print Raw data
Serial.print("Timing[");
Serial.print(results->rawlen-1, DEC);
Serial.println("]: ");

for (int i = 1; i < results->rawlen; i++) {


unsigned long x = results->rawbuf[i] *
USECPERTICK;
if (!(i & 1)) { // even
Serial.print("-");
if (x < 1000) Serial.print(" ") ;
if (x < 100) Serial.print(" ") ;
Serial.print(x, DEC);
} else { // odd
Serial.print(" ");
Serial.print("+");
if (x < 1000) Serial.print(" ") ;
if (x < 100) Serial.print(" ") ;
Serial.print(x, DEC);
if (i < results->rawlen-1) Serial.print(", "); //',' not
needed for last one
}
if (!(i % 8)) Serial.println("");
}
Serial.println(""); // Newline
}

//+======================================
=======================================
// Dump out the decode_results structure.
//
void dumpCode (decode_results *results)
{
// Start declaration
Serial.print("unsigned int "); // variable type
Serial.print("rawData["); // array name
Serial.print(results->rawlen - 1, DEC); // array size
Serial.print("] = {"); // Start declaration

// Dump data
for (int i = 1; i < results->rawlen; i++) {
Serial.print(results->rawbuf[i] * USECPERTICK, DEC);
if ( i < results->rawlen-1 ) Serial.print(","); // ',' not
needed on last one
if (!(i & 1)) Serial.print(" ");
}

// End declaration
Serial.print("};"); //

// Comment
Serial.print(" // ");
encoding(results);
Serial.print(" ");
ircode(results);

// Newline
Serial.println("");

// Now dump "known" codes


if (results->decode_type != UNKNOWN) {

// Some protocols have an address


if (results->decode_type == PANASONIC) {
Serial.print("unsigned int addr = 0x");
Serial.print(results->address, HEX);
Serial.println(";");
}

// All protocols have data


Serial.print("unsigned int data = 0x");
Serial.print(results->value, HEX);
Serial.println(";");
}
}
//+======================================
=======================================
// The repeating section of the code
//
void loop ( )
{
decode_results results; // Somewhere to store the
results

if (irrecv.decode(&results)) { // Grab an IR code


dumpInfo(&results); // Output the results
dumpRaw(&results); // Output the results in RAW
format
dumpCode(&results); // Output the results as
source code
Serial.println(""); // Blank line between entries

// Serial.println(iMode);
Serial.print("R ");
Serial.println(results.value, HEX);

bTransmit = false ;
switch(results.value){
case 0x18E710EF: // TV on off
PrevCode = TVONOFF ;
bTransmit = true ;
bRepeat = false ;
iMode = 0 ;
break;
case 0x18E750AF: // AV
PrevCode = TVAV ;
bTransmit = true ;
bRepeat = false ;
iMode = 0 ;
break;
case 0x18E740BF: // VOL +
PrevCode = TVVOLUP ;
bTransmit = true ;
bRepeat = true ;
iMode = 0 ;
break;
case 0x18E7C03F: // VOL -
PrevCode = TVVOLDN ;
bTransmit = true ;
bRepeat = true ;
iMode = 0 ;
break;
case 0x18E700FF: // CH +
PrevCode = TVCHUP ;
bTransmit = true ;
bRepeat = false ;
iMode = 0 ;
break;
case 0x18E7807F: // CH-
PrevCode = TVCHDN ;
bTransmit = true ;
bRepeat = false ;
iMode = 0 ;
break;
case 0xFFFFFFFF: // repeat code
if ( bRepeat == true ){
bTransmit = true ;
}
break;

case 0xD880287: // blue button


if ( iMode != 1 ){
iMode = 1;
}else{
iMode = 0;
}
bRepeat = false ;
break;
case 0xD88C247: // yellow button
PrevCode = TVMUTE ;
bTransmit = true ;
bRepeat = false ;
iMode = 0 ;
break;
case 0xD8842C7: // green button
if ( iMode != 3 ){
iMode = 2;
}else{
iMode = 0;
}
bRepeat = false ;
break;
case 0xD888207: // red button
if ( iMode != 4 ){
iMode = 3;
}else{
iMode = 0;
}
bRepeat = false ;
break;
case 0xD08E1E4: // left nav
if ( iMode == 1 ){
PrevCode = TVLNAV ;
bTransmit = true ;
bRepeat = false ;
}
break;
case 0xD081114: // right nav
if ( iMode == 1 ){
PrevCode = TVRNAV ;
bTransmit = true ;
bRepeat = false ;
}
break;
case 0xD086164: // down nav
if ( iMode == 1 ){
PrevCode = TVDNAV ;
bTransmit = true ;
bRepeat = false ;
}
break;
case 0xD08A1A4: // up nav
if ( iMode == 1 ){
PrevCode = TVUNAV ;
bTransmit = true ;
bRepeat = false ;
}
break;
case 0xD084144: // ok nav
if ( iMode == 1 ){
PrevCode = TVOKNAV ;
bTransmit = true ;
bRepeat = false ;
}
break;
case 0xD888A0F: // exit nav
if ( iMode == 1 ){
PrevCode = TVEXITNAV ;
bTransmit = true ;
bRepeat = false ;
}
break;
case 0xD086663: // status nav
bRepeat = false ;
break;
case 0xD088184: // return nav
bRepeat = false ;
break;
case 0xD08080D: // 1 nav pad
if ( iMode == 1 ){
PrevCode = TV1PAD ;
bTransmit = true ;
bRepeat = false ;
}
break;
case 0xD08888D: // 2 nav pad
if ( iMode == 1 ){
PrevCode = TV2PAD ;
bTransmit = true ;
bRepeat = false ;
}
break;
case 0xD08484D: // 3 nav pad
if ( iMode == 1 ){
PrevCode = TV3PAD ;
bTransmit = true ;
bRepeat = false ;
}
break;
case 0xD08C8CD: // 4 nav pad
if ( iMode == 1 ){
PrevCode = TV4PAD ;
bTransmit = true ;
bRepeat = false ;
}
break;
case 0xD08282D: // 5 nav pad
if ( iMode == 1 ){
PrevCode = TV5PAD ;
bTransmit = true ;
bRepeat = false ;
}
break;
case 0xD08A8AD: // 6 nav pad
if ( iMode == 1 ){
PrevCode = TV6PAD ;
bTransmit = true ;
bRepeat = false ;
}
break;
case 0xD08686D: // 7 nav pad
if ( iMode == 1 ){
PrevCode = TV7PAD ;
bTransmit = true ;
bRepeat = false ;
}
break;
case 0xD08E8ED: // 8 nav pad
if ( iMode == 1 ){
PrevCode = TV8PAD ;
bTransmit = true ;
bRepeat = false ;
}
break;
case 0xD08181D: // 9 nav pad
if ( iMode == 1 ){
PrevCode = TV9PAD ;
bTransmit = true ;
bRepeat = false ;
}
break;
case 0xD08989D: // 0 nav pad
if ( iMode == 1 ){
PrevCode = TV0PAD ;
bTransmit = true ;
bRepeat = false ;
}
break;
default:
bTransmit = false ;
bRepeat = false ;
break;
}
if ( bTransmit ){
Serial.print("T ");
Serial.println(PrevCode, HEX);
irsend.sendNEC(PrevCode,32);
bTransmit = false ;
}
delay(50);
irrecv.resume(); // Prepare for the next value
irrecv.enableIRIn(); // Start the receiver
irrecv.blink13(1);
}

59) Arduino Weather Wand


COMPONENTS AND SUPPLIES
SparkFun Arduino Pro Mini 328
- 3.3V/8MHz
× 1

TMP36 sensor
× 1

NeoPixel RGB LED


× 1

100 Ohm resistor (Green and × 2


Blue channel)

150 Ohm resistor (red channel)


× 1

110mah 3.7v lipo battery


× 1

ABOUT THIS PROJECT


The wondrous magical weather wand casts an
enchanting spell of light. Away to make the invisible
visible.
In less magical terms, I have an Arduino pro mini with a
temperature sensor (currently a TMP36) and a RGB
LED. The Arduino checks temperatures and sets the
color of the light based on the temperature.
The early version of this used a temp to color table (like
the temperature map project) that would for example set
to the light yellow if above 70º or to blue if below 30º.
However it would be pretty unlikely to encounter that
wide of a temperature range within a space so instead of
re-tuning the table for every location I wanted to have it
set it's own range.
The solution was to use statistics! It takes and averages
the temperatures it sees and sets the color to normal
(green) based on that average. The standard deviation (ie
max/min range) is set based on the variation the sensor
picks up. The color changes based not on a specific temp
value but the number of standard deviations from that
average. ie: 2+ stddev is red -2 stddev is purple, etc.
Testing the temperature variations around the room
Making of
Breadboard prototype with the v2 being built.

Resistor pack for the LED


working prototype
TMP36 and RGB LED at the tip
Future plans:
Would like to make a nice magic wand case, maybe fimo
clay or something.
Experimenting with timing and other sensors to get a
faster response rate and better sensitivity to change.
Might work on gradients between values instead of
'click-stops' for color change values.
Add a small capacitor to the TMP36 power input to
stabilize it. (Currently stabilizing in code and it is
slowing response times)
Quicky breadboard version of the NeoPixel weather
wand
SCHEMATICS

Wiring for RGB LED use

Wiring for NeoPixel use


1000uF cap on pixel power, 3-500 ohm resistor on
data, also added a .1uF cap to stabilize the TMP36
CODE

wx_wand_1.txtC/C++

/*
The Weather Wand!
A small wand that lights up at the tip based on if it is hot
or cold.
Hot and cold are determined by the standard deviation
from the average of the 50 most recent temperature
samples.
Hardware: An Arduino pro mini with a TMP36 temp
sensor and an common cathode RGB LED.

*/

//________________Setup________________________

int DEBUG = 1; // DEBUG counter; if set to 1, will


write values back via serial

// Init the Pins used for PWM


const int redPin = 3;
const int greenPin = 5;
const int bluePin = 6;

//Temp sensor stuff


int sensorPin = 0; //TMP36
float tempF;
float tempC;

// Vars for the color output


int redVal = 0;
int grnVal = 0;
int bluVal = 0;

//delay var
int del = 100;

//statistics
int max_samples = 50;
int temperature_samples[50];
int n_temperature_samples = 0;
int i_temperature_samples = 0;
float stddev_temperature = 5;
float avg_temperature = 50;
float tempF_recent = 0;

//________________Run
Time________________________

void setup()
{
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
if (DEBUG) { // If we want to see values for
debugging...
Serial.begin(9600); // ...set up the serial ouput
Serial.println("Starting");
}
}

void loop()
{
getTemp();

temperature_samples[i_temperature_samples] = tempF;
i_temperature_samples++;
if (n_temperature_samples < max_samples) {
n_temperature_samples++;
}
if (i_temperature_samples >= max_samples) {
i_temperature_samples = 0;
}

computeStdDev();
tempColor();

delay(del);
}

// ---------------- Function Fun --------------------

void getTemp()
{
//getting the voltage reading from the temperature sensor
int reading = analogRead(sensorPin);

// converting that reading to voltage, for 3.3v arduino use


3.3, for 5v use 5
float voltage = reading * 3.3;
voltage /= 1024.0;

// now kick out the temperature


tempC = (voltage - 0.5) * 100 ; //converting from 10 mv
per degree with 500 mV offset
//to degrees ((voltage - 500mV) times 100)
// Convert to Fahrenheit
tempF = (tempC * 9.0 / 5.0) + 32.0;

if (DEBUG) // If we want to print it all to console...


{
Serial.println("++++++++++++++");
Serial.print(voltage); Serial.println(" volts");
Serial.print(tempC); Serial.println(" degrees C");
Serial.print(tempF); Serial.println(" degrees F");
Serial.print(tempF_recent); Serial.println(" degrees F
(recent)");

Serial.println("--------------");
}

void computeStdDev() {
int i;
avg_temperature = 0;
for (i = 0; i < n_temperature_samples; i++){
avg_temperature = avg_temperature +
temperature_samples[i];
}
avg_temperature = avg_temperature /
n_temperature_samples;

stddev_temperature = 0;
for (i = 0; i < n_temperature_samples; i++){
stddev_temperature = stddev_temperature +
(temperature_samples[i] - avg_temperature) *
(temperature_samples[i] - avg_temperature);
}

stddev_temperature = stddev_temperature /
n_temperature_samples;
stddev_temperature = sqrt(stddev_temperature);

int start_i = i_temperature_samples - 5;


if (start_i < 0) {
start_i = 0;
}

if (i_temperature_samples - start_i > 0){

tempF_recent = 0;
for (i = start_i; i < i_temperature_samples; i++) {
tempF_recent = tempF_recent + temperature_samples[i];
}
tempF_recent /= (i_temperature_samples - start_i);

} else {
tempF_recent = tempF;
}

if (DEBUG) // If we want to print it all to console...


{
Serial.print("n_temperature_samples: ");
Serial.println(n_temperature_samples);
Serial.print("avg_temperature: ");
Serial.println(avg_temperature);
Serial.print("temperature: ");
Serial.println(tempF);
Serial.print("i: ");
Serial.println(i_temperature_samples);
Serial.print("stddev_temperature: ");
Serial.println(stddev_temperature);
}
}

//Set the RGB color based on standard deviation distance


from average temp
void tempColor()
{
float diff = (tempF_recent - avg_temperature) /
stddev_temperature;

if(diff < -2.5) {


setColor(255, 0, 255);
} else if (diff < -2.0) {
setColor(0, 100, 255);
} else if (diff < -1.5) {
setColor(0, 157, 200);
} else if (diff < -1.0) {
setColor(150, 206, 150);
} else if (diff < -0.5) {
setColor(0, 200, 50);
} else if (diff < 0.0) {
setColor(0, 255, 1);
} else if (diff < 0.5) {
setColor(150, 255, 0);
} else if (diff< 1.0) {
setColor(200, 200, 0);
} else if (diff < 1.5) {
setColor(255, 100, 0);
} else if (diff < 2.0) {
setColor(255, 10, 0);
} else {
setColor(100, 100, 100); //out of scope color
}

if (DEBUG) // Standard deviation visualizer


{
Serial.print("diff: ");
Serial.println(diff);

if(diff < -2.5) {


Serial.println("X----0+++++");
} else if (diff < -2.0) {
Serial.println("-X---0+++++");
} else if (diff < -1.5) {
Serial.println("--X--0+++++");
} else if (diff < -1.0) {
Serial.println("---X-0+++++");
} else if (diff < -0.5) {
Serial.println("----X0+++++");
} else if (diff < 0.0) {
Serial.println("-----0+++++");
} else if (diff < 0.5) {
Serial.println("-----0X++++");
} else if (diff< 1.0) {
Serial.println("-----0+X+++");
} else if (diff < 1.5) {
Serial.println("-----0++X++");
} else if (diff < 2.0) {
Serial.println("-----0+++X+");
} else {
Serial.println("X----0++++X");
}
}
}

//Send the RGB value to the color pins


void setColor(int r, int g, int b) //0-255 input
{
// plug it in
int redVal = r;
int grnVal = g;
int bluVal = b;

analogWrite(redPin, redVal); // Write current values to


LED pins
analogWrite(greenPin, grnVal);
analogWrite(bluePin, bluVal);

if (DEBUG) // If we want to print it all to console...


{
Serial.print(redVal); Serial.print(" R ");
Serial.print(grnVal); Serial.print(" G ");
Serial.print(bluVal); Serial.println(" B ");
Serial.println("--------------");
}
}

file_15302.txtC/C++

/*
The Weather Wand!
A small wand that lights Neo Pixels (addressable RGB
LEDs) at the tip in response to temperature .
Hot and cold are determined by the standard deviation
from the average of the 50 most recent temperature
samples.
Hardware: An Arduino pro mini with a TMP36 temp
sensor and addressable RGB LEDs.
NeoPixel library from Adafruit

*/

//________________Setup________________________

int DEBUG = 1; // DEBUG counter; if set to 1, will


write values back via serial

// NeoPixel setup
#include <Adafruit_NeoPixel.h>
#define PIN 6

// Parameter 1 = number of pixels in strip


// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel
products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2)
FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream
(most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1
FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(12, PIN,
NEO_GRB + NEO_KHZ800);

// IMPORTANT: To reduce NeoPixel burnout risk, add


1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first
pixel's data input
// and minimize distance between Arduino and first
pixel. Avoid connecting
// on a live circuit...if you must, connect GND first.

//Temp sensor setup


int sensorPin = 0; //TMP36
float tempF;
float tempC;
//delay var
int del = 80;

//statistics
int max_samples = 50;
int temperature_samples[50];
int n_temperature_samples = 0;
int i_temperature_samples = 0;
float stddev_temperature = 5;
float avg_temperature = 50;
float tempF_recent = 0;

//________________Run
Time________________________

void setup()
{
strip.begin();
strip.show(); // Initialize all pixels to 'off'
strip.setBrightness(50); // Turn down for what 0-255
if (DEBUG) { // If we want to see values for
debugging...
Serial.begin(9600); // ...set up the serial ouput
Serial.println("Starting");
}
}

void loop()
{
getTemp();

temperature_samples[i_temperature_samples] = tempF;
i_temperature_samples++;
if (n_temperature_samples < max_samples) {
n_temperature_samples++;
}
if (i_temperature_samples >= max_samples) {
i_temperature_samples = 0;
}

computeStdDev();

tempColor();
delay(del);
}

// ---------------- Function Fun --------------------

void getTemp()
{
//getting the voltage reading from the temperature sensor
int reading = analogRead(sensorPin);

// converting that reading to voltage, for 3.3v arduino use


3.3, for 5v use 5
float voltage = reading * 3.3;
voltage /= 1024.0;

// now kick out the temperature


tempC = (voltage - 0.5) * 100 ; //converting from 10 mv
per degree with 500 mV offset
//to degrees ((voltage - 500mV) times 100)

// Convert to Fahrenheit
tempF = (tempC * 9.0 / 5.0) + 32.0;

if (DEBUG) // If we want to print it all to console...


{
Serial.println("++++++++++++++");
Serial.print(voltage); Serial.println(" volts");
Serial.print(tempC); Serial.println(" degrees C");
Serial.print(tempF); Serial.println(" degrees F");
Serial.print(tempF_recent); Serial.println(" degrees F
(recent)");
Serial.println("--------------");
}

}//end

void computeStdDev() {
int i;
avg_temperature = 0;

for (i = 0; i < n_temperature_samples; i++){


avg_temperature = avg_temperature +
temperature_samples[i];
}
avg_temperature = avg_temperature /
n_temperature_samples;

stddev_temperature = 0;
for (i = 0; i < n_temperature_samples; i++){
stddev_temperature = stddev_temperature +
(temperature_samples[i] - avg_temperature) *
(temperature_samples[i] - avg_temperature);
}

stddev_temperature = stddev_temperature /
n_temperature_samples;
stddev_temperature = sqrt(stddev_temperature);

int start_i = i_temperature_samples - 5;


if (start_i < 0) {
start_i = 0;
}

if (i_temperature_samples - start_i > 0){

tempF_recent = 0;
for (i = start_i; i < i_temperature_samples; i++) {
tempF_recent = tempF_recent + temperature_samples[i];
}
tempF_recent /= (i_temperature_samples - start_i);

} else {
tempF_recent = tempF;
}

if (DEBUG) // If we want to print it all to console...


{
Serial.print("n_temperature_samples: ");
Serial.println(n_temperature_samples);
Serial.print("avg_temperature: ");
Serial.println(avg_temperature);
Serial.print("temperature: ");
Serial.println(tempF);
Serial.print("i: ");
Serial.println(i_temperature_samples);
Serial.print("stddev_temperature: ");
Serial.println(stddev_temperature);
}
}//end

//Set the RGB color based on standard deviation distance


from average temp
void tempColor()
{
float diff = (tempF_recent - avg_temperature) /
stddev_temperature;

if(diff < -2.5) {


setColor(strip.Color(255, 0, 255));
} else if (diff < -2.0) {
setColor(strip.Color(0, 100, 255));
} else if (diff < -1.5) {
setColor(strip.Color(0, 157, 200));
} else if (diff < -1.0) {
setColor(strip.Color(150, 206, 150));
} else if (diff < -0.5) {
setColor(strip.Color(0, 230, 50));
} else if (diff < 0.0) { // 0 = Avg
setColor(strip.Color(0, 255, 1));
} else if (diff < 0.5) {
setColor(strip.Color(50, 230, 0));
} else if (diff< 1.0) {
setColor(strip.Color(200, 200, 0));
} else if (diff < 1.5) {
setColor(strip.Color(255, 100, 0));
} else if (diff < 2.0) {
setColor(strip.Color(255, 50, 0));
} else {
setColor(strip.Color(255, 0, 0)); //max out color
}

if (DEBUG) // Standard deviation visualizer


{
Serial.print("diff: ");
Serial.println(diff);

if(diff < -2.5) {


Serial.println("X----0+++++");
} else if (diff < -2.0) {
Serial.println("-X---0+++++");
} else if (diff < -1.5) {
Serial.println("--X--0+++++");
} else if (diff < -1.0) {
Serial.println("---X-0+++++");
} else if (diff < -0.5) {
Serial.println("----X0+++++");
} else if (diff < 0.0) {
Serial.println("-----0+++++");
} else if (diff < 0.5) {
Serial.println("-----0X++++");
} else if (diff< 1.0) {
Serial.println("-----0+X+++");
} else if (diff < 1.5) {
Serial.println("-----0++X++");
} else if (diff < 2.0) {
Serial.println("-----0+++X+");
} else {
Serial.println("X----0++++X");
}
}
} //end

//Send the RGB value to the pixels


void setColor(uint32_t c) {
for(uint16_t i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
}
} //end

60) Arduino Air Meter Making


COMPONENTS AND SUPPLIES

Arduino UNO & Genuino UNO


× 1

DHT11 Temperature &


Humidity Sensor (3 pins)
× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT


I learned to use the WiFi module last time. This time
we will look at the most important temperature and
humidity sensors in this project.
Step 01
A dedicated library is required to use the DHT 11
module. Download the file below.
File
01 http://deneb21.tistory.com/attachment/cfile24.uf@2
20A6C3755DA9E322E7FED.zip
Once you have downloaded the file, load DHT 11
from the library.
If the file is successfully loaded, the following screen
appears.
Step 02
Now let's look at temperature and humidity with DHT
11 module.
Once you have entered the code and clicked Upload,
you can see the temperature and humidity by checking
the serial monitor.
Now we know how to use the DHT 11 module!
Next time, I will work on sending the temperature and
humidity data to the server using ESP-01 module and
DHT 11 module learned earlier.

SCHEMATICS
CODE

#include <DHT11.h> //Load library


int pin=2; //Pin number of the signal
DHT11 dht11(pin);
void setup()
{
Serial.begin(9600); //Communication speed setting
}

void loop()
{
int err;
float temp, humi;
if((err=dht11.read(humi, temp))==0) //Read temperature, humidity read
{
Serial.print("temperature:");
Serial.print(temp);
Serial.print(" humidity:");
Serial.print(humi);
Serial.println();
}
else //Processing in case of error
{
Serial.println();
Serial.print("Error No :");
Serial.print(err);
Serial.println();
}
delay(1000); //Repeat every second
}
61) Arduino Kayak GPS Navigation

COMPONENTS AND SUPPLIES


Arduino Nano R3 × 1
TinyCircuits TinyShield GPS
× 1

TinyCircuits TinyDuino Starter


Kit – Lithium Version
× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT


Latitude and Longitude
Solar Panel
Speed, Odomètre and Time
Speed, Azimut, Time, Tide Clock
Latitude and Longitude

I make this GPS for my kayak. I want to be


sufficiently robust to permanently attached to it (sea
condition) and can be run forever for long sea kayak
excursions.
-GPS is powered only by solar energy and can run 1-2
days without sun if need with a integrate lithium-ion
battery (if the battery is full).
-Screen can be read in the sunlight or night with back
light LED. On sunlight the back light LED is turns
OFF for reduce the consumption.
-Waterproof, epoxy sealed .
-Tide clock base on moon rotation 12 heures 25
minutes and 14 secondes. hours until low or high tide
are display has a count-down of hours from 5 to 1
-The GPS doesn't have integrate map and should be
use in conjunction with paper map for route planning
or can simply use for to see speed, time and odometer
as a dashboard.
-GPS Info available: Time, Latitude and Longitude,
Speed, Tide Clock, Azimuth compass rose, Azimuth
Returns/distance and Odometer,
-Pro mode display; Display Speed, Time,
Azimuth/compass rose , and alternatively
Azimuth/distance, Tide clock and Odometer
-Dashboard mode display; Big character speed,
odometer, time.
-controlled by 4 push buttons (select, Up, Down and
Power ON)
-the power on / off are controlled by the MCU and the
MCU can turn off if the battery voltage is too low
(battery protection).
-low energy mode, the GPS module is put in sleeping
mode for 10 sec and Hot Start to get data and back on
Sleeping Mode...
Next generation will use Arduino Nano pro, GPS
module and LCD display at 3.3 volts, more efficient
with 3.7 battery. Controlled by tree push buttons
(select/PowerON, Up and Down) , It will be smaller.
better box design, new option Navigation flashing
light (Red and Green). may be a integrate a buzzer for
alarm clock. temperature info.

SCHEMATICS
CODE

/*
*/

#include <SoftwareSerial.h>
#include <TinyGPS.h>
#include <LiquidCrystal.h>
#include <EEPROM.h>

#include <avr/pgmspace.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); //8>RS,9>E, 4-7>D4-D7,RW>0V,
SoftwareSerial gpsSerial(2, 3); //RX, TX 2>bleuTX, 3>VertRX
TinyGPS gps;

byte clo_n = 0;
boolean eco_mode = false;
boolean pro_mode = false;
static int vref = 211; // 1023/4.9 volts
byte solPanel = 3; //pin
byte batt = 4; //pin
byte LCD_LED = 11;
byte power_pin = 12;
byte sw_sel = 14;// select
byte sw_up = 15;// up
byte sw_dwn = 16;//down
byte fonction = 0;
int gmt;//, hr ;
long Year_Min;
long Tide_one;
unsigned long time_On;
unsigned long time_run;
unsigned long time_old;

int year;//, vinfo;


int menu_index = 0;
int cum_n;
static float rad2deg = 0.01745;
float Odometre;
char msg[6];
byte LCD_LED_N = 220; //OFF 0-a-255 ON
byte col, row, nb = 0, bc = 0; // general
byte bb[8];
byte month, day, hour, minute, second, sped; //hundredths,
long lat, lon; //, latmin, lonmin; //angle
long lat2 = 0;
long lon2 = 0;
long wp_lat, wp_lon ;

const char*azimuts[] = {"N ", "NE ", "E ", "SE ", "S ", "SW ", "W ",
"NW " };
const char custom[][8] PROGMEM = { // Custom character
definitions
{ 0x1F, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00 }, // char 1
{ 0x18, 0x1C, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }, // char 2
{ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x0F, 0x07, 0x03 }, // char 3
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F }, // char 4
{ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1C, 0x18 }, // char 5
{ 0x1F, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x1F, 0x1F }, // char 6
{ 0x1F, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F }, // char 7
{ 0x03, 0x07, 0x0F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }, // char 8

};
const char bigChars[][8] PROGMEM = {
{ 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Space
{ 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // !
{ 0x05, 0x05, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00 }, // "
{ 0x04, 0xFF, 0x04, 0xFF, 0x04, 0x01, 0xFF, 0x01 }, // #
{ 0x08, 0xFF, 0x06, 0x07, 0xFF, 0x05, 0x00, 0x00 }, // $
{ 0x01, 0x20, 0x04, 0x01, 0x04, 0x01, 0x20, 0x04 }, // %
{ 0x08, 0x06, 0x02, 0x20, 0x03, 0x07, 0x02, 0x04 }, // &
{ 0x05, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // '
{ 0x08, 0x01, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00 }, // (
{ 0x01, 0x02, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00 }, // )
{ 0x01, 0x04, 0x04, 0x01, 0x04, 0x01, 0x01, 0x04 }, // *
{ 0x04, 0xFF, 0x04, 0x01, 0xFF, 0x01, 0x00, 0x00 }, // +
{ 0x20, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //
{ 0x04, 0x04, 0x04, 0x20, 0x20, 0x20, 0x00, 0x00 }, // -
{ 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // .
{ 0x20, 0x20, 0x04, 0x01, 0x04, 0x01, 0x20, 0x20 }, // /
{ 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00 }, // 0
{ 0x01, 0x02, 0x20, 0x04, 0xFF, 0x04, 0x00, 0x00 }, // 1
{ 0x06, 0x06, 0x02, 0xFF, 0x07, 0x07, 0x00, 0x00 }, // 2
{ 0x01, 0x06, 0x02, 0x04, 0x07, 0x05, 0x00, 0x00 }, // 3
{ 0x03, 0x04, 0xFF, 0x20, 0x20, 0xFF, 0x00, 0x00 }, // 4
{ 0xFF, 0x06, 0x06, 0x07, 0x07, 0x05, 0x00, 0x00 }, // 5
{ 0x08, 0x06, 0x06, 0x03, 0x07, 0x05, 0x00, 0x00 }, // 6
{ 0x01, 0x01, 0x02, 0x20, 0x08, 0x20, 0x00, 0x00 }, // 7
{ 0x08, 0x06, 0x02, 0x03, 0x07, 0x05, 0x00, 0x00 }, // 8
{ 0x08, 0x06, 0x02, 0x07, 0x07, 0x05, 0x00, 0x00 }, // 9
};

const static byte gpsDefault[] PROGMEM = {0xB5, 0x62, 0x06, 0x09,


0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0x07, 0x1F, 0x9E};
const static byte gpsSave[] PROGMEM = {0xB5, 0x62, 0x06, 0x09, 0x0D,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x17, 0x31, 0xBF, 0x13};
const static byte gpsSleep[] = {0xB5, 0x62, 0x06, 0x04, 0x04, 0x00, 0x00,
0x00, 0x08, 0x00, 0x16, 0x74};
const static byte gpsHot[] = {0xB5, 0x62, 0x06, 0x04, 0x04, 0x00, 0x00,
0x00, 0x02, 0x00, 0x10, 0x68};
const static byte Disable_GPDTM[] PROGMEM = {0x24, 0x45, 0x49,
0x47, 0x50, 0x51, 0x2c, 0x44, 0x54, 0x4d, 0x2a, 0x33, 0x42, 0x0d, 0x0a,
0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x0a, 0x00, 0x04, 0x23}; //-
>Disable_GPDTM
const static byte Disable_GPGBS[] PROGMEM = {0x24, 0x45, 0x49, 0x47,
0x50, 0x51, 0x2c, 0x47, 0x42, 0x53, 0x2a, 0x33, 0x30, 0x0d, 0x0a, 0xb5,
0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x09, 0x00, 0x03, 0x21}; //-
>Disable_GPGBS
const static byte Disable_GPGGA[] PROGMEM = {0x24, 0x45, 0x49,
0x47, 0x50, 0x51, 0x2c, 0x47, 0x47, 0x41, 0x2a, 0x32, 0x37, 0x0d, 0x0a,
0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x00, 0x00, 0xfa, 0x0f};
//>Disable_GPGGA
const static byte Disable_GPGLL[] PROGMEM = {0x24, 0x45, 0x49, 0x47,
0x50, 0x51, 0x2c, 0x47, 0x4c, 0x4c, 0x2a, 0x32, 0x31, 0x0d, 0x0a, 0xb5,
0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x01, 0x00, 0xfb, 0x11}; //-
>Disable_GPGLL
const static byte Disable_GPGRS[] PROGMEM = {0x24, 0x45, 0x49, 0x47,
0x50, 0x51, 0x2c, 0x47, 0x52, 0x53, 0x2a, 0x32, 0x30, 0x0d, 0x0a, 0xb5,
0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x06, 0x00, 0x00, 0x1b}; //-
>Disable_GPGRS
const static byte Disable_GPGSA[] PROGMEM = {0x24, 0x45, 0x49, 0x47,
0x50, 0x51, 0x2c, 0x47, 0x53, 0x41, 0x2a, 0x33, 0x33, 0x0d, 0x0a, 0xb5,
0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x02, 0x00, 0xfc, 0x13}; //-
>DisableGPGSA
const static byte Disable_GPGST[] PROGMEM = {0x24, 0x45, 0x49, 0x47,
0x50, 0x51, 0x2c, 0x47, 0x53, 0x54, 0x2a, 0x32, 0x36, 0x0d, 0x0a, 0xb5,
0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x07, 0x00, 0x01, 0x1d}; //-
>Disable_GPGST
const static byte Disable_GPGSV[] PROGMEM = {0x24, 0x45, 0x49, 0x47,
0x50, 0x51, 0x2c, 0x47, 0x53, 0x56, 0x2a, 0x32, 0x34, 0x0d, 0x0a, 0xb5,
0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x03, 0x00, 0xfd, 0x15}; //-
>Disable_GPGSV
const static byte Disable_GPRMC[] PROGMEM = {0x24, 0x45, 0x49,
0x47, 0x50, 0x51, 0x2c, 0x52, 0x4d, 0x43, 0x2a, 0x33, 0x41, 0x0d, 0x0a,
0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x04, 0x00, 0xfe, 0x17}; //-
>Disable_GPRMC
const static byte Disable_GPVTG[] PROGMEM = {0x24, 0x45, 0x49,
0x47, 0x50, 0x51, 0x2c, 0x56, 0x54, 0x47, 0x2a, 0x32, 0x33, 0x0d, 0x0a,
0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x05, 0x00, 0xff, 0x19}; //-
>Disable_GPVTG
const static byte Disable_GPZDA[] PROGMEM = {0x24, 0x45, 0x49,
0x47, 0x50, 0x51, 0x2c, 0x5a, 0x44, 0x41, 0x2a, 0x33, 0x39, 0x0d, 0x0a,
0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x08, 0x00, 0x02, 0x1f}; //-
>Disable_GPZDA

///////////////////////////////////////////////////////
// Minute depuis debut annee //
///////////////////////////////////////////////////////
int days[] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; //
Number of days at the beginning of the month in a not leap year.
long DofY(int yr, int mo, int dy, int h, int mi)
{
int DfY;
long Min2Date;
if (mo == 1 || mo == 2)
{
DfY = days[mo] + dy - 1; //for any type of year, it calculate the
number of days for January or february
}
else if ((yr % 4 == 0 && yr % 100 != 0) || yr % 400 == 0)
{
DfY = days[mo] + dy + 1 - 1;
}
else
{
DfY = days[mo] + dy - 1;
}
Min2Date = (long)DfY * 1440l + (long)h * 60l + (long)mi;
return (Min2Date);
}
///////////////////////////////////////////////////////
// SETUP //
///////////////////////////////////////////////////////
void setup()
{
pinMode(power_pin, OUTPUT);
digitalWrite (power_pin, HIGH); // POWER ON!
analogReference(DEFAULT);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
Serial.begin(9600);
gpsSerial.begin(9600);
pinMode(LCD_LED, OUTPUT);
//pinMode(buz, OUTPUT);
pinMode(sw_sel, INPUT);
pinMode(sw_up, INPUT);
pinMode(sw_dwn, INPUT);
lcd.begin(16, 2);
analogWrite(LCD_LED, 100);

///////////////////////////////////////////////////////
// EE PROM Variable //
///////////////////////////////////////////////////////
hour = EEPROM.read(0); //lire le gmt
pro_mode = EEPROM.read(4);
EEPROM.get(10, wp_lat);
EEPROM.get(15, wp_lon);
EEPROM.get(20, Tide_one);
EEPROM.get(25, Odometre);
EEPROM.get(30, time_On);
if (isnan(Odometre)) // test if NAN value
{
Odometre = 0;
}
if (hour > 127) //numbre negatif
{
gmt = hour - 256;
}
else
{
gmt = hour;
}
///////////////////////////////////////////////////////
/// REV ///
///////////////////////////////////////////////////////
lcd.clear();
lcd.print(F("Ultimate YAK GPS"));
lcd.setCursor(0, 1);
lcd.print(F("GPS_1602B rev 92.1")); // Revision
Version<<<<
delay (2000);
lcd.clear();
lcd.print("GMT="); lcd.print(gmt);
float vbatt = (float) analogRead(batt) / vref + .21; //
lcd.setCursor(0, 1);
lcd.print(F("Batterie:"));
lcd.print(vbatt);
lcd.print("V");
delay (2000);
lcd.clear();
lcd.print(F("Odometre:"));
lcd.print(Odometre);
delay (2000);
lcd.clear();
lcd.print("WPLat:");
lcd.print(wp_lat);
lcd.setCursor(0, 1);
lcd.print("WPLon:");
lcd.print(wp_lon);
delay (2000);
lcd.clear();
lcd.print("Last Time ON:");
lcd.setCursor(0, 1);
lcd.print(time_On / 60000); lcd.print("Min");
delay (4000);

/*lcd.clear();
lcd.print("TIDE: ");
lcd.print(Tide_one);
float a = (float)Tide_one / 288; //288 = 24hr * 60/ 5 min/hr)
int tide_jr = (int)a;
float b = (a - (float) tide_jr) * 24;
tide_hr = (int)b;
tide_min = (b - (float) tide_hr) * 60 ;
lcd.setCursor(0, 1);
lcd.print(tide_jr + 1);
lcd.print("Days ");
lcd.print(tide_hr);
lcd.print(":");
lcd.print(tide_min);
delay(2000);
*/

if (vbatt < 2.8)//volts


{
lcd.setCursor(0, 1); lcd.print("Batt. LOW!");
delay (4000);
//digitalWrite(power_pin, LOW); //off
}
analogWrite(LCD_LED, 20);

///////////////////////////////////////////////////////
// GPS Reset //
///////////////////////////////////////////////////////
lcd.clear();

if (gps.encode(gpsSerial.read()))
{
lcd.print("GPS Reset");
gpsSerial.write(gpsHot, sizeof(gpsHot)); gpsSerial.flush();
gpsSerial.write( gpsDefault, sizeof( gpsDefault)); gpsSerial.flush();
gpsSerial.write( Disable_GPDTM, sizeof( Disable_GPDTM));
gpsSerial.flush();
gpsSerial.write( Disable_GPGBS, sizeof( Disable_GPGBS));
gpsSerial.flush();
gpsSerial.write( Disable_GPGLL, sizeof( Disable_GPGLL));
gpsSerial.flush();
gpsSerial.write( Disable_GPGRS, sizeof( Disable_GPGRS));
gpsSerial.flush();
gpsSerial.write( Disable_GPGSA, sizeof( Disable_GPGSA));
gpsSerial.flush();
gpsSerial.write( Disable_GPGSV, sizeof( Disable_GPGSV));
gpsSerial.flush();
gpsSerial.write( Disable_GPVTG, sizeof( Disable_GPVTG));
gpsSerial.flush();
gpsSerial.write( Disable_GPGGA, sizeof( Disable_GPGGA));
gpsSerial.flush();
}
lcd.setCursor(0, 1); lcd.println(F("Wait satellites."));
///////////////////////////////////////////////////////
/// create 8 custom characters ///
///////////////////////////////////////////////////////
for (nb = 0; nb < 8; nb++ )
{
for (bc = 0; bc < 8; bc++)
bb[bc] = pgm_read_byte( &custom[nb][bc] );
lcd.createChar ( nb + 1, bb );
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// LOOP ///
///////////////////////////////////////////////////////////////////////////////////////////////////////////
///
void loop()
{
while (gpsSerial.available()) // check for gps data
{
if (gps.encode(gpsSerial.read())) // encode gps data
{
gps.get_position(&lat, &lon); // get lat and long
gps.crack_datetime(&year, &month, &day, &hour, &minute, &second);
lat = lat / 100; //enlever les d-secondes
lon = lon / 100;
// lcd.setCursor(0, 0); lcd.print (lat); lcd.print (" "); lcd.print (lon); delay
(4000);
hour = hour + gmt;
if (hour > 128) // reference a gmt
{
hour = hour + 24;
day = day - 1;
}
////Serial.print ("DofY=");//Serial.println (DofY
(year,month,day,hour,minute));
//Serial.print (year); //Serial.print ("/"); //Serial.print (month); //Serial.print
("/"); //Serial.print (day); //Serial.print (" "); //Serial.print (hour);
//Serial.print (":"); //Serial.println (minute);
Year_Min = DofY ((int)year, (int)month, (int)day, (int)hour, (int)minute);
//Serial.print ("Year2min ="); //Serial.println (Year_Min);

if (digitalRead(sw_sel) == LOW) {
lcd.clear();
while (digitalRead(sw_sel) == 0) {} // wait for release
menu(0);
}
if (digitalRead(sw_dwn) == LOW)
{
lcd.clear();
while (digitalRead(sw_dwn) == 0) {} // wait for release
if (pro_mode == false)
{
lcd.clear(); lcd.print("PRO Display ");
delay (1500);
pro_mode = true;
EEPROM.write(4, pro_mode);
}
else
{
lcd.clear(); lcd.print("Dashboard MODE ");
pro_mode = false;
EEPROM.write(4, pro_mode);
delay (1500);
}
lcd.clear ();
}
///////////////////////////////////////////////////////
// LCD LED & test de batt //
///////////////////////////////////////////////////////
float vsol = (float) analogRead(solPanel) / vref ; // 1024/2.5voltsRef
if (eco_mode == true) {
LCD_LED_N = 20;
}
else {
LCD_LED_N = 150;
}
if (vsol > 1) {//volt
vsol = 1;//volt
}
LCD_LED_N = LCD_LED_N - (vsol * LCD_LED_N);
analogWrite(LCD_LED, LCD_LED_N);

float vbatt = (float) analogRead(batt) / vref + .21; // 1024/5voltsRef


if (vbatt < 2.8) // Volts 2.8
{
lcd.clear(); lcd.print("LOW BATT ");
lcd.setCursor(0, 1); lcd.print(vbatt); lcd.print("Volts");
EEPROM.put(25, Odometre); //save odometre
delay (5000);
digitalWrite(power_pin, LOW);// power off
}
if (vbatt > 4.2) // Volts
{
analogWrite(LCD_LED, 255);
digitalWrite(LED_BUILTIN, HIGH);
}
else
{
digitalWrite(LED_BUILTIN, LOW);
}
float speedf = gps.speed() * .01852; // 1.852 /100 knot to kmph

if (speedf < .5)


{
speedf = 0;
}
///////////////////////////////////////////////////////
/// ODOMETRE ///
///////////////////////////////////////////////////////
if (cum_n >= 10)
{
if (lat2 == 0)
{
lat2 = lat;
lon2 = lon;
}
cum_n = 0;
float lon2_dec = lon2 / 10000.0;
/////////////////////convert decimal degree into radian////////////////
float lat1_Rad = lat / 10000.0 * rad2deg;
float lon1_Rad = lon / 10000.0 * rad2deg;
float lat2_Rad = lat2 / 10000.0 * rad2deg;
float lon2_Rad = lon2 / 10000.0 * rad2deg;

//Calculate the distance KM


float latSin = sin((lat1_Rad - lat2_Rad) / 2);
float lonSin = sin((lon1_Rad - lon2_Rad) / 2);
float P2P = 2 * asin(sqrt((latSin * latSin) + cos(lat1_Rad) * cos(lat2_Rad) *
(lonSin * lonSin)));
P2P = P2P * 6371; //Earth radius = 6,371 km

if (P2P < 5 && speedf != 0) // plus de 5 km est une erreur ou speed =0kmh
{
Odometre += P2P;
lat2 = lat;
lon2 = lon;
EEPROM.put(25, Odometre);
time_run = time_run + (millis() - time_old);

EEPROM.put(30, millis()); //future reference


}
time_old = millis();
}
else
{
cum_n ++;
}
///////////////////////////////////////////////////////
// VITESSE //
///////////////////////////////////////////////////////

dtostrf (speedf, 3, 1, msg) ;


if (pro_mode == false)
{
writeBigString(msg, 0, 0);
lcd.setCursor(7, 0); lcd.print ("KM ");
lcd.setCursor(7, 1); lcd.print ("/H ");
lcd.setCursor(10, 0);
if (Odometre < 100)
{
dtostrf (Odometre, 1, 1, msg) ;
}
else
{
dtostrf (Odometre, 1, 0, msg) ;
}
lcd.print (msg); lcd.print ("KM ");

horloge (10, 1);


}
else
{
lcd.setCursor(0, 0);
lcd.print(msg); lcd.print("KMH ");//dtostrf (speedf, 3, 1, msg) ;
Print_Azimut(8, 0);
horloge(0, 1) ;
///////////////////////////////////////////////////////
// Display Fonction Variable //
///////////////////////////////////////////////////////
fonction++;
switch (fonction / 3)
{
case 1:
{
Print_wpazimut(6, 1);
EEPROM.put(30, millis());
}
break;
case 4:
{
Print_Tide(6, 1);
}
break;
case 2:
{
lcd.setCursor(6, 1);
if (Odometre < 100)
{
dtostrf (Odometre, 1, 1, msg) ;
}
else
{
dtostrf (Odometre, 1, 0, msg) ;
}
lcd.print ("Od:"); lcd.print (msg); lcd.print ("KM ");
}
break;
case 3:
{
lcd.setCursor(6, 1);
lcd.print ("Run:");
if (time_run > 10000000L)//msec
{
lcd.print (time_run / 3600000L);//msec
lcd.print ("Hr ");
}
else
{
lcd.print (time_run / 60000L);//msec
lcd.print ("Min ");
}
}
break;
default:
{
fonction = 2;
}
break;
}
///////////////////////////////////////////////////////
// eco mode
//
///////////////////////////////////////////////////////
if (eco_mode == true)
{
//char buffer[4]; //2del
gpsSerial.write(gpsSleep, sizeof(gpsSleep));
gpsSerial.flush();
for (int n = 0; n < 6 ; n++)//Sec.
{
lcd.setCursor(15, 0); lcd.print (n);
Print_Tide(6, 1);
delay (1500);
Print_wpazimut(6, 1);
delay (1500);
if (digitalRead(sw_sel) == 0)
{
lcd.clear ();
while (digitalRead(sw_sel) == 0) {}; delay(10); // debounce
menu(0);
}
}
gpsSerial.write(gpsHot, sizeof(gpsHot));
gpsSerial.flush();
delay (2000); //
//vinfo = 1;
}
}
}
}
}

///////////////////////////////////////////////////////
// MENU //
///////////////////////////////////////////////////////
static char* menu_items [] = {"Sel-UP-down", "Power OFF", "Lat-Long &
WP ", "Power Moniteur",
"Eco Mode", "GMT set ", "TIDE set" , "Display Mode", "Odometre",
"Retour", "Sel-up-DOWN"
};
void menu(int menu_index)
{
lcd.clear(); lcd.print(menu_items[menu_index]);
while (digitalRead(sw_sel) == LOW) {}; delay(5); //Debounce
while (digitalRead(sw_sel) != LOW)// Select
{
if (digitalRead(sw_up) == LOW)
{
lcd.clear();
while (digitalRead(sw_up) == LOW) {}; delay(10); //Debounce
menu_index ++;
if (menu_index > 8)
{
menu_index = 0;
}
lcd.clear();
//lcd.setCursor(0, 0); lcd.print(menu_items[0]);
lcd.setCursor(0, 1);
lcd.print(menu_items[menu_index]);
}
if (digitalRead(sw_dwn) == LOW)
{
lcd.clear();
while (digitalRead(sw_dwn) == LOW) {}; delay(10); //Debounce
menu_index -= 1;
if (menu_index < 0)
{
menu_index = 8;
}
lcd.clear();
lcd.print(menu_items[0]);
lcd.setCursor(0, 1);
lcd.print(menu_items[menu_index]);
}
}
lcd.clear();
while (digitalRead(sw_sel) == LOW) {}; delay(100); //Debounce
switch (menu_index)
{
case 1:
///////////////////////////////////////////////////////
// POWER OFF //
///////////////////////////////////////////////////////
{
lcd.clear();
lcd.print ("POWER OFF....");
delay (1500);
digitalWrite(power_pin, LOW);
delay (50);
asm volatile (" jmp 0");
}
break;
case 2:
///////////////////////////////////////////////////////
// LAT et LONG MEMO //
///////////////////////////////////////////////////////
{
lcd.clear ();
lcd.setCursor (0, 0);
lcd.print("Push DWN to Save") ;
lcd.setCursor (0, 1);
lcd.print("WayPoint ") ;
delay (1000); lcd.clear ();
while (digitalRead(sw_sel) != LOW)
{
Print_Latitude (0, 0);
Print_Longitude (0, 1);
if (digitalRead(sw_dwn) == LOW)
{
wp_lat = lat;
wp_lon = lon;
EEPROM.put(10, lat);
EEPROM.put(15, lon);
lcd.clear ();
lcd.setCursor (0, 0);
lcd.print("WayPoint SAVED") ;
delay (1500);
break;
}
if (digitalRead(sw_up) == LOW)
{
lcd.clear ();
lcd.setCursor (0, 0);
lcd.print("Push DWN to Save") ;
while (digitalRead(sw_up) == LOW) {};
delay(1000);
lcd.clear ();
}
gps.get_position(&lat, &lon);
lat = lat / 100; //enlever les d-secondes
lon = lon / 100;
}
lcd.clear ();
while (digitalRead(sw_sel) == LOW) {};
}
break;
case 3:
///////////////////////////////////////////////////////
// POWER MONITOR batt sol //
///////////////////////////////////////////////////////
{
gpsSerial.write(gpsSleep, sizeof(gpsSleep));
while (3)
{
float vsol = (float) analogRead(solPanel) / 204; // 1024/5voltsRef
dtostrf (vsol, 3, 1, msg) ;
lcd.setCursor(0, 0);
lcd.print ("Solaire=");
lcd.print (msg);
lcd.print ("V ");
float vbatt = (float) analogRead(batt) / vref + .21; // 1024/5voltsRef
dtostrf (vbatt, 3, 1, msg) ;
lcd.setCursor(0, 1);
lcd.print ("Batterie=");
lcd.print (msg); lcd.print ("V ");
if ((vsol - vbatt) > .4)//volts
{
lcd.setCursor(12, 1); lcd.print ("V Charge ");
}
else
{
lcd.setCursor(12, 1); lcd.print ("V ");
}
delay (1000);
if (digitalRead(sw_sel) == LOW)
{
lcd.clear();
while (digitalRead(sw_sel) == LOW) {} ;
gpsSerial.write(gpsHot, sizeof(gpsHot));
return;
}
delay (1000);
}
}
break;
case 4:
///////////////////////////////////////////////////////
/// ECO MODE select ///
///////////////////////////////////////////////////////
{
if (eco_mode == false)
{
lcd.setCursor(0, 0); lcd.print("ECONO MODE ON ");
delay (1500);
eco_mode = true;
analogWrite(LCD_LED, 0); // off lcd led
}
else
{
lcd.setCursor(0, 0); lcd.print("ECONO MODE OFF ");
eco_mode = false;
delay (1500);
analogWrite(LCD_LED, LCD_LED_N); // off lcd led
}
lcd.clear ();
}
break;
case 5:
///////////////////////////////////////////////////////
// GMT //
///////////////////////////////////////////////////////
{
//gmt = 0;
while (digitalRead(sw_sel) != LOW)
{
if (digitalRead(sw_up) == LOW)
{
lcd.clear ();
while (digitalRead(sw_up) == LOW) {} ;
gmt ++;
}
if (digitalRead(sw_dwn) == LOW)
{
lcd.clear ();
while (digitalRead(sw_dwn) == LOW) {} ;
gmt --;
}
lcd.clear();
lcd.print ("GMT");
lcd.print(gmt);
delay (300);
}
lcd.clear ();
while (digitalRead(sw_sel) == LOW) {} ;
lcd.setCursor (0, 1);
lcd.print ("SET GMT");
lcd.print(gmt);
EEPROM.write(0, gmt);
delay(1000);
return;
}
break;
case 6:
///////////////////////////////////////////////////////
// SET TIDE //
///////////////////////////////////////////////////////
{
//int tide_min, tide_hr;
lcd.setCursor (0, 0);
lcd.print ("Set ");
lcd.setCursor (0, 1);
lcd.print ("FullMoonHighTide");
EEPROM.get(20, Tide_one);
int tide_mth = 1;
//float a = (float)Tide_one / 288; //288 = 24hr * 60/ 5 min/hr)
int tide_jr = 12; //(int)a;
//float b = (a - (float) tide_jr) * 24;
int tide_hr = 7; // (int)b;
int tide_min = 45; //(b - (float) tide_hr) * 60 ;

///////////////////////////////////////////////////////
lcd.clear ();
while (digitalRead(sw_sel) != LOW)
{
lcd.setCursor (0, 1);
lcd.print (tide_mth); lcd.print("/");
lcd.setCursor (3, 1); lcd.print(tide_jr); lcd.print(" ");
lcd.setCursor (8, 1); lcd.print(tide_hr); lcd.print(":"); lcd.print(tide_min);
lcd.print(" ");
lcd.setCursor (0, 0) ;
lcd.print("v--Month ");
delay (350);
if (digitalRead(sw_up) == LOW)
{
tide_mth ++;
}
if (digitalRead(sw_dwn) == LOW)
{
tide_mth --;
}
}
///////////////////////////////////////////////////////
lcd.clear ();
while (digitalRead(sw_sel) == LOW) {}; delay (100);
while (digitalRead(sw_sel) != LOW)
{
lcd.setCursor (0, 1);
lcd.print (tide_mth); lcd.print("/");
lcd.setCursor (3, 1); lcd.print(tide_jr ); lcd.print(" ");
lcd.setCursor (8, 1); lcd.print(tide_hr); lcd.print(":"); lcd.print(tide_min);
lcd.print(" ");
lcd.setCursor (3, 0);
delay (350);
lcd.print("v--Day ");
if (digitalRead(sw_up) == LOW)
{
tide_jr ++;
}
if (digitalRead(sw_dwn) == LOW)
{
tide_jr --;
}
}
///////////////////////////////////////////////////////

lcd.clear ();
while (digitalRead(sw_sel) == LOW) {}; delay (100);
while (digitalRead(sw_sel) != LOW)
{
lcd.setCursor (0, 1);
lcd.print (tide_mth); lcd.print("/");
lcd.setCursor (3, 1); lcd.print(tide_jr ); lcd.print(" ");
lcd.setCursor (8, 1); lcd.print(tide_hr); lcd.print(":"); lcd.print(tide_min);
lcd.print(" ");
lcd.setCursor (8, 0);
lcd.print("v--Hr ");
delay (350);
if (digitalRead(sw_up) == LOW)
{
tide_hr ++;
}
if (digitalRead(sw_dwn) == LOW)
{
tide_hr --;
}
}
///////////////////////////////////////////////////////
lcd.clear ();
while (digitalRead(sw_sel) == LOW) {}; delay (100);
while (digitalRead(sw_sel) != LOW)
{
lcd.setCursor (0, 1);
lcd.print (tide_mth); lcd.print("/");
lcd.setCursor (3, 1); lcd.print(tide_jr ); lcd.print(" ");
lcd.setCursor (8, 1); lcd.print(tide_hr); lcd.print(":"); lcd.print(tide_min);
lcd.print(" ");
lcd.setCursor (5, 0);
lcd.print("Min--v ");
delay (350);
if (digitalRead(sw_up) == LOW)
{
tide_min += 5;
}
if (digitalRead(sw_dwn) == LOW)
{
tide_min -= 5;
}
if (tide_min < 1) {
tide_min = 1; // prevention 0/5
}
}
lcd.clear ();
while (digitalRead(sw_sel) == LOW) {}
Tide_one = DofY (year, tide_mth, tide_jr, tide_hr, tide_min);
lcd.setCursor (0, 0);
lcd.print ("Tide_one="); lcd.print (Tide_one); lcd.print (" ");
lcd.setCursor (0, 1);
lcd.print (tide_mth); lcd.print("/"); lcd.print (tide_jr ); lcd.print (" ");
lcd.print (tide_hr); lcd.print (":"); lcd.print (tide_min);
delay (3500);
while (digitalRead(sw_sel) == LOW) { }
lcd.clear ();
lcd.print ("Push Dwn to Save");
while (digitalRead(sw_sel) != LOW)
{
if (digitalRead(sw_dwn) == LOW)
{
if (Tide_one > 0)
{
EEPROM.put(20, Tide_one);
lcd.clear ();
lcd.print ("TIDE SAVED");
lcd.setCursor (0, 1);
lcd.print (Tide_one);
delay (2000);
while (digitalRead(sw_dwn) == LOW) { }
lcd.clear ();
return;
}
else
{
lcd.clear ();
lcd.print ("TIDE E R R O R");
lcd.setCursor (0, 1);
lcd.print (Tide_one);
delay (2500);
lcd.clear ();
return;
}
}
delay (50);
}
lcd.clear ();
return;
}
break;
case 7:
///////////////////////////////////////////////////////
// PRO MODE //
///////////////////////////////////////////////////////
{
if (pro_mode == false)
{
lcd.clear(); lcd.print("PRO Display ");
delay (1500);
pro_mode = true;
EEPROM.write(4, pro_mode);
}
else
{
lcd.clear(); lcd.print("Dashboard ");
pro_mode = false;
EEPROM.write(4, pro_mode);
delay (1500);
}
lcd.clear ();
}
break;
case 8:
///////////////////////////////////////////////////////
// ODOMETRE //
///////////////////////////////////////////////////////
{
Odometre = 0;
time_run = 0;
lat2 = lat;
lon2 = lon;
lcd.clear(); lcd.print("Odometre Reset");
delay (1500); lcd.clear ();
}
break;
default:
{
}
return;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// SUBROUTINES //
/////////////////////////////////////////////////////////////////////////////////////
// writeBigChar: writes big character 'ch' to column x, row y; returns
number of columns used by 'ch'
int writeBigChar(char ch, byte x, byte y) {
if (ch < ' ' || ch > '_') return 0; // If outside table range, do nothing
nb = 0; // character byte counter
for (bc = 0; bc < 8; bc++) {
bb[bc] = pgm_read_byte( &bigChars[ch - ' '][bc] ); // read 8 bytes from
PROGMEM
if (bb[bc] != 0) nb++;
}
bc = 0;
for (row = y; row < y + 2; row++) {
for (col = x; col < x + nb / 2; col++ ) {
lcd.setCursor(col, row); // move to position
lcd.write(bb[bc++]); // write byte and increment to next
}
}
return nb / 2 - 1; // returns number of columns used by
char
}
// writeBigString: writes out each letter of string
void writeBigString(char *str, byte x, byte y)
{
char c;
while ((c = *str++))
x += writeBigChar(c, x, y) + 1;
}
///////////////////////////////////////////////////////
// HORLOGE //
///////////////////////////////////////////////////////
void horloge(int C, int R)
{
lcd.setCursor(C, R);
lcd.print(hour); lcd.print(":");
if (minute < 10)
{
lcd.print("0");
}
lcd.print(minute);
lcd.print(" ");
}
///////////////////////////////////////////////////////
// LATITUDE //
///////////////////////////////////////////////////////
void Print_Latitude(int C, int R)
{
long latdeg = (lat / 10000);
lcd.setCursor(C, R);
lcd.print("Lat:");
lcd.print(abs(latdeg));
lcd.print((char)223);
float x = (float)(lat - latdeg * 10000) * .6 / 100;
lcd.print(x); lcd.print("'");
if (lat > 0)
{
lcd.print ("N");
}
else
{
lcd.print("S");
}
}
///////////////////////////////////////////////////////
// PRINT LONGITUDE //
///////////////////////////////////////////////////////
void Print_Longitude(int C, int R)
{
long londeg = (lon / 10000);
lcd.setCursor(C, R);
lcd.print("Lon:");
lcd.print(abs(londeg));
lcd.print((char)223);
float x = (float) (abs(lon) - abs(londeg) * 10000) * .6 / 100;
lcd.print(x); lcd.print("'");
if (lon > 0) {
lcd.print("E");
}
else {
lcd.print("W");
}
}

///////////////////////////////////////////////////////
// TIDE CLOCK display //
///////////////////////////////////////////////////////
void Print_Tide(int C, int R)
{
EEPROM.get(20, Tide_one);
const char*tideclock [] {"HIGH ", "L 5Hr ", "L 4Hr ", "L 3Hr ", "L 2Hr
", "L 1Hr ", "LOW ", "H 5Hr ", "H 4Hr ", "H 3Hr ", "H 2Hr ", "H 1Hr
", "HIGH ", "ERR "};
//Serial.print ("y min="); //Serial.println (Year_Min);
//Serial.print ("tide 1="); //Serial.println (Tide_one);
long tide_cycle = (Year_Min - Tide_one);
//Serial.print ("tide cycle="); //Serial.println (tide_cycle);
float tide_cyclef = (float)tide_cycle / 745.233333f; //Tide 12h25m14sec
(745.23 min)
dtostrf (tide_cyclef, 1, 6, msg) ;
//Serial.print ("tide cyclef="); //Serial.println (msg);
tide_cyclef = tide_cyclef - int(tide_cyclef);
dtostrf (tide_cyclef, 1, 6, msg) ;
//Serial.print ("tide cyclefraction="); //Serial.println (msg);
tide_cyclef = tide_cyclef * 12;
dtostrf (tide_cyclef, 1, 6, msg) ;
tide_cycle = round (tide_cyclef);
lcd.setCursor(C, R);
lcd.print ("Tide:");
lcd.print (tideclock[tide_cycle]);
//; break;

62) Arduino Morse Code Machine


COMPONENTS AND SUPPLIES
Arduino UNO & Genuino UNO
× 1

Buzzer
× 1

LED (generic) × 1
SparkFun Pushbutton switch
12mm
× 1

Jumper wires (generic)


× 10
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

Although I am pretty new to the IoT and Arduino


stage, with the help of my friends and classmates and
my professor I got into it pretty quickly. This was one
of my first real projects, finished a while ago, but I am
still making improvements.
Morse Code
Considering I knew Morse code as a kid, and that I
wanted to play with the components, I decided on the
Morse machine.

The isn't to hard to make, it requires some basic parts


(listed below) and some basic programming skill (feel
free to play with the code and make it more
interesting/efficient). Although writing in Morse code
is pretty hard you get a hang of it after a while. I
practiced with printed out sheet which you can get
online. Don't feel bad if you make mistakes or the
timer feels odd, for practice I advise to change those
variable values to make it easier to practice and when
you become a pro, turn down those values, so you
sound like a pro.
SCHEMATICS
CODE

const int buttonPin = 2;


const int ledPin = 13;
const int buzzer = 9;

int ledState = HIGH;


int buttonState = LOW;
int lastButtonState = LOW;
int doesitwork = LOW; // variable used for debuging early versions of the
code

int pause_value = 250; // depending on your skill and how fast your fingers
are you can change this value to make typing a message faster or slower
long signal_length = 0;
long pause = 0;

String morse = "";


String dash = "-";
String dot = "*";

boolean cheker = false;


boolean linecheker = false;

long lastDebounceTime = 0;
long debounceDelay = 50;
void setup()
{
Serial.begin(9600);

pinMode(buttonPin, INPUT);
pinMode(ledPin, OUTPUT);
pinMode(buzzer, OUTPUT);

Serial.println("Welcome to Arduino-Uno morse machine");


Serial.println("Using these values print out your message in morse and read
out the message in english in the serial monitor");
Serial.println("https://goo.gl/images/R4AIsW morse code values for
learing");

while(!digitalRead(buttonPin))
;

void loop() {

buttonState = digitalRead(buttonPin);

if (buttonState && lastButtonState) // basic state machine depending on


the state of the signal from the button
{
++signal_length;
if (signal_length<2*pause_value) //this help to notice that there is a
change in the signal length aka that its not a dot anymore but a dash
{ // best use for the measuring of signal_length
would be use of the millis() but this was used for simplicity
tone(buzzer, 1500) ;
}
else
{
tone(buzzer, 1000) ;
}
}
else if(!buttonState && lastButtonState) //this part of the code
happens when the button is released and it send either * or - into the buffer
{
if (signal_length>50 && signal_length<2*pause_value )
{
morse = morse + dot;
}
else if (signal_length>2*pause_value)
{
morse = morse + dash;
}
signal_length=0;
digitalWrite(13, LOW);
noTone(buzzer);
}
else if(buttonState && !lastButtonState) // this part happens when the
button is pressed and its use to reset several values
{
pause=0;
digitalWrite(13, HIGH);
cheker = true;
linecheker = true;
}
else if (!buttonState && !lastButtonState)
{
++pause;
if (( pause>3*pause_value ) && (cheker))
{
printaj(morse);
cheker = false;
morse = "";
}
if ((pause>15*pause_value) && (linecheker))
{
Serial.println();
linecheker = false;
}
}
lastButtonState=buttonState;
delay(1);
}
void printaj(String prevodilac) //ugly part of the code but it works fine
{ //compare morse string to known morse values and
print out the letter or a number
//the code is written based on the international morse code, one thing i
changed is that insted of typing a special string to end the line it happens
with enough delay
if (prevodilac=="*-")
Serial.print("A");
else if (prevodilac=="-***")
Serial.print("B");
else if (prevodilac=="-*-*")
Serial.print("C");
else if (prevodilac=="-**")
Serial.print("D");
else if (prevodilac=="*")
Serial.print("E");
else if (prevodilac=="**-*")
Serial.print("F");
else if (prevodilac=="--*")
Serial.print("G");
else if (prevodilac=="****")
Serial.print("H");
else if (prevodilac=="**")
Serial.print("I");
else if (prevodilac=="*---")
Serial.print("J");
else if (prevodilac=="-*-")
Serial.print("K");
else if (prevodilac=="*-**")
Serial.print("L");
else if (prevodilac=="--")
Serial.print("M");
else if (prevodilac=="-*")
Serial.print("N");
else if (prevodilac=="---")
Serial.print("O");
else if (prevodilac=="*--*")
Serial.print("P");
else if (prevodilac=="--*-")
Serial.print("Q");
else if (prevodilac=="*-*")
Serial.print("R");
else if (prevodilac=="***")
Serial.print("S");
else if (prevodilac=="-")
Serial.print("T");
else if (prevodilac=="**-")
Serial.print("U");
else if (prevodilac=="***-")
Serial.print("V");
else if (prevodilac=="*--")
Serial.print("W");
else if (prevodilac=="-**-")
Serial.print("X");
else if (prevodilac=="-*--")
Serial.print("Y");
else if (prevodilac=="--**")
Serial.print("Z");

else if (prevodilac=="*----")
Serial.print("1");
else if (prevodilac=="**---")
Serial.print("2");
else if (prevodilac=="***--")
Serial.print("3");
else if (prevodilac=="****-")
Serial.print("4");
else if (prevodilac=="*****")
Serial.print("5");
else if (prevodilac=="-****")
Serial.print("6");
else if (prevodilac=="--***")
Serial.print("7");
else if (prevodilac=="---**")
Serial.print("8");
else if (prevodilac=="----*")
Serial.print("9");
else if (prevodilac=="-----")
Serial.print("0");
Serial.print(" ");

prevodilac="";
}
63) Arduino Insteon Gateway

COMPONENTS AND SUPPLIES

Arduino UNO & Genuino UNO × 1


Arduino Ethernet Rev. 3
× 1

Insteon PLM
× 1

Arduino wiring shield


× 1

Adafruit Standard LCD - 16x2


White on Blue
× 1

Power supply 12v 2A


× 1

Plastic enclosure
× 1
ABOUT THIS PROJECT

The project is about Home Automation. I have some


devices that are Insteon-based. Insteon uses a
proprietary protocol to make the devices communicate
wirelessly together, in a mesh topology.
Here are examples:
Dimmer Module,
On/off Module,
Dimmer Switch,
On/off Switch,
Dimmer Keypad (by 8 or by 6),
Thermostat,
Motion detector
The goal of this project is to build a gateway betwen
Insteon world and a generic MQTT broker, over IP
BUT without dependency to Insteon Cloud.
Features
Here are the features provided by the "Insteon
gateway":
Gather and publish statuses: Arduino will (over a
serial link to the PLM ) get info published by all
devices, display them on the front panel, convert
it to MQTT messages and send them to the
MQTT broker
Listen, push and execute commands: Arduino
will listen to specific MQTT queues (one per
targeted Insteon device, display the messages to
the front panel and push those commands to the
PLM (over serial link). PLM will transfer those
commands to the targeted devices.
SCHEMATICS
CODE

#include <ArduinoJson.h>
#include <avr/wdt.h>
#include <Ethernet.h>
#include <LiquidCrystal.h>
#include <Network.h>
#include <PubSubClient.h>
#include <QueueArray.h>
#include "SoftwareSerial.h"
#include <SPI.h>
#include <Timer.h>

// HW pinout
const int LCD_E_PIN PROGMEM = 2; // LCD
const int RESET_BTN_PIN PROGMEM = 3; //
goes to LOW when someone press on the button and then goes to HIGH
when button is released, otherwise pull-down to GND
const int SD_CARD_PIN PROGMEM = 4; // SD
card on ethernet shield, not used
const int LCD_DB4_PIN PROGMEM = 5; //
LCD
const int LCD_DB5_PIN PROGMEM = 6; //
LCD
const int LCD_DB6_PIN PROGMEM = 7; //
LCD
const int LCD_DB7_PIN PROGMEM = 8; //
LCD
const int LCD_RS_PIN PROGMEM = 9; //
LCD
const int INSTEON_TX PROGMEM = 16; // TX
to INSTEON PLM
const int INSTEON_RX PROGMEM = 17; // RX
from INSTEON PLM

// Network
const byte mac[] = { 0xDE, 0xED, 0xBE, 0xBB, 0xFC, 0xAC };
// Arduino's MAC address
IPAddress ip(192, 168, 1, 221); // Arduino's IP
address
IPAddress server(192, 168, 1, 100); // MQTT
broker's address (Orechestrator)
EthernetClient ethClient;

// MQTT
PubSubClient client(ethClient);
const int mqttInterval PROGMEM = 300; //
determines how often the system will report to MQTT broker (ie. every
mqttInterval * mainLoopDelay ms )
int mqttIntervalCnt = 0; // local variable
used to count down
int isConnectedToBroker = -1; // 1 when
connected, -1 = unknown, 0 = unable to connected
#define INSTEONGATEWAY "PLM"

// Insteon
SoftwareSerial InsteonSerial(INSTEON_RX, INSTEON_TX,
true); // This is what we use to send/receive Insteon commands
using the home automation shield
const int PLMtimeOut PROGMEM = 1000; // in
millisec
int inByte[26]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // for
storing incoming serial bytes
int outByte[26]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //
for storing ougoing serial bytes
const int zeroByte PROGMEM= 0x00; // I use
this because if I do "Serial.write (0);" instead I get a compile error
const int startByte PROGMEM = 0x02; // Every
Insteon message begins with this
const int msgLength PROGMEM = 30; // Used
to assign an expected length for the message... starts out high so that we
don't prematurely trigger an end-of-message
int i = 0; // Looping variable for
incoming messages
int j = 0; // Looping variable for
outgoing messages

// Display and log


const int mode PROGMEM = 1; // 0 =
normal, 1 = verbose
LiquidCrystal lcd (LCD_RS_PIN, LCD_E_PIN, LCD_DB4_PIN,
LCD_DB5_PIN ,LCD_DB6_PIN, LCD_DB7_PIN);
const int LCD_ROWS = 2;
const int LCD_COLUMNS = 16;

// Local queue
volatile QueueArray <byte> cmdQueue; // each
command received from MQTT broker is stored here
byte* incoming; // an incoming
message to route to Insteon network

// Manual RESET button


volatile boolean isResetRequested = 0; // this one
will change when button triggers an interrupt

// Logic
const int mainLoopDelay = 500; // a fixed
delay within main loop, in ms
void(* resetFunc) (void) = 0;

// Initialization
void setup()
{
wdt_disable(); // disable watchdog
Serial.begin(19200); // open console port
Serial.println(F("Begin of setup"));
pinMode(SD_CARD_PIN, OUTPUT); // always good
to disable it, if it was left 'on' or you need init time
digitalWrite(SD_CARD_PIN, HIGH); // to disable SD
card since we do not use it
pinMode (RESET_BTN_PIN, INPUT);
InsteonSerial.begin(19200); // open another serial
port for Insteon PLM
cmdQueue.setPrinter (Serial); // setup local queue
lcd.begin(LCD_COLUMNS, LCD_ROWS); // set up the
LCD's number of columns and rows:
testLCD(); // just a welcome message
client.setServer(server, 1883); // setup MQTT
client.setCallback(MQTTBrokerCallback);
Ethernet.begin(mac, ip); // setup network
Serial.print(F("Current IP is : "));
Serial.print(Ethernet.localIP());
Serial.print(F(" - MQTT broker IP is : "));
Serial.println(server);
enableInterruptOnResetButton(); // from here,
interrupts are trapped
subscribeToToDoLists(); // from here, callbacks
are trapped
delay(1500); // allow hardware to sort itself out
Serial.println(F("End of setup")); Serial.println();
}

// Main loop

void loop()
{
if (isResetRequested == 1) {resetAll();} // someone pressed the Reset
button

// Part 1 : deal with messages originating from Insteon PLM


while (InsteonSerial.available() > 0)
{
if (receiveMessageFromPLM() == 0) // message received and compliant
with message type definition
{
Serial.println();
if (inByte[1] == 0x50 && ( (inByte[8] & 0b11100000) == 192) &&
inByte[9] != 6 ) // we do not support all message types currently, just group
broadcast messages
{
displayInsteonGroupBroadcast();
routeGroupBroadcastMessageToBroker();
Serial.println();
}
else
{
Serial.println(F("Message type not currently supported.")); // See
http://www.madreporite.com/insteon/receiving.html
Serial.println();
}
};
};

// Part 2 : deal with messages originating from MQTT Broker. Those


messages are waiting in a local queue

while (!cmdQueue.isEmpty ())


{
if (parseMessage() == 0)
{
sendMessageToInsteonDevice();
};
}

// Part 3 : report device status to MQTT broker

if (mqttIntervalCnt == 0)
{
Serial.println(F("Reporting gateway status to MQTT Broker..."));
routeGatewayStatusMessageToBroker();
mqttIntervalCnt = mqttInterval;
Serial.println();
}
else
{
mqttIntervalCnt = mqttIntervalCnt - 1;
}
// Take some rest
delay(mainLoopDelay / 2 );
client.loop();
delay(mainLoopDelay / 2);
}

// Parse a message stored in the local queue

int parseMessage()
{
byte b;
int hex_digit_to_read = 2;
bool reading_hex = true;
byte hex = 0;
for(int j=0;j<26;j++) outByte[j] = 0xFF;
while (!cmdQueue.isEmpty ())
{
b = cmdQueue.dequeue();
if (b == ':') // delimiter between each set of 2 characters
{
hex = 0;
hex_digit_to_read = 2;
reading_hex = true;
continue;
};
if (hex_digit_to_read > 0)
{
hex = (hex << 4) | CharToHex(b);
hex_digit_to_read--;
};
if (reading_hex && hex_digit_to_read == 0)
{
reading_hex = false;
if (hex == 0x02) // end of message
{
hex_digit_to_read = 2;
reading_hex = true;
hex = 0;
j = 0;
return 0;
}
else
{
outByte[j] = hex;
Serial.print(hex, HEX);
Serial.print(' ');
j++;
};
};
};
}
// Send commands to Insteon devices

int sendMessageToInsteonDevice()
{
Serial.print(F("Sending command to Insteon devices : "));
sendCmd(2, false);
sendCmd(98, false);
sendCmd(outByte[1], true);
sendCmd(outByte[2], true);
sendCmd(outByte[3], true);
sendCmd(15, false);
sendCmd(outByte[4], false);
sendCmd(outByte[5], false);
Serial.println();
}

void sendCmd(byte b, bool isHex)


{
if (isHex) { Serial.print(b, HEX); } else { Serial.print(b); };
Serial.print(F("-"));
InsteonSerial.write(b);
}

// Gather bytes sent by Insteon PLM in order to get a well structured


message

int receiveMessageFromPLM()
{
long start_time = millis();
int currentIndex = 0;
for(int j=0;j<26;j++) inByte[j] = 0;
byte currentByte;
while (true)
{
if ((millis() - start_time) > PLMtimeOut) // we should get a complete
message in a short period of time
{
displayError1();
return 1;
};
if (InsteonSerial.available() > 0)
{
if (currentIndex == 0)
{
Serial.print(F("### New message entering : "));
}
currentByte = InsteonSerial.read();
inByte[currentIndex] = currentByte;
displayRawData(currentByte);
if (currentIndex == 0 && currentByte != startByte) // a new message
should always start with the specified start byte
{
// displayError2(currentByte);
return 2;
};
if (currentIndex > 11) // message looks longer than expected
{
return 4;
};
if (currentIndex == 10) // message has been received as expected
{
return 0; // full message received
};
currentIndex = currentIndex + 1; // just keep going with parsing
};
};
}

// Route a command issued by MQTT Broker to Insteon devices

void routeGroupBroacastToInsteon()
{
// displayInsteonOutgoingGroupBroadcast();
for (int i=0;i<26;i++)
{
if ( outByte[i] == 0xFF) { break;}
Serial.print(InsteonSerial.write(outByte[i]));
}
}

// Reset button management

void resetAll()
{
Serial.println(F("Someone pushed on the button to reset this device"));
displayInfo("Reset requested");
routeGatewayStatusMessageToBroker();
wdt_enable(WDTO_1S); //enable watchdog, will fire in 1 second
delay(5000);
Serial.println(F("This message should never appear... unless this board is a
zombie"));
}
void enableInterruptOnResetButton()
{
isResetRequested = 0;
attachInterrupt(1, onResetRequested, CHANGE);
}
void onResetRequested()
{
detachInterrupt(1);
isResetRequested = 1;
}

//
// MQTT related functions
//
// NOTE : MQTT_MAX_PACKET_SIZE = 128 bytes.. therefore not more
than 100 for the payload !!!!!!!
// unless you change it in
/Arduino/libraries/pubSubClient/src/PubSubClient.h

// Route broadcasts to MQTT broker (topic = GLI/XX-YY-ZZ/WhishList)

void routeGroupBroadcastMessageToBroker()
{
char topic[30];
strcpy(topic, "GLI");
strcat(topic, "/");
strcat(topic, byteToHexaString(inByte[2]));
strcat(topic, "-");
strcat(topic, byteToHexaString(inByte[3]));
strcat(topic, "-");
strcat(topic, byteToHexaString(inByte[4]));
strcat(topic,"/");
strcat(topic, "WhishList");
char payload[100];
strcpy(payload, "{");
strcat(payload,"\n");
strcat(payload,"\"Group\": ");
strcat(payload, byteToString(inByte[7]));
strcat(payload, ",");
strcat(payload,"\n");
strcat(payload,"\"Command\": ");
strcat(payload, byteToHexaString(inByte[9]));
strcat(payload, ",");
strcat(payload,"\n");
strcat(payload,"\"Parameters\": ");
strcat(payload, byteToString(inByte[10]));
strcat(payload,"\n");
strcat(payload,"}");
publishMsg( topic, payload);
}

// Route gateway status to MQTT broker (topic = GLI/Gateway/Status)

void routeGatewayStatusMessageToBroker()
{
char topic[30];
strcpy(topic, "GLI");
strcat(topic, "/");
strcat(topic, "Gateway");
strcat(topic,"/");
strcat(topic, "Status");
char payload[100];
strcpy(payload, "{");
strcat(payload,"\n");
strcat(payload,"\"ManualReset\": ");
strcat(payload,"\n");
if (isResetRequested == 1) { strcat(payload, "Yes");} else {strcat(payload,
"No");};
strcat(payload,"\n");
strcat(payload, ",");
strcat(payload,"\n");
strcat(payload,"\"LocalQueueLevel\": ");
// strcat(payload, intToString(cmdQueue.count));
strcat(payload,"}");
publishMsg( topic, payload);
}

// Subscribe to the MQTT broker to get list of commands to forward to


Insteon devices (topic = GLI/Gateway/ToDo)

void subscribeToToDoLists()
{
if (connectToBroker() == true)
{
char topic[50];
strcpy(topic, "GLI");
strcat(topic, "/");
strcat(topic, "Gateway");
strcat(topic,"/");
strcat(topic, "ToDo");
client.subscribe(topic); // otherwise subscriptions will growth
forever..
if (client.subscribe(topic) == true)
{
isConnectedToBroker = 1;
Serial.print(F("Registred to MQTT broker as a subscriber for the following
topic: "));
Serial.println(topic);
}
else
{
Serial.println(F("Not registred to MQTT broker as a subscriber"));
isConnectedToBroker = 0;
}
client.loop();
}
else
{
isConnectedToBroker = 0;
Serial.println(F("Cannot subscribe to any topic since connection to MQTT
broker is not established"));
}
}

// This function will be invoked by MQTT broker each time a message is


added to GLI/Gateway/ToDo queue

void MQTTBrokerCallback(char* subscribedTopic, byte* payload,


unsigned int msgLength)
{
Serial.print(F("New message received from MQTT broker. Topic = "));
Serial.print(subscribedTopic);
Serial.print(F(", Length = "));
Serial.println(msgLength);
cmdQueue.enqueue('0');
cmdQueue.enqueue('2');
for (int i=0;i<msgLength;i++)
{
cmdQueue.enqueue(payload[i]); // store msg in local Queue
}
Serial.println();
}

// Report to MQTT broker

void publishMsg(const char* topic, const char* payload)


{
if (connectToBroker() == true)
{
if (client.publish( topic, payload ) == true)
{
isConnectedToBroker = 1;
Serial.print(F("Message sent to MQTT broker using the following topic "));
Serial.println(topic);
}
else
{
Serial.print(F("Message NOT sent to MQTT broker using the following
topic "));
Serial.println(topic);
isConnectedToBroker = 0;
}
client.loop();
}
}

// Manage connection with MQTT broker

int connectToBroker()
{
// Serial.println(F(""));
// Serial.print(F("Connecting to network and to MQTT Broker... "));
if (client.connect(INSTEONGATEWAY) == true)
{
// Serial.print(F("connected as "));
// Serial.println(INSTEONGATEWAY);
}
else
{
switch (client.state())
{
case -4:
Serial.println(F("MQTT_CONNECTION_TIMEOUT - the server didn't
respond within the keepalive time"));
break;
case -3:
Serial.println(F("MQTT_CONNECTION_LOST - the network connection
was broken"));
break;
case -2:
Serial.println(F("MQTT_CONNECT_FAILED - the network connection
failed"));
break;
case -1:
Serial.println(F("MQTT_DISCONNECTED - the client is disconnected
cleanly"));
break;
case 0:
break;
case 1:
Serial.println(F("MQTT_CONNECT_BAD_PROTOCOL - the server
doesn't support the requested version of MQTT"));
break;
case 2:
Serial.println(F("MQTT_CONNECT_BAD_CLIENT_ID - the server
rejected the client identifier"));
break;
case 3:
Serial.println(F("MQTT_CONNECT_UNAVAILABLE - the server was
unable to accept the connection"));
break;
case 4:
Serial.println(F("MQTT_CONNECT_BAD_CREDENTIALS - the
username/password were rejected"));
break;
case 5:
Serial.println(F("MQTT_CONNECT_UNAUTHORIZED - the client was
not authorized to connect"));
break;
default:
Serial.print("failed, rc=");
Serial.println(client.state());
break;
}
}
return client.connected();
}

//
// LCD management
//

void displayInsteonGroupBroadcast()
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print('G');
lcd.setCursor(2,0);
lcd.print(inByte[2], HEX);
lcd.print('-');
lcd.print(inByte[3], HEX);
lcd.print('-');
lcd.print(inByte[4], HEX);
lcd.setCursor(0,1);
lcd.print("CMD");
lcd.setCursor(5,1);
lcd.print(inByte[9], HEX);
lcd.setCursor(8,1);
lcd.print("TO ");
lcd.setCursor(11,1);
lcd.print(inByte[7]);
delay(1000);
}

void displayInsteonOutgoingGroupBroadcast( const char* cmd, const char*


dest, const char* parms )
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print('I');
lcd.setCursor(2,0);
lcd.print('MQTT BROKER');
lcd.print("CMD");
lcd.setCursor(5,1);
lcd.print(cmd);
lcd.setCursor(8,1);
lcd.print("TO ");
lcd.setCursor(11,1);
lcd.print(dest);
delay(1000);
}
void displayBrokerMessage()
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print('X');
delay(500);
}
void displayError(const String& code, const String& message)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print('E');
lcd.setCursor(0,2);
lcd.print(code);
lcd.setCursor(0,1);
lcd.print(message);
delay(500);
}
void displayInfo(const String& info)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print(info);
delay(500);
}
void testLCD()
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Hello PHSA !");
delay(500);
}
void displayRawData(byte b)
{
if (mode == 1)
{
Serial.print(F("["));
Serial.print(b, HEX);
Serial.print(F("]"));
};
}
void displayError1()
{
if (mode == 1)
{
Serial.print(F("An error (type 1) has occured while parsing message from
PLM : communication has timed out"));
};
displayError("1","Parsing");
}
void displayError2(byte currentByte)
{
if (mode == 1)
{
Serial.print(F("An error (type 2) has occured while parsing message from
PLM : ["));
Serial.print(currentByte, HEX);
Serial.println(F("] skipped since it does not start with 0x20 as per the
standard"));
};
displayError("2","Structure");
}

// Utility functions

char* byteToHexaString(byte b)
{
char buff[4];
snprintf(buff, 4, "%02X", b);
return buff;
}

char* byteToString(byte b)
{
char buff[4];
snprintf(buff, 4, "%d", b);
return buff;
}

char* intToString(int i)
{
char buff[4];
snprintf(buff, 4, "%d", i);
return buff;
}

int doubleBytesToInt(byte high_byte, byte low_byte)


{
return high_byte * 256 + low_byte;
}
int StrToHex(char str[])
{
return (int) strtol(str, 0, 16);
}

byte CharToHex(char c)
{
byte out = 0;
if( c >= '0' && c <= '9'){
out = (byte)(c - '0');
}
else if ( c >= 'A' && c <= 'F'){
out = (byte) (c - 'A') + 10;
}
else if ( c >= 'a' && c <= 'f'){
out = (byte) (c - 'a') + 10;
}

return out;
}
64) Arduino Monitorning the Fill Height of Paper
Shredder

COMPONENTS AND SUPPLIES


Arduino UNO & Genuino
UNO
× 1

PHPoC Shield for Arduino × 1


Ultrasonic Sensor - HC-SR04
× 1

Jumper wires (generic)

ABOUT THIS PROJECT

ntroduction
In this tutorial, I am going to show you how to detect
the fullness of a paper shredder and send a notification
via Gmail using Arduino Uno.
I made this tutorial for beginners! It is really easy!
Detecting the Fill Height of Paper Shredder
Ultrasonic Sensor - HC-SR04 is used to detect the
fullness of paper shredder. When the distance between
sensor and paper trash is at a threshold, paper shredder is
considered to be full.
Handling Event
In this project, when an event occurs, a notification is
sent via Gmail.
SCHEMATICS

Assembly
Assembly
1. Stack PHPoC Shield on Arduino
2. Connect LAN cable or USB wifi Dongle to the
shield for Ethernet
3. Pin wiring between Arduino and Sensor.
Pin wiring between Arduino and Sensor
All system
CODE

#define PIN_TRIG 5
#define PIN_ECHO 6
#define BIN_HEIGHT 20 // maximum containable height of bin in
centimeters

#include "SPI.h"
#include "Phpoc.h"

long ultrasonicGetDistance();
boolean dustbinSendGmail();

PhpocEmail email;
boolean isSent = false;
void setup() {
Serial.begin(9600);
while(!Serial)
;
pinMode(PIN_TRIG, OUTPUT);
pinMode(PIN_ECHO, INPUT);

Phpoc.begin(PF_LOG_SPI | PF_LOG_NET | PF_LOG_APP);

void loop() {
long distance = 0;
// read 10 time and get average value to eliminate noises
for(int i = 0; i < 100; i++)
{
long temp = 0;
do
{
temp = ultrasonicGetDistance();
}
while(temp > BIN_HEIGHT);

distance += temp;
delay(10);
}
distance /= 100;

Serial.print(distance);
Serial.println(" cm");

if(distance <= 5)
{
if(!isSent)
{
Serial.println("Dustbin is almost full");
isSent = dustbinSendGmail();
}
}
else if(isSent && distance > 8) // avoid send alot of email when the distance
is oscillated around 5cm
isSent = false;

delay(500);
}

long ultrasonicGetDistance(){
long duration, distance;
digitalWrite(PIN_TRIG, LOW);
delayMicroseconds(2);
digitalWrite(PIN_TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(PIN_TRIG, LOW);
duration = pulseIn(PIN_ECHO, HIGH);
distance = (duration/2) / 29.1;
return distance;
}

boolean dustbinSendGmail(){
// setup outgoing relay server - gmail.com
email.setOutgoingServer("smtp.gmail.com", 587);
email.setOutgoingLogin("your_login_id", "your_login_password");

// setup From/To/Subject
email.setFrom("from_email_address", "from_user_name");
email.setTo("to_email_address", "to_user_name");

email.setSubject("Your dustbin is almost full");

// write email message


email.beginMessage();
email.println("Location: Planet Earth.");
email.println("");
email.println("Your dustbin is almost full.");
email.println("");
email.println("Prepare to through it out.");
email.endMessage();

// send email
if(email.send() > 0)
{
Serial.println("Email send ok");
return true;
}
else
{
Serial.println("Email send failed");
return false;
}
}

65) Arduino 4 Digit 7 Segment Counter with Lipo


Backup
COMPONENTS AND SUPPLIES

Arduino UNO & Genuino UNO


× 1

General Purpose Transistor NPN


I used 2N3904 × 4
Resistor 100 ohm × 7

Resistor 10k ohm


× 4

One Channel Relay Module


Board Shield × 1
Relay
Adafruit 4 Digit 7 Segment LED
Display, 1.2" Yellow, Common
Cathode
Just a standard relay from × 1
Amazon\Ebay, +5V signal with
open connection when there is
no signal
Adafruit Powerboost 500C
× 1

Battery, 3.7 V
LiPo Battery 18650, 3000mAH × 1
ABOUT THIS PROJECT

I needed a counter at work and currently have a habit of


making things with bright LEDs.
So I came up with this.
It uses a large 4-digit 7-segment display, an Adafruit
PowerBoost 500C for LiPo battery backup and an
Arduino Uno. A relay turns off the display when on
battery, there is an option to override this (using black
button).
The PCB is just a prototype board, I dont have time for
etching, it's housed in a perspex case.
The controls are to increment the count by +1, +10 and
+100, decrement by -1, reset to 0, turn of the display and
LEDs to power save when on battery and turn off the
unit.
SCHEMATICS
CODE
#define button A0 // +1
#define button_minus A1 // -1
#define button_10 A2 // +10
#define button_100 A3 // +100
#define button_reset A4 // reset

// common pins of the four digits definitions


#define Dig1 2
#define Dig2 3
#define Dig3 4
#define Dig4 5
// segment pin definitions
#define SegA 6
#define SegB 7
#define SegC 8
#define SegD 9
#define SegE 10
#define SegF 11
#define SegG 12
// A=10 :

// variable declarations
byte current_digit;
int count = 0;

void setup()
{
pinMode(button, INPUT_PULLUP);
pinMode(button_minus, INPUT_PULLUP);
pinMode(button_10, INPUT_PULLUP);
pinMode(button_100, INPUT_PULLUP);
pinMode(button_reset, INPUT_PULLUP);
pinMode(SegA, OUTPUT);
pinMode(SegB, OUTPUT);
pinMode(SegC, OUTPUT);
pinMode(SegD, OUTPUT);
pinMode(SegE, OUTPUT);
pinMode(SegF, OUTPUT);
pinMode(SegG, OUTPUT);
pinMode(Dig1, OUTPUT);
pinMode(Dig2, OUTPUT);
pinMode(Dig3, OUTPUT);
pinMode(Dig4, OUTPUT);

disp_off(); // turn off the display

// Timer1 module overflow interrupt configuration


TCCR1A = 0;
TCCR1B = 1; // enable Timer1 with prescaler = 1 ( 16 ticks each 1 µs)
TCNT1 = 0; // set Timer1 preload value to 0 (reset)
TIMSK1 = 1; // enable Timer1 overflow interrupt

}
ISR(TIMER1_OVF_vect) // Timer1 interrupt service routine (ISR)
{
disp_off(); // turn off the display

switch (current_digit)
{
case 1:
if (count >= 1000)
{
disp(count / 1000); // prepare to display digit 1 (most left)
digitalWrite(Dig1, HIGH); // turn on digit 1
}
break;

case 2:
if (count >= 100)
{
disp( (count / 100) % 10); // prepare to display digit 2
digitalWrite(Dig2, HIGH); // turn on digit 2
}
break;

case 3:
if (count >= 10)
{
disp( (count / 10) % 10); // prepare to display digit 3
digitalWrite(Dig3, HIGH); // turn on digit 3
}
break;

case 4:
disp(count % 10); // prepare to display digit 4 (most right)
digitalWrite(Dig4, HIGH); // turn on digit 4
}

current_digit = (current_digit % 4) + 1;
}

// main loop
void loop()
{
if(digitalRead(button) == 0)
{
count++; // increment 'count' by 1
if(count > 9999)
count = 0;
delay(200); // wait 200 milliseconds
}
else if(digitalRead(button_minus) == 0)
{
count--; // decrement 'count' by 1
if(count < 0)
count = 9999;
delay(200); // wait 200 milliseconds
}
else if(digitalRead(button_10) == 0)
{
count=count+10; // increment by 10
if(count > 9999)
count = 0;
delay(200); // wait 200 milliseconds
}
else if(digitalRead(button_100) == 0)
{
count=count+100; // increment by 100
if(count > 9999)
count = 0;
delay(200); // wait 200 milliseconds
}
else if(digitalRead(button_reset) == 0)
{
count=0; // reset
delay(200); // wait 200 milliseconds
}
}

void disp(byte number)


{
switch (number)
{
case 0: // print 0
digitalWrite(SegA, HIGH);
digitalWrite(SegB, HIGH);
digitalWrite(SegC, HIGH);
digitalWrite(SegD, HIGH);
digitalWrite(SegE, HIGH);
digitalWrite(SegF, HIGH);
digitalWrite(SegG, LOW);
break;

case 1: // print 1
digitalWrite(SegA, LOW);
digitalWrite(SegB, HIGH);
digitalWrite(SegC, HIGH);
digitalWrite(SegD, LOW);
digitalWrite(SegE, LOW);
digitalWrite(SegF, LOW);
digitalWrite(SegG, LOW);
break;

case 2: // print 2
digitalWrite(SegA, HIGH);
digitalWrite(SegB, HIGH);
digitalWrite(SegC, LOW);
digitalWrite(SegD, HIGH);
digitalWrite(SegE, HIGH);
digitalWrite(SegF, LOW);
digitalWrite(SegG, HIGH);
break;

case 3: // print 3
digitalWrite(SegA, HIGH);
digitalWrite(SegB, HIGH);
digitalWrite(SegC, HIGH);
digitalWrite(SegD, HIGH);
digitalWrite(SegE, LOW);
digitalWrite(SegF, LOW);
digitalWrite(SegG, HIGH);
break;

case 4: // print 4
digitalWrite(SegA, LOW);
digitalWrite(SegB, HIGH);
digitalWrite(SegC, HIGH);
digitalWrite(SegD, LOW);
digitalWrite(SegE, LOW);
digitalWrite(SegF, HIGH);
digitalWrite(SegG, HIGH);
break;

case 5: // print 5
digitalWrite(SegA, HIGH);
digitalWrite(SegB, LOW);
digitalWrite(SegC, HIGH);
digitalWrite(SegD, HIGH);
digitalWrite(SegE, LOW);
digitalWrite(SegF, HIGH);
digitalWrite(SegG, HIGH);
break;

case 6: // print 6
digitalWrite(SegA, HIGH);
digitalWrite(SegB, LOW);
digitalWrite(SegC, HIGH);
digitalWrite(SegD, HIGH);
digitalWrite(SegE, HIGH);
digitalWrite(SegF, HIGH);
digitalWrite(SegG, HIGH);
break;

case 7: // print 7
digitalWrite(SegA, HIGH);
digitalWrite(SegB, HIGH);
digitalWrite(SegC, HIGH);
digitalWrite(SegD, LOW);
digitalWrite(SegE, LOW);
digitalWrite(SegF, LOW);
digitalWrite(SegG, LOW);
break;

case 8: // print 8
digitalWrite(SegA, HIGH);
digitalWrite(SegB, HIGH);
digitalWrite(SegC, HIGH);
digitalWrite(SegD, HIGH);
digitalWrite(SegE, HIGH);
digitalWrite(SegF, HIGH);
digitalWrite(SegG, HIGH);
break;

case 9: // print 9
digitalWrite(SegA, HIGH);
digitalWrite(SegB, HIGH);
digitalWrite(SegC, HIGH);
digitalWrite(SegD, HIGH);
digitalWrite(SegE, LOW);
digitalWrite(SegF, HIGH);
digitalWrite(SegG, HIGH);
}
}

void disp_off()
{
digitalWrite(Dig1, LOW);
digitalWrite(Dig2, LOW);
digitalWrite(Dig3, LOW);
digitalWrite(Dig4, LOW);
}

// end of code.
66) Arduino Wireless Weather Station
COMPONENTS AND SUPPLIES
Arduino UNO & Genuino UNO
× 1

M1201 step down converter DC-


DC 3-40V to 1.25-35V × 1

Mini-360 step down converter × 1


DC-DC 4.75V-23V to 1V-17V
DHT11 Temperature &
Humidity Sensor (4 pins)
× 1

Carbon Monoxide (CO) Sensor -


MQ-7 × 1

Espressif ESP8266 ESP-12E


× 1

SparkFun Logic Level Converter


- Bi-Directional
× 1

5V Low Level Trigger 1 Channel


Relay Module × 1

SparkFun Pushbutton switch


12mm
× 1

Basic On/Off DC Switch × 1


LED (generic)
× 6

Buzzer
× 1

USB-A to Micro-USB Cable


× 1

1N4007 – High Voltage, High


Current Rated Diode
× 2

Resistor 10k ohm


× 3

Jumper wires (generic)


× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)

Hot glue gun (generic)

Electric file

Multimeter
APPS AND ONLINE SERVICES
Arduino IDE

ThingSpeak API

ABOUT THIS PROJECT


This project started off as a final assessment homework
for an university course I've followed this year, but
proved out to be a really fun and practical way of
learning new and interesting things about wireless
communication and microcontrollers in general.
The main idea:
The core of this project is an Arduino Uno developing
board which gathers data from two sensors:
DHT 11 - which is used for measuring temperature
and humidity levels
MQ-7 - which is used for measuring the CO level
in the air (ppm)
The data received from the sensors is then sent
to www.thingspeak.com by using an ESP8266 12-E
Wireless Module.
The components and their role:
M1201 step down buck converter (#2)
This component is needed to step down the voltage
from 5V to 1.4V. The 1.4V are then used to power up the
MQ-7 gas sensor for a period of 90s, the so called
"reading period". (check MQ-7 datasheet for more info
on the operation principle)
Note: The one that I had couldn't go down
to 1.4V (although it should have) so I've used 2 more
diodes to lower the voltage (check the schematics)
Mini-360 step down buck converter (#3)
This component is needed to step down the voltage
from 5V to 3.3V. You can as well see it as the
main 3.3V power supply in the system. The 3.3V are
used to power up the ESP8266 12-E Wi-Fi module, as
well as the low side of the logic level shifter.
The ESP8266 12-E is a Wi-Fi module which is
powered at 3.3V, NOT 5V. Powering it at 5V will
permanently damage the module!
The ESP8266 draws more than 200mA of current
while operating and sending values to the web
server. Powering it from Arduino's 3.3V power pin
would be a big mistake as Arduino cannot provide
that much current, thus making the Wi-Fi module
unstable.
SRD-05VDC-SL-C 5V 1 Channel Relay Module(#8)
This relay is directly connected on the powering line of
the MQ-7 CO gas sensor and has the role of cycling
between 1.4V for 90S and 5V for 60s. Why so? Well
according to the MQ-7 datasheet you have to heat up the
sensor for 90s@5V. Only after the heating cycle you can
read the sensor values for the next 60s@1.4V.
Note: See the MQ-7 datasheet for mor info on this
Logic level shifter 5V - 3.3V (#7)
Since the Arduino Uno runs at 5V and the ESP8266 12-
E runs at 3.3V the logic levels are quite different
between the two components. Thus, when trying to
"speak" with the ESP8266 by using the RX,TX (serial
communication) ports on the Arduino Uno we need a
logic level shifter to do so. This component does exactly
what we need: shifts the logic levels from 5V to 3.3V.
Check the image (fig. 1) bellow for a visual
representation of the different logic levels.
Same thing could also be done way cheaper by
directly connecting the RX line between the two
components, while using a voltage divider on the
TX line of the Arduino Uno. For more info on this
check the following link:
http://jamesreubenknowles.com/level-shifting-
stragety-experments-1741
fig. 1
Wi-Fi ESP8266 E-12 Wi-Fi module (#6)
I guess it's pretty obvious what this part is used for and
that's connecting to a local Wi-Fi network
(preconfigured in the source code) and sending the
sensor data to www.thingspeak.com
On/Off Switch (#10)
It seems that one cannot upload a new source code file
on the Arduino Uno while having the TX pin connected
to another component. If you try to do so you would get
a lot of errors in Arduino IDE. While uploading a new
sketch the TX pin should be "floating". To do so, I've
used a on/off switch to disconnect the TX line from the
ESP8266 whenever I want to upload an new code on the
board. (check schematics down bellow)
MQ-7 Gas Sensor (#5)
Used for reading the CO level in the air. The value
provided is measured in ppm.
As stated earlier check the datasheet to see the
working principle. The sensor needs to be powered
for 90s@5v, time during which no reading is done,
and 60s@1.4V, time which represents the reading
period.
Check the datasheet for info on calibrating the
sensor.
Reset button (#9)
Since the hole wiring will be hidden inside a box a the
end of this project, with the Arduino Uno stuck with hot
glue at the bottom of box, uploading a new sketch on the
board it would pose quite a problem when it comes to
physically reseting the board without opening the box.
To solve this issue we would need an external reset
button. That's exactly what this big red button does. It
resets the board.
The LED's (#9)
11 - general error indicator (for debugging the error
we would need to connect the board to a pc and
check the Serial Monitor Interface in Arduino IDE
for the error message)
12 - signals the presence/absence of the ESP8266
in the current system
13 - signals if ESP8266 is connected/not connected
to the local network
14 - signals sending sensor data tot thingspeak.com
15 - blinks whenever the MQ-7 is heating
16 - blinks whenever Arduino Uno reads data from
sensors
The Buzzer
Whenever the CO level read from the MQ-7 gas sensor
exceeds a certain value hardcoded in the code, an alarm
will be triggered by using the buzzer.
Software requirements:
In order to see the value of sensor data, we will need a
private channel on thingspeak.com. We will also need
Arduino IDE to write/upload the code for Arduino Uno.
List of software requirements:
Private channel on Thingspeak.com and
Arduino IDE (Preferably latest version).
In order for the sketch to work we will also need the
DHT11 library which you can download in the
attachment section down bellow. For a step by step
tutorial on how to add this library to
Now lets create a private channel on thingspeak.com
Creating private channel on Thingspeak.com
To make a private channel on thingspeak.com follow
these steps:
Open your web browser and go to thingspeak.com
and click on 'Sign Up' tab in right top corner,
(Image no.1)
Fill in the details and click on 'Create account',
(Image no.2)
Now click on 'New Channel' tab, (Image no.3)
Again fill in details for channel and enable 4 fields
(as we will be sending 4 sensor values), scroll
down and click on 'Save Channel' tab, (Image
no.4/5)
On this page click on 'API Keys' tab and note down
your 'Write API Key'.
That's all folks, now you have your private ThingSpeak
channel. Now lets put all electronics component
together.
The Code
The code for Portable weather station is quite simple. I
have commented code properly for ease of
portability. Before you burn the code take care of
following things.
Make sure that all libraries are installed,
Replace hyphens (--------) with SSID of your
access point (wifi router) in line 14 of the code,
Replace hyphens (--------) with PASSWORD of
your wifi network in line 15 of the code,
Replace hyphens (--------) with your ThingSpeak's
private channel write API key in line 17 and
While uploading the code to the Arduino make
sure that the on/off switch on the TX line is set to
"off" so that you can upload the code
Now that we have our hardware and software in place,
only thing remaining is packaging.
The logic
If you find the code pretty difficult to understand take a
look on the logic diagram down bellow:
Logical Diagram
Blinking order
Packaging and enclosing the system
Down bellow you are going to find some useful photos
taken while I was preparing the enclosure for the system.
Make sure you have the tools required to make a box
like the one bellow (elecrtic file, soldering iron, hot glue
gun...)
As you can see in the third image above I've used
some generic "mother" type pins soldered together
for providing power/ground to the components of
the system. I've then hot glue the piece to the side
panel of the box, inside of it.
Results
You can check the results of this project by clicking on
the following link which should redirect you to the
public view of my thingspeak
channel: https://thingspeak.com/channels/152176
Plotted data
Problems encountered during development
Sometimes some parts of the system went
unresponsive due to poor contact on the
breadboard. If the ESP8266 becomes unresponsive
out of a sudden, first thing I would suggest doing
would be to check the connections once again
If you see a lot of garbage in the Serial Monitor
console make sure the baud rate in the console is
set accordingly with the ESP8266 settings.
For more info on changing the baud rate of the Serial
Montior console check the following
link: https://learn.adafruit.com/adafruit-arduino-lesson-
5-the-serial-monitor/other-things-to-do
For more info on changing the baud rate setting of the
ESP8266 check the following
link: http://www.esp8266.com/viewtopic.php?
f=13&t=718
Make sure you calibrate the MQ-7 sensor correctly
as if not you would receive some big measurement
errors
Future projects tips
DHT11 isn't quite precise, in the sense that it can
give random errors. A DHT22 sensor would prove
much more accurate, but it is also a little bit more
expensive than the DHT11
ESP8266 proved to be a little bit unstable during
the development phase. A ESP32 or a NodeMCU
board might be better for a future project
Some random photos taken during developing stage
SCHEMATICS
CODE
#include<stdlib.h>
#include "DHT.h"

//-----ESP8266 macros---------
#define SSID "------"//your network name
#define PASS "------"//your network password
#define IP "184.106.153.149" // thingspeak.com
#define Baud_Rate 9600 //Another common value is
115200
#define GREEN_LED 3 //optional LED's for debugging
#define RED_LED 4 //optional LED's for debugging
#define YELLOW_LED 5 //optional LED's for
debugging
#define ESP_FOUND_LED 6 //optional LED's for
debugging
#define DELAY_TIME 3000 //time in ms between
posting data to ThingSpeak

//Can use a post also


String GET = "GET /update?key=------";
//String FIELD1 = "&field1=";
String FIELD2 = "&field2=";
String FIELD3 = "&field3=";

bool updated;

//----Relay/MQ-7 macros
#define RELAY 8
#define MQ7_ANALOG_IN_PIN 0
#define HEATING_LED 9
#define READING_LED 10
#define BUZZER 11

#define MQ7_HEATER_5_V_TIME_MILLIS 60000


#define MQ7_HEATER_1_4_V_TIME_MILLIS 90000
#define GAS_LEVEL_READING_PERIOD_MILLIS
1000

unsigned long startMillis;


unsigned long switchTimeMillis;
unsigned int gasLevel;
boolean heaterInHighPhase;
//----Temperature sensor macros
#define DHTPIN 7 // what pin the DHT sensor is
connected to
#define DHTTYPE DHT11 // Change to DHT22 if
that's what you have

DHT dht(DHTPIN, DHTTYPE);

//this runs once


void setup()
{
//initalize DHT sensor
dht.begin();

//start the clock


startMillis = millis();

//initialize network LEDs


pinMode(GREEN_LED, OUTPUT);
pinMode(RED_LED, OUTPUT);
pinMode(YELLOW_LED, OUTPUT);
pinMode(ESP_FOUND_LED, OUTPUT);
//initialize MQ-7 LEDs
pinMode(HEATING_LED, OUTPUT);
pinMode(READING_LED, OUTPUT);
pinMode(BUZZER, OUTPUT);

//initialize MQ-7 power supply


pinMode(RELAY, OUTPUT);

//set baud rate


Serial.begin(Baud_Rate);
delay(1000);

//-----connect to network---------
Serial.println("Checking if ESP8266 is online...");
connectionStart:
Serial.println("AT");
delay(5000);

if (Serial.find("OK")) {
digitalWrite(ESP_FOUND_LED, HIGH);
Serial.println("ESP8266 found <module online>...");
Serial.println("Trying to connect to network...");
//connect to your wifi netowork
bool connected = false;

do {
networkBlinkConnecting();

connected = connectWiFi();

if (!connected) //signal failure


for (int i = 0; i < 3; i++)
networkBlinkError();
} while (!connected);

Serial.println("Connection achived....");
digitalWrite(YELLOW_LED, HIGH); // indicate
connection achived

} else {
Serial.println("ESP8266 not found...");
Error();
goto connectionStart;
}
}

//this runs over and over


void loop() {

if (heaterInHighPhase) {
// 5v phase of cycle. see if need to switch low yet
if (millis() > switchTimeMillis) {
Serial.println("Reading from sensors....");
turnHeaterLow();
}
blinkHeating();
}
else {
// 1.4v phase of cycle. see if need to switch high yet
if (millis() > switchTimeMillis) {
Serial.println("Heating the gas sensor....");
turnHeaterHigh();
}

// Read temperature and humidity


float h = dht.readHumidity();
float f = dht.readTemperature(false);
unsigned int gasLevel = readGasLevel();
blinkReading();

// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(f) || isnan(gasLevel)) {
networkBlinkError();
return;
}
else if (gasLevel >= 60) {
tone(BUZZER, 3000); // Send 1KHz sound signal...
}
else {
noTone(BUZZER); // Stop sound...
}

//update ThingSpeak channel with new values


updated = updateValues(String(f), String(h),
String(gasLevel));

//if update succeeded light up green LED, else light up


red LED
Serial.println(updated);
if (updated) {
networkBlinkSending();
} else {

networkBlinkError();
}

blinkReading();
}
}

//----network update function--------------


bool updateValues(String temp, String humid, String
gasLevel) {

//initialize your AT command string


String cmd = "AT+CIPSTART=\"TCP\",\"";

//add IP address and port


cmd += IP;
cmd += "\",80";
//connect
Serial.println(cmd);
delay(500);

if (Serial.find("Error")) {
return false;
}

//build GET command, ThingSpeak takes Post or Get


commands for updates, I use a Get
cmd = GET;
//cmd += FIELD1;
cmd += temp;
cmd += FIELD2;
cmd += humid;
cmd += FIELD3;
cmd += gasLevel;

cmd += "\r\n";

//Use AT commands to send data


Serial.print("AT+CIPSEND=");
Serial.println(cmd.length());
if (Serial.find(">")) {
//send through command to update values
Serial.print(cmd);
} else {
Serial.println("AT+CIPCLOSE");
}

if (Serial.find("OK")) {
//success! Your most recent values should be online.
return true;
} else {
return false;
}
}

//----network functions--------------
boolean connectWiFi() {
//set ESP8266 mode with AT commands
Serial.println("AT+CWMODE=1");
delay(2000);

//build connection command


String cmd = "AT+CWJAP=\"";
cmd += SSID;
cmd += "\",\"";
cmd += PASS;
cmd += "\"";

//connect to WiFi network and wait 5 seconds


Serial.println(cmd);
delay(5000);

//if connected return true, else false


if (Serial.find("OK")) {
return true;
} else {
return false;
}
}

void Error() {
networkBlinkError();
Serial.println("Error");
}
//----MQ-7 functions--------------

void blinkHeating() {
digitalWrite(HEATING_LED, HIGH);
delay(200);
digitalWrite(HEATING_LED, LOW);
delay(200);
}

void blinkReading() {
digitalWrite(READING_LED, HIGH);
delay(GAS_LEVEL_READING_PERIOD_MILLIS /
2);
digitalWrite(READING_LED, LOW);
delay(GAS_LEVEL_READING_PERIOD_MILLIS /
2);
}
//--read from gas sensor---------
unsigned int readGasLevel() {
return analogRead(MQ7_ANALOG_IN_PIN);
}
//----network LEDs--------

void networkBlinkSending() {
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, HIGH);
delay(500);
digitalWrite(GREEN_LED, LOW);
delay(500);
}

void networkBlinkError() {
digitalWrite(GREEN_LED, LOW);
digitalWrite(RED_LED, HIGH);
delay(200);
digitalWrite(RED_LED, LOW);
delay(200);
}

void networkBlinkConnecting() {
digitalWrite(YELLOW_LED, HIGH);
delay(200);
digitalWrite(YELLOW_LED, LOW);
delay(200);
}

//--- relay logic


void turnHeaterHigh() {
// 5v phase
digitalWrite(RELAY, HIGH);
heaterInHighPhase = true;
switchTimeMillis = millis() +
MQ7_HEATER_5_V_TIME_MILLIS;
}

void turnHeaterLow() {
// 1.4v phase
digitalWrite(RELAY, LOW);
heaterInHighPhase = false;
switchTimeMillis = millis() +
MQ7_HEATER_1_4_V_TIME_MILLIS;
}
67) Arduino Catch The Beat

COMPONENTS AND SUPPLIES

Arduino 101 & Genuino 101


× 1
Buzzer × 1

Rotary potentiometer (generic)


× 1

8x8 led matrix


× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT


This project is inspired in OSU!Catch the beat and this
game consist in catching the falling balls, you have 10
lives, you lose one for every ball you miss and you
recover two for every ball you catch getting one point.
Every four point the speed increases and you tun out of
lives the game ends.

How to do this project:


Step 1: Check Arduino connection.
Step 2: Copy and paste the code in new sketch of
Arduino IDE.
Step 3: Conect the led matrix, buzzer and
potentiometer to Arduino.
SCHEMATICS
CODE
int row[] = {2, 7, A5, 5, 13, A4, 12, A2};
int col[] = {6, 11, 10, 3, A3, 4, 8, 9};
int joystick = A0; //es un simple potenciometro
int lastUpdate;
int puntos = 0;
int vidas = 10;
int speakerPin = A1;
int speed = 16;
bool updatedAsteroid = false, updatedPlayer = true;

typedef struct coordenada {


int x; //cordenada de la columna
int y; //cordenada de la fila
}COORD;

COORD asteroid, jugador;

void setup() {
// put your setup code here, to run once:
for (int i = 0; i < 8; i++)
{
pinMode(row[i], OUTPUT);
pinMode(col[i], OUTPUT);
digitalWrite(col[i], HIGH);
digitalWrite(row[i], LOW);
}
pinMode(speakerPin, OUTPUT);
initGame();
Serial.begin(9600);
}

void loop() {
// put your main code here, to run repeatedly:
for(int i = 0; i < 2; i++)
{
clearScreen(); //limpia la matriz de leds
if(lastUpdate == 1) {
movePlayer();
}
if(lastUpdate == 0) {
asteroidFall();
//Serial.print("El asteroide cambia de posicion!!\n");
}
lastUpdate = Update(); //actualiza la matriz de leds
segun movePlayer() y asteroidFall()
delay(speed);
}
puntuacion(); //calcula la puntuacion y aumenta una vida
por punto, cuando el jugador se queda sin vidas se pasa a
gameover() para reiniciar la partida
if (asteroid.y == 8 || asteroid.y > 8) {
initasteroid(); //inizializa un nuevo asteroid cuando el
anterior ya ha caido
}
}

void initGame() {
vidas = 10;
puntos = 0;
speed = 16;
initplayer();
initasteroid();
return;
}

void initplayer() {
jugador.x = 3;
jugador.y = 7;
digitalWrite(col[jugador.y], HIGH);
digitalWrite(row[jugador.x], LOW);
return;
}

void initasteroid() {
asteroid.x = random(0, 7);
asteroid.y = -1; //para que asteroidFall() comienze en 0
nada mas ejecutarse
digitalWrite(col[asteroid.x], LOW);
digitalWrite(row[asteroid.y], HIGH);
return;
}

void movePlayer() {
int value = analogRead(joystick);
value = map(value, 0, 1023, 0, 7);
value = constrain(value, 0, 7);
//Serial.print("joystickX: ");
//Serial.print(jugador.x);
//Serial.print("\n");
if(value >= 0 && value <= 7) {
jugador.x = value;
}
return;
}

void asteroidFall() {
asteroid.y++;
//Serial.print("AsteroidY: ");
//Serial.print(asteroid.y);
//Serial.print("\n");
return;
}

void clearScreen() {
for (int led = 0; led < 8; led++)
{
digitalWrite(col[led], HIGH);
digitalWrite(row[led], LOW);
}
return;
}
int Update() {
if(updatedAsteroid == true && updatedPlayer == false)
{
digitalWrite(col[jugador.x], LOW);
digitalWrite(row[jugador.y], HIGH);
updatedAsteroid = false;
updatedPlayer = true;
//Serial.print("Jugador Actualizado!!\n");
return 0; //retorna que se ha actualizado el jugador
} else {
digitalWrite(col[asteroid.x], LOW);
digitalWrite(row[asteroid.y], HIGH);
updatedAsteroid = true;
updatedPlayer = false;
//Serial.print("Asteroid Actualizado!!\n");
return 1; //retorna que se ha actualizado el asteroide
}
}

void puntuacion() {
if(asteroid.y == jugador.y && asteroid.x == jugador.x) {
digitalWrite(speakerPin, HIGH);
puntos++;
delay(100);
digitalWrite(speakerPin, LOW);
vidas += 2;
if(speed > 9 && puntos >= 4) {
speed--; //aumenta la velocidad del juego (nivel nuevo)
puntos = 0; //reiniciamos la puntucion al pasar al
siguiente nivel
}
Serial.print("Puntos: ");
Serial.print(puntos);
Serial.print("\n");
}
if(asteroid.y == jugador.y && asteroid.x != jugador.x) {
vidas--;
Serial.print("Vidas: ");
Serial.print(vidas);
Serial.print("\n");
if(vidas == 0) {
gameover();
}
}
return;
}
void gameover() {
//animacion cuando pierdes la partida
for(int y = 0; y < 5; y++)
{
//Serial.print("Animacion: ");
//Serial.print(y);
//Serial.print("\n");
//bucle que apaga todos los leds de la matriz
digitalWrite(speakerPin, HIGH);
for(int i = 0; i < 8; i++)
{
digitalWrite(col[i], HIGH);
digitalWrite(row[i], LOW);
}
delay(500);
//bucle que enciende todos los leds de la matriz
for(int i = 0; i < 8; i++)
{
digitalWrite(col[i], LOW);
digitalWrite(row[i], HIGH);
}
digitalWrite(speakerPin, LOW);
delay(500);
}
delay(1000);
initGame(); //inicializa una nueva partida
return;
}

68) Arduino Safepools pH


COMPONENTS AND SUPPLIES
Arduino UNO & Genuino UNO
× 1

DFRobot pH Sensor DFRobot


× 1

SparkFun Bluetooth Modem -


BlueSMiRF Silver
× 1

Jumper wires (generic)


× 1

Temperature Sensor
× 1

9V to Barrel Jack Connector × 1


9V battery (generic)
× 1

NXP Hexiwear
× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)

Hot glue gun (generic)

Mini Plastic Container

ABOUT THIS PROJECT


The primary objective of this project is to use
Hexiwear to monitor the pH and temperature levels of
swimming pools.
Hexiwear Setup
The Hexiwear can be placed anywhere near the
bluetooth range of the Hardware Sensor. Using the
LCD screen, it displays the Temp and pH Sensor.
The Hexiware can be programmed to analyze the data
from sensors given the computation of Langelier
Saturation Index (LSI). Using the LSI we can
calculate if the pool is acidic, alkaline or
in normal level. The computation can also give
recommendations on how many chemicals to be put on
the water to stabilize the level.
Hardware Sensor Setup
The hardware station prototype is placed inside a 4.3”
x 1.9” rectangular plastic container and was created by
connecting an Arduino Uno R3 to a pH sensor,
temperature sensor, and Bluetooh Module. The power
source is connected through a USB cable and power
bank.
Field Test
We have tested the hardware sensor to Private, Public
and School Swimming Pool. Collecting the data from
these respondents' pool enabled us to analyze the
capability of the hardware.
School Pool

Photos from a private school swimming pool.


Results
We wanted to provide an automated swimming pool
water quality monitoring.
The development is still in progress. But we hope that
through this, may there will be an increased awareness
regarding the continuous degradation of the swimming
pool water quality as people tend to focus more on the
amenities that are offered instead of checking how
safe they are. They also intend to contribute to the
community by being able to provide a means to make
water quality testing more efficient and effective
without the unnecessary sacrifice of resources.
SCHEMATICS

Connect the sensors and bluetooth module using


jumper wires to the Arduino Uno.

Bluetooth module to RX/TX


Temp Sensor Output(Blue) to Analog 0, GND(Black)
to GND and V(Red) to 5V.
pH Sensor Output to Analog 1(Green), GND(Black) to
GND and V(Red) to 5V.
CODE
#include <SoftwareSerial.h>
#include <OneWire.h>
#include <DallasTemperature.h>

#define SensorPin A0 //pH meter Analog output


to Arduino Analog Input 0
#define Offset 0.00 //deviation compensate
#define LED 13
#define samplingInterval 20
#define printInterval 800
#define ArrayLenth 40 //times of collection
int pHArray[ArrayLenth]; //Store the average value of
the sensor feedback
int pHArrayIndex=0;

#define tempOffSet 0.00

#define DEBUG false


#define responseTime 20

#define ONE_WIRE_BUS 4 // Data wire is


plugged into port 2 on the Arduino
OneWire oneWire(ONE_WIRE_BUS); // Setup a
oneWire instance to communicate with any OneWire
//devices (not just Maxim/Dallas temperature ICs)
DallasTemperature sensors(&oneWire); // Pass our
oneWire reference to Dallas Temperature.

SoftwareSerial bluetoothSerial(2, 3); // RX, TX

void setup()
{

//setup RGB LED as indicator instead of softserial


pinMode(12,OUTPUT);
digitalWrite(12,HIGH);
// Open serial communications and wait for port to open:
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo
only
}
bluetoothSerial.begin(115200);
while (!bluetoothSerial) {
; // wait for serial port to connect. Needed for Leonardo
only
}
sendTobluetooth("AT+CWMODE=2",responseTime,DE
BUG); // configure as access point
sendTobluetooth("AT+CIFSR",responseTime,DEBUG);
// get ip address
sendTobluetooth("AT+CIPMUX=1",responseTime,DEB
UG); // configure for multiple connections
sendTobluetooth("AT+CIPSERVER=1,80",responseTim
e,DEBUG); // turn on server on port 80

sendToUno("Safepools.pH Hardware is
ready!",responseTime,DEBUG);

void loop()
{
///// Read pH Regularly //////
static unsigned long samplingTime = millis();
static unsigned long printTime = millis();
static float pHValue,voltage;
if(millis()-samplingTime > samplingInterval)
{
pHArray[pHArrayIndex++]=analogRead(SensorPin);
if(pHArrayIndex==ArrayLenth)pHArrayIndex=0;
voltage = avergearray(pHArray, ArrayLenth)*5.0/1024;
pHValue = 3.5*voltage+Offset;
samplingTime=millis();
}
if(Serial.available()>0){
String message = readSerialMessage();
if(find(message,"debugdebugBluetooth:")){
String result =
sendTobluetooth(message.substring(13,message.length()
),responseTime,DEBUG);
if(find(result,"OK"))
sendData("\nOK");
else
sendData("\nEr");
}
}
if(bluetoothSerial.available()>0){
String message = readbluetoothSerialMessage();

if(find(message,"debugBluetooth:")){
String result =
sendTobluetooth(message.substring(8,message.length()),
responseTime,DEBUG);
if(find(result,"OK"))
sendData("\n"+result);
else
sendData("\nATCE1001"); //At command
ERROR CODE for Failed Executing statement
}else
if(find(message,"getT")){
float temp = 0;
sensors.requestTemperatures(); // Send the
command to get temperatures
temp = sensors.getTempCByIndex(0);
sensors.requestTemperatures(); // Send the
command to get temperatures
temp = sensors.getTempCByIndex(0);
if(temp==85)
sendData("\nTE1001"); //Temperature
ERROR CODE for INITIALIZE
else if(temp==0 || temp==-127)
sendData("\nTE1002"); //Temperature
ERROR CODE for NOT CONNECTED
else{
String temperature = "";
temperature+=temp+tempOffSet;
sendData("\n"+temperature);
}
}else
if(find(message,"getP")){
//sending ph level:
if(pHValue==0){
sendData("\nPE1001"); //pH ERROR CODE
for NOT OPEN
}else{
String ph = "";
ph+=pHValue;
sendData("\n"+ph);
}
}else if(find(message,"pHOff")){
//sending ph level:
digitalWrite(12,0);
}else if(find(message,"pHOn")){
//sending ph level:
digitalWrite(12,1);
}
else{
sendData("\nErrRead"); //Command ERROR
CODE for UNABLE TO READ
}
}
delay(responseTime);
}

double avergearray(int* arr, int number){


int i;
int max,min;
double avg;
long amount=0;
if(number<=0){
Serial.println("Error number for the array to
avraging!/n");
return 0;
}
if(number<5){ //less than 5, calculated directly
statistics
for(i=0;i<number;i++){
amount+=arr[i];
}
avg = amount/number;
return avg;
}else{
if(arr[0]<arr[1]){
min = arr[0];max=arr[1];
}
else{
min=arr[1];max=arr[0];
}
for(i=2;i<number;i++){
if(arr[i]<min){
amount+=min; //arr<min
min=arr[i];
}else {
if(arr[i]>max){
amount+=max; //arr>max
max=arr[i];
}else{
amount+=arr[i]; //min<=arr<=max
}
}//if
}//for
avg = (double)amount/(number-2);
}//if
return avg;
}

/*
* Name: sendData
* Description: Function used to send string to tcp client
using cipsend
* Params:
* Returns: void
*/
void sendData(String str){
String len="";
len+=str.length();
sendTobluetooth("AT+CIPSEND=0,"+len,responseTime
,DEBUG);
delay(100);
sendTobluetooth(str,responseTime,DEBUG);
delay(100);
sendTobluetooth("AT+CIPCLOSE=5",responseTime,DE
BUG);
}

/*
* Name: find
* Description: Function used to match two string
* Params:
* Returns: true if match else false
*/
boolean find(String string, String value){
if(string.indexOf(value)>=0)
return true;
return false;
}
/*
* Name: readSerialMessage
* Description: Function used to read data from Arduino
Serial.
* Params:
* Returns: The response from the Arduino (if there is a
reponse)
*/
String readSerialMessage(){
char value[100];
int index_count =0;
while(Serial.available()>0){
value[index_count]=Serial.read();
index_count++;
value[index_count] = '\0'; // Null terminate the string
}
String str(value);
str.trim();
return str;
}
/*
* Name: readbluetoothSerialMessage
* Description: Function used to read data from
debugBluetooth Serial.
* Params:
* Returns: The response from the debugBluetooth (if
there is a reponse)
*/
String readbluetoothSerialMessage(){
char value[100];
int index_count =0;
while(bluetoothSerial.available()>0){
value[index_count]=bluetoothSerial.read();
index_count++;
value[index_count] = '\0'; // Null terminate the string
}
String str(value);
str.trim();
return str;
}
/*
* Name: sendTobluetooth
* Description: Function used to send data to
debugBluetooth.
* Params: command - the data/command to send;
timeout - the time to wait for a response; debug - print to
Serial window?(true = yes, false = no)
* Returns: The response from the debugBluetooth (if
there is a reponse)
*/
String sendTobluetooth(String command, const int
timeout, boolean debug){
String response = "";
bluetoothSerial.println(command); // send the read
character to the debugBluetooth
long int time = millis();
while( (time+timeout) > millis())
{
while(bluetoothSerial.available())
{
// The esp has data so display its output to the serial
window
char c = bluetoothSerial.read(); // read the next character.
response+=c;
}
}
if(debug)
{
Serial.println(response);
}
return response;
}

/*
* Name: sendTobluetooth
* Description: Function used to send data to
debugBluetooth.
* Params: command - the data/command to send;
timeout - the time to wait for a response; debug - print to
Serial window?(true = yes, false = no)
* Returns: The response from the debugBluetooth (if
there is a reponse)
*/
String sendToUno(String command, const int timeout,
boolean debug){
String response = "";
Serial.println(command); // send the read character to the
debugBluetooth
long int time = millis();
while( (time+timeout) > millis())
{
while(Serial.available())
{
// The esp has data so display its output to the serial
window
char c = Serial.read(); // read the next character.
response+=c;
}
}
if(debug)
{
Serial.println(response);
}
return response;
}

69) Arduino Water Level Monitor


COMPONENTS AND SUPPLIES

Arduino Nano R3
× 1
Resistor 1k ohm × 1

5 mm LED: Green
× 1

Solu SL067 Water Sensor


× 1

USB-A to Mini-B Cable


× 1

5 V DC, 500 mA Power Supply


× 1

Small Guage Wire for DC


Applications. × 1

Heat Shrink Tubing, Assorted


Sizes × 1

Pocket Solder- 60/40 Rosin Core × 1


0.031" diameter
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)

Heat Gun
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT


This project will demonstrate how to build a water
level monitor using an Arduino Nano, a Solu SL067
water level sensor, and an LED indicator. There are
many possible uses for this simple system, examples
include monitoring a sump pit (to control pump
activation), rainfall detection, leakage detection, or
monitoring plant water levels. I built this specifically
to monitor the water level of my Christmas tree.
Credit:

I have significantly modified the code from the link


above to use one LED with blink codes rather than the
three LEDs that were used in the original
development. I've also cleaned up the calibration
instructions to hopefully make this completely
understandable for a layman. You can simply assemble
the circuit, upload my sketch to your Arduino, and
follow the calibration requirements to have a
functional and reliable water level monitor. Minimal
programming knowledge is needed to modify my
sketch to suit your needs.
**NOTE - I have only been using this for a few days,
and do not know how well the sensor will hold up.
There is potential for corrosion, and it's possible that a
piece of debris (wet pine needle) could short two
traces and give a false reading. I strongly recommend
that you visually confirm your water level until you
are confident that the sensor will continue to work as
desired. I will continue to verify sensor operation
every few days, but this helps to avoid the necessity to
move gifts and tree skirt every day to check the water
level.
About the sensor:
The sensor works by using a series of five exposed
traces which are connected to system ground.
Interlaced between every two ground trace is a sense
trace, five ground traces and five sense traces in total.
The sense traces are connected to a 1 Megaohm pull-
up resistor. The sense traces are pulled high until a
drop or plane of water shorts the sense trace to
ground. This sensor will theoretically output an analog
signal between 0-1024, but with the length of traces
on this PCB I found a usable range between 480 and
~710. The sensor is not designed to be fully
submersed, be mindful to install it so that only the
exposed traces on the PCB will be exposed to contact
with water. Output voltage of the sensor is 0 - 4.2 V,
so this could be used as a digital input if only low/high
indication is required.
The analog output values correspond to the following
distance from bottom of the sensor (approximate):
480 = 0 mm
530 = 5 mm
615 = 10 mm
660 = 15 mm
680 = 20 mm
690 = 25 mm
700 = 30 mm
705 = 35 mm
710 = 40 mm
The sensor resolution decreases as the the water level
increases.
== Installation
1. Upload the sketch to your Arduino.
2. Assemble the circuit using the schematic included
with this project.
**LED: The LED resistor must be installed between
the circuit ground and LED. If your LED has one leg
that is longer than the other, the longer leg needs to be
connected to the supply voltage (D2 of Arduino).
*Note: I used ~2.5 ft wire length for the sensor and 2
ft wire length for the LED. This allowed me to place
the Arduino away from the water, and route the LED
to the end of a tree branch for visibility.
3. Follow the calibration instructions below (also
included in the sketch):
**************************** Calibration/Setup
****************************
a) Connect Arduino to IDE and open serial monitor.
b) Insert depth sensor into water to a depth that you
consider to be the minimum amount needed to trigger
the full indicator. Note the value indicated in the serial
monitor for use as the FULL level.
* Any value >= this will trigger the corresponding
FULL blink code.
c) Repeat step 2 to determine the value you will assign
to the LOW value.
* Any value above this but below the FULL value will
trigger the corresponding INTERMEDIATE blink
code.
* Any value below this value will trigger the
corresponding LOW blink code.
d) Plug the values determined from steps 2 and 3 in as
the const int FULL and LOW values in the sketch.
e) Upload the sketch with the updated values and your
sensor is now calibrated.
4. Place your Arduino is some type of enclosure to
prevent damage from water, moving parts, or shorts.
5. Install the system into your application.
=== Folder Structure
WaterLevelMontior_SingleLED => Arduino sketch
folder
├── WaterLevelMonitor_SingleLED.ino => main
Arduino file
├── WaterLevelMonitor.png => an image of the
required schematics
└── ReadMe.adoc => this file
SCHEMATICS
CODE

roject: Water Level Monitor

****************************** Calibration/Setup
******************************
1) Upload sketch to Arduino and open serial monitor.
2) Insert depth sensor into water to a depth that you
consider to be the minimum amount needed
to trigger the full indicator. Note the value indicated in
the serial monitor
for use as the FULL level.
* Any value >= this will trigger the corresponding FULL
indicator.
3) Repeat step 2 to determine the value you will assign
to the LOW value.
* Any value above this but below the FULL value will
trigger the corresponding INTERMEDIATE
blink code.
* Any value below this value will trigger the
corresponding LOW blink code.
4) Plug the values determined from steps 2 and 3 in as
the const int FULL and LOW values
in the sketch.
5) Upload the sketch with the updated values and your
sensor is now calibrated.
*/

const int full = 575;


const int low = 490;
int depthSensor = 0; //Set depthSensor input pin to
Analog 0.
int lastValue = 0;
char printBuffer[128];

/* The following line sets the LED pin to the


corresponding digital pin of the
Arduino. You can set these to any digital pin as needed
*/

const int whiteLED = 2;

void setup()
{
Serial.begin(9600); // Begin serial communication to
obtain sensor values during calibration.
pinMode(whiteLED, OUTPUT); // Set LED pin to
OUTPUT mode.
}

void loop()
{
int value = analogRead(depthSensor); // Read the sensor
values.
if(((lastValue >= value) && ((lastValue - value) > 10)) ||
(lastValue = 10)) /* If the delta
between last and current value is > 10, display the
current value. */
{
// Displays depth sensor value to serial port.
sprintf(printBuffer, "ADC%d level is %d\n",
depthSensor, value);
Serial.print(printBuffer);
Serial.println();
//Serial.println(value);
//Serial.println();
// Set last value to current value for next loop.
lastValue - value;
}
if(value >= full)
{
// FULL
for(int x = 0; x < 3; x++){
digitalWrite(whiteLED, HIGH);
delay(800);
digitalWrite(whiteLED, LOW);
delay(800);
}
}
else if((value < full) && (value >= low))
{
// INTERMEDIATE
for(int x = 0; x < 2; x++){
digitalWrite(whiteLED, HIGH);
delay(1000);
}
}
else
{
//LOW
for(int x = 0; x < 4; x++){
digitalWrite(whiteLED, HIGH);
delay(100);
digitalWrite(whiteLED, LOW);
delay(100);
}
}
delay(3000); // Read current sensor value every three
seconds.
}

/*
=== License
This project utilizes common electronic theory and
C/C++ programming language. I am not claiming to
hold
a copyright or own any intellectual property related to
the documents included in this project. This
sketch, the associated ReadMe.adoc, and system
schematic may be modified or distributed freely. This
project is released under a Public Domain License.
=== DISCLAIMER
This SOFTWARE PRODUCT is provided by THE
PROVIDER "as is" and "with all faults." THE
PROVIDER makes no
representations or warranties of any kind concerning the
safety, suitability, lack of viruses,
inaccuracies, typographical errors, or other harmful
components of this SOFTWARE PRODUCT. There are
inherent dangers in the use of any software, and you are
solely responsible for determining whether this
SOFTWARE PRODUCT is compatible with your
equipment and other software installed on your
equipment. You
are also solely responsible for the protection of your
equipment and backup of your data, and THE
PROVIDER will not be liable for any damages you may
suffer in connection with using, modifying, or
distributing this SOFTWARE PRODUCT.
*/
70) Arduino Obstacles Avoiding Robot with Servo
Motor
COMPONENTS AND SUPPLIES
Arduino UNO & Genuino UNO
× 1

SG90 Micro-servo motor × 1


SparkFun Ultrasonic Sensor -
HC-SR04
× 1

Robot Chassis Kit - 2WD with


DC Motors × 1

Jumper wires (generic)


× 1

Arduino MotorShield Rev3


× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT


Step 1:
Prepare and build your Robot chasis. Inside the
package have a few components, chassis, two motors,
two wheels, a front wheel, a battery holder, some
screws, switch and jumper wires. Photo below:
The instructions paper will come with the package that
you buy from online or the shops. Or else you can
view "how to build" in the youtube.
Step 2:
Before solder the jumper wires on your both motor, I
would recommend to test every components for make
sure they all are working well, example: Both DC
motors, Arduino board, Motor Shield, Servo motor
and Ultrasonic sensor. Then we will start solder the
red and black wire on both motors, example picture
below:

Step 3:
Come to our battery chassis and switch part. We only
need to cut half of the black wire from the battery
chassis and solder 1 wire side at 1 hole, another black
wire will solder at another hole. Our switch is ready!
Step 4:
We will need to stack Arduino board and Motor Shield
board, Motor Shield will stack on Arduino board.
Example below:

Step 5:
We will move on to the Motor Shield board. This
shield provides power to the motors and the servo
motor, the motors need a lot of current, and this shield
can provide up to 600mA of current to each motor. We
need to solder/fixed the DC motors wires at the Motor
shield board. If the your DC motor wires are long
enough to reach the Motor Shield will be great, if not
you might need to use external jumper wires(No
matter is Male/Female jumper wire), cut off the
jumper wire head and make sure inside the copper line
shows up. (You will need to cut jumper wire rubber to
make the copper wire appear). And you need to solder
the external wires to the DC motor wires. Example:

Then connect the left motor wire to M1 connector of


the motor shield. Right motor wire will coneect to M3
connector from the Motor shield board. Example:
Pictures by Darwin
Step 6:
Then we will need to connect the battery switch wires
both red and black wire to the Motor shield board.
For Battery switch wire (Pictures by Darwin)
After that, we will need to ready Male and Female
jumper wires for solder them to 5V, GND, Analog Pin
4 and Analog Pin 5. Before that, we will need to find
same colors of female and male jumper wires and cut
them into half. Why must be same color? First is easy
for us to recognize which wire are for which part.
Second, white Male jumper wire will solder with
white Female jumper wire which connect to 5V. Black
color Male jumper wire will solder with female
jumper wire and Male jumper wire will solder to
GND. Orange color Male jumper wire will solder with
orange Female jumper wire, Orange male jumper wire
will solder at Analog Pin 5. Lastly but not least, brown
male jumper wire will solder with female brown
jumper wire, then brown color male jumper wire will
solder to Analog Pin 4. Example:

Pictures by Darwin
Step 7:
You are able to use double sided tape or hot glue gun
for attach the both shield on the robot chassis.
Step 8: Come to Ultrasonic Sensor part
From the Female & Male jumper wires that we solder
just now, White jumper wire(5V)(Female site jumper
wire) will connect to Ultrasonic Sensor VCC pin.
Black Jumper wire(GND)(Female site jumper wire)
will connect to GND pin. Brown jumper wire(Analog
Pin 4)(Female site jumper wire) will connect to Echo
pin. Orange color jumper wire(Analog Pin 5)(Female
site jumper wire) will connect to TRIG pin.

Step 9:
Lastly, For the Servo motor will connect to servo_2
slot. Note* (There are few types of servo motor out
there. you might need to find it online for how they
plug to servo_2 slot). Below is for my own version of
servo slot.
Last Step: Code
For this Obstacles avoiding robot, we will need 3
libraries, which is Motor Shield library for Motor
Shield driver

SCHEMATICS
CODE

#include <AFMotor.h>
#include <Servo.h>
#include <NewPing.h>

#define TRIG_PIN A4
#define ECHO_PIN A5
#define MAX_DISTANCE_POSSIBLE 1000
#define MAX_SPEED 150 //
#define MOTORS_CALIBRATION_OFFSET 3
#define COLL_DIST 20
#define TURN_DIST COLL_DIST+10
NewPing sonar(TRIG_PIN, ECHO_PIN,
MAX_DISTANCE_POSSIBLE);

AF_DCMotor leftMotor(3, MOTOR12_8KHZ);


AF_DCMotor rightMotor(1, MOTOR12_8KHZ);
Servo neckControllerServoMotor;

int pos = 0;
int maxDist = 0;
int maxAngle = 0;
int maxRight = 0;
int maxLeft = 0;
int maxFront = 0;
int course = 0;
int curDist = 0;
String motorSet = "";
int speedSet = 0;

void setup() {
neckControllerServoMotor.attach(10);
neckControllerServoMotor.write(90);
delay(2000);
checkPath();
motorSet = "FORWARD";
neckControllerServoMotor.write(90);
moveForward();
}
void loop() {
checkForward();
checkPath();
}

void checkPath() {
int curLeft = 0;
int curFront = 0;
int curRight = 0;
int curDist = 0;
neckControllerServoMotor.write(144);
delay(120);
for(pos = 144; pos >= 36; pos-=18)
{
neckControllerServoMotor.write(pos);
delay(90);
checkForward();
curDist = readPing();
if (curDist < COLL_DIST) {
checkCourse();
break;
}
if (curDist < TURN_DIST) {
changePath();
}
if (curDist > curDist) {maxAngle = pos;}
if (pos > 90 && curDist > curLeft) { curLeft = curDist;}
if (pos == 90 && curDist > curFront) {curFront =
curDist;}
if (pos < 90 && curDist > curRight) {curRight =
curDist;}
}
maxLeft = curLeft;
maxRight = curRight;
maxFront = curFront;
}

void setCourse() {
if (maxAngle < 90) {turnRight();}
if (maxAngle > 90) {turnLeft();}
maxLeft = 0;
maxRight = 0;
maxFront = 0;
}
void checkCourse() {
moveBackward();
delay(500);
moveStop();
setCourse();
}

void changePath() {
if (pos < 90) {lookLeft();}
if (pos > 90) {lookRight();}
}

int readPing() {
delay(70);
unsigned int uS = sonar.ping();
int cm = uS/US_ROUNDTRIP_CM;
return cm;
}

void checkForward() { if (motorSet=="FORWARD")


{leftMotor.run(FORWARD);
rightMotor.run(FORWARD); } }

void checkBackward() { if
(motorSet=="BACKWARD")
{leftMotor.run(BACKWARD);
rightMotor.run(BACKWARD); } }

void moveStop() {leftMotor.run(RELEASE);


rightMotor.run(RELEASE);}

void moveForward() {
motorSet = "FORWARD";
leftMotor.run(FORWARD);
rightMotor.run(FORWARD);
for (speedSet = 0; speedSet < MAX_SPEED; speedSet
+=2)
{
leftMotor.setSpeed(speedSet+MOTORS_CALIBRATIO
N_OFFSET);
rightMotor.setSpeed(speedSet);
delay(5);
}
}
void moveBackward() {
motorSet = "BACKWARD";
leftMotor.run(BACKWARD);
rightMotor.run(BACKWARD);
for (speedSet = 0; speedSet < MAX_SPEED; speedSet
+=2)
{
leftMotor.setSpeed(speedSet+MOTORS_CALIBRATIO
N_OFFSET);
rightMotor.setSpeed(speedSet);
delay(5);
}
}

void turnRight() {
motorSet = "RIGHT";
leftMotor.run(FORWARD);
rightMotor.run(BACKWARD);
delay(400);
motorSet = "FORWARD";
leftMotor.run(FORWARD);
rightMotor.run(FORWARD);
}

void turnLeft() {
motorSet = "LEFT";
leftMotor.run(BACKWARD);
rightMotor.run(FORWARD);
delay(400);
motorSet = "FORWARD";
leftMotor.run(FORWARD);
rightMotor.run(FORWARD);
}

void lookRight() {rightMotor.run(BACKWARD);


delay(400); rightMotor.run(FORWARD);}
void lookLeft() {leftMotor.run(BACKWARD);
delay(400); leftMotor.run(FORWARD);}
71) Arduino Morse Encoder Displayer
COMPONENTS AND SUPPLIES

Arduino UNO & Genuino UNO


× 1

Breadboard (generic) × 1
Jumper wires (generic)
× 27

Adafruit Standard LCD - 16x2


White on Blue
× 1

Buzzer
× 1

Resistor 221 ohm


× 1

Rotary potentiometer (generic)


× 2
APPS AND ONLINE SERVICES
Arduino IDE

Arduino Web Editor

ABOUT THIS PROJECT


This project is an Arduino program, that listen to the
serial port (reception/emission) and outputs two
things:
Firstly, it convert the text you sent it into morse,
and emit it via pin 11 (you may want to connect
to a potentiometer in serie with a buzzer).
Secondly, in the same time, on the LCD screen,
it writes the letter it is encoding and prints the
morse code on the second line. When it reaches
the end of the first line, it clears the line.
It also send back what it received, prefixed with
"Received: ".
When it does not recognize a character, it buzzes the
length of 4 dots then wait the equivalent of 2 dots,
send an error message with the character it didn't
recognized and its binary value on the serial, and
replace the character with a "?" on the LCD screen.
I have an idea to upgrade this project: add a third
potentiometer to control the duration of a
dot/dash/pauses.

SCHEMATICS
CODE

#include <LiquidCrystal.h>

LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

#define BUZZER 11

#define SMALLER_DELAY 128


PROGMEM const uint8_t morse_code_a_z[26] = {
0b01100000, // A .-
0b10010101, // B -...
0b10011001, // C -.-.
0b10010100, // D -..
0b01000000, // E .
0b01011001, // F ..-.
0b10100100, // G --.
0b01010101, // H ....
0b01010000, // I ..
0b01101010, // J .---
0b10011000, // K -.-
0b01100101, // L .-..
0b10100000, // M --
0b10010000, // N -.
0b10101000, // O ---
0b01101001, // P .--.
0b10100110, // Q --.-
0b01100100, // R .-.
0b01010100, // S ...
0b10000000, // T -
0b01011000, // U ..-
0b01010110, // V ...-
0b01101000, // W .--
0b10010110, // X -..-
0b10011010, // Y -.--
0b10100101, // Z --..
};

void send_bit(const bool& dash) {


lcd.print(dash ? '-' : '.');
analogWrite(BUZZER, 63);
delay((dash ? 3 : 1) * SMALLER_DELAY);
digitalWrite(BUZZER, LOW);
delay(1 * SMALLER_DELAY);
}

uint8_t hpos = 0;
void send_char(const char& c) {
// Send the character to the LCD
lcd.setCursor(hpos++, 0);
lcd.print(c);

// Position the cursor to the next line to start the .- sequence


lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
}

void print_number(const char& number) {


if (!isDigit(number)) return;

send_char(number);

uint8_t num = number - '0';


for (uint8_t i = 0 ; i < 5 ; i++) {
if (num == i) num += 10;

if (num < 6 + i) send_bit(false);


else send_bit(true);
}
}

void print_character(char character) {


if (!isAlpha(character)) return;

if (isLowerCase(character)) character += 'A' - 'a';

send_char(character);

uint8_t code = morse_code_a_z[character - 'A'];


while (code != 0) {
switch (code >> 6) {
case 0:
break;
case 1:
send_bit(false);
break;
case 2:
send_bit(true);
break;
case 3:
Serial.print("Error while printing character: ");
Serial.println(character);
Serial.print("Got 3 in the 2 leftmost bits of code ");
Serial.println(code, BIN);
break;
default:
Serial.print("Error while printing character: ");
Serial.println(character);
Serial.print("Got ? in the 2 leftmost bits of code ");
Serial.println(code, BIN);
}
code <<= 2;
}
}

void print_whitespace() {
send_char(' ');
delay(3 * SMALLER_DELAY);
}

void print_char(const char& character) {


if (isWhitespace(character)) print_whitespace();
else if (isAlpha(character)) print_character(character);
else if (isDigit(character)) print_number(character);
else if (isPunct(character)) { send_char(character); delay(1 *
SMALLER_DELAY); }
else if (character == '\0') {}
else if (character == '\1') { /* This happens at the end of every string, don't
know why */ }
else {
Serial.print("Error: unknown character ");
Serial.print(character);
Serial.print(" (0b");
Serial.print((uint8_t)character, BIN);
Serial.println(")");
send_char('?');
analogWrite(BUZZER, 63);
delay(4 * SMALLER_DELAY);
digitalWrite(BUZZER, LOW);
delay(1 * SMALLER_DELAY);
}

delay(2 * SMALLER_DELAY);
}

void print_string(const char* characters, int len = 15) {


for (uint8_t pos = 0 ; pos <= len ; pos++) {
print_char(characters[pos]);
}
}

void reset_LCD() {
hpos = 0;

lcd.clear();
lcd.noCursor();
lcd.setCursor(0, 0);
}

void setup() {
// put your setup code here, to run once:
Serial.begin(9600);

lcd.begin(16, 2);
reset_LCD();

pinMode(BUZZER, OUTPUT);
}

char* readStr() {
uint8_t idx = 0;
char* str = (char*)malloc(128 * sizeof(char));
while (Serial.available() && idx < 128) {
str[idx] = Serial.read();
idx++;
delay(2);
}
for ( ; idx < 128 ; idx++) {
str[idx] = '\0';
}

return str;
}

void serialEvent() {
while (Serial.available()) {
char* string;
Serial.setTimeout(-1);
string = readStr();
Serial.print("Received: ");
Serial.println(string);

char substr[16];
for (uint8_t c = 0 ; c < 128 && string[c] != '\0' && string[c] != '\r' &&
string[c] != '\n' ; c += 16) {
for (uint8_t offset = 0 ; offset < 15 ; offset++) {
if (string[c + offset] != '\0' && string[c + offset] != '\r' && string[c + offset]
!= '\n') {
substr[offset] = string[c + offset];
} else {
substr[offset] = '\0';
}
}

reset_LCD();
print_string(substr);
}

free((void*)string);
}
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 0);
}

void loop() {
}

72) Arduino Analog Style LED POV Clock


COMPONENTS AND SUPPLIES

Arduino Nano R3

× 1

LED (generic) × 17
Hall Effect Sensor

× 1

Resistor 100 ohm

× 17

DC motor (generic)
× 1

Boost (Step Up) Switching Regulator, Fixed

× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT


The electronic part contains the Arduino Nano 17
LED diodes and the Hall effect sensor. LED Diode
groups d1-d11, d12-d16 and d17 are of different color
for better visual effect.The device is powered by a
lithium ion battery through a step-up converter.
The most difficult part of the projects for me was
mechanical stability. In the first attempt, the battery
was set eccentrically and at a higher speed of rotation
there was a huge vibration. Then I made a
modification and put the battery in the center of
rotation.
For rotation I use a 12V electric motor connected to a
variable power supply so the speed of rotation of the
device can be easy controlled. Depending on the speed
of rotation of the device, in the code you need to set
the value of "delayMicroseconds" to a determined
value.
The presented video is not clear enough, because for
this purpose I need a camera with a better frames per
second.
SCHEMATICS
CODE
// hobbyprojects
// ArduinoNanoPropellerLEDAnalogClock20190403A

int LED1 = 2;
int LED2 = 3;
int LED3 = 4;
int LED4 = 5;
int LED5 = 6;
int LED6 = 7;
int LED7 = 8;
int LED8 = 9;
int LED9 = 10;
int LED10 = 11;
int LED11 = 12;
int LED12 = A1;
int LED13 = A2;
int LED14 = A3;
int LED15 = A4;
int LED16 = A5;

int sensorPin = A0;

unsigned int n,ADCvalue,propeller_posn;


unsigned long previousTime = 0;

byte hours = 12; // set hours


byte minutes = 15; // set minutes
byte seconds = 00; // set seconds

int val;

void setup()
{
pinMode(LED1,OUTPUT);
pinMode(LED2,OUTPUT);
pinMode(LED3,OUTPUT);
pinMode(LED4,OUTPUT);
pinMode(LED5,OUTPUT);
pinMode(LED6,OUTPUT);
pinMode(LED7,OUTPUT);
pinMode(LED8,OUTPUT);
pinMode(LED9,OUTPUT);
pinMode(LED10,OUTPUT);
pinMode(LED11,OUTPUT);
pinMode(LED12,OUTPUT);
pinMode(LED13,OUTPUT);
pinMode(LED14,OUTPUT);
pinMode(LED15,OUTPUT);
pinMode(LED16,OUTPUT);

pinMode(sensorPin,INPUT_PULLUP);

if(hours == 12)
hours = 0;
}

void loop()
{
val = digitalRead(sensorPin);

while (val == LOW)


{
val = digitalRead(sensorPin);
}

if (millis() >= (previousTime))


{
previousTime = previousTime + 1000;
seconds = seconds+1;
if (seconds == 60)
{
seconds = 0;
minutes = minutes+1;
}
if (minutes == 60)
{
minutes = 0;
hours = hours+1;
}
if (hours == 12)
{
hours = 0;
}
}
propeller_posn=30;
n=0;

while(n < 60)


{

drawMinuteMarker();

if ((propeller_posn==0) || (propeller_posn==5) || (propeller_posn==10) ||


(propeller_posn==15) || (propeller_posn==20) || (propeller_posn==25) ||
(propeller_posn==30) || (propeller_posn==35) || (propeller_posn==40) ||
(propeller_posn==45) || (propeller_posn==50) || (propeller_posn==55))
drawHourMarker();

if ((propeller_posn==0) || (propeller_posn==15) || (propeller_posn==30) ||


(propeller_posn==45))
drawQuarterMarker();

if((propeller_posn == hours*5) || (( propeller_posn == 0 ) && (hours ==


0)))
drawHoursHand();

if(propeller_posn == minutes)
drawMinutesHand();

if(propeller_posn == seconds)
drawSecondsHand();

delayMicroseconds(140); // for LED pixel width (change the value


according to motor speed. Increase for low speed, decrease for high speed
motor)

displayClear();

drawInner_Circle();

delayMicroseconds(600); // for the gap between LED pixels/minutes


markers (change the value according to motor speed. Increase for low
speed, decrease for high speed motor)
n++;
propeller_posn++;
if(propeller_posn == 60)
propeller_posn=0;
}

val = digitalRead(sensorPin);

while (val == HIGH)


{
val = digitalRead(sensorPin);
}
}

//=========================

void displayClear()
{
digitalWrite(LED1,LOW);
digitalWrite(LED2,LOW);
digitalWrite(LED3,LOW);
digitalWrite(LED4,LOW);
digitalWrite(LED5,LOW);
digitalWrite(LED6,LOW);
digitalWrite(LED7,LOW);
digitalWrite(LED8,LOW);
digitalWrite(LED9,LOW);
digitalWrite(LED10,LOW);
digitalWrite(LED11,LOW);
digitalWrite(LED12,LOW);
digitalWrite(LED13,LOW);
digitalWrite(LED14,LOW);
digitalWrite(LED15,LOW);
digitalWrite(LED16,LOW);
}

void drawMinuteMarker()
{
digitalWrite(LED16,HIGH);
}

void drawHourMarker()
{
digitalWrite(LED15,HIGH);
digitalWrite(LED14,HIGH);
}

void drawQuarterMarker()
{
digitalWrite(LED13,HIGH);
digitalWrite(LED12,HIGH);
}

void drawHoursHand()
{
digitalWrite(LED1,HIGH);
digitalWrite(LED2,HIGH);
digitalWrite(LED3,HIGH);
digitalWrite(LED4,HIGH);
digitalWrite(LED5,HIGH);
digitalWrite(LED6,HIGH);
digitalWrite(LED7,HIGH);
}

void drawMinutesHand()
{
digitalWrite(LED1,HIGH);
digitalWrite(LED2,HIGH);
digitalWrite(LED3,HIGH);
digitalWrite(LED4,HIGH);
digitalWrite(LED5,HIGH);
digitalWrite(LED6,HIGH);
digitalWrite(LED7,HIGH);
digitalWrite(LED8,HIGH);
digitalWrite(LED9,HIGH);
}
void drawSecondsHand()
{
digitalWrite(LED1,HIGH);
digitalWrite(LED2,HIGH);
digitalWrite(LED3,HIGH);
digitalWrite(LED4,HIGH);
digitalWrite(LED5,HIGH);
digitalWrite(LED6,HIGH);
digitalWrite(LED7,HIGH);
digitalWrite(LED8,HIGH);
digitalWrite(LED9,HIGH);
digitalWrite(LED10,HIGH);
digitalWrite(LED11,HIGH);
}

void drawInner_Circle()
{
digitalWrite(LED1,HIGH);
delayMicroseconds(30);
digitalWrite(LED1,LOW);
}

73) Arduino Darkness Activated Ghots


COMPONENTS AND SUPPLIES
Arduino UNO & Genuino UNO
× 1

Breadboard (generic)
× 1

Jumper wires (generic)


× 1

9V Battery Clip × 1
RobotGeek Light Sensor
We used a photo resistor, also
know as a LDR ( Light
× 1
Dependent Resistor ), i would
recommend this as its cheaper
and serves the purpose.
9V battery (generic)
× 1
NECESSARY TOOLS AND MACHINES
Laser cutter (generic)

Soldering iron (generic)

Hot glue gun (generic)


APPS AND ONLINE SERVICES
Arduino IDE

circuito.io

ABOUT THIS PROJECT


Ever wondered if we could scare our friends in the
dark and have a good laugh? Ever wondered if we
could create a simple artificial ghost and haunt your
house?!
Well here is a system that we devised that does exactly
so, the system uses an Arduino and the code and
schematics were created with Circuito.io ( a fun and
easy software that creates the founding blocks of you
projects, great for beginners, do check it out! ). Follow
on to see how our ''Ghost'' works and how we made it!
This idea came up with the often occurring fear of
Darkness! Our system works with the help of a light
sensor, which detects the light intensity in the room.
Using this the program gets activated when the lights
are put off at night, in other words when it's
completely dark. We then cleverly recorded and
manipulated are voices to make it sound like a ghost.
If the person who is pranked turns on the light scared
the voice immediately stops. Giving the effect as
though there is a real ghost in the room, giving it a
haunted feeling and making you roll with laughter as
you see your friend freak out!!!
MECHANISM
We made the device portable and small so that it can
fit in any small hiding place in your house. We
decided to hide it in a book, more of that in the next
steps. As we didn't have an Arduino audio shield, we
hacked our smartphone to fit into our device. We
figure that we needed to click on two buttons, the
''Play'' and the ''Skip''. To do this we used servo motors
having tips wrapped in foil, which clicks on the screen
either playing or skipping the audio clips. All of the
components were mounted on a custom laser cut part
that we modeled.
LET'S GET MAKING!
Materials Needed:
An Arduino UNO, a Photoresistor & a Switch
Arduino UNO
LDR ( Photo resistor)
2 x 9g Micro Servo Motors
Switch
9 volt battery + clip
Jumper wire
2 x rubber bands
And your smartphone!
Assembling the system:
Start by getting the laser-cutting file cut,( though keep
in mind that it needs to fit your smartphone) you will
need to make few adjustments. Once done peel the
protective layer.

The lasercut white acrylic

Opening exposing display


Mount the piece, simply with rubber bands
Squirt out dabs of hot glue around the servo, making
sure that the horns touch the required buttons. Stick
both of them firmly in place, you can then move and
with the switch and stick the Arduino UNO with a
strip of double sided tape. (Follow the pictures to
better understand the arrangement).
over the button

glueing the servos


make sure the horns are parallel

mount the arduino with tape


MAKING THE ALUMINIUM TABS:
Take the leftover pieces of acrylic from the slot and
break it into two small tabs. Wrap them with foil and
connect arduino's ground pin to it, imitating them to
act like your fingers and the touch screen

aluminium tabs attached to the horns

hot glued
smooth surface sticking out

the tabs shouldn't touch


make sure the aluminium tabs are slightly at an angle
Wire them all up, hooking up the servo motors to the
Arduino with jumper wires. Follow the schematics.

Circuito helped us get an acurate schematics


Soldering...
It's complete
THE AUDIO RECORDINGS:
This is one of the most fun parts, it's when your ghost
comes to life. Record some spooky ghost lines and be
creative in making it scary with sound effects! Then
upload the clips to your smartphone in the right
sequence and you are nearly done!
recording our spooky voices and adding sound effect
YOU'RE DONE!
We had made this cut out book a while back and found
it a perfect object to conceal the system. Try and find
a none obvious hiding spot or an object like a pot or
an old regulator case, etc...
You are ready, wait till evening and prank your friend
by slipping in your smartphone and clicking a switch!
This spooked us out to even though we made it. It got
us hilarious results and we feel it definitely does give
a shiver!
our Fake book!

as you can see this FAKE BOOK is the perfect size

Time to put it on
Simply put in the whole device
make sure the LDR sticks out

Now place it on a table..


.
..or a Shelf
SCHEMATICS

CODE
#include <Servo.h>
Servo servo1;
Servo servo2;
int pos1 = 0;
int pos2 = 0;

int ldr = A0;


int sensor_value = 0;
int thresh = 150;
bool state = false;

void play(){
for (pos1 = 0; pos1 <= 180; pos1 += 1) { // goes from 0 degrees to 180
degrees
// in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
for (pos1 = 180; pos1 >= 0; pos1 -= 1) { // goes from 180 degrees to 0
degrees
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
while(true);
}

void next_clip(){
for (pos2 = 0; pos2 <= 180; pos2 += 1) { // goes from 0 degrees to 180
degrees
// in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
for (pos2 = 180; pos2 >= 0; pos2 -= 1) { // goes from 180 degrees to 0
degrees
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
while(true);
}
void setup() {
// put your setup code here, to run once:
servo1.attach(7);
servo2.attach(8);
Serial.begin(9600); //for debugging only

void loop() {
// put your main code here, to run repeatedly:
sensor_value = analogRead(ldr);

//the moment lights go off the first clip starts to play


if (sensor_value < thresh){
play();
state = true;

//once the victim is scared and tries to turn on the lights. play next clip
else if(sensor_value > thresh && state == true){
next_clip();
play();
state = false;
}

//do nothing
}
74) Arduino and Vibration Sensor with Relay

COMPONENTS AND SUPPLIES


Arduino UNO & Genuino UNO × 1
SW-420 Vibration sensor module
× 1

Optocoupler PC817
× 1

Transistor BC 547
× 1

1N4007 – High Voltage, High


Current Rated Diode
× 1

Relay 5V DC
× 1

5 mm LED: Red
A second LED is used to show × 1
the relay contact ON OFF

Resistor 220 ohm × 2


Breadboard (generic)
× 1

Jumper wires (generic)


× 1

4xAA battery holder


In this project I used a battery × 1
holder with 3 AA batteries

ABOUT THIS PROJECT


The idea: A big light must flash 3 times when at long
distance shooting the target is hit. (Target is a metal
round piece attached on a metal frame) How it works:
When the target is hit, the sensitive vibration sensor,
fixed on the back of the target frame, will detect
vibration. To indicate the target was hit, the light will
flash 3 times. (2sec ON, 1 sec OFF, 3 times)
The sensor module is powered by the Arduino. With the
help of the Optocoupler PC817 we keep the circuit for
the relay seperated from the Arduino UNO.
The relay is powered by the external source, in this case
3x AA battery.
SCHEMATICS
CODE
//Vibration Sensor Module (Code)Arduino with relay and external 5V power
source.

int vib_pin=2;
int led_pin=13;

// put your setup code here, to run once:


void setup() {
pinMode(vib_pin,INPUT);
pinMode(led_pin,OUTPUT);
}
// put your main code here, to run repeatedly:
void loop() {
int val;
val=digitalRead(vib_pin);
if(val==1)
{
digitalWrite(led_pin,LOW);
delay(2000);
digitalWrite(led_pin,HIGH);
delay(1000);
digitalWrite(led_pin,LOW);
delay(2000);
digitalWrite(led_pin,HIGH);
delay(1000);
digitalWrite(led_pin,LOW);
delay(2000);
digitalWrite(led_pin,HIGH);
delay(1000);

}
else
digitalWrite(led_pin,HIGH);
}

75) Arduino Tic Tac Toe Board Game with Robotic


Arm
COMPONENTS AND SUPPLIES
4 x 4 Matrix Array 16 Key Membrane Switch
Keypad Keyboard for Arduino × 1

Connector - DB9 Male Socket


× 1

Female Header 4 position 0.1" spacing


This mates with the X-Arm Serial port × 1
header
Connector DB9 - Female Plug × 1
Enclosure Plastic 5.5" (L) x 3.25" (W) x 1/5"
(H)
Any plastic enclosure to house the
Mega2560 and room to mount the DB-9 × 1
Socket. Punch or drill out holes for socket
and connectors of Mega2560, and mount the
Keypad on top panel of enclosure.
Robotic Arm with 6DOF - Lewansoul model
X-Arm × 1

BSIRI TicTacToe Classic Board Games


Noughts and Crosses × 1

Nylon spacers (for board mounting)


× 4

Nylon screws 4-40 size (for mounting board)


× 1

Nylon nuts (for mounting board)


× 4

Arduino Mega 2560 & Genuino Mega 2560


Substituted Elegoo LYSB01H4ZDYCE-
ELECTRNCSMEGA 2560 R3 Board × 1
NECESSARY TOOLS AND MACHINES

ABOUT THIS PROJECT


I wanted to use the Lewansoul's robotic arm (X-
arm) ( to play a real board version of tic-tac-toe to
illustrate the movement of the arm to pickup and place
pieces into positions in a game environment. The
robotic arm is controlled by the Arduino Mega 2560
and input from the player ("X") is confirmed by a
membrane keypad using keys 1-9 to represent each of
the board positions 1-9. I used an existing tic-tac-toe
sketch (see contributor) from GitHub, that uses the
MinMax algorithm to determine which move the
computer should make after the player makes each
move. I added to this program the code to control the
X-arm position using the stored action groups in the
X-arm controller for each possible position 1-9 of the
board. So for a specific move by the computer to play
the next position, say, position 4, the x-arm would be
sent an action group command "4" to pick up the
computer piece (in this case, the computer is "O") and
place it in the number 4 position on the tic-tac-toe
game board.

SCHEMATICS

Tic-tac-toe schematic
Tic-Tac-toe Breadboard

CODE
//
//BobN2Tech 03-22-18 add Xarm code for robotic control and Keypad input
code
//Thanks to https://github.com/klauscam/ArduinoTicTacToe for the tic-tac-
toe algorithm
//this code requires mega2560 which uses serial port 3 (serial3) to control
the Lewansoul xarm
//note: actiongroups 0-8 must be downloaded to the xarm controller prior
//to using this program. Action group numbers 0 to 8 represent the board
positions that
//will be placed the moved piece. Initially has to be done manually (train the
x-arm) to determine each board position
//where the xarm will place the computer move piece.
//action group 100 is preloaed for the initial position of the arm (recommend
standing up)
//action group 9 is for moving the arm as computer winning game - does
some fancy gyration
//optional action group 10 is for a draw - does some gyration
//optional action group 11 is for a losing - does some humble gesture.
//action group 12 is places arm into position where it will get the "O" pieces
//The computer will never lose!
//
int difficulty=8;
//xarm
#include <LobotServoController.h>
//Not using software serial
//#define rxPin 2 //software serial
//#define txPin 3 //software serial

//SoftwareSerial mySerial(rxPin, txPin);


//LobotServoController myse(mySerial);

//hardware serial - use only if not using serial0 ow it conflicts


LobotServoController myse(Serial3);

const int speed = 100; //percent of action speed set in group. 100 = 100% =
same speed as programmed, 50 = 1/2 speed, 200 = twice speed
int lastComputerMove = -1;
bool xarmConnected = false;
//keypad
#include <Keypad.h>

const byte ROWS = 4; //four rows


const byte COLS = 4; //four columns
//define the cymbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6}; //connect to the row pinouts of the
keypad
byte colPins[COLS] = {5, 4, 3, 2}; //connect to the column pinouts of the
keypad
char customKey;
//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins,
colPins, ROWS, COLS);
//

void setup(){
Serial.begin(9600);
while(!Serial);
digitalWrite(13,HIGH);
Serial3.begin(9600);
while(!Serial3);
//xarm code
//
int moveNo = 0;
pinMode(13,OUTPUT);
// mySerial.begin(9600);
// while(!mySerial);
// digitalWrite(13,HIGH);

//check if xarm is connected - send the initial positon


myse.runActionGroup(100,1);

if(myse.waitForStopping(5000)) //Waiting for the action group is


completed, or be stopped or timeout. The unit of the parameter(timeout) is
milliscond. finish or stop, you will get a true. timeout, you will get a false
{
Serial.println("Xarm is connected");
digitalWrite(13, LOW);
xarmConnected = true;
}
else
Serial.println("X-Arm not connected");

//test - change to loop for 9 positions

if (xarmConnected)
{

for (int i = 0;i <9; i++)


{
myse.setActionGroupSpeed(i,speed); //Set the running speed of i action
group at % speed of programmed
delay (1000);
//optional test all action groups are working
// Serial.println("xarm move to position " + String(i));
// myse.runActionGroup(i,1);
// delay(3000);

}
//optional
// myse.setActionGroupSpeed(100,speed); //Set the running speed of
No.100 action group at 1 sec
// delay(1000);

//put arm back into stand up as initial position (assume group 100)

// myse.runActionGroup(100,1);
// delay(2000);

xarmMove (12); //put arm into position for getting the pieces

delay (5000);
//
}
}

char displayChar(int c) {
switch(c) {
case -1:
return 'X';
case 0:
return ' ';
case 1:
return 'O';
}
}

void draw(int board[9]) {


Serial.print(" ");Serial.print(displayChar(board[0])); Serial.print(" |
");Serial.print(displayChar(board[1])); Serial.print(" |
");Serial.print(displayChar(board[2])); Serial.println(" ");
Serial.println("---+---+---");
Serial.print(" ");Serial.print(displayChar(board[3])); Serial.print(" |
");Serial.print(displayChar(board[4])); Serial.print(" |
");Serial.print(displayChar(board[5])); Serial.println(" ");
Serial.println("---+---+---");
Serial.print(" ");Serial.print(displayChar(board[6])); Serial.print(" |
");Serial.print(displayChar(board[7])); Serial.print(" |
");Serial.print(displayChar(board[8])); Serial.println(" ");
}

int win(const int board[9]) {


//list of possible winning positions
unsigned wins[8][3] = {{0,1,2},{3,4,5},{6,7,8},{0,3,6},{1,4,7},{2,5,8},
{0,4,8},{2,4,6}};
int winPos;
for(winPos = 0; winPos < 8; ++winPos) {
if(board[wins[winPos][0]] != 0 && board[wins[winPos][0]] ==
board[wins[winPos][1]] && board[wins[winPos][0]] ==
board[wins[winPos][2]])
return board[wins[winPos][2]];
}
return 0;
}

int minimax(int board[9], int player, int depth) {


//check the positions for players
int winner = win(board);
if(winner != 0) return winner*player;

int move = -1;


int score = -2;
int i;
for(i = 0; i < 9; ++i) {

if(board[i] == 0) {
board[i] = player;
int thisScore=0;
if (depth<difficulty){
thisScore = -minimax(board, player*-1,depth+1);
}

if(thisScore > score) {


score = thisScore;
move = i;

}
//choose the worst move for opponent
board[i] = 0;
}
}
if(move == -1) return 0;
return score;

void computerMove(int board[9])


{
int move = -1;
int score = -2;
int i;
for(i = 0; i < 9; ++i) {
if(board[i] == 0) {
board[i] = 1;
int tempScore = -minimax(board, -1, 0);
board[i] = 0;
if(tempScore > score) {
score = tempScore;
move = i;
lastComputerMove = i;
}
}
}
//returns a score based on minimax tree at a given node.
board[move] = 1;
}

void playerMove(int board[9])


{
int move = 0;
int bmove =0;
String smove;

do {

// Get value from custom keypad but start with keypad 1 = board 0;
Serial.println("\nInput move ([1..9]): ");
while ((customKey = customKeypad.getKey())== NO_KEY)
{delay(100);}

Serial.println(customKey);
//convert to string so can convert char to integer -
smove = (String)customKey;
bmove = smove.toInt()-1; //use keypad so will start with numbers 1-9 to
correspond to physical board layout
move = bmove;
//

Serial.println("\n");
} while ((move >= 9 || move < 0) || board[move] != 0);
board[move] = -1;
}

void xarmMove (int action)


{
if (!xarmConnected)
return;

myse.runActionGroup(action,1); //run action group once for each move

//test to get status while its running and do other things


Serial.println("Start RUNNING at " + String(millis())); //show total time

while (myse.isRunning()) //RAC


{

// Serial.println("IS STILL RUNNING" + String(millis())); //show total


time
myse.receiveHandle(); //must include this, otherwise will never leave
this loop

Serial.println("Action Completed at " + String(millis()));


Serial.println("FINISH XARM MOVE");

void loop(){
int board[9] = {0,0,0,0,0,0,0,0,0};
//x-arm Play only 1, playing 2 does not work correctly
// Serial.println("Would you like to play X(1) or O(2)?");
Serial.println("Press 1 to start playing - you are 'X' and Computer is 'O'");
/* get input from computer keyboard
while(Serial.available()==0)
{
delay(100);
}

int player=Serial.parseInt();
Serial.println(player);
*/

// Get value from custom keypad ;


int player;
String s;
while ((customKey = customKeypad.getKey())== NO_KEY)
{delay(100);}

Serial.println(customKey);
//convert to string so can convert char to integer
s = (String)customKey;
player = s.toInt();
//

unsigned turn;
for(turn = 0; turn < 9 && win(board) == 0; ++turn) {
if((turn+player) % 2 == 0)
{
computerMove(board);

Serial.println("xarm move is " + String(lastComputerMove));

if (lastComputerMove != -1 & lastComputerMove < 9)


xarmMove (lastComputerMove); //action groups index start at 0
}
else
{
draw(board);
playerMove(board);
}
}
switch(win(board)) {
case 0:
Serial.println("It's a draw.\n");
//send the initial positon
xarmMove (12);
break;
case 1:
draw(board);
Serial.println("You lose.\n");
xarmMove (9);
break;
case -1:
Serial.println("You win!\n");
xarmMove (11);
break;
}
}
76) Arduino Spectrum Analyzer with RGN LEDs

COMPONENTS AND SUPPLIES


Arduino Nano R3 × 1
Resistor 22.1k ohm
I just used 22k Ohm × 1

Resistor 221k ohm


I just used 220k Ohm × 2

MSGEQ7
× 1

Capacitor 33pF
× 1

Capacitor 100 nF
× 2

Capacitor 10 nF
× 1

Adressable RGB-LED Strip


× 1

USB Connector, USB Type B × 1


Female Header 8 Position 1
Row (0.1")
× 1

Wire, Wrapping Wire


× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)

Solder Wire, Lead Free

Hot glue gun (generic)

Bantam Tools Desktop PCB Milling


Machine

ABOUT THIS PROJECT


The project is to visualize an audio signal with a RGB
Led Stripe. The used MSGE7 have 7 bandpasses, thats
why I made 7 lines with the LED stripes.
The circuit board is designed with Eagle and made by
a circuit board milling mashine.
For the Power supply I used a normal USB Type B
socket. On the Bottom are the connectors for the AUX
wire and X4 is for the LED-Stripe.
The USB-Interface is used for the power supply.
MSGEQ7, Arduino Nano and the jumper are fixed on
one circut board.
I just soldered the single stripes behid each other and
glued them on transperend PE.
This is how its looks inside the case.
The circuit board is in a 3D printed case with Aux
sockets for input and output signal.
SCHEMATICS
CODE
//Arduino Spectrum Analyzer with RGB-LED Stripe and MSGEQ7
// declarations for the Neopixel by Adafruit
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN 4 // Pin for the RGB Stripe
#define NUMPIXELS 70 // Number of Pixels
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN,
NEO_GRB + NEO_KHZ800);
int strobePin = 2; // Strobe Pin on the MSGEQ7
int resetPin = 3; // Reset Pin on the MSGEQ7
int outPin = A0; // Output Pin on the MSGEQ7
int level[7]; // An array to hold the values from the 7 frequency bands
int l;
uint32_t aus = pixels.Color(0,0,0);
uint32_t gr = pixels.Color(0,200,0);
uint32_t grb = pixels.Color(0,160,40);
uint32_t grbl = pixels.Color(0,120,80);
uint32_t gbl = pixels.Color(0,80,120);
uint32_t bl = pixels.Color(0,40,160);
uint32_t blr = pixels.Color(0,0,200);
uint32_t blro = pixels.Color(40,0,160);
uint32_t bro = pixels.Color(80,0,120);
uint32_t ro = pixels.Color(120,0,80);
uint32_t rog = pixels.Color(160,0,0);

void setup()
{
Serial.begin(9600);
pinMode(strobePin, OUTPUT); // Define our pin modes
pinMode(resetPin, OUTPUT);
pinMode(outPin, INPUT);
pinMode(3,OUTPUT);
digitalWrite(resetPin, LOW); // Create an initial state for our pins
digitalWrite(strobePin, LOW);
delay(1);
digitalWrite(resetPin, HIGH); // Reset the MSGEQ7 as per the datasheet
timing diagram
delay(1);
digitalWrite(resetPin, LOW);
digitalWrite(strobePin, HIGH);
delay(1);
pixels.begin(); // enables Adafruit Neopixels
pixels.show(); // reset Pixels
for (int i = 0; i < 70; i++)
{
int ii = i-5; //snake effect at the start
pixels.setPixelColor(i, gr);
pixels.setPixelColor(ii, aus);
pixels.show();
delay(20);
}
}
void LEDaus1(int a,int b,int c,int d,int e,int f,int g,int h,int j,int k)
{
for (int i=a; i <=k; i++)
{
pixels.setPixelColor(i, aus);
pixels.show();
}
}
void LEDaus2(int a,int b,int c,int d,int e,int f,int g,int h,int j,int k)
{
for (int i=a; i >=k; i--)
{
pixels.setPixelColor(i, aus);
pixels.show();
}
}
void LED0(int a,int b,int c,int d,int e,int f,int g,int h,int j,int k, uint32_t gr)
{
pixels.setPixelColor(a, gr);
for (int i=b; i <= k; i++) pixels.setPixelColor(i, aus);
}
void LED1(int a,int b,int c,int d,int e,int f,int g,int h,int j,int k)
{
pixels.setPixelColor(a, gr);
pixels.setPixelColor(b, grb);
for (int i=k; i <= c; i++) pixels.setPixelColor(i, aus);
}
void LED2(int a,int b,int c,int d,int e,int f,int g,int h,int j,int k)
{
pixels.setPixelColor(a, gr);
pixels.setPixelColor(b, grb);
pixels.setPixelColor(c, grbl);
for (int i=d; i <= k; i++) pixels.setPixelColor(i, aus);
}
void LED3(int a,int b,int c,int d,int e,int f,int g,int h,int j,int k)
{
pixels.setPixelColor(a, gr);
pixels.setPixelColor(b, grb);
pixels.setPixelColor(c, grbl);
pixels.setPixelColor(d, gbl);
for (int i=k; i <= e; i++) pixels.setPixelColor(i, aus);
}
void LED4(int a,int b,int c,int d,int e,int f,int g,int h,int j,int k)
{
pixels.setPixelColor(a, gr);
pixels.setPixelColor(b, grb);
pixels.setPixelColor(c, grbl);
pixels.setPixelColor(d, gbl);
pixels.setPixelColor(e, bl);
for (int i=f; i <= k; i++) pixels.setPixelColor(i, aus);
}
void LED5(int a,int b,int c,int d,int e,int f,int g,int h,int j,int k)
{
pixels.setPixelColor(a, gr);
pixels.setPixelColor(b, grb);
pixels.setPixelColor(c, grbl);
pixels.setPixelColor(d, gbl);
pixels.setPixelColor(e, bl);
pixels.setPixelColor(f, blr);
for (int i=k; i <= g; i++) pixels.setPixelColor(i, aus);
}
void LED6(int a,int b,int c,int d,int e,int f,int g,int h,int j,int k)
{
pixels.setPixelColor(a, gr);
pixels.setPixelColor(b, grb);
pixels.setPixelColor(c, grbl);
pixels.setPixelColor(d, gbl);
pixels.setPixelColor(e, bl);
pixels.setPixelColor(f, blr);
pixels.setPixelColor(g, blro);
for (int i=h; i <= k; i++) pixels.setPixelColor(i, aus);
}
void LED7(int a,int b,int c,int d,int e,int f,int g,int h,int j,int k)
{
pixels.setPixelColor(a, gr);
pixels.setPixelColor(b, grb);
pixels.setPixelColor(c, grbl);
pixels.setPixelColor(d, gbl);
pixels.setPixelColor(e, bl);
pixels.setPixelColor(f, blr);
pixels.setPixelColor(g, blro);
pixels.setPixelColor(h, bro);
for (int i=k; i <= j; i++) pixels.setPixelColor(i, aus);
}
void LED8(int a,int b,int c,int d,int e,int f,int g,int h,int j,int k)
{
pixels.setPixelColor(a, gr);
pixels.setPixelColor(b, grb);
pixels.setPixelColor(c, grbl);
pixels.setPixelColor(d, gbl);
pixels.setPixelColor(e, bl);
pixels.setPixelColor(f, blr);
pixels.setPixelColor(g, blro);
pixels.setPixelColor(h, bro);
pixels.setPixelColor(j, ro);
pixels.setPixelColor(k, aus);
}
void LED9(int a,int b,int c,int d,int e,int f,int g,int h,int j,int k)
{
pixels.setPixelColor(a, gr);
pixels.setPixelColor(b, grb);
pixels.setPixelColor(c, grbl);
pixels.setPixelColor(d, gbl);
pixels.setPixelColor(e, bl);
pixels.setPixelColor(f, blr);
pixels.setPixelColor(g, blro);
pixels.setPixelColor(h, bro);
pixels.setPixelColor(j, ro);
pixels.setPixelColor(k, rog);
}
void abfolge(int a,int b,int c,int d,int e,int f,int g,int h,int j,int k)
{
switch (l)
{
case 93 ... 104:/*<---------------------------------------first LED area-------------
-------------------------------------------*/
LED0(a,b,c,d,e,f,g,h,j,k,gr);
break;
case 105 ... 139:/*<---------------------------------------second LED area--------
----------------------------------------------*/
LED1(a,b,c,d,e,f,g,h,j,k);
break;
case 140 ... 164:/*<---------------------------------------third LED area----------
---------------------------------------------*/
LED2(a,b,c,d,e,f,g,h,j,k);
break;
case 165 ... 199:/*<---------------------------------------fourth LED area---------
---------------------------------------------*/
LED3(a,b,c,d,e,f,g,h,j,k);
break;
case 200 ... 234:/*<---------------------------------------fith LED area------------
--------------------------------------------*/
LED4(a,b,c,d,e,f,g,h,j,k);
break;
case 235 ... 269:/*<---------------------------------------sixth LED area----------
---------------------------------------------*/
LED5(a,b,c,d,e,f,g,h,j,k);
break;
case 270 ... 304:/*<---------------------------------------seventh LED area-------
----------------------------------------------*/
LED6(a,b,c,d,e,f,g,h,j,k);
break;
case 305 ... 339:/*<---------------------------------------eighth LED area---------
---------------------------------------------*/
LED7(a,b,c,d,e,f,g,h,j,k);
break;
case 340 ... 374:/*<---------------------------------------nineth LED area---------
---------------------------------------------*/
LED8(a,b,c,d,e,f,g,h,j,k);
break;
case 375 ... 1000:/*<---------------------------------------tenth LED area---------
---------------------------------------------*/
LED9(a,b,c,d,e,f,g,h,j,k);
break;
}
}
void loop()
{
// Cycle through each frequency band by pulsing the strobe.
for (int i = 0; i < 7; i++)
{
digitalWrite (strobePin, LOW);
delayMicroseconds (100); // Delay necessary due to timing
diagram
level[i] = analogRead (outPin);
digitalWrite (strobePin, HIGH);
delayMicroseconds (100); // Delay necessary due to timing
diagram
}
/*-----------------------------------------------------------Band1(For the first LED
stripe)---------------------------------------------------------------*/
// allocation for the Numbers of LEDs
l = level [0];
abfolge(0,1,2,3,4,5,6,7,8,9);
if (l < 92) LEDaus1(0,1,2,3,4,5,6,7,8,9);
/*-----------------------------------------------------------Band2(For the second
LED stripe)---------------------------------------------------------------*/
// allocation for the Numbers of LEDs
l = level [1];
abfolge(19,18,17,16,15,14,13,12,11,10);
if (l < 92) LEDaus2(19,18,17,16,15,14,13,12,11,10);
/*-----------------------------------------------------------Band3(For the third
LED stripe)---------------------------------------------------------------*/
// allocation for the Numbers of LEDs
l = level [2];
abfolge(20,21,22,23,24,25,26,27,28,29);
if (l < 92) LEDaus1(20,21,22,23,24,25,26,27,28,29);
/*-----------------------------------------------------------Band4(For the fourth
LED stripe)---------------------------------------------------------------*/
// allocation for the Numbers of LEDs
l = level [3];
abfolge(39,38,37,36,35,34,33,32,31,30);
if (l < 92) LEDaus2(39,38,37,36,35,34,33,32,31,30);
/*-----------------------------------------------------------Band5(For the fifth LED
stripe)---------------------------------------------------------------*/
// allocation for the Numbers of LEDs
l = level [4];
abfolge(40,41,42,43,44,45,46,47,48,49);
if (l < 92) LEDaus1(40,41,42,43,44,45,46,47,48,49);
/*-----------------------------------------------------------Band6(For the sixth
LED stripe)---------------------------------------------------------------*/
// allocation for the Numbers of LEDs
l = level [5];
abfolge(59,58,57,56,55,54,53,52,51,50);
if (l < 92) LEDaus2(59,58,57,56,55,54,53,52,51,50);
/*-----------------------------------------------------------Band7(For the seventh
LED stripe)---------------------------------------------------------------*/
// allocation for the Numbers of LEDs
l = level [6];
abfolge(60,61,62,63,64,65,66,67,68,69);
if (l < 92) LEDaus1(60,61,62,63,64,65,66,67,68,69);
}

17) Arduino Line Follower Robot


COMPONENTS AND SUPPLIES
Arduino UNO & Genuino UNO
× 1

BO motor
× 1
wheels × 1

ir sensor
× 1

Texas Instruments Dual H-


Bridge motor drivers L293D
× 1

Custom PCB
× 1

9V battery (generic)
× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

Components used:
Piece of cardboard/ Acrylic sheet
Arduino Uno
IR sensor
BO motor
Wheels
Caster wheel
L293d IC
PCB
Flexible wire
Battery
Fix all components on acrylic sheet and make a
chassis as shown in pictures.
you can make this circuit on dotted pcb like this.

or can use this type of professional looking PCB.


SCHEMATICS
CODE
//
//for Line Following Robot using 2IR sensors
int lm1=8; //left motor output 1
int lm2=9; //left motor output 2
int rm1=10; //right motor output 1
int rm2=11; //right motor output 2
int sl=13; //sensor 1 input (left)
int sr=12; //sensor 2 input (right)
int SlV=0;
int SrV=0;
int led=A0;
void setup()
{
pinMode(lm1,OUTPUT);
pinMode(lm2,OUTPUT);
pinMode(rm1,OUTPUT);
pinMode(rm2,OUTPUT);
pinMode(led,OUTPUT);
pinMode(sl,INPUT);
pinMode(sr,INPUT);
sTOP();
}
void loop()
{
SlV=digitalRead(sl);
SrV=digitalRead(sr);
if(SrV==LOW && SlV== LOW)
{
ForWard();
}
if(SrV==HIGH && SlV== LOW)
{
Left();
}
if(SrV==LOW && SlV== HIGH)
{
Right();
}
if(SrV==HIGH && SlV== HIGH)
{
sTOP();
}
}
void ForWard()
{
digitalWrite(lm1,HIGH);
digitalWrite(lm2,LOW);
digitalWrite(rm1,HIGH);
digitalWrite(rm2,LOW);
}
void BackWard()
{
digitalWrite(lm1,LOW);
digitalWrite(lm2,HIGH);
digitalWrite(rm1,LOW);
digitalWrite(rm2,HIGH);
}
void Left()
{
digitalWrite(lm1,LOW);
digitalWrite(lm2,HIGH);
digitalWrite(rm1,HIGH);
digitalWrite(rm2,LOW);
}
void Right()
{
digitalWrite(lm1,HIGH);
digitalWrite(lm2,LOW);
digitalWrite(rm1,LOW);
digitalWrite(rm2,HIGH);
}
void sTOP()
{
digitalWrite(lm1,LOW);
digitalWrite(lm2,LOW);
digitalWrite(rm1,LOW);
digitalWrite(rm2,LOW);
}

78) Arduino Automated Plant Watering System


COMPONENTS AND SUPPLIES
Arduino Nano R3
× 1

DHT11 Temperature & × 1


Humidity Sensor (4 pins)
Seeed Grove - OLED Display
1.12'' V2
× 1

Espressif ESP8266 ESP-01


× 1

Relay (generic)
× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)

Hot glue gun (generic)

ABOUT THIS PROJECT

My country has been badly affected by climate change


due to heavy deforestation. So many campaigns arose
planting more trees. However, to reduce my effort in
gardening, I made something that water my plants
based on an Android app.
The concept is simple: I designed a web server using
ESP8266. Changed index a bit. Also, the ESP8266
controls the relay to water pump.
Pump to watering
The second component is an Arduino Nano, which
takes readings from DHT11 and displays on an OLED.
Complete control box

SCHEMATICS
CODE
Automated Garden Watering Nano

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>

#define DHTPIN 2 // what pin we're connected to


#define DHTTYPE DHT11 // DHT 11
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

// Initialize DHT sensor for normal 16mhz Arduino


DHT dht(DHTPIN, DHTTYPE);
String info;
boolean watering= false, status=false;
void setup()
{
Wire.begin();
dht.begin(); // initialize dht
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);// initialize with the I2C
addr 0x3C (for the 128x32)(initializing the display)
Serial.begin(9600);
}
void displayTempHumid(){
delay(2000);
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
// Read temperature as Celsius
float t = dht.readTemperature();
// Read temperature as Fahrenheit
float f = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t) || isnan(f)) {
display.clearDisplay(); // clearing the display
display.setTextColor(WHITE); //setting the color
display.setTextSize(1); //set the font size
display.setCursor(5,0); //set the cursor coordinates
display.print("Failed to read from DHT sensor!");
return;
}
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0,0);
display.print("Humidity: ");
display.print(h);
display.print(" %\t");
display.setCursor(0,10);
display.print("Temperature: ");
display.print(t);
display.print(" C");
display.setCursor(0,20);
display.print("Temperature: ");
display.print(f);
display.print(" F");
}

void loop()
{
displayTempHumid();
display.display();
}

Automated Garden Watering Esp8266

/*
* This sketch demonstrates how to set up a simple HTTP-like server.
* The server will set a GPIO pin depending on the request
* http://server_ip/gpio/0 will set the GPIO2 low,
* http://server_ip/gpio/1 will set the GPIO2 high
* server_ip is the IP address of the ESP8266 module, will be
* printed to Serial when the module is connected.
*/

#include <ESP8266WiFi.h>

const char* ssid = "ASH";


const char* password = "12345678";

// Create an instance of the server


// specify the port to listen on as an argument
WiFiServer server(80);

boolean waternow=false;

void setup() {
Serial.begin(9600);
delay(10);
pinMode(2, OUTPUT);

// Connect to WiFi network


Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);

WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {


delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
// Start the server
server.begin();
Serial.println("Server started");

// Print the IP address


Serial.write(WiFi.localIP());
}

void loop() {
// Check if a client has connected
WiFiClient client = server.available();
if (!client) {
return;
}

// Wait until the client sends some data


Serial.println("new client");
while(!client.available()){
delay(1);
}

// Read the first line of the request


String req = client.readStringUntil('\r');
client.flush();

int val;

if (req.indexOf("manu/ON") != -1){
waternow=true;}
else if (req.indexOf("manu/OFF") != -1){
waternow=false;}

else {
Serial.println("invalid request");
client.stop();
return;
}
client.flush();

delay(1);
Serial.println("Client disonnected");
if (waternow==true){ digitalWrite(2, HIGH);
delay (30000);
waternow=false;}
else{digitalWrite(2, LOW);}

// The client will actually be disconnected


// when the function returns and 'client' object is detroyed
}

79) Full Control of Your Tv Using Alexa and Arduino


IoT Cloud
COMPONENTS AND SUPPLIES

Arduino Nano 33 IoT


× 1

Resistor 330 ohm × 1


IR receiver (generic)
× 1
ex. VS1838B
IR transmitter (generic)
× 1

Jumper wires (generic)


× 1

Breadboard (generic)
× 1
APPS AND ONLINE SERVICES
Arduino Web Editor

Arduino IoT Cloud

Arduino Amazon Alexa Official


Arduino Skill

ABOUT THIS PROJECT

Intro: Arduino IoT Cloud


Arduino IoT Cloud is a platform that enables anyone
to build IoT connected object with ease. In order to
control our TV using Alexa, we'll also be using
the Official Arduino Alexa Skill.
If you are new to Arduino IoT Cloud, we advise to
first take a look at this introductory project, which will
give you an overview and guide you through the
process of setting up one of the supported boards, IoT
Cloud Things and Properties and get you onboard.
Part 1: How to Control a TV Set
The easiest way to control any kind of television, is to
act as if we were its very own remote infrared
controller. In order to do so, we'll have to listen for the
signals the remote will send, capture the data and
mimick it with our Arduino board. Once the circuit is
assembled, we'll upload this sketch to our board. It
will traslate the IR signal bursts generated by remote
button presses into an array of unsigned integers. Let's
point the remote at the Arduino IR Receiver we built
and press the following buttons:
POWER/STANDBY
CHANNELS FROM 1 TO 9
VOLUME UP
VOLUME DOWN
MUTE
CHANNEL UP
CHANNEL DOWN
We'll see the values coming through the Serial
Monitor, reported as rawData. Let's take note of them
into a text file for now, and assign each list its own
array name (chan1, chan2 and so on). The following
values are just for reference, and are generated by a
Samsung's TV remote.
CHANNEL 1
unsigned int chan1[67] = {4450,4500, 550,1700,
500,1700, 550,1700, 550,550, 550,600, 500,600,
550,550, 550,600, 500,1700, 550,1700, 550,1700,
500,600, 500,600, 550,550, 550,600, 500,600,
550,550, 550,600, 500,1700, 550,600, 500,600,
550,550, 550,600, 500,600, 550,1700, 500,1700,
550,600, 500,1700, 550,1700, 550,1700, 500,1700,
550,1700, 500};
CHANNEL 2
unsigned int chan2[67] = {4500,4500, 550,1700,
500,1700, 550,1700, 550,550, 550,550, 550,600,
500,600, 550,600, 500,1700, 550,1700, 500,1700,
550,600, 500,600, 550,550, 550,600, 500,600,
550,1700, 500,600, 550,1700, 500,600, 550,550,
550,600, 500,600, 550,550, 550,650, 450,1700,
550,600, 500,1700, 550,1700, 500,1700, 550,1700,
550,1700, 500};
CHANNEL 3
unsigned int chan3[67] = {4500,4500, 500,1700,
550,1700, 550,1700, 500,600, 550,550, 550,600,
500,600, 550,550, 550,1700, 500,1700, 550,1700,
550,550, 550,600, 500,600, 550,550, 550,600,
500,600, 550,1700, 500,1700, 550,600, 550,550,
550,550, 550,600, 550,550, 550,1700, 500,600,
550,550, 550,1700, 550,1650, 550,1700, 550,1700,
500,1700, 600};
CHANNEL 4
unsigned int chan4[67] = {4450,4450, 550,1700,
550,1700, 500,1700, 550,600, 500,600, 550,550,
600,550, 500,600, 550,1700, 500,1700, 550,1700,
550,550, 550,600, 500,600, 550,550, 550,600,
500,600, 550,550, 550,600, 500,1700, 550,600,
500,600, 550,550, 550,600, 500,1700, 550,1700,
550,1700, 500,600, 550,1700, 500,1700, 550,1700,
550,1700, 500};
CHANNEL 5
unsigned int chan5[67] = {4500,4500, 500,1700,
550,1700, 550,1700, 550,550, 550,550, 550,550,
600,550, 550,550, 550,1700, 550,1650, 550,1700,
550,550, 550,600, 500,600, 550,550, 550,600,
500,1700, 550,600, 500,600, 550,1700, 500,600,
550,550, 550,600, 550,550, 550,550, 550,1700,
550,1700, 500,600, 550,1700, 500,1700, 550,1700,
550,1700, 500};
CHANNEL 6
unsigned int chan6[67] = {4500,4500, 550,1650,
550,1700, 550,1700, 500,600, 550,550, 550,600,
500,600, 500,600, 550,1700, 500,1700, 550,1700,
550,550, 600,550, 500,600, 550,550, 600,550,
550,550, 550,1700, 500,600, 550,1700, 500,600,
550,550, 550,600, 500,600, 550,1700, 500,600,
550,1700, 500,600, 550,1650, 600,1650, 550,1700,
550,1650, 600};
CHANNEL 7
unsigned int chan7[67] = {4500,4500, 550,1700,
500,1700, 550,1750, 500,550, 550,600, 500,650,
500,550, 550,550, 550,1750, 500,1700, 500,1700,
550,650, 450,650, 500,550, 550,600, 500,650,
500,550, 550,600, 500,1700, 550,1750, 500,600,
500,550, 550,600, 500,650, 500,1750, 450,1700,
550,600, 500,650, 500,1700, 500,1700, 550,1750,
500,1700, 500};
CHANNEL 8
unsigned int chan8[67] = {4450,4550, 500,1700,
550,1700, 550,1650, 550,600, 500,600, 550,550,
550,600, 500,600, 550,1700, 500,1700, 550,1700,
550,550, 550,600, 500,600, 550,550, 550,600,
500,1700, 550,600, 500,1700, 550,1700, 500,600,
550,550, 550,650, 450,600, 550,550, 550,1700,
550,550, 550,600, 500,1700, 550,1700, 550,1700,
500,1700, 550};
CHANNEL 9
unsigned int chan9[67] = {4450,4500, 550,1700,
550,1700, 500,1700, 550,600, 500,600, 550,550,
550,600, 500,600, 550,1700, 500,1700, 550,1700,
500,600, 550,550, 550,600, 500,600, 550,550,
550,600, 500,1700, 550,1700, 550,1700, 500,600,
550,550, 550,550, 550,600, 500,1700, 550,600,
500,600, 550,550, 550,1700, 550,1700, 500,1700,
550,1700, 550};
VOLUME UP
unsigned int volUp[67] = {4500,4500, 550,1700,
500,1750, 500,1700, 550,600, 500,600, 500,600,
550,550, 550,600, 500,1700, 550,1700, 550,1700,
500,650, 450,600, 550,600, 500,650, 450,650,
500,1700, 500,1750, 500,1750, 500,550, 550,600,
500,650, 500,550, 550,600, 500,650, 500,600,
500,600, 500,1700, 550,1750, 450,1750, 500,1700,
550,1700, 500};
VOLUME DOWN
unsigned int volDown[67] = {4450,4550, 500,1700,
550,1700, 550,1650, 550,600, 550,550, 550,600,
500,600, 500,600, 550,1700, 500,1700, 550,1700,
550,550, 550,600, 500,600, 550,550, 550,600,
500,1700, 550,1700, 550,600, 500,1700, 550,600,
500,600, 500,600, 550,550, 550,600, 500,650,
500,1700, 500,650, 500,1700, 500,1750, 500,1700,
550,1700, 500};
CHANNEL UP
unsigned int chanUp[67] = {4500,4450, 550,1700,
550,1650, 550,1700, 550,550, 550,600, 550,550,
550,550, 600,550, 550,1650, 550,1700, 550,1650,
600,550, 550,550, 550,600, 500,600, 550,550,
550,550, 550,1700, 550,550, 600,550, 550,1650,
550,600, 550,550, 550,550, 550,1700, 550,550,
550,1700, 550,1700, 550,550, 550,1650, 600,1650,
550,1700, 550};
CHANNEL DOWN
unsigned int chanDown[67] = {4500,4450, 600,1650,
550,1700, 550,1650, 550,600, 550,550, 550,550,
550,600, 500,600, 550,1700, 500,1700, 550,1700,
550,550, 550,600, 550,550, 550,550, 550,550,
600,550, 550,550, 550,600, 500,600, 550,1650,
600,550, 550,550, 550,550, 600,1650, 550,1700,
500,1700, 600,1650, 550,550, 600,1650, 550,1700,
500,1700, 550};
Part 2: Arduino IoT Cloud
From the main Arduino IoT Cloud page, we'll create a
new Thing and assign it a meaningful name. Let's call
it TVRemoteController. We'll then select the board we
are going to use. For this tutorial we used an Arduino
Nano 33 IoT, but if you have another compatible
board it will also be fine, just keep in mind that the
pinout and the behavior of the IR library might
change. If at this point you cannot see your board, you
might have skipped the Getting Started procedure we
mentioned above, if this is the case, go back through
that process.
Once done, we'll add one Property to our Thing, it will
represent our TV set. Under the Smart Home category,
select "TV" as Property Type, set it as "Read &
Write", and under "Update" select "When the value
changes".
Here it is what the Properties view of our Thing
should look like at this point:

Our newly created Thing's property view


Part 3: Arduino Web Editor
The time has come to click on the "EDIT SKETCH"
button, which will take us the Web Editor, where we
can add some custom code to the Sketch automatically
generated by IoT Cloud.
The first thing we have to include is the IR
Remote library, by Ken Shirriff.
#include <IRremote.h>
We then have to setup one two-dimensional array for
our channels, and 6 arrays for the commands we need.
If you remember, in Part 1 we captured some IR data
which we'll now use to fill our arrays
const unsigned int chan[9][67] = {
{chan1},
{chan2},
{chan3},
{chan4},
{chan5},
{chan6},
{chan7},
{chan8},
{chan9}
};
const unsigned int volUp[67] = {...};
const unsigned int volDown[67] = {...};
const unsigned int chanUp[67] = {...};
const unsigned int chanDown[67] = {...};
const unsigned int onoff[67] = {...};
const unsigned int mute[67] = {...};
Let's then setup the IR library and the required frequency
(for this kind of application it will always be 38KHz)
IRsend irsend;
const int freq = 38;
We'll also need a function to send out IR commands and
blink the built-in LED (at this stage mostly for
debugging purposes). The delay value used will depend
on the make and model of your television, so feel free to
tweak it if things aren't working as expected (wrong
commands or no commands received).
void sendIR(const unsigned int buf[]) {
digitalWrite(LED_BUILTIN, HIGH);
irsend.sendRaw(buf, 67, freq);
delay(300);
digitalWrite(LED_BUILTIN, LOW);
}
The final step is to complete the generated
callback onTvChange() with some custom code in order
to send IR commands when the TV property is changed
by Alexa commands. For example, if the volume is
increased, we have to virtually press the button Volume
Up, if the channel is set to 7, we have to send the
sequence for the channel 7 button, and so on.
void onTvChange() {
Serial.println("==================");
Serial.println("Switch:"+String(tv.getSwitch()));
Serial.println("Volume:"+String(tv.getVolume()));
Serial.println("Channel:"+String(tv.getChannel()));
Serial.println("Mute:"+String(tv.getMute()));
Serial.println("==================");
if (first){
prevSwitch = tv.getSwitch();
prevVolume = tv.getVolume();
prevChannel = tv.getChannel();
prevMute = tv.getMute();
first = false;
return;
}
// Volume changed
if (tv.getVolume() > prevVolume) {
tv.setMute(false);
prevMute = false;
for (int k = prevVolume + 1 ; k<=tv.getVolume(); k++)
{
sendIR(volUp);
Serial.println("Volume
requested:"+String(tv.getVolume())+" Set:"+String(k));
}
prevVolume = tv.getVolume();
}
else if (tv.getVolume() < prevVolume) {
tv.setMute(false);
prevMute = false;
for (int k = prevVolume - 1; k>=tv.getVolume(); k--) {
sendIR(volDown);
Serial.println("Volume
changed:"+String(tv.getVolume())+" Set:"+String(k));
}
prevVolume = tv.getVolume();
}
// Mute changed
if (tv.getMute() != prevMute && tv.getMute()) {
prevMute = tv.getMute();
sendIR(mute);
Serial.println("Mute changed:"+String(tv.getMute()));
}
else if (tv.getMute() != prevMute && !tv.getMute()) {
prevMute = tv.getMute();
sendIR(mute);
Serial.println("Mute changed:"+String(tv.getMute()));
}
// Channel changed
if (tv.getChannel() != prevChannel) {
int newChannel = tv.getChannel();
if (newChannel > 0 && newChannel < 10) {
sendIR(chan[newChannel-1]);
} else if (newChannel > 9) {
if (newChannel > prevChannel) {
for (int ch = prevChannel; ch < newChannel; ch++)
{
sendIR(chanUp);
Serial.println("Chan
requested:"+String(newChannel)+" Set:"+String(ch));
}
} else if (newChannel < prevChannel) {
for (int ch = prevChannel; ch > newChannel; ch--)
{
sendIR(chanDown);
Serial.println("Chan
requested:"+String(newChannel)+" Set:"+String(ch));
}
}
}
prevChannel = newChannel;
Serial.println("Channel
changed:"+String(tv.getChannel()));
}
// On/Off changed
if (tv.getSwitch() != prevSwitch) {
prevSwitch = tv.getSwitch();
if (tv.getSwitch()) {
sendIR(chan[6]);
} else {
sendIR(onoff);
}
Serial.println("Switch
changed:"+String(tv.getSwitch()));
}
Part 4: Amazon Alexa
We will now need the Amazon Alexa app which can
be downloaded from the Apple App Store or
the Google Play Store. Once installed, login with your
existing account or create a new one.
Let's go through the steps necessary to install the
Arduino Alexa Skill and configure it to access and
control our TV. We'll follow the sequence of images
below to see all the required steps.
Tap on "Devices"
2/11: Let's now enable our Smart Home Skills
We'll be presented with the featured ones. Time to
search for what we need :)

We're done, it's now time to voice control our TV


asking things like
”Alexa, turn the volume up on TV.”
”Alexa, mute TV" or “Alexa, unmute TV.”
”Alexa, next channel on TV.”
SCHEMATICS
CODE
/*
Sketch generated by the Arduino IoT Cloud Thing
"TVRemoteController"
https://create.arduino.cc/cloud/things/994d9efc-9c38-
4a4c-9d3c-454106da00f6

Arduino IoT Cloud Properties description

The following variables are automatically generated


and updated when changes are made to the Thing
properties

CloudTelevision tv;

Properties which are marked as READ/WRITE in the


Cloud Thing will also have functions
which are called when their values are changed from
the Dashboard.
These functions are generated with the Thing and
added at the end of this sketch.
*/

#include "thingProperties.h"
#include <IRremote.h>
const unsigned int chan[9][67] = {
{4450,4500, 550,1700, 500,1700, 550,1700, 550,550,
550,600, 500,600, 550,550, 550,600, 500,1700,
550,1700, 550,1700, 500,600, 500,600, 550,550,
550,600, 500,600, 550,550, 550,600, 500,1700,
550,600, 500,600, 550,550, 550,600, 500,600,
550,1700, 500,1700, 550,600, 500,1700, 550,1700,
550,1700, 500,1700, 550,1700, 500},
{4500,4500, 550,1700, 500,1700, 550,1700, 550,550,
550,550, 550,600, 500,600, 550,600, 500,1700,
550,1700, 500,1700, 550,600, 500,600, 550,550,
550,600, 500,600, 550,1700, 500,600, 550,1700,
500,600, 550,550, 550,600, 500,600, 550,550,
550,650, 450,1700, 550,600, 500,1700, 550,1700,
500,1700, 550,1700, 550,1700, 500},
{4500,4500, 500,1700, 550,1700, 550,1700, 500,600,
550,550, 550,600, 500,600, 550,550, 550,1700,
500,1700, 550,1700, 550,550, 550,600, 500,600,
550,550, 550,600, 500,600, 550,1700, 500,1700,
550,600, 550,550, 550,550, 550,600, 550,550,
550,1700, 500,600, 550,550, 550,1700, 550,1650,
550,1700, 550,1700, 500,1700, 600},
{4450,4450, 550,1700, 550,1700, 500,1700, 550,600,
500,600, 550,550, 600,550, 500,600, 550,1700,
500,1700, 550,1700, 550,550, 550,600, 500,600,
550,550, 550,600, 500,600, 550,550, 550,600,
500,1700, 550,600, 500,600, 550,550, 550,600,
500,1700, 550,1700, 550,1700, 500,600, 550,1700,
500,1700, 550,1700, 550,1700, 500},
{4500,4500, 500,1700, 550,1700, 550,1700, 550,550,
550,550, 550,550, 600,550, 550,550, 550,1700,
550,1650, 550,1700, 550,550, 550,600, 500,600,
550,550, 550,600, 500,1700, 550,600, 500,600,
550,1700, 500,600, 550,550, 550,600, 550,550,
550,550, 550,1700, 550,1700, 500,600, 550,1700,
500,1700, 550,1700, 550,1700, 500},
{4500,4500, 550,1650, 550,1700, 550,1700, 500,600,
550,550, 550,600, 500,600, 500,600, 550,1700,
500,1700, 550,1700, 550,550, 600,550, 500,600,
550,550, 600,550, 550,550, 550,1700, 500,600,
550,1700, 500,600, 550,550, 550,600, 500,600,
550,1700, 500,600, 550,1700, 500,600, 550,1650,
600,1650, 550,1700, 550,1650, 600},
{4500,4500, 550,1700, 500,1700, 550,1750, 500,550,
550,600, 500,650, 500,550, 550,550, 550,1750,
500,1700, 500,1700, 550,650, 450,650, 500,550,
550,600, 500,650, 500,550, 550,600, 500,1700,
550,1750, 500,600, 500,550, 550,600, 500,650,
500,1750, 450,1700, 550,600, 500,650, 500,1700,
500,1700, 550,1750, 500,1700, 500},
{4450,4550, 500,1700, 550,1700, 550,1650, 550,600,
500,600, 550,550, 550,600, 500,600, 550,1700,
500,1700, 550,1700, 550,550, 550,600, 500,600,
550,550, 550,600, 500,1700, 550,600, 500,1700,
550,1700, 500,600, 550,550, 550,650, 450,600,
550,550, 550,1700, 550,550, 550,600, 500,1700,
550,1700, 550,1700, 500,1700, 550},
{4450,4500, 550,1700, 550,1700, 500,1700, 550,600,
500,600, 550,550, 550,600, 500,600, 550,1700,
500,1700, 550,1700, 500,600, 550,550, 550,600,
500,600, 550,550, 550,600, 500,1700, 550,1700,
550,1700, 500,600, 550,550, 550,550, 550,600,
500,1700, 550,600, 500,600, 550,550, 550,1700,
550,1700, 500,1700, 550,1700, 550}
};

const unsigned int volUp[67] = {4500,4500, 550,1700,


500,1750, 500,1700, 550,600, 500,600, 500,600,
550,550, 550,600, 500,1700, 550,1700, 550,1700,
500,650, 450,600, 550,600, 500,650, 450,650,
500,1700, 500,1750, 500,1750, 500,550, 550,600,
500,650, 500,550, 550,600, 500,650, 500,600,
500,600, 500,1700, 550,1750, 450,1750, 500,1700,
550,1700, 500};
const unsigned int volDown[67] = {4450,4550,
500,1700, 550,1700, 550,1650, 550,600, 550,550,
550,600, 500,600, 500,600, 550,1700, 500,1700,
550,1700, 550,550, 550,600, 500,600, 550,550,
550,600, 500,1700, 550,1700, 550,600, 500,1700,
550,600, 500,600, 500,600, 550,550, 550,600,
500,650, 500,1700, 500,650, 500,1700, 500,1750,
500,1700, 550,1700, 500};

const unsigned int chanUp[67] = {4500,4450,


550,1700, 550,1650, 550,1700, 550,550, 550,600,
550,550, 550,550, 600,550, 550,1650, 550,1700,
550,1650, 600,550, 550,550, 550,600, 500,600,
550,550, 550,550, 550,1700, 550,550, 600,550,
550,1650, 550,600, 550,550, 550,550, 550,1700,
550,550, 550,1700, 550,1700, 550,550, 550,1650,
600,1650, 550,1700, 550};
const unsigned int chanDown[67] = {4500,4450,
600,1650, 550,1700, 550,1650, 550,600, 550,550,
550,550, 550,600, 500,600, 550,1700, 500,1700,
550,1700, 550,550, 550,600, 550,550, 550,550,
550,550, 600,550, 550,550, 550,600, 500,600,
550,1650, 600,550, 550,550, 550,550, 600,1650,
550,1700, 500,1700, 600,1650, 550,550, 600,1650,
550,1700, 500,1700, 550};

const unsigned int onoff[67] = {4400,4600, 450,1800,


400,1800, 450,1750, 500,600, 450,750, 400,650,
450,700, 400,700, 400,1800, 450,1750, 450,1800,
450,650, 450,650, 450,700, 400,700, 450,650,
450,650, 450,1800, 450,600, 500,650, 400,700,
450,650, 500,600, 500,700, 400,1850, 400,700,
400,1750, 450,1800, 450,1750, 500,1700, 450,1800,
450,1850, 350};
const unsigned int mute[67] = {4550,4450, 550,1700,
450,1750, 500,1700, 550,600, 600,450, 600,550,
550,550, 600,550, 550,1650, 550,1650, 600,1650,
550,550, 600,500, 550,600, 550,500, 600,500,
600,1650, 600,1600, 600,1650, 600,1650, 550,550,
500,600, 550,550, 500,650, 500,600, 500,600,
500,600, 500,600, 500,1700, 550,1700, 500,1700,
550,1700, 500};

IRsend irsend;
const int freq = 38;
bool first;

int prevChannel;
int prevVolume;
bool prevSwitch;
bool prevMute;

void setup() {
// Initialize serial and wait for port to open:
Serial.begin(9600);
// This delay gives the chance to wait for a Serial
Monitor without blocking if none is found
delay(1500);

// Defined in thingProperties.h
initProperties();

// Connect to Arduino IoT Cloud


ArduinoCloud.begin(ArduinoIoTPreferredConnection)
;
setDebugMessageLevel(2);
ArduinoCloud.printDebugInfo();

first = true;
pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
ArduinoCloud.update();
}

void sendIR(const unsigned int buf[]) {


digitalWrite(LED_BUILTIN, HIGH);
irsend.sendRaw(buf, 67, freq);
delay(300);
digitalWrite(LED_BUILTIN, LOW);
}

void onTvChange() {
Serial.println("==================");
Serial.println("Switch:"+String(tv.getSwitch()));
Serial.println("Volume:"+String(tv.getVolume()));
Serial.println("Channel:"+String(tv.getChannel()));
Serial.println("Mute:"+String(tv.getMute()));
Serial.println("==================");

if (first){
prevSwitch = tv.getSwitch();
prevVolume = tv.getVolume();
prevChannel = tv.getChannel();
prevMute = tv.getMute();
first = false;
return;
}
// Volume changed
if (tv.getVolume() > prevVolume) {
tv.setMute(false);
prevMute = false;
for (int k = prevVolume + 1 ; k<=tv.getVolume(); k++)
{
sendIR(volUp);
Serial.println("Volume
requested:"+String(tv.getVolume())+"
Set:"+String(k));
}
prevVolume = tv.getVolume();
}
else if (tv.getVolume() < prevVolume) {
tv.setMute(false);
prevMute = false;
for (int k = prevVolume - 1; k>=tv.getVolume(); k--) {
sendIR(volDown);
Serial.println("Volume
changed:"+String(tv.getVolume())+" Set:"+String(k));
}
prevVolume = tv.getVolume();
}

// Mute changed
if (tv.getMute() != prevMute && tv.getMute()) {
prevMute = tv.getMute();
sendIR(mute);
Serial.println("Mute changed:"+String(tv.getMute()));
}
else if (tv.getMute() != prevMute && !tv.getMute()) {
prevMute = tv.getMute();
sendIR(mute);
Serial.println("Mute changed:"+String(tv.getMute()));
}

// Channel changed
if (tv.getChannel() != prevChannel) {
int newChannel = tv.getChannel();
if (newChannel > 0 && newChannel < 10) {
sendIR(chan[newChannel-1]);
} else if (newChannel > 9) {
if (newChannel > prevChannel) {
for (int ch = prevChannel; ch < newChannel; ch++) {
sendIR(chanUp);
Serial.println("Chan
requested:"+String(newChannel)+" Set:"+String(ch));
}
} else if (newChannel < prevChannel) {
for (int ch = prevChannel; ch > newChannel; ch--) {
sendIR(chanDown);
Serial.println("Chan
requested:"+String(newChannel)+" Set:"+String(ch));
}
}
}
prevChannel = newChannel;
Serial.println("Channel
changed:"+String(tv.getChannel()));
}

// On/Off changed
if (tv.getSwitch() != prevSwitch) {
prevSwitch = tv.getSwitch();
if (tv.getSwitch()) {
sendIR(chan[6]);
} else {
sendIR(onoff);
}
Serial.println("Switch
changed:"+String(tv.getSwitch()));
}

}
80) Arduino Rickoll Box

COMPONENTS AND SUPPLIES


Arduino UNO & Genuino UNO
× 1

Breadboard (generic) × 1
Buzzer
× 1

Photo resistor
× 1

LED (generic)
× 1

Single Turn Potentiometer- 10k


ohms
× 1

SparkFun Pushbutton switch


12mm
× 1

Resistor 10k ohm × 2


Resistor 560 ohm
× 2

Jumper wires (generic)


× 12

ABOUT THIS PROJECT

Basically, this involves a surprise piezo rendition of


the song “Never Gonna Give You Up” by Rick Astley
that plays when the box is opened and pauses when
the box is closed. When the box is reopened, the song
picks up where it left off. While the song is playing,
an LED blinks to the notes of the music, and the Serial
monitor outputs the lyrics in time with the actual song.
A potentiometer can be turned to adjust the volume of
the music. A fun button also exists that, when pressed,
makes the song get faster. It can be pressed a few
more times to make the tempo get progressively faster
until it loops back around to the original tempo.
I/O Components
Inputs:
Potentiometer –used as a dial to adjust volume of
piezo output
Photoresistor—determines whether box is open
or closed (light or dark)
Button – can be pressed to make song get
progressively faster
Outputs:
Piezo – used to create sound for song
LED – blinks to notes of song
Serial Output – prints out words of song
Circuit connections shown outside of box for clarity.
Circuit connections shown outside of box for clarity.
Methods
In order to play music, the song first had to be
transcribed into a form that could be interpreted in
code. The notes were determined by listening to the
song and matching them on the piano. The rhythms
were determined by counting and clapping out the
song to a consistent set of beats. In the code, these
notes were stored in arrays as their respective
frequencies, i.e. A4=440 Hz. This is how the Piezo
outputs noise; it generates sound at specified
frequencies to create a pitch. All frequencies required
for the song were defined at the beginning of the code.
For the rhythm of the song, relative durations of notes
were stored in arrays, and these durations were later
multiplied by a constant beat length in order to
determine the full duration of the note. A gap 30% of
the length of the previous note was introduced to
create space between notes. The full song was divided
into the intro, first verse, and chorus, which were set
to play in the following order indefinitely: chorus, first
verse, chorus, intro, intro, first verse etc. Finally, these
arrays of notes and rhythms could be iterated through
on a step-by-step basis, which allowed for the
integration of visual outputs, such as light and lyrics.
To actually output the sound from the piezo, the tone
function was used, which handles the tone duration
with its own independent timer. This necessitated
additional delay calls in order to keep the notes on
time with other parts of the code.
A light threshold was generated during setup in order
to determine when the box would be open (bright) and
closed (dark) in order to play and pause the song. In
order to take input from the button at any time, since
the state change is instantaneous (as opposed to the
photoresistor, which produces continuous digital
input), an interrupt was attached to the button pin in
order to detect when it was pressed. Interrupts,
initialized in the setup, are always listening for state
changes; when the specified change is detected, the
program immediately switches to handling the
interrupt with a specified method and then picks up
where it left off. This is a good way to handle inputs
because it allows them to be read at any time, even if
another portion of code is executing. Interrupts just
have to be handled carefully, and any variable that is
changed by them should be declared as volatile.
Future Modifications
Add a servo, and take a mini Rick Astley to its
arm to dance to the music.
Replace standard LED with RGB LED, and cycle
through colors during the song.
Add more standard LEDs to blink to the beat of
the music.
Whenever Rick Astley sings "Never gonna give
you up," play Darude "Sandstorm," and start
flashing LEDs at random.

SCHEMATICS
CODE
/*

This program is free software: you can redistribute it and/or


modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.

DISCLAIMER: The song "Never Gonna Give You Up" by Rick Astley
is not the creative property of the author. This code simply
plays a Piezo buzzer rendition of the song.
*/

#define a3f 208 // 208 Hz


#define b3f 233 // 233 Hz
#define b3 247 // 247 Hz
#define c4 261 // 261 Hz MIDDLE C
#define c4s 277 // 277 Hz
#define e4f 311 // 311 Hz
#define f4 349 // 349 Hz
#define a4f 415 // 415 Hz
#define b4f 466 // 466 Hz
#define b4 493 // 493 Hz
#define c5 523 // 523 Hz
#define c5s 554 // 554 Hz
#define e5f 622 // 622 Hz
#define f5 698 // 698 Hz
#define f5s 740 // 740 Hz
#define a5f 831 // 831 Hz

#define rest -1

int piezo = 7;
int led = 9;
int button = 2;
int sensor = A0;

volatile int beatlength = 100; // determines tempo


float beatseparationconstant = 0.3;

int threshold;

int a; // part index


int b; // song index
int c; // lyric index

boolean flag;

// Parts 1 and 2 (Intro)

int song1_intro_melody[] =
{c5s, e5f, e5f, f5, a5f, f5s, f5, e5f, c5s, e5f, rest, a4f, a4f};

int song1_intro_rhythmn[] =
{6, 10, 6, 6, 1, 1, 1, 1, 6, 10, 4, 2, 10};

// Parts 3 or 5 (Verse 1)

int song1_verse1_melody[] =
{ rest, c4s, c4s, c4s, c4s, e4f, rest, c4, b3f, a3f,
rest, b3f, b3f, c4, c4s, a3f, a4f, a4f, e4f,
rest, b3f, b3f, c4, c4s, b3f, c4s, e4f, rest, c4, b3f, b3f, a3f,
rest, b3f, b3f, c4, c4s, a3f, a3f, e4f, e4f, e4f, f4, e4f,
c4s, e4f, f4, c4s, e4f, e4f, e4f, f4, e4f, a3f,
rest, b3f, c4, c4s, a3f, rest, e4f, f4, e4f
};

int song1_verse1_rhythmn[] =
{ 2, 1, 1, 1, 1, 2, 1, 1, 1, 5,
1, 1, 1, 1, 3, 1, 2, 1, 5,
1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 3,
1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 4,
5, 1, 1, 1, 1, 1, 1, 1, 2, 2,
2, 1, 1, 1, 3, 1, 1, 1, 3
};

char* lyrics_verse1[] =
{ "We're ", "no ", "strangers ", "", "to ", "love ", "", "\r\n",
"You ", "know ", "the ", "rules ", "and ", "so ", "do ", "I\r\n",
"A ", "full ", "commitment's ", "", "", "what ", "I'm ", "thinking ", "", "of",
"\r\n",
"You ", "wouldn't ", "", "get ", "this ", "from ", "any ", "", "other ", "",
"guy\r\n",
"I ", "just ", "wanna ", "", "tell ", "you ", "how ", "I'm ", "feeling", "\r\n",
"Gotta ", "", "make ", "you ", "understand", "", "\r\n"
};

// Parts 4 or 6 (Chorus)

int song1_chorus_melody[] =
{ b4f, b4f, a4f, a4f,
f5, f5, e5f, b4f, b4f, a4f, a4f, e5f, e5f, c5s, c5, b4f,
c5s, c5s, c5s, c5s,
c5s, e5f, c5, b4f, a4f, a4f, a4f, e5f, c5s,
b4f, b4f, a4f, a4f,
f5, f5, e5f, b4f, b4f, a4f, a4f, a5f, c5, c5s, c5, b4f,
c5s, c5s, c5s, c5s,
c5s, e5f, c5, b4f, a4f, rest, a4f, e5f, c5s, rest
};

int song1_chorus_rhythmn[] =
{ 1, 1, 1, 1,
3, 3, 6, 1, 1, 1, 1, 3, 3, 3, 1, 2,
1, 1, 1, 1,
3, 3, 3, 1, 2, 2, 2, 4, 8,
1, 1, 1, 1,
3, 3, 6, 1, 1, 1, 1, 3, 3, 3, 1, 2,
1, 1, 1, 1,
3, 3, 3, 1, 2, 2, 2, 4, 8, 4
};

char* lyrics_chorus[] =
{ "Never ", "", "gonna ", "", "give ", "you ", "up\r\n",
"Never ", "", "gonna ", "", "let ", "you ", "down", "", "\r\n",
"Never ", "", "gonna ", "", "run ", "around ", "", "", "", "and ", "desert ", "",
"you\r\n",
"Never ", "", "gonna ", "", "make ", "you ", "cry\r\n",
"Never ", "", "gonna ", "", "say ", "goodbye ", "", "", "\r\n",
"Never ", "", "gonna ", "", "tell ", "a ", "lie ", "", "", "and ", "hurt ",
"you\r\n"
};

void setup()
{
pinMode(piezo, OUTPUT);
pinMode(led, OUTPUT);
pinMode(button, INPUT_PULLUP);
pinMode(sensor, INPUT);
attachInterrupt(digitalPinToInterrupt(button), getFaster, FALLING);
digitalWrite(led, LOW);
Serial.begin(9600);
flag = false;
a = 4;
b = 0;
c = 0;
threshold = analogRead(sensor) + 250;
}

void loop()
{
int sensorreading = analogRead(sensor);
if (sensorreading < threshold) { // if bright, play
flag = true;
}
else if (sensorreading > threshold) { // if dark, pause
flag = false;
}

// play next step in song


if (flag == true) {
play();
}
}

void play() {
int notelength;
if (a == 1 || a == 2) {
// intro
notelength = beatlength * song1_intro_rhythmn[b];
if (song1_intro_melody[b] > 0) {
digitalWrite(led, HIGH);
tone(piezo, song1_intro_melody[b], notelength);
}
b++;
if (b >= sizeof(song1_intro_melody) / sizeof(int)) {
a++;
b = 0;
c = 0;
}
}
else if (a == 3 || a == 5) {
// verse
notelength = beatlength * 2 * song1_verse1_rhythmn[b];
if (song1_verse1_melody[b] > 0) {
digitalWrite(led, HIGH);
Serial.print(lyrics_verse1[c]);
tone(piezo, song1_verse1_melody[b], notelength);
c++;
}
b++;
if (b >= sizeof(song1_verse1_melody) / sizeof(int)) {
a++;
b = 0;
c = 0;
}
}
else if (a == 4 || a == 6) {
// chorus
notelength = beatlength * song1_chorus_rhythmn[b];
if (song1_chorus_melody[b] > 0) {
digitalWrite(led, HIGH);
Serial.print(lyrics_chorus[c]);
tone(piezo, song1_chorus_melody[b], notelength);
c++;
}
b++;
if (b >= sizeof(song1_chorus_melody) / sizeof(int)) {
Serial.println("");
a++;
b = 0;
c = 0;
}
}
delay(notelength);
noTone(piezo);
digitalWrite(led, LOW);
delay(notelength * beatseparationconstant);
if (a == 7) { // loop back around to beginning of song
a = 1;
}
}

void getFaster() { // decrease beat length in order to increase tempo


beatlength = beatlength / 2;
if (beatlength < 20) { // loop back to original tempo
beatlength = 100;
}
}
81) Arduino A Very Compact Alarm with Card
Reader and Real Time Clock

COMPONENTS AND SUPPLIES

Arduino UNO & Genuino UNO × 1


PHPoC Bread Board
× 1

LED (generic)
× 2

Resistor 221 ohm


× 2

Ultrasonic Sensor - HC-SR04


(Generic)
× 1

Buzzer
× 1

RC522 Card Reader × 1


Real Time Clock
× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

This is my first project released on Hackster and every


suggestion is accepted. Well, I've made this alarm just
for fun and I hope you will like it!
How does the alarm work?
In order to see from the image to start the alarm, you
must put the correct magnetic card on the RC522 Card
Reader. If the card is indeed correct, the alarm will
turn on automatically (green LED: on; red LED: off),
but if the card isn't correct, nothing is happening
(green LED: off; red LED: on).
When the alarm is started, the HC-SR04 Ultrasonic
Sensor will capture any movement in front of it.
To shut down the alarm, we will again put the correct
magnetic card on RC522 Card Reader (green LED:
off; red LED: on).
What if you forget to turn on the alarm before going to
sleep?
We can go to sleep without activating the alarm
because the Real Time Clock will activate the alarm at
a certain hour.
Here you can find some code explanation:
On line 29, you can set the code of your magnetic
card.
String codiceAutorizzato = "5545A93980";
On line 53, you can schedule the automatic start of the
alarm (24 hours format).
if (orario=="21:56" && statoattivato==0)
On line 65, you can set the maximum distance from
which the sensor works (it must be expressed in
centimeters). Beyond this limit, the sensor won't work
and no movement will be notice.
if (sr04.Distance()<120)
For every explanation or suggestion, feel free to
comment below.
I'm sorry, I can't make my real schematics because
with Fritzing I can't compact the circuit, please
forgive me ;-)

SCHEMATICS
CODE

#include <RFID.h>
#include <SPI.h>
#include <SR04.h>
#include <DS3231.h>
#include <Wire.h>
String ora;
String mins;
String orario;
DS3231 Clock;

#define ECHO_PIN 3
#define TRIG_PIN 4
#define green 5
#define red 6
#define buzz 8
#define RESET_DIO 9
#define SDA_DIO 10

#define delayRead 600

SR04 sr04 = SR04(ECHO_PIN,TRIG_PIN);


RFID RC522(SDA_DIO, RESET_DIO);

bool h12;
bool PM;
int attivo=false;
int statoattivato=0;
String codiceLetto;
String codiceAutorizzato = "5545A93980";

void setup(){
Wire.begin();
SPI.begin();
RC522.init();
pinMode(buzz,OUTPUT);
pinMode(red,OUTPUT);
pinMode(green,OUTPUT);
digitalWrite(green,LOW);
digitalWrite(red,HIGH);
}

void loop(){
ora=Clock.getHour(h12, PM), DEC;
mins=Clock.getMinute(), DEC;
orario=ora+":"+mins;
byte i;
if (RC522.isCard()) {
if(verificaCodice(lettura())) {
rilevatore();
}
delay(delayRead);
}
if (orario=="21:56" && statoattivato==0) {
statoattivato=1;
rilevatore();
}
}

void rilevatore() {
if (attivo==false) {
attivo=true;
digitalWrite(red,LOW);
digitalWrite(green,HIGH);
while (attivo=true) {
if (sr04.Distance()<120)
tone(8,262,500);
if (RC522.isCard()) {
if (verificaCodice(lettura())) {
attivo=false;
digitalWrite(green,LOW);
digitalWrite(red,HIGH);
break;
}
}
}
}
}

boolean verificaCodice(String codiceLetto){


if(codiceLetto.equals(codiceAutorizzato)){
return true;
}
else{
return false;
}
}

String lettura(){
byte i;
RC522.readCardSerial();
String codiceLetto ="";
for(i = 0; i <= 4; i++) {
codiceLetto += String (RC522.serNum[i],HEX);
codiceLetto.toUpperCase();
}
return codiceLetto;
}
82) Arduino Smart Whellchair
COMPONENTS AND SUPPLIES
Arduino UNO & Genuino UNO
× 1

SparkFun Dual H-Bridge motor


drivers L298
× 1

HC-05 Bluetooth Module


× 1

Ultrasonic Sensor - HC-SR04


(Generic)
× 1

DC motor (generic)
× 1

Rocker Switch, Non Illuminated


× 1

SparkFun Pushbutton switch × 1


12mm

Buzzer
× 1

Breadboard (generic)
× 1

Li-Ion Battery 1000mAh


× 1

5 mm LED: Red
× 1

Jumper wires (generic)


× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

Objective
The objective of this project is to help physically
challenged people. It will basically very helpful for
those who cannot able to walk.
Introduction
This is a simple prototype of Smart Wheelchair. The
wheelchair is multi functioned. One can use this
wheelchair for various purposes. This chair can be
used as panic alarm. If the person needs instant help,
he/she can hit the panic alarm button so that someone
can help him/her immediately. This wheelchair also
has a led light. So, anyone can roam here and there
when the surroundings has not enough light. Last but
not the least this wheelchair is also automatically
identify the obstacles and it makes decision to go with
the obstacle free path.
Required Equipments
Arduino UNO
Motor Driver (Model:L298N)
Bluetooth Module (Model:HC-05)
Ultrasonic Sensor (Model:HC-SR04)
DC Motor
Lipo Battery(1000mAh)
Breadboard
LED
Push Button
Switch(ON/OFF)
Buzzer
Jumper Wire (Male to Male | Male to Female |
Female to Female)
Connections
A) Motor Driver to Arduino
IN1 to Digital Pin 8
IN2 to Digital Pin 9
IN3 to Digital Pin 10
IN4 to Digital Pin 11
+12V to Lipo Battery Positive Lead
GND to Lipo Battery Negative Lead
+5V to VIN (Arduino)
B)Bluetooth Module to Arduino
+5V (Arduino) to +5V (Bluetooth)
GND (Arduino) to GND (Bluetooth)
RX (Arduino) to TX (Bluetooth)
TX (Arduino) to RX (Bluetooth)
C) Ultrasonic Sensor to Arduino
Trig Pin to Digital Pin 12
Echo Pin to Digital Pin 13
Trig Pin to Digital Pin 7
Echo Pin to Digital Pin 6
VCC to 5V
GND to GND
D) Other Connections
Led Light (Anode ) to Digital Pin 5 (Arduino)
Buzzer (Positive Lead) to Digital
Pin 4 (Arduino)
Push Button (Positive Lead) to Digital
Pin 3 (Arduino)
Bluetooth App Google Play Store Link
App Download
Link: https://play.google.com/store/apps/details?
id=com.keuwl.arduinobluetooth
Bluetooth App Setting
Step-1
First download the app from the Google Play Store. I
have given the link of the app in the above (Bluetooth
App Google Play Store Link) Section.
Android App
Step-2
Edit a new panel for your Wheelchair controls

Edit a new panel for Wheelchair


Step-3
Now click on the "Connect" button and select
"Bluetooth Classic" option then click "Next" button to
build up the bluetooth connection.

Click on Connect

Click on Bluetooth Classic


Step-4
After pairing between the application and "HC-05
Bluetooth Module" and click "Done" button. Finally
Click "Run" button to start working with this app.

Click Done
Important Instructions
During the uploading the code on Arduino we
need to pull down the RX and TX connection
from the Arduino.
Lipo Battery is very powerful battery. So, make
sure that the each connections are perfectly ok.
SCHEMATICS
CODE
int motorRightA = 8; //Right Motor-clockwise
int motorRightB = 9; //Right Motor-anticlockwise
int motorLeftA = 11; //Left Motor-clockwise
int motorLeftB = 10; //Left Motor-clockwise
int trigPin1 = 12; // Trig Pin
int echoPin1 = 13; // Echo Pin
int light = 5;
long duration1;
int distance1;
char bt = 0; //Bluetooth Control
int trigPin2 = 7; // Trig Pin
int echoPin2 = 6; // Echo Pin
long duration2;
int distance2;
int buzzer = 4;
int pushButton = 3;
void setup()
{
pinMode(motorRightA, OUTPUT);
pinMode(motorRightB, OUTPUT);
pinMode(motorRightB, OUTPUT);
pinMode(motorLeftB, OUTPUT);
pinMode(trigPin1, OUTPUT);
pinMode(echoPin1, INPUT);
pinMode(trigPin2, OUTPUT);
pinMode(echoPin2, INPUT);
pinMode(light, OUTPUT);
pinMode(buzzer, OUTPUT);
pinMode(pushButton, INPUT_PULLUP);
Serial.begin(9600);
}
void loop()
{
//Light On Off
lightOnOff();
//Panic Button
panicSound();
// Right
digitalWrite(trigPin1, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin1, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin1, LOW);
// Reads the echoPin, returns the sound wave travel time
in microseconds
duration1 = pulseIn(echoPin1, HIGH);
// Calculating the distance
distance1 = duration1 * 0.034 / 2;
// Prints the distance on the Serial Monitor
Serial.print("Distance: ");
Serial.println(distance1);
// Left
digitalWrite(trigPin2, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin2, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin2, LOW);
// Reads the echoPin, returns the sound wave travel time
in microseconds
duration2 = pulseIn(echoPin2, HIGH);
// Calculating the distance
distance2 = duration2 * 0.034 / 2;
// Prints the distance on the Serial Monitor
Serial.print("Distance: ");
Serial.println(distance2);

if (distance1 <= 20 || distance2 <= 20) {


//Stop Wheel Chair
digitalWrite(motorRightA, LOW);
digitalWrite(motorRightB, LOW);
digitalWrite(motorLeftA, LOW);
digitalWrite(motorLeftB, LOW);
control();
}
else {
control(); // Call All the Control
}
}
// All the Controls of the Wheel Chair
void control() {
if (Serial.available() > 0)
{
bt = Serial.read();
if (bt == 'F') //move forwards
{
digitalWrite(motorRightA, HIGH);
digitalWrite(motorLeftA, HIGH);
}
else if (bt == 'B') //move backwards
{
digitalWrite(motorRightB, HIGH);
digitalWrite(motorLeftB, HIGH);
}
else if (bt == 'S') //stop!
{
digitalWrite(motorRightA, LOW);
digitalWrite(motorRightB, LOW);
digitalWrite(motorLeftA, LOW);
digitalWrite(motorLeftB, LOW);
}
else if (bt == 'R') //right
{
digitalWrite(motorRightA, LOW);
digitalWrite(motorRightB, LOW);
digitalWrite(motorLeftA, HIGH);
digitalWrite(motorLeftB, LOW);
}
else if (bt == 'L') //left
{
digitalWrite(motorRightA, HIGH);
digitalWrite(motorRightB, LOW);
digitalWrite(motorLeftA, LOW);
digitalWrite(motorLeftB, LOW);
}
else if (bt == 'I') //forward right
{
digitalWrite(motorRightA, HIGH);
digitalWrite(motorRightB, LOW);
digitalWrite(motorLeftA, LOW);
digitalWrite(motorLeftB, HIGH);
}
else if (bt == 'G') //forward left
{
digitalWrite(motorRightA, LOW);
digitalWrite(motorRightB, HIGH);
digitalWrite(motorLeftA, HIGH);
digitalWrite(motorLeftB, LOW);
}
}
}

void lightOnOff() {

if (bt == 'O') {
digitalWrite(light, HIGH);
}
else if (bt == 'o') {
digitalWrite(light, LOW);
}
}
void panicSound() {
int val = digitalRead(pushButton);
if (val == LOW) {
digitalWrite(buzzer, HIGH);
} else {
digitalWrite(buzzer, LOW);
}
}
83) Arduino Social Distancing Reminder

COMPONENTS AND SUPPLIES

Arduino UNO & Genuino UNO


Arduino Nano works better for
× 1
this, but I have used an
Arduino UNO.
Arduino Proto Shield × 1
I used it, but it's optional.

Adafruit Mini Breadboard


× 1

Elegoo 16 x 2 LCD Display


× 1

Ultrasonic Sensor - HC-SR04


(Generic)
× 1

Touch sensor
You can also use a button, but
× 1
you'll need a pull-down
resistor.
NTC Thermistor
× 1

Resistor 10k ohm


× 1

Buzzer × 1
Rotary potentiometer (generic)
This is to adjust the contrast of × 1
the LCD.

Jumper wires (generic)


× 1

A transparent box to put


everything into
It needs to be transparent for
× 1
you to be able to see the LCD
and it needs to be waterproof to
light rain
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

What is it?
Reasonably, the most reliable approach to slowing
down the spread of the coronavirus is to keep away
from others; prevention is better than cure. However,
it would be irritating to turn around every thirty
seconds and look if someone was approaching you. It
would be helpful if there were a device that could
warn others to keep away from you. That is the
purpose behind the project: to alert others to maintain
a 2-meter distance from you. It is a 2-in-1 as the
thermistor is not only used to add accuracy to the
distance measurement (the speed of sound changes
depending on the temperature) but it also means that –
by using a button or a touch sensor to switch between
the modes – it can have two modes: alerting if
someone comes close to you (Mode 1) and measuring
the temperature and the distance (Mode 2). The
measuring mode shows the temperature and the
distance on the LCD.
How does it work?
The Arduino measures the temperature.
The temperature is used to calculate the distance
with greater accuracy.
If the Arduino is on Mode 1:
If the distance is between 2m and 1m, the LCD
backlight lights up and the LCD shows "Please
keep away" and how far away the person is.
If the distance is 1m - 50cm the backlight of the
LCD flashes and the LCD shows "Keep away"
If the distance is less than 50cm the backlight
turns off and on twice a second and the LCD
shows "STAY AWAY!"
If the Arduino is on Mode 2, the LCD shows the
distance on the top and the temperature on the bottom
of the screen.
To protect the components from the rain, I attached
half a plastic bottle which can be pushed up when
there is rain.
It can be attached to (using two pieces of string) and
be easily removed from the bottom of a rucksack.
Mode 2
1m to 50cm
Closer than 50cm

2m to 1m

Protection from light rain

It can be attached to the bottom of a bag with


string.
The touch sensor is used to switch between the modes.
The simplified algorithm
How do I build it?
Connect the components according to the circuit
diagram below.
Once you have done that, import the libraries under
the section named 'Code' – which you can do by
(assuming you have opened the Arduino IDE) going to
'Sketch' —> 'Include Library' —> 'Add .ZIP Library...'
and selecting the library (which should be a .zip file).
Both libraries are needed for the code to work.
Importing a library

Importing a library
SCHEMATICS

CODE
#include <HCSR04.h>
#include <LiquidCrystal.h>
#define trigPin 7
#define echoPin 6
#define buzzer 9
#define backlight 10

LiquidCrystal lcd(12, 11, 5, 4, 3, 8);


UltraSonicDistanceSensor distanceSensor(trigPin, echoPin);

int tempReading;
double tempK;
float tempC;
int rounded;
int temp_round;
volatile boolean modes = 0;
double distance;

void setup() {
lcd.begin(16, 2);
attachInterrupt(0, changeMode, FALLING);
pinMode(2, INPUT);
pinMode(buzzer, OUTPUT);
pinMode(backlight, OUTPUT);
digitalWrite(backlight, HIGH);
backlightOn();
}

void loop() {
tempReading = analogRead(A0);
tempK = log(10000.0 * ((1024.0 / tempReading - 1)));
tempK = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * tempK
* tempK )) * tempK );
tempC = tempK - 273.15;
distance = distanceSensor.measureDistanceCm(tempC);
temp_round = round(tempC);
if (modes == 1) {
backlightOn();
if (distance >= 300 || distance <= 0) {
rounded = 0;
lcd.clear();
lcd.print("Out of range");
lcd.setCursor(0, 1);
lcd.print("Temperature:" + String(temp_round) + " C");
}
else {
rounded = round(distance);
lcd.clear();
lcd.print("Distance: ");
lcd.print(rounded);
lcd.print(" cm");
lcd.setCursor(0, 1);
lcd.print("Temperature:" + String(temp_round) + " C");
}
} else {
if (distance >= 300 || distance <= 0) {
rounded = 0;
lcd.clear();
backlightOff();
}
else {
rounded = round(distance);
if (distance >= 200) {
backlightOff();
lcd.clear();
}
else if (distance <= 200 && distance > 100) {
backlightOn();
lcd.clear();
lcd.print("Please keep away");
lcd.setCursor(0, 1);
lcd.print("Distance:");
lcd.print(rounded);
lcd.print(" cm");
}
else if (distance <= 100 && distance > 50) {
backlightOn();
lcd.clear();
lcd.print("Keep away");
lcd.setCursor(0, 1);
lcd.print("Distance:");
lcd.print(rounded);
lcd.print(" cm");
delay(200);
buzz();
backlightOff();
delay(100);
unbuzz();
backlightOn();
delay(100);
}
else if (distance <= 50) {
backlightOn();
lcd.clear();
lcd.print("STAY AWAY!");
lcd.setCursor(0, 1);
lcd.print("Distance:");
lcd.print(rounded);
lcd.print(" cm");
delay(200);
buzz();
backlightOff();
delay(200);
unbuzz();
backlightOn();
delay(200);
buzz();
backlightOff();
delay(200);
unbuzz();
backlightOn();
}
}
}
delay(700);
}

void changeMode() {
modes = !modes;
}

void backlightOn() {
digitalWrite(backlight, HIGH);
}

void backlightOff() {
digitalWrite(backlight, LOW);
}

void buzz() {
digitalWrite(buzzer, HIGH);
}

void unbuzz() {
digitalWrite(buzzer, LOW);
}

84) Arduino RGB Goggles


COMPONENTS AND SUPPLIES
Arduino Nano R3
× 1

SparkFun RGB LED Breakout - × 88


WS2812B
HC-05 Bluetooth Module
× 1

Battery, 3.7 V
× 1

Toggle Switch, On-On


× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)
APPS AND ONLINE SERVICES

Arduino IDE

ABOUT THIS PROJECT

Hey! I have made a RGB Goggles using WS2812B


LEDs and Arduino Nano. The goggles have many
animations they can be controlled using a mobile
app.The app can communicate with Arduino through
Bluetooth module. This goggles are lightweight.
SCHEMATICS
CODE
#include <FastLED.h>
#define LED_PIN 3
#define NUM_LEDS 88
#define LED_TYPE WS2812B
#define COLOR_ORDER RGB
#define BRIGHTNESS 255
#define UPDATES_PER_SECOND 100

#define kMatrixWidth 17
#define kMatrixHeight 6
#define kMatrixSerpentineLayout true

CRGBArray<NUM_LEDS> leds;

uint32_t x,y,v_time,hue_time,hxy;
uint8_t octaves=1;
uint8_t hue_octaves=3;
int xscale=57771;
int yscale=57771;
int hue_scale=1;
int time_speed=1111;
int hue_speed=31;
int x_speed=331;
int y_speed=1111;

CRGBPalette16 currentPalette;
TBlendType currentBlending;
extern CRGBPalette16 myRedWhiteBluePalette;
extern const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM;

void setup()
{
Serial.begin(9600);
delay(1000);
FastLED.addLeds<NEOPIXEL,LED_PIN>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS);
currentPalette = RainbowColors_p;
currentBlending = LINEARBLEND;

random16_set_seed(8934);
random16_add_entropy(analogRead(3));
hxy = (uint32_t)((uint32_t)random16() << 16) + (uint32_t)random16();
x = (uint32_t)((uint32_t)random16() << 16) + (uint32_t)random16();
y = (uint32_t)((uint32_t)random16() << 16) + (uint32_t)random16();
v_time = (uint32_t)((uint32_t)random16() << 16) + (uint32_t)random16();
hue_time = (uint32_t)((uint32_t)random16() << 16) +
(uint32_t)random16();
}

void fadeall() { for(int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(250); }


}

char ch;
void loop()
{
FastLED.clear();
FastLED.show();
if(Serial.available())
{
ch=Serial.read();
Serial.println(ch);
switch (ch)
{
case '1':
for(int i=0;i<10;i++)
{
leds[37] = CRGB(255, 0, 0);
leds[44] = CRGB(255, 0, 0);
FastLED.show();
delay(90);
FastLED.clear();
leds[20] = CRGB(255, 0, 0);
leds[30] = CRGB(255, 0, 0);
leds[36] = CRGB(255, 0, 0);
leds[38] = CRGB(255, 0, 0);
leds[43] = CRGB(255, 0, 0);
leds[45] = CRGB(255, 0, 0);
leds[51] = CRGB(255, 0, 0);
leds[58] = CRGB(255, 0, 0);
FastLED.show();
delay(90);
FastLED.clear();

leds[19] = CRGB(255, 0, 0);


leds[21] = CRGB(255, 0, 0);
leds[29] = CRGB(255, 0, 0);
leds[31] = CRGB(255, 0, 0);
leds[35] = CRGB(255, 0, 0);
leds[36] = CRGB(255, 0, 0);
leds[37] = CRGB(255, 0, 0);
leds[38] = CRGB(255, 0, 0);
leds[39] = CRGB(255, 0, 0);
leds[42] = CRGB(255, 0, 0);
leds[43] = CRGB(255, 0, 0);
leds[44] = CRGB(255, 0, 0);
leds[45] = CRGB(255, 0, 0);
leds[46] = CRGB(255, 0, 0);
leds[50] = CRGB(255, 0, 0);
leds[51] = CRGB(255, 0, 0);
leds[52] = CRGB(255, 0, 0);
leds[57] = CRGB(255, 0, 0);
leds[58] = CRGB(255, 0, 0);
leds[59] = CRGB(255, 0, 0);
leds[65] = CRGB(255, 0, 0);
leds[72] = CRGB(255, 0, 0);
FastLED.show();

delay(90);
FastLED.clear();

leds[1] = CRGB(255, 0, 0);


leds[2] = CRGB(255, 0, 0);
leds[4] = CRGB(255, 0, 0);
leds[5] = CRGB(255, 0, 0);
leds[6] = CRGB(0, 0, 0);
leds[11] = CRGB(255, 0, 0);
leds[12] = CRGB(255, 0, 0);
leds[14] = CRGB(255, 0, 0);
leds[15] = CRGB(255, 0, 0);
leds[17] = CRGB(255, 0, 0);
leds[18] = CRGB(255, 0, 0);
leds[19] = CRGB(255, 0, 0);
leds[20] = CRGB(255, 0, 0);
leds[21] = CRGB(255, 0, 0);
leds[22] = CRGB(255, 0, 0);
leds[23] = CRGB(255, 0, 0);
leds[27] = CRGB(255, 0, 0);
leds[28] = CRGB(255, 0, 0);
leds[29] = CRGB(255, 0, 0);
leds[30] = CRGB(255, 0, 0);
leds[31] = CRGB(255, 0, 0);
leds[32] = CRGB(255, 0, 0);
leds[33] = CRGB(255, 0, 0);
leds[34] = CRGB(255, 0, 0);
leds[35] = CRGB(255, 0, 0);
leds[36] = CRGB(255, 0, 0);
leds[37] = CRGB(255, 0, 0);
leds[38] = CRGB(255, 0, 0);
leds[39] = CRGB(255, 0, 0);
leds[40] = CRGB(255, 0, 0);
leds[41] = CRGB(255, 0, 0);
leds[42] = CRGB(255, 0, 0);
leds[43] = CRGB(255, 0, 0);
leds[44] = CRGB(255, 0, 0);
leds[45] = CRGB(255, 0, 0);
leds[46] = CRGB(255, 0, 0);
leds[47] = CRGB(255, 0, 0);
leds[49] = CRGB(255, 0, 0);
leds[50] = CRGB(255, 0, 0);
leds[51] = CRGB(255, 0, 0);
leds[52] = CRGB(255, 0, 0);
leds[53] = CRGB(255, 0, 0);
leds[56] = CRGB(255, 0, 0);
leds[57] = CRGB(255, 0, 0);
leds[58] = CRGB(255, 0, 0);
leds[59] = CRGB(255, 0, 0);
leds[60] = CRGB(255, 0, 0);
leds[64] = CRGB(255, 0, 0);
leds[65] = CRGB(255, 0, 0);
leds[66] = CRGB(255, 0, 0);
leds[71] = CRGB(255, 0, 0);
leds[72] = CRGB(255, 0, 0);
leds[73] = CRGB(255, 0, 0);
leds[79] = CRGB(255, 0, 0);
leds[84] = CRGB(255, 0, 0);
FastLED.show();
delay(90);
FastLED.clear();

leds[19] = CRGB(255, 0, 0);


leds[21] = CRGB(255, 0, 0);
leds[29] = CRGB(255, 0, 0);
leds[31] = CRGB(255, 0, 0);
leds[35] = CRGB(255, 0, 0);
leds[36] = CRGB(255, 0, 0);
leds[37] = CRGB(255, 0, 0);
leds[38] = CRGB(255, 0, 0);
leds[39] = CRGB(255, 0, 0);
leds[42] = CRGB(255, 0, 0);
leds[43] = CRGB(255, 0, 0);
leds[44] = CRGB(255, 0, 0);
leds[45] = CRGB(255, 0, 0);
leds[46] = CRGB(255, 0, 0);
leds[50] = CRGB(255, 0, 0);
leds[51] = CRGB(255, 0, 0);
leds[52] = CRGB(255, 0, 0);
leds[57] = CRGB(255, 0, 0);
leds[58] = CRGB(255, 0, 0);
leds[59] = CRGB(255, 0, 0);
leds[65] = CRGB(255, 0, 0);
leds[72] = CRGB(255, 0, 0);
FastLED.show();

delay(90);
FastLED.clear();

leds[20] = CRGB(255, 0, 0);


leds[30] = CRGB(255, 0, 0);
leds[36] = CRGB(255, 0, 0);
leds[38] = CRGB(255, 0, 0);
leds[43] = CRGB(255, 0, 0);
leds[45] = CRGB(255, 0, 0);
leds[51] = CRGB(255, 0, 0);
leds[58] = CRGB(255, 0, 0);
FastLED.show();
delay(90);
FastLED.clear();
}
break;

case '2':
for(int i=0;i<5;i++)
{
leds[36] = CRGB(255, 0, 187);
leds[37] = CRGB(255, 0, 187);
leds[44] = CRGB(255, 0, 187);
leds[45] = CRGB(255, 0, 187);
leds[50] = CRGB(255, 0, 187);
leds[51] = CRGB(255, 0, 187);
leds[58] = CRGB(255, 0, 187);
leds[59] = CRGB(255, 0, 187);
FastLED.show();
delay(90);
FastLED.clear();

leds[19] = CRGB(255, 0, 187);


leds[20] = CRGB(255, 0, 187);
leds[30] = CRGB(255, 0, 187);
leds[31] = CRGB(255, 0, 187);
leds[35] = CRGB(255, 0, 187);
leds[38] = CRGB(255, 0, 187);
leds[43] = CRGB(255, 0, 187);
leds[46] = CRGB(255, 0, 187);
leds[49] = CRGB(255, 0, 187);
leds[52] = CRGB(255, 0, 187);
leds[57] = CRGB(255, 0, 187);
leds[60] = CRGB(255, 0, 187);
leds[64] = CRGB(255, 0, 187);
leds[65] = CRGB(255, 0, 187);
leds[72] = CRGB(255, 0, 187);
leds[73] = CRGB(255, 0, 187);
FastLED.show();
delay(90);
FastLED.clear();

leds[0] = CRGB(0, 0, 0);


leds[1] = CRGB(255, 0, 187);
leds[2] = CRGB(255, 0, 187);
leds[3] = CRGB(255, 0, 187);
leds[4] = CRGB(255, 0, 187);
leds[12] = CRGB(255, 0, 187);
leds[13] = CRGB(255, 0, 187);
leds[14] = CRGB(255, 0, 187);
leds[15] = CRGB(255, 0, 187);
leds[17] = CRGB(255, 0, 187);
leds[22] = CRGB(255, 0, 187);
leds[28] = CRGB(255, 0, 187);
leds[33] = CRGB(255, 0, 187);
leds[34] = CRGB(255, 0, 187);
leds[39] = CRGB(255, 0, 187);
leds[42] = CRGB(255, 0, 187);
leds[47] = CRGB(255, 0, 187);
leds[48] = CRGB(255, 0, 187);
leds[53] = CRGB(255, 0, 187);
leds[56] = CRGB(255, 0, 187);
leds[61] = CRGB(255, 0, 187);
leds[62] = CRGB(255, 0, 187);
leds[67] = CRGB(255, 0, 187);
leds[70] = CRGB(255, 0, 187);
leds[75] = CRGB(255, 0, 187);
leds[77] = CRGB(255, 0, 187);
leds[78] = CRGB(255, 0, 187);
leds[79] = CRGB(255, 0, 187);
leds[80] = CRGB(255, 0, 187);
leds[83] = CRGB(255, 0, 187);
leds[84] = CRGB(255, 0, 187);
leds[85] = CRGB(255, 0, 187);
leds[86] = CRGB(255, 0, 187);
FastLED.show();
delay(90);
FastLED.clear();

leds[0] = CRGB(0, 0, 0);


leds[1] = CRGB(255, 0, 187);
leds[2] = CRGB(255, 0, 187);
leds[3] = CRGB(255, 0, 187);
leds[4] = CRGB(255, 0, 187);
leds[12] = CRGB(255, 0, 187);
leds[13] = CRGB(255, 0, 187);
leds[14] = CRGB(255, 0, 187);
leds[15] = CRGB(255, 0, 187);
leds[17] = CRGB(255, 0, 187);
leds[22] = CRGB(255, 0, 187);
leds[28] = CRGB(255, 0, 187);
leds[33] = CRGB(255, 0, 187);
leds[34] = CRGB(255, 0, 187);
leds[39] = CRGB(255, 0, 187);
leds[42] = CRGB(255, 0, 187);
leds[47] = CRGB(255, 0, 187);
leds[48] = CRGB(255, 0, 187);
leds[53] = CRGB(255, 0, 187);
leds[56] = CRGB(255, 0, 187);
leds[61] = CRGB(255, 0, 187);
leds[62] = CRGB(255, 0, 187);
leds[67] = CRGB(255, 0, 187);
leds[70] = CRGB(255, 0, 187);
leds[75] = CRGB(255, 0, 187);
leds[77] = CRGB(255, 0, 187);
leds[78] = CRGB(255, 0, 187);
leds[79] = CRGB(255, 0, 187);
leds[80] = CRGB(255, 0, 187);
leds[83] = CRGB(255, 0, 187);
leds[84] = CRGB(255, 0, 187);
leds[85] = CRGB(255, 0, 187);
leds[86] = CRGB(255, 0, 187);
FastLED.show();
delay(90);
FastLED.clear();

leds[19] = CRGB(255, 0, 187);


leds[20] = CRGB(255, 0, 187);
leds[30] = CRGB(255, 0, 187);
leds[31] = CRGB(255, 0, 187);
leds[35] = CRGB(255, 0, 187);
leds[38] = CRGB(255, 0, 187);
leds[43] = CRGB(255, 0, 187);
leds[46] = CRGB(255, 0, 187);
leds[49] = CRGB(255, 0, 187);
leds[52] = CRGB(255, 0, 187);
leds[57] = CRGB(255, 0, 187);
leds[60] = CRGB(255, 0, 187);
leds[64] = CRGB(255, 0, 187);
leds[65] = CRGB(255, 0, 187);
leds[72] = CRGB(255, 0, 187);
leds[73] = CRGB(255, 0, 187);
FastLED.show();
delay(90);
FastLED.clear();

leds[36] = CRGB(255, 0, 187);


leds[37] = CRGB(255, 0, 187);
leds[44] = CRGB(255, 0, 187);
leds[45] = CRGB(255, 0, 187);
leds[50] = CRGB(255, 0, 187);
leds[51] = CRGB(255, 0, 187);
leds[58] = CRGB(255, 0, 187);
leds[59] = CRGB(255, 0, 187);
FastLED.show();
delay(90);
FastLED.clear();
}
break;

case '3':
for(int i=0;i<5;i++)
{
leds[0] = CRGB(255, 0, 187);
leds[1] = CRGB(255, 0, 187);
leds[2] = CRGB(255, 0, 187);
leds[3] = CRGB(255, 0, 187);
leds[4] = CRGB(255, 0, 187);
leds[5] = CRGB(255, 0, 187);
leds[6] = CRGB(255, 0, 187);
leds[7] = CRGB(255, 0, 187);
leds[8] = CRGB(255, 0, 187);
leds[9] = CRGB(255, 0, 187);
leds[10] = CRGB(255, 0, 187);
leds[11] = CRGB(255, 0, 187);
leds[12] = CRGB(255, 0, 187);
leds[13] = CRGB(255, 0, 187);
leds[14] = CRGB(255, 0, 187);
leds[15] = CRGB(255, 0, 187);
leds[16] = CRGB(255, 0, 187);
leds[17] = CRGB(255, 0, 187);
leds[18] = CRGB(255, 161, 0);
leds[19] = CRGB(255, 161, 0);
leds[20] = CRGB(255, 161, 0);
leds[21] = CRGB(255, 161, 0);
leds[22] = CRGB(255, 161, 0);
leds[23] = CRGB(255, 0, 187);
leds[24] = CRGB(255, 0, 187);
leds[25] = CRGB(255, 0, 187);
leds[26] = CRGB(255, 0, 187);
leds[27] = CRGB(255, 0, 187);
leds[28] = CRGB(255, 161, 0);
leds[29] = CRGB(255, 161, 0);
leds[30] = CRGB(255, 161, 0);
leds[31] = CRGB(255, 161, 0);
leds[32] = CRGB(255, 161, 0);
leds[33] = CRGB(255, 0, 187);
leds[34] = CRGB(255, 0, 187);
leds[35] = CRGB(255, 161, 0);
leds[36] = CRGB(0, 255, 255);
leds[37] = CRGB(0, 255, 255);
leds[38] = CRGB(0, 255, 255);
leds[39] = CRGB(255, 161, 0);
leds[40] = CRGB(255, 0, 187);
leds[41] = CRGB(255, 0, 187);
leds[42] = CRGB(255, 161, 0);
leds[43] = CRGB(0, 255, 255);
leds[44] = CRGB(0, 255, 255);
leds[45] = CRGB(0, 255, 255);
leds[46] = CRGB(255, 161, 0);
leds[47] = CRGB(255, 0, 187);
leds[48] = CRGB(255, 0, 187);
leds[49] = CRGB(255, 161, 0);
leds[50] = CRGB(0, 255, 255);
leds[51] = CRGB(0, 255, 255);
leds[52] = CRGB(0, 255, 255);
leds[53] = CRGB(255, 161, 0);
leds[54] = CRGB(255, 0, 187);
leds[55] = CRGB(255, 0, 187);
leds[56] = CRGB(255, 161, 0);
leds[57] = CRGB(0, 255, 255);
leds[58] = CRGB(0, 255, 255);
leds[59] = CRGB(0, 255, 255);
leds[60] = CRGB(255, 161, 0);
leds[61] = CRGB(255, 0, 187);
leds[62] = CRGB(255, 0, 187);
leds[63] = CRGB(255, 161, 0);
leds[64] = CRGB(255, 161, 0);
leds[65] = CRGB(255, 161, 0);
leds[66] = CRGB(255, 161, 0);
leds[67] = CRGB(255, 161, 0);
leds[68] = CRGB(255, 0, 187);
leds[69] = CRGB(255, 0, 187);
leds[70] = CRGB(255, 161, 0);
leds[71] = CRGB(255, 161, 0);
leds[72] = CRGB(255, 161, 0);
leds[73] = CRGB(255, 161, 0);
leds[74] = CRGB(255, 161, 0);
leds[75] = CRGB(255, 0, 187);
leds[76] = CRGB(255, 0, 187);
leds[77] = CRGB(255, 0, 187);
leds[78] = CRGB(255, 0, 187);
leds[79] = CRGB(255, 0, 187);
leds[80] = CRGB(255, 0, 187);
leds[81] = CRGB(255, 0, 187);
leds[82] = CRGB(255, 0, 187);
leds[83] = CRGB(255, 0, 187);
leds[84] = CRGB(255, 0, 187);
leds[85] = CRGB(255, 0, 187);
leds[86] = CRGB(255, 0, 187);
leds[87] = CRGB(255, 0, 187);
FastLED.show();
delay(90);
FastLED.clear();

leds[0] = CRGB(255, 164, 0);


leds[1] = CRGB(255, 164, 0);
leds[2] = CRGB(255, 164, 0);
leds[3] = CRGB(255, 164, 0);
leds[4] = CRGB(255, 164, 0);
leds[5] = CRGB(255, 164, 0);
leds[6] = CRGB(255, 164, 0);
leds[7] = CRGB(255, 164, 0);
leds[8] = CRGB(255, 164, 0);
leds[9] = CRGB(255, 164, 0);
leds[10] = CRGB(255, 164, 0);
leds[11] = CRGB(255, 164, 0);
leds[12] = CRGB(255, 164, 0);
leds[13] = CRGB(255, 164, 0);
leds[14] = CRGB(255, 164, 0);
leds[15] = CRGB(255, 164, 0);
leds[16] = CRGB(255, 164, 0);
leds[17] = CRGB(255, 164, 0);
leds[18] = CRGB(0, 255, 255);
leds[19] = CRGB(0, 255, 255);
leds[20] = CRGB(0, 255, 255);
leds[21] = CRGB(0, 255, 255);
leds[22] = CRGB(0, 255, 255);
leds[23] = CRGB(255, 164, 0);
leds[24] = CRGB(255, 164, 0);
leds[25] = CRGB(255, 164, 0);
leds[26] = CRGB(255, 164, 0);
leds[27] = CRGB(255, 164, 0);
leds[28] = CRGB(0, 255, 255);
leds[29] = CRGB(0, 255, 255);
leds[30] = CRGB(0, 255, 255);
leds[31] = CRGB(0, 255, 255);
leds[32] = CRGB(0, 255, 255);
leds[33] = CRGB(255, 164, 0);
leds[34] = CRGB(255, 164, 0);
leds[35] = CRGB(0, 255, 255);
leds[36] = CRGB(255, 0, 177);
leds[37] = CRGB(255, 0, 177);
leds[38] = CRGB(255, 0, 177);
leds[39] = CRGB(0, 255, 255);
leds[40] = CRGB(255, 164, 0);
leds[41] = CRGB(255, 146, 0);
leds[42] = CRGB(0, 255, 255);
leds[43] = CRGB(255, 0, 177);
leds[44] = CRGB(255, 0, 177);
leds[45] = CRGB(255, 0, 177);
leds[46] = CRGB(0, 255, 255);
leds[47] = CRGB(255, 146, 0);
leds[48] = CRGB(255, 146, 0);
leds[49] = CRGB(0, 255, 255);
leds[50] = CRGB(255, 0, 177);
leds[51] = CRGB(255, 0, 177);
leds[52] = CRGB(255, 0, 177);
leds[53] = CRGB(0, 255, 255);
leds[54] = CRGB(255, 164, 0);
leds[55] = CRGB(255, 164, 0);
leds[56] = CRGB(0, 255, 255);
leds[57] = CRGB(255, 0, 177);
leds[58] = CRGB(255, 0, 177);
leds[59] = CRGB(255, 0, 177);
leds[60] = CRGB(0, 255, 255);
leds[61] = CRGB(255, 164, 0);
leds[62] = CRGB(255, 164, 0);
leds[63] = CRGB(0, 255, 255);
leds[64] = CRGB(0, 255, 255);
leds[65] = CRGB(0, 255, 255);
leds[66] = CRGB(0, 255, 255);
leds[67] = CRGB(0, 255, 255);
leds[68] = CRGB(255, 164, 0);
leds[69] = CRGB(255, 164, 0);
leds[70] = CRGB(0, 255, 255);
leds[71] = CRGB(0, 255, 255);
leds[72] = CRGB(0, 255, 255);
leds[73] = CRGB(0, 255, 255);
leds[74] = CRGB(0, 255, 255);
leds[75] = CRGB(255, 164, 0);
leds[76] = CRGB(255, 164, 0);
leds[77] = CRGB(255, 164, 0);
leds[78] = CRGB(255, 164, 0);
leds[79] = CRGB(255, 164, 0);
leds[80] = CRGB(255, 164, 0);
leds[81] = CRGB(255, 164, 0);
leds[82] = CRGB(255, 164, 0);
leds[83] = CRGB(255, 164, 0);
leds[84] = CRGB(255, 164, 0);
leds[85] = CRGB(255, 164, 0);
leds[86] = CRGB(255, 164, 0);
leds[87] = CRGB(255, 164, 0);
FastLED.show();
delay(90);
FastLED.clear();
leds[0] = CRGB(0, 255, 255);
leds[1] = CRGB(0, 255, 255);
leds[2] = CRGB(0, 255, 255);
leds[3] = CRGB(0, 255, 255);
leds[4] = CRGB(0, 255, 255);
leds[5] = CRGB(0, 255, 255);
leds[6] = CRGB(0, 255, 255);
leds[7] = CRGB(0, 255, 255);
leds[8] = CRGB(0, 255, 255);
leds[9] = CRGB(0, 255, 255);
leds[10] = CRGB(0, 255, 255);
leds[11] = CRGB(0, 255, 255);
leds[12] = CRGB(0, 255, 255);
leds[13] = CRGB(0, 255, 255);
leds[14] = CRGB(0, 255, 255);
leds[15] = CRGB(0, 255, 255);
leds[16] = CRGB(0, 255, 255);
leds[17] = CRGB(0, 255, 255);
leds[18] = CRGB(255, 0, 208);
leds[19] = CRGB(255, 0, 208);
leds[20] = CRGB(255, 0, 180);
leds[21] = CRGB(255, 0, 180);
leds[22] = CRGB(255, 0, 180);
leds[23] = CRGB(0, 255, 255);
leds[24] = CRGB(0, 255, 255);
leds[25] = CRGB(0, 255, 255);
leds[26] = CRGB(0, 255, 255);
leds[27] = CRGB(0, 255, 255);
leds[28] = CRGB(255, 0, 208);
leds[29] = CRGB(255, 0, 208);
leds[30] = CRGB(255, 0, 180);
leds[31] = CRGB(255, 0, 180);
leds[32] = CRGB(255, 0, 180);
leds[33] = CRGB(0, 255, 255);
leds[34] = CRGB(0, 255, 255);
leds[35] = CRGB(255, 0, 180);
leds[36] = CRGB(255, 148, 0);
leds[37] = CRGB(255, 148, 0);
leds[38] = CRGB(255, 148, 0);
leds[39] = CRGB(255, 0, 208);
leds[40] = CRGB(0, 255, 255);
leds[41] = CRGB(0, 255, 255);
leds[42] = CRGB(255, 0, 180);
leds[43] = CRGB(255, 148, 0);
leds[44] = CRGB(255, 148, 0);
leds[45] = CRGB(255, 148, 0);
leds[46] = CRGB(255, 0, 180);
leds[47] = CRGB(0, 255, 255);
leds[48] = CRGB(0, 255, 255);
leds[49] = CRGB(255, 0, 208);
leds[50] = CRGB(255, 148, 0);
leds[51] = CRGB(255, 148, 0);
leds[52] = CRGB(255, 148, 0);
leds[53] = CRGB(255, 0, 180);
leds[54] = CRGB(0, 255, 255);
leds[55] = CRGB(0, 255, 255);
leds[56] = CRGB(255, 0, 180);
leds[57] = CRGB(255, 148, 0);
leds[58] = CRGB(255, 148, 0);
leds[59] = CRGB(255, 148, 0);
leds[60] = CRGB(255, 0, 180);
leds[61] = CRGB(0, 255, 255);
leds[62] = CRGB(0, 255, 255);
leds[63] = CRGB(255, 0, 180);
leds[64] = CRGB(255, 0, 180);
leds[65] = CRGB(255, 0, 180);
leds[66] = CRGB(255, 0, 180);
leds[67] = CRGB(255, 0, 180);
leds[68] = CRGB(0, 255, 255);
leds[69] = CRGB(0, 255, 255);
leds[70] = CRGB(255, 0, 180);
leds[71] = CRGB(255, 0, 180);
leds[72] = CRGB(255, 0, 180);
leds[73] = CRGB(255, 0, 180);
leds[74] = CRGB(255, 0, 180);
leds[75] = CRGB(0, 255, 255);
leds[76] = CRGB(0, 255, 255);
leds[77] = CRGB(0, 255, 255);
leds[78] = CRGB(0, 255, 255);
leds[79] = CRGB(0, 255, 255);
leds[80] = CRGB(0, 255, 255);
leds[81] = CRGB(0, 255, 255);
leds[82] = CRGB(0, 255, 255);
leds[83] = CRGB(0, 255, 255);
leds[84] = CRGB(0, 255, 255);
leds[85] = CRGB(0, 255, 255);
leds[86] = CRGB(0, 255, 255);
leds[87] = CRGB(0, 255, 255);
FastLED.show();
delay(90);
FastLED.clear();

leds[0] = CRGB(0, 255, 255);


leds[1] = CRGB(0, 255, 255);
leds[2] = CRGB(0, 255, 255);
leds[3] = CRGB(0, 255, 255);
leds[4] = CRGB(0, 255, 255);
leds[5] = CRGB(0, 255, 255);
leds[6] = CRGB(0, 255, 255);
leds[7] = CRGB(0, 255, 255);
leds[8] = CRGB(0, 255, 255);
leds[9] = CRGB(0, 255, 255);
leds[10] = CRGB(0, 255, 255);
leds[11] = CRGB(0, 255, 255);
leds[12] = CRGB(0, 255, 255);
leds[13] = CRGB(0, 255, 255);
leds[14] = CRGB(0, 255, 255);
leds[15] = CRGB(0, 255, 255);
leds[16] = CRGB(0, 255, 255);
leds[17] = CRGB(0, 255, 255);
leds[18] = CRGB(255, 0, 208);
leds[19] = CRGB(255, 0, 208);
leds[20] = CRGB(255, 0, 180);
leds[21] = CRGB(255, 0, 180);
leds[22] = CRGB(255, 0, 180);
leds[23] = CRGB(0, 255, 255);
leds[24] = CRGB(0, 255, 255);
leds[25] = CRGB(0, 255, 255);
leds[26] = CRGB(0, 255, 255);
leds[27] = CRGB(0, 255, 255);
leds[28] = CRGB(255, 0, 208);
leds[29] = CRGB(255, 0, 208);
leds[30] = CRGB(255, 0, 180);
leds[31] = CRGB(255, 0, 180);
leds[32] = CRGB(255, 0, 180);
leds[33] = CRGB(0, 255, 255);
leds[34] = CRGB(0, 255, 255);
leds[35] = CRGB(255, 0, 180);
leds[36] = CRGB(255, 148, 0);
leds[37] = CRGB(255, 148, 0);
leds[38] = CRGB(255, 148, 0);
leds[39] = CRGB(255, 0, 208);
leds[40] = CRGB(0, 255, 255);
leds[41] = CRGB(0, 255, 255);
leds[42] = CRGB(255, 0, 180);
leds[43] = CRGB(255, 148, 0);
leds[44] = CRGB(255, 148, 0);
leds[45] = CRGB(255, 148, 0);
leds[46] = CRGB(255, 0, 180);
leds[47] = CRGB(0, 255, 255);
leds[48] = CRGB(0, 255, 255);
leds[49] = CRGB(255, 0, 208);
leds[50] = CRGB(255, 148, 0);
leds[51] = CRGB(255, 148, 0);
leds[52] = CRGB(255, 148, 0);
leds[53] = CRGB(255, 0, 180);
leds[54] = CRGB(0, 255, 255);
leds[55] = CRGB(0, 255, 255);
leds[56] = CRGB(255, 0, 180);
leds[57] = CRGB(255, 148, 0);
leds[58] = CRGB(255, 148, 0);
leds[59] = CRGB(255, 148, 0);
leds[60] = CRGB(255, 0, 180);
leds[61] = CRGB(0, 255, 255);
leds[62] = CRGB(0, 255, 255);
leds[63] = CRGB(255, 0, 180);
leds[64] = CRGB(255, 0, 180);
leds[65] = CRGB(255, 0, 180);
leds[66] = CRGB(255, 0, 180);
leds[67] = CRGB(255, 0, 180);
leds[68] = CRGB(0, 255, 255);
leds[69] = CRGB(0, 255, 255);
leds[70] = CRGB(255, 0, 180);
leds[71] = CRGB(255, 0, 180);
leds[72] = CRGB(255, 0, 180);
leds[73] = CRGB(255, 0, 180);
leds[74] = CRGB(255, 0, 180);
leds[75] = CRGB(0, 255, 255);
leds[76] = CRGB(0, 255, 255);
leds[77] = CRGB(0, 255, 255);
leds[78] = CRGB(0, 255, 255);
leds[79] = CRGB(0, 255, 255);
leds[80] = CRGB(0, 255, 255);
leds[81] = CRGB(0, 255, 255);
leds[82] = CRGB(0, 255, 255);
leds[83] = CRGB(0, 255, 255);
leds[84] = CRGB(0, 255, 255);
leds[85] = CRGB(0, 255, 255);
leds[86] = CRGB(0, 255, 255);
leds[87] = CRGB(0, 255, 255);
FastLED.show();
delay(90);
FastLED.clear();

leds[0] = CRGB(255, 164, 0);


leds[1] = CRGB(255, 164, 0);
leds[2] = CRGB(255, 164, 0);
leds[3] = CRGB(255, 164, 0);
leds[4] = CRGB(255, 164, 0);
leds[5] = CRGB(255, 164, 0);
leds[6] = CRGB(255, 164, 0);
leds[7] = CRGB(255, 164, 0);
leds[8] = CRGB(255, 164, 0);
leds[9] = CRGB(255, 164, 0);
leds[10] = CRGB(255, 164, 0);
leds[11] = CRGB(255, 164, 0);
leds[12] = CRGB(255, 164, 0);
leds[13] = CRGB(255, 164, 0);
leds[14] = CRGB(255, 164, 0);
leds[15] = CRGB(255, 164, 0);
leds[16] = CRGB(255, 164, 0);
leds[17] = CRGB(255, 164, 0);
leds[18] = CRGB(0, 255, 255);
leds[19] = CRGB(0, 255, 255);
leds[20] = CRGB(0, 255, 255);
leds[21] = CRGB(0, 255, 255);
leds[22] = CRGB(0, 255, 255);
leds[23] = CRGB(255, 164, 0);
leds[24] = CRGB(255, 164, 0);
leds[25] = CRGB(255, 164, 0);
leds[26] = CRGB(255, 164, 0);
leds[27] = CRGB(255, 164, 0);
leds[28] = CRGB(0, 255, 255);
leds[29] = CRGB(0, 255, 255);
leds[30] = CRGB(0, 255, 255);
leds[31] = CRGB(0, 255, 255);
leds[32] = CRGB(0, 255, 255);
leds[33] = CRGB(255, 164, 0);
leds[34] = CRGB(255, 164, 0);
leds[35] = CRGB(0, 255, 255);
leds[36] = CRGB(255, 0, 177);
leds[37] = CRGB(255, 0, 177);
leds[38] = CRGB(255, 0, 177);
leds[39] = CRGB(0, 255, 255);
leds[40] = CRGB(255, 164, 0);
leds[41] = CRGB(255, 146, 0);
leds[42] = CRGB(0, 255, 255);
leds[43] = CRGB(255, 0, 177);
leds[44] = CRGB(255, 0, 177);
leds[45] = CRGB(255, 0, 177);
leds[46] = CRGB(0, 255, 255);
leds[47] = CRGB(255, 146, 0);
leds[48] = CRGB(255, 146, 0);
leds[49] = CRGB(0, 255, 255);
leds[50] = CRGB(255, 0, 177);
leds[51] = CRGB(255, 0, 177);
leds[52] = CRGB(255, 0, 177);
leds[53] = CRGB(0, 255, 255);
leds[54] = CRGB(255, 164, 0);
leds[55] = CRGB(255, 164, 0);
leds[56] = CRGB(0, 255, 255);
leds[57] = CRGB(255, 0, 177);
leds[58] = CRGB(255, 0, 177);
leds[59] = CRGB(255, 0, 177);
leds[60] = CRGB(0, 255, 255);
leds[61] = CRGB(255, 164, 0);
leds[62] = CRGB(255, 164, 0);
leds[63] = CRGB(0, 255, 255);
leds[64] = CRGB(0, 255, 255);
leds[65] = CRGB(0, 255, 255);
leds[66] = CRGB(0, 255, 255);
leds[67] = CRGB(0, 255, 255);
leds[68] = CRGB(255, 164, 0);
leds[69] = CRGB(255, 164, 0);
leds[70] = CRGB(0, 255, 255);
leds[71] = CRGB(0, 255, 255);
leds[72] = CRGB(0, 255, 255);
leds[73] = CRGB(0, 255, 255);
leds[74] = CRGB(0, 255, 255);
leds[75] = CRGB(255, 164, 0);
leds[76] = CRGB(255, 164, 0);
leds[77] = CRGB(255, 164, 0);
leds[78] = CRGB(255, 164, 0);
leds[79] = CRGB(255, 164, 0);
leds[80] = CRGB(255, 164, 0);
leds[81] = CRGB(255, 164, 0);
leds[82] = CRGB(255, 164, 0);
leds[83] = CRGB(255, 164, 0);
leds[84] = CRGB(255, 164, 0);
leds[85] = CRGB(255, 164, 0);
leds[86] = CRGB(255, 164, 0);
leds[87] = CRGB(255, 164, 0);
FastLED.show();
delay(90);
FastLED.clear();
leds[0] = CRGB(255, 0, 187);
leds[1] = CRGB(255, 0, 187);
leds[2] = CRGB(255, 0, 187);
leds[3] = CRGB(255, 0, 187);
leds[4] = CRGB(255, 0, 187);
leds[5] = CRGB(255, 0, 187);
leds[6] = CRGB(255, 0, 187);
leds[7] = CRGB(255, 0, 187);
leds[8] = CRGB(255, 0, 187);
leds[9] = CRGB(255, 0, 187);
leds[10] = CRGB(255, 0, 187);
leds[11] = CRGB(255, 0, 187);
leds[12] = CRGB(255, 0, 187);
leds[13] = CRGB(255, 0, 187);
leds[14] = CRGB(255, 0, 187);
leds[15] = CRGB(255, 0, 187);
leds[16] = CRGB(255, 0, 187);
leds[17] = CRGB(255, 0, 187);
leds[18] = CRGB(255, 161, 0);
leds[19] = CRGB(255, 161, 0);
leds[20] = CRGB(255, 161, 0);
leds[21] = CRGB(255, 161, 0);
leds[22] = CRGB(255, 161, 0);
leds[23] = CRGB(255, 0, 187);
leds[24] = CRGB(255, 0, 187);
leds[25] = CRGB(255, 0, 187);
leds[26] = CRGB(255, 0, 187);
leds[27] = CRGB(255, 0, 187);
leds[28] = CRGB(255, 161, 0);
leds[29] = CRGB(255, 161, 0);
leds[30] = CRGB(255, 161, 0);
leds[31] = CRGB(255, 161, 0);
leds[32] = CRGB(255, 161, 0);
leds[33] = CRGB(255, 0, 187);
leds[34] = CRGB(255, 0, 187);
leds[35] = CRGB(255, 161, 0);
leds[36] = CRGB(0, 255, 255);
leds[37] = CRGB(0, 255, 255);
leds[38] = CRGB(0, 255, 255);
leds[39] = CRGB(255, 161, 0);
leds[40] = CRGB(255, 0, 187);
leds[41] = CRGB(255, 0, 187);
leds[42] = CRGB(255, 161, 0);
leds[43] = CRGB(0, 255, 255);
leds[44] = CRGB(0, 255, 255);
leds[45] = CRGB(0, 255, 255);
leds[46] = CRGB(255, 161, 0);
leds[47] = CRGB(255, 0, 187);
leds[48] = CRGB(255, 0, 187);
leds[49] = CRGB(255, 161, 0);
leds[50] = CRGB(0, 255, 255);
leds[51] = CRGB(0, 255, 255);
leds[52] = CRGB(0, 255, 255);
leds[53] = CRGB(255, 161, 0);
leds[54] = CRGB(255, 0, 187);
leds[55] = CRGB(255, 0, 187);
leds[56] = CRGB(255, 161, 0);
leds[57] = CRGB(0, 255, 255);
leds[58] = CRGB(0, 255, 255);
leds[59] = CRGB(0, 255, 255);
leds[60] = CRGB(255, 161, 0);
leds[61] = CRGB(255, 0, 187);
leds[62] = CRGB(255, 0, 187);
leds[63] = CRGB(255, 161, 0);
leds[64] = CRGB(255, 161, 0);
leds[65] = CRGB(255, 161, 0);
leds[66] = CRGB(255, 161, 0);
leds[67] = CRGB(255, 161, 0);
leds[68] = CRGB(255, 0, 187);
leds[69] = CRGB(255, 0, 187);
leds[70] = CRGB(255, 161, 0);
leds[71] = CRGB(255, 161, 0);
leds[72] = CRGB(255, 161, 0);
leds[73] = CRGB(255, 161, 0);
leds[74] = CRGB(255, 161, 0);
leds[75] = CRGB(255, 0, 187);
leds[76] = CRGB(255, 0, 187);
leds[77] = CRGB(255, 0, 187);
leds[78] = CRGB(255, 0, 187);
leds[79] = CRGB(255, 0, 187);
leds[80] = CRGB(255, 0, 187);
leds[81] = CRGB(255, 0, 187);
leds[82] = CRGB(255, 0, 187);
leds[83] = CRGB(255, 0, 187);
leds[84] = CRGB(255, 0, 187);
leds[85] = CRGB(255, 0, 187);
leds[86] = CRGB(255, 0, 187);
leds[87] = CRGB(255, 0, 187);
FastLED.show();
delay(90);
FastLED.clear();
}
break;

case '4':

leds[2] = CRGB(0, 183, 255);


leds[3] = CRGB(0, 183, 255);
leds[13] = CRGB(0, 183, 255);
leds[14] = CRGB(0, 183, 255);
leds[17] = CRGB(0, 183, 255);
leds[18] = CRGB(0, 183, 255);
leds[19] = CRGB(0, 183, 255);
leds[20] = CRGB(0, 183, 255);
leds[21] = CRGB(0, 183, 255);
leds[28] = CRGB(0, 183, 255);
leds[29] = CRGB(0, 183, 255);
leds[30] = CRGB(0, 183, 255);
leds[31] = CRGB(0, 183, 255);
leds[32] = CRGB(0, 183, 255);
leds[34] = CRGB(0, 183, 255);
leds[36] = CRGB(0, 183, 255);
leds[37] = CRGB(0, 183, 255);
leds[42] = CRGB(0, 183, 255);
leds[44] = CRGB(0, 183, 255);
leds[45] = CRGB(0, 183, 255);
leds[48] = CRGB(0, 183, 255);
leds[49] = CRGB(0, 183, 255);
leds[50] = CRGB(0, 183, 255);
leds[51] = CRGB(0, 183, 255);
leds[52] = CRGB(0, 183, 255);
leds[53] = CRGB(0, 183, 255);
leds[56] = CRGB(0, 183, 255);
leds[57] = CRGB(0, 183, 255);
leds[58] = CRGB(0, 183, 255);
leds[59] = CRGB(0, 183, 255);
leds[60] = CRGB(0, 183, 255);
leds[64] = CRGB(0, 183, 255);
leds[65] = CRGB(0, 183, 255);
leds[67] = CRGB(0, 183, 255);
leds[72] = CRGB(0, 183, 255);
leds[73] = CRGB(0, 183, 255);
leds[75] = CRGB(0, 183, 255);
leds[77] = CRGB(0, 183, 255);
leds[78] = CRGB(0, 183, 255);
leds[79] = CRGB(0, 183, 255);
leds[80] = CRGB(0, 183, 255);
leds[81] = CRGB(0, 183, 255);
leds[83] = CRGB(0, 183, 255);
leds[84] = CRGB(0, 183, 255);
leds[85] = CRGB(0, 183, 255);
leds[86] = CRGB(0, 183, 255);
leds[87] = CRGB(0, 183, 255);
FastLED.show();
delay(3000);
FastLED.clear();

break;
case '5':
for(int i=0;i<4;i++)
{
static uint8_t hue;
for(int i = 0; i < NUM_LEDS/2; i++) {
// fade everything out
leds.fadeToBlackBy(40);

// let's set an led value


leds[i] = CHSV(hue++,255,255);

// now, let's first 20 leds to the top 20 leds,


leds(NUM_LEDS/2,NUM_LEDS-1) = leds(NUM_LEDS/2 - 1 ,0);
FastLED.delay(33);
}
}
break;

case '6':
{
for(int i=0;i<3;i++)
{
static uint8_t hue = 0;
Serial.print("x");
for(int i = 0; i < NUM_LEDS; i++) {
leds[i] = CHSV(hue++, 255, 255);
FastLED.show();
fadeall();
delay(10);
}
Serial.print("x");
for(int i = (NUM_LEDS)-1; i >= 0; i--) {
leds[i] = CHSV(hue++, 255, 255);
FastLED.show();
fadeall();
delay(10);
...

This file has been truncated, please download it to see its full contents.

85) Arduino Automated Aeroponic System Wifi


COMPONENTS AND SUPPLIES

Arduino Mega 2560 & Genuino


Mega 2560
× 1

NodeMCU ESP8266 Breakout × 1


Board

TaydaElectronics MINI RELAY


SPDT 5 PINS 12VDC 10A
120V CONTACT × 3

Adafruit Waterproof DS18B20


Digital temperature sensor
× 1

DFRobot Gravity: Analog LM35


Temperature Sensor For Arduino
× 1

SparkFun Dual H-Bridge motor


drivers L298
× 1

DHT22 Temperature Sensor


× 1

Male/Female Jumper Wires × 3


DFRobot I2C 16x2 Arduino
LCD Display Module
× 1

Module peltier 12706


× 1

Module RTC 1302


× 1

Hw 125 MicroSD Reader


× 1

Peristaltic pump 12v 7w


11ml/min × 2

Water pump 12v brushless


× 3

Plastic box 30X20X12cm


× 3

Heatsink from PC watercooling × 1


8mm pvc pipe 5meter
× 1

1mm silicon pipe 5meter


× 1
NECESSARY TOOLS AND MACHINES
Hot glue gun (generic)

Soldering iron (generic)

Multitool, Screwdriver

Drill / Driver, Cordless

Manual saw

ABOUT THIS PROJECT

Introduction
Hi, I'm a chemical engineering student. Until I started
this project I had no idea how to code. I started with
blink... two months ago... thanks to the lockdown. I
can't guarantee that my code is written according to
the rules. But I've tested it for hours, days, it works.
I challenge myself in many ways, in this project, I did
it for myself; it's not a school project or anything else.
I started from scratch. I used a lot of lines of code
from other sources, but in the end, I started writing my
own. I'm not in a good position to teach someone
because I'm a beginner. But I think that since I've read
tons of projects and trained for over 450 hours
reading, coding and failing tons of times, maybe this
one can help people. Besides, knowledge dies when
it's not shared.
Main view inside the greenhouse
The roots parts with the nutrient pipe in the middle
Main solution with sensors, filter, coldsink peltier,
watering pump, and drain pump for cleaning

The electrical case with acrylic cover

The Black Sheep mascot


What the system can do?
The system i've made currently can record, set and
monitor through WebBrowser these differents
parameters:
Water temperature
Air temperature (inside the greenhouse)
Air temperature inside the electronical box
Humidity level
TDS (Nutrient )
Time Trigger for Light
Time Trigger for Watering On/Off Cycle
All the datas can be stored in SDcard
Water level with AutoRefill (Sensor
+pump+relay)*
Humidity with mistmaker and fan (Mistmaker +
fan+relay)*
Legend for* [Will be added soon]
WebServer Video Demostration
https://streamable.com/w97i19
This is the link of WebServer access by Iphone8 on 4g
connexion.
Description of the content of the video:
First I check the error page if log are false (that was
made for 20 April )
Then I push a button to see the confirmation message
After that I check no blank formular and ranged value
and submit to see response of the arduino the value
come from it after refresh
The home page contain some casual widget
It's fully optimised for SmartPhone Browser
You can Monitor data collected by sensor
You can switch on/off light and pump manualy
You can set time trigger for light and watering
You can set Water temperature and TDS value

SCHEMATICS
CODE
int getMedianNum(int bArray[], int iFilterLen)
{
int bTab[iFilterLen];
for (byte i = 0; i < iFilterLen; i++)
bTab[i] = bArray[i];
int i, j, bTemp;
for (j = 0; j < iFilterLen - 1; j++)
{
for (i = 0; i < iFilterLen - j - 1; i++)
{
if (bTab[i] > bTab[i + 1])
{
bTemp = bTab[i];
bTab[i] = bTab[i + 1];
bTab[i + 1] = bTemp;
}
}
}
if ((iFilterLen & 1) > 0)
bTemp = bTab[(iFilterLen - 1) / 2];
else
bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
return bTemp;
}

byte Heart[8] = {
0b00000,
0b01010,
0b11111,
0b11111,
0b01110,
0b00100,
0b00000,
0b00000
};

//=========================================debut
Muoton"Black Sheep" Alexandros Pantelidis Avril
2020=================================
byte tete1[8] =
{
0b00011,
0b00100,
0b01010,
0b10000,
0b11111,
0b00011,
0b00011,
0b00010
};

byte tete2[8] =
{
0b11000,
0b11100,
0b10001,
0b11110,
0b10001,
0b11000,
0b11111,
0b10001
};

byte tete3[8] =
{
0b00000,
0b00000,
0b10011,
0b01110,
0b10001,
0b00100,
0b10001,
0b01110
};

byte tete4[8] =
{
0b00000,
0b00000,
0b00000,
0b10000,
0b01000,
0b01000,
0b11100,
0b10110
};

byte bas1[8] =
{
0b00010,
0b00010,
0b00011,
0b00001,
0b00001,
0b00000,
0b00000,
0b00000
};

byte bas2[8] =
{
0b01011,
0b01100,
0b00111,
0b01000,
0b11111,
0b01001,
0b01001,
0b01001
};

byte bas3[8] =
{
0b00011,
0b11001,
0b00000,
0b10100,
0b11111,
0b00010,
0b00010,
0b00010
};
byte bas4[8] =
{
0b10001,
0b01001,
0b00101,
0b10011,
0b11110,
0b00100,
0b00100,
0b00100
};
//=========================================Fin
mouton=================================
//=========================================Librarie
utilisées=========================
#include <EEPROM.h>
#include <DHT.h>
#include <DallasTemperature.h>
#include <SPI.h>
#include <SD.h>
#include <LiquidCrystal_I2C.h>
#include <virtuabotixRTC.h> //Library used
#include <ResponsiveAnalogRead.h>
//=========================================Pin
definie=================================
#define RELAY1 24
#define POMPES 22
#define LAMPES 26
#define moteurA_1 38
#define moteurA_2 40
#define moteurB_1 36
#define moteurB_2 34
#define DS1302_GND_PIN 33
#define DS1302_VCC_PIN 31
#define Tbox A2
#define DHTPIN 32 // what pin we're connected to
#define DHTTYPE DHT22 // DHT 22 (AM2302)
#define TdsSensorPin A8
#define VREF 5.0 // analog reference voltage(Volt) of the ADC
#define SCOUNT 3 // sum of sample point
#define ONE_WIRE_BUS 7
//=========================================Constantes
utiilisées============================
unsigned long currentMillis1 = 0;
unsigned long currentMillis4 = 0;
unsigned long previousMillis1 = 0;
unsigned long previousMillis = 0;
unsigned long previousMillis3 = 0;
const long interval = 10000;
unsigned long periodtds = 3600000; // 1h
const long nettoyage = 10000;
const int chipSelect = 49;
unsigned long startMillis1;
unsigned long startMillis;
String message = "";
bool messageReady = false;
String message1 = "";
bool messageReady1 = false;

int analogBuffer1[SCOUNT]; // store the analog value in the array, read


from ADC
int analogBufferTemp1[SCOUNT];
int analogBufferIndex1 = 0, copyIndex1 = 0;

int analogBuffer[SCOUNT];
int analogBufferTemp[SCOUNT];
int analogBufferIndex = 0, copyIndex = 0;
float averageVoltage = 0 , tdsValue = 0;

int analogBuffer2[SCOUNT];
int analogBufferTemp2[SCOUNT];
int analogBufferIndex2 = 0, copyIndex2 = 0;
float averageVoltage2 = 0;

int val;
int addr = 0;
const byte numChars = 64;
char receivedChars[numChars];
char tempChars[numChars];
char messageFromPC[numChars] = {0};
int integerFromPC = 0;
float floatFromPC = 0.0;
boolean newData = false;

int ledstate;
int pompestate;

int int1;
int int2;
int int3;
int int4;
int int5;
int int6;
int int7;

int minteau ;
int maxteau ;
int timearro;

float temperature;
float humi;
float temp;
float tbox;
int tdsval;

int OnHour;
int OnMin; //set hour and minutes for timer

int OffHour;
int OffMin;

int valeur_brute;

bool freshtds = false;


bool cleanup = false;
bool perioff = true;
//=========================================Fonction
declaré============================

LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16
chars and 2 line display
DHT dht(DHTPIN, DHTTYPE); //// Initialize DHT sensor for normal
16mhz Arduino
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
ResponsiveAnalogRead analog(Tbox, true);
virtuabotixRTC myRTC(35, 37, 39); //If you change the wiring change the
pins here also
//=========================================Fonction
demmarage ============================
void LedState() {

val = EEPROM.read(addr);
if (val == 1)
{
digitalWrite(LAMPES, HIGH);

}
if (val == 2)
{
digitalWrite(LAMPES, LOW);
}
maxteau = EEPROM.read(2);
minteau = EEPROM.read(3);
OnHour = EEPROM.read(4);

OnMin = EEPROM.read(5);
OffHour = EEPROM.read(6);
OffMin = EEPROM.read(7);
tdsval = 10 * EEPROM.read(8);

timearro = EEPROM.read(9);
Serial.println(maxteau);
Serial.println(minteau);
Serial.println(OnHour);
Serial.println(OnMin);
Serial.println(OffHour);
Serial.println(OffMin);
Serial.println(tdsval);
Serial.println(timearro);

//=========================================Executé au
demmarage============================
void setup() {
Serial.begin(9600);
delay(1);
Serial1.begin(115200);
delay(1);
Serial.print("Initializing SD card...");
delay(1);

if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
while (1);
}
Serial.println("card initialized.");
dht.begin();
sensors.begin();
pinMode(TdsSensorPin, INPUT);
pinMode(RELAY1, OUTPUT);
pinMode(POMPES, OUTPUT);
pinMode(LAMPES, OUTPUT);
pinMode(Tbox, INPUT);
pinMode(moteurA_1, OUTPUT);
pinMode(moteurB_1, OUTPUT);
pinMode(moteurA_2, OUTPUT);
pinMode(moteurB_2, OUTPUT);
digitalWrite(POMPES, HIGH);
digitalWrite(moteurA_1, LOW);
digitalWrite(moteurA_2, LOW);
digitalWrite(moteurB_1, LOW);
digitalWrite(moteurB_2, LOW);
digitalWrite(DS1302_GND_PIN, LOW);
pinMode(DS1302_GND_PIN, OUTPUT);
digitalWrite(DS1302_VCC_PIN, HIGH);
pinMode(DS1302_VCC_PIN, OUTPUT);

LedState();
startMillis1 = millis();
startMillis = millis();
lcd.init();
lcd.createChar(0, Heart);
lcd.createChar(1, tete1);
lcd.createChar(2, tete2);
lcd.createChar(3, tete3);
lcd.createChar(4, tete4);
lcd.createChar(5, bas1);
lcd.createChar(6, bas2);
lcd.createChar(7, bas3);
lcd.createChar(8, bas4);
lcd.backlight();
lcd.setCursor(0, 0);

lcd.print("Alex's Hydro Box");


lcd.setCursor(3, 1);
lcd.print("Bienvenue ^^");
delay(5000);
lcd.clear();
//myRTC.setDS1302Time(0, 8, 19, 2, 7, 4, 2020);

//=========================================Set cycle arrosage


/on/off============================

void setpompe() {
timearro = EEPROM.read(9);

currentMillis1 = millis(); //get the current "time" (actually the number of


milliseconds since the program started)
if (currentMillis1 - startMillis >= (1000 * 60 * timearro) ) {
digitalWrite(POMPES, !digitalRead(POMPES)); //if so, change the state
of the LED. Uses a neat trick to change the state
startMillis = currentMillis1; //IMPORTANT to save the start time of the
current LED state.
}
}

void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;

while (Serial1.available() > 0 && newData == false) {


rc = Serial1.read();

if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}

else if (rc == startMarker) {


recvInProgress = true;
}
}
}

void parseData() {

char * strtokIndx; // this is used by strtok() as an index

//strtokIndx = strtok(tempChars,","); // get the first part - the string


//strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC

strtokIndx = strtok(tempChars, ","); // this continues where the previous


call left off
integerFromPC = atoi(strtokIndx);

strtokIndx = strtok(NULL, ",");


int1 = atoi(strtokIndx);

strtokIndx = strtok(NULL, ",");


int2 = atoi(strtokIndx);

strtokIndx = strtok(NULL, ",");


int3 = atoi(strtokIndx);

strtokIndx = strtok(NULL, ",");


int4 = atoi(strtokIndx);

strtokIndx = strtok(NULL, ",");


int5 = atoi(strtokIndx);

strtokIndx = strtok(NULL, ",");


int6 = atoi(strtokIndx);

}
//=========================================fonction recu
depuis nodemcu============================

void showParsedData() {
if (integerFromPC == 1) {
digitalWrite(LAMPES, HIGH);
EEPROM.update(addr, 1);
integerFromPC = 250;
}
if (integerFromPC == 0) {
digitalWrite(LAMPES, LOW);
EEPROM.update(addr, 2);
integerFromPC = 250;
}

if (integerFromPC == 4) {
digitalWrite(POMPES, HIGH);
integerFromPC = 250;
}
if (integerFromPC == 5) {
digitalWrite(POMPES, LOW);
integerFromPC = 250;
}
if (integerFromPC == 9 && int1 != 0 ) {

int timearro = int1;

EEPROM.update(9, timearro);
integerFromPC = 250;
int1 = 0;
}
}

void formulair () {
if (integerFromPC == 6 && int1 != 0 && int2 != 0) {
int maxteau = int1;
int minteau = int2;
EEPROM.update(2, maxteau);
EEPROM.update(3, minteau);
Serial.println(maxteau);
Serial.println(minteau);
integerFromPC = 250;
int1 = 0;
int2 = 0;
}
}
void formulair1 () {
if (integerFromPC == 7 && int3 != 0 ) {
int OnHour = int3;
int OnMin = int4;
int OffHour = int5;
int OffMin = int6;
EEPROM.update(4, OnHour);
EEPROM.update(5, OnMin);
EEPROM.update(6, OffHour);
EEPROM.update(7, OffMin);
Serial.println(OnHour);
Serial.println(OnMin);
Serial.println(OffHour);
Serial.println(OffMin);
integerFromPC = 250;
}
}
void tdsva () {
if (integerFromPC == 8 && int1 != 0 ) {
int tdsval = int1;

EEPROM.update(8, tdsval);

Serial.println(tdsval * 10);

integerFromPC = 250;
}
}

void settds() {
int tdsval = 10 * EEPROM.read(8); //10* valeur epprom car max 256
impossible de stocker 1000 comme valeur mais 100*10 c'est possible

unsigned long currentMillis3 = millis();


if (tdsValue <= tdsval && tdsValue != 0 && freshtds == false &&
pompestate == 1 && tdsValue > 150) {

currentMillis4 = millis(); //get the current "time" (actually the number of


milliseconds since the program started)
if (currentMillis4 - startMillis >= 8000 ) {
digitalWrite(moteurB_1, !digitalRead(moteurB_1)); //if so, change the
state of the LED. Uses a neat trick to change the state
startMillis1 = currentMillis4; //IMPORTANT to save the start time of the
current LED state.

}
previousMillis3 = currentMillis3;
cleanup = true;
}
if (tdsValue >= tdsval && cleanup == true ) {

digitalWrite(moteurB_1, LOW);
digitalWrite(moteurB_2, HIGH);

freshtds = true;
cleanup = false;
perioff = false;

}
if (currentMillis3 - previousMillis3 > nettoyage && perioff == false ) {

digitalWrite(moteurB_1, LOW);
digitalWrite(moteurB_2, LOW);
perioff = true;
}

if (currentMillis3 - previousMillis3 > periodtds && perioff == true) {


Serial.print("freshtds false");
freshtds = false;
}
}
void loop() {

recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
showParsedData();
newData = false;
}

state();
sensor();
tdsva();
setpompe();
myRTC.updateTime();
settds();
formulair();
formulair1();
timmer();
data();
flcd();
average();
setwater();
}

void state() {
maxteau = EEPROM.read(2);
minteau = EEPROM.read(3);

OnHour = EEPROM.read(4);
OnMin = EEPROM.read(5);
OffHour = EEPROM.read(6);
OffMin = EEPROM.read(7);

tdsval = 10 * EEPROM.read(8);
timearro = EEPROM.read(9);
analog.update();
ledstate = digitalRead(LAMPES);
pompestate = digitalRead(POMPES);
}

void sensor() {
sensors.requestTemperatures();
temperature = sensors.getTempCByIndex(0);
humi = dht.readHumidity();
temp = dht.readTemperature();

valeur_brute = analog.getValue();
tbox = valeur_brute * (5.0 / 1023.0 * 100.0);
}

void setwater() {
if (temperature >= maxteau && temperature != -127 && temperature != 0)
{
digitalWrite(RELAY1, HIGH);

}
else if (temperature <= minteau && temperature != -127 && temperature
!= 0)
{
digitalWrite(RELAY1, LOW);

}
else {
;
}
}

void average() {
static unsigned long analogSampleTimepoint = millis();
if (millis() - analogSampleTimepoint > 40U) //every 40 milliseconds,read
the analog value from the ADC
{
analogSampleTimepoint = millis();
analogBuffer[analogBufferIndex] = analogRead(TdsSensorPin); //read
the analog value and store into the buffer
analogBufferIndex++;
if (analogBufferIndex == SCOUNT)
analogBufferIndex = 0;
}
static unsigned long printTimepoint = millis();
if (millis() - printTimepoint > 800U)
{
printTimepoint = millis();
for (copyIndex = 0; copyIndex < SCOUNT; copyIndex++)
analogBufferTemp[copyIndex] = analogBuffer[copyIndex];
averageVoltage = getMedianNum(analogBufferTemp, SCOUNT) *
(float)VREF / 1024.0; // read the analog value more stable by the median
filtering algorithm, and convert to voltage value
float compensationCoefficient = 1.0 + 0.02 * (temperature - 25.0);
//temperature compensation formula: fFinalResult(25^C) =
fFinalResult(current)/(1.0+0.02*(fTP-25.0));
float compensationVolatge = averageVoltage / compensationCoefficient;
//temperature compensation
tdsValue = (133.42 * compensationVolatge * compensationVolatge *
compensationVolatge - 255.86 * compensationVolatge *
compensationVolatge + 857.39 * compensationVolatge) * 0.5; //convert
voltage value to tds value
}
}

void recorddata() {

unsigned long currentMillis = millis();


if (currentMillis - previousMillis > 1000) {
previousMillis = currentMillis;
//Serial.print("Current Date / Time: ");

// Serial.print(myRTC.dayofmonth); //You can switch between


day and month if you're using American system && myRTC.minutes ==
OnMin
// Serial.print("/");
// Serial.print(myRTC.month);
// Serial.print("/");
// Serial.print(myRTC.year);
// Serial.print(" ");
// Serial.print(myRTC.hours);
// Serial.print(":");
//Serial.print(myRTC.minutes);
// Serial.print(":");
// Serial.println(myRTC.seconds);
// Serial.print("Humidity: ");
// Serial.print(humi);
// Serial.println(" %");
// Serial.print("Temp air: ");
//Serial.print(temp);
// Serial.println(" Celsius");
// Serial.print("Temp H2O ;");
// Serial.print(temperature);
// Serial.println(" Celsius");
// Serial.print("TDS Value:");
// Serial.print(tdsValue, 0);
// Serial.println("ppm");
//Serial.print("Temp box: ");
// Serial.println(tbox, 1);
// Serial.println(" Celsius");

File dataFile = SD.open("datalog1.txt", FILE_WRITE);


delay(1);
dataFile.println(temperature);
delay(1);
dataFile.close();

}
}

void timmer() {
if (myRTC.hours == OnHour && myRTC.minutes == OnMin ) {
EEPROM.update(addr, 1);
digitalWrite(LAMPES, HIGH);
delay(5);
}
else if (myRTC.hours == OffHour && myRTC.minutes == OffMin ) { //
add && myRTC.minutes == OnMin ; (myRTC.hours == OffHour &&
myRTC.minutes == OffMin){
EEPROM.update(addr, 2);
digitalWrite(LAMPES, LOW);
delay(5);
}
}

void data() {
if (integerFromPC == 3) {

Serial1.print("<");
Serial1.print(ledstate);
Serial1.print(",");
Serial1.print(pompestate);
Serial1.print(",");
Serial1.print(tdsValue, 0);
Serial1.print(",");
Serial1.print(temp, 2);
Serial1.print(",");
Serial1.print(temperature, 2);
Serial1.print(",");
Serial1.print(humi, 2);
Serial1.print(",");
Serial1.print(tbox, 2);
Serial1.print(",");
Serial1.print(tdsval);
Serial1.print(",");
Serial1.print(OnHour);
Serial1.print(",");
Serial1.print(OnMin);
Serial1.print(",");
Serial1.print(OffHour);
Serial1.print(",");
Serial1.print(OffMin);
Serial1.print(",");
Serial1.print(maxteau);
Serial1.print(",");
Serial1.print(minteau);
Serial1.print(",");
Serial1.print(timearro);
Serial1.print(">");
Serial1.println("");
}
}

void flcd() {
lcd.setCursor(0, 0);
lcd.print("T Eau:");
lcd.print(temperature, 1);
lcd.print((char)223);
lcd.setCursor(12, 0);
lcd.print("Hum:");
lcd.print(humi, 0);
lcd.print(" % ");
lcd.print("AP Grow Box V1");
lcd.print(" ");
lcd.write(byte(1));
lcd.write(byte(2));
lcd.write(byte(3));
lcd.write(byte(4));

lcd.setCursor(0, 1);
lcd.print("T Air:");
lcd.print(temp, 1);
lcd.print((char)223);
lcd.setCursor(12, 1);
lcd.print("TDS:");
lcd.print(tdsValue, 0);
lcd.print(" ppm ");
lcd.print("T Box:");
lcd.print(tbox, 1);
lcd.print((char)223);
lcd.print(" ");
lcd.write(byte(5));
lcd.write(byte(6));
lcd.write(byte(7));
lcd.write(byte(8));
lcd.scrollDisplayLeft();
}
86) Arduino Nano 7SEG Clock + Temp + Humid
COMPONENTS AND SUPPLIES

7 Segment LED Display,


InfoVue
× 4

Arduino Nano R3 × 1
DHT22 Temperature Sensor

ABOUT THIS PROJECT

I need to control the humidity and temperature of some


carnivorous plants in the greenhouse, this requires
constant temperatures and humidity all year round, plus I
have inserted a clock that has proved very useful when I
spend a lot of time in the greenhouse.
I ordered the RTC form and I'm waiting for it to arrive.
As soon as it is available I will modify and update the
program to add the more precise RTC.
SCHEMATICS
CODE

#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
#include <SevSeg.h>
DHT dht(A2,DHT22);
SevSeg Display;
char text[10][6];
int i = 0;
unsigned long timer;

//----------------------SET OROLOGIO
const unsigned long period = 1000; //durata 1 sec.
const unsigned long led_period = 500; //durata lampeggio :
unsigned long startMillis;
unsigned long led_startMillis;
unsigned long currentMillis;
unsigned long led_currentMillis;
const int hrs_btn = A0; //set ore
const int min_btn = A1; //set minuti
const int ledPin = 13; //pin lampeggio :
int Hrs = 0;
int Min = 0;
int Sec = 0;
int Time = 0000;
int ledState = HIGH;

void setup() {
pinMode(hrs_btn, INPUT_PULLUP);
pinMode(min_btn, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
byte numDigits = 4;
byte digitPins[] = {12, 10, 9, 11};
//byte digitPins[] = {11, 9, 10, 12};
byte segmentPins[] = {2, 3, 4, 5, 6, 7, 8,0};
bool resistorsOnSegments = false; // 'false' means resistors are on digit pins
byte hardwareConfig = COMMON_CATHODE; // See README.md for
options
bool updateWithDelays = false; // Default 'false' is Recommended
bool leadingZeros = true; // Use 'true' if you'd like to keep the leading zeros
bool disableDecPoint = true; // Use 'true' if your decimal point doesn't exist
or isn't connected
Display.begin(hardwareConfig, numDigits, digitPins, segmentPins,
resistorsOnSegments,
updateWithDelays, leadingZeros, disableDecPoint);
Display.setBrightness(100);
dht.begin();
pinMode(ledPin, OUTPUT); // PIN 13 lampeggio :
pinMode(A2, INPUT); // input DHT22
}

void loop()
{
char mychar[ ] = "ORA";
float hu = dht.readHumidity();
float t = dht.readTemperature();
float orario = Time;

String e = String (mychar); //memorizza mychar


String f = e.substring (0,4); //memorizza cifra a 4 digit
f.toCharArray(text[1],5); //visualizza come 1 (ARRAY)

orario=orario*10;
String c = String (orario); //memorizza ora
String d = c.substring (0,4); //memorizza cifra a 4 digit
d.toCharArray(text[2],5); //visualizza come 2 (ARRAY)
t=t*10;
String k = String(t); //memorizza t
String r = k.substring (0,3)+"*"; //memorizza cifra a 3 digit + C
r.toCharArray(text[3],5); //visualizza come 3 (ARRAY)

hu=hu*10;
String A = String(hu); //memorizza hu
String B = A.substring(0,3)+"h"; //memorizza cifra a 3 digit
B.toCharArray(text[4],5); // visualizza come 4 (ARRAY)

switch (i)
{
case 1:
digitalWrite(ledPin, LOW); //pin 13 on Humid
break;
case 2:
digitalWrite(ledPin, HIGH); //pin 13 off ORA
break;
case 3:
digitalWrite(ledPin, LOW); //orario
Display.setNumber(Time);
if (digitalRead(hrs_btn) == LOW){goto X;}
if (digitalRead(min_btn) == LOW){goto X;}
break;
case 4:
digitalWrite(ledPin, LOW); //gradi
break;
}
if (millis() > (timer + 6000)) //tempo di visualizzazione
{
switch(i);
Display.setChars(text[i]);
i++;
if (i >= 5) i = 1; // (ARRAY)conta fino a 5 poi torna a 1
timer = millis();}

//--------------------------------OROLOGIO
X: currentMillis = millis();
if (currentMillis - startMillis >= period)
{
Sec = Sec + 1;
startMillis = currentMillis;
}
led_currentMillis = millis();
if (led_currentMillis - led_startMillis >= led_period)
{ led_startMillis = led_currentMillis;

if (ledState == LOW) { ledState = HIGH;

if (digitalRead(hrs_btn) == LOW) //avanzamento ore


{ Hrs = Hrs + 1; }

if (digitalRead(min_btn) == LOW) //avanzamento min


{ Min = Min + 1; Sec = 0; }
}
else
{ ledState = LOW; }
digitalWrite(ledPin, ledState);
}
if (Sec == 60)
{
Sec = 0;
Min = Min + 1;
}
if (Min == 60)
{
Min = 0;
Hrs = Hrs + 1;
}
if (Hrs == 24) //12/24 ore
{
Hrs = 0;
}
Time = Hrs * 100 + Min;

Display.refreshDisplay();
}
87) Interface I2C 16X2 LCD with Arduino

COMPONENTS AND SUPPLIES


Arduino UNO & Genuino
UNO
× 1

Male/Female Jumper Wires × 1


I2C Serial Adapter
× 1
APPS AND ONLINE SERVICES
Arduino Web Editor

ABOUT THIS PROJECT

Interface I2C 16x2 LCD with Arduino Uno


In this article I am going to interface a 16x2 I2C LCD
with Arduino Uno. In my previous article is discuss
about interfacing of 16x2 LCD with Arduino Uno. The
difference is in number of wires. There we need more
than 12 wires. But here only use just 4 wires. How
?!!!!!! Before I use parallel communication method for
interfacing LCD with Arduino. But now I am using
I2C Communication.
How it works ?
Here I use the same 16X2 LCD in my previous article.
But additionally attach a I2C Module to the 16x2
LCD. It work as an inter mediator between the LCD
and MCU (here Arduino).
Before starting you must know about I2C Serial
Interface Adapter (I2C Module) , I2C
communication , and Addressof I2C LCD
I2C Communication
I2C Communication
I2C is short for Inter-IC. And it is a type of BUS. This
is designed by Philips semiconductors. I2C is a
synchronous, multi slave, multi master packet
switched, single-ended serial bus. ie. multiple chips
can be connect to the same bus.I2C uses only two
bidirectional open collector or open drain lines, Serial
Data Line (SDA) and Serial Clock Line (SCL), pulled
up with resistors. Typical voltages used are +5 V or
+3.3 V, although systems with other voltages are
permitted. For more about I2C protocol click here.
I2C Serial Interface Adapter

I2C Serial interface Adapter


It is also known as I2C Module. It has total of 20 male
pins. 16 pins are faced to rear side and 4 pins faced
towards front side. The 16 pins for connect to 16x2
LCD and the 2 pins out of 4 pins are SDA and SCL.
SDA is the serial data pin and SCL is the clock pin.
The rest 2 pins for power supply (Vcc and
ground).There is a POT on the I2C Module. We can
control the contrast of the LCD display by rotating
this POT. And there is a jumber fixed on the module.
When we remove the jumber, the backlight of the
LCD display will go OFF.
Address of I2C LCD
Before starting we need to know about addressing of
I2C devices. Every device which can attached to MCU
have an address. We need to know this address for
communicate with that particular device.
You can see three solder pads on the I2C module.
which is labeled as A0, A1 and A2. This is Address
selectors. ie, each solder pads have one upper potion
and a one lower potion. if, there is a connection
between upper potion with lower connection it is
called "Connected" otherwise it is called "Not
connected". When A0, A1, A2 are in "Not Connected"
condition ( A0 = 0, A1 = 0, A2 = 0) the address would
be 0x27. In default the A0, A1, A2 are in "Not
connected" condition. And some time default address
is 0x3F. There is no need to change the address of the
I2C module when we use only one LCD. But when we
use more than one LCD, need to change the address.
Because two or more different device can't
communicate with the same address. For more address
see the table given below.

Step -1
Skip this Step - 1 & Step -2 if you already know the
address of the LCD
In some cases A0, A1, A2 are "Not connected" state,
but the address is not 0x27. We can't communicate
with this address. So we need to find the original
address of that device. For that we need to run the
Arduino with "I2C Scanner" code.
I2C Scanner Code
I2C Scanner code is used for find the number of I2C
devices and address of I2C devices. First add the
header file for include "Wire.h" library. Then in setup
part, begin the "Wire" library by "Wire.begin()". Then
begin the serial monitor as the baud rate of 9600 by
"Serial.begin()". Next in loop part, define two
variables with the datatype "byte" named "error" and
"address". Then define another variable with the
"Integer ( int)" datatype named as "Devices". And set
initial value as 0. Next start a for loop with minimum
value of 1 and maximum of 127. "address" used as
loop variable. Next input the address to wire with the
function "Wire.beginTransmission()". The i2c_scanner
uses the return value of the
"Write.endTransmisstion()" to see if a device did
acknowledge to the address. This return value store
the value to the variable "error". The return value
become 0, if a device acknowledge to the address.
Otherwise, the return value become 4. Next use a if.
And the condition is "error==0". Then print the
particular address to the serial monitor only if the
address<16. Here we print the address in
Hexadecimal. The printing instruction is
"Serial.print(address, HEX)". And count the
Device. The complete I2C Scanner code is given
below
#include <Wire.h>
void setup()
{
Wire.begin();
Serial.begin(9600);
Serial.println("\nI2C Scanner");
}
void loop()
{
byte error, address;
int Devices;
Serial.println("Scanning...");
Devices = 0;
for(address = 1; address < 127; address++ )
{
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");
Devices++;
}
else if (error==4)
{
Serial.print("Unknown error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (Devices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
delay(5000);
}
Upload the I2C Scanner Code to Arduino Uno.
Step- 2
If you have a I2C LCD please skip this step. But if
you have a 16x2 LCD and a I2C Module see the step
to connect this module to LCD.
Connection
First solder the I2C Module. There is no label on the
I2C Module for connecting to 16x2 LCD. So solder it
with the help of the image given below
I2C Module on 16x2 LCD
After soldering connect the I2C Module to Arduino
Uno.
Arduino Uno I2C module
Analog Pin 4 - SDA
Analog pin 5 - SCL
5V - Vcc
GND - GND
Connect the Arduino to computer.
Next open Serial monitor from the icon on top right
corner of Arduino IDE. And set the baud rate as 9600.
Please ensure the correct port. Then you can see the
address of LCD in serial monitor like shown below
Finally we find the address of the I2C LCD. That is
0x27
Step - 3
Next I am going to display a text on our I2C LCD.
Before that need to add a library to Arduino IDE. Go
to the link and download the library Arduino-
LiquidCrystal-I2C-library. Then open Arduino IDE
and go to Sketch>Include Library> Add.ZIP Library.
Next select the downloaded ZIP file and click open.
Step - 4
Next create a sketch. First I include the header
"Wire.h". This library help to communicate with I2C
device. Then include "LiquidCrystal_I2C.h" for better
communication with display.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
Step - 5
Next set the address, number of column and number of
rows using the function "LiquidCrystal_I2C lcd(). The
address is 0x27 (discovered using the I2C Scanner
Code). Number of columns is 16 and number of rows
is 2. After this, we can call the display using "lcd".
You can also use multiple I2C LCDs with Arduino
Uno. But set different addresses and variable for each
display.
LiquidCrystal_I2C lcd(0x27, 16, 2);
Step - 6
Next code the setup part. First initialize the display
using the function "lcd.begin()". If you have another
display initialize them.
lcd.begin();
Step - 7
Next turn on the backlight using the function
"lcd.backlight()".
lcd.backlight();
Step - 8
Next clear the lcd using the instruction "lcd.clear()".
Then set the cursor to the position (4, 0).
lcd.clear();
lcd.setCursor(4,0);
Step - 9
Now the LCD is ready to print. The cursor is at 4th
column(count from 0), and 0th row(count from 0).
Then print the Message "Hackster" by the function
"lcd.print()".
lcd.print("Hackster");
Then leave the loop part as empty.
The programming is completed. Upload the sketch to
Arduino and see the message on LCD. The complete
code is given in the Code section of this article.
SCHEMATICS
CODE

//sketch created by Akshay Joseph


#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup()
{

lcd.begin();

lcd.backlight();
lcd.clear();
lcd.setCursor(4,0);
lcd.print("Hackster");
}

void loop()
{
}
88) Lego Gun Shooter with and Arduino
COMPONENTS AND SUPPLIES

Arduino UNO & Genuino UNO


This is the board I used for this
× 1
project. However, an Arduino
Uno would work as well.
SG90 Micro-servo motor
These are the motors needed × 4
for the project.

Jumper wires (generic)


× 1

Lego Star Wars Shootable


Cannon × 4

Breadboard (generic)
× 1
APPS AND ONLINE SERVICES
Arduino IDE
A program that runs Arduino Code on
Mac, Windows, and Linux Devices.

ABOUT THIS PROJECT

This project is about getting Lego Cannons to shoot


automatically. I like playing with legoes, and I like
using Arduinos, so I decided to do this project in my
free time. The Servos spin around, hitting the lever
and shooting the cannon. A great first, second or third
project for beginners!
This is a step by step guide on how to make it.
Step 1) The Basics
Start with VIN going to the positively charged row
and GRND going to the negatively charged row. It'll
look like this -
Step 2) Hooking up Servo #1
The Servo has three wires - the orange/yellow (signal)
one will take up a slot in the DIGITAL (PWM~), the
red one (Power) will go to VIN (which is any pin in
the positive row), and the black/brown wire (GRND)
will go to the negatively charged row connected to the
GRND pin on the Uno. The Digital pin that I used for
my first servo is 7. Here is how the schematic looks
like when the first servo is hooked in -
Step 3) Wiring up the rest of the Servos
Once you get the hang of it with the servos, the rest
should be a breeze. One thing to note, however - you
have to keep consistent with the Digital Pins you
attached with your servo in the code.
For example, the code (which can be found at the
bottom of the page), states-
countServo2.attach(8);
Therefore, the second Servo must be connected to the
digital pin 8.
In the same way, the third Servo must be attached to
the digital pin 6, and the fourth should be attached to
the ninth digital pin.
However, these can be changed so that they are in any
order you want them to be. Just make sure you are
changing both hardware and software for consistency,
otherwise, the code will not work.
To run with the code provided at the bottom, this is
how the schematic should look like-

Note - It may look complicated, but as I said before, it


is much easier than it looks once you get the hang of it
Congratulations! You have officially completed the
hardware portion of this project.
Now, copy and paste the code at the bottom of the
page onto an Arduino sketch, and upload it. Make sure
you have the Servo library before uploading the code,
otherwise it will not work! If you have any other
issues, you can comment in the comments section and
I will respond ASAP. If it works, the congratulations.
The last step requires the lego cannons and some old-
fashioned regular tape. The lego cannon looks like this
-
The Lego cannon
Run the code. See which way the servo turns. Tape the
servo onto the lego cannon so that its trajectory sets it
on a collision course with the lever on top of the
cannon in the picture above.
SCHEMATICS
CODE
#include <Servo.h>

float duration, distance;

Servo countServo;
Servo countServo2;
Servo countServo3;
Servo countServo4;

void setup() {

Serial.begin(9600);

countServo.attach(7);
countServo.write(180);
delay(700);
countServo.write(0);
delay(700);
countServo.write(180);
countServo2.attach(8);
countServo2.write(180);
delay(700);
countServo2.write(0);
delay(700);
countServo2.write(180);
countServo3.attach(6);
countServo3.write(180);
delay(700);
countServo3.write(0);
delay(700);
countServo3.write(180);
countServo4.attach(9);
countServo4.write(180);
delay(700);
countServo4.write(0);
delay(700);
countServo4.write(180);
}

void loop() {

{
countdownServo();

}
delay(100);
{
countdownServo2();
}
delay(100);
{
countdownServo3();
}
delay(100);
{
countdownServo4();
}
}

void countdownServo() {
int halfseconds = 5;

for (int i = halfseconds; i >= 0; i--) {

countServo.write((int)(i * 4.5));
delay(500);
}

countServo.write(180);
delay(700);
}

void countdownServo2() {
int halfseconds = 5;

for (int i = halfseconds; i >= 0; i--) {

countServo2.write((int)(i * 4.5));
delay(500);
}

countServo2.write(180);
delay(700);
}

void countdownServo3() {
int halfseconds = 5;

for (int i = halfseconds; i >= 0; i--) {

countServo3.write((int)(i * 4.5));
delay(500);
}
countServo3.write(180);
delay(700);

void countdownServo4() {
int halfseconds = 5;
for (int i = halfseconds; i >= 0; i--) {

countServo4.write((int)(i * 4.5));
delay(500);
}

countServo4.write(180);
delay(700);
}

89) DIY Arduino Height Measuring Machine


COMPONENTS AND SUPPLIES
Arduino Nano R3
× 1

Ultrasonic Sensor - HC-SR04 × 1


(Generic)
Alphanumeric LCD, 16 x 2
× 1

Trimmer Potentiometer, 10
kohm
× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)

ABOUT THIS PROJECT

When I noticed that my kids were measuring their


height every day, I got the idea to make such a device.
To find out your height, all you have to do is stand
under the device and activate a sound that indicates
that your height has been measured.
It is very easy to build and consist only a few
components:
-Arduino Nano
-HC SR04 ultrasonic sensor
-LCD display
-Buzzer
-Battery
Now let's explain how it works:
First we need to install the device with the help of
double-sided adhesive at a certain height, which is
previously defined in the code, and is marked with the
letter H on the picture
When someone stands under the device, the sensor
measures the distance D. Next the code calculates the
distance H-D which actually represents the height of
the person under the device H1 and displays this value
on the LCD. Library "LcdBarGraph" helps draw
horizontal bargraph, where the length of the bar is
proportional to the values provided. When there is no
one under the device, the calculated value is zero
because in this case H = D and H-D is zero. The
device is mounted in a suitable box with the LCD on
the front and the ultrasonic sensor on the bottom.
.
SCHEMATICS
CODE
// includes the LiquidCrystal Library
#include <LiquidCrystal.h>

// includes the LcdBarGraph Library


#include <LcdBarGraph.h>

// Maximum distance we want to ping for (in centimeters).


#define max_distance 200

// Creates an LCD object. Parameters: (rs, enable, d4, d5, d6, d7)
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

LcdBarGraph lbg(&lcd, 16, 0, 1); // Creates an LCD Bargraph object.

const int trigPin = 9;


const int echoPin = 10;
long duration;
int distance;
int distance1;
int speakerPin = 8;
void setup()
{
lcd.begin(16,2); // Initializes the interface to the LCD screen

pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
}

void loop()
{
// Write a pulse to the HC-SR04 Trigger Pin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);

// Measure the response from the HC-SR04 Echo Pin


duration = pulseIn(echoPin, HIGH);

// Determine distance from duration


// Use 343 metres per second as speed of sound
distance= duration*0.034/2;
distance1= 180 - distance ;
// Prints "Distance: <value>" on the first line of the LCD

if (distance1 > 100) {


tone (speakerPin, 1000);

} else {
noTone (speakerPin);

}
lcd.setCursor(0,0);
lcd.print("HEIGHT: ");
lcd.print(distance1);
lcd.print(" cm ");

// Draws bargraph on the second line of the LCD


lcd.setCursor(0,1);
lbg.drawValue(distance1, max_distance);
delay(500);
}
90) Arduino Retro LED Bubble Display
COMPONENTS AND SUPPLIES

NSA1166
× 1

Resistor 220 ohm


× 6

Breadboard (generic) × 1
Jumper wires (generic)
× 1

Male Header 40 Position 1 Row


(0.1")
× 1

Arduino MKR WiFi 1010


× 1

ABOUT THIS PROJECT

The display is a common cathode type seven-segment,


six-digit array. It actually works a lot like the seven-
segment LED displays which have libraries and
tutorials available which was a good starting point.
I got it working with some minor modification to the
SparkFun SevSeg library that already supports four-
digit displays. I just added an extra two digits. The
result looked pretty cool:

However, unlike the modern Serial displays it does not


have a built-in controller or a SPI interface - this
means that Arduino pins need to be connected to each
segment (7) and a select pin for each digit (6). The
LED display is illuminated by the Arduino continually
strobing across each digit in order, and setting the right
segments for that digit for just a fraction of a second.
If the Arduino sketch stops doing this, the display will
go blank or flicker.
Keeping the lights on
Of course, it's being driven by an Arduino MKR WiFi
1010 so there is some Internet connected fun that
could be had.
But fetching some data from the Internet takes time,
and waiting for the operation to complete means the
display would go blank. A way to solve this is to use
timer-based interrupts in order to continually update
the LED display in the background.

SCHEMATICS
CODE

#include "SevSegPlus.h" // https://github.com/8bitkick/SevSegPlus

SevSegPlus ledDisplay;
void setup()
{
ledDisplay.begin();
}

void loop()
{
ledDisplay.print(" Hi ");
delay(1000);

ledDisplay.print("There ");
delay(1000);
}
91) Arduino Battery Capacity Tester

COMPONENTS AND SUPPLIES

SparkFun Arduino Pro Mini 328 × 1


- 5V/16MHz
Can be gotten just about
anywhere online.

20x4 LCD white on blue, with


backlite
Original project used Nokia
× 1
5110 LCD. I don't have any on
hand. I do have several of
these....
Power MOSFET N-Channel
Close enough, I used what I
× 1
had on hand, an AO D3N50
HEXFET.
I2C/twi/spi interface module for
20x4 LCD
× 1
Saves pins, and libraries work
quite well with these.
SparkFun Pushbutton switch
12mm
× 1

Female Header 8 Position 1 Row × 1


(0.1")
Close. I bought several 20x1
sticks from eBay, and cut what
I needed from them.

terminal block two position


× 2
generic screw terminal block
8 ohm 2w resistor
× 1
Needs to be at least 2W.
Resistor 10k ohm
× 2

Speaker: 0.25W, 8 ohms


× 1

prototyping pc board
× 1

wire
× 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)

solder

diagonal cutters
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

I have, for a long while, avoided the use of Li-Ion type


batteries, owing to the cost and special charging
profiles needed. Now that the technology is more
mature, I am venturing into their use.
Since my supply of cells will be primarily used stock
from various recycle streams, I needed to come up
with the tools to test each cell. With that in mind,
here's my derivative of this tester.
What I did
The main changes I did are the 20x4 LCD rather than
buying a Nokia 5110 that the original author used. I
also used the I2C/TWI/SPI interface board for the
LCD screen.
Note that the SCL and SDA pins are NOT broken out
on the pro mini, they are on the A5 and A4 pins, as
noted in the sketch.
Any MOSFET capable of 2.5A constant current or
better can be used, best to use one with the lowest Rds
on that you can. The one used here actually has a
fairly high Rds on of 2.4 Ohm typical. This may
actually skew the mAh results. This means that my
cells may have a slight bit higher storage capacity than
indicated. I had these on hand, left over from a
previous project. This particular HEXFET/MOSFET
is SMD, but the gate and source pins line up with the
.1" spacing on a protoboard. Easy to solder, and even
gives a few vias under the drain tab to add a heat sink
under the board if needed.
Bad pic, and bad solder job... got it twisted a bit. The
resistor is a pull-down on the gate.
The odd headers for the speaker and LCD are recycled
from an old printer I tore apart. I used a 6 position
female header section for the load resistor, so I can
change the load if I need to. I just have to remember to
change the code to match whatever I use. 3 position on
each end are paralleled, so I can match resistance to
whatever load mA I want to use according to the type
of cell I'm testing.
Lower right screw block is for 5V power in, upper left
block is test cell connection.
The rat's nest of point to point wiring to make the
connections. Maybe I should have used several
different colors to make it easier to trace should I have
a problem later on.
The I2C/TWI/SPI interface board. Cheap on eBay, or
Aliexpress, as long as you don't mind waiting 4-6
weeks for delivery. Can be bought anywhere
worldwide online.
Second view of the LCD, showing the changes from
the title image.
Still to do is a case for it, might even need to change
the screw blocks out for something else.
SCHEMATICS
CODE
/*
* Li-Ion capacity tester.
* set up:
* 8 Ohm discharge load
* ~190mA discharge rate.
* I2C LCD.
* MOSFET for discharge control.
* SCl pin = A5
* SDA pin = A4
*/

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

//LCD set-up
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 20
chars and 4 line lcd
// definitions

#define STATE_WAITING 0
#define STATE_MEASURING 1
#define STATE_MEASURING_ENDED 2
#define BAT_LI 0
#define BAT_NI 1
#define BAT_UNREC 2
#define BAT_LI_DISCHARGED 3

//variables

float vtgBatLoaded; //shows the drop in cell V under load


float vtgBatUnloaded; //cell V for no load
float vtgLoad;
float vtgDropOnLoad;
float vtgDropRin;
float rLoad=8; //resistanse of the load in Ohms
float rIn; //calculated cell internal resistance
float batCurrent;
float mAh; //running total cell capacity
uint8_t FET_Base=7; //otherwise known as the Gate.
uint8_t button = 6;
uint8_t speaker= 5;
uint8_t state=STATE_WAITING;
float LiChargedVtg=4.35;
float LiCutoffVtg=2.9;
float NiChargedVtg=1.45;
float NiCutoffVtg=1.1;
float cutoff;
uint8_t BatteryType;
boolean DischargeAllowed=false;
String BatTypeString;

void setup()
{
pinMode(FET_Base,OUTPUT);
pinMode(button,INPUT); //can be changed in the circuit to active low,
// will need to turn on the internal pull-up
pinMode(speaker,OUTPUT);
digitalWrite(FET_Base,LOW);
noTone(speaker);
lcd.init();
lcd.backlight();
}

void loop()
{
if (state==STATE_MEASURING)
{

vtgBatUnloaded=analogRead(0)*5.0/1024.0; //get the voltage of


UNLOADED battery

if (vtgBatUnloaded<cutoff)
{
state=STATE_MEASURING_ENDED;
DischargeAllowed=false;
for (uint8_t i=0;i<4;++i)
{tone(speaker,2000,500); delay(500);noTone(5);delay(300);}
}
digitalWrite(FET_Base,HIGH); //turn the MOSFET on
delay(1000);
vtgBatLoaded=analogRead(0)*5.0/1024.0; //get the voltage of LOADED
battery
vtgLoad=analogRead(1)*5.0/1024.0;
digitalWrite(FET_Base,LOW);//turn the MOSFET off
vtgDropOnLoad=vtgBatLoaded-vtgLoad;
if(vtgDropOnLoad>0) batCurrent=vtgDropOnLoad/rLoad;
else batCurrent=0;
vtgDropRin=vtgBatUnloaded-vtgBatLoaded;
if(batCurrent>0) rIn=vtgDropRin/batCurrent;
else rIn=0;
mAh+=batCurrent/3.6; //*1000.0/3600.0;
lcd.clear();
lcdState();
lcd.setCursor(0,0);
lcd.print(" Bat Load I ");
lcd.setCursor(0,1);
lcd.print(vtgBatUnloaded); lcd.print("V ");lcd.print(vtgBatLoaded);
lcd.print("V ");lcd.print(batCurrent); lcd.print("A");
lcd.setCursor(0,2);
lcd.print("Rin= "); lcd.print(rIn); lcd.setCursor(11,2); lcd.print(" Ohm");
lcd.setCursor(0,3);
lcd.print("Cap= "); lcd.print(mAh); lcd.print(" mA/h");
delay(500);
}
else if (state==STATE_WAITING)
{
digitalWrite(FET_Base,LOW);//turn the MOSFET off
vtgBatUnloaded=analogRead(0)*5.0/1024.0; //get the voltage of
UNLOADED battery
DefBatteryType();
lcd.clear();
lcdState();
lcd.setCursor(0,0);
lcd.print("Bat= "); lcd.print(vtgBatUnloaded); lcd.print(" V");
lcd.setCursor(0,1);
lcd.print(BatTypeString);
lcd.setCursor(0,2);
lcd.print("Test ");
if (DischargeAllowed) lcd.print("allowed");
else lcd.print("denied");
CheckButtons();
delay(500);
}
else if (state==STATE_MEASURING_ENDED)
{
digitalWrite(FET_Base,LOW);//turn the MOSFET off
vtgBatUnloaded=analogRead(0)*5.0/1024.0; //get the voltage of
UNLOADED battery
lcd.clear();
lcdState();
lcd.setCursor(0,0);
lcd.print("Bat= "); lcd.print(vtgBatUnloaded); lcd.print(" V");
lcd.setCursor(0,1);
lcd.print("Cap= ");lcd.print(mAh); lcd.print(" mA/h");
CheckButtons();
delay(500);
}
}

void CheckButtons(void) {

if (digitalRead(button)==HIGH){ // if changed to active low.....you know


what to do!
switch (state){

case STATE_WAITING : DefBatteryType();


if (DischargeAllowed){ mAh=0; state=STATE_MEASURING;
tone(speaker,1000,500); delay(500);noTone(5);}
break;

case STATE_MEASURING : state=STATE_MEASURING_ENDED;


break;

case STATE_MEASURING_ENDED : state=STATE_WAITING;


break;
}
}
}

void lcdState(void){
String stateString;
lcd.setCursor(0,0);
if(state==STATE_WAITING) stateString="Waiting ";
if(state==STATE_MEASURING) stateString="Measuring ";
if(state==STATE_MEASURING_ENDED) stateString="Measuring done";
lcd.print(stateString);
}

void DefBatteryType(void){

if (vtgBatUnloaded>LiCutoffVtg&&vtgBatUnloaded<LiChargedVtg)
{BatteryType=BAT_LI; DischargeAllowed=true;BatTypeString="Li-ion
battery";cutoff=LiCutoffVtg;}
if (vtgBatUnloaded>NiCutoffVtg&&vtgBatUnloaded<NiChargedVtg)
{BatteryType=BAT_NI; DischargeAllowed=true;BatTypeString="Ni-MH
battery ";cutoff=NiCutoffVtg;}
if (vtgBatUnloaded<LiCutoffVtg&&vtgBatUnloaded>NiChargedVtg)
{BatteryType=BAT_LI_DISCHARGED;
DischargeAllowed=false;BatTypeString="Li-ion battery";}
if (vtgBatUnloaded<NiCutoffVtg||vtgBatUnloaded>LiChargedVtg)
{BatteryType=BAT_UNREC;
DischargeAllowed=false;BatTypeString="UNKNOWN bat ";}
}
92) Arduino RFID Controlled Light Switch
COMPONENTS AND SUPPLIES

Arduino Nano R3
× 1
ABOUT THIS PROJECT

This is a light swtich (but can be used for many other


things) which can be turned ON and OFF using
dedicated 125 kHz RFID tags. In this case, 10
different tags (users) can be used.
I have a underground room in the commune space in
my bloc (building) and to access this space I powered
up a light system from my apartment. The switch for
the light is on the entrance in the cellar and all my
neighbors can access that space, and some of them put
the light ON "in purpose" only to increase my
electricity bill :)). After a while, I decided to do
something to stop them doing this. Because the
building has a Electra access system using 125 kHz
tags with unique numbers I decided to use this tag
because is attached to my keys all the time.
I used for this project a Arduino Nano, RFID reader
RDM 6300, one 5V relay, one old Nokia charger and
other few parts.
The program is not very hard to understand and have
explanations for majority of the lines.
In OFF mode the white LED is ON (to be visible the
box because is installed in a dark zone). When a
authorized tag is putted in front of antenna the white
LED goes OFF, green LED and relay goes ON and the
light is starting. If a unauthorized tag is used the white
LED is going OFF, red LED is coming ON for two
seconds and after the white LED is coming ON again,
the relay remain OFF all the time.
To put OFF the light you need to put again close to
antenna one authorized tag, green LED become OFF,
same the relay and the white LED become ON. If one
unauthorized tag is present, when the light is ON, the
green LED is going OFF and the red LED is going ON
for two seconds after the green LED is ON again,
nothing happen with the relay, the light remain on
during this time.
After the light is ON you need to wait minimum two
seconds before you can put again the tag near antenna
and get the light OFF. This cycle can be repeated
again and again and again...

SCHEMATICS
CODE
// define constants for pins

#include <SoftwareSerial.h>

int green_LED = 3;
int RELAY = 5;
int red_LED = 4;
int white_LED = 12;

SoftwareSerial ssrfid = SoftwareSerial(6,8);

// variables to keep state


int readVal = 0; // individual character read from serial
unsigned int readData[10]; // data read from serial
int counter = -1; // counter to keep position in the buffer
char tagId[11]; // final tag ID converted to a string
int ON_OFF = 2; //
char* authorizedTags[10]; // array to hold the list of authorized tags

void initAuthorizedTags() // fills the list of authorzied tags


{
// add your own tag IDs here
authorizedTags[0] = "1B00B2D95B"; //Tag 1
authorizedTags[1] = "0000000000"; //Tag 2
authorizedTags[2] = "0000000000"; //Tag 3
authorizedTags[3] = "0000000000"; //Tag 4
authorizedTags[4] = "0000000000"; //Tag 5
authorizedTags[5] = "0000000000"; //Tag 6
authorizedTags[6] = "0000000000"; //Tag 7
authorizedTags[7] = "0000000000"; //Tag 8
authorizedTags[8] = "0000000000"; //Tag 9
authorizedTags[9] = "0000000000"; //Tag 10
}

void setup()
{
Serial.begin(9600);
ssrfid.begin(9600);
ssrfid.listen();

pinMode(green_LED, OUTPUT);
pinMode(RELAY, OUTPUT);
pinMode(red_LED, OUTPUT);
pinMode(white_LED, OUTPUT);
digitalWrite(green_LED, LOW);
digitalWrite(RELAY, LOW);
digitalWrite(red_LED, LOW);
digitalWrite(white_LED, HIGH);

initAuthorizedTags();
}

int checkTag() // check if the tag ID we just read is any of the


authorized tags
{
int i;
for (i = 0; i < 10; ++i)
{
if (strcmp(authorizedTags[i], tagId) == 0)
{
return 1;
}
}
return 0;
}

void parseTag() // convert the int values read from serial to ASCII
chars
{
int i;
for (i = 0; i < 10; ++i)
{
tagId[i] = readData[i];
}
tagId[10] = 0;
}

void processTag() // once a whole tag is read, process it


{
parseTag(); // convert id to a string
printTag(); // print it
if (checkTag() == 1) // check if the tag is authorized
{
tagSuccess(); // if so, relay and green LED will be turned from OFF to
ON or from ON to OFF, depend the value of ON_OFF variable (odd or
even)
}
else
{
tagFailed(); // otherwise, inform user of failure
}
}

void printTag()
{
Serial.print("Tag value: ");
Serial.println(tagId);
}

void tagSuccess() // perform an action when an authorized tag


was read
{
Serial.println("Tag authorized.");
if ((ON_OFF % 2) == 0) // if ON_OFF is even number means the
relay (light) and the green LED is "off" and will go "on"
{
digitalWrite(green_LED, HIGH);
digitalWrite(RELAY, HIGH);
digitalWrite(white_LED, LOW);
digitalWrite(red_LED, LOW);
Serial.println("Light ON");
delay(2000);
}
else // if ON_OFF is odd number means the relay (light)
and the green LED is "on" and will go "off"
{
digitalWrite(green_LED, LOW);
digitalWrite(RELAY, LOW);
digitalWrite(white_LED, HIGH);
digitalWrite(red_LED, LOW);
Serial.println("Light OFF");
delay(2000);
}
ON_OFF ++; // increment ON_OFF for next cicle
}

void tagFailed() // inform the user that the tag is not


authorized
{
Serial.println("Unauthorized access!");
digitalWrite(green_LED, LOW); // put the green LED low
digitalWrite(red_LED, HIGH); // put the red LED high, signal for
unauthorized tag
delay(2000);
if ((ON_OFF % 2) != 0)
{
digitalWrite(green_LED, HIGH); // if tag fail and the light is on, green
LED will be put back high
}
}

void clearSerial() // this function clears the rest of data on the


serial, to prevent multiple scans
{
while (ssrfid.read() >= 0)
{
; // do nothing
}
}
void loop()
{
// turn red LED off
digitalWrite(red_LED, LOW);

if (ssrfid.available() > 0)
{
readVal = ssrfid.read(); // read the incoming byte:
if (readVal == 2) // a "2" signals the beginning of a tag
{
counter = 0; // start reading
}
else if (readVal == 3) // a "3" signals the end of a tag
{
processTag(); // process the tag we just read
clearSerial(); // clear serial to prevent multiple reads
counter = -1; // reset reading state
}
else if (counter >= 0) // if we are in the middle of reading a tag
{
readData[counter] = readVal; // save valuee
++counter; // increment counter
}
}

93) Presure Pad Interfacing with Arduino


COMPONENTS AND SUPPLIES
Arduino UNO & Genuino
UNO
× 1

SEN-09376 Pressure Pad


× 1

LED (generic)
× 3
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

Pressure pads are designed to detect when pressure is


applied to an area, and they come in a variety of
quality and accuracy. The simplest pressure pads are
often the equivalent of big switches. Inside a pressure
pad are two layers of foil separated by a layer of foam
with holes in it. When the foam is squashed, the metal
contacts touch through the foam and complete the
circuit.
This tutorial serves as a quick primer on rressure pads
and demonstrates how to hook them up and use them
with Arduino.
SCHEMATICS
CODE
const int FSR_PIN = A0; // Pin connected to FSR/resistor divider
const int LED_PIN1 = 7;
const int LED_PIN2 = 6;
const int LED_PIN3 = 4;
const float VCC = 4.98; // Measured voltage of Ardunio 5V line
const float R_DIV = 3230.0; // Measured resistance of 3.3k resistor

void setup()
{
Serial.begin(9600);
pinMode(FSR_PIN, INPUT);
pinMode(LED_PIN1, OUTPUT);
pinMode(LED_PIN2, OUTPUT);
pinMode(LED_PIN3, OUTPUT);
}

void loop()
{
int fsrADC = analogRead(FSR_PIN);
// If the FSR has no pressure, the resistance will be
// near infinite. So the voltage should be near 0.
if (fsrADC != 0) // If the analog reading is non-zero
{
// Use ADC reading to calculate voltage:
float fsrV = fsrADC * VCC / 1023.0;
// Use voltage and static resistor value to
// calculate FSR resistance:
float fsrR = R_DIV * (VCC / fsrV - 1.0);
Serial.println("Resistance: " + String(fsrR) + " ohms");
// Guesstimate force based on slopes in figure 3 of
// FSR datasheet:
float force;
float fsrG = 1.0 / fsrR; // Calculate conductance
// Break parabolic curve down into two linear slopes:
if (fsrR <= 600)
force = (fsrG - 0.00075) / 0.00000032639;
else
force = fsrG / 0.000000642857;
Serial.println("Force: " + String(force) + " g");
Serial.println();
if(force<10)
{
digitalWrite(LED_PIN1,LOW);
digitalWrite(LED_PIN2,LOW);
digitalWrite(LED_PIN3,LOW);}
if(force>20)
{
digitalWrite(LED_PIN1,HIGH);
digitalWrite(LED_PIN2,LOW);
digitalWrite(LED_PIN3,LOW);

}
if(force>60)
{
digitalWrite(LED_PIN2,HIGH);
digitalWrite(LED_PIN1,LOW);
digitalWrite(LED_PIN3,LOW);
}
if(force>100)
{
digitalWrite(LED_PIN3,HIGH);
digitalWrite(LED_PIN2,LOW);
digitalWrite(LED_PIN1,LOW);
}

delay(500);

}
else
{
// No pressure detected
}
}
94) Arduino Automated Clothes Shoes Donation
Machine
COMPONENTS AND SUPPLIES
Arduino UNO & Genuino
UNO
× 1

1Sheeld
× 1
Power Supply 12V/ 5A × 1

Fan 12V
× 1

LED strips
× 1

Push Button
× 1

Android Smartphone
× 1

Relay Module 5V
× 1
APPS AND ONLINE SERVICES
Twitter

ABOUT THIS PROJECT


Q : Do you have clothes, shoes, books and ...etc that
you no longer want ?
A : Sure!
Q : What happens to these things? Stored for along
time in your closet?
A : Yes :(
Now, pick these things you no longer want, and take
them to the nearest donation machine :)
Simply, the machine will sense if you donated with
something and will ask you if you want to share your
photo on the machine's twitter account to encourage
your friends to donate and know more about the
machine. Also when filled the machine will send a
SMS message to a charity association representative to
ask him to empties the machine.
This machine is totally open source so you can build
your own machine at your district :) and i will be
pleased if you shared your kindly feedback to enhance
the second version.You can download all the needed
files starting from the CAD files to the Arduino code,
Enjoy :D
By the way, the machine was featured in a national TV
show that discuss out of the box solutions for
enhancing our community.
Step 1: What you will need?
Materials:
1. MDF (8mm) Sheets
2. MDF (5mm) Sheets
3. Knotty pine wood
4. Stickers for the outer finish
5. Black Paint
6. Primer paint
7. Aluminum Bars
8. Hinge L3899-2B
Tools:>1. Screwdrivers>
2. Hammer
3. Pliers
4. Flush cutter
5. Wire Stripper
6. Soldering Iron
7. Soldering Iron Stand
8. Solder
9. De-soldering pump
10. Digital Multimeter
11. Double Sided Glue Tape.
12. Nails and adhesive
13. Screws & Nuts
14. M4 Bolts x 20mm
15. Copper spacers ( To fix the Arduino Board)
16. Nylon Cable Tie Belt
17. Stainless steel angle brackets
18. 3" Rubber Caster Wheels
19. Paint brush
20. Circular saw
21 Table saw
22. Jig Saw
23. Drill and bits
24. Laser cutter
25. CNC
26. Wood files
27. Sand paper
28. Air compressor with nail gun
Electronics:>1. Arduino UNO
2. 1Sheeld
3. Power Supply 12V/ 5A
4. Fan 12v
5. LED strips
6. Bush button
7. Android Smart Phone
8. Relay module 5V
Step 2: Building The Machine Frame

https://www.youtube.com/embed/Eu4tEww3dzw?
feature=oembed
1. We used the pine wood to build the machine's frame
then we used MDF sheets to cover the machine's
frame, we used nails and screws to fix the MDF sheets
to cover the machine's frame.Machine's dimensions is
: 170 * 100 * 80 cm
2. We used aluminum sections to create the machine's
door and we covered it using MDF sheets. we used
laser cutter machine to cut the machine's door.
3. We used 3 hinges(L3899-2B) to fix the machine's
door to the machine's body.
4. We used 4 x 3" Rubber Caster Wheels to make it
movable.
5. We added a lock to secure the machine.
6. Then we started to prepare the machine for painting,
we can't paint MDF directly you should coat the
machine with primer then we used black paint for the
final layer.
7. After the machine has dried we used the designed
stickers to give the machine the final finish and we
used aluminum angels in the corners to support the
machine and protect the stickers.
Step 3: The Machine's Exterior Design

We used some Islamic patterns such as the Islamic star


pattern to design the exterior stickers for the machine,
you can download the design files and translate it into
your language and we will be happy if you shared
your design with us.
Step 4: Electronics & Control System
Simply, the machine will sense if you donated with
something and will ask you if you want to share your
photo on the machine's Twitter account to encourage
your friends to donate and know more about the
machine. Also when filled the machine will send a
SMS message to a charity association representative to
ask him to empties the machine.
Q: How the machine will sense if i donated with
something?A: Using the first ultrasonic sensor fixed
above the machine's door.Q: How the machine will
interact with me ?A: Using Text to Speech Shield in
1Sheeld App, you need to write some statements at the
Arduino sketch such as :
TextToSpeech.say("Please stand in front of the camera
After Your donation");<br>OneSheeld.delay(5500);
TextToSpeech.say("If you want to share you photo
with community please long press the Bush button");
OneSheeld.delay(7500);
Q: How the machine will sense it was filled?
A: I fixed two ultrasonic sensors in the internal top
side of the machine, if the two sensor's values are less
than 40 cm this means that the machine was filled so it
will send a SMS message to a charity association
representative to ask him to empties the machine.
Q: How the machine will send a SMS message?
A: Using SMS Shield in 1Sheeld App, all you need yo
do is to write the message body and the mobile
number.SMS.send("123456789", "Message body");
Q: What should i do to let the machine take a photo
for me and share it on it's Twitter account?
A: The machine will ask you to press a bush button to
take the photo, then the LED strips will toggle 3 times
to give you the chance to say cheese :D, then it will
upload the photo to its Twitter account.

SCHEMATICS
CODE
#define CUSTOM_SETTINGS
#define INCLUDE_TERMINAL_SHIELD
#define INCLUDE_SMS_SHIELD
#define INCLUDE_TWITTER_SHIELD
#define INCLUDE_CAMERA_SHIELD
#define INCLUDE_TEXT_TO_SPEECH_SHIELD

// Include 1Sheeld library.


#include <OneSheeld.h>

const int trigPin1 = 2;


const int echoPin1 = 3;

const int trigPin2 = 7;


const int echoPin2 = 8;

// Define a boolean flag.


boolean isMessageSent = false;

const int buttonPin = 12; // the number of the pushbutton pin


int buttonState = 0; // variable for reading the pushbutton status

const int ledPin = 13; // the number of the led pin

//--------------------------------------------------------------------------------------

void setup() {
// Start communication
OneSheeld.begin();

// initialize the LED pin as an output:


pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);

pinMode(trigPin1, OUTPUT);
pinMode(echoPin1, INPUT);

pinMode(echoPin2, INPUT);
pinMode(trigPin2, OUTPUT);
}

void loop()
{
long duration1, distance1, duration2, distance2;

digitalWrite(trigPin1, LOW);
delayMicroseconds(2);
digitalWrite(trigPin1, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin1, LOW);

duration1 = pulseIn(echoPin1, HIGH);


// convert the time into a distance1
distance1 = duration1 / 29 / 2;

digitalWrite(trigPin2, LOW);
delayMicroseconds(2);
digitalWrite(trigPin2, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin2, LOW);

duration2 = pulseIn(echoPin2, HIGH);


distance2 = duration2 / 29 / 2;

Terminal.print("Ultrasonic1 = ");
Terminal.print(distance1);
Terminal.println(" cm");

Terminal.print("Ultrasonic2 = ");
Terminal.print(distance2);
Terminal.println(" cm");

// Ultrasonic sensor measeures the depth of the machine if this distance1


increased above 100 cm this means that the door is opened
// The machine will tell the user to stand in front of the camera then the
machine will take a photo for him and uplaoad it on twitter

if (distance1 < 40) {


// ------------------------- Chack if the machine is filled --------------------------
------
if (distance1 <= 60 && distance2 <= 60) {
if (!isMessageSent)
{
// Send the SMS.

SMS.send("+201222326539 ", " ");

Terminal.println("Sending SMS done");

Terminal.println("Machine is filled");

// Set the flag.


isMessageSent = true;
}
}// if machine is filled

else
{
// Reset the flag
isMessageSent = false;

Terminal.println("Some one donated with something");

// Wait for 5 seconds while the user stand in front of the camera
TextToSpeech.say("Please stand in front of the camera After Your
donation");
OneSheeld.delay(5500);
TextToSpeech.say("If you want to share you photo with community please
long press the Bush button");
OneSheeld.delay(7500);

// read the state of the pushbutton value:


buttonState = digitalRead(buttonPin);

if (buttonState == HIGH) {
TextToSpeech.say("You have pressed the push button Please stand behind
the red line");
OneSheeld.delay(6000);

Terminal.println("Bush Button is pressed");

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


digitalWrite(ledPin, HIGH); // turn the LED on (HIGH is the voltage
level)
OneSheeld.delay(1000); // wait for a second
digitalWrite(ledPin, LOW); // turn the LED off by making the
voltage LOW
OneSheeld.delay(1000); // wait for a second
}//for

Camera.setFlash(ON);
// Take the picture.
Camera.rearCapture();
Terminal.println("Photo taken");

OneSheeld.delay(3000);
TextToSpeech.say("Yor photo has been taken");
OneSheeld.delay(7000);

// Post the picture on Twitter.


Twitter.tweetLastPicture(" ");
Terminal.println("Uploading");

TextToSpeech.say("Uploading your image");


OneSheeld.delay(4000);
TextToSpeech.say("Thank you");
// Wait for 5 seconds.
OneSheeld.delay(5000);

}// if button si pressed


else {
TextToSpeech.say("You didn't press the push button, Thank you sir");
OneSheeld.delay(6000);
}//Push button isn't pressed
}//Machine wasn't filled

}// if distance1 < 40 cm


}//void loop

95) Arduino Sodering Station


COMPONENTS AND SUPPLIES
Nano V3.0 ATmega328 For
Arduino × 1

IRF520 MOSFET Driver


Module for Arduino × 1

× 1
MAX6675 Module for Arduino

MAX7219 8-Digital Segment


Digital LED Display Tube For
Arduino × 1

Jumper wires (generic)


× 1

Cooling Fan 5V DC Brushless


0.10A 40mm x 40mm x 10mm
2pin Connector Black × 1

Self Locking Electrical Cable


Connectors × 1

JST-XH Right angle Connectors


× 1

CASE200x120x75mm Plastic
Electronic Project Cover
Enclosure × 1
Green Round Cap Push Button × 1
Switch

AC 16A/250V 20A/125V
Illuminated SPST Boat Rocker
Switch × 1

Soldering Station Iron Handle


for HAKKO 907 ESD × 1
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)
APPS AND ONLINE SERVICES
Arduino Web Editor

EasyEDA

LibreCAD

ABOUT THIS PROJECT

Overview
Controls
On switching on power, our station in standby mode. It
is mean that heater do not connected and you can see
iron handle current temperature on LED display.
To start working need a long press on button 3 (Mode/
Standby). After this station enters to last working mode
stored in EEPROM memory.
There is two working mode named "CLASS 1" and
"CLASS 2".
CLASS 1 is temperature control working mode. It is
possible to set desired temperature by two buttons 1 and
2 (UP and DOWN). Short press change units for 1 and
long press for 5. These values you can change in sketch
file:
const byte pinHeater = 2; //pin for irf520 module
const uint16_t minTemp = 50;//temperature minimum
const uint16_t maxTemp = 700;//temperature maximum
const uint16_t measInterval = 500; //measurement
interval ms. over 500
const byte shortPressStep = 1; //temperature step on
button's short press
const byte autoPressStep = 5; //temperature step on
button's long press
On the right half of LED display you can see defined
temperature and in the left side real temperature of iron
readied by thermocouple K-type.
CLASS 1 mode (temperature control)
CLASS 2. Power control mode. In this mode, you can
set power level from 0% to 100%. Controls is same in
Class 1 - button 1 (up) and button 2 (down) long and
short press. Right half display - desired power level and
left side - iron temperature.
Change working mode by short press on Button 3. Long
press on button 3 to standby mode
Power control mode (CLASS 2)
If iron handle is unplugged or there is other problem and
it is impossible to read data from thermocouple, special
symbol shown instead iron temperature both in standby
and in working mode
Unplugged handle detection in working mode
Unplugged handle in standby mode
Modules
Station have a module structure and almost not discreet
components. Only one descrete component is resistor for
LED indicator of heating.
1. Power supply. I use power supply from old fax
machine that have +5 and +24 volt out that i need.
2. Modules.
Arduino NANO. It placed on my own PCB with all
needed connectors an headers that i produce by
laser transfer technology. However it is possible to
use breadboard for this target.
Assembled PCB
IRF520 mosfet module for heater control
IRF520 module
MAX6675 thermocouple K-type driver
max6675 module
MAX7219 8 digit module
That's all that you need!!!!!
In addition, you need a simple passive element such
buttons, connectors, wires and plugs.
Case
Assembling
Main Arduino module
LED display
Fully assembled
Finished

SCHEMATICS
CODE
//-- Libraries include
#include "LedControl.h" //max7219 7 segment display driver
#include "max6675.h" //thermocouple driver
#include "sav_button.h" //buttons library
#include "EEPROM.h" //Memory Storage

#include <SoftPWM.h> //Software PWM library


#include <SoftPWM_timer.h>

//-- Libraries definition


//------------------------------------------------
//-- MAX7219 LED segment display driver--------
const byte pinLedDIN = 13; //DATA-IN pin of MAX7219
const byte pinLedCLK = 11; //CLK pin of MAX7219
const byte pinLedCS = 12; //CS pin of MAX7219
LedControl led = LedControl(pinLedDIN, pinLedCLK, pinLedCS, 1);
//-- MAX6675 Thermocouple driver------------
const byte pinTcSO = 7;
const byte pinTcCS = 8;
const byte pinTcCLK = 9;
MAX6675 tc(pinTcCLK, pinTcCS, pinTcSO);

//-- PushButtons-----------------------------
const byte pinButtonUp = 4;
const byte pinButtonDown = 5;
const byte pinButtonOk = 6;
SButton Up (pinButtonUp, 50, 0, 800, 100);
SButton Down (pinButtonDown, 50, 0, 800, 100);
SButton Ok (pinButtonOk, 50, 1000, 4000, 250);

//-- Types definition


enum myUnits {
CELSIUS,
PERCENT
};

//-- Constatnts definition


const byte pinHeater = 2; //pin for irf520 module
const uint16_t minTemp = 50;//temperature minimum
const uint16_t maxTemp = 700;//temperature maximum
const uint16_t measInterval = 500; //measurement interval ms. Must be over
500
const byte shortPressStep = 1; //temperature change step on button's short
press
const byte autoPressStep = 5; //temperature change step on button's long
press

const int tempAddr = 0; // eeprom addresses


const byte powerAddr = 2;
const byte modeAddr = 3;

//-- Variables definition


uint16_t reqTemp = 60; //required temperature(celsius) from minTemp to
maxTemp in temperature mode
byte power = 50; //required power(percent) in power mode
byte mode = 0; //working mode (0 - temperature, 1 - power)
uint16_t temp; //Heater temperature
uint32_t measTime = millis();
boolean isChanged = true; // is any changes
boolean standBy = true; //standby mode on/off

byte logo[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
0x05, 0x3d,
0x1c, 0x10, 0x15, 0x1d, 0x00, 0x5b, 0x1d, 0x30, 0x3d, 0x4f, 0x05,
0x00, 0x5b, 0x0f, 0x77, 0x0f, 0x10, 0x1d, 0x15, 0x00, 0xed, 0x7e};
//Arduino Solder station 1_0

byte class1[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e,
0x0e, 0x77, 0x5b, 0x5b, 0x00, 0x00, 0x30}; //CLASS 1
byte class2[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e,
0x0e, 0x77, 0x5b, 0x5b, 0x00, 0x00, 0x6d}; //CLASS 2
byte stby[] = {0x5b, 0x0f, 0x1f, 0x3b, 0x00, 0x00, 0x00, 0x00}; //STDBY

//-- My functions definition


void writeInfo(uint16_t num, byte group, myUnits units) { //Write info to
led screen (number, 4 digit group(0-right, 1-left, units (CELSIUS,
PERCENT))
byte ones, tens, hundreds;

if (num==temp && temp==0 && units==CELSIUS) {


led.setRow (0, 0 + 4 * group, 0x00);
led.setRow (0, 1 + 4 * group, 0x78);
led.setRow (0, 2 + 4 * group, 0x4e);
led.setRow (0, 3 + 4 * group, 0x00);
}

else {

ones = num % 10;


tens = (num / 10) % 10;
hundreds = byte(num / 100);

if (units == CELSIUS) led.setRow (0, 0 + 4 * group, B01100011);


if (units == PERCENT)
{
if (power<34) led.setRow (0, 0 + 4 * group, B00001000);
if (33<power && power<67) led.setRow (0, 0 + 4 * group, B00001001);
if (power>66) led.setRow (0, 0 + 4 * group, B01001001);
//led.setRow (0, 0 + 4 * group, B01001001);

}
led.setDigit(0, 1 + 4 * group, ones, false);
if ( tens==0 && hundreds==0) led.setChar(0,2+4*group, ' ', false);
else led.setDigit(0, 2 + 4 * group, tens, false);
if (hundreds == 0) led.setChar(0, 3 + 4 * group, ' ', false);
else led.setDigit(0, 3 + 4 * group, hundreds, false);
}

}
// Read config from EEPROM
void readConf(){
uint16_t t;
byte p, m;
EEPROM.get(tempAddr, t);
if (minTemp<=t && t<=maxTemp) reqTemp = t;
EEPROM.get(powerAddr, p);
if (p>=0 && p<=100) power = p;
EEPROM.get(modeAddr, m);
if (m==0 || m==1) mode = m;
}

//save config to EEPROM


void saveConf(){
EEPROM.put(tempAddr, reqTemp);
EEPROM.put(powerAddr, power);
EEPROM.put(modeAddr, mode);
}
//set iron temperature
void setTemp(){
switch (mode){
case 0:
if (temp>=reqTemp){
SoftPWMSet(pinHeater, 0);
}
else {
SoftPWMSet(pinHeater, 255);
}
break;
case 1:
SoftPWMSet(pinHeater, map(power,0, 100, 0, 255));
break;
}
}
//show string on led dispaly
void ShowString(byte str[], byte sizeOfStr){
byte pos = 0;
for (byte i = 0; i<sizeOfStr-7; i++){
for(byte j=0; j<8; j++){
pos = i+j;
if (pos >= sizeOfStr) pos -= sizeOfStr;
led.setRow(0,7-j,str[pos]);
}
delay(80);
}
delay (800);
}

void unitsUp(byte vStep){

switch (mode){
case 0:
if ((reqTemp + vStep) <= maxTemp) {
reqTemp += vStep;
isChanged = true;
}
break;
case 1:
if ((power + vStep) <= 100) {
power += vStep;
isChanged = true;
}
break;
}

void unitsDown(byte vStep){

switch (mode){
case 0:
if ((reqTemp - vStep) >= minTemp) {
reqTemp -= vStep;
isChanged = true;
}
break;
case 1:
if ((int(power) - int(vStep)) >= 0) {
power -= vStep;
isChanged = true;
}
break;
}
}

void standByMode(){

SoftPWMSet(pinHeater,0);
led.setIntensity(0, 1);
for (byte i=0; i<5; i++) led.setRow(0,(7-i),stby[i]);
writeInfo(temp, 0, CELSIUS);

switch( Ok.Loop() ){
case SB_LONG_CLICK:
standBy = false;
led.setIntensity(0, 15);
if (mode == 0){
ShowString(class1, sizeof(class1));
isChanged = true;
}
else if (mode == 1){
ShowString(class2, sizeof(class2));
isChanged = true;
}
break;

}
}

void setup() {
led.shutdown(0, false);
led.setIntensity(0,15);
led.clearDisplay(0);

Up.begin();
Down.begin();
Ok.begin();

readConf();

//---- Soft PWM-----------------------------------


SoftPWMBegin();
SoftPWMSet(pinHeater, 0);
SoftPWMSetFadeTime(pinHeater, 4000, 0);
//------------------------------------------------
ShowString(logo, sizeof(logo));
standBy = true;

//Serial.begin(9600);
}

void loop() {
if ((millis()-measTime) > measInterval){
temp = tc.readCelsius();
measTime = millis();
// Serial.println(temp);
}

if (standBy) standByMode();
else{
switch( Up.Loop() ){
case SB_CLICK:
unitsUp(shortPressStep);
break;
/*case SB_LONG_CLICK:

break;*/
case SB_AUTO_CLICK:
unitsUp(autoPressStep);
break;
}
switch( Down.Loop() ){
case SB_CLICK:
unitsDown(shortPressStep);
break;
/*case SB_LONG_CLICK:

break;*/
case SB_AUTO_CLICK:
unitsDown(autoPressStep);
break;
}
switch( Ok.Loop() ){
case SB_CLICK:
if (mode == 0){
mode = 1;
ShowString(class2, sizeof(class2));
isChanged = true;
}
else if (mode == 1){
mode = 0;
ShowString(class1, sizeof(class1));
isChanged = true;
}
break;
case SB_LONG_CLICK:
standBy=true;
break;
/*case SB_AUTO_CLICK:
break;*/
}

if (isChanged) {
if (mode == 0) writeInfo(reqTemp, 0, CELSIUS);
if (mode == 1) writeInfo(power, 0, PERCENT);
saveConf();
isChanged = false;
}

setTemp();
writeInfo(temp, 1, CELSIUS);
}
}

96) Arduino LCD Backlight and Contrast Control


COMPONENTS AND SUPPLIES

Arduino UNO & Genuino UNO


× 1

Adafruit Standard LCD - 16x2 × 1


White on Blue
Jumper wires (generic)
× 1

Rotary potentiometer (generic)


× 1

Breadboard (generic)
× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

I am learning to program the Arduino and making


myself some tutorials so I can remember it more
easily. I hope it will help you! If a code translation is
requested, I'll deliver it. In this project, I want to show
how you can control the backlight and contrast of a
LCD 16x2 screen.
The only thing you have to do is send PWM Signals to
V0 (contrast) and A (backlight) on the LCD pins.

SCHEMATICS
CODE

#include <LiquidCrystal.h>

// Integer Bibliothek
int hintergrundLichtPIN = 8; // Hintergrundlicht
PIN
int hintergrundLichtWert = 49; // Hintergrund Wert =
Höher => Heller

int kontrastPIN = 9; // Kontrast PIN


int kontrastWert = 49; // Kontrast Wert = Kleiner
=> mehr Kontrast

int analogWert;

// Setup der LCD Bibliothek


LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {

// Computer Schnittstellen-Verbindung
Serial.begin(9600);

// Setup der PINs


pinMode(hintergrundLichtPIN, OUTPUT);
pinMode(kontrastPIN, OUTPUT);
// Kontrast und Hintergrund Steuerung des LCD
analogWrite(hintergrundLichtPIN,
hintergrundLichtWert);
analogWrite(kontrastPIN, kontrastWert);

// Einführung des LCD in den Microkontroller


lcd.begin(16, 2);

void loop() {

// Schreiben des AnalogInputs A0


analogWert = analogRead(A0) / 100;

// Wertausgabe in die Console(Debugging)


Serial.print(analogWert);
Serial.print("\n"); // Neue Zeile

// Sender der Information an den LCD


lcd.setCursor(0, 0);
lcd.print("Potentiometer");
lcd.setCursor(0, 1);
lcd.print(analogWert);
lcd.setCursor(2, 1);
lcd.print("k");
delay(100);

// Löschung des Feldes(zweite Zeile, zweite Reihe) im


LCD
// Sonst bleibt eine 0 stehen, wenn man auf 10k geht und
wieder zurück geht
lcd.setCursor(1, 1);
lcd.print(" ");
delay(7);

97) Smart Home Arduino In 30 Minutes Posting in


Ubidots
COMPONENTS AND SUPPLIES
Arduino Mega 2560 & Genuino
Mega 2560
× 1

Arduino Ehernet Shield


× 1

DHT11 Temperature & × 1


Humidity Sensor (4 pins)

PIR Motion Sensor (generic)


× 1

LED (green)
× 1

Buzzer
× 1

SparkFun Breadboard Power


Supply 5V/3.3V
× 1
APPS AND ONLINE SERVICES
Ubidots
Make your account , create 3 variables ,
take the data directly from your Arduino
Ethernet Shield

ABOUT THIS PROJECT


A few days ago , I became interested more for IoT
technology and its facilities and possibilities.
Thinking about it and doing intensive research on the
web, I found that there were no tutorials and simple
designs, anyone with little or none experience with
Arduino, API, JSON, WEB SERVER and a plurality
of expertise could enjoy this feature ( IoT ).
This publication is simple to send variables sensors to
clound ( Ubidots ) in a fast , direct and dynamic way. I
will not describe in this tutorial step by step account
setup , since the material of their own website is much
better than what I could do. www.ubidots.com
Sensor 1 - DHT11
Will need only one sensor, in my case I used a DHT11
sensor, but the Internet has several ways to make a
transistor pick up ambient temperature information.
Well, comments of the DHT11 sensor is a device that
collects temperature and humidity environment,
almost everyone who bought a starter kit have this
sensor.
This sensor has three terminals, one VCC to left,
another in the center OUT(Data Signal) and GND
(ground) right.
Identified there in your component?
We need to connect it to breadboard it will connect to
other more on sensor, you can follow the example we
went through, so the wiring diagram had been clearer.
After that, we will connect the breadboard to Arduino,
in my case I used the MEGA 2560, but nothing
prevents you to use any model you have, because we
use the total project only 3 Digital pins and 1 Analog
pin.
Again nothing prevents you to modify and test in your
project, for to understand better, but do it after
mounting the way they explain, it will be easier after
work, going for me.
Once connected to the terminals VCC and GND, the
OUT (Data Signal) pin plug in the Digital pin 3 of
your Arduino.
Ready your sensor DHT is already positioned.
Sensor 2 - PIR DYP-M003
Let's go to another sensor, in my case I used a PIR
sensor DYP-ME003 (Motion Sensor), this consists of
three terminals, see the image, and the terminal left
VCC (5V-12V), the central OUT and the right
terminal GND (ground) .
Once identified terminals, connect them to
breadboard, terminal OUT at pin A1 (Analog 1) of the
Arduino.
The approach to the regulation of sensitivity and
activation time, I'll leave as homework for you search
the internet, material widely publicized in search
websites.
Now that the sensors are positioned and properly
connected, let the final part of the physical links of the
project.
Others - LED (green)
The design of the LED can be both appearing on pin
13 of the Arduino and an external LED, I opted for
external LED only as a way to better display the drive
motion sensor PIR DYP-M003.

Note that the scheme used, connect the cathode on


GND (ground) and the anode in a 220 ohm resistor,
+/- 5% and turn it to the Arduino pin 4.
We're almost there , the timer tah running there?
Others - Buzzer
The final link is the simplest , used a buzzer , which is
triggered when the PIR sensor recognizes movement
in the environment , therefore, beyond the LED warn
visually , have a buzz that warns the presence of
movement, this can be used to control access or as a
primitive alarm, giving the idea of how to integrate all
these features at once .
The buzzer has a positive pole , which usually in
addition to their greater attachment terminal, a markup
on top ( +) indicating the same and a negative pole,
usually a lower leg GND (ground ) .
The connection is simple, the lower leg binds to the
GND (ground ), and the greater leg (+) in Arduino pin
2.
Ready, is mounted all the physical part of your Smart
Home Mini system , now let's make the magic happen.
Download the available code , open the Arduino IDE
and upload it to your Arduino and see the operation .
Remember that to send the data from the sensors ,
need to set in your account Ubidots the variables will
be three variables , humidity , temperature and
movement , once you have the data of these variables
add fields the indicated code , set data LOCAL
NETWORK of its Ethernet Shield and see how simple
it is .

Example DashBoar Ubidots - Collecting Data's


Take the opportunity to study the code, thus
understood better than the coding is simple, so you
could play with it !
SCHEMATICS
CODE

#include <DHT.h>
#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>

// assign a MAC address for the ethernet controller.


// fill in your address here:
byte mac[] = {
0xZZ, 0xZZ, 0xZZ, 0xZZ, 0xZZ, 0xZZ // Change all ZZ MAC ADDRESS
ETHERNET SHIELD
};
// fill in an available IP address on your network here,
// for manual configuration:
IPAddress ip(0, 0, 0, 0); ETHERNET SHIELDIP ADDRESS LOCAL LAN

// fill in your Domain Name Server address here:


IPAddress myDns(0, 0, 0, 0); DNS IP ADDRESS LOCAL LAN

// initialize the library instance:


EthernetClient client;

String idvariable = ""; //Varible Temperature UBIDOTS


String idvariable_umidade = ""; //Variable Humidity UBIDOTS
String idvariable_sensorPIR = ""; //Variable presence sensor UBIDOTS
String token = ""; //TOKEN UBIDOTS

//Define PIN do Sensor


#define DHTPIN A1 // pino que estamos conectado
#define DHTTYPE DHT11 // DHT 11

// Conecte pino 1 do sensor (esquerda) ao +5V


// Conecte pino 2 do sensor ao pino de dados definido em seu Arduino
// Conecte pino 4 do sensor ao GND
// Conecte o resistor de 10K entre pin 2 (dados)
// e ao pino 1 (VCC) do sensor
DHT dht(DHTPIN, DHTTYPE);

//SD Card
File dataFiles;

//Declarao das variveis referentes aos pinos digitais - ALARME + PIR.


int pinBuzzer = 2;
int pinSensorPIR = 3;
int pinLed = 4;
int valorSensorPIR = 0;

void setup() {

// start serial port:


Serial.begin(9600);

// start the Ethernet connection using a fixed IP address and DNS server:
Ethernet.begin(mac, ip, myDns);
// print the Ethernet board/shield's IP address:
Serial.print("Conexao com a REDE LOCAL - IP: ");
Serial.println(Ethernet.localIP());
delay(1000);
if (Ethernet.begin(mac) == 0) {
Serial.println("Falha na Conexao com a REDE Local");
// no point in carrying on, so do nothing forevermore:
for(;;);
}

// SD Card - Iniciando
Serial.println("Inicializando SD card...");

if (!SD.begin(4)) {
Serial.println("Falha na Inicializacao do SD Card!");
Serial.println("Falha no Modo DATA LOGGER SD Card!");
return;
}
Serial.println("Inicializacao Completa");
Serial.println("Modo DATA LOGGER Inicializado com Sucesso");

// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
dataFiles = SD.open("test.txt", FILE_WRITE);

// if the file opened okay, write to it:


if (dataFiles) {
Serial.print("Escrevendo no Arquivo test.txt...");
dataFiles.println("Testando 1, 2, 3.");
// close the file:
dataFiles.close();
Serial.println("Escrita FInalizada com Sucesso");
} else {
// if the file didn't open, print an error:
Serial.println("Erro Abrindo arquivo test.txt");
}

// re-open the file for reading:


dataFiles = SD.open("test.txt");
if (dataFiles) {
Serial.println("test.txt:");

// read from the file until there's nothing else in it:


while (dataFiles.available()) {
Serial.write(dataFiles.read());
}
// close the file:
dataFiles.close();
} else {
// if the file didn't open, print an error:
Serial.println("Erro Abrindo arquivo test.txt para LEITURA");
}

//Inicia Sensor DHT


Serial.println("Iniciando - Sensor - DHT");
dht.begin();

//Definido pinos como de entrada ou de sada


pinMode(pinBuzzer, OUTPUT);
pinMode(pinSensorPIR, INPUT);
pinMode(pinLed, OUTPUT);

void loop()
{

// A leitura da temperatura e umidade pode levar 250ms!


// O atraso do sensor pode chegar a 2 segundos.
float h = dht.readHumidity();
float t = dht.readTemperature();
// testa se retorno valido, caso contrrio algo est errado.
if (isnan(t) || isnan(h))
{
Serial.println("Falha na Leitura do Sensor - DHT");
} else {

//Lendo o valor do sensor PIR. Este sensor pode assumir 2 valores


//1 quando detecta algum movimento e 0 quando no detecta.
valorSensorPIR = digitalRead(pinSensorPIR);
Serial.print("Sensor de Movimento - Valor Recebido: ");
Serial.println(valorSensorPIR);

//Verificando se ocorreu deteco de movimentos


if (valorSensorPIR == 1) {
ligarAlarme();
} else {
desligarAlarme();
}

int value_temperatura = t;
int value_umidade = h;
int value_sensorPIR = valorSensorPIR;
save_value(String(value_temperatura));
save_value_umidade(String(value_umidade));
save_value_sensorPIR(String(value_sensorPIR));
}
}

//Grava Dados Variavel 1 - Temperatura


void save_value(String value_temperatura)
{
// if you get a connection, report back via serial:
int num=0;
String var = "{\"value\":"+ String(value_temperatura) + "}";
num = var.length();
delay(500);
if(client.connect("things.ubidots.com", 80))
{
Serial.println("connected");

// New lines according to ubidots support:

//Temperatura
client.println("POST /api/v1.6/variables/"+idvariable+"/values HTTP/1.1");
Serial.println("POST /api/v1.6/variables/"+idvariable+"/values HTTP/1.1");
client.println("Content-Type: application/json");
Serial.println("Content-Type: application/json");
client.println("Content-Length: "+String(num));
Serial.println("Content-Length: "+String(num));
client.println("X-Auth-Token: "+token);
Serial.println("X-Auth-Token: "+token);
client.println("Host: things.ubidots.com\n");
Serial.println("Host: things.ubidots.com\n");
client.print(var);
Serial.print(var+"\n");
}
else
{
// if you didn't get a connection to the server:
Serial.println("Falha na Gravacao - Variavel 2 - Temperatura");
}

if (!client.connected())
{
Serial.println();
Serial.println("DESCONECTANDO...");
client.stop();
}

if (client.available())
{
char c = client.read();
Serial.print(c);
}
client.flush();
client.stop();

//Grava DAdos Variavel 2 - Humidade


void save_value_umidade(String value_umidade)
{
// if you get a connection, report back via serial:
int num=0;
String var2 = "{\"value\":"+ String(value_umidade) + "}";
num = var2.length();
delay(1000);
if(client.connect("things.ubidots.com", 80))
{
Serial.println("connected");

// New lines according to ubidots support:

//Temperatura
client.println("POST /api/v1.6/variables/"+idvariable_umidade+"/values
HTTP/1.1");
Serial.println("POST /api/v1.6/variables/"+idvariable_umidade+"/values
HTTP/1.1");
client.println("Content-Type: application/json");
Serial.println("Content-Type: application/json");
client.println("Content-Length: "+String(num));
Serial.println("Content-Length: "+String(num));
client.println("X-Auth-Token: "+token);
Serial.println("X-Auth-Token: "+token);
client.println("Host: things.ubidots.com\n");
Serial.println("Host: things.ubidots.com\n");
client.print(var2);
Serial.print(var2+"\n");
}
else
{
// if you didn't get a connection to the server:
Serial.println("Falha na Gravacao - Variavel 1 - Humidade");
}

if (!client.connected())
{
Serial.println();
Serial.println("DESCONECTANDO...");
client.stop();
}

if (client.available())
{
char c = client.read();
Serial.print(c);
}

client.flush();
client.stop();

//Grava Dados Variavel 3 - Sensor PIR


void save_value_sensorPIR(String value_sensorPIR)
{
// if you get a connection, report back via serial:
int num=0;
String var3 = "{\"value\":"+ String(value_sensorPIR) + "}";
num = var3.length();
delay(1000);
if(client.connect("things.ubidots.com", 80))
{
Serial.println("connected");

// New lines according to ubidots support:

//Temperatura
client.println("POST /api/v1.6/variables/"+idvariable_sensorPIR+"/values
HTTP/1.1");
Serial.println("POST /api/v1.6/variables/"+idvariable_sensorPIR+"/values
HTTP/1.1");
client.println("Content-Type: application/json");
Serial.println("Content-Type: application/json");
client.println("Content-Length: "+String(num));
Serial.println("Content-Length: "+String(num));
client.println("X-Auth-Token: "+token);
Serial.println("X-Auth-Token: "+token);
client.println("Host: things.ubidots.com\n");
Serial.println("Host: things.ubidots.com\n");
client.print(var3);
Serial.print(var3+"\n");
}
else
{
// if you didn't get a connection to the server:
Serial.println("Falha na Gravacao - Variavel 1 - Humidade");
}

if (!client.connected())
{
Serial.println();
Serial.println("DESCONECTANDO...");
client.stop();
}

if (client.available())
{
char c = client.read();
Serial.print(c);
}

client.flush();
client.stop();

//Alarme de Presena
void ligarAlarme() {
//Ligando o led
digitalWrite(pinLed, HIGH);

//Ligando o buzzer com uma frequencia de 1500 hz.


tone(pinBuzzer, 1500);
delay(4000); //tempo que o led fica acesso e o buzzer toca

if (valorSensorPIR != 1){
desligarAlarme();
}
}

void desligarAlarme() {
//Desligando o led
digitalWrite(pinLed, LOW);

//Desligando o buzzer
noTone(pinBuzzer);
}

98) Arduino Multi Functional Clock


COMPONENTS AND SUPPLIES

Arduino UNO & Genuino UNO × 1


We do not recommend using
the Arduino UNO! It has
insufficient onboard storage.
We planned on using the
Arduino 101 instead, but it is
incompatible with the Sparkfun
Color LCD Shield we use.
Arduino Wifi Shield 101
We used an older version of × 1
this shield, not the 101.

TP-LINK M5250 3G Mobile


Wi-Fi × 1

AllThingsTalk IOTOPIA Rapid


Development kit
Grove Air Quality Sensor, × 1
Grove Buzzer, Grove Base
Shield
Sparkfun Color LCD Shield
× 1

Sparkfun Real Time Clock


Module × 1
NECESSARY TOOLS AND MACHINES
3D - Printer
APPS AND ONLINE SERVICES
Temboo

Arduino IDE

PowToon

ABOUT THIS PROJECT


Introduction
We’ve all had this happen before: You go to a party,
stay up late… and forget to set your alarm. It’s
raining, or it’s freezing and snowing the next morning
and you end up being late at work or school… again.
These are the sort of situations we want to prevent. We
mainly designed the MultiFunctional Clock to do just
that.
The alarm checks your digital calendar, theweather
and the traffic in your region. By doing so, it
determines when youshould wake up by itself. Every
day when you wake up, it will also suggest whenyou
should go to bed. The MFC will also determine the
optimal means oftransport.
In addition, the MFC also checks the air quality in
your room. You don't want to wake up feeling sick, do
you?
What we want to Do
As you can imagine, and have read, there are a lot of
things that can interact with the MFC.
Here you have a diagram:
Example situation:
It's raining heavily, winds from the North.
Today you have to work at 9:30 AM, tomorrow
at 9:00 AM.
You prefer going by bicycle, and you live more
than 10 km away.
In general, you take 40 minutes to prepare
yourself.
It's raining, more people will go to their jobs and school
by bus, train and car. If you yourself are still going by
bicycle or on foot, this won't affect you very much, but
the opposite is true because of the wind... You'll
probably get slowed down a lot either way!
Let's say that you have to be woken up 10 minutes
earlier than normal: 8:20 AM
How we do It
Here you can see how to configure the MFC. (Sorry for
the bad quality!)
Currently, you don't see the completed version of the
code in the video. That is because we ran into difficulties
quite a lot while making it.
The Arduino UNO we were using did not have sufficient
PROGMEM and RAM for the code. If you try to
reproduce, we recommend you use any board with the
same size as the UNO, but with more storage. Also use a
more modern LCD TFT Shield than we did.
The program will ask you the following things:
How long do you usually take to get ready? (In
minutes)
What means of transport do you use? (Walk /
Bicycle / Car)
Examples of questions that could be added in the future
are:
What's the name of your google calendar?
Where do you live?
Where do you work?
Do you want to use the snooze function? How long
in between? (In minutes)
Leave the screen on at all times?
The list goes on and on!
The answers could be saved in the EEPROM of the
Arduino, so you don't need to answer them twice!
When you answered the questions successfully, it will
authenticate with google. Go to the link (provided in the
serial monitor) with your favorite browser. Click on
'Allow'. Now the MFC is connected to your google
account, which allows it you check your calendar.
We expect that the first event in your calendar is 'going
to work or school'. You will be woken up with time to
completely prepare yourself in the morning, and be on
time, of course. Your calendar gets checked every 5
minutes, so don't you worry about missing a newly made
appointment.
Air Quality
In the images below, you can see the air qualities (top
left of the screen). It can detect 4 grades.
"Goed" / "Good": No worries, you'll sleep well.
"Aanvaardbaar" / "Acceptable": Could be better...
"Slecht" / "Bad": You should open your window...
"Leef je nog?!" / "How are you still alive?!": No
explanation needed...
An alarm goes off when the grade gets worse
than "Aanvaardbaar" / "Acceptable". The sound gets
louder when the quality degrades.

"Good"
"Acceptable"

"Bad"
SCHEMATICS
CODE
MFC - Air qualityArduino
This code gives a representation of how the air
quality and time can be displayed. This code in
combination with 'MFC- Alarm' code is our finished
program.
//-----------------RTC----------------------------//
#include <Wire.h>
#include "RTClib.h"

#if defined(ARDUINO_ARCH_SAMD) // for Zero, output on USB


Serial console, remove line below if using programming port to program the
Zero!
#define Serial SerialUSB
#endif

RTC_DS1307 rtc;

char daysOfTheWeek[7][12] = {"Zondag", "Maandag", "Dinsdag",


"Woensdag", "Donderdag", "Vrijdag", "Zaterdag"};
char daysOfTheWeekShort[7][3] = {"Zo", "Ma", "Di", "Wo", "Do", "Vr",
"Za"};

enum Dagen {

Zondag,
Maandag,
Dinsdag,
Woensdag,
Donderdag,
Vrijdag,
Zaterdag
};
char scherm_bitbuffer[133];

//-----------------LCD----------------------------//

#include <SparkFunColorLCDShield.h>
#define BACKGROUND WHITE // Achtergrond
#define COLOR BLACK // This is the color of the clock face,
and digital clock
#define COLOR_2 BLUE

LCDShield lcd;

char Uur[3];
char Minuten[3];
char Seconden[3];
char Dag[3];
char Maand[3];
char Jaar[3];

char Tijd_Nu[9];
char Tijd_alarm[6];

//-----------------AirQuality---------------------//

#include"AirQuality.h"
#include"Arduino.h"
AirQuality airqualitysensor;
int current_quality =-1;
//-------------------------------------------------------------------------------------//

void setup () {

pinMode(3, OUTPUT);
analogWrite(3, 0);

//-----------------instellingen scherm -----------//


lcd.init(PHILIPS);
lcd.contrast(50);
lcd.clear(BACKGROUND);
//-----------------instellingen airquality -------//

Serial.begin(9600);
airqualitysensor.init(14);
//-----------------RTC----------------------------//
#ifndef ESP8266
while (!Serial);
#endif

Serial.begin(9600);
if (! rtc.begin()) {
Serial.println("Couldn't find RTC ");
lcd.setStr("Couldn't find RTC ", 20, 10, COLOR, BACKGROUND);
while (1);
}

if (! rtc.isrunning()) {
Serial.println("RTC is NOT running!");
lcd.setStr("RTC werkt niet! ", 20, 10, COLOR_2, BACKGROUND);
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
}
//-------------------------------------------------------------------------------------//
void loop () {

DateTime now = rtc.now();

//-----------------RTC- LCD shield----------------//

//tijd.

lcd.setStr(itoa(now.hour(), Uur, 10), 45, 10, COLOR, BACKGROUND);


lcd.setStr(":", 44, 26, COLOR, BACKGROUND);
lcd.setStr(itoa(now.minute(), Minuten, 10), 45, 33, COLOR,
BACKGROUND);
lcd.setStr(":", 44, 49, COLOR, BACKGROUND);
lcd.setStr(itoa(now.second(), Seconden, 10), 45, 56, COLOR,
BACKGROUND);

//weekdag.
lcd.setStr(daysOfTheWeek[now.dayOfTheWeek()], 70, 10, COLOR,
BACKGROUND);

//datum.
lcd.setStr(itoa(now.day(), Dag, 10), 103, 10, COLOR, BACKGROUND);
lcd.setStr("/", 101 , 28, COLOR, BACKGROUND);
lcd.setStr(itoa(now.month(), Maand, 10), 103, 37, COLOR,
BACKGROUND);
lcd.setStr("/", 101, 55, COLOR, BACKGROUND);
lcd.setStr(itoa(now.year(), Jaar, 10), 103, 61, COLOR, BACKGROUND);

delay(500);

//-----------------airquality---------------------//
current_quality=airqualitysensor.slope();
if (current_quality >= 0) // if a valid data returned.
{
if (current_quality==0) {
lcd.setStr("Leef je nog?! ", 5, 5, COLOR, BACKGROUND);
analogWrite(3, 20);
}
else if (current_quality==1) {
lcd.setStr("Slecht ", 5, 5, COLOR, BACKGROUND);
analogWrite(3, 20);
}
else if (current_quality==2) {
lcd.setStr("Aanvaardbaar ", 5, 5, COLOR, BACKGROUND);
analogWrite(3, 0);
}
else if (current_quality ==3){
lcd.setStr("Goed ", 5, 5, COLOR, BACKGROUND);
analogWrite(3, 0);
}
}
}

ISR(TIMER1_OVF_vect)
{
if(airqualitysensor.counter==61)//set 2 seconds as a detected duty
{

airqualitysensor.last_vol=airqualitysensor.first_vol;
airqualitysensor.first_vol=analogRead(A0);
airqualitysensor.counter=0;
airqualitysensor.timer_index=1;
PORTB=PORTB^0x20;
}
else
{
airqualitysensor.counter++;
}

MFC - AlarmArduino
This code gives a representation of how the prog will
work and how your calendar is read. This code in
combination with 'MFC - Air quality' code is our
finished program.

#include <avr/pgmspace.h>
#include <SPI.h>
#include <Temboo.h>
#include <Wire.h>
#include <WiFi.h>
#include <WiFiClient.h>

#include "RTClib.h"
// #include "SparkFunColorLCDShield.h"

//////////////////////////////////////////////////////////////////////////////

char cBuffer_s_0[5];
char cBuffer_s_1[5];
char cBuffer_s_2[34];
char cBuffer_s_3[24];
char cBuffer_s_4[24];
char cBuffer_s_5[24];
char cBuffer_l_0[42];
char cBuffer_l_1[56];

char* cBuffer[8] = {

cBuffer_s_0,
cBuffer_s_1,
cBuffer_s_2,
cBuffer_s_3,
cBuffer_s_4,
cBuffer_s_5,
cBuffer_l_0,
cBuffer_l_1
};

String sBuffer;
String CallbackID;
String AccessToken;
DateTime* AccessToken_Time;
String RefreshToken;
String CalendarID;
DateTime* ReadCalendar_Time;
int Count;
bool Setup;

int MFC_WifiStatus;
WiFiClient MFC_WifiClient(255);

RTC_DS1307 MFC_Time;
DateTime* Now_Time;

// LCDShield MFC_LCDColorShield;

////////////////////////////////////////////////////////////////////////////////

const PROGMEM char PROGMEMTEXT_COMMON_OK[] = "OK\0";


const PROGMEM char PROGMEMTEXT_COMMON_FAIL[] = "FAIL\0";
const PROGMEM char PROGMEMTEXT_COMMON_ADJUSTED[] =
"ADJUSTED\0";
const PROGMEM char
PROGMEMTEXT_COMMON_UNEXPECTEDERROR[] = " [ERROR]\0";

const PROGMEM char


PROGMEMTEXT_COMMON_DAYSOFTHEWEEK_OFFSET[] = "\0";
const PROGMEM char PROGMEMTEXT_COMMON_SUNDAY[] =
"Sun\0";
const PROGMEM char PROGMEMTEXT_COMMON_MONDAY[] =
"Mon\0";
const PROGMEM char PROGMEMTEXT_COMMON_TUESDAY[] =
"Tue\0";
const PROGMEM char PROGMEMTEXT_COMMON_WEDNESDAY[] =
"Wed\0";
const PROGMEM char PROGMEMTEXT_COMMON_THURSDAY[] =
"Thu\0";
const PROGMEM char PROGMEMTEXT_COMMON_FRYDAY[] =
"Fri\0";
const PROGMEM char PROGMEMTEXT_COMMON_SATURDAY[] =
"Sat\0";

const PROGMEM char


PROGMEMTEXT_COMMON_MONTHSOFTHEYEAR_OFFSET[] = "\0";
const PROGMEM char PROGMEMTEXT_COMMON_JANUARY[] =
"Jan\0";
const PROGMEM char PROGMEMTEXT_COMMON_FEBRUARY[] =
"Feb\0";
const PROGMEM char PROGMEMTEXT_COMMON_MARCH[] =
"Mar\0";
const PROGMEM char PROGMEMTEXT_COMMON_APRIL[] = "Apr\0";
const PROGMEM char PROGMEMTEXT_COMMON_MAY[] = "May\0";
const PROGMEM char PROGMEMTEXT_COMMON_JUNE[] = "Jun\0";
const PROGMEM char PROGMEMTEXT_COMMON_JULY[] = "Jul\0";
const PROGMEM char PROGMEMTEXT_COMMON_AUGUST[] =
"Aug\0";
const PROGMEM char PROGMEMTEXT_COMMON_SEPTEMBER[] =
"Sept\0";
const PROGMEM char PROGMEMTEXT_COMMON_OCTOBER[] =
"Oct\0";
const PROGMEM char PROGMEMTEXT_COMMON_NOVEMBER[] =
"Nov\0";
const PROGMEM char PROGMEMTEXT_COMMON_DECEMBER[] =
"Dec\0";

const PROGMEM char PROGMEMTEXT_COMMON_WALK[] =


"Walk\0";
const PROGMEM char PROGMEMTEXT_COMMON_BICYCLE[] =
"Bicycle\0";
const PROGMEM char PROGMEMTEXT_COMMON_CAR[] = "Car\0";

const PROGMEM char PROGMEMTEXT_COMMON_HTTPCODE[] =


"HTTP_CODE\0";
const PROGMEM char
PROGMEMTEXT_COMMON_HTTPCODESERIALPRINT[] = "
HTTP_CODE: \0";

const PROGMEM char PROGMEMTEXT_COMMON_RTCDETECTION[]


= "RTC DET: \0";
const PROGMEM char
PROGMEMTEXT_COMMON_RTCCONFIGURATION[] = "RTC CONF:
\0";
const PROGMEM char PROGMEMTEXT_COMMON_WIFISHIELD[] =
"WIFI DET: \0";
const PROGMEM char
PROGMEMTEXT_COMMON_WIFICONNECTION[] = "WIFI CONN:
\0";
const PROGMEM char PROGMEMTEXT_COMMON_WIFISSID[] =
"MFC\0";
const PROGMEM char PROGMEMTEXT_COMMON_WIFIPASSWORD[]
= "VTIV5IWMFC\0";

const PROGMEM char


PROGMEMTEXT_COMMON_GOOGLEINITIALIZEOAUTH[] =
"GOOGLE INITIALIZE: \0";
const PROGMEM char
PROGMEMTEXT_COMMON_GOOGLEFINALIZEOAUTH[] =
"GOOGLE FINALIZE: \0";
const PROGMEM char
PROGMEMTEXT_COMMON_GOOGLESEARCHCALENDAR[] =
"GOOGLE SEARCH CAL: \0";
const PROGMEM char
PROGMEMTEXT_COMMON_GOOGLEREADCALENDAR[] =
"GOOGLE READ CAL: \0";
const PROGMEM char
PROGMEMTEXT_COMMON_GOOGLEDISTANCEMATRIX[] =
"GOOGLE DISTANCE CALC: \0";

////////////////////////////////////////////////////////////////////////////////

const PROGMEM char PROGMEMTEXT_TEMBOO_ACCOUNT[] =


"mfc\0";
const PROGMEM char PROGMEMTEXT_TEMBOO_APPNAME[] =
"MFC\0";
const PROGMEM char PROGMEMTEXT_TEMBOO_APPKEY[] =
"j4iHr8BebAHu9D1CHv4pOwGg07dyefES\0";

const PROGMEM char


PROGMEMTEXT_TEMBOO_PROFILE_INITIALIZEMFC[] =
"InitializeMFC\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_PROFILE_FINALIZEMFC[] =
"FinalizeMFC\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_PROFILE_SEARCHCALENDARMFC[] =
"SearchCalendarMFC\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_PROFILE_READCALENDARMFC[] =
"ReadCalendarMFC\0";

const PROGMEM char


PROGMEMTEXT_TEMBOO_CHOREO_INITIALIZEOAUTH[] =
"/Library/Google/OAuth/InitializeOAuth\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_FINALIZEOAUTH[] =
"/Library/Google/OAuth/FinalizeOAuth\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_SEARCHCALENDARSBYNAM
E[] = "/Library/Google/Calendar/SearchCalendarsByName\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_GETNEXTEVENT[] =
"/Library/Google/Calendar/GetNextEvent\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_WALKINGDISTANCEMATRIX[
] = "/Library/Google/DistanceMatrix/WalkingDistanceMatrix\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_BICYCLINGDISTANCEMATRI
X[] = "/Library/Google/DistanceMatrix/BicyclingDistanceMatrix\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_DRIVINGDISTANCEMATRIX[]
= "/Library/Google/DistanceMatrix/DrivingDistanceMatrix\0";

const PROGMEM char


PROGMEMTEXT_TEMBOO_CHOREO_INPUT_SCOPE[] = "Scope\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_SCOPE_VALUE[] =
"https://www.googleapis.com/auth/calendar\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_CALLBACKID[] =
"CallbackID\0";
// const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_CALLBACKID_VALUE
[] = "\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_CALENDARNAME[] =
"CalendarName\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_CALENDARNAME_VA
LUE[] = "MultiFunctional Clock\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_CALENDARID[] =
"CalendarID\0";
// const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_CALENDARID_VALUE
[] = "\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_ACCESSTOKEN[] =
"AccessToken\0";
// const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_ACCESSTOKEN_VALU
E[] = "\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_REFRESHTOKEN[] =
"RefreshToken\0";
// const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_REFRESHTOKEN_VAL
UE[] = "\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_ORIGIN[] = "Origins\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_ORIGIN_VALUE[] =
"51.007990, 2.727744";
const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_DESTINATION[] =
"Destinations\0";
const PROGMEM char
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_DESTINATION_VALUE
[] = "51.063598, 2.666651\0";
const PROGMEM char PROGMEMTEXT[] = "\0";

////////////////////////////////////////////////////////////////////////////////

enum PROGMEMTEXT_LIST {

OK,
FAIL,
ADJUSTED,
UNEXPECTEDERROR,

DAYSOFTHEWEEK_OFFSET,
SUNDAY,
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRYDAY,
SATURDAY,

MONTHSOFTHEYEAR_OFFSET,
JANUARY,
FEBRUARY,
MARCH,
APRIL,
MAY,
JUNE,
JULY,
AUGUST,
SEPTEMBER,
OCTOBER,
NOVEMBER,
DECEMBER,

WALK,
BICYCLE,
CAR,
HTTP_CODE,
HTTP_CODE_SERIALPRINT,

RTC_DETECTION,
RTC_CONFIGURATION,

WIFI_SHIELD,
WIFI_CONNECTION,
WIFI_SSID,
WIFI_PASSWORD,

GOOGLE_INITIALIZEOAUTH,
GOOGLE_FINALIZEOAUTH,
GOOGLE_SEARCHCALENDAR,
GOOGLE_READCALENDAR,
GOOGLE_DISTANCEMATRIX,

ACCOUNT,
APP_NAME,
APP_KEY,

INITIALIZEMFC,
FINALIZEMFC,
SEARCHCALENDARMFC,
READCALENDARMFC,

INITIALIZEOAUTH,
FINALIZEOAUTH,
SEARCHCALENDARSBYNAME,
GETNEXTEVENT,
WALKINGDISTANCEMATRIX,
BICYCLINGDISTANCEMATRIX,
DRIVINGDISTANCEMATRIX,

SCOPE,
SCOPE_VALUE,
CALLBACKID,
// CALLBACKID_VALUE,
CALENDARNAME,
CALENDARNAME_VALUE,
CALENDARID,
//CALENDARID_VALUE,
ACCESSTOKEN,
// ACCESSTOKEN_VALUE,
REFRESHTOKEN,
// REFRESHTOKEN_VALUE,
ORIGIN,
ORIGIN_VALUE,
DESTINATION,
DESTINATION_VALUE,

PROGMEMTEXT_LIST_SIZE
};

PROGMEMTEXT_LIST MeansOfTransport;
unsigned long UserPrepTime;
unsigned long CurrentPrepTime;

////////////////////////////////////////////////////////////////////////////////

const PROGMEM char* const PROGMEMTEXT_TABLE[] = {

PROGMEMTEXT_COMMON_OK,
PROGMEMTEXT_COMMON_FAIL,
PROGMEMTEXT_COMMON_ADJUSTED,
PROGMEMTEXT_COMMON_UNEXPECTEDERROR,

PROGMEMTEXT_COMMON_DAYSOFTHEWEEK_OFFSET,
PROGMEMTEXT_COMMON_SUNDAY,
PROGMEMTEXT_COMMON_MONDAY,
PROGMEMTEXT_COMMON_TUESDAY,
PROGMEMTEXT_COMMON_WEDNESDAY,
PROGMEMTEXT_COMMON_THURSDAY,
PROGMEMTEXT_COMMON_FRYDAY,
PROGMEMTEXT_COMMON_SATURDAY,

PROGMEMTEXT_COMMON_MONTHSOFTHEYEAR_OFFSET,
PROGMEMTEXT_COMMON_JANUARY,
PROGMEMTEXT_COMMON_FEBRUARY,
PROGMEMTEXT_COMMON_MARCH,
PROGMEMTEXT_COMMON_APRIL,
PROGMEMTEXT_COMMON_MAY,
PROGMEMTEXT_COMMON_JUNE,
PROGMEMTEXT_COMMON_JULY,
PROGMEMTEXT_COMMON_AUGUST,
PROGMEMTEXT_COMMON_SEPTEMBER,
PROGMEMTEXT_COMMON_OCTOBER,
PROGMEMTEXT_COMMON_NOVEMBER,
PROGMEMTEXT_COMMON_DECEMBER,

PROGMEMTEXT_COMMON_WALK,
PROGMEMTEXT_COMMON_BICYCLE,
PROGMEMTEXT_COMMON_CAR,

PROGMEMTEXT_COMMON_HTTPCODE,
PROGMEMTEXT_COMMON_HTTPCODESERIALPRINT,

PROGMEMTEXT_COMMON_RTCDETECTION,
PROGMEMTEXT_COMMON_RTCCONFIGURATION,

PROGMEMTEXT_COMMON_WIFISHIELD,
PROGMEMTEXT_COMMON_WIFICONNECTION,
PROGMEMTEXT_COMMON_WIFISSID,
PROGMEMTEXT_COMMON_WIFIPASSWORD,

PROGMEMTEXT_COMMON_GOOGLEINITIALIZEOAUTH,
PROGMEMTEXT_COMMON_GOOGLEFINALIZEOAUTH,
PROGMEMTEXT_COMMON_GOOGLESEARCHCALENDAR,
PROGMEMTEXT_COMMON_GOOGLEREADCALENDAR,
PROGMEMTEXT_COMMON_GOOGLEDISTANCEMATRIX,

PROGMEMTEXT_TEMBOO_ACCOUNT,
PROGMEMTEXT_TEMBOO_APPNAME,
PROGMEMTEXT_TEMBOO_APPKEY,

PROGMEMTEXT_TEMBOO_PROFILE_INITIALIZEMFC,
PROGMEMTEXT_TEMBOO_PROFILE_FINALIZEMFC,
PROGMEMTEXT_TEMBOO_PROFILE_SEARCHCALENDARMFC,
PROGMEMTEXT_TEMBOO_PROFILE_READCALENDARMFC,

PROGMEMTEXT_TEMBOO_CHOREO_INITIALIZEOAUTH,
PROGMEMTEXT_TEMBOO_CHOREO_FINALIZEOAUTH,
PROGMEMTEXT_TEMBOO_CHOREO_SEARCHCALENDARSBYNAM
E,
PROGMEMTEXT_TEMBOO_CHOREO_GETNEXTEVENT,
PROGMEMTEXT_TEMBOO_CHOREO_WALKINGDISTANCEMATRIX,
PROGMEMTEXT_TEMBOO_CHOREO_BICYCLINGDISTANCEMATRI
X,
PROGMEMTEXT_TEMBOO_CHOREO_DRIVINGDISTANCEMATRIX,

PROGMEMTEXT_TEMBOO_CHOREO_INPUT_SCOPE,
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_SCOPE_VALUE,
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_CALLBACKID,
//
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_CALLBACKID_VALUE
,
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_CALENDARNAME,
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_CALENDARNAME_VA
LUE,
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_CALENDARID,
//
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_CALENDARID_VALUE
,
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_ACCESSTOKEN,
//
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_ACCESSTOKEN_VALU
E,
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_REFRESHTOKEN,
//
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_REFRESHTOKEN_VAL
UE,
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_ORIGIN,
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_ORIGIN_VALUE,
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_DESTINATION,
PROGMEMTEXT_TEMBOO_CHOREO_INPUT_DESTINATION_VALUE
,
PROGMEMTEXT
};

#define getPROGMEMTEXT_DayOfTheWeek(DayOfTheWeek)
(strcpy_P(cBuffer[0], (char*)pgm_read_word(&
(PROGMEMTEXT_TABLE[DayOfTheWeek +
PROGMEMTEXT_LIST::DAYSOFTHEWEEK_OFFSET + 1]))))
#define getPROGMEMTEXT_MonthOfTheYear(MonthOfTheYear)
(strcpy_P(cBuffer[0], (char*)pgm_read_word(&
(PROGMEMTEXT_TABLE[MonthOfTheYear +
PROGMEMTEXT_LIST::MONTHSOFTHEYEAR_OFFSET]))))

#define getPROGMEMTEXT(enum_PROGMEMTEXT_LIST_value)
(strcpy_P(cBuffer[7], (char*)pgm_read_word(&
(PROGMEMTEXT_TABLE[enum_PROGMEMTEXT_LIST_value]))))
#define getPROGMEMTEXT_i(enum_PROGMEMTEXT_LIST_value,
cBuffer_index) (strcpy_P(cBuffer[cBuffer_index],
(char*)pgm_read_word(&
(PROGMEMTEXT_TABLE[enum_PROGMEMTEXT_LIST_value]))))

////////////////////////////////////////////////////////////////////////////////

void setup() {

Serial.begin(57600);
while(!Serial);

pinMode(3, OUTPUT);
analogWrite(3, 0);

/*
MFC_LCDColorShield.init(PHILIPS);
MFC_LCDColorShield.contrast(50);
MFC_LCDColorShield.clear(WHITE);
*/

RTC();
Wifi();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void loop() {

if(Setup == 0) {

Serial.println(F("\nHow long do you usually take to get ready? (In


minutes)"));

while(!Serial.available());

sBuffer = Serial.readString();

Serial.print(sBuffer);

UserPrepTime = (atol(sBuffer.c_str()) * 60);

Serial.println(F("\nWhat means of transport do you use? (Walk / Bicycle /


Car)"));

while(!Serial.available());

sBuffer = Serial.readString();

if(sBuffer.c_str() ==
getPROGMEMTEXT(PROGMEMTEXT_LIST::WALK))
MeansOfTransport =
PROGMEMTEXT_LIST::WALKINGDISTANCEMATRIX;

else if(sBuffer.c_str() ==
getPROGMEMTEXT(PROGMEMTEXT_LIST::BICYCLE))
MeansOfTransport =
PROGMEMTEXT_LIST::BICYCLINGDISTANCEMATRIX;

else if(sBuffer.c_str() ==
getPROGMEMTEXT(PROGMEMTEXT_LIST::DRIVE))
MeansOfTransport =
PROGMEMTEXT_LIST::DRIVINGDISTANCEMATRIX;

else
MeansOfTransport =
PROGMEMTEXT_LIST::DRIVINGDISTANCEMATRIX;

Serial.println(sBuffer);

Initialize();
Finalize();

SearchCalendar();
ReadCalendar();

Setup = 1;
}

delete Now_Time;
Now_Time = new DateTime(MFC_Time.now());

if(Now_Time->unixtime() < (ReadCalendar_Time->unixtime() -


CurrentPrepTime - 300)) {
if((Count % 300) == 0) {
ReadCalendar();
DistanceMatrix();
}
}

if(((Now_Time->unixtime() - 30UL) < (ReadCalendar_Time->unixtime() -


CurrentPrepTime)) && (Now_Time->unixtime() >= (ReadCalendar_Time-
>unixtime() - CurrentPrepTime))) {
analogWrite(3, 20);
delay(3000UL);
analogWrite(3, 0);
}
else if(Now_Time->unixtime() > (ReadCalendar_Time->unixtime() -
CurrentPrepTime)) {
ReadCalendar();
DistanceMatrix();
}

Serial.print(F("Current date: "));


Serial.print(getPROGMEMTEXT_DayOfTheWeek(Now_Time-
>dayOfTheWeek()));
Serial.print(F(" "));
Serial.print(Now_Time->day(), DEC);
Serial.print(F("/"));
Serial.print(Now_Time->month(), DEC);
Serial.print(F(" ("));
Serial.print(getPROGMEMTEXT_MonthOfTheYear(Now_Time-
>month()));
Serial.print(F(") "));
Serial.println(Now_Time->year());

Serial.print(F("Current time: "));


Serial.print(Now_Time->hour(), DEC);
Serial.print(F(":"));
Serial.print(Now_Time->minute(), DEC);
Serial.print(F(":"));
Serial.println(Now_Time->second(), DEC);

Serial.print(F("Alarm time: "));


if((ReadCalendar_Time->minute() == 0) && (CurrentPrepTime != 0))
Serial.print(ReadCalendar_Time->hour() - 1, DEC);
else
Serial.print(ReadCalendar_Time->hour(), DEC);
Serial.print(F(":"));
Serial.print(ReadCalendar_Time->minute() - CurrentPrepTime, DEC);
Serial.print(F(":"));
Serial.println(ReadCalendar_Time->second(), DEC);
Serial.println();

/*
MFC_LCDColorShield.setStr(itoa(Now_Time->hour(), cBuffer[7], 10), 44,
10, BLACK, WHITE);
MFC_LCDColorShield.setStr(":", 44, 26, BLACK, WHITE);
MFC_LCDColorShield.setStr(itoa(Now_Time->minute(), cBuffer[7], 10),
44, 34, BLACK, WHITE);
MFC_LCDColorShield.setStr(":", 44, 42, BLACK, WHITE);
MFC_LCDColorShield.setStr(itoa(Now_Time->second(), cBuffer[7], 10),
44, 58, BLACK, WHITE);

MFC_LCDColorShield.setStr(getPROGMEMTEXT_DayOfTheWeek(Now_
Time->dayOfTheWeek()), 70, 10, COLOR, BACKGROUND);

MFC_LCDColorShield.setStr(itoa(Now_Time->day(), Dag, 10), 70, 10,


COLOR, BACKGROUND);
MFC_LCDColorShieldcd.setStr("/", 101 , 28, COLOR, BACKGROUND);
MFC_LCDColorShield.setStr(itoa(Now_Time->month(), Maand, 10), 103,
37, COLOR, BACKGROUND);
MFC_LCDColorShield.setStr("/", 101, 55, COLOR, BACKGROUND);
MFC_LCDColorShield.setStr(itoa(Now_Time->year(), Jaar, 10), 103, 61,
COLOR, BACKGROUND);
*/

delay(1000);

Count++;
}

////////////////////////////////////////////////////////////////////////////////

void RTC(void) {

Serial.print(getPROGMEMTEXT(PROGMEMTEXT_LIST::RTC_DETECT
ION));

if (MFC_Time.begin()) {
Serial.println(getPROGMEMTEXT(PROGMEMTEXT_LIST::OK));
} else {
Serial.println(getPROGMEMTEXT(PROGMEMTEXT_LIST::FAIL));
while(true);
}
Serial.print(getPROGMEMTEXT(PROGMEMTEXT_LIST::RTC_CONFIG
URATION));

if (MFC_Time.isrunning()) {
Serial.println(getPROGMEMTEXT(PROGMEMTEXT_LIST::OK));
} else {
MFC_Time.adjust(DateTime(F(__DATE__), F(__TIME__)));
Serial.println(getPROGMEMTEXT(PROGMEMTEXT_LIST::ADJUSTED)
);
}
}

void Wifi(void) {

Serial.print(getPROGMEMTEXT(PROGMEMTEXT_LIST::WIFI_SHIELD
));

if (WiFi.status() != WL_NO_SHIELD) {
Serial.println(getPROGMEMTEXT(PROGMEMTEXT_LIST::OK));
} else {
Serial.println(getPROGMEMTEXT(PROGMEMTEXT_LIST::FAIL));
while(true);
}

Serial.print(getPROGMEMTEXT(PROGMEMTEXT_LIST::WIFI_CONNE
CTION));

MFC_WifiStatus = WL_IDLE_STATUS;

for(int i = 0; (i < 10) && (MFC_WifiStatus != WL_CONNECTED); i++) {


MFC_WifiStatus =
WiFi.begin(getPROGMEMTEXT_i(PROGMEMTEXT_LIST::WIFI_SSID,
6), getPROGMEMTEXT_i(PROGMEMTEXT_LIST::WIFI_PASSWORD,
7));
delay(6000);
}

if (MFC_WifiStatus == WL_CONNECTED) {
Serial.println(getPROGMEMTEXT(PROGMEMTEXT_LIST::OK));
} else {
Serial.println(getPROGMEMTEXT(PROGMEMTEXT_LIST::FAIL));
while(true);
}
}

////////////////////////////////////////////////////////////////////////////////

void Initialize(void) {

Serial.print(getPROGMEMTEXT(PROGMEMTEXT_LIST::GOOGLE_INI
TIALIZEOAUTH));

TembooChoreo InitializeOAuthChoreo(MFC_WifiClient);

InitializeOAuthChoreo.begin();

InitializeOAuthChoreo.setAccountName(getPROGMEMTEXT_i(PROGME
MTEXT_LIST::ACCOUNT, 0));
InitializeOAuthChoreo.setAppKeyName(getPROGMEMTEXT_i(PROGME
MTEXT_LIST::APP_NAME, 1));
InitializeOAuthChoreo.setAppKey(getPROGMEMTEXT_i(PROGMEMTE
XT_LIST::APP_KEY, 2));

InitializeOAuthChoreo.setProfile(getPROGMEMTEXT_i(PROGMEMTEX
T_LIST::INITIALIZEMFC, 3));

InitializeOAuthChoreo.addInput(getPROGMEMTEXT_i(PROGMEMTEXT
_LIST::SCOPE, 4),
getPROGMEMTEXT_i(PROGMEMTEXT_LIST::SCOPE_VALUE, 6));

InitializeOAuthChoreo.setChoreo(getPROGMEMTEXT_i(PROGMEMTEX
T_LIST::INITIALIZEOAUTH, 7));

if(InitializeOAuthChoreo.run() == 0) {

Serial.println(getPROGMEMTEXT(PROGMEMTEXT_LIST::OK));

while(InitializeOAuthChoreo.available()) {
InitializeOAuthChoreo.readStringUntil('\x1F');
InitializeOAuthChoreo.readStringUntil('\x1E');

InitializeOAuthChoreo.readStringUntil('\x1F');
Serial.println(F("\nNavigate to this web-page and click \"Allow\"."));
Serial.println(InitializeOAuthChoreo.readStringUntil('\x1E'));

while(!Serial.available());

InitializeOAuthChoreo.readStringUntil('\x1F');
CallbackID = InitializeOAuthChoreo.readStringUntil('\x1E');
CallbackID.trim();

// Serial.print((char)InitializeOAuthChoreo.read());
}
} else {

Serial.print(getPROGMEMTEXT(PROGMEMTEXT_LIST::FAIL));

while(true);
}

InitializeOAuthChoreo.close();
}

////////////////////////////////////////////////////////////////////////////////

void Finalize(void) {

Serial.print(getPROGMEMTEXT(PROGMEMTEXT_LIST::GOOGLE_FIN
ALIZEOAUTH));

TembooChoreo FinalizeOAuthChoreo(MFC_WifiClient);

FinalizeOAuthChoreo.begin();

FinalizeOAuthChoreo.setAccountName(getPROGMEMTEXT_i(PROGME
MTEXT_LIST::ACCOUNT, 0));
FinalizeOAuthChoreo.setAppKeyName(getPROGMEMTEXT_i(PROGME
MTEXT_LIST::APP_NAME, 1));
FinalizeOAuthChoreo.setAppKey(getPROGMEMTEXT_i(PROGMEMTEX
T_LIST::APP_KEY, 2));

FinalizeOAuthChoreo.setProfile(getPROGMEMTEXT_i(PROGMEMTEXT
_LIST::FINALIZEMFC, 3));

FinalizeOAuthChoreo.addInput(getPROGMEMTEXT_i(PROGMEMTEXT
_LIST::CALLBACKID, 4), CallbackID);

FinalizeOAuthChoreo.setChoreo(getPROGMEMTEXT_i(PROGMEMTEX
T_LIST::FINALIZEOAUTH, 7));

if(FinalizeOAuthChoreo.run() == 0) {

Serial.println(getPROGMEMTEXT(PROGMEMTEXT_LIST::OK));

delete Now_Time;
Now_Time = new DateTime(MFC_Time.now());

delete AccessToken_Time;
AccessToken_Time = new DateTime(Now_Time->year(), Now_Time-
>month(), Now_Time->day(), Now_Time->hour() + 1, Now_Time-
>minute(), Now_Time->second());

while(FinalizeOAuthChoreo.available()) {

FinalizeOAuthChoreo.readStringUntil('\x1F');
FinalizeOAuthChoreo.readStringUntil('\x1E');

FinalizeOAuthChoreo.readStringUntil('\x1F');
RefreshToken = FinalizeOAuthChoreo.readStringUntil('\x1E');
RefreshToken.trim();

FinalizeOAuthChoreo.readStringUntil('\x1F');
FinalizeOAuthChoreo.readStringUntil('\x1E');

FinalizeOAuthChoreo.readStringUntil('\x1F');
FinalizeOAuthChoreo.readStringUntil('\x1E');

FinalizeOAuthChoreo.readStringUntil('\x1F');
AccessToken = FinalizeOAuthChoreo.readStringUntil('\x1E');
AccessToken.trim();

// Serial.print((char)FinalizeOAuthChoreo.read());
}
} else {

Serial.print(getPROGMEMTEXT(PROGMEMTEXT_LIST::FAIL));

while(true);
}

FinalizeOAuthChoreo.close();
}

////////////////////////////////////////////////////////////////////////////////

void SearchCalendar(void) {

Serial.print(getPROGMEMTEXT(PROGMEMTEXT_LIST::GOOGLE_SE
ARCHCALENDAR));

TembooChoreo SearchCalendarChoreo(MFC_WifiClient);

SearchCalendarChoreo.begin();

SearchCalendarChoreo.setAccountName(getPROGMEMTEXT_i(PROGME
MTEXT_LIST::ACCOUNT, 0));
SearchCalendarChoreo.setAppKeyName(getPROGMEMTEXT_i(PROGME
MTEXT_LIST::APP_NAME, 1));
SearchCalendarChoreo.setAppKey(getPROGMEMTEXT_i(PROGMEMTE
XT_LIST::APP_KEY, 2));

delete Now_Time;
Now_Time = new DateTime(MFC_Time.now());
if(Now_Time->unixtime() < AccessToken_Time->unixtime()) {
SearchCalendarChoreo.addInput(getPROGMEMTEXT_i(PROGMEMTEXT
_LIST::ACCESSTOKEN, 3), AccessToken);
} else {

delete AccessToken_Time;
AccessToken_Time = new DateTime(Now_Time->year(), Now_Time-
>month(), Now_Time->day(), Now_Time->hour() + 1, Now_Time-
>minute(), Now_Time->second());

SearchCalendarChoreo.setProfile(getPROGMEMTEXT_i(PROGMEMTEX
T_LIST::SEARCHCALENDARMFC, 3));
SearchCalendarChoreo.addInput(getPROGMEMTEXT_i(PROGMEMTEXT
_LIST::REFRESHTOKEN, 4), RefreshToken);
}

SearchCalendarChoreo.addInput(getPROGMEMTEXT_i(PROGMEMTEXT
_LIST::CALENDARNAME, 5),
getPROGMEMTEXT_i(PROGMEMTEXT_LIST::CALENDARNAME_VA
LUE, 6));

SearchCalendarChoreo.setChoreo(getPROGMEMTEXT_i(PROGMEMTEX
T_LIST::SEARCHCALENDARSBYNAME, 7));

if(SearchCalendarChoreo.run() == 0) {

Serial.println(getPROGMEMTEXT(PROGMEMTEXT_LIST::OK));

while(SearchCalendarChoreo.available()) {

SearchCalendarChoreo.readStringUntil('\x1F');
SearchCalendarChoreo.readStringUntil('\x1E');

SearchCalendarChoreo.readStringUntil('\x1F');
SearchCalendarChoreo.readStringUntil('\x1E');

SearchCalendarChoreo.readStringUntil('\x1F');
sBuffer = SearchCalendarChoreo.readStringUntil('\x1E');
sBuffer.trim();
if(sBuffer !=
getPROGMEMTEXT(PROGMEMTEXT_LIST::PROGMEMTEXT_LIST_S
IZE))
AccessToken = sBuffer;

SearchCalendarChoreo.readStringUntil('\x1F');
SearchCalendarChoreo.readStringUntil('\x1E');

SearchCalendarChoreo.readStringUntil('\x1F');
SearchCalendarChoreo.readStringUntil('\x1E');

SearchCalendarChoreo.readStringUntil('\x1F');
CalendarID = SearchCalendarChoreo.readStringUntil('\x1E');
CalendarID.trim();

SearchCalendarChoreo.readStringUntil('\x1F');
SearchCalendarChoreo.readStringUntil('\x1E');

// Serial.print((char)SearchCalendarChoreo.read());
}
} else {

Serial.print(getPROGMEMTEXT(PROGMEMTEXT_LIST::FAIL));

while(true);
}

SearchCalendarChoreo.close();
}

////////////////////////////////////////////////////////////////////////////////

void ReadCalendar(void) {

Serial.print(getPROGMEMTEXT(PROGMEMTEXT_LIST::GOOGLE_RE
ADCALENDAR));

TembooChoreo ReadCalendarChoreo(MFC_WifiClient);
ReadCalendarChoreo.begin();

ReadCalendarChoreo.setAccountName(getPROGMEMTEXT_i(PROGME
MTEXT_LIST::ACCOUNT, 0));
ReadCalendarChoreo.setAppKeyName(getPROGMEMTEXT_i(PROGME
MTEXT_LIST::APP_NAME, 1));
ReadCalendarChoreo.setAppKey(getPROGMEMTEXT_i(PROGMEMTEX
T_LIST::APP_KEY, 2));

delete Now_Time;
Now_Time = new DateTime(MFC_Time.now());

if(Now_Time->unixtime() < AccessToken_Time->unixtime()) {


ReadCalendarChoreo.addInput(getPROGMEMTEXT_i(PROGMEMTEXT_
LIST::ACCESSTOKEN, 3), AccessToken);
} else {

delete AccessToken_Time;
AccessToken_Time = new DateTime(Now_Time->year(), Now_Time-
>month(), Now_Time->day(), Now_Time->hour() + 1, Now_Time-
>minute(), Now_Time->second());

ReadCalendarChoreo.setProfile(getPROGMEMTEXT_i(PROGMEMTEXT
_LIST::READCALENDARMFC, 3));
ReadCalendarChoreo.addInput(getPROGMEMTEXT_i(PROGMEMTEXT_
LIST::REFRESHTOKEN, 4), RefreshToken);
}

ReadCalendarChoreo.addInput(getPROGMEMTEXT_i(PROGMEMTEXT_
LIST::CALENDARID, 6), CalendarID);

ReadCalendarChoreo.setChoreo(getPROGMEMTEXT_i(PROGMEMTEXT
_LIST::GETNEXTEVENT, 7));

if(ReadCalendarChoreo.run() == 0) {

Serial.print(getPROGMEMTEXT(PROGMEMTEXT_LIST::OK));

while(ReadCalendarChoreo.available()) {
ReadCalendarChoreo.readStringUntil('\x1F');
ReadCalendarChoreo.readStringUntil('\x1E');

ReadCalendarChoreo.readStringUntil('\x1F');
ReadCalendarChoreo.readStringUntil('\x1E');

ReadCalendarChoreo.readStringUntil('\x1F');
sBuffer = ReadCalendarChoreo.readStringUntil('\x1E');
sBuffer.trim();

if(sBuffer !=
getPROGMEMTEXT(PROGMEMTEXT_LIST::PROGMEMTEXT_LIST_S
IZE)) {

sBuffer[4] = '\0';
sBuffer[7] = '\0';
sBuffer[10] = '\0';
sBuffer[13] = '\0';
sBuffer[16] = '\0';
sBuffer[19] = '\0';

delete ReadCalendar_Time;
ReadCalendar_Time = new DateTime(atoi(&sBuffer[0]), atoi(&sBuffer[5]),
atoi(&sBuffer[8]), atoi(&sBuffer[11]), atoi(&sBuffer[14]),
atoi(&sBuffer[17]));

Serial.println();
}
else {

Serial.println(getPROGMEMTEXT(PROGMEMTEXT_LIST::UNEXPECT
EDERROR));

while(true);
}

ReadCalendarChoreo.readStringUntil('\x1F');
sBuffer = ReadCalendarChoreo.readStringUntil('\x1E');
sBuffer.trim();
if(sBuffer !=
getPROGMEMTEXT(PROGMEMTEXT_LIST::PROGMEMTEXT_LIST_S
IZE))
AccessToken = sBuffer;

sBuffer =
getPROGMEMTEXT(PROGMEMTEXT_LIST::PROGMEMTEXT_LIST_S
IZE);

ReadCalendarChoreo.readStringUntil('\x1F');
ReadCalendarChoreo.readStringUntil('\x1E');

ReadCalendarChoreo.readStringUntil('\x1F');
ReadCalendarChoreo.readStringUntil('\x1E');

//Serial.print((char)ReadCalendarChoreo.read());
}
} else {

Serial.print(getPROGMEMTEXT(PROGMEMTEXT_LIST::FAIL));

while(true);
}

ReadCalendarChoreo.close();
}

////////////////////////////////////////////////////////////////////////////////

void DistanceMatrix(void) {

Serial.print(getPROGMEMTEXT(PROGMEMTEXT_LIST::GOOGLE_DIS
TANCEMATRIX));

TembooChoreo DistanceMatrixChoreo(MFC_WifiClient);

DistanceMatrixChoreo.begin();
DistanceMatrixChoreo.setAccountName(getPROGMEMTEXT_i(PROGME
MTEXT_LIST::ACCOUNT, 0));
DistanceMatrixChoreo.setAppKeyName(getPROGMEMTEXT_i(PROGME
MTEXT_LIST::APP_NAME, 1));
DistanceMatrixChoreo.setAppKey(getPROGMEMTEXT_i(PROGMEMTE
XT_LIST::APP_KEY, 2));

DistanceMatrixChoreo.addInput(getPROGMEMTEXT_i(PROGMEMTEXT
_LIST::ORIGIN, 3),
getPROGMEMTEXT_i(PROGMEMTEXT_LIST::ORIGIN_VALUE, 4));
DistanceMatrixChoreo.addInput(getPROGMEMTEXT_i(PROGMEMTEXT
_LIST::DESTINATION, 5),
getPROGMEMTEXT_i(PROGMEMTEXT_LIST::DESTINATION_VALUE
, 6));

DistanceMatrixChoreo.setChoreo(getPROGMEMTEXT_i(MeansOfTranspo
rt, 7));

DistanceMatrixChoreo.run();

if(DistanceMatrixChoreo.run() == 0) {

Serial.println(getPROGMEMTEXT(PROGMEMTEXT_LIST::OK));

while(DistanceMatrixChoreo.available()) {

DistanceMatrixChoreo.readStringUntil('\x1F');
DistanceMatrixChoreo.readStringUntil('\x1E');

DistanceMatrixChoreo.readStringUntil('\x1F');
sBuffer = DistanceMatrixChoreo.readStringUntil('\x1E');
sBuffer.trim();

CurrentPrepTime = UserPrepTime + atoi(sBuffer.c_str());

DistanceMatrixChoreo.readStringUntil('\x1F');
DistanceMatrixChoreo.readStringUntil('\x1E');

// Serial.print((char)DistanceMatrixChoreo.read());
}
} else {

Serial.print(getPROGMEMTEXT(PROGMEMTEXT_LIST::FAIL));

while(true);
}

DistanceMatrixChoreo.close();
}
99) Arduino Smart Humidifer

COMPONENTS AND SUPPLIES


Basic Bread board - 16.5*5.5 cm
× 1

LCD 16*2 Characters - Green × 1


Yellow back light
Humidity /temperature sensor
module × 1

Breadboard Jumper Wire


Pack(200mm/165mm/125mm/80mm) × 1

Arduino UNO & Genuino UNO


× 1

Momentary Pushbutton Switch


× 1

Grove - Water Atomization v1.0


× 1

ABOUT THIS PROJECT


There are three key components to healthy air. It must
be fresh, clean, and have the proper humidity. Humans
are sensitive to humidity because the human body uses
evaporative cooling, enabled by perspiration, as the
primary mechanism to rid itself of waste heat. Humans
can be comfortable within a wide range of humidity
depending on the temperature—from thirty to seventy
percent but ideally between 50% and 60%. Very low
humidity can create discomfort, respiratory problems,
and aggravate allergies in some individuals. In the
winter, it is advisable to maintain relative humidity at
30 percent or above. Extremely low (below 20%)
relative humidity may also cause eye irritation.
Humidify your home, especially the bedrooms. Low
humidity is a common cause of nosebleeds. The right
humidity levels help your home to feel cool in the
summer and warm in the winter.In the winter, or in
regions that tend to be cold for most of the year,
humidification, or adding moisture, is essential.
This project senses temperature & humidity from your
room or environment and check either it is in
comfortable range or not. If it finds that relative
humidity is lower than the required limit, it turns on
the humidifier for 10 seconds, then again checks the
humidity level. If not adequate then again turns on.
Seeed studio HSM-20G temperature & humidity
sensor is used here to sense the temperature and
humidity. A LCD display is used to show the
temperature and humidity level on your room. You can
use Grove button to manually control the humidifier.
To control all the things Arduino UNO is used.
How it works:
Grove - Water Atomization is fine Grove module for
you to develop an atomizer or an atomizer module in
your applications easily. It Heated with ultrasound. If
you give logic high to the enable pin it starts working.
It works with 5V and takes maximum 2W. Details
HSM-20G temperature & humidity module: HSM-
20G is a low price temperature/humidity module and
gives analog reading. It converts relative humidity and
temperature to corresponding standard voltage
Connection:
Follow the schematic diagram carefully. A 10K
resistor is connected to T and Ground pin according to
datasheet. Another 100K and 10uF capacitor is
connected to H and Ground pin. I used open source
fritzing to draw the schematic. I did not find Water
Atomization to fritzing parts library and for that I used
Grove buzzer module and made a note as water
automization. Don't panic, connection is same and just
consider the signal pin as enable pin of water
atomization. I attached two image here, one without
LCD connection and another with LCD connection.

Fritzing source file is attached to source code of my


github repository. You can download it.
Collect all the component mentioned below. Connect
HSM-20G temperature and humidity sensor to the
arduino board with the resistors and capacitor shown
in the schematic. You can use breadboard to easily
connect sensor to the resistors and capacitor and the
arduino board.

Make & Test:


Upload the program to the arduino board and open the
serial monitor. If it works correctly you should get the
following result from the serial monitor.

Now connect the LCD display to the arduino board


and test it. LCD should display the relative humidity
and temperature. If everything works well now it is
the time to connect water atomization to the system.
To do that first connect the driver board to the arduino
board, then connect ultrasonic transducer to the driver
board.
Take a cup filled with water and put some tissue into
the water. Put ultrasonic transducer onto
tissue. Note that the bottom side is the side with
hollow which is supposed to face downside. Let
bottom of transducer plate sink into the water and
keep top side above water. The function of tissue is
lead water to the transducer and keep upper side of
transducer above water.
Power up the system, If you see vapor produced then
congratulation! You made it, experiment with it!!!
Notes that do not touch transducer interface pins
directly because peak output voltage of Drier board
can be 65V.
SCHEMATICS
CODE
#include <LiquidCrystal.h>
LiquidCrystal lcd(13, 12, 8, 9, 10, 11);

const byte nsum=10;

//int humidityPin=A0;
//int Thgm20Pin=A1;
int atomizationPin = 2;
unsigned int sensorValue2 = 0; // variable to store the
value coming from the sensor
unsigned int sensorValue3 = 0; // variable to store the
value coming from the sensor

void setup() {
Serial.begin(9600);
pinMode(atomizationPin, OUTPUT);
lcd.begin(16, 2);
}
void loop() {
for (byte i=0;i<nsum;i++)
{ // read 10 values for T & H
sensorValue2 += analogRead(A0);
sensorValue3 += analogRead(A1);
}
// average the value
int sensorValue2Avg=sensorValue2/nsum;
float RH= 0.1515*sensorValue2Avg-12.0;
int sensorValue3Avg=sensorValue3/nsum;
float Vt=(float) sensorValue3Avg*5.0/1023.0;
float R=(5.0-Vt)*10.0/Vt; // convert the value to relative
humidity
float TinC=281.583*pow(1.0230,
(1.0/R))*pow(R,-0.1227)-150.6614;
float TinF=TinC*(9.0/5.0)+32; // convert the
temperature to fahrenheit
// print to serial monitor
Serial.print(RH,0);
Serial.println(" %RH");
Serial.print(TinC,1);
Serial.println(" deg C");
Serial.print(TinF,1);
Serial.println(" deg F");
Serial.print(R);
// print the value to lcd display
lcd.setCursor(0, 0);
lcd.print("%RH = ");
lcd.setCursor(6, 0);
lcd.print(R);
lcd.setCursor(0, 1);
lcd.print("T = ");
lcd.setCursor(5, 1);
lcd.print(TinC);
//
// if relatie humidity less than 40 % then turn on
humidifire
// for 10sec.
if(R < 50){
digitalWrite(atomizationPin, HIGH);
delay(10000);
digitalWrite(atomizationPin, LOW);
sensorValue2=0;
sensorValue3=0;
delay(5000)
}
100) Arduino Advent Candle
COMPONENTS AND SUPPLIES
Arduino UNO & Genuino UNO

× 1

White Plastic Tube


× 1

3 mm LED: Red × 25
RTC DS3231
× 1

Yellow LED Flickering Candle


× 1

Rechargeable Li-ion Battery Pack 1200mAh


× 1

Speaker: 0.25W, 8 ohms

× 1

SparkFun Pushbutton switch 12mm

× 1

Slide Switch

× 1

Jumper wires (generic) × 1


Round wood box
× 1
NECESSARY TOOLS AND MACHINES
Hot glue gun (generic)

Driller

Soldering iron (generic)


APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT


I was always used to have an Advent Candle during
December, but this year we were not able to buy one
in time. So I decided to build an electronic one and
control it with Arduino. Indeed it was a lot of work
and it was ready only by the 10th of December but,
well, next year it will still be working and I can
program new effects!
I am controlling 25 LEDs with 10 GPIO pins, so I
needed to build a matrix of LEDs and make some
multiplexing.
At the beginning, I was thinking to use a Raspberry Pi
but I switched soon to Arduino since such a board has
been lying in a drawer for a long time. The code is
pretty naive at the moment. I hope to have a better
understanding of how to manage this kind of "parallel"
stuff in Arduino in the future: listening for a button
press while controlling a LED animation can be pretty
tricky when you don't have threads. Do you? I took
inspiration
Candle on 14th of December

The hardest part was to put the LEDs from the


inside... without breaking the soldering
Lots of wires,,, a distinct colour for any of them in
order to identify them later
Fixing components into the box
Proper holes to access Arduino and battery recharge
USB ports
Main ON/OFF switch
View of the lid from the bottom (not all cables have
passed yet)
Candle stuck on the lid (with date decorations
provided by my daughter and her baby-sitter)
Silicon glue makes a nice "wax" effect
Now with the RTC module inside... we want to keep
the date during successive switching on and off and in
the next days (also change properly date at midnight)
Now just close the box and it's done (the buzzer has
been later replaced with a proper speaker)
Ready to plug!
Acknowledgements
This is actually my first "real" hardware project,
involving more than 70 solder joints. I thought I
would have never managed such a thing and now I am
pretty excited to have accomplished it. I need to thank
my uncle Stefano for inspiring, Edo for remembering I
had an Arduino and letting me discover Hackster.io,
Daniele D.S. for providing the main hardware
component, my wife, Julia, for bearing with me while
I was playing with this stuff and my nephew Richard
for encouragement with his enthusiasm and helping
with soldering.

SCHEMATICS
CODE

#include "Wire.h"
#include "pitches.h"
#define DS3231_I2C_ADDRESS 0x68

const int LOOPS = 7; // number of loops


const int BUTTON = 13; // pin number of button
const int SPEAKER = 14; // pin number of speaker

int cathods[] = {2,4,7,8,12}; // pins of cathodes


int anodes[] = {3,5,6,9,10}; // pins of anodes
int current_led = 1; // current ON led
int current_loop = 0; // current loop

int delays[] = {1,20,50,100,150,100,50,20};

unsigned long previousMillis = 0;


unsigned long previousLoop = 0;

// Convert binary coded decimal to normal decimal numbers


byte bcdToDec(byte val)
{
return( (val/16*10) + (val%16) );
}

// switch on a single led (switch off all other)


void led_on(int index) {
int myAnode = (index - 1) / 5;
int myCathode = (index - 1) % 5;

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


digitalWrite(anodes[i], LOW);
digitalWrite(cathods[i], HIGH);
}

digitalWrite(anodes[myAnode], HIGH);
digitalWrite(cathods[myCathode], LOW);

// get day of month from RTC clock


byte get_day() {
byte second;
byte minute;
byte hour;
byte dayOfWeek;
byte dayOfMonth;
byte month;
byte year;
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0); // set DS3231 register pointer to 00h
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
second = bcdToDec(Wire.read() & 0x7f);
minute = bcdToDec(Wire.read());
hour = bcdToDec(Wire.read() & 0x3f);
dayOfWeek = bcdToDec(Wire.read());
dayOfMonth = bcdToDec(Wire.read());
return dayOfMonth;
}

// play music switching on leds until the one of today


void play(byte today) {

// jingle bells

int melody[] = {
NOTE_E3, NOTE_E3, NOTE_E3,
NOTE_E3, NOTE_E3, NOTE_E3,
NOTE_E3, NOTE_G3, NOTE_C3, NOTE_D3,
NOTE_E3,
NOTE_F3, NOTE_F3, NOTE_F3, NOTE_F3,
NOTE_F3, NOTE_E3, NOTE_E3, NOTE_E3, NOTE_E3,
NOTE_E3, NOTE_D3, NOTE_D3, NOTE_E3,
NOTE_D3, NOTE_G3,
NOTE_E3, NOTE_E3, NOTE_E3,
NOTE_E3, NOTE_E3, NOTE_E3,
NOTE_E3, NOTE_G3, NOTE_C3, NOTE_D3,
NOTE_E3,
NOTE_F3, NOTE_F3, NOTE_F3, NOTE_F3,
NOTE_F3, NOTE_E3, NOTE_E3, NOTE_E3, NOTE_E3,
NOTE_G3, NOTE_G3, NOTE_F3, NOTE_D3,
NOTE_C3
};

// note durations: 4 = half note 2 = quarter note, 1 = eighth note, etc.:


int noteDurations[] = {2,2,4, 2,2,4, 2,2,3,1, 8, 2,2,3,1, 2,2,2,1,1, 2,2,2,2, 4,4,
2,2,4, 2,2,4, 2,2,3,1, 8, 2,2,2,2, 2,2,2,1,1, 2,2,2,2, 8};
// play music
for (int thisNote = 0; thisNote < 51; thisNote++) {

led_on((thisNote % today)+1);

// every quarter lasts 250 ms


int noteDuration = noteDurations[thisNote]*125;
tone(SPEAKER, melody[thisNote],noteDuration);

// to distinguish the notes, set a minimum time between them.


// the note's duration + 30% seems to work well:
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
// stop the tone playing:
noTone(SPEAKER);

// stop music on button press


int sensorVal = digitalRead(BUTTON);
if (sensorVal == LOW) {
Serial.println("Button pressed, stopping music");
delay(300);
// stop the tone playing:
noTone(SPEAKER);
break;
}

// setup
void setup() {
Wire.begin();
Serial.begin(9600);
pinMode(BUTTON, INPUT_PULLUP);
// switch off all
for (int i = 0; i < 5; i++) {
pinMode(cathods[i], OUTPUT);
pinMode(anodes[i], OUTPUT);
digitalWrite(cathods[i], LOW);
digitalWrite(anodes[i], LOW);
}
}

// loop
void loop() {

byte today = get_day();


unsigned long currentMillis = millis();
int loop_interval = 3000;

int myDelay = delays[current_loop];

if (myDelay == 1) {
loop_interval = 5000;
} else {
loop_interval = myDelay * today * 5;
}
// play song on press button
int sensorVal = digitalRead(BUTTON);
if (sensorVal == LOW) {
Serial.println("Button pressed, starting music");
play(today);
}

// different led in the loop (stay "myDelay" on)


if (currentMillis - previousMillis >= myDelay) {
led_on(current_led);
current_led ++;
if (current_led > today) {
// start over after today
current_led = 1;
}
previousMillis = currentMillis;
}
// different loops
if (currentMillis - previousLoop >= loop_interval) {
current_loop ++;
if (current_loop > LOOPS) {
// start over from first loop
current_loop = 0;
}
previousLoop = currentMillis;
}

101) Arduino DIY Code Red Button for Healthcare


Simulation
COMPONENTS AND SUPPLIES
Arduino UNO & Genuino UNO
× 1

Adafruit 16mm Illuminated


Pushbutton On/Off × 1

Adafruit Super Bright Red LED


5mm × 3

Adafruit 5mm Plastic Flat LED


Holder × 3

Adafruit Hook-Up Wire Spool


Set × 1

Adafruit 5V 2A Switching
Power Supply × 1

Adafruit Perma-Proto Quarter- × 1


sized Breadboard PCB

Adafruit Nylon Screws


× 8
NECESSARY TOOLS AND MACHINES
Soldering iron (generic)

Ultimaker 3

ABOUT THIS PROJECT

DIY CODE RED BUTTON


For those that work in healthcare simulation, we can
often find ourselves trying to simulate different events
or procedures. This DIY code red button can be used
in lieu of a real wall button. Follow these steps:
This is an advanced project that requires the use
of multiple pieces of equipment. Gather all
necessary supplies and equipment.
If you own a 3D printer, print the attached CAD
files. If not, you order locally from 3DHubs.
Screw Arduino Uno board into back panel using
nylon screws. Be careful not to apply too much
force.
Assemble the front plate and code red plate. Push
the 5mm plastic flat LED holder into the 3 holes
on the front plate. Glue code red plate in place,
allow time for glue to dry.
Front Plate with LED Holders in place
Assemble Electronics
This is the electronics assembly part. Get your
soldering iron ready with all the required components.
Get your Perma-Proto breadboard and attach the
resistors. Solder in place.
Attach resistors
Start hooking up wires for connection to the LEDs and
pushbutton On/Off. Solder wire connections to the
LEDs, use heat-shrink tubing if needed.
Attach the push button On/Off switch. It does not need
to be glued in place.
Place the LEDs into the flat LED holder through the
back of the front plate. They will snap into place.
Connect both front and back panel. Power using
Arduino cable or 9v battery. Push button, enjoy!

SCHEMATICS
CODE

/*
DIY Code Red Button
Created by David Escobar
Date: 04/14/17
*/

int ledOn = 4; //LED Button On


int led1 = 5; //LED 1
int led2 = 6; //LED 2
int led3 = 7; //LED 3

void setup() {
pinMode(ledOn, OUTPUT);
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(led3, OUTPUT);
}

void loop() {

blink();
}

void blink(){
digitalWrite(ledOn, HIGH);
digitalWrite(led1, HIGH);
digitalWrite(led2, HIGH);
digitalWrite(led3, HIGH);
delay(250);
digitalWrite(led1, LOW);
digitalWrite(led2, LOW);
digitalWrite(led3, LOW);
delay(100);
}

102) Arduino Fix Ice Making Machine


COMPONENTS AND SUPPLIES

Arduino UNO & Genuino


UNO
× 1

Relay (generic) × 1
NECESSARY TOOLS AND MACHINES
Old Ice Maker
APPS AND ONLINE SERVICES
Arduino IDE

ardublock

ABOUT THIS PROJECT


My Ice Maker
arduino and relays
Ice maker in operation

SCHEMATICS
CODE

void setup()
{
pinMode( 4 , INPUT);
pinMode( 5 , INPUT);
pinMode( 6 , INPUT);
pinMode( 4 , OUTPUT);
pinMode( 5 , OUTPUT);
pinMode( 6 , OUTPUT);
pinMode( 8 , OUTPUT);
pinMode( 9 , OUTPUT);
pinMode( 10 , OUTPUT);
pinMode( 11 , OUTPUT);
digitalWrite( 4 , LOW );

digitalWrite( 5 , LOW );

digitalWrite( 6 , LOW );

digitalWrite( 8 , HIGH );

digitalWrite( 9 , HIGH );

digitalWrite( 10 , HIGH );

digitalWrite( 11 , HIGH );

void loop()
{
if ( digitalRead( 4))
{
digitalWrite( 8 , LOW );
}
if ( digitalRead( 5))
{
digitalWrite( 8 , HIGH );
digitalWrite( 9 , LOW );
delay( 40000 );
digitalWrite( 9 , HIGH );
digitalWrite( 10 , LOW );
delay( 700000 );
digitalWrite( 8 , LOW );
delay( 5000 );
}
if ( digitalRead( 6))
{
digitalWrite( 8 , HIGH );
delay( 5000 );
digitalWrite( 11 , LOW );
delay( 30000 );
digitalWrite( 11 , HIGH );
digitalWrite( 8 , LOW );
delay( 10000 );
}
}
103) Arduino Based Graph
COMPONENTS AND SUPPLIES
Arduino UNO & Genuino
UNO
× 1

Rotary potentiometer (generic)


× 1

ABOUT THIS PROJECT

This shows you how to send a byte of data from the


Arduino or Genuino to a personal computer and graph
the result. This is called serial communication because
the connection appears to both the board and the
computer as a serial port, even though it may actually
use a USB cable, a serial to USB and a USB to serial
converter.
You can use the serial monitor of the Arduino Software
(IDE) to view the sent data, or it can be read by
Processing (see code below), Flash, PD, Max/MSP, etc.
Circuit
Connect a potentiometer or other analog sensor to analog
input 0.

Schematic
Code
/* Graph
A simple example of communication from the Arduino
board to the computer: The value of analog input 0 is
sent out the serial port. We call this "serial"
communication because the connection appears to both
the Arduino and the computer as a serial port, even
though it may actually use a USB cable. Bytes are sent
one after another (serially) from the Arduino to the
computer.
You can use the Arduino Serial Monitor to view the sent
data, or it can be read by Processing, PD, Max/MSP, or
any other program capable of reading data from a serial
port. The Processing code below graphs the data
received so you can see the value of the analog input
changing over time.
The circuit: - any analog input sensor attached to
analog in pin 0*/
void setup() { // initialize the serial communication:
Serial.begin(9600);}
void loop() { // send the value of analog input 0:
Serial.println(analogRead(A0)); // wait a bit for the
analog-to-digital converter to stabilize after the last //
reading: delay(2);}
/* Processing code for this example
// Graphing sketch
// This program takes ASCII-encoded strings from the
serial port at 9600 baud // and graphs them. It expects
values in the range 0 to 1023, followed by a // newline,
or newline and carriage return
import processing.serial.*;
Serial myPort; // The serial port int xPos = 1;
// horizontal position of the graph float inByte = 0;
void setup () { // set the window size: size(400,
300);
// List all the available serial ports // if using
Processing 2.1 or later, use Serial.printArray()
println(Serial.list());
// I know that the first port in the serial list on my Mac
is always my // Arduino, so I open Serial.list()[0]. //
Open whatever port is the one you're using. myPort =
new Serial(this, Serial.list()[0], 9600);
// don't generate a serialEvent() unless you get a
newline character: myPort.bufferUntil('\n');
// set initial background: background(0); }
void draw () { // draw the line: stroke(127, 34,
255); line(xPos, height, xPos, height - inByte);
// at the edge of the screen, go back to the beginning:
if (xPos >= width) { xPos = 0; background(0); }
else { // increment the horizontal position:
xPos++; } }
void serialEvent (Serial myPort) { // get the ASCII
string: String inString = myPort.readStringUntil('\n');
if (inString != null) { // trim off any whitespace:
inString = trim(inString); // convert to an int and map
to the screen height: inByte = float(inString);
println(inByte); inByte = map(inByte, 0, 1023, 0,
height); } }
*/
/* Max/MSP v5 patch for this example
----------begin_max5_patcher---------
-1591.3oc0YszbaaCD9r7uBL5RalQUAO3CvdyS5zVen
WZxs5NcfHgjPCIfJITRTxj+6AOHkoTDooroUs0AQPR
73a+1cwtK3WtZxzEpOwqlB9YveAlL4KWMYh6Q1G
Lo99ISKXeJMmU451zTUQAWpmNy+NM+SZ2y+sR1
l02JuU9t0hJvFlNcMPydOuBv.U5Rgb0LPpRpYBooM3
529latArTUVvzZdFPtsXAuDrrTU.f.sBffXxLvGE50lIH
kUVJXq3fRtdaoDvjYfbgjujaFJSCzq4.tLaN.bi1tJefWpq
bO0uz1IjIABoluxrJ1guxh2JfPO2B5zRNyBCLDFcqbw
Nvuv9fHCb8bvevyyEU2JKTYhkBSWPAfq2TZ6Yhqm
uMUo0feUn+rYpY4YtY+cFw3lUJdCMYAapZqzwUH
X8ScrjAd+SIOU6UBAwIygy.Q1+HAA1KH6EveWOF
QlitUK92ehfal9kFhUxJ3tWcsgpxadigWExbt1o7Ps5dk3
yttivyg20W0VcSmg1G90qtx92rAZbH4ez.ruy1nhmaDP
idE07J+5n2sg6E6oKXxUSmc20o6E3SPRDbrkXnPGU
YE.i5nCNB9TxQjG.G0kCTZtH88f07Rt0ZMMWUw8V
vbKVAaTk6GyoraPdZff7rQTejBN54lgyvHE0Ft7AvIvv
gvIwO23jBdUkYOuSvIFSiNcjFhiSsUBwsUCh1AgfNS
BAeNDBZDIDqY.f8.YjfjV1HAn9XDTxyNFYatVTkKx
3kcK9GraZpI5jv7GOx+Z37Xh82LSKHIDmDXaESoX
RngIZQDKVkpxUkMCyXCQhcCK1z.G457gi3TzMz4
RFD515FG3bIQQwcP3SOF0zlkGhiCBQ1kOHHFFlXa
EBQIQnCwv9QF1LxPZ.A4jR5cyQsvbvHMJsLll01We
+rE2LazX6zYmCraRrsPFwKg1ANBZFY.IAihr8Ox.aH
0oALhB8nQVw0FSJiZeunOykbT6t3r.NP8.iL+bnwNiX
uVMNJH9H9YCm89CFXPBERbz422p8.O4dg6kRxdyj
DqRwMIHTbT3QFLskxJ8tbmQK4tm0XGeZWF7wKK
tYYaTAF.XPNFaaQBinQMJ4QLF0aNHF0JtYuHSxoUZ
fZY6.UU2ejJTb8lQw8Fo5kRv6e2PI+fOM71o2ecY1Vg
TYdCSxxUqLokuYq9jYJi6lxPgD2NIPePLB0mwbGYA
9Rgxdiu1k5xiLlSU6JVnx6wzg3sYHwTesB8Z5D7RiGZ
pXyvDNJY.DQX3.HhvmcUN4bP1yCkhpTle2P37jtBsK
rLWcMScEmltOPv22ZfAqQAdKr9HzATQwZq18PrUG
t6Tst2XMCRUfGuhXs6ccn23YloomMqcTiC5iMGPsHs
HRWhWFlaenVXcqwgCQiGGJzptyS2ZMODBz6fGza0
bzmXBj7+DA94bvpR01MffAlueO7HwcIpWCwmzJdvi
9ILgflLAFmyXB6O7ML0YbD26lenmcGxjVsZUN+A6
pUK7AtTrPgM+eRYG0qD9j4I7eEbco8Xh6WcO.or9X
DC6UCiewbXHkh6xm5LiPEkzpJDRTumEB44Fgz4NC
tJvX.SM1vo2SlTCZGAe7GZu6ahdRyzFOhYZ+mbVV
SYptBw.K1tboIkatIA7c1cTKD1u.honLYV04VkluHsXe
0szv9pQCE9Ro3jaVB1o15pz2XzYoBvO5KXCAe0LC
YJybE8ZODf4fV8t9qW0zYxq.YJfTosj1bv0xc.SaC0+A
V9V9L.KKyV3SyTcRtmzi6rO.O16USvts4B5xe9EymD
vebK0eMfW6+NIsNlE2meqRyJ0utRq13+RjmqYKN1e.
4d61jjdsauXe3.2p6jgi9hsNIv97CoyJ01xzlc3ZhUCtSHx
3UZgjoEJYqNY+hYs5zZQVFW19L3JDYaTlMLqAAt1
G2yXlnFg9a53L1FJVcv.cOX0dh7mCVGCLce7GFcQw
DdH5Ta3nyAS0pQbHxegr+tGIZORgMRnMj5vGl1Fs1
6drnk7Tf1XOLgv1n0d2iEsCxR.eQsNOZ4FGF7whofgfI
3kES1kCeOX5L2rifbdu0A9ae2X.V33B1Z+.Bj1FrP5iFr
CYCG5EUWSG.hhunHJd.HJ5hhnng3h9HPj4lud02.1bx
Gw.-----------end_max5_patcher-----------
*/
Processing Sketch
Using the Processing sketch in the code sample above,
you'll get a graph of the sensor's value. As you change
the value of the analog sensor, you'll get a graph
something like this:

SCHEMATICS
CODE
/* Graph

A simple example of communication from the Arduino


board to the computer: The
value of analog input 0 is sent out the serial port. We call
this "serial"
communication because the connection appears to both
the Arduino and the
computer as a serial port, even though it may actually
use a USB cable. Bytes
are sent one after another (serially) from the Arduino to
the computer.

You can use the Arduino Serial Monitor to view the sent
data, or it can be
read by Processing, PD, Max/MSP, or any other program
capable of reading data
from a serial port. The Processing code below graphs the
data received so you
can see the value of the analog input changing over time.

The circuit:
- any analog input sensor attached to analog in pin 0
*/

void setup() {
// initialize the serial communication:
Serial.begin(9600);
}

void loop() {
// send the value of analog input 0:
Serial.println(analogRead(A0));
// wait a bit for the analog-to-digital converter to
stabilize after the last
// reading:
delay(2);
}

/* Processing code for this example

// Graphing sketch

// This program takes ASCII-encoded strings from the


serial port at 9600 baud
// and graphs them. It expects values in the range 0 to
1023, followed by a
// newline, or newline and carriage return

import processing.serial.*;
Serial myPort; // The serial port
int xPos = 1; // horizontal position of the graph
float inByte = 0;

void setup () {
// set the window size:
size(400, 300);

// List all the available serial ports


// if using Processing 2.1 or later, use Serial.printArray()
println(Serial.list());

// I know that the first port in the serial list on my Mac is


always my
// Arduino, so I open Serial.list()[0].
// Open whatever port is the one you're using.
myPort = new Serial(this, Serial.list()[0], 9600);

// don't generate a serialEvent() unless you get a newline


character:
myPort.bufferUntil('\n');

// set initial background:


background(0);
}

void draw () {
// draw the line:
stroke(127, 34, 255);
line(xPos, height, xPos, height - inByte);

// at the edge of the screen, go back to the beginning:


if (xPos >= width) {
xPos = 0;
background(0);
} else {
// increment the horizontal position:
xPos++;
}
}

void serialEvent (Serial myPort) {


// get the ASCII string:
String inString = myPort.readStringUntil('\n');
if (inString != null) {
// trim off any whitespace:
inString = trim(inString);
// convert to an int and map to the screen height:
inByte = float(inString);
println(inByte);
inByte = map(inByte, 0, 1023, 0, height);
}
}

*/

/* Max/MSP v5 patch for this example

----------begin_max5_patcher----------
1591.3oc0YszbaaCD9r7uBL5RalQUAO3CvdyS5zVen
WZxs5NcfHgjPCIfJIT
RTxj+6AOHkoTDooroUs0AQPR73a+1cwtK3WtZxzEp
OwqlB9YveAlL4KWMYh6
Q1GLo99ISKXeJMmU451zTUQAWpmNy+NM+SZ2y
+sR1l02JuU9t0hJvFlNcMPy
dOuBv.U5Rgb0LPpRpYBooM3529latArTUVvzZdFPts
XAuDrrTU.f.sBffXxL
vGE50lIHkUVJXq3fRtdaoDvjYfbgjujaFJSCzq4.tLaN.b
i1tJefWpqbO0uz
1IjIABoluxrJ1guxh2JfPO2B5zRNyBCLDFcqbwNvuv9f
HCb8bvevyyEU2JKT
YhkBSWPAfq2TZ6YhqmuMUo0feUn+rYpY4YtY+cF
w3lUJdCMYAapZqzwUHX8S
crjAd+SIOU6UBAwIygy.Q1+HAA1KH6EveWOFQlitU
K92ehfal9kFhUxJ3tWc
sgpxadigWExbt1o7Ps5dk3yttivyg20W0VcSmg1G90qtx
92rAZbH4ez.ruy1
nhmaDPidE07J+5n2sg6E6oKXxUSmc20o6E3SPRDbrk
XnPGUYE.i5nCNB9TxQ
jG.G0kCTZtH88f07Rt0ZMMWUw8VvbKVAaTk6Gyor
aPdZff7rQTejBN54lgyv
HE0Ft7AvIvvgvIwO23jBdUkYOuSvIFSiNcjFhiSsUBw
sUCh1AgfNSBAeNDBZ
DIDqY.f8.YjfjV1HAn9XDTxyNFYatVTkKx3kcK9Gra
ZpI5jv7GOx+Z37Xh82
LSKHIDmDXaESoXRngIZQDKVkpxUkMCyXCQhcC
K1z.G457gi3TzMz4RFD515F
G3bIQQwcP3SOF0zlkGhiCBQ1kOHHFFlXaEBQIQnC
wv9QF1LxPZ.A4jR5cyQs
vbvHMJsLll01We+rE2LazX6zYmCraRrsPFwKg1ANB
ZFY.IAihr8Ox.aH0oAL
hB8nQVw0FSJiZeunOykbT6t3r.NP8.iL+bnwNiXuVM
NJH9H9YCm89CFXPBER
bz422p8.O4dg6kRxdyjDqRwMIHTbT3QFLskxJ8tbmQ
K4tm0XGeZWF7wKKtYY
aTAF.XPNFaaQBinQMJ4QLF0aNHF0JtYuHSxoUZfZ
Y6.UU2ejJTb8lQw8Fo5k
Rv6e2PI+fOM71o2ecY1VgTYdCSxxUqLokuYq9jYJi6l
xPgD2NIPePLB0mwbG
YA9Rgxdiu1k5xiLlSU6JVnx6wzg3sYHwTesB8Z5D7Ri
GZpXyvDNJY.DQX3.H
hvmcUN4bP1yCkhpTle2P37jtBsKrLWcMScEmltOPv2
2ZfAqQAdKr9HzATQwZ
q18PrUGt6Tst2XMCRUfGuhXs6ccn23YloomMqcTiC5
iMGPsHsHRWhWFlaenV
XcqwgCQiGGJzptyS2ZMODBz6fGza0bzmXBj7+DA9
4bvpR01MffAlueO7HwcI
pWCwmzJdvi9ILgflLAFmyXB6O7ML0YbD26lenmcG
xjVsZUN+A6pUK7AtTrPg
M+eRYG0qD9j4I7eEbco8Xh6WcO.or9XDC6UCiewbX
Hkh6xm5LiPEkzpJDRTu
mEB44Fgz4NCtJvX.SM1vo2SlTCZGAe7GZu6ahdRyz
FOhYZ+mbVVSYptBw.K1
tboIkatIA7c1cTKD1u.honLYV04VkluHsXe0szv9pQCE
9Ro3jaVB1o15pz2X
zYoBvO5KXCAe0LCYJybE8ZODf4fV8t9qW0zYxq.Y
JfTosj1bv0xc.SaC0+AV
9V9L.KKyV3SyTcRtmzi6rO.O16USvts4B5xe9EymDve
bK0eMfW6+NIsNlE2m
eqRyJ0utRq13+RjmqYKN1e.4d61jjdsauXe3.2p6jgi9hs
NIv97CoyJ01xzl
c3ZhUCtSHx3UZgjoEJYqNY+hYs5zZQVFW19L3JDY
aTlMLqAAt1G2yXlnFg9a
53L1FJVcv.cOX0dh7mCVGCLce7GFcQwDdH5Ta3ny
AS0pQbHxegr+tGIZORgM
RnMj5vGl1Fs16drnk7Tf1XOLgv1n0d2iEsCxR.eQsNO
Z4FGF7whofgfI3kES
1kCeOX5L2rifbdu0A9ae2X.V33B1Z+.Bj1FrP5iFrCYC
G5EUWSG.hhunHJd.
HJ5hhnng3h9HPj4lud02.1bxGw.
-----------end_max5_patcher-----------

*/
104) Robotic Arm Control Using Bluetooth Arduino
and Android App
COMPONENTS AND SUPPLIES
Adafruit ROBOTIC ARM
× 1

HC-05 Bluetooth Module


× 1

L293D MOTOR DRIVERS


× 5

Arduino Mega 2560 & Genuino


Mega 2560
× 1

DC motor (generic)
× 2

BASE AS CAR CHASIS


× 1

9V battery (generic)
× 3
APPS AND ONLINE SERVICES

LOVELY ROBOTIC ARM

Arduino IDE

ABOUT THIS PROJECT

Operating robotic arm with wireless Bluetooth


connection from Android app.
Connections:
Connect:
pin 2,3 to wheel left motor
pin 4,5 to wheel right motor
pin 6,7 to gripper hand motor for holding and
dropping
pin 8,9 to joint 2 motor
pin 10,11, to joint 3 motor
Pin 12,13 to joint 4 motor
Pin 14,15 to joint 5 motor
HC-05 rx to tx of Arduino
HC-05 tx to rx of Arduino
HC-05 vcc to 5v of Arduino
HC-05 gnd to gnd of Arduino
SCHEMATICS

CODE
int inByte;
void setup()
{
Serial.begin(9600);
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);
pinMode(14, OUTPUT);
pinMode(15, OUTPUT);

}
void loop()
{
if (Serial.available() > 0)
{
inByte = Serial.read();
switch (inByte)
{
case '1':
digitalWrite(2, LOW);
digitalWrite(3, HIGH);
digitalWrite(4, LOW);
digitalWrite(5, HIGH);
Serial.println("FRONT");
break;
case '2':
digitalWrite(2, HIGH);
digitalWrite(3, LOW);
digitalWrite(4, HIGH);
digitalWrite(5, LOW);
Serial.println("BACK");
break;
case '3':
digitalWrite(2, LOW);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
digitalWrite(5, HIGH);
Serial.println("LEFT");
break;
case '4':
digitalWrite(2, LOW);
digitalWrite(3, HIGH);
digitalWrite(4, LOW);
digitalWrite(5, LOW);
Serial.println("RIGHT");
break;
case '5':
digitalWrite(2, LOW);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
digitalWrite(5, LOW);
Serial.println("STOP");
break;
case 'A':
digitalWrite(6, LOW);
digitalWrite(7, HIGH);
Serial.println("JOINT 1 CLOCK");
delay(200);
digitalWrite(6, LOW);
digitalWrite(7, LOW);
break;
case 'B':
digitalWrite(6, HIGH );
digitalWrite(7, LOW);
Serial.println("JOINT 1 ANTICLOCK");
delay(200);
digitalWrite(6, LOW);
digitalWrite(7, LOW);
break;
case 'C':
digitalWrite(8, LOW);
digitalWrite(9, HIGH);
Serial.println("JOINT 2 CLOCK");
delay(200);
digitalWrite(8, LOW);
digitalWrite(9, LOW);
break;
case 'D':
digitalWrite(8, HIGH);
digitalWrite(9, LOW);
Serial.println("JOINT 2 ANTICLOCK");
delay(200);
digitalWrite(8, LOW);
digitalWrite(9, LOW);
break;
case 'E':
digitalWrite(10, LOW);
digitalWrite(11, HIGH);
Serial.println("JOINT 3 CLOCK");
delay(200);
digitalWrite(10, LOW);
digitalWrite(11, LOW);
break;
case 'F':
digitalWrite(10, HIGH);
digitalWrite(11, LOW);
Serial.println("JOINT 3 ANTICLOCK");
delay(200);
digitalWrite(10, LOW);
digitalWrite(11, LOW);
break;
case 'G':
digitalWrite(12, LOW);
digitalWrite(13, HIGH);
Serial.println("JOINT 4 CLOCK");
delay(200);
digitalWrite(12, LOW);
digitalWrite(13, LOW);
break;
case 'H':
digitalWrite(12, HIGH);
digitalWrite(13, LOW);
Serial.println("JOINT 4 ANTICLOCK");
delay(200);
digitalWrite(12, LOW);
digitalWrite(13, LOW);
break;
case 'I':
digitalWrite(14, LOW);
digitalWrite(15, HIGH);
Serial.println("JOINT 5 CLOCK");
delay(200);
digitalWrite(14, LOW);
digitalWrite(15, LOW);
break;
case 'J':
digitalWrite(14, HIGH);
digitalWrite(15, LOW);
Serial.println("JOINT 5 ANTICLOCK");
delay(200);
digitalWrite(14, LOW);
digitalWrite(15, LOW);
break;
}
}}
105) Arduino Atari Joystick Linking for Robotics
Control

COMPONENTS AND SUPPLIES

Arduino Mega 2560 & Genuino × 1


Mega 2560
Any Arduino based card will
work

Adafruit RGB Backlight LCD -


16x2
× 1
Any type of readable display
device
Analog joystick (Generic)
The Joystick you select must
have Infrared Capabilities, but × 1
you may also use almost any
Infrared remote device.
Solderless Breadboard Full Size
× 2

Jumper wires (generic)


× 1

Resistor 10k ohm × 2


IR receiver (generic)
Be sure to check if you need to
× 1
install an inline resistor. Some
have them built in.
Single Turn Potentiometer- 10k
ohms
× 2
For LCD brightness and
contrast control
9V battery (generic)
× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

For use with robotics control when completed as a


whole project. The joysticks are recovered from a
bygone era of my time, '80s when computers were just
taking off. Anyway, these joysticks are infrared, they
work, and both have different signals, but on the same
timings frequency.
One of them is a master having the reset, next, and
select menu buttons on it. The other does not.
The oldie but goodie joysticks
Now to the usage video. These joysticks send out
some funky monkey types of signals as you will see, I
traced it down to three variables that needed to be
worked out.
Receive the IR signal from one of the joysticks.
Set a slight delay to allow the IR device to
decipher the signal, for these joysticks it was
around 15 to 20 milliseconds.
Await the joysticks "End of Transmission" code.
This set sends out a third IR pulse at the end, and
it is always the same. It is an end of activity
signal of sorts.
SCHEMATICS
CODE
#include <IRremote.h>
#include <LiquidCrystal.h>

int RECV_PIN = 2;
int CONFIRM_PIN = 3;
IRrecv irrecv(RECV_PIN);
decode_results results;
LiquidCrystal lcd(22,23,27,26,25,24);
void setup()
{
pinMode(CONFIRM_PIN, OUTPUT);
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
lcd.begin(16, 2);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" IR Recieve and ");
lcd.setCursor(0, 1);
lcd.print("then output test");
delay(2000);
lcd.clear();
}

void loop() {
digitalWrite(CONFIRM_PIN, LOW);
lcd.setCursor(0, 0);
lcd.print("Ready to Recieve");
lcd.setCursor(0, 1);
lcd.print("Press any button");

if (irrecv.decode(&results)) {
Serial.println(results.value, HEX);
Serial.println(results.value, DEC);
digitalWrite(CONFIRM_PIN, HIGH);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" HEX = ");
lcd.print(results.value, HEX);
lcd.setCursor(0, 1);
lcd.print(" DEC = ");
lcd.print(results.value, DEC);
delay(3000);
irrecv.resume(); // Receive the next value
}
}
106) Arduino LED Temperature Indicator

COMPONENTS AND SUPPLIES


Arduino UNO & Genuino × 1
UNO

LED (generic)
Any color × 3

Temperature Sensor
× 1

Jumper wires (generic)


× 16
ABOUT THIS PROJECT

tep 1: Get Parts

Arduino Uno/Genuino
Breadboard
Jumper wires (generic)
3 220Ω resistors
3 LEDs (any color)
A temperature sensor (mine is an LM35, but
most should work)
Step 2: Put Parts in Place

Follow Picture
Step 3: Wire It Up

Wire Set-up
Wire it up:
>Red LED goes to digital pin 4 through one of the
resistors, and ground
>Green LED goes to digital pin 3 though a resistor,
and ground
>Blue LED goes to digital pin 2 through a resistor,
and ground
>Pin one (the pin on the left) of the temperature sensor
goes to 5v
>Pin two (the pin in the middle) of the temperature
sensor goes to analog pin A2
>pin three (the pin on the right) of the temperature
sensor goes to ground
Step 4 : Put Code

SCHEMATICS

CODE
const int hot = 87; //set hot parameter
const int cold = 75; //set cold parameter
void setup() {
pinMode(A2, INPUT); //sensor
pinMode(2, OUTPUT); //blue
pinMode(3, OUTPUT); //green
pinMode(4, OUTPUT); //red
Serial.begin(9600);
}
void loop() {
int sensor = analogRead(A2);
float voltage = (sensor / 1024.0) * 5.0;
float tempC = (voltage - .5) * 100;
float tempF = (tempC * 1.8) + 32;
Serial.print("temp: ");
Serial.print(tempF);
if (tempF < cold) { //cold
digitalWrite(2, HIGH);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
Serial.println(" It's Cold.");
}
else if (tempF >= hot) { //hot
digitalWrite(2, LOW);
digitalWrite(3, LOW);
digitalWrite(4, HIGH);
Serial.println(" It's Hot.");
}
else { //fine
digitalWrite(2, LOW);
digitalWrite(3, HIGH);
digitalWrite(4, LOW);
Serial.println(" It's Fine.");
}
delay(10);
}
107) Arduino Portable Electronic Sudoku Game

COMPONENTS AND SUPPLIES


Arduino UNO & Genuino UNO
× 1

2.8 inch TFT Touch LCD screen × 1


Li-Po Rechargeable Battery
600mAh 3.7v (30mm x 50mm x
6mm maximum physical × 1
dimensions)

TP4056 Lithium Battery Charger


Board Micro USB × 1

NECESSARY TOOLS AND MACHINES


3D printer with a minimum 160mm x 70mm
x 30mm build capacity
ABOUT THIS PROJECT

Years ago, just for fun, I wrote an excel macro to solve


Sudoku puzzles on a desktop computer. It occurred to
me that this could be incorporated into an Arduino
touchscreen device. The perfect fit for this was an
Arduino Uno and a compatible 2.8-inch TFT
touchscreen shield.
SCHEMATICS
CODE
// Array with following locations: {0 , 1 , 2 3 4, 5, 6, 7, 8,
9,10,11,12, 13 }
// Array with following Structure: {Solved, value , X , Y ,
V1,V2,V3,V4,V5,V6,V7,V8,V9 panel# }

colcoord[9] = { 10, 34, 58, 90, 114, 138, 170, 194, 218 };
rowcoord[9] = { 8, 33, 58, 88, 113, 138, 170, 194, 218 };

int location = 1;

const int sudoku[81][12];

*/
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library
#include <TouchScreen.h>

#define YP A3 // must be an analog pin, use "An" notation!


#define XM A2 // must be an analog pin, use "An" notation!
#define YM 9 // can be a digital pin
#define XP 8 // can be a digital pin

// Revised Touch Callibration numbers


#define TS_MINX 130
#define TS_MINY 88
#define TS_MAXX 915
//#define TS_MAXY 927
#define TS_MAXY 880

// For better pressure precision, we need to know the resistance


// between X+ and X- Use any multimeter to read it
// For the one we're using, its 300 ohms across the X plate
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
// optional
#define LCD_RESET A4

// Assign human-readable names to some common 16-bit color values:


// I had to reverse these colors for my screen
int BLACK = 0x0000;
int RED = 0x001F;
int BLUE = 0xF800;
int GREEN = 0x07E0;
int YELLOW = 0x07FF;
int MAGENTA = 0xF81F;
int CYAN = 0xFFE0;
int WHITE = 0xFFFF;
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD,
LCD_RESET);

#define BOX 78 // Block to clear screen


#define BOXSIZE 80
#define BUTTON 20

boolean debounce = false; // Used to debounce touch screen input

// Array with following Structure: {value , X , Y , Solved }

const byte colcoord[9] = { 10, 34, 58, 90, 114, 138, 170, 194, 218 };
const byte rowcoord[9] = { 8, 33, 58, 88, 113, 138, 170, 194, 218 };

byte location = 1;

byte puzzlenum = 1; // These identifier for 5 puzzles stored in memory

byte sudoku[82][14];

byte touchlocation = 0; // Used to track the array value that the stylis is
closest to in the Sudoku 9x9 framework

int delay1 = 400; // Pause input into screen

byte tempreading = 0;

void setup(void) {
// Serial.begin(9600);
// Serial.println(F("Paint!"));

tft.reset();

uint16_t identifier = tft.readID();


identifier=0x9325;

tft.begin(identifier);
tft.setRotation(1);
tft.fillScreen(BLACK);

// **** Splash Screen

tft.drawRoundRect(0, 0, 320, 240, 20, BLUE);


tft.drawRoundRect(1, 1, 318, 238, 20, BLUE);

byte g = 70;

tft.drawCircle(46, g, 25, GREEN);


tft.fillCircle(46, g, 20, GREEN);
tft.setTextColor(BLACK); tft.setTextSize(3);
tft.setCursor(39, g-10); tft.println("S");

tft.drawCircle(91, g+30, 25, BLUE);


tft.fillCircle(91, g+30, 20, BLUE);
tft.setTextColor(BLACK); tft.setTextSize(3);
tft.setCursor(84, g+20); tft.println("U");

tft.drawCircle(137, g, 25, YELLOW);


tft.fillCircle(137, g, 20, YELLOW);
tft.setTextColor(BLACK); tft.setTextSize(3);
tft.setCursor(130, g-10); tft.println("D");

tft.drawCircle(183, g+30, 25, RED);


tft.fillCircle(183, g+30, 20, RED);
tft.setTextColor(BLACK); tft.setTextSize(3);
tft.setCursor(176, g+20); tft.println("O");

tft.drawCircle(229, g, 25, GREEN);


tft.fillCircle(229, g, 20, GREEN);
tft.setTextColor(BLACK); tft.setTextSize(3);
tft.setCursor(222, g-10); tft.println("K");

tft.drawCircle(274, g+30, 25, YELLOW);


tft.fillCircle(274, g+30, 20, YELLOW);
tft.setTextColor(BLACK); tft.setTextSize(3);
tft.setCursor(267, g+20); tft.println("U");

tft.setTextColor(WHITE); tft.setTextSize(2);
tft.setCursor(25, 170); tft.println("Play, Create, Solve");

tft.setTextColor(GREEN); tft.setTextSize(1);
tft.setCursor(25, 200); tft.println("By TechKiwiGadgets 2019");

delay(4000);

tft.fillScreen(BLACK);

drawscreen(); // Clearscreen and setup Sudoku matrix


resetmatrix(); // Initialize the sudoku matrix by setting all locations to zero
and loading in the coordinates for each touch location
loadpaneldata(); // Load specifc Panel identification Data into the Array for
each of the 81 locations
solvealigndata(); // Sanitize test puzzle data with correct data format

// Test Display by showing all values in the puzzle - White are Solved , Blue
are others

tft.setTextSize(2);

for (byte a = 1; a < 82; a++) {

//Test solve or set condition


if (sudoku[a][1] != 0) {
if (sudoku[a][0] != 0) {
tft.setTextColor(WHITE);
} else {
tft.setTextColor(GREEN); // Set this colour if not a genuine set clue
}
tft.setCursor( sudoku[a][3], sudoku[a][2]);
tft.println(sudoku[a][1]);
}
}
drawbuttons();

pinMode(13, OUTPUT);

// testText();

#define MINPRESSURE 5
#define MAXPRESSURE 1000

// tft.begin(identifier);

void loop()
{

// Read the Touch Screen Locations


digitalWrite(13, HIGH);
TSPoint p = ts.getPoint();
digitalWrite(13, LOW);

// if sharing pins, you'll need to fix the directions of the touchscreen pins
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);

// we have some minimum pressure we consider 'valid'


// pressure of 0 means no pressing!

if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {

/*
Serial.print("X = "); Serial.print(p.x);
Serial.print("\tY = "); Serial.print(p.y);
Serial.print("\tPressure = "); Serial.println(p.z);

*/
// scale from 0->1023 to tft.width
p.x = map(p.x, TS_MINX, TS_MAXX, 0, 240);
p.y = map(p.y, TS_MINY, TS_MAXY, 0, 320); // Original Code

/*
Serial.print("X = "); Serial.print(p.x);
Serial.print("\tY = "); Serial.print(p.y);
Serial.print("\tPressure = "); Serial.println(p.z);
*/

// Calculate the position of the screen touch based on the input values of p.x
and p.y

if ((p.x > 0) && (p.x < 27)) { // Coloumn 1

if ((p.y > 0) && (p.y < 27)) { // Row 1


touchlocation = 1;
}
if ((p.y > 28) && (p.y < 53)) { // Row 2
touchlocation = 2;
}
if ((p.y > 54) && (p.y < 80)) { // Row 3
touchlocation = 3;
}
if ((p.y > 81) && (p.y < 107)) { // Row 4
touchlocation = 4;
}
if ((p.y > 108) && (p.y < 133)) { // Row 5
touchlocation = 5;
}
if ((p.y > 134) && (p.y < 160)) { // Row 6
touchlocation = 6;
}
if ((p.y > 161) && (p.y < 187)) { // Row 7
touchlocation = 7;
}
if ((p.y > 188) && (p.y < 213)) { // Row 8
touchlocation = 8;
}
if ((p.y > 214) && (p.y < 240)) { // Row 9
touchlocation = 9;
}
} else
if ((p.x > 28) && (p.x < 53)) { // Coloumn 2

if ((p.y > 0) && (p.y < 27)) { // Row 1


touchlocation = 10;
}
if ((p.y > 28) && (p.y < 53)) { // Row 2
touchlocation = 11;
}
if ((p.y > 54) && (p.y < 80)) { // Row 3
touchlocation = 12;
}
if ((p.y > 81) && (p.y < 107)) { // Row 4
touchlocation = 13;
}
if ((p.y > 108) && (p.y < 133)) { // Row 5
touchlocation = 14;
}
if ((p.y > 134) && (p.y < 160)) { // Row 6
touchlocation = 15;
}
if ((p.y > 161) && (p.y < 187)) { // Row 7
touchlocation = 16;
}
if ((p.y > 188) && (p.y < 213)) { // Row 8
touchlocation = 17;
}
if ((p.y > 214) && (p.y < 240)) { // Row 9
touchlocation = 18;
}
} else
if ((p.x > 54) && (p.x < 80)) { // Coloumn 3

if ((p.y > 0) && (p.y < 27)) { // Row 1


touchlocation = 19;
}
if ((p.y > 28) && (p.y < 53)) { // Row 2
touchlocation = 20;
}
if ((p.y > 54) && (p.y < 80)) { // Row 3
touchlocation = 21;
}
if ((p.y > 81) && (p.y < 107)) { // Row 4
touchlocation = 22;
}
if ((p.y > 108) && (p.y < 133)) { // Row 5
touchlocation = 23;
}
if ((p.y > 134) && (p.y < 160)) { // Row 6
touchlocation = 24;
}
if ((p.y > 161) && (p.y < 187)) { // Row 7
touchlocation = 25;
}
if ((p.y > 188) && (p.y < 213)) { // Row 8
touchlocation = 26;
}
if ((p.y > 214) && (p.y < 240)) { // Row 9
touchlocation = 27;
}

} else
if ((p.x > 81) && (p.x < 107)) { // Coloumn 4

if ((p.y > 0) && (p.y < 27)) { // Row 1


touchlocation = 28;
}
if ((p.y > 28) && (p.y < 53)) { // Row 2
touchlocation = 29;
}
if ((p.y > 54) && (p.y < 80)) { // Row 3
touchlocation = 30;
}
if ((p.y > 81) && (p.y < 107)) { // Row 4
touchlocation = 31;
}
if ((p.y > 108) && (p.y < 133)) { // Row 5
touchlocation = 32;
}
if ((p.y > 134) && (p.y < 160)) { // Row 6
touchlocation = 33;
}
if ((p.y > 161) && (p.y < 187)) { // Row 7
touchlocation = 34;
}
if ((p.y > 188) && (p.y < 213)) { // Row 8
touchlocation = 35;
}
if ((p.y > 214) && (p.y < 240)) { // Row 9
touchlocation = 36;
}

} else
if ((p.x > 108) && (p.x < 133)) { // Coloumn 5

if ((p.y > 0) && (p.y < 27)) { // Row 1


touchlocation = 37;
}
if ((p.y > 28) && (p.y < 53)) { // Row 2
touchlocation = 38;
}
if ((p.y > 54) && (p.y < 80)) { // Row 3
touchlocation = 39;
}
if ((p.y > 81) && (p.y < 107)) { // Row 4
touchlocation = 40;
}
if ((p.y > 108) && (p.y < 133)) { // Row 5
touchlocation = 41;
}
if ((p.y > 134) && (p.y < 160)) { // Row 6
touchlocation = 42;
}
if ((p.y > 161) && (p.y < 187)) { // Row 7
touchlocation = 43;
}
if ((p.y > 188) && (p.y < 213)) { // Row 8
touchlocation = 44;
}
if ((p.y > 214) && (p.y < 240)) { // Row 9
touchlocation = 45;
}

} else
if ((p.x > 134) && (p.x < 160)) { // Coloumn 6

if ((p.y > 0) && (p.y < 27)) { // Row 1


touchlocation = 46;
}
if ((p.y > 28) && (p.y < 53)) { // Row 2
touchlocation = 47;
}
if ((p.y > 54) && (p.y < 80)) { // Row 3
touchlocation = 48;
}
if ((p.y > 81) && (p.y < 107)) { // Row 4
touchlocation = 49;
}
if ((p.y > 108) && (p.y < 133)) { // Row 5
touchlocation = 50;
}
if ((p.y > 134) && (p.y < 160)) { // Row 6
touchlocation = 51;
}
if ((p.y > 161) && (p.y < 187)) { // Row 7
touchlocation = 52;
}
if ((p.y > 188) && (p.y < 213)) { // Row 8
touchlocation = 53;
}
if ((p.y > 214) && (p.y < 240)) { // Row 9
touchlocation = 54;
}

} else
if ((p.x > 161) && (p.x < 187)) { // Coloumn 7

if ((p.y > 0) && (p.y < 27)) { // Row 1


touchlocation = 55;
}
if ((p.y > 28) && (p.y < 53)) { // Row 2
touchlocation = 56;
}
if ((p.y > 54) && (p.y < 80)) { // Row 3
touchlocation = 57;
}
if ((p.y > 81) && (p.y < 107)) { // Row 4
touchlocation = 58;
}
if ((p.y > 108) && (p.y < 133)) { // Row 5
touchlocation = 59;
}
if ((p.y > 134) && (p.y < 160)) { // Row 6
touchlocation = 60;
}
if ((p.y > 161) && (p.y < 187)) { // Row 7
touchlocation = 61;
}
if ((p.y > 188) && (p.y < 213)) { // Row 8
touchlocation = 62;
}
if ((p.y > 214) && (p.y < 240)) { // Row 9
touchlocation = 63;
}

} else
if ((p.x > 188) && (p.x < 213)) { // Coloumn 8

if ((p.y > 0) && (p.y < 27)) { // Row 1


touchlocation = 64;
}
if ((p.y > 28) && (p.y < 53)) { // Row 2
touchlocation = 65;
}
if ((p.y > 54) && (p.y < 80)) { // Row 3
touchlocation = 66;
}
if ((p.y > 81) && (p.y < 107)) { // Row 4
touchlocation = 67;
}
if ((p.y > 108) && (p.y < 133)) { // Row 5
touchlocation = 68;
}
if ((p.y > 134) && (p.y < 160)) { // Row 6
touchlocation = 69;
}
if ((p.y > 161) && (p.y < 187)) { // Row 7
touchlocation = 70;
}
if ((p.y > 188) && (p.y < 213)) { // Row 8
touchlocation = 71;
}
if ((p.y > 214) && (p.y < 240)) { // Row 9
touchlocation = 72;
}
} else
if ((p.x > 214) && (p.x < 240)) { // Coloumn 9

if ((p.y > 0) && (p.y < 27)) { // Row 1


touchlocation = 73;
}
if ((p.y > 28) && (p.y < 53)) { // Row 2
touchlocation = 74;
}
if ((p.y > 54) && (p.y < 80)) { // Row 3
touchlocation = 75;
}
if ((p.y > 81) && (p.y < 107)) { // Row 4
touchlocation = 76;
}
if ((p.y > 108) && (p.y < 133)) { // Row 5
touchlocation = 77;
}
if ((p.y > 134) && (p.y < 160)) { // Row 6
touchlocation = 78;
}
if ((p.y > 161) && (p.y < 187)) { // Row 7
touchlocation = 79;
}
if ((p.y > 188) && (p.y < 213)) { // Row 8
touchlocation = 80;
}
if ((p.y > 214) && (p.y < 240)) { // Row 9
touchlocation = 81;
}

}
// debounce function to remove issue with first touch screen reading
being spurious
if (debounce == false) {
touchlocation = 0;
debounce = true;
}

// This code only applies to stylis activity within the Sudokumatrix


if ( ((p.x < 235)&&(p.y < 230))&& (touchlocation != 0)) {

// tft.fillRect(250, 80, 15, 10, BLACK);

/*
Serial.print("Y = "); Serial.print(p.x);
Serial.print("\tX = "); Serial.print(p.y);
Serial.print("\tLocation = "); Serial.println(touchlocation);
*/

// Calculate the incremental changes to the data array


// Array Structure: {value , X , Y , Solved }

// Only increment if has not been solved, Debounce by checking if this


is the second time the same range is selected
if ((tempreading == touchlocation)&&(sudoku[touchlocation][0]==0)||
(tempreading == touchlocation)&&(sudoku[touchlocation][0]==2)) {
sudoku[touchlocation][1]++;
if (sudoku[touchlocation][1] > 9) {
sudoku[touchlocation][1] = 0;
}
// Test to see if changing an item can be classified as solved
if (sudoku[touchlocation][1]!=0) {
sudoku[touchlocation][0]=2; // Set to Solved if a manually changed
number however flag as manual change with va,ue of 2
} else {
sudoku[touchlocation][0]=0; // Set to Not Solved if 0
}
// Finally reset all of the data values in this location that have been
manually changed to unsolved
for (byte u = 1; u < 82; u++) {
// If preprogrammed from a game then leave values otherwise reset data
to baseline
if (sudoku[u][0]!=1){
for (byte q = 4; q < 13; q++) {
sudoku[u][q]=q-3;
}
}
}
}

// tft.setTextColor(WHITE); tft.setTextSize(1);
// tft.setCursor(250, 80); tft.println(touchlocation);

// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[touchlocation][3], sudoku[touchlocation][2], 15, 15,
BLACK);
tft.setTextSize(2);

if (sudoku[touchlocation][0] != 0) { // Do not draw 0 just leave blank


square
if (sudoku[touchlocation][0] == 1) {
tft.setTextColor(WHITE);
} else if (sudoku[touchlocation][0] == 2) {
tft.setTextColor(GREEN); // Set this colour if not a genuine set clue
}
tft.setCursor( sudoku[touchlocation][3], sudoku[touchlocation][2]);
tft.println(sudoku[touchlocation][1]);
}
if (tempreading == touchlocation) {
delay(delay1);
}

tempreading = touchlocation; // take a first sample then repeat and


compare to debounce

// Inside touch sensor reading if statement

// HOME Button Pressed


************************************************
if ( ((p.y > 255)&&(p.y < 300))&& ((p.x > 10)&&(p.x < 40))) {

tft.fillCircle(280, 30, 20, WHITE);


tft.setTextColor(BLACK); tft.setTextSize(1);
tft.setCursor(268, 27); tft.println("HOME");

delay(delay1/2);

drawscreen(); // Clearscreen and setup Sudoku matrix


resetmatrix(); // Initialize the sudoku matrix by setting all locations to
zero:
refreshdisplay();
drawbuttons();
}

// PLAY Button Pressed


************************************************
if ( ((p.y > 255)&&(p.y < 300))&& ((p.x > 80)&&(p.x < 110))) {

//PLAY Button pressed


//Button 2
tft.fillCircle(280, 90, 20, WHITE);
tft.setTextColor(BLACK); tft.setTextSize(1);
tft.setCursor(268, 87); tft.println("PLAY");

delay(delay1/2);

drawscreen(); // Clearscreen and setup Sudoku matrix


resetmatrix(); // Initialize the sudoku matrix by setting all locations to
zero:

loadtestpuzzle1(); // Loads test puzzle into the location array

solvealigndata(); // Sanitize test puzzle data with correct data format

refreshdisplay(); // Only display testpuzzle data locations that are


drawbuttons(); // Redraw buttons togive push button effect
tft.setCursor(277, 97); tft.println(puzzlenum);

// Manage Puzzle Number


puzzlenum++; // increment puzzle number
if (puzzlenum > 5) {
puzzlenum = 1;
}

// HELP Button Pressed


************************************************
if ( ((p.y > 255)&&(p.y < 300))&& ((p.x > 140)&&(p.x < 160))) {

//Button 3
tft.fillCircle(280, 150, 20, WHITE);
tft.setTextColor(BLACK); tft.setTextSize(1);
tft.setCursor(268, 147); tft.println("HELP");

delay(delay1/2);

// drawscreen(); // Clearscreen and setup Sudoku matrix


// solvehorizontal(); // Solve horiontal rule
// solvevertical(); // Solve vertical rule
// solvepanel(); // Solve Panel rule

helpbutton(); // Run algorythm and test for incorrect locations then


highlight in red

// reversesolve();
delay(800);// Display the changes before reverting to original colors

refreshdisplay(); // Only display testpuzzle data locations that are


drawbuttons(); // Redraw buttons togive push button effect
}

// SOLVE Button Pressed


************************************************
if ( ((p.y > 255)&&(p.y < 300))&& ((p.x > 200)&&(p.x < 220))) {

//SOLVE Button Pressed

//Button 4
tft.fillCircle(280, 210, 20, WHITE);
tft.setTextColor(BLACK); tft.setTextSize(1);
tft.setCursor(266, 207); tft.println("SOLVE");
delay(delay1/2);

solvepanel(); // Solve Panel rule


solvehorizontal(); // Solve horiontal rule
solvevertical(); // Solve vertical rule

reversesolvecolor();

uniquecandidate(); // Test
solvealigndata();
reversesolvecolor();

solvehorizontal(); // Solve horiontal rule


solvevertical(); // Solve vertical rule
solvepanel(); // Solve Panel rule
reversesolvecolor();

solvehorizontal(); // Solve horiontal rule


solvevertical(); // Solve vertical rule
solvepanel(); // Solve Panel rule
reversesolvecolor();

solvehorizontal(); // Solve horiontal rule


solvevertical(); // Solve vertical rule
solvepanel(); // Solve Panel rule
reversesolvecolor();

solvehorizontal(); // Solve horiontal rule


solvevertical(); // Solve vertical rule
solvepanel(); // Solve Panel rule
reversesolvecolor();
solvehorizontal(); // Solve horiontal rule
solvevertical(); // Solve vertical rule
solvepanel(); // Solve Panel rule
reversesolvecolor();

solvehorizontal(); // Solve horiontal rule


solvevertical(); // Solve vertical rule
solvepanel(); // Solve Panel rule
reversesolvecolor();

solvehorizontal(); // Solve horiontal rule


solvevertical(); // Solve vertical rule
solvepanel(); // Solve Panel rule
reversesolvecolor();

solvehorizontal(); // Solve horiontal rule


solvevertical(); // Solve vertical rule
solvepanel(); // Solve Panel rule
reversesolvecolor();

solvehorizontal(); // Solve horiontal rule


solvevertical(); // Solve vertical rule
solvepanel(); // Solve Panel rule
reversesolvecolor();

solvehorizontal(); // Solve horiontal rule


solvevertical(); // Solve vertical rule
solvepanel(); // Solve Panel rule
reversesolvecolor();
solvepanel(); // Solve Panel rule
solvehorizontal(); // Solve horiontal rule
solvevertical(); // Solve vertical rule

reversesolvecolor();

uniquecandidate(); // Test
solvealigndata();
reversesolvecolor();

solvepanel(); // Solve Panel rule


solvehorizontal(); // Solve horiontal rule
solvevertical(); // Solve vertical rule

reversesolvecolor();

uniquecandidate(); // Test
solvealigndata();
reversesolvecolor();

solvepanel(); // Solve Panel rule


solvehorizontal(); // Solve horiontal rule
solvevertical(); // Solve vertical rule

reversesolvecolor();

uniquecandidate(); // Test
solvealigndata();
reversesolvecolor();

drawscreen(); // Clearscreen and setup Sudoku matrix

refreshdisplay(); // Only display testpuzzle data locations that are


helpbutton(); // Run algorythm and test for incorrect locations then
highlight in red
drawbuttons(); // Redraw buttons togive push button effect
}

/*
Serial.print("Y = "); Serial.print(p.x);
Serial.print("\tX = "); Serial.println(p.y);
*/
p.z = 0;// Force the sensor value below threshold to avoid ghost values
}

void loadtestpuzzle1(){

// Test Puzzle example 1 loaded into array

if (puzzlenum == 1 ){

// Load Numbers
sudoku[1][1] = 2; sudoku[3][1] = 9; sudoku[19][1] = 3; sudoku[21][1]
= 5;

sudoku[5][1] = 6; sudoku[6][1] = 3; sudoku[14][1] = 2; sudoku[23][1]


= 9;
sudoku[7][1] = 4; sudoku[9][1] = 8; sudoku[26][1] = 7;

sudoku[39][1] = 1; sudoku[46][1] = 9; sudoku[47][1] = 7; sudoku[48]


[1] = 2;

sudoku[31][1] = 9; sudoku[32][1] = 8; sudoku[50][1] = 1; sudoku[51]


[1] = 6;

sudoku[34][1] = 7; sudoku[35][1] = 1; sudoku[36][1] = 6; sudoku[43]


[1] = 2;

sudoku[56][1] = 3; sudoku[73][1] = 5; sudoku[75][1] = 6;

sudoku[59][1] = 7; sudoku[68][1] = 3; sudoku[76][1] = 1; sudoku[77]


[1] = 4;

sudoku[61][1] = 6; sudoku[63][1] = 1; sudoku[79][1] = 8; sudoku[81]


[1] = 7;

// Set the Solved Flag for each


sudoku[1][0] = 1; sudoku[3][0] = 1; sudoku[19][0] = 1; sudoku[21][0]
= 1;

sudoku[5][0] = 1; sudoku[6][0] = 1; sudoku[14][0] = 1; sudoku[23][0]


= 1;

sudoku[7][0] = 1; sudoku[9][0] = 1; sudoku[26][0] = 1;

sudoku[39][0] = 1; sudoku[46][0] = 1; sudoku[47][0] = 1; sudoku[48]


[0] = 1;

sudoku[31][0] = 1; sudoku[32][0] = 1; sudoku[50][0] = 1; sudoku[51]


[0] = 1;

sudoku[34][0] = 1; sudoku[35][0] = 1; sudoku[36][0] = 1; sudoku[43]


[0] = 1;
sudoku[56][0] = 1; sudoku[73][0] = 1; sudoku[75][0] = 1;

sudoku[59][0] = 1; sudoku[68][0] = 1; sudoku[76][0] = 1; sudoku[77]


[0] = 1;

sudoku[61][0] = 1; sudoku[63][0] = 1; sudoku[79][0] = 1; sudoku[81]


[0] = 1;

} else

if (puzzlenum == 2 ){

// Load Numbers
sudoku[1][1] = 4; sudoku[10][1] = 2; sudoku[19][1] = 1;

sudoku[5][1] = 2; sudoku[15][1] = 4; sudoku[24][1] = 5;

sudoku[25][1] = 2; sudoku[17][1] = 8; sudoku[18][1] = 6;

sudoku[29][1] = 3; sudoku[30][1] = 2; sudoku[37][1] = 9; sudoku[39]


[1] = 5; sudoku[46][1] = 7; sudoku[47][1] = 6;

sudoku[31][1] = 6; sudoku[40][1] = 4; sudoku[41][1] = 8; sudoku[42]


[1] = 3; sudoku[51][1] = 2;

sudoku[35][1] = 4; sudoku[36][1] = 1; sudoku[43][1] = 6; sudoku[45]


[1] = 2; sudoku[52][1] = 3; sudoku[53][1] = 5;

sudoku[57][1] = 1; sudoku[64][1] = 3; sudoku[65][1] = 8;

sudoku[58][1] = 7; sudoku[67][1] = 5; sudoku[77][1] = 9;

sudoku[63][1] = 9; sudoku[72][1] = 7; sudoku[81][1] = 5;


// Set the Solved Flag for each
sudoku[1][0] = 1; sudoku[10][0] = 1; sudoku[19][0] = 1;

sudoku[5][0] = 1; sudoku[15][0] = 1; sudoku[24][0] = 1;

sudoku[25][0] = 1; sudoku[17][0] = 1; sudoku[18][0] = 1;

sudoku[29][0] = 1; sudoku[30][0] = 1; sudoku[37][0] = 1; sudoku[39]


[0] = 1; sudoku[46][0] = 1; sudoku[47][0] = 1;

sudoku[31][0] = 1; sudoku[40][0] = 1; sudoku[41][0] = 1; sudoku[42]


[0] = 1; sudoku[51][0] = 1;

sudoku[35][0] = 1; sudoku[36][0] = 1; sudoku[43][0] = 1; sudoku[45]


[0] = 1; sudoku[52][0] = 1; sudoku[53][0] = 1;

sudoku[57][0] = 1; sudoku[64][0] = 1; sudoku[65][0] = 1;

sudoku[58][0] = 1; sudoku[67][0] = 1; sudoku[77][0] = 1;

sudoku[63][0] = 1; sudoku[72][0] = 1; sudoku[81][0] = 1;

} else

if (puzzlenum == 3 ){

// Load Numbers
sudoku[12][1] = 8; sudoku[19][1] = 4;

sudoku[5][1] = 2; sudoku[13][1] = 9; sudoku[14][1] = 4; sudoku[22][1]


= 7; sudoku[24][1] = 8;

sudoku[7][1] = 8; sudoku[9][1] = 7; sudoku[25][1] = 2; sudoku[27][1]


= 9;
sudoku[28][1] = 1; sudoku[29][1] = 2; sudoku[38][1] = 4; sudoku[39]
[1] = 3; sudoku[30][1] = 7;

sudoku[31][1] = 5; sudoku[41][1] = 8; sudoku[51][1] = 7;

sudoku[43][1] = 5; sudoku[44][1] = 7; sudoku[52][1] = 9; sudoku[53]


[1] = 2; sudoku[54][1] = 4;

sudoku[55][1] = 8; sudoku[57][1] = 9; sudoku[73][1] = 6; sudoku[75]


[1] = 4;

sudoku[58][1] = 1; sudoku[60][1] = 2; sudoku[68][1] = 6; sudoku[69]


[1] = 9; sudoku[77][1] = 3;

sudoku[70][1] = 1; sudoku[63][1] = 3;

// Set the Solved Flag for each


sudoku[12][0] = 1; sudoku[19][0] = 1;

sudoku[5][0] = 1; sudoku[13][0] = 1; sudoku[14][0] = 1; sudoku[22][0]


= 1; sudoku[24][0] = 1;

sudoku[7][0] = 1; sudoku[9][0] = 1; sudoku[25][0] = 1; sudoku[27][0]


= 1;

sudoku[28][0] = 1; sudoku[29][0] = 1; sudoku[38][0] = 1; sudoku[39]


[0] = 1; sudoku[30][0] = 1;

sudoku[31][0] = 1; sudoku[41][0] = 1; sudoku[51][0] = 1;

sudoku[43][0] = 1; sudoku[44][0] = 1; sudoku[52][0] = 1; sudoku[53]


[0] = 1; sudoku[54][0] = 1;
sudoku[55][0] = 1; sudoku[57][0] = 1; sudoku[73][0] = 1; sudoku[75]
[0] = 1;

sudoku[58][0] = 1; sudoku[60][0] = 1; sudoku[68][0] = 1; sudoku[69]


[0] = 1; sudoku[77][0] = 1;

sudoku[70][0] = 1; sudoku[63][0] = 1;

} else

if (puzzlenum == 4 ){

// Load Numbers
sudoku[3][1] = 6; sudoku[12][1] = 2;

sudoku[5][1] = 7; sudoku[6][1] = 9; sudoku[13][1] = 1;

sudoku[16][1] = 6; sudoku[17][1] = 5; sudoku[18][1] = 4; sudoku[25]


[1] = 7; sudoku[26][1] = 1;

sudoku[29][1] = 6; sudoku[30][1] = 5; sudoku[37][1] = 8; sudoku[46]


[1] = 1; sudoku[48][1] = 3;

sudoku[33][1] = 4; sudoku[40][1] = 7; sudoku[41][1] = 2; sudoku[42]


[1] = 5; sudoku[49][1] = 8;

sudoku[34][1] = 9; sudoku[36][1] = 8; sudoku[45][1] = 3; sudoku[52]


[1] = 4; sudoku[53][1] = 7;

sudoku[56][1] = 3; sudoku[57][1] = 7; sudoku[64][1] = 6; sudoku[65]


[1] = 4;sudoku[66][1] = 1;

sudoku[76][1] = 6; sudoku[77][1] = 4; sudoku[69][1] = 3;


sudoku[70][1] = 8; sudoku[79][1] = 5;

// Set the Solved Flag for each


sudoku[3][0] = 1; sudoku[12][0] = 1;

sudoku[5][0] = 1; sudoku[6][0] = 1; sudoku[13][0] = 1;

sudoku[16][0] = 1; sudoku[17][0] = 1; sudoku[18][0] = 1; sudoku[25]


[0] = 1; sudoku[26][0] = 1;

sudoku[29][0] = 1; sudoku[30][0] = 1; sudoku[37][0] = 1; sudoku[46]


[0] = 1; sudoku[48][0] = 1;

sudoku[33][0] = 1; sudoku[40][0] = 1; sudoku[41][0] = 1; sudoku[42]


[0] = 1; sudoku[49][0] = 1;

sudoku[34][0] = 1; sudoku[36][0] = 1; sudoku[45][0] = 1; sudoku[52]


[0] = 1; sudoku[53][0] = 1;

sudoku[56][0] = 1; sudoku[57][0] = 1; sudoku[64][0] = 1; sudoku[65]


[0] = 1;sudoku[66][0] = 1;

sudoku[76][0] = 1; sudoku[77][0] = 1; sudoku[69][0] = 1;

sudoku[70][0] = 1; sudoku[79][0] = 1;

} else

if (puzzlenum == 5 ){

// Load Numbers
sudoku[2][1] = 3; sudoku[3][1] = 2; sudoku[12][1] = 6; sudoku[21][1]
= 9;
sudoku[4][1] = 9; sudoku[5][1] = 8; sudoku[22][1] = 2;

sudoku[17][1] = 3; sudoku[27][1] = 7;

sudoku[30][1] = 7; sudoku[47][1] = 9;

sudoku[31][1] = 1; sudoku[40][1] = 3; sudoku[42][1] = 5; sudoku[51]


[1] = 4;

sudoku[35][1] = 5; sudoku[52][1] = 6;

sudoku[55][1] = 2; sudoku[65][1] = 6;

sudoku[60][1] = 9; sudoku[77][1] = 5; sudoku[78][1] = 3;

sudoku[61][1] = 3; sudoku[70][1] = 7; sudoku[79][1] = 2; sudoku[80]


[1] = 6;

// Set the Solved Flag for each


sudoku[2][0] = 1; sudoku[3][0] = 1; sudoku[12][0] = 1; sudoku[21][0]
= 1;

sudoku[4][0] = 1; sudoku[5][0] = 1; sudoku[22][0] = 1;

sudoku[17][0] = 1; sudoku[27][0] = 1;

sudoku[30][0] = 1; sudoku[47][0] = 1;

sudoku[31][0] = 1; sudoku[40][0] = 1; sudoku[42][0] = 1; sudoku[51]


[0] = 1;

sudoku[35][0] = 1; sudoku[52][0] = 1;
sudoku[55][0] = 1; sudoku[65][0] = 1;

sudoku[60][0] = 1; sudoku[77][0] = 1; sudoku[78][0] = 1;

sudoku[61][0] = 1; sudoku[70][0] = 1; sudoku[79][0] = 1; sudoku[80]


[0] = 1;

}
void refreshdisplay() { //Refresh the display once a value has changed

tft.setTextSize(2);

for (byte a = 1; a < 82; a++) {

//Test solve or set condition


if (sudoku[a][1] != 0) {

//First Clear Location


tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);

if (sudoku[a][0] != 0) { // Do not draw 0 just leave blank square


if (sudoku[a][0] == 1) {
tft.setTextColor(WHITE);
} else if (sudoku[a][0] == 2) {
tft.setTextColor(GREEN); // Set this colour if not a genuine set clue
}
tft.setCursor( sudoku[a][3], sudoku[a][2]);
tft.println(sudoku[a][1]);
}

}
}

void drawscreen(){

// tft.fillScreen(BLACK);

// Setup Screen
GREEN = 0x07E0;

tft.fillRect(1, 1, 239, 239, BLACK);

tft.drawRect(0, 0, BOXSIZE, BOXSIZE, WHITE);


tft.drawRect(0+BOXSIZE, 0, BOXSIZE, BOXSIZE, WHITE);
tft.drawRect(0+BOXSIZE+BOXSIZE, 0, BOXSIZE, BOXSIZE,
WHITE);

tft.drawRect(0, BOXSIZE, BOXSIZE, BOXSIZE, WHITE);


tft.drawRect(0+BOXSIZE, BOXSIZE, BOXSIZE, BOXSIZE, WHITE);
tft.drawRect(0+BOXSIZE+BOXSIZE, BOXSIZE, BOXSIZE,
BOXSIZE, WHITE);

tft.drawRect(0, BOXSIZE*2, BOXSIZE, BOXSIZE, WHITE);


tft.drawRect(0+BOXSIZE, BOXSIZE*2, BOXSIZE, BOXSIZE,
WHITE);
tft.drawRect(0+BOXSIZE+BOXSIZE, BOXSIZE*2, BOXSIZE,
BOXSIZE, WHITE);

void resetmatrix(){ // Initialize the sudoku matrix by setting all


locations to zero and loading in the coordinates for each touch location
byte hole = 1;
for (byte a = 0; a < 9; a++) {
for (byte b = 0; b < 9; b++) {
sudoku[hole][0] = 0; // Solve Flag
sudoku[hole][1] = 0; // Display Value
sudoku[hole][2] = colcoord[a]; // Matrix Column coordinate
sudoku[hole][3] = rowcoord[b]; // Matrix Row coordinate
sudoku[hole][4] = 1; // V1
sudoku[hole][5] = 2; // V2
sudoku[hole][6] = 3; // V3
sudoku[hole][7] = 4; // V4
sudoku[hole][8] = 5; // V5
sudoku[hole][9] = 6; // V6
sudoku[hole][10] = 7; // V7
sudoku[hole][11] = 8; // V8
sudoku[hole][12] = 9; // V9
hole++;
}
}
}

void drawbuttons() {
// Setup Buttons
GREEN = 0x07E0;

//Button 1
tft.drawCircle(280, 30, 24, GREEN);
tft.fillCircle(280, 30, 20, GREEN);
tft.setTextColor(BLACK); tft.setTextSize(1);
tft.setCursor(268, 27); tft.println("HOME");

//Button 2
tft.drawCircle(280, 90, 24, YELLOW);
tft.fillCircle(280, 90, 20, YELLOW);
tft.setTextColor(BLACK); tft.setTextSize(1);
tft.setCursor(268, 87); tft.println("PLAY");

//Button 3
tft.drawCircle(280, 150, 24, MAGENTA);
tft.fillCircle(280, 150, 20, MAGENTA);
tft.setTextColor(BLACK); tft.setTextSize(1);
tft.setCursor(268, 147); tft.println("HELP");

//Button 4
tft.drawCircle(280, 210, 24, BLUE);
tft.fillCircle(280, 210, 20, BLUE);
tft.setTextColor(BLACK); tft.setTextSize(1);
tft.setCursor(266, 207); tft.println("SOLVE");

void solvealigndata(){ // Once a location is marked as solved then all


data in that location nees to be set to Zero

for (byte a = 1; a < 82; a++) { // Cycle through all locations

if (sudoku[a][0] > 0) { // If location solved then zero out all data in


array except correct value

/*
Serial.print(a); Serial.print(" ");

Serial.print(sudoku[a][1]); Serial.print(" ");

Serial.print(3+sudoku[a][1]); Serial.print(" ");

Serial.print(sudoku[a][4]);

Serial.print(sudoku[a][5]);

Serial.print(sudoku[a][6]);

Serial.print(sudoku[a][7]);

Serial.print(sudoku[a][8]);

Serial.print(sudoku[a][9]);

Serial.print(sudoku[a][10]);
Serial.print(sudoku[a][11]);

Serial.println(sudoku[a][12]);

*/

sudoku[a][4] = 0; // V1
sudoku[a][5] = 0; // V2
sudoku[a][6] = 0; // V3
sudoku[a][7] = 0; // V4
sudoku[a][8] = 0; // V5
sudoku[a][9] = 0; // V6
sudoku[a][10] = 0; // V7
sudoku[a][11] = 0; // V8
sudoku[a][12] = 0; // V9

// Now poke the answer into the correct location


sudoku[a][(sudoku[a][1]+3)] = sudoku[a][1]; // Load the solved value
into the array

/*
Serial.print(a); Serial.print(" ");

Serial.print(sudoku[a][1]); Serial.print(" ");

Serial.print(3+sudoku[a][1]); Serial.print(" ");

Serial.print(sudoku[a][4]);

Serial.print(sudoku[a][5]);

Serial.print(sudoku[a][6]);

Serial.print(sudoku[a][7]);

Serial.print(sudoku[a][8]);
Serial.print(sudoku[a][9]);

Serial.print(sudoku[a][10]);

Serial.print(sudoku[a][11]);

Serial.println(sudoku[a][12]);

*/

}
}

void reversesolve(){ // subroutine to reverse engineer solved locations


in the matrix and label themas solved
byte tempcount = 0;
for (byte a = 1; a < 82; a++) { // Cycle through all locations

/*
Serial.print(a); Serial.print(" ");

Serial.print(sudoku[a][0]); Serial.print(" ");

// Serial.print(3+sudoku[a][1]); Serial.print(" ");

Serial.print(sudoku[a][4]);

Serial.print(sudoku[a][5]);

Serial.print(sudoku[a][6]);

Serial.print(sudoku[a][7]);
Serial.print(sudoku[a][8]);

Serial.print(sudoku[a][9]);

Serial.print(sudoku[a][10]);

Serial.print(sudoku[a][11]);

Serial.println(sudoku[a][12]);

*/

if (sudoku[a][0] == 0) { // Ignore location if already solved

// Read each and count the number that have been elimated
tempcount = 0;
for (byte b = 4; b < 13; b++) {
if (sudoku[a][b] == 0) {// If equal to 0 then count
tempcount++;
}
}

if (tempcount == 8){ // If only one valid result then find again then
mark location as solved
for (byte c = 4; c < 13; c++) { // Read each and identify the only
solution
if (sudoku[a][c] > 0) {
sudoku[a][0] = 1; // Set Solved Location Flag
sudoku[a][1] = sudoku[a][c]; // Set value
}
}
}
}

/*
Serial.print(a); Serial.print(" ");
Serial.print(sudoku[a][0]); Serial.print(" ");

Serial.print(tempcount); Serial.print(" ");

Serial.print(sudoku[a][4]);

Serial.print(sudoku[a][5]);

Serial.print(sudoku[a][6]);

Serial.print(sudoku[a][7]);

Serial.print(sudoku[a][8]);

Serial.print(sudoku[a][9]);

Serial.print(sudoku[a][10]);

Serial.print(sudoku[a][11]);

Serial.println(sudoku[a][12]);

*/
}
}

void reversesolvecolor(){ // subroutine to reverse engineer solved


locations in the matrix and label themas solved
byte tempcount = 0;
for (byte a = 1; a < 82; a++) { // Cycle through all locations

/*
Serial.print(a); Serial.print(" ");

Serial.print(sudoku[a][0]); Serial.print(" ");


// Serial.print(3+sudoku[a][1]); Serial.print(" ");

Serial.print(sudoku[a][4]);

Serial.print(sudoku[a][5]);

Serial.print(sudoku[a][6]);

Serial.print(sudoku[a][7]);

Serial.print(sudoku[a][8]);

Serial.print(sudoku[a][9]);

Serial.print(sudoku[a][10]);

Serial.print(sudoku[a][11]);

Serial.println(sudoku[a][12]);

*/

if (sudoku[a][0] == 0) { // Ignore location if already solved

// Read each and count the number that have been elimated
tempcount = 0;
for (byte b = 4; b < 13; b++) {
if (sudoku[a][b] == 0) {// If equal to 0 then count
tempcount++;
}
}

if (tempcount == 8){ // If only one valid result then find again then
mark location as solved
for (byte c = 4; c < 13; c++) { // Read each and identify the only
solution
if (sudoku[a][c] > 0) {
sudoku[a][0] = 2; // Set Solved Location Flag
sudoku[a][1] = sudoku[a][c]; // Set value
}
}
}
}

/*
Serial.print(a); Serial.print(" ");

Serial.print(sudoku[a][0]); Serial.print(" ");

Serial.print(tempcount); Serial.print(" ");

Serial.print(sudoku[a][4]);

Serial.print(sudoku[a][5]);

Serial.print(sudoku[a][6]);

Serial.print(sudoku[a][7]);

Serial.print(sudoku[a][8]);

Serial.print(sudoku[a][9]);

Serial.print(sudoku[a][10]);

Serial.print(sudoku[a][11]);

Serial.println(sudoku[a][12]);

*/
}
}
void solvehorizontal(){ // Take Solved locations and apply horizontal
rule
// Cycle through all locations and using solved flag remove all associate
horizontal possibilities

/*
for (byte d = 1; d < 82; d++) { // Cycle through all locations
Serial.print(d); Serial.print(" ");

Serial.print(sudoku[d][0]); Serial.print(" ");

Serial.print(sudoku[d][4]);

Serial.print(sudoku[d][5]);

Serial.print(sudoku[d][6]);

Serial.print(sudoku[d][7]);

Serial.print(sudoku[d][8]);

Serial.print(sudoku[d][9]);

Serial.print(sudoku[d][10]);

Serial.print(sudoku[d][11]);

Serial.println(sudoku[d][12]);
}
*/
// ROW 1 ************************
// Step through each of ROW locations and delete duplicates of the
Solved location. Ignore the current location you are solving for
for (byte a = 1; a < 10; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved
and delete any occurences that are already in scope of enquiry
for (byte r = 1; r < 10; r++) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}

// ROW 2 ************************
// Step through each of ROW locations and delete duplicates of the
Solved location. Ignore the current location you are solving for
for (byte a = 10; a < 19; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved
and delete any occurences that are already in scope of enquiry
for (byte r = 10; r < 19; r++) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}

// ROW 3 ************************
// Step through each of ROW locations and delete duplicates of the
Solved location. Ignore the current location you are solving for
for (byte a = 19; a < 28; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved
and delete any occurences that are already in scope of enquiry
for (byte r = 19; r < 28; r++) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}

// ROW 4 ************************
// Step through each of ROW locations and delete duplicates of the
Solved location. Ignore the current location you are solving for
for (byte a = 28; a < 37; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved
and delete any occurences that are already in scope of enquiry
for (byte r = 28; r < 37; r++) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}
// ROW 5 ************************
// Step through each of ROW locations and delete duplicates of the
Solved location. Ignore the current location you are solving for
for (byte a = 37; a < 46; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved
and delete any occurences that are already in scope of enquiry
for (byte r = 37; r < 46; r++) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}

// ROW 6 ************************
// Step through each of ROW locations and delete duplicates of the
Solved location. Ignore the current location you are solving for
for (byte a = 46; a < 55; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved
and delete any occurences that are already in scope of enquiry
for (byte r = 46; r < 55; r++) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}
// ROW 7 ************************
// Step through each of ROW locations and delete duplicates of the
Solved location. Ignore the current location you are solving for
for (byte a = 55; a < 64; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved
and delete any occurences that are already in scope of enquiry
for (byte r = 55; r < 64; r++) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}

// ROW 8 ************************
// Step through each of ROW locations and delete duplicates of the
Solved location. Ignore the current location you are solving for
for (byte a = 64; a < 73; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved
and delete any occurences that are already in scope of enquiry
for (byte r = 64; r < 73; r++) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}

// ROW 9 ************************
// Step through each of ROW locations and delete duplicates of the
Solved location. Ignore the current location you are solving for
for (byte a = 73; a < 82; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved
and delete any occurences that are already in scope of enquiry
for (byte r = 73; r < 82; r++) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}

/*
for (byte e = 1; e < 82; e++) { // Cycle through all locations
Serial.print(e); Serial.print(" ");

Serial.print(sudoku[e][0]); Serial.print(" ");

Serial.print(sudoku[e][4]);

Serial.print(sudoku[e][5]);

Serial.print(sudoku[e][6]);

Serial.print(sudoku[e][7]);

Serial.print(sudoku[e][8]);

Serial.print(sudoku[e][9]);

Serial.print(sudoku[e][10]);

Serial.print(sudoku[e][11]);

Serial.println(sudoku[e][12]);
}
*/
}

void solvevertical(){ // Take Solved locations and apply horizontal rule


// Cycle through all locations and using solved flag remove all associate
vertical possibilities

/*
for (byte d = 1; d < 82; d++) { // Cycle through all locations
Serial.print(d); Serial.print(" ");

Serial.print(sudoku[d][0]); Serial.print(" ");

Serial.print(sudoku[d][4]);

Serial.print(sudoku[d][5]);

Serial.print(sudoku[d][6]);

Serial.print(sudoku[d][7]);

Serial.print(sudoku[d][8]);

Serial.print(sudoku[d][9]);

Serial.print(sudoku[d][10]);

Serial.print(sudoku[d][11]);

Serial.println(sudoku[d][12]);
}
*/
// COL 1 ************************
// Step through each of Col locations and delete duplicates of the
Solved location. Ignore the current location you are solving for
for (byte a = 1; a < 74; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved
and delete any occurences that are already in scope of enquiry
for (byte r = 1; r < 74; r=r+9) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}

// COL 2 ************************
// Step through each of COL locations and delete duplicates of the
Solved location. Ignore the current location you are solving for
for (byte a = 2; a < 75; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved
and delete any occurences that are already in scope of enquiry
for (byte r = 2; r < 75; r=r+9) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}

// COL 3 ************************
// Step through each of COL locations and delete duplicates of the
Solved location. Ignore the current location you are solving for
for (byte a = 3; a < 76; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved
and delete any occurences that are already in scope of enquiry
for (byte r = 3; r < 76; r=r+9) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}

// COL 4 ************************
// Step through each of COL locations and delete duplicates of the
Solved location. Ignore the current location you are solving for
for (byte a = 4; a < 77; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved
and delete any occurences that are already in scope of enquiry
for (byte r = 4; r < 77; r=r+9) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}
// COL 5 ************************
// Step through each of COL locations and delete duplicates of the
Solved location. Ignore the current location you are solving for
for (byte a = 5; a < 78; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved
and delete any occurences that are already in scope of enquiry
for (byte r = 5; r < 78; r=r+9) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}

// COL 6 ************************
// Step through each of COL locations and delete duplicates of the
Solved location. Ignore the current location you are solving for
for (byte a = 6; a < 79; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved
and delete any occurences that are already in scope of enquiry
for (byte r = 6; r < 79; r=r+9) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}
// COL 7 ************************
// Step through each of COL locations and delete duplicates of the
Solved location. Ignore the current location you are solving for
for (byte a = 7; a < 80; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved
and delete any occurences that are already in scope of enquiry
for (byte r = 7; r < 80; r=r+9) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}

// COL 8 ************************
// Step through each of COL locations and delete duplicates of the
Solved location. Ignore the current location you are solving for
for (byte a = 8; a < 81; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved
and delete any occurences that are already in scope of enquiry
for (byte r = 8; r < 81; r=r+9) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}

// COL 9 ************************
// Step through each of COL locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 9; a < 82; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 9; r < 83; r=r+9) {
if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}
}
}
}

/*
for (byte e = 1; e < 82; e++) { // Cycle through all locations
Serial.print(e); Serial.print(" ");

Serial.print(sudoku[e][0]); Serial.print(" ");

Serial.print(sudoku[e][4]);

Serial.print(sudoku[e][5]);

Serial.print(sudoku[e][6]);

Serial.print(sudoku[e][7]);

Serial.print(sudoku[e][8]);

Serial.print(sudoku[e][9]);

Serial.print(sudoku[e][10]);

Serial.print(sudoku[e][11]);
Serial.println(sudoku[e][12]);

}
*/
}

void solvepanel(){ // Take Solved locations and apply horizontal rule


// Cycle through all locations and using solved flag remove all associate
panel possibilities

/*

for (byte d = 1; d < 82; d++) { // Cycle through all locations


Serial.print(d); Serial.print(" ");

Serial.print(sudoku[d][0]); Serial.print(" ");


Serial.print(sudoku[d][4]);
Serial.print(sudoku[d][5]);
Serial.print(sudoku[d][6]);
Serial.print(sudoku[d][7]);
Serial.print(sudoku[d][8]);
Serial.print(sudoku[d][9]);
Serial.print(sudoku[d][10]);
Serial.print(sudoku[d][11]);
Serial.println(sudoku[d][12]);
}

*/

// PANEL Algorythm ************************


// Step through each of locations and delete duplicates of the Solved
location using the panel formulae. Ignore the current location you are
solving for
for (byte a = 1; a < 82; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 1; r < 82; r++) { // Step through all locations
if ((sudoku[a][13] == sudoku[r][13]) && (a!=r)) { // Identify the locations
on the Same Panel
if ((sudoku[a][13] == sudoku[r][13]) && (a!=r)) {
sudoku[r][sudoku[a][1]+3] = 0;
}

}
}
}
}

/*

for (byte e = 1; e < 82; e++) { // Cycle through all locations


Serial.print(e); Serial.print(" ");
Serial.print(sudoku[e][0]); Serial.print(" ");
Serial.print(sudoku[e][4]);
Serial.print(sudoku[e][5]);
Serial.print(sudoku[e][6]);
Serial.print(sudoku[e][7]);
Serial.print(sudoku[e][8]);
Serial.print(sudoku[e][9]);
Serial.print(sudoku[e][10]);
Serial.print(sudoku[e][11]);
Serial.println(sudoku[e][12]);
*/

void loadpaneldata(){ // Load specifc Panel identification Data into the


Array for each of the 81 locations
// Load Numbers
// Panel 1
sudoku[1][13] = 1; sudoku[2][13] = 1; sudoku[3][13] = 1;
sudoku[10][13] = 1; sudoku[11][13] = 1; sudoku[12][13] = 1;
sudoku[19][13] = 1; sudoku[20][13] = 1; sudoku[21][13] = 1;
// Panel 2
sudoku[4][13] = 2; sudoku[5][13] = 2; sudoku[6][13] = 2;
sudoku[13][13] = 2; sudoku[14][13] = 2; sudoku[15][13] = 2;
sudoku[22][13] = 2; sudoku[23][13] = 2; sudoku[24][13] = 2;
// Panel 3
sudoku[7][13] = 3; sudoku[8][13] = 3; sudoku[9][13] = 3;
sudoku[16][13] = 3; sudoku[17][13] = 3; sudoku[18][13] = 3;
sudoku[25][13] = 3; sudoku[26][13] = 3; sudoku[27][13] = 3;
// Panel 4
sudoku[28][13] = 4; sudoku[29][13] = 4; sudoku[30][13] = 4;
sudoku[37][13] = 4; sudoku[38][13] = 4; sudoku[39][13] = 4;
sudoku[46][13] = 4; sudoku[47][13] = 4; sudoku[48][13] = 4;
// Panel 5
sudoku[31][13] = 5; sudoku[32][13] = 5; sudoku[33][13] = 5;
sudoku[40][13] = 5; sudoku[41][13] = 5; sudoku[42][13] = 5;
sudoku[49][13] = 5; sudoku[50][13] = 5; sudoku[51][13] = 5;
// Panel 6
sudoku[34][13] = 6; sudoku[35][13] = 6; sudoku[36][13] = 6;
sudoku[43][13] = 6; sudoku[44][13] = 6; sudoku[45][13] = 6;
sudoku[52][13] = 6; sudoku[53][13] = 6; sudoku[54][13] = 6;
// Panel 7
sudoku[55][13] = 7; sudoku[56][13] = 7; sudoku[57][13] = 7;
sudoku[64][13] = 7; sudoku[65][13] = 7; sudoku[66][13] = 7;
sudoku[73][13] = 7; sudoku[74][13] = 7; sudoku[75][13] = 7;
// Panel 8
sudoku[58][13] = 8; sudoku[59][13] = 8; sudoku[60][13] = 8;
sudoku[67][13] = 8; sudoku[68][13] = 8; sudoku[69][13] = 8;
sudoku[76][13] = 8; sudoku[77][13] = 8; sudoku[78][13] = 8;
// Panel 9
sudoku[61][13] = 9; sudoku[62][13] = 9; sudoku[63][13] = 9;
sudoku[70][13] = 9; sudoku[71][13] = 9; sudoku[72][13] = 9;
sudoku[79][13] = 9; sudoku[80][13] = 9; sudoku[81][13] = 9;
}

// Used to identify and highlight errors in a current matrix - use solve


method however instead of solving outcome just highlight conflicts in red
void helpbutton(){

// Horizontal *********************
// ROW 1 ************************
// Step through each of ROW locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 1; a < 10; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 1; r < 10; r++) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}

// ROW 2 ************************
// Step through each of ROW locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 10; a < 19; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 10; r < 19; r++) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}

// ROW 3 ************************
// Step through each of ROW locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 19; a < 28; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 19; r < 28; r++) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}

// ROW 4 ************************
// Step through each of ROW locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 28; a < 37; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 28; r < 37; r++) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}
// ROW 5 ************************
// Step through each of ROW locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 37; a < 46; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 37; r < 46; r++) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}

// ROW 6 ************************
// Step through each of ROW locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 46; a < 55; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 46; r < 55; r++) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}
// ROW 7 ************************
// Step through each of ROW locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 55; a < 64; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 55; r < 64; r++) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}
// ROW 8 ************************
// Step through each of ROW locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 64; a < 73; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 64; r < 73; r++) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}

// ROW 9 ************************
// Step through each of ROW locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 73; a < 82; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 73; r < 82; r++) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}

// Vertical ****************
// COL 1 ************************
// Step through each of Col locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 1; a < 74; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 1; r < 74; r=r+9) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}

// COL 2 ************************
// Step through each of COL locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 2; a < 75; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 2; r < 75; r=r+9) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}

// COL 3 ************************
// Step through each of COL locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 3; a < 76; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 3; r < 76; r=r+9) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}

// COL 4 ************************
// Step through each of COL locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 4; a < 77; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 4; r < 77; r=r+9) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}
// COL 5 ************************
// Step through each of COL locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 5; a < 78; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 5; r < 78; r=r+9) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}

// COL 6 ************************
// Step through each of COL locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 6; a < 79; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 6; r < 79; r=r+9) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}
// COL 7 ************************
// Step through each of COL locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 7; a < 80; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 7; r < 80; r=r+9) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}

// COL 8 ************************
// Step through each of COL locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 8; a < 81; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 8; r < 81; r=r+9) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}

// COL 9 ************************
// Step through each of COL locations and delete duplicates of the Solved
location. Ignore the current location you are solving for
for (byte a = 9; a < 82; a=a+9) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 9; r < 83; r=r+9) {
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}
}
}
}
// Panels *******************

// PANEL Algorythm ************************


// Step through each of locations and delete duplicates of the Solved
location using the Oanel formulae. Ignore the current location you are
solving for
for (byte a = 1; a < 82; a++) { // Cycle through all locations
if (sudoku[a][0] > 0) { // Identify the locations that are already solved and
delete any occurences that are already in scope of enquiry
for (byte r = 1; r < 82; r++) { // Step through all locations
if ((sudoku[a][13] == sudoku[r][13]) && (a!=r)) { // Identify the locations
on the Same Panel
if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a
master value and it is duplicate then color RED
// Refresh only the location concerned with new value and show colour
coded
//First Clear Location
tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
}

}
}
}
}

// Horizontal conflict help function - Step through data and identify


manually changed locations as conflicts in RED. Leave items set at WHITE
as WHITE

// Vertical conflict help function - Step through data and identify manually
changed locations as conflicts in RED. Leave items set at WHITE as
WHITE
// Panel conflict help function - Step through data and identify manually
changed locations as conflicts in RED. Leave items set at WHITE as
WHITE

void uniquecandidate() { // Each panel, row and column on a Sudoku board


must contain every number between 1 and 9.
// Therefore, if a number, say 4, can only be put in a single cell within a
block/column/row, then that number is guaranteed to fit there.

/*

for (byte d = 1; d < 82; d++) { // Cycle through all locations


Serial.print(d); Serial.print(" ");

Serial.print(sudoku[d][0]); Serial.print(" ");


Serial.print(sudoku[d][1]); Serial.print(" ");
Serial.print(sudoku[d][4]);
Serial.print(sudoku[d][5]);
Serial.print(sudoku[d][6]);
Serial.print(sudoku[d][7]);
Serial.print(sudoku[d][8]);
Serial.print(sudoku[d][9]);
Serial.print(sudoku[d][10]);
Serial.print(sudoku[d][11]);
Serial.println(sudoku[d][12]);
}

*/

byte tempcount = 0;

for (byte p = 1; p < 10; p++) { // Cycle through all panels 1 to 9

for (byte v = 1; v < 10; v++) { // Step through all possible unique location
values in each panel
for (byte r = 1; r < 82; r++) { // Step through all locations

if (sudoku[r][13] == p) { //Only operate on those locations that are in this


panel

if (sudoku[r][v+3] == v) {// Count this if value is what we are looking for


tempcount++;
}
}
}
// Check if unique
if ( tempcount == 1) { // This is a unique value so reset the location with
this being a solved location
// Repeat process to locate unique location
for (byte r = 1; r < 82; r++) { // Step through all locations and then mark as
solved

if (sudoku[r][13] == p) { //Only operate on those locations that are in this


panel
if (sudoku[r][v+3] == v) {// Count this if value is what we are looking for

// Now poke the answer into the correct location


if (sudoku[r][0] == 0) { // Change to solved but remain green
sudoku[r][0] = 2;
}
sudoku[r][1] = v;
}
}
}
}
// Reset temp counter
tempcount = 0;
}
}
/*
for (byte d = 1; d < 82; d++) { // Cycle through all locations
Serial.print(d); Serial.print(" ");
Serial.print(sudoku[d][0]); Serial.print(" ");
Serial.print(sudoku[d][1]); Serial.print(" ");
Serial.print(sudoku[d][4]);
Serial.print(sudoku[d][5]);
Serial.print(sudoku[d][6]);
Serial.print(sudoku[d][7]);
Serial.print(sudoku[d][8]);
Serial.print(sudoku[d][9]);
Serial.print(sudoku[d][10]);
Serial.print(sudoku[d][11]);
Serial.println(sudoku[d][12]);
}
*/

108) Arduino DIY Math Solving Alarm Clock Out of


Cardboard
COMPONENTS AND SUPPLIES

Arduino UNO & Genuino UNO


× 1

DFRobot I2C 16x2 Arduino × 1


LCD Display Module
Buzzer
× 1

IR receiver (generic)
× 1

JustBoom IR Remote
× 1

Seeed Pi RTC (DS1307)


× 1

Jumper wires (generic)


× 1

Resistor 10k ohm × 1


APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

This clock only works for the Elegoo remote as shown


below:
Story
Have you ever fallen right back to sleep after snoozing
your alarm clock? That's because you're still bran-
dead when you hit that snooze button. A simple way
to prevent this is to wake your brain up with a simple
math problem.
Earlier this year, I bought the Elegoo Starter Kit UNO
R3 Project with the hope of being able to make some
cool stuff that I once saw like robot or toy car. This is
one of my very first project using Arduino Uno R3
and since I've just started it, the clock itself looks like
crap. But it's still better than nothing, right? Link to
the kit is here.
Libraries
For this little project, there's a few libraries you need
to download and format as you can see below:
https://github.com/z3t0/Arduino-IRremote.
*For the IRremote library, you'll have to go to
boarddefs.h, find the following segment of code:
// Arduino Duemilanove, Diecimila, LilyPad, Mini,
Fio, Nano, etc
// ATmega48, ATmega88, ATmega168, ATmega328
//#define IR_USE_TIMER1 // tx = pin 9
#define IR_USE_TIMER2 // tx = pin 3
and change it to:
// Arduino Duemilanove, Diecimila, LilyPad, Mini,
Fio, Nano, etc
// ATmega48, ATmega88, ATmega168, ATmega328
#define IR_USE_TIMER1 // tx = pin 9
//#define IR_USE_TIMER2 // tx = pin 3
https://github.com/arduino-libraries/LiquidCrystal
https://github.com/adafruit/RTClib
The cardboard box
Choose and cut whatever cardboard that fits your
circuit best. For me, I just cut a random amazon
delivery box, and it works great!

The circuit
Assemble your circuit according to the following
image
To save some place because my goal is making an as
small and compact an alarm clock as possible, I use
the Arduino Prototype Shield v.5 that comes with the
kit I bought. You can choose to use or not to use the
board.
Fits perfectly! :)
Tips
- When compiling the code, don't hit verify (the check
icon) but hit upload (the arrow icon) instead.
- When you upload, if you want the clock to have the
right time on it, then don't unplug it from the computer
or unplug after connect it to external battery.
- If you unplug it and then connect it to the power
source, the time shows is the time when you last
upload it.
Remote Controller
+ ST/REPT: Hit it if you want to set Alarm. If you've
entered "Set hour," hit it again to set minute and again
to set second. Hit it one last time to finish setting up
alarm
+ The red power button: This button is programmed as
a backspace button. Hit it once you've finished setting
alarm and want to change (since this remote is a really
crappy one, hit power button multiple times until the
second line of the LCD indicating the alarm turns off),
or when you're typing the wrong answer for the simple
math problem (hit it until the answer turns into zero)
+ Apart from number buttons, ST/REPT and red
power button, other buttons have no use.

SCHEMATICS
CODE
#include <IRremote.h>
#include <IRremoteInt.h>
#include <LiquidCrystal.h>
#include "RTClib.h"
/**
* Go to boarddefs.h
* // Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, Nano, etc
* #else
* #define IR_USE_TIMER1 tx = pin 9
* //#define IR_USE_TIMER2 // tx = pin 3
*/
#include <stdlib.h>
RTC_DS1307 rtc;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int buzzerPin = 10;
int RECV_PIN = 9;
IRrecv irrecv(RECV_PIN);
decode_results results;
long num[10] = {0xFF6897, 0xFF30CF, 0xFF18E7, 0xFF7A85, 0xFF10EF,
0xFF38C7, 0xFF5AA5, 0xFF42BD, 0xFF4AB5, 0xFF52AD};
int a = 0;
int b = 0;
int c = 0;
int d = 0;
int setAlarm = 0;

void setup() {
lcd.begin(16, 2);
Serial.begin(9600);
irrecv.enableIRIn();
if(rtc.begin()&&rtc.isrunning()){
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
}
void loop() {
DateTime now = rtc.now();
lcd.setCursor(0, 0);
if(now.hour()<10)lcd.print("0");
lcd.print(now.hour());
lcd.print(':');
if(now.minute()<10)lcd.print("0");
lcd.print(now.minute());
lcd.print(':');
if(now.second()<10)lcd.print("0");
lcd.print(now.second());
lcd.print(" ");
getAlarm();
}
void getAlarm(){
int ques1 = rand()%100+1;
int ques2 = rand()%100+1;
int ans = ques1 + ques2;
if (irrecv.decode(&results)){
Serial.println(results.value, HEX);
irrecv.resume();
if(results.value==0xFFB04F){
setAlarm=1;
}else if(results.value==0xFFFFFFFF){
setAlarm = setAlarm;
}
}
if(digitalRead(buzzerPin)==HIGH){
setAlarm=5;
}
while(setAlarm==1){
lcd.setCursor(0,0);
lcd.print("Set Hour");
lcd.setCursor(0,1);
if(irrecv.decode(&results)){
for(int i = 0; i<10; i++){
if(results.value==num[i]){
a = a*10+i;
}else if(results.value==0xFFFFFFFF){
a = a;
}
irrecv.resume();
}
if(a<24){
lcd.print(a);
if(results.value==0xFFB04F){
setAlarm=2;
}
}else{
lcd.clear();
setAlarm = 1;
a=0;
}
}
}
while(setAlarm==2){
lcd.setCursor(0,0);
lcd.print("Set Minute");
lcd.setCursor(0,1);
if(irrecv.decode(&results)){
for(int i = 0; i<10; i++){
if(results.value==num[i]){
b = b*10+i;
}else if(results.value==0xFFFFFFFF){
b = b;
}else if(results.value==0xFFB04F){
setAlarm++;
}
irrecv.resume();
}
lcd.print(a);
lcd.print(':');
if(b<60){
lcd.print(b);
if(results.value==0xFFB04F){
setAlarm=3;
}
}else{
lcd.clear();
setAlarm = 2;
b=0;
}
}
}
while(setAlarm==3){
lcd.setCursor(0,0);
lcd.print("Set Second");
lcd.setCursor(0,1);
if(irrecv.decode(&results)){
for(int i = 0; i<10; i++){
if(results.value==num[i]){
c = c*10+i;
}else if(results.value==0xFFFFFFFF){
c = c;
}else if(results.value==0xFFB04F){
setAlarm++;
}
irrecv.resume();
}
lcd.print(a);
lcd.print(':');
lcd.print(b);
lcd.print(':');
if(c<60){
lcd.print(c);
if(results.value==0xFFB04F){
setAlarm=4;
}
}else{
lcd.clear();
setAlarm = 3;
c=0;
}
}
}
while(setAlarm==4){
lcd.setCursor(0,1);
lcd.print("Alarm-");
if(a<10)lcd.print("0");
lcd.print(a);
lcd.print(':');
if(b<10)lcd.print("0");
lcd.print(b);
lcd.print(':');
if(c<10)lcd.print("0");
lcd.print(c);
if(results.value==0xFFB04F){
setAlarm=0;
}
}
DateTime now = rtc.now();
if(now.hour()==a && now.minute()==b && now.second()==c){
tone(buzzerPin, 100);
a=0;
b=0;
c=0;
}
if(irrecv.decode(&results)){
if(results.value==0xFFA25D){
a=0;
b=0;
c=0;
lcd.setCursor(0,1);
lcd.clear();
}
}
while(setAlarm==5){
lcd.setCursor(0,0);
lcd.print(ques1);
lcd.print('+');
lcd.print(ques2);
lcd.print(" ");
if(irrecv.decode(&results)){
for(int i = 0; i<10; i++){
if(results.value==num[i]){
d = d*10+i;
}else if(results.value==0xFFA25D){
d=0;
lcd.print(" ");
}
irrecv.resume();
}
lcd.print(d);
}
if(d==ans){
noTone(buzzerPin);
setAlarm=0;
lcd.setCursor(0,1);
lcd.clear();
d=0;
}
}
}
109) Arduino Gesture Mouse

COMPONENTS AND SUPPLIES


Arduino Leonardo × 1
GY-521 MPU-6050 3 Axis
Gyroscope + Accelerometer
Module For Arduino × 1

SparkFun Pushbutton switch


12mm
× 1

Breadboard (generic)
× 1

Jumper wires (generic)


× 1

Adafruit Joystick
× 1
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

1. Leonardo:
Arduino Leonardo is an old board but the only
compatible board for this project. It has the required
SCL and SDA pin for connection of MPU6050.
Connections: Connect the 5V and GND to breadboard.
2. Joystick:
Use: We use the joystick as a keyboard. While playing
a game,we use it move the character in front or back
or sideways,etc.
Connections: Connect the GND and 5V in the same
line as that of Leonardo as shown in the schematics.
Connect the VRX to A1 (Analog Pin 1) and VRY to
A0 of Leonardo.
3. MPU6050:
Use: The MPU6050 is a 6 DOF (Degrees of Freedom)
or a six axis IMU sensor, which means that it gives six
values as output. Three values from the accelerometer
and three from the gyroscope. It is basically used as a
mouse.
Connections: Connect the GND and VCC in the
railing as in schematics. Connect the SCL and SDA to
SCL and SDA of Leonardo.
4. Button:
Use: Used as a fire button while playing any game.
Connections: Connect the button pin to Digital Pin 1
and other to GND.
Connect everything according to the schematics.
Upload the code to Leonardo and watch the fun!
Note: To switch on the joystick, press it down once.
SCHEMATICS
CODE
#include <Keyboard.h>
#include <Wire.h>
#include <I2Cdev.h>
#include <MPU6050.h>
#include <Mouse.h>
#define LBUT 7
#define RBUT 5

int xPin = A1;


int yPin = A0;
int buttonPin = 1;

int xPosition = 0;
int yPosition = 0;
int buttonState = 0;
MPU6050 mpu;
int16_t ax, ay, az, gx, gy, gz;

int angleToDistance(int a)
{
if (a < -80)
{
return -40;
}
else if (a < -65) {
return -20;
}
else if (a < -50) {
return -10;
}
else if (a < -15) {
return -5;
}
else if (a < -5) {
return -1;
}
else if (a > 80) {
return 40;
}
else if (a > 65) {
return 20;
}
else if (a > 15) {
return 10;
}
else if (a > 5) {
return 1;
}
}

void setup() {
// initialize serial communications at 9600 bps:
Serial.begin(9600);
Keyboard.begin();
Mouse.begin();

pinMode(xPin, INPUT);
pinMode(yPin, INPUT);

//activate pull-up resistor on the push-button pin


pinMode(buttonPin, INPUT_PULLUP);

// For versions prior to Arduino 1.0.1


// pinMode(buttonPin, INPUT);
// digitalWrite(buttonPin, HIGH);
// put your setup code here, to run once:
pinMode(LBUT, INPUT);
digitalWrite(LBUT, HIGH);
pinMode(RBUT, INPUT);
digitalWrite(RBUT, HIGH);
Wire.begin();
mpu.initialize();
if (!mpu.testConnection()) {
while (1);
}
}
void loop() {
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
int vx = map(ax, -16000, 16000, 90, -90);
int vy = map(ay, -16000, 16000, 90, -90);
attachInterrupt(1, keyboard, CHANGE);
attachInterrupt(7,fire,HIGH);
Mouse.move(angleToDistance(vx), angleToDistance(vy));
if (digitalRead(LBUT) == LOW) {
if (!Mouse.isPressed(MOUSE_LEFT)) {
Mouse.press(MOUSE_LEFT);
}
}
else {
if (Mouse.isPressed(MOUSE_LEFT)) {
Mouse.release(MOUSE_LEFT);
}
}
if (digitalRead(RBUT) == LOW) {
if (!Mouse.isPressed(MOUSE_RIGHT)) {
Mouse.press(MOUSE_RIGHT);
}
}
else {
if (Mouse.isPressed(MOUSE_RIGHT)) {
Mouse.release(MOUSE_RIGHT);
}
}
delay(20);
xPosition = analogRead(xPin);
yPosition = analogRead(yPin);
buttonState = digitalRead(buttonPin);
Serial.print("X: ");
Serial.print(xPosition);

Serial.print(" | Y: ");
Serial.print(yPosition);
Serial.print(" | Button: ");
Serial.println(buttonState);

// delay(100); // add some delay between reads

if (yPosition < 10)


{
Keyboard.releaseAll();
Keyboard.press('w'); //for w
Keyboard.releaseAll();
}
if (yPosition < 700 && yPosition > 600||yPosition>1020)
{
Keyboard.releaseAll();
Keyboard.press('s'); //for s
Keyboard.releaseAll();

if (xPosition < 10)


{

Keyboard.releaseAll();

Keyboard.press('a'); //for a
Keyboard.releaseAll();
}

if (xPosition < 700 && xPosition > 600||xPosition>1020)


{
Keyboard.releaseAll();

Keyboard.press('d'); //for d
Keyboard.releaseAll();
}
}
void keyboard()
{
xPosition = analogRead(xPin);
yPosition = analogRead(yPin);
buttonState = digitalRead(buttonPin);
Serial.print("X: ");
Serial.print(xPosition);

Serial.print(" | Y: ");
Serial.print(yPosition);
Serial.print(" | Button: ");
Serial.println(buttonState);

//delay(100); // add some delay between reads

if (yPosition < 10)


{
Keyboard.releaseAll();
Keyboard.press('w'); //for w
Keyboard.releaseAll();
}
if (yPosition < 700 && yPosition > 600||yPosition>1020)
{
Keyboard.releaseAll();
Keyboard.press('s'); //for s
Keyboard.releaseAll();

if (xPosition < 10)


{

Keyboard.releaseAll();

Keyboard.press('a'); //for a
Keyboard.releaseAll();
}
if (xPosition < 700 && xPosition > 600||xPosition>1020)
{
Keyboard.releaseAll();
Keyboard.press('d'); //for d
Keyboard.releaseAll();

}
}
void fire()
{

}
110) A Power Router to Optimize Homemade
Electricity with Arduino

COMPONENTS AND SUPPLIES


Arduino UNO & Genuino UNO × 1

DFRobot I2C 16x2 Arduino


LCD Display Module
× 1

Pushbutton Switch, Momentary


× 3
NECESSARY TOOLS AND MACHINES
Digilent Mastech MS8217 Autorange
Digital Multimeter
APPS AND ONLINE SERVICES
Arduino IDE

ABOUT THIS PROJECT

Or how to make a Power Router to optimize


homemade electricity consumption and to prevent
against public grid injection.
Are your tired to offer to your electricity grid provider
any surplus of your own electricity you produce?
Would you prefer either to switch on a machine to
consume this surplus, or to switch off a (micro)
invertor so that exceeded energy will only charge
batteries?And so this would be done automatically?
A Power Router is a device that will detect any
injection in public power grid and help to prevent
against it.This manual explains step by step how to
build this device, with an Arduino Uno rev.3.
The device detects the current at the immediate
entrance of the public power grid, and the voltage on
the line.Any injection in the public power grid is
detected by the shift between current and
voltage:When “in same way” we are consuming.
When “in opposite way” we are injecting.
Then the power consumption is calculated and the
Triac is driven by the device in order to prevent any
injection. Parameters allow to fix limit values.
In addition a load shedding is possible that will switch
on or off any device, depending of the consumption.
For instance a SSR can cut off the wind turbine
injection (and then it will charge batteries only) if
consumption is near 0 (near injection in grid) and will
be switched on again once consumption raises the
power delivered by the wind turbine invertor.
SCHEMATICS
CODE
/*

A Power Router is a device that detects any homemade electrical energy in


exceed. If so
several actions can be taken :
- with the Triac function: gradually switch on a resistive load that will take
all the
exceed energy. This load must be resistive (edison light, water heat, etc...)
due to
the power factor which must stay near 1.
- with the SSR function: prevent against any exceed by performing a load
shedding : just
before injection in the public power grid, either a load can be add to
increase
consumtion, or a power generator (solar panel, wind turbine) can be
stopped.

The operation is performed by:


- a shift detection between the grid current and the voltage which detect a
power consumption
or a power injection.
- in case of injection it initiates the gradual absorption by a resistive load of
any exceed power
- the current measure allows the absorption adjustment
- a load shedding becomes active when the system is very near injection and
automatically
stops as soon as a level of consumption is raised.

This device is actually in operation in two homes with a power load of


350W and 1000W.

Materials :
1* Arduino Uno R3 - IDE version 1.8.7
1* AC current sensor 20A/25mA
1* AC-AC 230V-2.5V transformer
1* LCD 1602 with I2C extension
1* shield : see manual documentation for wiring implementation
1* triac dimming module with zero-cross detection
3* push-buttons
1* SSR + 1* transistor NPN, 1* transistor PNP, few resistors, capacitors...

Pinup :
- pin A0 (analog 0) => AC current sensor
- pin A1 (analog 1) => AC voltage sensor
- pin A4 (analog 4) => SDA output for LCD
- pin A5 (analog 5) => SCL output for LCD
- pin 2 (numeric 2) => zero-cross detection
- pin 3 (numeric 3) => output to a LED which indicate pwm
- pin 4 (numeric 4) => input from push-button "entry"
- pin 5 (numeric 5) => input from push-button "+"
- pin 6 (numeric 6) => input from push-button "-"
- pin 10 (numeric 10) => pwm output that drives the Triac
- pin 11 (numeric 11) => output to load shedding
- pin 13 (numeric 13) => overflow LED alarm

*/

#include <EEPROM.h>
#include <avr/wdt.h> // documentation:
https://tushev.org/articles/arduino/5/arduino-and-watchdog-timer
#include <TimerOne.h> // library to install:
http://www.arduino.cc/playground/Code/Timer1
#include <LiquidCrystal_I2C.h> //
https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library

// calibration variables:

bool CALIBRATION = false; // if true = adjustment of Vcalibration and


Icalibration
bool VERBOSE = false; // if true = console display BUT VERY SLOW

// Calibration of measures which depend of the hardware. Must be done


once at the beginning :
// first: ajust Vcalibration for reading 230V on the console
// after: Icalibration by comparing with a multimeter
// optional: phasecalibration can be adjust with the help of a powermeter

float Vcalibration = 0.97; // to obtain 230V


float Icalibration = 40.6; // to adjust the current reading to reality
float phasecalibration = 1.7; // to correct the phase shift due to hardware
byte totalCount = 20; // number of half-period studied measuring
cycle

// power thresholds in Watts

int limitP = 1; // hysteresis of tolerance for the Triac action: if 1 =>


sensibility is +1W/-1W
int delestON = 1; // threshold to start the load shedding
int delestOFF = 350; // value to stop the load shedding
bool etat_delest_repos = HIGH; // inactive state of the load shedding:
HIGH for switched on

// Reactance level to calculate dimstep :


// dimstep evoluates by the factor 'power to dissiate'/reactancelevel
// it is a compromise between reaction speed and instability:
// too small = instability risk, too high = slower
// help how to calculate: reactancelevel ~ (dissipation power of the load in
Watts)/40
unsigned int reactancelevel = 9;

// Arduino inputs and outputs

const byte pushEntryPin = 4; // push button 'entry'


const byte pushPlusPin = 5; // push button '+'
const byte pushMinusPin = 6; // push button '-'
const byte triacPin = 10; // pwm output to Triac gate
const byte delestPin = 11; // output for load shedding
const byte triacLedPin = 3; // LED display Triac activity
const byte limitLedPin = 13; // LED for power overflow
const byte voltageSensorPin = 1; // input from voltage sensor
const byte currentSensorPin = 0; // input from current sensor
const byte zeroCrossPin = 2; // input from zero-cross detection

// variables for interruptions (zero-crossing) :

byte dimmax = 128; // max value of dim that shuttoff the Triac
byte dim = dimmax; // Dimming level (0-128) 0 = on, 128 = 0ff
char periodStep = 75; // value of the timer (65 for 60Hz, 78 for 50Hz,
in s)
// according the formula (500000/AC_freq)/NumSteps = periodStep
// 78*128=10ms=1/2 period 50Hz but in fact 75 works better
volatile int i = 0; // Variable to use as a counter
volatile bool zero_cross = false; // zero-cross detected for driving the
Triac
volatile bool zero_cross_flag = false; // zero-cross detected for power
calcultion

// variables for electrical mesasures

int readV, memo_readV, readI; // voltage and current in bits (0 1023


bits)
float rPower, V, I, sqV, sumV = 0, sqI, sumI = 0, instP, sumP = 0;
byte zero_crossCount = 0; // halp-period counter

// other variables

int dimstep; // value of the increment of dim


unsigned long loadsheddingcounter; // time counter of load shedding
duration
unsigned int memo_temps = 0;
bool delestage = false; // load shedding state
bool unefois = false; // for one time only flag
bool etat_delest_actif = !etat_delest_repos; // active loads shedding state
byte ret_push_button = 0;
byte windows = 0;
byte count_before_timeout = 0;
byte refresh_tempo = 2;
byte timeout = 20;

// LCD declaration with I2C :

// documentation : http://arduino-info.wikispaces.com/LCD-Blue-I2C
// Set the pins on the I2C chip used for LCD connections:
// addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
// => pinup for I2C with l'Arduino Uno R3 : SDA = A4, SCL = A5

//
// SETUP
//____________________________________________________________
_________________________________

void setup() { // Begin setup


pinMode(pushEntryPin, INPUT_PULLUP); // set the push-buttons as
entries pullup to +5V
pinMode(pushPlusPin, INPUT_PULLUP);
pinMode(pushMinusPin, INPUT_PULLUP);
pinMode(triacPin, OUTPUT); // Set the Triac pin as output
pinMode(delestPin, OUTPUT);
pinMode(triacLedPin, OUTPUT); // Set the LED pin as output
pinMode(limitLedPin, OUTPUT);

attachInterrupt(digitalPinToInterrupt(zeroCrossPin), zero_cross_detect,
RISING);
// each zeroCrossPin rising generates an interruption : the function
'zero_cross_detect()' is called
// documentation :
https://www.arduino.cc/reference/en/language/functions/external-
interrupts/attachinterrupt/

Timer1.initialize(periodStep); // TimerOne from library initialisation


Timer1.attachInterrupt(dim_check, periodStep);
// for every periodStep time spent, dim_check is called

// EEPROM functions are used to calculate how many time the device has
rebooted
// EEPROM stored values are of type char.
// default values in case of first use are set to 255
unsigned char reboot_high = EEPROM.read(0); // to get the high value of
the number
unsigned char reboot_low = EEPROM.read(1); // to get the low value of
the number
unsigned int reboot = (reboot_high << 8) + reboot_low;
reboot++;
EEPROM.update(0, highByte(reboot));
EEPROM.update(1, lowByte(reboot));

// EEPROM functions are used to store parameters


if(EEPROM.read(2) < 200) limitP = EEPROM.read(2); else
EEPROM.write(2, limitP);
if(EEPROM.read(3) < 50) delestON = EEPROM.read(3); else
EEPROM.write(3, delestON);
unsigned char delestOFF_high = EEPROM.read(4);
unsigned char delestOFF_low = EEPROM.read(5);
int delestOFF_full = (delestOFF_high << 8) + delestOFF_low;
if( delestOFF_full < 10001 ) delestOFF = delestOFF_full;
else {
EEPROM.write(4, highByte(delestOFF));
EEPROM.write(5, lowByte(delestOFF));
}
if(EEPROM.read(6) < 2) etat_delest_repos = EEPROM.read(6); else
EEPROM.write(6, etat_delest_repos);
if(EEPROM.read(7) < 255) reactancelevel = EEPROM.read(7); else
EEPROM.write(7, reactancelevel);
if(EEPROM.read(8) < 31) phasecalibration = (EEPROM.read(8))/10.0; else
EEPROM.write(8, (phasecalibration*10));

// LCD initialisation
lcd.begin(); // initialize the lcd for 16 chars 2 lines
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("POWER ROUTER");
lcd.setCursor(0, 1);
lcd.print("is starting !");

// console initialisation
Serial.begin(250000);
Serial.println ();
Serial.print("PLEASE NOTE : ");
Serial.print(reboot);
Serial.println(" total number of reboots");
Serial.println();
Serial.println("Ready to start ...");
Serial.println ();
delay(500);
if( VERBOSE == true ) Serial.print(" Pu (W) || dimstep | dim || load
shedding");
else Serial.println("It is working now !");
Serial.println();

digitalWrite(delestPin, etat_delest_repos); // state output to the default


load shedding state
wdt_enable(WDTO_500MS); // watchdog = reset if no
activity longer than 500ms

} // End setup

//
// ZERO CROSS DETECT : zero-cross interrupt
//____________________________________________________________
________________________________

void zero_cross_detect() { // this function is called at each zero-cross


interrupt
zero_cross_flag = true; // flag for the real power calculation
zero_cross = true; // flag to drive the Triac
}

//
// DIM CHECK : drive the Triac
//____________________________________________________________
________________________________

void dim_check() { // Function will fire the triac at the


proper time
if(zero_cross == true && dim < dimmax) // First check to make sure the
zero-cross has
{ // happened else do nothing
if(i>dim) { // i is a counter that defines the fire delay. higher is dim
longer i will count
digitalWrite(triacPin, HIGH); // and later the triac will fire
delayMicroseconds(50); // Pause briefly to ensure the triac turned
on
digitalWrite(triacPin, LOW); // Turn off the Triac gate, but the triac
stays switch on until OV
i = 0; // Reset the counter for the next cycle
zero_cross = false;
}
else i++; // If the dimming value has not been reached, increase it
} // End zero_cross check
} // End dim_check function

//
// LOOP
//____________________________________________________________
________________________________
void loop() { // Main Loop

// 1st part: calculation of the real electric power rPower


//____________________________________________________________
________________________________
//

unsigned int numberOfSamples = 0;


sumV = 0;
sumI = 0;
sumP = 0;
unsigned int temps_actuel = millis()/1000; // get the time spent in
seconds

// increment zero_crossCount at each zero-cross until totalCount, then


rPower value is calculated

if( zero_crossCount >= totalCount ) zero_crossCount = 0;

// as most as possible number of measures between the totalCount number


of half-periods
// themself defined by zero-cross flag
while( zero_crossCount < totalCount ) {
if( zero_cross_flag == true ) { // increment of half-period count for
each zero-cross
zero_cross_flag = false;
zero_crossCount++;
}
numberOfSamples++; // number of measures
memo_readV = readV; // memorize the past value
readV = analogRead(voltageSensorPin); // voltage measure in bits - 0V =
bit 512
delayMicroseconds(50);
if( readV == memo_readV && readV > 509 && readV < 515 ) { // test if
no grid
lcd.setCursor(0, 0);
lcd.print("ABSENCE DE ");
lcd.setCursor(0, 1);
lcd.print("TENSION SECTEUR ");
delay(200);
goto nogrid; // exit to the end of program
}
readI = analogRead(currentSensorPin); // current measure in bits - 0A = bit
512
delayMicroseconds(50);

// calculation of the effective values of voltage and current


if( CALIBRATION == true ) { // for calibration only
sqV= (readV -512.0) * (readV -512.0); // -512 as offset to get 0V = bit 0
sumV += sqV;
sqI = (readI -512.0) * (readI -512.0);
sumI += sqI;
} // end test upon CALIBRATION

// instant power calculation


instP = ((memo_readV -512.0) + phasecalibration * ((readV -512.0) -
(memo_readV -512))) * (readI -512.0);
sumP +=instP;
} // End of while upon zero_crossCount

// memorization of the values


if( numberOfSamples > 0 ) {
if( CALIBRATION == true ) {
V = Vcalibration * sqrt(sumV / numberOfSamples);
I = Icalibration * sqrt(sumI / numberOfSamples);
}
rPower = ((Vcalibration * Icalibration * sumP )/ numberOfSamples) /
1000.0;
}

// 2nd part: dim and dimstep calculation to drive the Triac, and load
shedding management
//____________________________________________________________
________________________________
//

// dimstep calculation: higher is the power to take in charge, higher will be


dimstep
if( rPower > 0 ) { dimstep = rPower/10/reactancelevel + 1; }
else { dimstep = 1 - rPower/10/reactancelevel; }

if( rPower > limitP ) { // injection increases, the delay to fire the
Triac decreases
if( dim > dimstep ) dim -= dimstep; else dim = 0;
}
else if( rPower < -limitP ) { // injection decreases, the delay to fire the
Triac decreases
if( dim + dimstep < dimmax ) dim += dimstep; else dim = dimmax;
}

if( dim < 1 ) digitalWrite(limitLedPin, HIGH); // overload LED


else { digitalWrite(limitLedPin, LOW); }
analogWrite(triacLedPin, dimmax-dim); // Write the value to the
LED for testing

// load shedding management


if( rPower > -delestON) { delestage = true; } // threshold activation
value for load shedding

if( delestage == true ) {


if( unefois == false ) {
digitalWrite(delestPin, etat_delest_actif); // load shedding driver update
loadsheddingcounter = temps_actuel; // for load shedding spent time
unefois = true;
}
if( rPower < -delestOFF ) { // threshold inactive value for
load shedding
digitalWrite(delestPin, etat_delest_repos); // load shedding driver update
unefois = false;
delestage = false;
}
} // end of test upon delestON

// LCD and menues management


//_______________________________________________
//
// display update and push-button request every 2 seconds
if( temps_actuel >= memo_temps + refresh_tempo ) {
memo_temps = temps_actuel;
ret_push_button = push_button(); // reading push-button status here only
lcd.clear();
lcd.setCursor(0, 0);
if( ret_push_button == 1 ) next_windows(); // if 'entry' pushed increase of
window
if( windows == 0 ) {
lcd.print("P= ");
lcd.print(String(-rPower,0));
lcd.print("w");
lcd.setCursor(10, 0);
lcd.print("T= ");
lcd.print( map(dim, 0, dimmax, 99, 0) );
lcd.print("%");
lcd.setCursor(0, 1);
lcd.print("DELESTAGE "); // load shedding in French
if( delestage == true ) {
lcd.print(temps_actuel - loadsheddingcounter);
lcd.print("s ");
}
else { lcd.print("ARRETE"); } // stoped in French
}
else { // end of window 0, start of parameters review
count_before_timeout++;
if( count_before_timeout > timeout ) { // timeout to return to usual display
if no job done
count_before_timeout = 0;
windows = 0;
lcd.noBacklight();
}
if( windows == 1 ) {
if(ret_push_button == 2) limitP++; // if "+" pushed
if(ret_push_button == 3) limitP--; // if "-" pushed
limitP = constrain(limitP, 1, 200);
lcd.print("SEUIL DETECTION");
lcd.setCursor(0, 1);
lcd.print("seuil = ");
lcd.setCursor(8, 1);
lcd.print(limitP);
lcd.print("W");
} // end of windows 1
if( windows == 2 ) {
if(ret_push_button == 2) delestON++; // if "+" pushed
if(ret_push_button == 3) delestON--; // if "-" pushed
delestON = constrain(delestON, 1, 50);
lcd.print("DELESTAGE ACTIF");
lcd.setCursor(0, 1);
lcd.print("seuil = ");
lcd.setCursor(8, 1);
lcd.print(delestON);
lcd.print("W");
} // end of windows 2
if( windows == 3 ) {
if(ret_push_button == 2) delestOFF+= 50; // if "+" pushed
if(ret_push_button == 3) delestOFF-= 50; // if "-" pushed
delestOFF = constrain(delestOFF, 50, 10000);
lcd.print("DELESTAGE ARRET");
lcd.setCursor(0, 1);
lcd.print("seuil = ");
lcd.setCursor(8, 1);
lcd.print(delestOFF);
lcd.print("W");
} // end of windows 3
if( windows == 4 ) {
if( ret_push_button > 1 ) etat_delest_repos =! etat_delest_repos;
etat_delest_actif =! etat_delest_repos;
lcd.print("DELESTAGE :");
lcd.setCursor(0, 1);
if( etat_delest_repos == HIGH ) lcd.print("DEMARRE au repos");
else lcd.print("ARRETE au repos");
} // end of windows 4
if( windows == 5 ) {
if(ret_push_button == 2) reactancelevel++; // if "+" pushed
if(ret_push_button == 3) reactancelevel--; // if "-" pushed
reactancelevel = constrain(reactancelevel, 1, 254);
lcd.print("COEF DE REACTION");
lcd.setCursor(0, 1);
lcd.print("taux = ");
lcd.setCursor(7, 1);
lcd.print(reactancelevel);
} // end of windows 5
if( windows == 6 ) {
byte phasecalibrationDEC = phasecalibration*10;
if(ret_push_button == 2) phasecalibrationDEC++; // if "+" pushed
if(ret_push_button == 3) phasecalibrationDEC--; // if "-" pushed
phasecalibrationDEC = constrain(phasecalibrationDEC, 1, 30);
phasecalibration = phasecalibrationDEC/10.0;
lcd.print("CALIBRATION Pu");
lcd.setCursor(0, 1);
lcd.print("valeur = ");
lcd.setCursor(9, 1);
lcd.print(phasecalibration);
} // end of windows 6

// EEPROM updated if needed


EEPROM.update(2, limitP);
EEPROM.update(3, delestON);
EEPROM.update(4, highByte(delestOFF));
EEPROM.update(5, lowByte(delestOFF));
EEPROM.update(6, etat_delest_repos);
EEPROM.update(7, reactancelevel);
EEPROM.update(8, (phasecalibration*10));

} // end of paramerter review


} // end of display management

// console display
if( CALIBRATION == true ) {
Serial.print(V);
Serial.print(" | ");
Serial.print(I/1000);
Serial.print(" | ");
Serial.print(rPower);
Serial.println();
}
if( VERBOSE == true ) {
Serial.print(rPower);
Serial.print(" || ");
Serial.print(dimstep);
Serial.print(" | ");
Serial.print(dim);
Serial.print(" || ");
Serial.print(" load shedding : ");
Serial.print(delestage);
Serial.print(" seconds : ");
Serial.println(temps_actuel - loadsheddingcounter);
}
else delay(1); // required for stability
nogrid:
wdt_reset(); // watchdog reset

} // end of main Loop

//
// NEXT_WINDOWS : next windows procedure
//____________________________________________________________
________________________________

void next_windows() {

windows = (windows+1) % 7; // next windows modulo 6


ret_push_button = 0; // reset the buttun state
lcd.clear();
lcd.setCursor(0, 0);
} // end of next_windows function

//
// PUSH_BUTTON : return value depending of the state of the 3 push-
buttons
//____________________________________________________________
________________________________

byte push_button() {

if( digitalRead(pushEntryPin) == 0 ) {
count_before_timeout = 0; // reset the timeout counter
lcd.backlight(); // switch on display
return 1;
}
if( digitalRead(pushPlusPin) == 0 ) {
count_before_timeout = 0; // reset the timeout counter
lcd.backlight(); // switch on display
refresh_tempo = 1; // temporary lower display update duration
return 2;
}
if( digitalRead(pushMinusPin) == 0 ) {
count_before_timeout = 0; // reset the timeout counter
lcd.backlight(); // switch on display
refresh_tempo = 1; // temporary lower display update duration
return 3;
}
refresh_tempo = 2; // go back to initial value
return 0;
} // end of push_button function

You might also like