Posts with «arduinobasics» label

Arduino based Security Project Using Cayenne


 

Description

This is an Arduino based home security project that uses the power of "Cayenne" for extraordinary capabilities.

Cayenne Beta

Cayenne is a new IoT drag and drop platform originally released for the Raspberry Pi, but now available for Arduino. Cayenne makes the task of connecting your Arduino to the internet as simple as possible. All of the complexity of internet connectivity is hidden within the Cayenne library.

You can easily create a Network of Arduinos and build an IoT system which can be managed and operated within the Cayenne dashboard. This dashboard is accessible through your browser or via the Cayenne smart phone app (on IOS or Android).

The feature I liked the most, was the ability to change the position of sensors or actuators on the Arduino without having to re-upload Arduino code. I could manage the changed position from within the Cayenne platform. The other feature that I liked was the ability to setup actions based on custom triggers. You can use Cayenne to trigger a whole range of functions, for example: play a sound, move a motor, light up an LED, or to send alert notifications via email or SMS.

Cayenne is in Beta at the moment, so there are a few minor bugs here and there, but overall - I give it a thumbs up - it is definitely worth checking out.
 

Here is a link to the Cayenne Beta Program:
**Cayenne Beta Link**



              Source: myDevices Media Kit

 

Home Security Project Summary

In order to fully experience this new IoT platform, I decided to create a project to really put it through its paces. This is what my Security Project will need:

  1. It will use two Arduinos, one connected to the internet via an Ethernet shield, and the other via WIFI.
  2. Two detectors - a PIR sensor and a laser trip wire.
  3. If the sensors are tripped, the person has 10 seconds to present an RFID tag to the Grove RFID reader:
    • If a valid RFID tag is SUCCESSFULLY presented within the time limit, a nice personalised greeting will be played to that person using a Grove - Serial MP3 player
    • If a valid RFID FAILS to be presented within the time limit, an Alarm will sound, and I will be notified of the intrusion via an SMS alert.
  4. The Cayenne dashboard will show the status of the sensors, and I will have full control over my security system via the web interface (or smartphone app).
  5. The sensors will be attached to a different Arduino to that of the Grove MP3 player and the RFID tag reader, which means that there will have to be some level of communication between the two Arduinos. In fact, the cross communication will be vital to the success of this project.


 
 
 

Project Video



 
 
 
 

 

Flow Diagrams:

Main Flow Diagram

The following flow diagram shows the Security project process. It is a high level view of the decisions being made by each Arduino in response to various events.  


 

Triggers Flow Diagram

The following flow diagram aims to highlight the various triggers set up within Cayenne to get this Security system to work.  

 
 
 

Arduino IDE and Library Downloads

You will need an Arduino IDE to upload code to the Arduino and the Seeeduino Cloud.
Here is the link to the Arduino IDE: Arduino IDE - download location

The Cayenne service requires that you download and install the Cayenne Library into your Arduino IDE.
You can get the Cayenne Library from here: Cayenne Library File - Download


 

Cayenne Connectivity Setup

The Seeeduino Cloud needs to be prepared for use with Cayenne.
Normal operating/setup instructions can be found here: Seeeduino Cloud WIKI page
 
Once you have successfully connected Seeeduino Cloud to your WIFI network, you can add it to the Cayenne Dashboard by making the following selections from within the Cayenne Web application:

  1. Add New
  2. Device/Widget
  3. Microcontrollers
  4. Arduino
  5. Ensure Seeeduino Cloud is connected to WIFI network - the select the NEXT button
  6. Select - Arduino Yun: Built-in Ethernet - ticked
  7. Providing you have already installed the Cayenne library as described above - you should be able to copy and paste the code to the Arduino IDE and upload to the Seeeduino Cloud.
  8. If successful, you should see the Arduino Yun board appear within the Cayenne Dashboard. If not, then seek help within the Cayenne forum.


 

The Arduino UNO with WIZNET 5100 - Ethernet Shield
also needs to be prepared with Cayenne

  1. Add New
  2. Device/Widget
  3. Microcontrollers
  4. Arduino
  5. Ensure Arduino is powered, and Ethernet shield is connected to your internet router via an Ethernet cable
  6. Select - Arduino Uno: Ethernet Shield W5100 - ticked
  7. Copy and paste the code to the Arduino IDE and upload to the Arduino UNO.
  8. If successful, you should see the Arduino Uno board appear within the Cayenne Dashboard. If not, then seek help within the Cayenne forum.

 


 
If you have the Ethernet shield with the WIZNET 5200 chip, then you may need to download a specific Ethernet library in addition to the Cayenne library.
 
Just follow the instructions within the Automatically generated sketch provided - when you select your specific Arduino/Ethernet/WIFI shield combination. If you need further instructions on connecting your device to Cayenne - then please visit the myDevices website for the online documentation.
 


 
 
 
 

ARDUINO CODE (1)


Code for Arduino UNO with Ethernet Shield:

The following code will need to be uploaded to the Arduino UNO:


 
 
 
 
 

ARDUINO CODE (2)


Code for Seeeduino Cloud:

The following code will need to be uploaded to the Seeeduino Cloud:


 
 
 
 

Fritzing diagram (1)


Fritzing diagram for Arduino UNO with Ethernet

Please click on the picture below for an enlarged version of this fritzing diagram


 
 
 
 

Fritzing diagram (2)


Fritzing diagram for Seeeduino Cloud

Please click on the picture below for an enlarged version of this fritzing diagram


 
 
 
 
 
 
 

Cayenne Dashboard Setup - GUI


The Arduino code only provides half of the functionality of this project. The Cayenne Dashboard needs to be setup to provide the rest of the functionality. The following instructions will show you how to add each of the widgets required for this Home Security project.


Arduino Ethernet - Master Switch

The master switch allows me to turn the security system on and off. When I turn the MASTER SWITCH ON, the laser beam will turn on, and the sensors will start monitoring the area for intruders. This widget is NOT associated with a physical switch/sensor on the Arduino - it uses virtual channel 0. We need to add the Master switch to the dashboard:


  1. Add New
  2. Device/Widget
  3. Actuators
  4. Generic
  5. Digital Output - Control a Digital Output
  6. Widget Name: Master On Off Switch
  7. Select Device: Arduino Ethernet
  8. Connectivity: Virtual
  9. Pin: V0
  10. Choose Widget: Button
  11. Choose Icon: Valve
  12. Step2: Add Actuator
We will add a trigger later to get this button to automatically turn the Laser beam on.


 
 
 

Arduino Ethernet - PIR Sensor

This sensor will be used to detect movement in the room. If a person walks into the room, this sensor will detect movement, and will trigger a message to be played on the Grove Serial MP3 player. The message will aim to get the person to identify themselves. They identify themselves by placing their RFID tag in close proximity to the Grove RFID reader. If the tag is valid, a "Welcome home" message is played on the Grove MP3 player. If a valid tag is not presented to the reader within 10 seconds, an Alarm will go off ("Alarm sound" played on Grove MP3 player.)

The PIR sensor is connected to digital Pin 6 of the Arduino, however, it is mapped to virtual pin 1 for better synchronisation with the Cayenne dashboard. This was done to capture ALL detections - as the PIR sensor could change from a LOW to HIGH and back to LOW state in between a Cayenne state check - and therefore, Cayenne could miss this motion detection.. Therefore we need to assign the PIR sensor to a virtual channel in the following way:
  1. Add New
  2. Device/Widget
  3. Sensors
  4. Motion
  5. Digital Motion Sensor - Motion Detector
  6. Widget Name: PIR sensor
  7. Select Device: Arduino Ethernet
  8. Connectivity: Virtual
  9. Pin: V1
  10. Choose Widget: 2-State Display
  11. Choose Icon: Light
  12. Step2: Add Sensor
  13. Select Settings from the PhotoResistor
  14. Choose Display: Value
  15. Save

 
 
 

Arduino Ethernet - Photoresistor

This sensor will be used with the laser beam to create a laser tripwire. If the sensor detects a change in light levels (drops below the threshold), it will activate the laser trigger button on the dashboard. The person will then be required to identify themselves etc etc (similar to the motion detection by the PIR sensor). The photoresistor widget will display the raw analog reading from the sensor (connected to A2), but is associated with virtual channel 2. I used a virtual channel for more control over this sensor. To add the Photoresistor to the dashboard:

  1. Add New
  2. Device/Widget
  3. Sensors
  4. Luminosity
  5. Photoresistor - Luminosity sensor
  6. Widget Name: PhotoResistor
  7. Select Device: Arduino Ethernet
  8. Connectivity: Virtual
  9. Pin: V2
  10. Choose Widget: Value
  11. Choose Icon: Light
  12. Step2: Add Sensor


 
 
 

Arduino Ethernet - Laser Trigger

The laser trigger is just an indicator that someone tripped the laser beam. The state of this widget is used to notify the Seeeduino that a presence has been detected. This widget is associated with virtual pin 4 on the Arduino UNO with Ethernet.

  1. Add New
  2. Device/Widget
  3. Actuators
  4. Generic
  5. Digital Output - Control a Digital Output
  6. Widget Name: Laser Trigger
  7. Select Device: Arduino Ethernet
  8. Connectivity: Virtual
  9. Pin: V4
  10. Choose Widget: Button
  11. Choose Icon: Lock
  12. Step2: Add Actuator


 
 
 

Arduino Ethernet - Laser Threshold

The laser threshold is used to manually configure the light level at which the laser trigger will trip. When the photoresistor value drops below the threshold value, the laser trigger icon will activate. This allows the threshold value to be updated from the Cayenne dashboard, rather than having to manually adjust the value in the Arduino code. Also, this threshold can be set remotely, in that you don't have to be near the Arduino to change this value. A very useful feature of this Security system. This widget is associated with virtual pin 5 on the Arduino UNO with Ethernet.

  1. Add New
  2. Device/Widget
  3. Actuators
  4. Generic
  5. PWM Output - Control a PWM Output
  6. Widget Name: Laser Threshold
  7. Select Device: Arduino Ethernet
  8. Connectivity: Virtual
  9. Pin: V5
  10. Choose Widget: Slider
  11. Slider Min Value: 0
  12. Slider Max Value: 10
  13. Step2: Add Actuator
The max value of the slider is 10 - due to a current bug in the Cayenne software. Once resolved, this value (as well as the relevant Arduino code) will need to be updated.


 
 
 

Seeeduino Cloud - Presence Detected

The presence detected widget is there to notify the Seeeduino Cloud that a presence has been detected on the Arduino Uno with Ethernet shield. When the PIR sensor detects movement or if the laser tripwire is tripped, Cayenne will change the state of the Presence Detected widget from LOW to HIGH. This is used within the Seeeduino Cloud to trigger the message "Place your keys on the Mat"
. If a valid RFID tag is read by the Grove RFID reader, then this widget's state will change back from HIGH to LOW, and the MasterSwitch will be deactivated - turning the Security system off. This widget is associated with Virtual pin 6 on the Seeeduino Cloud.

  1. Add New
  2. Device/Widget
  3. Actuators
  4. Generic
  5. Digital Output - Control a Digital Output
  6. Widget Name: Presence Detected
  7. Select Device: Seeeduino Cloud
  8. Connectivity: Virtual
  9. Pin: V6
  10. Choose Widget: Button
  11. Choose Icon: Lock
  12. Step2: Add Actuator


 
 
 

Seeeduino Cloud - Intruder Alert

If a valid RFID tag is not read by the Grove RFID reader within 10 seconds of a presence detection event, an alarm will sound, and this widget will be activated. This will trigger a notification event - to notify me of the unauthorised intrusion - via SMS or email. I will also have a visual indicator on the Cayenne dashboard that an intrusion has taken place. This widget is associated with Virtual pin 7 on the Seeeduino Cloud.

  1. Add New
  2. Device/Widget
  3. Actuators
  4. Generic
  5. Digital Output - Control a Digital Output
  6. Widget Name: Laser Trigger
  7. Select Device: Seeeduino Cloud
  8. Connectivity: Virtual
  9. Pin: V7
  10. Choose Widget: Button
  11. Choose Icon: Thermometer
  12. Step2: Add Actuator


 
 
 

Seeeduino Cloud - Laser Beam

The laser beam widget was created to allow for full control over the laser beam. The laser beam can be turned on or off from the Cayenne dashboard, and a connected to digital pin 7 on the Seeeduino Cloud.


  1. Add New
  2. Device/Widget
  3. Actuators
  4. Light
  5. Light Switch - Turn On/Off a Light
  6. Widget Name: xLaser Beam
  7. Select Device: Seeeduino Cloud
  8. Connectivity: Digital
  9. Pin: D7
  10. Choose Widget: Button
  11. Choose Icon: Light
  12. Step2: Add Actuator


 
 
 
 

Cayenne Triggers

Now that all of the widgets have been added to the Dashboard, there is just one more step to complete the Security System. We need to setup the triggers. These triggers provide a level of automation that is easy to create within Cayenne, but would be very complicated otherwise. I set my triggers up as per the table below. Each row represents one of the triggers within my Cayenne dashboard. If you would like to see an example of how to add a trigger - please have a look at the video at the top of this tutorial.  


 
 
 
 
 
 

Concluding comments

I used many different elements to put this home/office security project together - Multiple Arduinos were connected to the internet, both controlled by a web/smart phone app, cross-communication/synchronisation between the Arduinos, and the use of multiple sensors and modules including a laser beam !
 
This was way more than just a simple PIR sense and alarm project. I now have a personalised greeting and reminder system when I walk in the door. Everyone else has their own personalised greeting. I can enable my Security System remotely, from two blocks away, and if I wanted to - I could enable it from the other side of the world. I know instantly when someone has entered my house/office.... with an SMS alert straight to my phone.
 
This project could easily be extended:

  1. Press a button on my phone to manually trigger/play a specific message/sound/song
  2. Take a picture of the intruder
  3. Introduce fire or leak detection aswell
  4. Add other environmental sensors - Temperature / Humidity
  5. Connect it to lamp/light - creating a security light
I am sure you can think of more things I could do with this system. In fact, why don't you mention your ideas in the comments below.
 
Cayenne was instrumental in getting this project to work. I don't think I would know where to start if I had to do this project without this cool IoT platform. I think I will definitely be trying out a few more projects using Cayenne, and should you want to do the same, then please make sure to join Cayenne Beta:
 
Here is the link you need to get to the right place: Cayenne Beta Link

 

If you like this page, please do me a favour and show your appreciation :

 
Visit my ArduinoBasics Google + page.
Follow me on Twitter by looking for ScottC @ArduinoBasics.
I can also be found on Pinterest and Instagram.
Have a look at my videos on my YouTube channel.

             

ScottC 30 Aug 15:42
alarm  arduino  arduinobasics  cayenne  laser  mp3  mydevices  pir  rfid  security  sms  tutorial  

Arduino LED Light Box

Description

Long straight lines of LED luminescence is nice, but sometimes you may want to light up something that has an unusual shape, or is not so linear. This is where the 12mm diffused flat digital RGB LED Pixels can come into play. This cool strand of 25 NeoPixels fit nicely into 12mm pre-drilled holes of any material you like.

This tutorial is dedicated to making a LED Light Box. I wanted the box to be equally as interesting during the day as it was at night. If you decide you make your own, feel free to be as creative as you want !! However, if you lack artistic acumen, you may need to source a minion or two.


 

Arduino Libraries and IDE

Before you start to hook up any components, upload the following sketch to the Arduino microcontroller. I am assuming that you already have the Arduino IDE installed on your computer. If not, the IDE can be downloaded from here.

The FastLED library is useful for simplifying the code for programming the NeoPixels. The latest "FastLED library" can be downloaded from here. I used FastLED library version 3.0.3 in this project.

If you have a different LED strip or your NeoPixels have a different chipset, make sure to change the relevant lines of code to accomodate your hardware. I would suggest you try out a few of the FastLED library examples before using the code below, so that you become more familiar with the library, and will be better equipped to make the necessary changes.

If you have a single strand of 25 Neopixels with the WS8201 chipset, then you will not have to make any modification below.


 

ARDUINO CODE:

Arduino Code Description

The code above will generate a randomised raindrop pattern on the NeoPixel LED Light box, however I have written code for a few more LED animations. These animations were written specifically for this light-box setup. In other words, once you have hooked everything up, you will be able to upload these other LED animations to the Arduino board without any further modification to the hardware/wiring, and yet experience a totally different light effect. You can find the code for the other animation effects by clicking on the links below:

  1. Breathing effect
  2. Ripple effect
  3. Clock effect
  4. Rotation effect
  5. Sweep effect
  6. Spiral effect
  7. Lightning effect
  8. Paparazzi in the Rain effect

Hooking it up:

Power requirements

Each Neopixel LED can draw up to 60 milliamps at maximum brightness (white). ie. 20 mA for each colour (red, green and blue). Therefore you should not try to power the LED strand directly from the Arduino, because the strand will draw too much current and damage the microcontroller(and possibly your USB port too). The LED strand will therefore need to be powered by a separate power supply. The power supply must supply the correct voltage (5V DC) and must also be able to supply sufficient current (1.5A or greater per strand of 25 LEDs).

Excessive voltage will damage or destroy your Neopixel strand. The LEDs will only draw as much current as they need, however your power supply must provide at least 1.5A or greater for each strand. If you chain two strands together, you will need a 5V 3A power supply.

Neopixel strand connection

There are 25 Neopixel LEDs per strand. Four of the wires at each end of the strand are terminated with a JST connector. The red wire is for power (VCC), blue wire for ground (GND), yellow wire is for Data, and green wire for Clock. A spare red wire (VCC) and a spare blue wire (GND) are attached to the ends of each strand for convenience, however, I did not use either. Please double check the colour of your wires... they may be different.

If you want to attach the LED strand to a breadboard, you can cut the JST connector off and use the Neopixel strand wires. Alternatively, if you would prefer to preserve the JST connector, you can simply insert jumper wires (or some male header pins) into the JST connector, and then plug them into the breadboard as required.

Each neopixel LED is individually controllable using two pins on your Arduino. The strand is directional. i.e. There is an INPUT side and an OUTPUT side. The strand should be connected such that wires from the microcontroller are attached to the INPUT side of the first neopixel. The arrows on each LED show the direction of data flow from INPUT to OUTPUT. The arrow on the first NeoPixel should be pointing towards the second NeoPixel, NOT towards the breadboard.

Other considerations

As a precaution, you should use a large capacitor across the + and - terminals of the power supply to prevent the initial onrush of current from damaging the Neopixels. I used a 4700uF 16V Electrolytic capacitor for this purpose. According to Adafruit, a 1000uF 6.3V capacitor (or higher) will also do the trick. You may also want to consider a 330 ohm resistor between the Arduino Digital pin and the strand's DATA pin.

If you want to power the Arduino using the regulated 5V external power supply. Disconnect the USB cable from the Arduino, and then connect the positive terminal of the power supply to the 5V pin on the Arduino. Be warned however, that excess voltage at this pin could damage your Arduino, because the 5V regulator will be bypassed.
 
Providing the USB cable is NOT connected to the Arduino, it should now be safe to plug the power supply into the wall. This setup will allow you to power the Neopixel strand and the Arduino using the same power supply.
 
WARNING: Never change any connections while the circuit is powered.

For more information about these NeoPixel strands, you may want to visit the Adafruit site. Adafruit was the source for most of these NeoPixel Strand precautions.


Fritzing diagram

The following diagram demonstrates how to connect the NeoPixel Strand to the Arduino and to the External 5V power supply.


This diagram was created using Fritzing


Connection Instructions

These instructions will help to guide you through the process of connecting your NeoPixel strand to the Arduino, and to the external power supply. The instructions assume that you will be powering the Arduino via a USB cable.



LightBox assembly

You will need to drill a 12mm hole into the craft timber box for each LED on the strand. It is worth taking the time to make accurate measurements before drilling the holes.
 
I made 12 holes for the outside circle pattern (12cm diameter), 6 holes for the inside circle pattern (8cm diameter), and a hole in the centre. I also made two holes at the front of the box, two on the left side, and two on the right side. I made one last hole at the back of the box for the 2.1mm DC power line socket.
 
Therefore you should have a total of 26 holes in the box. 25 of the holes are for the Neopixel LEDs and one for the external power supply socket.

The lid of the box is about 19.5cm x 14.5cm long, which makes for a very tight squeeze. Probably too tight, because you have to account for the inner dimensions of the box. The inside of the box is used to house the Arduino, breadboard, the chipset side of the LEDs and cables/components. The inner dimensions of the box are 18cm x 13cm. Therefore, the housing for the LED chipset PCB (1.8cm x 2.5cm) prevented the box from closing. I used a Dremel to carve out the space required to close the lid.

Each LED is approximately 8cm apart on the strand, however, if you are really keen, you could cut the wires and extend them to any distance you require. But keep in mind that each LED is mounted on a small PCB (with a WS2801 chipset).You will therefore need to leave a minimum of 2cm between each 12mm hole to accomodate the size of the PCB+LED. If you plan carefully, you can probably squeeze a couple of LEDs within a distance of 1cm... but I would recommend that you give yourself a bit more room, because the PCBs are not square, and there is a good chance that you will have to start all over again.

In hindsight, I could have made the circle patterns a bit smaller, however I don't know if I could have packed these LEDs any closer. The diameter of the inner circle pattern must be at least 2cm smaller than the outer circle pattern. So I think "a bigger box" would have been the best option.

Once all of the holes have been drilled, paint and decorate the box to suit your style.

When the paint is dry, insert the LEDs into the drilled holes in number order.
You can see the end result below.



Project Pictures

These pictures show the Light box after it has been drilled and painted. The LEDs have been inserted into their respective holes, and all wires + Arduino + breadboard are hidden within the box.





Concluding comments

Once you start writing LED animations for the NeoPixel Lightbox, it is very hard to stop. The colour combinations



If you like this page, please do me a favour and show your appreciation :

 
Visit my ArduinoBasics Google + page.
Follow me on Twitter by looking for ScottC @ArduinoBasics.
I can also be found on Pinterest and Instagram.
Have a look at my videos on my YouTube channel.

             

This project would not have been possible without OpenLab's collaborative effort.
Please visit their site for more cool projects.



However, if you do not have a google profile...
Feel free to share this page with your friends in any way you see fit.

Say Hello

I have just launched my guest book on my blog.

You will notice a new menu at the top of the blog which reads "Guest Book".
This is just a place for people to say hello, share their project with me, or provide any other feedback. You can either leave a video message, or a traditional written message, either (or both) is fine.

Thank you very much for visiting. Knowing that people like you are actually reading my work is incentive enough to keep on going. Please tell me if you don't like something, or if you do like something, tell me that too.

Sometimes it is hard to know if I am on the right track and whether there is any benefit in providing this information.
Thank you very much for dropping by.
Please come again soon :)

Visit my Guest book here

ScottC 11 Oct 15:11

MT8870 DTMF - Dual Tone Multi Frequency Decoder

Project Description

We will be using an MT8870 DTMF module with an Arduino UNO to control a small servo motor in this project. The DTMF module gives the Arduino super-powers and allows you to control the Servo motor in so many ways. For example, this tutorial will show you how to control the servo motor using:
  • a YouTube Video
  • a voice recorder
  • A web application (Online tone generator)
  • A smart phone app (DTMF Pad)
  • A touch-tone phone to cell-phone call
All of these control methods will take advantage of the same exact Arduino code/sketch. But how???
The MT8870 DTMF decoder is quite a neat little module that allows you incorporate DTMF technology into your arduino projects. DTMF stands for Dual-Tone Multi-Frequency. DTMF tones are commonly associated with touch-tone phones and other telecommunication systems. When you press the number "1" on a touch-tone phone, two sine waves with frequencies: 697Hz and 1209Hz are combined to produce a unique DTMF signal which can be transmitted through the phone line. The MT8870 DTMF module can take this signal as an input, and decode it to produce a binary output.
 
 

 
The DTMF module does not care how you produce the DTMF tone. However, if it receives this tone, it will decode it. We can take advantage of this feature to supply the module with tones from different sources. The module has a 3.5mm port for line input. Providing you can connect your DTMF source to this line input in some way, it should work. I must warn you, however that this is a line input and NOT a microphone input. If you wanted to use a microphone, you will need to boost or amplify the signal before sending it to the DTMF module.
 
You will need the following parts for this project
 

Parts Required:

Software/Apps Required

Arduino Sketch


Upload the following sketch to the Arduino.
 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/* ================================================================================================================================================== Project: MT8870 DTMF Servo sketch Author: Scott C Created: 4th August 2015 Arduino IDE: 1.6.4 Website: http://arduinobasics.blogspot.com/p/arduino-basics-projects-page.html Description: This project will allow you to control a Servo motor using an Arduino UNO and a MT8870 DTMF Module. The DTMF signal is received through the 3.5mm port of the DTMF module and is decoded. We will use the decoded output to control the position of the Servo. A SG-5010 Servo motor was used in this project. ===================================================================================================================================================== *///This sketch uses the Servo library that comes with the Arduino IDE #include <Servo.h> //Global variables----------------------------------------------------------------------------------------- Servo SG5010; // The SG5010 variable provides Servo functionality int servoPosition = 0; // The servoPosition variable will be used to set the position of the servo byte DTMFread; // The DTMFread variable will be used to interpret the output of the DTMF module. const int STQ = 3; // Attach DTMF Module STQ Pin to Arduino Digital Pin 3 const int Q4 = 4; // Attach DTMF Module Q4 Pin to Arduino Digital Pin 4 const int Q3 = 5; // Attach DTMF Module Q3 Pin to Arduino Digital Pin 5 const int Q2 = 6; // Attach DTMF Module Q2 Pin to Arduino Digital Pin 6 const int Q1 = 7; // Attach DTMF Module Q1 Pin to Arduino Digital Pin 7 /*========================================================================================================= setup() : will setup the Servo, and prepare the Arduino to receive the MT8700 DTMF module's output. ========================================================================================================== */void setup() { SG5010.attach(9); // The Servo signal cable will be attached to Arduino Digital Pin 9 SG5010.write(servoPosition); // Set the servo position to zero. //Setup the INPUT pins on the Arduino pinMode(STQ, INPUT); pinMode(Q4, INPUT); pinMode(Q3, INPUT); pinMode(Q2, INPUT); pinMode(Q1, INPUT);} /*========================================================================================================= loop() : Arduino will interpret the DTMF module output and position the Servo accordingly ========================================================================================================== */void loop() { if(digitalRead(STQ)==HIGH){ //When a DTMF tone is detected, STQ will read HIGH for the duration of the tone. DTMFread=0; if(digitalRead(Q1)==HIGH){ //If Q1 reads HIGH, then add 1 to the DTMFread variable DTMFread=DTMFread+1; } if(digitalRead(Q2)==HIGH){ //If Q2 reads HIGH, then add 2 to the DTMFread variable DTMFread=DTMFread+2; } if(digitalRead(Q3)==HIGH){ //If Q3 reads HIGH, then add 4 to the DTMFread variable DTMFread=DTMFread+4; } if(digitalRead(Q4)==HIGH){ //If Q4 reads HIGH, then add 8 to the DTMFread variable DTMFread=DTMFread+8; } servoPosition = DTMFread * 8.5; //Set the servoPosition varaible to the combined total of all the Q1 to Q4 readings. Multiply by 8.5 to amplify the servo rotation. } SG5010.write(servoPosition); //Set the servo's position according to the "servoPosition" variable. }


 
 
 

Fritzing Sketch


Connect the Arduino to the MT8870 DTMF module, and to a Servo.
Use the following Fritzing sketch as a guide.
 
(Click the image above to enlarge it)



Discussion


You will need to connect a cable from the DTMF module's 3.5mm port to that of your smart phone, computer, voice recorder or any other DTMF source of your choice.
 

 

When you power up your Arduino, the Servo motor should turn all the way to the left to it's zero position. Once the DTMF module receives a DTMF signal, it will identify the relevant frequecies as described in the table at the beginning of this tutorial, and produce a binary like output. You will notice the DTMF module's onboard LEDs light up when a tone is detected. Onboard LED (D5) will turn on for the length of the DTMF tone it just received, and turn off when the tone has stopped. On the other hand, the onboard LEDs (D1 to D4) will light up depending on the tone received, and will remain lit until the module receives another tone. The onboard LEDs are a visual representation of the voltages applied to the DTMF module's pins (Q1 to Q4, and STQ). Q1 matches D1, Q2 matches D2 etc etc. and STQ matches D5.
 
You will notice that there are two STQ pins on the DTMF module. The STQ pin that is closest to Q4 will only go high when a DTMF tone is detected, and will remain high for the duration of the tone. The other STQ pin is the exact opposite. It will switch LOW when a tone is received and remain LOW for the duration of the tone. When there is no tone, this STQ pin will remain HIGH. The table below provides a summary of the DTMF module outputs, with a blue box representing a voltage applied to that pin (HIGH), whereas a black box indicates no voltage applied (LOW).


 
In order to follow this project, you need a source of DTMF tones. You can produce DTMF tones using a touch-tone phone, or through the use of a DTMF Pad app. If you are feeling creative, you can create a DTMF song/tune like the one I posted on YouTube. You can see the video below:
 

 
As you can see from the video, I also recorded the DTMF tune onto a voice recorder, and was able to control the servo that way. If you are not feeling creative, you can visit this website to create DTMF tones from your browser.

Concluding comments


This project was very fun, and shows some novel ways to control your Arduino. After completing the project, I realised that I could use this module to alert me when new emails or messages arrive on my phone or computer. If you have the ability to change the email or message notification sound to a DTMF tone, you should be able to get the module and Arduino to respond accordingly. Oh well, maybe I'll save that project for another day.
 
If this project helped you in anyway or if you use my code within your project, please let me know in the comments below. I would be interested to see what you did.


If you like this page, please do me a favour and show your appreciation :

 
Visit my ArduinoBasics Google + page.
Follow me on Twitter by looking for ScottC @ArduinoBasics.
I can also be found on Pinterest and Instagram.
Have a look at my videos on my YouTube channel.


 
 
             

 



However, if you do not have a google profile...
Feel free to share this page with your friends in any way you see fit.

NeoPixel Heart Beat Display


Project Description


In this project, your heart will control a mesmerising LED sequence on a 5 metre Neopixel LED strip with a ws2812B chipset. Every heart beat will trigger a LED animation that will keep you captivated and attached to your Arduino for ages. The good thing about this project is that it is relatively easy to set up, and requires no soldering. The hardest part is downloading and installing the FastLED library into the Arduino IDE, but that in itself is not too difficult. The inspiration and idea behind this project came from Ali Murtaza, who wanted to know how to get an LED strip to pulse to his heart beat.
 
Have a look at the video below to see this project in action.
 
 
 

The Video


 


 
 

Parts Required:


 

Power Requirements

Before you start any LED strip project, the first thing you will need to think about is POWER. According to the Adafruit website, each individual NeoPixel LED can draw up to 60 milliamps at maximum brightness - white. Therefore the amount of current required for the entire strip will be way more than your Arduino can handle. If you try to power this LED strip directly from your Arduino, you run the risk of damaging not only your Arduino, but your USB port as well. The Arduino will be used to control the LED strip, but the LED strip will need to be powered by a separate power supply. The power supply you choose to use is important. It must provide the correct voltage, and must able to supply sufficient current.
 

Operating Voltage (5V)

The operating voltage of the NeoPixel strip is 5 volts DC. Excessive voltage will damage/destroy your NeoPixels.

Current requirements (9.0 Amps)

OpenLab recommend the use of a 5V 10A power supply. Having more Amps is OK, providing the output voltage is 5V DC. The LEDs will only draw as much current as they need. To calculate the amount of current this 5m strip can draw with all LEDs turned on at full brightness - white:

30 NeoPixel LEDs x 60mA x 5m = 9000mA = 9.0 Amps for a 5 metre strip.

Therefore a 5V 10A power supply would be able to handle the maximum current (9.0 Amps) demanded by a 5m NeoPixel strip containing a total of 150 LEDs.
 
 


Arduino Libraries and IDE


Before you start to hook up any components, upload the following sketch to the Arduino microcontroller. I am assuming that you already have the Arduino IDE installed on your computer. If not, the IDE can be downloaded from here.
 
The FastLED library is useful for simplifying the code for programming the NeoPixels. The latest "FastLED library" can be downloaded from here. I used FastLED library version 3.0.3 in this project.
 
If you have a different LED strip or your NeoPixels have a different chipset, make sure to change the relevant lines of code to accomodate your hardware. I would suggest you try out a few of the FastLED library examples before using the code below, so that you become more familiar with the library, and will be better equipped to make the necessary changes. If you have a 5 metre length of the NeoPixel 30 LED/m strip with the ws2812B chipset, then you will not have to make any modification below.
 

ARDUINO CODE:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/* ================================================================================================ Project: NeoPixel Heart Beat Display Neopixel chipset: ws2812B (30 LED/m strip) Author: Scott C Created: 8th July 2015 Arduino IDE: 1.6.4 Website: http://arduinobasics.blogspot.com/p/arduino-basics-projects-page.html Description: This sketch will display a heart beat on a 5m Neopixel LED strip. Requires a Grove Ear-clip heart rate sensor and a Neopixel strip. This project makes use of the FastLED library: http://fastled.io/ You may need to modify the code below to accomodate your specific LED strip. See the FastLED library site for more details. ================================================================================================== */ //This project needs the FastLED library - link in the description. #include "FastLED.h" //The total number of LEDs being used is 150 #define NUM_LEDS 150 // The data pin for the NeoPixel strip is connected to digital Pin 6 on the Arduino #define DATA_PIN 6 //Attach the Grove Ear-clip heart rate sensor to digital pin 2 on the Arduino. #define EAR_CLIP 2 //Initialise the LED array CRGB leds[NUM_LEDS]; //Initialise the global variables used to control the LED animation int ledNum = 0; //Keep track of the LEDs boolean beated = false; //Used to identify when the heart has beated int randomR = 0; //randomR used to randomise the fade-out of the LEDs //================================================================================================ // setup() : Is used to initialise the LED strip //================================================================================================ void setup() { FastLED.addLeds<NEOPIXEL,DATA_PIN>(leds, NUM_LEDS); //Set digital pin 2 (Ear-clip heart rate sensor) as an INPUT pinMode(EAR_CLIP, INPUT);} //================================================================================================ // loop() : Take readings from the Ear-clip sensor, and display the animation on the LED strip //================================================================================================ void loop() { //If the Ear-clip sensor moves from LOW to HIGH, call the beatTriggered method if(digitalRead(EAR_CLIP)>0){ //beatTriggered() is only called if the 'beated' variable is false. //This prevents multiple triggers from the same beat. ifbeated){ beatTriggered(); } } else { beated = false; //Change the 'beated' variable to false when the Ear-clip heart rate sensor is reading LOW. } //Fade the LEDs by 1 unit/cycle, when the heart is at 'rest' (i.e. between beats) fadeLEDs(5);} //================================================================================================ // beatTriggered() : This is the LED animation sequence when the heart beats //================================================================================================ void beatTriggered(){ //Ignite 30 LEDs with a red value between 0 to 255 for(int i = 0; i<30; i++){ //The red channel is randomised to a value between 0 to 255 leds[ledNum].r=random8(); FastLED.show(); //Call the fadeLEDs method after every 3rd LED is lit. if(ledNum%3==0){ fadeLEDs(5); } //Move to the next LED ledNum++; //Make sure to move back to the beginning if the animation falls off the end of the strip if(ledNum>(NUM_LEDS-1)){ ledNum=0; } } //Ignite 20 LEDS with a blue value between 0 to 120 for(int i = 0; i<20; i++){ //The blue channel is randomised to a value between 0 to 120 leds[ledNum].b=random8(120); FastLED.show(); //Call the fadeLEDs method after every 3rd LED is lit. if(ledNum%3==0){ fadeLEDs(5); } //Move to the next LED ledNum++; //Make sure to move back to the beginning if the animation falls off the end of the strip if(ledNum>(NUM_LEDS-1)){ ledNum=0; } } //Change the 'beated' variable to true, until the Ear-Clip sensor reads LOW. beated=true;} //================================================================================================ // fadeLEDs() : The fading effect of the LEDs when the Heart is resting (Ear-clip reads LOW) //================================================================================================ void fadeLEDs(int fadeVal){ for (int i = 0; i<NUM_LEDS; i++){ //Fade every LED by the fadeVal amount leds[i].fadeToBlackBy( fadeVal ); //Randomly re-fuel some of the LEDs that are currently lit (1% chance per cycle) //This enhances the twinkling effect. if(leds[i].r>10){ randomR = random8(100); if(randomR<1){ //Set the red channel to a value of 80 leds[i].r=80; //Increase the green channel to 20 - to add to the effect leds[i].g=20; } } } FastLED.show();}


 

NeoPixel Strip connection

The NeoPixel strip is rolled up when you first get it. You will notice that there are wires on both sides of the strip. This allows you to chain LED strips together to make longer strips. The more LEDs you have, the more current you will need. Connect your Arduino and power supply to the left side of the strip, with the arrows pointing to the right. (i.e. the side with the "female" jst connector).
 



NeoPixel Strip Wires

There are 5 wires that come pre-attached to either side of the LED strip.
 

 
You don't have to use ALL FIVE wires, however you will need at least one of each colour: red, white & green.
 

 

Fritzing sketch

The following diagram will show you how to wire everything together
 
(click to enlarge)

Arduino Power considerations

Please note that the Arduino is powered by a USB cable.
If you plan to power the Arduino from your power supply, you will need to disconnect the USB cable from the Arduino FIRST, then connect a wire from the 5V line on the Power supply to the VIN pin on the Arduino. Do NOT connect the USB cable to the Arduino while the VIN wire is connected.
 

 

Large Capacitor

Adafruit also recommend the use of a large capacitor across the + and - terminals of the LED strip to "prevent the initial onrush of current from damaging the pixels". Adafruit recommends a capacitor that is 1000uF, 6.3V or higher. I used a 4700uF 16V Electrolytic Capacitor.
 

 

Resistor on Data Pin

Another recommendation from Adafruit is to place a "300 to 500 Ohm resistor" between the Arduino's data pin and the data input on the first NeoPixel to prevent voltage spikes that can damage the first pixel. I used a 330 Ohm resistor.
 

 

Grove Ear-clip heart rate sensor connection

The Grove Base shield makes it easy to connect Grove modules to the Arduino. If you have a Grove Base shield, you will need to connect the Ear-clip heart rate sensor to Digital pin 2 as per the diagram below.
 

 

Completed construction

Once you have everything connected, you can plug the USB cable into the Arduino, and turn on the LED power supply. Attach the ear-clip to your ear (or to your finger) and allow a few seconds to allow the sensor to register your pulse. The LED strip will light up with every heart beat with an animation that moves from one end of the strip to the other in just three heart beats. When the ear-clip is not connected to your ear or finger, the LEDs should remain off. However, the ear clip may "trigger" a heart beat when opening or closing the clip.
 
Here is a picture of all the components (fully assembled).
 


Concluding comments


This very affordable LED strip allows you to create amazing animations over a greater distance. I thought that having less LEDs per metre would make the animations look "jittery", but I was wrong, they look amazing. One of the good things about this strip is the amount of space between each Neopixel, allowing you to easily cut and join the strip to the size and shape you need.
 
This LED strip is compatible with the FastLED library, which makes for easy LED animation programming. While I used this LED strip to display my heart beat, you could just as easily use it to display the output of any other sensor attached to the Arduino.
 



If you like this page, please do me a favour and show your appreciation :

 
Visit my ArduinoBasics Google + page.
Follow me on Twitter by looking for ScottC @ArduinoBasics.
I can also be found on Pinterest and Instagram.
Have a look at my videos on my YouTube channel.


 
 
             

 
This project would not have been possible without OpenLab's collaborative effort.
Please visit their site for more cool projects.



However, if you do not have a google profile...
Feel free to share this page with your friends in any way you see fit.

NeoPixel Playground


The NeoPixel Digital RGB LED Strip (144 LED/m) is a really impressive product that will have you lighting up your room in next to no time. The 144 individually addressable LEDs packed onto a 1 metre flexible water resistant strip, enables a world of luminescent creativity that will blow your blinking Arduino friends away. The following tutorial will show you how to create an immersive and interactive LED display using an Arduino UNO, a potentiometer and an accelerometer. There will be a total of FIVE LED sequences to keep you entertained or you can create your own !
 
This tutorial was specifically designed to work with the 144 Neopixel Digital RGB LED strip with the ws2812B chipset.

 

Parts Required:

Power Requirements

Before you start any LED strip project, the first thing you will need to think about is POWER. According to the Adafruit website, each individual NeoPixel LED can draw up to 60 milliamps at maximum brightness - white. Therefore the amount of current required for the entire strip will be way more than your Arduino can handle. If you try to power this LED strip directly from your Arduino, you run the risk of damaging not only your Arduino, but your USB port as well. The Arduino will be used to control the LED strip, but the LED strip will need to be powered by a separate power supply. The power supply you choose to use is important. It must provide the correct voltage, and must able to supply sufficient current.
 

Operating Voltage(5V)

The operating voltage of the NeoPixel strip is 5 volts DC. Excessive voltage will damage/destroy your NeoPixels.

Current requirements (8.6 Amps)

OpenLab recommend the use of a 5V 10A power supply. Having more Amps is OK, providing the output voltage is 5V DC. The LEDs will only draw as much current as they need. To calculate the amount of current this 1m strip can draw with all LEDs turned on at full brightness - white:

144 NeoPixel LEDs x 60 mA x 1 m = 8640 mA = 8.64 Amps for a 1 metre strip.

Therefore a 5V 10A power supply would be able to handle the maximum current (8.6 Amps) demanded by a single 1m NeoPixel strip of 144 LEDs.
 
 

Arduino Libraries and IDE


Before you start to hook up any components, upload the following sketch to the Arduino microcontroller. I am assuming that you already have the Arduino IDE installed on your computer. If not, the IDE can be downloaded from here.
 
The FastLED library is useful for simplifying the code for programming the NeoPixels. The latest "FastLED library" can be downloaded from here. I used FastLED library version 3.0.3 in this project.
 
If you have a different LED strip or your NeoPixels have a different chipset, make sure to change the relevant lines of code to accomodate your hardware. I would suggest you try out a few of the FastLED library examples before using the code below, so that you become more familiar with the library, and will be better equipped to make the necessary changes. If you have a single 144 NeoPixel LED/m strip with the ws2812B chipset, then you will not have to make any modifications below (unless you want to).
 

ARDUINO CODE:


 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318



/* ==================================================================================================================================================
         Project: NeoPixel Playground
Neopixel chipset: ws2812B  (144 LED/m strip)
          Author: Scott C
         Created: 12th June 2015
     Arduino IDE: 1.6.4
         Website: http://arduinobasics.blogspot.com/p/arduino-basics-projects-page.html
     Description: This project will allow you to cycle through and control five LED
                  animation sequences using a potentiometer and an accelerometer
                     Sequence 1:   Cylon with Hue Control                                       Control: Potentiometer only
                     Sequence 2:   Cylon with Brightness Control                                Control: Potentiometer only
                     Sequence 3:   Comet effect with Hue and direction control                  Control: Potentiometer and Accelerometer (Y axis only)
                     Sequence 4:   FireStarter / Rainbow effect with Hue and Direction control  Control: Potentiometer and Accelerometer (Y axis only)
                     Sequence 5:   Digital Spirit Level                                         Control: Accelerometer only (Y axis)
            
                  This project makes use of the FastLED library. Some of the code below was adapted from the FastLED library examples (eg. Cylon routine).
                  The Comet, FireStarter and Digital Spirit Level sequence was designed by ScottC.
                  The FastLED library can be found here: http://fastled.io/
                  You may need to modify the code below to accomodate your specific LED strip. See the FastLED library site for more details.
===================================================================================================================================================== */

//This project needs the FastLED library - link in the description.
#include "FastLED.h"

//The total number of LEDs being used is 144
#define NUM_LEDS 144

// The data pin for the NeoPixel strip is connected to digital Pin 6 on the Arduino
#define DATA_PIN 6

//Initialise the LED array, the LED Hue (ledh) array, and the LED Brightness (ledb) array.
CRGB leds[NUM_LEDS];
byte ledh[NUM_LEDS];
byte ledb[NUM_LEDS];

//Pin connections
const int potPin = A0; // The potentiometer signal pin is connected to Arduino's Analog Pin 0
const int yPin = A4; // Y pin on accelerometer is connected to Arduino's Analog Pin 4
                            // The accelerometer's X Pin and the Z Pin were not used in this sketch

//Global Variables ---------------------------------------------------------------------------------
byte potVal; // potVal: stores the potentiometer signal value
byte prevPotVal=0; // prevPotVal: stores the previous potentiometer value
int LEDSpeed=1; // LEDSpeed: stores the "speed" of the LED animation sequence
int maxLEDSpeed = 50; // maxLEDSpeed: identifies the maximum speed of the LED animation sequence
int LEDAccel=0; // LEDAccel: stores the acceleration value of the LED animation sequence (to speed it up or slow it down)
int LEDPosition=72; // LEDPosition: identifies the LED within the strip to modify (leading LED). The number will be between 0-143. (Zero to NUM_LEDS-1)
int oldPos=0; // oldPos: holds the previous position of the leading LED
byte hue = 0; // hue: stores the leading LED's hue value
byte intensity = 150; // intensity: the default brightness of the leading LED
byte bright = 80; // bright: this variable is used to modify the brightness of the trailing LEDs
int animationDelay = 0; // animationDelay: is used in the animation Speed calculation. The greater the animationDelay, the slower the LED sequence.
int effect = 0; // effect: is used to differentiate and select one out of the four effects
int sparkTest = 0; // sparkTest: variable used in the "sparkle" LED animation sequence
boolean constSpeed = false; // constSpeed: toggle between constant and variable speed.


//===================================================================================================================================================
// setup() : Is used to initialise the LED strip
//===================================================================================================================================================
void setup() {
    delay(2000); //Delay for two seconds to power the LEDS before starting the data signal on the Arduino
    FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS); //initialise the LED strip
}


//===================================================================================================================================================
// loop() : The Arduino will take readings from the potentiometer and accelerometer to control the LED strip
//===================================================================================================================================================
void loop(){
  readPotentiometer();           
  adjustSpeed();
  constrainLEDs();
 
  switch(effect){
    case 0: // 1st effect : Cylon with Hue control - using Potentiometer
      cylonWithHueControl();
      break;
      
    case 1: // 2nd effect : Cylon with Brightness control - using Potentiometer
      cylonWithBrightnessControl();
      break;
      
    case 2: // 3rd effect : Comet effect. Hue controlled by potentiometer, direction by accelerometer
      cometEffect();
      break;
      
    case 3: // 4th effect : FireStarter / Rainbow Sparkle effect. Direction controlled by accelerometer, sparkle by potentiometer.
      fireStarter(); 
      break;
    
    case 4:
      levelSense();                                        // 5th effect : LevelSense - uses the accelerometer to create a digital "spirit" level.
      break;
  }
}


//===================================================================================================================================================
// readPotentiometer() : Take a potentiometer reading. This value will be used to control various LED animations, and to choose the animation sequence to display.
//===================================================================================================================================================
void readPotentiometer(){
  //Take a reading from the potentiometer and convert the value into a number between 0 and 255
  potVal = map(analogRead(potPin), 0, 1023 , 0, 255);
  
  // If the potentiometer reading is equal to zero, then move to the next effect in the list.
  if(potVal==0){
    if(prevPotVal>0){ // This allows us to switch effects only when the potentiometer reading has changed to zero (from a positive number). Multiple zero readings will be ignored.
      prevPotVal = 0;   // Set the prev pot value to zero in order to ignore replicate zero readings.
      effect++;         // Go to the next effect.
      if(effect>4){
        effect=0;       // Go back to the first effect after the fifth effect.
      }
    }
  }
  prevPotVal=potVal;    // Keep track of the previous potentiometer reading
}


//===================================================================================================================================================
// adjustSpeed() : use the Y axis value of the accelerometer to adjust the speed and the direction of the LED animation sequence
//===================================================================================================================================================
void adjustSpeed(){
  // Take a reading from the Y Pin of the accelerometer and adjust the value so that
  // positive numbers move in one direction, and negative numbers move in the opposite diraction.
  // We use the map function to convert the accelerometer readings, and the constrain function to ensure that it stays within the desired limits
  // The values of 230 and 640 were determined by trial and error and are specific to my accelerometer. You will need to adjust these numbers to suit your module.
  
  LEDAccel = constrain(map(analogRead(yPin), 230, 640 , maxLEDSpeed, -maxLEDSpeed),-maxLEDSpeed, maxLEDSpeed);
  
  
  // If the constSpeed variable is "true", then make sure that the speed of the animation is constant by modifying the LEDSpeed and LEDAccel variables.
  if(constSpeed){
    LEDAccel=0; 
    if(LEDSpeed>0){
      LEDSpeed = maxLEDSpeed/1.1;     // Adjust the LEDSpeed to half the maximum speed in the positive direction
    } 
    if (LEDSpeed<0){
      LEDSpeed = -maxLEDSpeed/1.1;    // Adjust the LEDSpeed to half the maximum speed in the negative direction
    }
  } 
 
  // The Speed of the LED animation sequence can increase (accelerate), decrease (decelerate) or stay the same (constant speed)
  LEDSpeed = LEDSpeed + LEDAccel;                        
  
  //The following lines of code are used to control the direction of the LED animation sequence, and limit the speed of that animation.
  if (LEDSpeed>0){
    LEDPosition++;                                       // Illuminate the LED in the Next position
    if (LEDSpeed>maxLEDSpeed){
      LEDSpeed=maxLEDSpeed;                              // Ensure that the speed does not go beyond the maximum speed in the positive direction
    }
  }
  
  if (LEDSpeed<0){
    LEDPosition--;                                       // Illuminate the LED in the Prior position
    if (LEDSpeed<-maxLEDSpeed){
      LEDSpeed = -maxLEDSpeed;                           // Ensure that the speed does not go beyond the maximum speed in the negative direction
    }
  }
}


//===================================================================================================================================================
// constrainLEDs() : This ensures that the LED animation sequence remains within the boundaries of the various arrays (and the LED strip)
//                   and it also creates a "bouncing" effect at both ends of the LED strip.
//===================================================================================================================================================
void constrainLEDs(){
  LEDPosition = constrain(LEDPosition, 0, NUM_LEDS-1); // Make sure that the LEDs stay within the boundaries of the LED strip
  if(LEDPosition == 0 || LEDPosition == NUM_LEDS-1) {
    LEDSpeed = (LEDSpeed * -0.9);                         // Reverse the direction of movement when LED gets to end of strip. This creates a bouncing ball effect.
  }
}



//===================================================================================================================================================
// cylonWithHueControl() :  This is the 1st LED effect. The cylon colour is controlled by the potentiometer. The speed is constant.
//===================================================================================================================================================
void cylonWithHueControl(){
      constSpeed = true; // Make the LED animation speed constant
      showLED(LEDPosition, potVal, 255, intensity);       // Illuminate the LED
      fadeLEDs(8);                                        // Fade LEDs by a value of 8. Higher numbers will create a shorter tail.
      setDelay(LEDSpeed);                                 // The LEDSpeed is constant, so the delay is constant
}


//===================================================================================================================================================
// cylonWithBrightnessControl() : This is the 2nd LED effect. The cylon colour is red (hue=0), and the brightness is controlled by the potentiometer
//===================================================================================================================================================
void cylonWithBrightnessControl(){
      constSpeed = true; // Make speed constant
      showLED(LEDPosition, 0, 255, potVal);               // Brightness is controlled by potentiometer.
      fadeLEDs(16);                                       // Fade LEDs by a value of 16
      setDelay(LEDSpeed);                                 // The LEDSpeed is constant, so the delay is constant
}


//===================================================================================================================================================
// cometEffect() :  This is the 3rd LED effect. The random brightness of the trailing LEDs produces an interesting comet-like effect.
//===================================================================================================================================================
void cometEffect(){
      constSpeed = false; // The speed will be controlled by the slope of the accelerometer (y-Axis)
      showLED(LEDPosition, potVal, 255, intensity);        // Hue will change with potentiometer.
      
      //The following lines create the comet effect
      bright = random(50, 100); // Randomly select a brightness between 50 and 100
      leds[LEDPosition] = CHSV((potVal+40),255, bright); // The trailing LEDs will have a different hue to the leading LED, and will have a random brightness
      fadeLEDs(8);                                         // This will affect the length of the Trailing LEDs
      setDelay(LEDSpeed);                                  // The LEDSpeed will be affected by the slope of the Accelerometer's y-Axis
}


//===================================================================================================================================================
// fireStarter() : This is the 4th LED effect. It starts off looking like a ball of fire, leaving a trail of little fires. But as you
//                 turn the potentiometer, it becomes more like a shooting star with a rainbow-sparkle trail.
//===================================================================================================================================================
void fireStarter(){
      constSpeed = false; // The speed will be controlled by the slope of the accelerometer (y-Axis)
      ledh[LEDPosition] = potVal;                          // Hue is controlled by potentiometer
      showLED(LEDPosition, ledh[LEDPosition], 255, intensity); 
      
      //The following lines create the fire starter effect
      bright = random(50, 100); // Randomly select a brightness between 50 and 100
      ledb[LEDPosition] = bright;                          // Assign this random brightness value to the trailing LEDs
      sparkle(potVal/5);                                   // Call the sparkle routine to create that sparkling effect. The potentiometer controls the difference in hue from LED to LED.
      fadeLEDs(1);                                         // A low number creates a longer tail
      setDelay(LEDSpeed);                                  // The LEDSpeed will be affected by the slope of the Accelerometer's y-Axis
}


//===================================================================================================================================================
// levelSense() : This is the 5th and final LED effect. The accelerometer is used in conjunction with the LED strip to create a digital "Spirit" Level.
//                You can use the illuminated LEDs to identify the angle of the LED strip
//===================================================================================================================================================
void levelSense(){
      constSpeed = true;
      LEDPosition = constrain(map(analogRead(yPin), 230, 640, 1, NUM_LEDS-1), 0 , NUM_LEDS-1);
      
      //Jitter correction: this will reduce the amount of jitter caused by the accelerometer reading variability
      if(abs(LEDPosition-oldPos) < 2){
        LEDPosition = oldPos;
      }
      
      //The following lines of code will ensure the colours remain within the red to green range, with green in the middle and red at the ends.
      hue = map(LEDPosition, 0, NUM_LEDS-1, 0, 200);
      if (hue>100){
         hue = 200 - hue;
      }
      
      //Illuminate 2 LEDs next to each other
      showLED(LEDPosition, hue, 255, intensity); 
      showLED(LEDPosition-1, hue, 255, intensity);              
      
      //If the position moves, then fade the old LED positions by a factor of 25 (high numbers mean shorter tail)
      fadeLEDs(25);                               
      oldPos = LEDPosition; 
}


//===================================================================================================================================================
// fadeLEDs(): This function is used to fade the LEDs back to black (OFF) 
//===================================================================================================================================================
void fadeLEDs(int fadeVal){
  for (int i = 0; i<NUM_LEDS; i++){
    leds[i].fadeToBlackBy( fadeVal );
  }
}



//===================================================================================================================================================
// showLED() : is used to illuminate the LEDs 
//===================================================================================================================================================
void showLED(int pos, byte LEDhue, byte LEDsat, byte LEDbright){
  leds[pos] = CHSV(LEDhue,LEDsat,LEDbright);
  FastLED.show();
}


//===================================================================================================================================================
// setDelay() : is where the speed of the LED animation sequence is controlled. The speed of the animation is controlled by the LEDSpeed variable.
//              and cannot go faster than the maxLEDSpeed variable.
//===================================================================================================================================================
void setDelay(int LSpeed){
  animationDelay = maxLEDSpeed - abs(LSpeed);
  delay(animationDelay);
}


//===================================================================================================================================================
// sparkle() : is used by the fireStarter routine to create a sparkling/fire-like effect
//             Each LED hue and brightness is monitored and modified using arrays  (ledh[]  and ledb[])
//===================================================================================================================================================
void sparkle(byte hDiff){
  for(int i = 0; i < NUM_LEDS; i++) {
    ledh[i] = ledh[i] + hDiff;                // hDiff controls the extent to which the hue changes along the trailing LEDs
    
    // This will prevent "negative" brightness.
    if(ledb[i]<3){
      ledb[i]=0;
    }
    
    // The probability of "re-igniting" an LED will decrease as you move along the tail
    // Once the brightness reaches zero, it cannot be re-ignited unless the leading LED passes over it again.
    if(ledb[i]>0){
      ledb[i]=ledb[i]-2;
      sparkTest = random(0,bright);
      if(sparkTest>(bright-(ledb[i]/1.1))){
        ledb[i] = bright;
      } else {
        ledb[i] = ledb[i] / 2;                  
      }
    }
    leds[i] = CHSV(ledh[i],255,ledb[i]);
  }
}


 

NeoPixel Strip connection

The NeoPixel strip is rolled up when you first get it. You will notice that there are wires on both sides of the strip. This allows you to chain LED strips together to make longer strips. The more LEDs you have, the more current you will need. Connect your Arduino and power supply to the left side of the strip, with the arrows pointing to the right side of the strip.
 

Follow the Arrows

The arrows are quite hard to see on this particular LED strip because they are so small, plus they are located right under the thicker part of the NeoPixel weatherproof sheath. I have circled the arrows in RED so that you know where to look:

 


NeoPixel Strip Wires

There are 4 wires coming from either side of the NeoPixel LED strip:
 
  One red wire, one white wire, and two black wires.
 
It doesn't matter which Black wire you use to connect to the power supply (or Arduino) GND. Both black wires appear to be going to the same pin on the LED strip anyway. Use the table below to make the necessary NeoPixel Strip connections to the Arduino and power supply.


Large Capacitor

Adafruit also recommend the use of a large capacitor across the + and - terminals of the LED strip to "prevent the initial onrush of current from damaging the pixels". Adafruit recommends a capacitor that is 1000uF, 6.3V or higher. I used a 4700uF 16V Electrolytic Capacitor.

Resistor on Data Pin

Another recommendation from Adafruit is to place a "300 to 500 Ohm resistor" between the Arduino's data pin and the data input on the first NeoPixel to prevent voltage spikes that can damage the first pixel. I used a 330 Ohm resistor.
 

Powering your Arduino (USB vs Power supply)

You can power your Arduino board via USB cable or via the LED strip power supply.
*** Please note: different power supplies will yield different accelerometer readings. I noticed this when changing the Arduino's power source from USB to LED power supply. My final sketch was designed to eliminate the USB/computer connection, hence I have chosen to power the Arduino via the power supply. The fritzing sketch below shows the Arduino being powered by a power supply only.

**WARNING: If you decide to power your Arduino UNO via a USB cable, please make sure to remove (or disconnect) the wire that goes to the the Arduino VIN pin. The GND connections remain unchanged.


Fritzing Sketch - NeoPixel strip connection


 

Potentiometer connection

The potentiometer will be used to switch between the different LED sequences. When it reads zero, it will switch to the next sequence in the list. It will jump right back to the beginning after the last sequence. The potentiometer is also used to interact with the LEDs (e.g. controlling hue, brightness etc etc).
See the fritzing sketch below to add the potentiometer to this project.



 

Accelerometer connection (Y-axis)

The accelerometer makes the LEDs much more fun and interactive. We will only be using the Y-axis of the accelerometer in this sketch. By tilting the accelerometer from one side to the other, the LEDs react and respond accordingly. The accelerometer is an essential component of the digital spirit level sequence. That's right ! You can use this sketch to create your own spirit level. This digital version can also be used to measure angles !
 
Have a look below to see how to hook up the accelerometer to the Arduino. The Y-axis is connected to the Arduino analog pin 4. If you wanted to use the X and Z axis, connect them to one of the other available analog pins (eg. A3 and A5).




 

Let the fun begin !!

Now that you have the Arduino code uploaded to the Arduino, and have made all of the necessary wire/component connections, it is time to turn on the power supply.
 

Sequence 1: Cylon with Hue control

The LEDs will move from one end of the strip to the other. It should start off as a RED cylon effect. As you turn the potentiometer clockwise, the colour of the LEDs will change and move through the various colours of the rainbow. If the potentiometer reading gets back to zero (fully anti-clockwise), it will move to sequence 2.
 

Sequence 2: Cylon with brightness control

You will see that the LEDs have turned off. The potentiometer readings correlate with the LED brightness. At the start of this sequence, the potentiometer readings will be zero, therefore the brightness will be zero (LEDs turned off). As you turn the potentiometer clockwise, the readings increase, and so will the brightness of the LEDs.
 

Sequence 3: Comet effect with Hue and direction control

This is where the real fun begins. You control the hue of the leading LED with the potentiometer, however the LED will move along the LED strip as though it were affected by gravity. As it hits the end of the LED strip, it will bounce for a while and eventually come to a stop. The more you tilt the accelerometer, the greater the acceleration of the leading LED. The trailing LEDs have an interesting randomised glow, which creates the "comet" effect.
 

Sequence 4: FireStarter / Rainbow effect : Hue and direction control

The initial colours of LEDs in this sequence creates a fire-like animation. As the leading LED moves along the LED strip, it appears to ignite the LEDs in its path, leaving a fire trail behind it. The fire effect is best when you turn the potentiometer clockwise slightly to introduce a small amount of yellow into the mix of colours. As you turn the potentiometer further clockwise, the fire trail turns into a pretty rainbow trail. The accelerometer affects the leading LED in the same way as the previous sequence.
 

Sequence 5: Digital spirit level

This sequence was my original idea for this project, however I thought it would be nice to share some of the other cool effects I created on my journey of discovery. The idea was to make a digital version of a spirit level. I originally wanted the LEDs to represent a spirit level bubble that would "float" according to the vertical/horizontal position of the LED strip. However, as I played around with this sketch, I discovered that it could potentially be used to measure the angle of the strip relative to the horizon. The angle can be determined by the illuminated LED. If the strip is horizontal, the illuminated LEDs will be close to the middle of the strip, and their colour will be green. If the strip is vertical, the illuminated LEDs will be close to end of the strip, and their colour will be red. The colour is just an additional visual indicator.
 


Concluding Comments

The NeoPixel Digital RGB LED strip is a lot of fun. The FastLED library makes for easy programming, and allows you to get up and running really quickly. 144 LEDs on a single strip means you have plenty of room for creative algorithms and lighting effects. Add a few sensors, and "pretty" quickly turns into "awesome" !!
 
This tutorial shows you how to control a "144 NeoPixel per metre Digital RGB LED strip" with an Arduino UNO. Feel free to share your own LED creations in the comments below.



If you like this page, please do me a favour and show your appreciation :

 
Visit my ArduinoBasics Google + page.
Follow me on Twitter by looking for ScottC @ArduinoBasics.
I can also be found on Pinterest and Instagram.
Have a look at my videos on my YouTube channel.


 
 
             

This project would not have been possible without the collaborative effort from OpenLab.
Please visit their site for more cool projects.



However, if you do not have a google profile...
Feel free to share this page with your friends in any way you see fit.

Send HEX values to Arduino

FIVE MINUTE TUTORIAL

Project Description: Sending Hex values to an Arduino UNO


This simple tutorial will show you how to send Hexadecimal values from a computer to an Arduino Uno. The "Processing" programming language will be used to send the HEX values from the computer when a mouse button is pressed. The Arduino will use these values to adjust the brightness of an LED.



 

Learning Objectives


  • To Send Hexadecimal (Hex) values from a computer to the Arduino
  • Trigger an action based on the press of a mouse button
  • Learn to create a simple Computer to Arduino interface
  • Use Arduino's PWM capabilities to adjust brightness of an LED
  • Learn to use Arduino's analogWrite() function
  • Create a simple LED circuit


 

Parts Required:


Fritzing Sketch


The diagram below will show you how to connect an LED to Digital Pin 10 on the Arduino.
Don't forget the 330 ohm resistor !
 


 
 

Arduino Sketch


The latest version of Arduino IDE can be downloaded here.
 
  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* ==================================================================================================================================================
         Project: 5 min tutorial: Send Hex from computer to Arduino
          Author: Scott C
         Created: 21th June 2015
     Arduino IDE: 1.6.4
         Website: http://arduinobasics.blogspot.com/p/arduino-basics-projects-page.html
     Description: Arduino Sketch used to adjust the brightness of an LED based on the values received
                  on the serial port. The LED needs to be connected to a PWM pin. In this sketch
                  Pin 10 is used, however you could use Pin 3, 5, 6, 9, or 11 - if you are using an Arduino Uno.
===================================================================================================================================================== */

byte byteRead; //Variable used to store the byte received on the Serial Port
int ledPin = 10; //LED is connected to Arduino Pin 10. This pin must be PWM capable.

void setup() {
 Serial.begin(9600); //Initialise Serial communication with the computer
 pinMode(ledPin, OUTPUT); //Set Pin 10 as an Output pin
 byteRead = 0;                   //Initialise the byteRead variable to zero.
}

void loop() {
  if(Serial.available()) {
    byteRead = Serial.read(); //Update the byteRead variable with the Hex value received on the Serial COM port.
  }
  
  analogWrite(ledPin, byteRead); //Use PWM to adjust the brightness of the LED. Brightness is determined by the "byteRead" variable.
}


 


 
 

Processing Sketch


The latest version of the Processing IDE can be downloaded here.
 
  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/* ==================================================================================================================================================
         Project: 5 min tutorial: Send Hex from computer to Arduino
          Author: Scott C
         Created: 21th June 2015
  Processing IDE: 2.2.1
         Website: http://arduinobasics.blogspot.com/p/arduino-basics-projects-page.html
     Description: Processing Sketch used to send HEX values from computer to Arduino when the mouse is pressed.
                  The alternating values 0xFF and 0x00 are sent to the Arduino Uno to turn an LED on and off.
                  You can send any HEX value from 0x00 to 0xFF. This sketch also shows how to convert Hex strings
                  to Hex numbers.
===================================================================================================================================================== */

import processing.serial.*; //This import statement is required for Serial communication

Serial comPort;                       //comPort is used to write Hex values to the Arduino
boolean toggle = false; //toggle variable is used to control which hex variable to send
String zeroHex = "00"; //This "00" string will be converted to 0x00 and sent to Arduino to turn LED off.
String FFHex = "FF"; //This "FF" string will be converted to 0xFF and sent to Arduino to turn LED on.

void setup(){
    comPort = new Serial(this, Serial.list()[0], 9600); //initialise the COM port for serial communication at a baud rate of 9600.
    delay(2000);                      //this delay allows the com port to initialise properly before initiating any communication.
    background(0); //Start with a black background.
    
}


void draw(){ //the draw() function is necessary for the sketch to compile
    //do nothing here //even though it does nothing.
}


void mousePressed(){ //This function is called when the mouse is pressed within the Processing window.
  toggle = ! toggle;                   //The toggle variable will change back and forth between "true" and "false"
  if(toggle){ //If the toggle variable is TRUE, then send 0xFF to the Arduino
     comPort.write(unhex(FFHex)); //The unhex() function converts the "FF" string to 0xFF
     background(0,0,255); //Change the background colour to blue as a visual indication of a button press.
  } else {
    comPort.write(unhex(zeroHex)); //If the toggle variable is FALSE, then send 0x00 to the Arduino
    background(0); //Change the background colour to black as a visual indication of a button press.
  }
}


 

The Video


 

The tutorial above is a quick demonstration of how to convert Hex strings on your computer and send them to an Arduino. The Arduino can use the values to change the brightness of an LED as shown in this tutorial, however you could use it to modify the speed of a motor, or to pass on commands to another module. Hopefully this short tutorial will help you with your project. Please let me know how it helped you in the comments below.

 
 



If you like this page, please do me a favour and show your appreciation :

 
Visit my ArduinoBasics Google + page.
Follow me on Twitter by looking for ScottC @ArduinoBasics.
I can also be found on Pinterest and Instagram.
Have a look at my videos on my YouTube channel.


 
 
             


 
 



However, if you do not have a google profile...
Feel free to share this page with your friends in any way you see fit.

CH376S USB Read/Write module

Have you ever wondered if there was a way to store and retrieve data from a USB stick with an Arduino UNO? Most people choose SD cards to store their project data, but you may be surprised there IS a way!
IC Station have a nice little module which allows you store and retrieve your Arduino (or other MCU) project data to a USB stick.
 
I am not too sure why USB storage is not widely used in Arduino projects? These modules are not expensive, they have been around for quite a while, and are relatively simple to use. You do not need any libraries to get them to work, however, I must say that documentation for this module is not that easy to find. This site and this document proved to be very useful in my endevour to get this module working, and I hope my tutorial below will help you get started and bridge some of the information gaps.
 
The "CH376S USB read/write module" has a CH376S chip onboard which does most of the hard work for you. All you have to do is send the module some commands from the Arduino and the CH376S chip will do the rest. You can communicate with the module in three different ways:

  • Parallel communication
  • SPI communication
  • and Serial (UART) communication.

This project will show you the connections and code for the Serial (UART) communication method only.


 

Parts Required:

Remove the Jumper

When the CH376S USB module arrives in it's package, it will have a jumper between the TXD pin and GND. You will need to remove this jumper to make the necessary connections between the Arduino UNO and the CH376S USB module.


 

Fritzing Sketch

Please note, that the Arduino Sketch makes use of the Arduino UNO's onboard LED on digital pin 13. The Fritzing sketch below shows an LED + 300 ohm resistor on a breadboard. This is optional. The LED is not a necessary component of CH376S module communication.

Also be aware that the CH376S USB module has an onboard LED just above the TXD and GND pins near the USB port. This LED will only turn on providing the CH376S module is in USB mode AND a USB device has been inserted into the USB port. Both conditions must be met before the module's onboard LED will illuminate. You will not see the LED turn on just by powering the board.
 
The wire diagram below is the correct setup for Serial communication between an Arduino UNO and the CH376S module. If you wish to use SPI or Parallel communication, you will need to refer to the datasheet.


 
 

Arduino Sketch


 
  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505

/* ===============================================================
      Project: CH376S USB Read/Write Module testing ground
       Author: Scott C
      Created: 1st May 2015
  Arduino IDE: 1.6.2
      Website: http://arduinobasics.blogspot.com/p/arduino-basics-projects-page.html
  Description: This project will allow you to perform many of the functions available on the CH376S module.
               Checking connection to the module, putting the module into USB mode, resetting the module, 
               reading, writing, appending text to files on the USB stick. This is very useful alternative to
               SD card modules, plus it doesn't need any libraries.
================================================================== */

#include <SoftwareSerial.h>

byte computerByte; //used to store data coming from the computer
byte USB_Byte; //used to store data coming from the USB stick
int LED = 13; //the LED is connected to digital pin 13
int timeOut = 2000; //TimeOut is 2 seconds. This is the amount of time you wish to wait for a response from the CH376S module.
String wrData = "What is the meaning of life ?"; //We will write this data to a newly created file.
String wrData2 = "42"; //We will append this data to an already existing file.

SoftwareSerial USB(10, 11); // Digital pin 10 on Arduino (RX) connects to TXD on the CH376S module
                                                      // Digital pin 11 on Arduino (TX) connects to RXD on the CH376S module
                                                      // GND on Arduino to GND on CH376S module
                                                      // 5V on Arduino to 5V on CH376S module
//==============================================================================================================================================
void setup() {
  Serial.begin(9600); // Setup serial communication with the computer (using a baud rate of 9600 on serial monitor)
  USB.begin(9600); // Setup serial communication with the CH376S module (using the default baud rate of 9600)
  pinMode(LED,OUTPUT); // Define digital pin 13 as an OUTPUT pin - so that we can use it with an LED
  digitalWrite(LED,LOW); // Turn off the LED
}

//================================================================================================================================================
void loop() {
  if(Serial.available()){
    computerByte = Serial.read(); //read any incoming bytes from the Serial monitor, and store this byte in the variable called computerByte
    if(computerByte==49){ //1 //If you send the number 1 from the serial monitor, the arduino will read it as digital number 49. Google "ascii table" for more info.
      printCommandHeader("COMMAND1: CHECK CONNECTION");
      checkConnection(0x01);                           // Check for successful connection and communication with the CH376S module.
    } 
    if(computerByte==50){ //2
     printCommandHeader("COMMAND2: set_USB_Mode");
      set_USB_Mode(0x06);                              // Code used to enable read/write communication and monitoring of the USB stick
    }
    if(computerByte==51){ //3
      printCommandHeader("COMMAND3: resetALL");
      resetALL();                                      // Reset the USB device
    }
    if(computerByte==52){ //4
      printCommandHeader("COMMAND4: Create and Write to File : TEST4.TXT");
      writeFile("TEST4.TXT", wrData); // Create a file called TEST4.TXT and then Write the contents of wrData to this file
    }
    if(computerByte==53){ //5
      printCommandHeader("COMMAND5: Read File: TEST4.TXT");
      readFile("TEST4.TXT"); // Read the contents of this file on the USB disk, and display contents in the Serial Monitor
    }
    if(computerByte==54){ //6
      printCommandHeader("COMMAND6: Append data to file: TEST4.TXT");
      appendFile("TEST4.TXT", wrData2); // Append data to the end of the file.
    }
    if(computerByte==55){ //7
      printCommandHeader("COMMAND7: Delete File: TEST4.TXT");
      fileDelete("TEST4.TXT"); // Delete the file named TEST4.TXT
    }
    if(computerByte==56){ //8
      printCommandHeader("COMMAND8: Read File: TEST2.TXT");
      readFile("TEST2.TXT"); // Read the contents of the TEST2.TXT file on the USB disk, and display contents in the Serial Monitor
    }
    if(computerByte==57){ //9
      printCommandHeader("COMMAND9: Read File: TEST3.TXT");
      readFile("TEST3.TXT"); // Read the contents of the TEST3.TXT file on the USB disk, and display contents in the Serial Monitor
    }
  }
  
  if(USB.available()){ // This is here to capture any unexpected data transmitted by the CH376S module
    Serial.print("CH376S has just sent this code:");
    Serial.println(USB.read(), HEX);
  }
}

//END OF LOOP FUNCTION ========================================================================================================================================

//print Command header
void printCommandHeader(String header){
   Serial.println("======================");
   Serial.println("");
   Serial.println(header);
   Serial.println("----------------------");
}

//checkConnection==================================================================================
//This function is used to check for successful communication with the CH376S module. This is not dependant of the presence of a USB stick.
//Send any value between 0 to 255, and the CH376S module will return a number = 255 - value. 
void checkConnection(byte value){
  USB.write(0x57);
  USB.write(0xAB);
  USB.write(0x06);
  USB.write(value);
  
  if(waitForResponse("checking connection")){ //wait for a response from the CH376S. If CH376S responds, it will be true. If it times out, it will be false.
    if(getResponseFromUSB()==(255-value)){
       Serial.println(">Connection to CH376S was successful.");
       blinkLED();                               //blink the LED for 1 second if the connection was successful
    } else {
      Serial.print(">Connection to CH376S - FAILED.");
    }
  }
}

//set_USB_Mode=====================================================================================
//Make sure that the USB is inserted when using 0x06 as the value in this specific code sequence
void set_USB_Mode (byte value){
  USB.write(0x57);
  USB.write(0xAB);
  USB.write(0x15);
  USB.write(value);
  
  delay(20);
  
  if(USB.available()){
    USB_Byte=USB.read();
    //Check to see if the command has been successfully transmitted and acknowledged.
    if(USB_Byte==0x51){ // If true - the CH376S has acknowledged the command.
        Serial.println("set_USB_Mode command acknowledged"); //The CH376S will now check and monitor the USB port
        USB_Byte = USB.read();
        
        //Check to see if the USB stick is connected or not.
        if(USB_Byte==0x15){ // If true - there is a USB stick connected
          Serial.println("USB is present");
          blinkLED();                                     // If the process was successful, then turn the LED on for 1 second
        } else {
          Serial.print("USB Not present. Error code:"); // If the USB is not connected - it should return an Error code = FFH
          Serial.print(USB_Byte, HEX);
          Serial.println("H");
        }
        
    } else {
        Serial.print("CH3765 error! Error code:");
        Serial.print(USB_Byte, HEX);
        Serial.println("H");
    }   
  }
  delay(20);
}

//resetALL=========================================================================================
//This will perform a hardware reset of the CH376S module - which usually takes about 35 msecs =====
void resetALL(){
    USB.write(0x57);
    USB.write(0xAB);
    USB.write(0x05);
    Serial.println("The CH376S module has been reset !");
    delay(200);
}

//readFile=====================================================================================
//This will send a series of commands to read data from a specific file (defined by fileName)
void readFile(String fileName){
  resetALL();                     //Reset the module
  set_USB_Mode(0x06);             //Set to USB Mode
  diskConnectionStatus();         //Check that communication with the USB device is possible
  USBdiskMount();                 //Prepare the USB for reading/writing - you need to mount the USB disk for proper read/write operations.
  setFileName(fileName);          //Set File name
  fileOpen();                     //Open the file for reading
  int fs = getFileSize(); //Get the size of the file
  fileRead();                     //***** Send the command to read the file ***
  fileClose(0x00);                //Close the file
}

//writeFile========================================================================================
//is used to create a new file and then write data to that file. "fileName" is a variable used to hold the name of the file (e.g TEST.TXT). "data" should not be greater than 255 bytes long. 
void writeFile(String fileName, String data){
  resetALL();                     //Reset the module
  set_USB_Mode(0x06);             //Set to USB Mode
  diskConnectionStatus();         //Check that communication with the USB device is possible
  USBdiskMount();                 //Prepare the USB for reading/writing - you need to mount the USB disk for proper read/write operations.
  setFileName(fileName);          //Set File name
  if(fileCreate()){ //Try to create a new file. If file creation is successful
    fileWrite(data);              //write data to the file.
  } else {
    Serial.println("File could not be created, or it already exists");
  }
  fileClose(0x01);
}

//appendFile()====================================================================================
//is used to write data to the end of the file, without erasing the contents of the file.
void appendFile(String fileName, String data){
    resetALL();                     //Reset the module
    set_USB_Mode(0x06);             //Set to USB Mode
    diskConnectionStatus();         //Check that communication with the USB device is possible
    USBdiskMount();                 //Prepare the USB for reading/writing - you need to mount the USB disk for proper read/write operations.
    setFileName(fileName);          //Set File name
    fileOpen();                     //Open the file
    filePointer(false); //filePointer(false) is to set the pointer at the end of the file. filePointer(true) will set the pointer to the beginning.
    fileWrite(data);                //Write data to the end of the file
    fileClose(0x01);                //Close the file using 0x01 - which means to update the size of the file on close.
}
  
//setFileName======================================================================================
//This sets the name of the file to work with
void setFileName(String fileName){
  Serial.print("Setting filename to:");
  Serial.println(fileName);
  USB.write(0x57);
  USB.write(0xAB);
  USB.write(0x2F);
  USB.write(0x2F); // Every filename must have this byte to indicate the start of the file name.
  USB.print(fileName); // "fileName" is a variable that holds the name of the file. eg. TEST.TXT
  USB.write((byte)0x00); // you need to cast as a byte - otherwise it will not compile. The null byte indicates the end of the file name.
  delay(20);
}

//diskConnectionStatus================================================================================
//Check the disk connection status
void diskConnectionStatus(){
  Serial.println("Checking USB disk connection status");
  USB.write(0x57);
  USB.write(0xAB);
  USB.write(0x30);

  if(waitForResponse("Connecting to USB disk")){ //wait for a response from the CH376S. If CH376S responds, it will be true. If it times out, it will be false.
    if(getResponseFromUSB()==0x14){ //CH376S will send 0x14 if this command was successful
       Serial.println(">Connection to USB OK");
    } else {
      Serial.print(">Connection to USB - FAILED.");
    }
  }
}

//USBdiskMount========================================================================================
//initialise the USB disk and check that it is ready - this process is required if you want to find the manufacturing information of the USB disk
void USBdiskMount(){
  Serial.println("Mounting USB disk");
  USB.write(0x57);
  USB.write(0xAB);
  USB.write(0x31);

  if(waitForResponse("mounting USB disk")){ //wait for a response from the CH376S. If CH376S responds, it will be true. If it times out, it will be false.
    if(getResponseFromUSB()==0x14){ //CH376S will send 0x14 if this command was successful
       Serial.println(">USB Mounted - OK");
    } else {
      Serial.print(">Failed to Mount USB disk.");
    }
  }
}

//fileOpen========================================================================================
//opens the file for reading or writing
void fileOpen(){
  Serial.println("Opening file.");
  USB.write(0x57);
  USB.write(0xAB);
  USB.write(0x32);
  if(waitForResponse("file Open")){ //wait for a response from the CH376S. If CH376S responds, it will be true. If it times out, it will be false.
    if(getResponseFromUSB()==0x14){ //CH376S will send 0x14 if this command was successful
       Serial.println(">File opened successfully.");
    } else {
      Serial.print(">Failed to open file.");
    }
  }
}

//setByteRead=====================================================================================
//This function is required if you want to read data from the file. 
boolean setByteRead(byte numBytes){
  boolean bytesToRead=false;
  int timeCounter = 0;
  USB.write(0x57);
  USB.write(0xAB);
  USB.write(0x3A);
  USB.write((byte)numBytes); //tells the CH376S how many bytes to read at a time
  USB.write((byte)0x00);
  if(waitForResponse("setByteRead")){ //wait for a response from the CH376S. If CH376S responds, it will be true. If it times out, it will be false.
    if(getResponseFromUSB()==0x1D){ //read the CH376S message. If equal to 0x1D, data is present, so return true. Will return 0x14 if no data is present.
      bytesToRead=true;
    }
  }
  return(bytesToRead);


//getFileSize()===================================================================================
//writes the file size to the serial Monitor.
int getFileSize(){
  int fileSize=0;
  Serial.println("Getting File Size");
  USB.write(0x57);
  USB.write(0xAB);
  USB.write(0x0C);
  USB.write(0x68);
  delay(100);
  Serial.print("FileSize =");
  if(USB.available()){
    fileSize = fileSize + USB.read();
  } 
  if(USB.available()){
    fileSize = fileSize + (USB.read()*255);
  } 
  if(USB.available()){
    fileSize = fileSize + (USB.read()*255*255);
  } 
  if(USB.available()){
    fileSize = fileSize + (USB.read()*255*255*255);
  }     
  Serial.println(fileSize);
  delay(10);
  return(fileSize);
}


//fileRead========================================================================================
//read the contents of the file
void fileRead(){
  Serial.println("Reading file:");
  byte firstByte = 0x00; //Variable to hold the firstByte from every transmission. Can be used as a checkSum if required.
  byte numBytes = 0x40; //The maximum value is 0x40 = 64 bytes
 
  while(setByteRead(numBytes)){ //This tells the CH376S module how many bytes to read on the next reading step. In this example, we will read 0x10 bytes at a time. Returns true if there are bytes to read, false if there are no more bytes to read.
    USB.write(0x57);
    USB.write(0xAB);
    USB.write(0x27); //Command to read ALL of the bytes (allocated by setByteRead(x))
    if(waitForResponse("reading data")){ //Wait for the CH376S module to return data. TimeOut will return false. If data is being transmitted, it will return true.
        firstByte=USB.read(); //Read the first byte
        while(USB.available()){
          Serial.write(USB.read()); //Send the data from the USB disk to the Serial monitor
          delay(1); //This delay is necessary for successful Serial transmission
        }
    }
    if<!continueRead()){><span>//prepares the module for further reading. If false, stop reading.</span><br />      <span>break</span>; <span>//You need the continueRead() method if the data to be read from the USB device is greater than numBytes.</span><br />    }<br />  }<br />  <span><b>Serial</b></span>.<span>println</span>();<br />  <span><b>Serial</b></span>.<span>println</span>(<span>"NO MORE DATA"</span>);<br />}<br /><br /><span>//fileWrite=======================================================================================</span><br /><span>//are the commands used to write to the file</span><br /><span>void</span> fileWrite(<span>String</span> data){<br />  <span><b>Serial</b></span>.<span>println</span>(<span>"Writing to file:"</span>);<br />  <span>byte</span> dataLength = (<span>byte</span>) data.<span>length</span>(); <span>// This variable holds the length of the data to be written (in bytes)</span><br />  <span><b>Serial</b></span>.<span>println</span>(data);<br />  <span><b>Serial</b></span>.<span>print</span>(<span>"Data Length:"</span>);<br />  <span><b>Serial</b></span>.<span>println</span>(dataLength);<br />  <span>delay</span>(100);<br />  <span>// This set of commands tells the CH376S module how many bytes to expect from the Arduino. (defined by the "dataLength" variable)</span><br />  USB.<span>write</span>(0x57);<br />  USB.<span>write</span>(0xAB);<br />  USB.<span>write</span>(0x3C);<br />  USB.<span>write</span>((<span>byte</span>) dataLength);<br />  USB.<span>write</span>((<span>byte</span>) 0x00);<br />  <span>if</span>(waitForResponse(<span>"setting data Length"</span>)){ <span>// Wait for an acknowledgement from the CH376S module before trying to send data to it</span><br />    <span>if</span>(getResponseFromUSB()==0x1E){ <span>// 0x1E indicates that the USB device is in write mode.</span><br />      USB.<span>write</span>(0x57);<br />      USB.<span>write</span>(0xAB);<br />      USB.<span>write</span>(0x2D);<br />      USB.<span>print</span>(data); <span>// write the data to the file</span><br />  <br />      <span>if</span>(waitForResponse(<span>"writing data to file"</span>)){ <span>// wait for an acknowledgement from the CH376S module</span><br />      }<br />      <span><b>Serial</b></span>.<span>print</span>(<span>"Write code (normally FF and 14): "</span>);<br />      <span><b>Serial</b></span>.<span>print</span>(USB.<span>read</span>(),<span>HEX</span>); <span>// code is normally 0xFF</span><br />      <span><b>Serial</b></span>.<span>print</span>(<span>","</span>);<br />      USB.<span>write</span>(0x57);<br />      USB.<span>write</span>(0xAB);<br />      USB.<span>write</span>(0x3D); <span>// This is used to update the file size. Not sure if this is necessary for successful writing.</span><br />      <span>if</span>(waitForResponse(<span>"updating file size"</span>)){ <span>// wait for an acknowledgement from the CH376S module</span><br />      }<br />      <span><b>Serial</b></span>.<span>println</span>(USB.<span>read</span>(),<span>HEX</span>); <span>//code is normally 0x14</span><br />    }<br />  }<br />}<br /><br /><span>//continueRead()==================================================================================</span><br /><span>//continue to read the file : I could not get this function to work as intended.</span><br /><span>boolean</span> continueRead(){<br />  <span>boolean</span> readAgain = <span>false</span>;<br />  USB.<span>write</span>(0x57);<br />  USB.<span>write</span>(0xAB);<br />  USB.<span>write</span>(0x3B);<br />  <span>if</span>(waitForResponse(<span>"continueRead"</span>)){ <span>//wait for a response from the CH376S. If CH376S responds, it will be true. If it times out, it will be false.</span><br />     <span>if</span>(getResponseFromUSB()==0x14){ <span>//CH376S will send 0x14 if this command was successful</span><br />       readAgain=<span>true</span>;<br />     }<br />  }<br />  <span>return</span>(readAgain);<br />} <br /><br /><span>//fileCreate()========================================================================================</span><br /><span>//the command sequence to create a file</span><br /><span>boolean</span> fileCreate(){<br />  <span>boolean</span> createdFile = <span>false</span>;<br />  USB.<span>write</span>(0x57);<br />  USB.<span>write</span>(0xAB);<br />  USB.<span>write</span>(0x34);<br />  <span>if</span>(waitForResponse(<span>"creating file"</span>)){ <span>//wait for a response from the CH376S. If file has been created successfully, it will return true.</span><br />     <span>if</span>(getResponseFromUSB()==0x14){ <span>//CH376S will send 0x14 if this command was successful</span><br />       createdFile=<span>true</span>;<br />     }<br />  }<br />  <span>return</span>(createdFile);<br />}<br /><br /><br /><span>//fileDelete()========================================================================================</span><br /><span>//the command sequence to delete a file</span><br /><span>void</span> fileDelete(<span>String</span> fileName){<br />  setFileName(fileName);<br />  <span>delay</span>(20);<br />  USB.<span>write</span>(0x57);<br />  USB.<span>write</span>(0xAB);<br />  USB.<span>write</span>(0x35);<br />  <span>if</span>(waitForResponse(<span>"deleting file"</span>)){ <span>//wait for a response from the CH376S. If file has been created successfully, it will return true.</span><br />     <span>if</span>(getResponseFromUSB()==0x14){ <span>//CH376S will send 0x14 if this command was successful</span><br />       <span><b>Serial</b></span>.<span>println</span>(<span>"Successfully deleted file"</span>);<br />     }<br />  }<br />}<br />  <br /><br /><span>//filePointer========================================================================================</span><br /><span>//is used to set the file pointer position. true for beginning of file, false for the end of the file.</span><br /><span>void</span> filePointer(<span>boolean</span> fileBeginning){<br />  USB.<span>write</span>(0x57);<br />  USB.<span>write</span>(0xAB);<br />  USB.<span>write</span>(0x39);<br />  <span>if</span>(fileBeginning){<br />    USB.<span>write</span>((<span>byte</span>)0x00); <span>//beginning of file</span><br />    USB.<span>write</span>((<span>byte</span>)0x00);<br />    USB.<span>write</span>((<span>byte</span>)0x00);<br />    USB.<span>write</span>((<span>byte</span>)0x00);<br />  } <span>else</span> {<br />    USB.<span>write</span>((<span>byte</span>)0xFF); <span>//end of file</span><br />    USB.<span>write</span>((<span>byte</span>)0xFF);<br />    USB.<span>write</span>((<span>byte</span>)0xFF);<br />    USB.<span>write</span>((<span>byte</span>)0xFF);<br />  }<br />  <span>if</span>(waitForResponse(<span>"setting file pointer"</span>)){ <span>//wait for a response from the CH376S. </span><br />     <span>if</span>(getResponseFromUSB()==0x14){ <span>//CH376S will send 0x14 if this command was successful</span><br />       <span><b>Serial</b></span>.<span>println</span>(<span>"Pointer successfully applied"</span>);<br />     }<br />  }<br />}<br /><br /><br /><span>//fileClose=======================================================================================</span><br /><span>//closes the file</span><br /><span>void</span> fileClose(<span>byte</span> closeCmd){<br />  <span><b>Serial</b></span>.<span>println</span>(<span>"Closing file:"</span>);<br />  USB.<span>write</span>(0x57);<br />  USB.<span>write</span>(0xAB);<br />  USB.<span>write</span>(0x36);<br />  USB.<span>write</span>((<span>byte</span>)closeCmd); <span>// closeCmd = 0x00 = close without updating file Size, 0x01 = close and update file Size</span><br /><br />  <span>if</span>(waitForResponse(<span>"closing file"</span>)){ <span>// wait for a response from the CH376S. </span><br />     <span>byte</span> resp = getResponseFromUSB();<br />     <span>if</span>(resp==0x14){ <span>// CH376S will send 0x14 if this command was successful</span><br />       <span><b>Serial</b></span>.<span>println</span>(<span>">File closed successfully."</span>);<br />     } <span>else</span> {<br />       <span><b>Serial</b></span>.<span>print</span>(<span>">Failed to close file. Error code:"</span>);<br />       <span><b>Serial</b></span>.<span>println</span>(resp, <span>HEX</span>);<br />     }  <br />  }<br />}<br /><br /><span>//waitForResponse===================================================================================</span><br /><span>//is used to wait for a response from USB. Returns true when bytes become available, false if it times out.</span><br /><span>boolean</span> waitForResponse(<span>String</span> errorMsg){<br />  <span>boolean</span> bytesAvailable = <span>true</span>;<br />  <span>int</span> counter=0;<br />  <span>while</span><!USB><span>available</span>()){ <span>//wait for CH376S to verify command</span><br />    <span>delay</span>(1);<br />    counter++;<br />    <span>if</span>(counter>timeOut){<br />      <span><b>Serial</b></span>.<span>print</span>(<span>"TimeOut waiting for response: Error while: "</span>);<br />      <span><b>Serial</b></span>.<span>println</span>(errorMsg);<br />      bytesAvailable = <span>false</span>;<br />      <span>break</span>;<br />    }<br />  }<br />  <span>delay</span>(1);<br />  <span>return</span>(bytesAvailable);<br />}<br /><br /><span>//getResponseFromUSB================================================================================</span><br /><span>//is used to get any error codes or messages from the CH376S module (in response to certain commands)</span><br /><span>byte</span> getResponseFromUSB(){<br />  <span>byte</span> response = <span>byte</span>(0x00);<br />  <span>if</span> (USB.<span>available</span>()){<br />    response = USB.<span>read</span>();<br />  }<br />  <span>return</span>(response);<br />}<br /><br /><br /><br /><span>//blinkLED==========================================================================================</span><br /><span>//Turn an LED on for 1 second</span><br /><span>void</span> blinkLED(){<br />  <span>digitalWrite</span>(LED, <span>HIGH</span>);<br />  <span>delay</span>(1000);<br />  <span>digitalWrite</span>(LED,<span>LOW</span>);<br />}<br /><br /></pre> </td> </tr> </table></div></p> <br /> <p> If you copy and paste this code directly into the Arduino IDE; you may get a warning like this when you compile the code:<br />   <br />    "Low memory available, stability problems may occur". <br />  <br /> I managed to run the sketch without any issues, however, I did experience problems with some of the methods when I had made further memory hungry modifications. If you do encounter problems, I would recommend that you eliminate any methods which you do not plan to use, and perhaps reduce the number of Serial.print statements throughout the code. However, please note that some of the methods will not work unless the module is in the correct state, so be careful which methods you delete. For example, I found that I could get some simple functionality without the "USBdiskMount()" method. However, I could not read/write data beyond a certain length without this method.<br />   <br /> Also please note, that some of the methods called within the reading and writing sequence do not need to be called every time. They can be called once in setup, while other methods within the sequence will need to be called every time. I grouped them all together for simplicity. </p> <!--separator --><img src="https://images-blogger-opensocial.googleusercontent.com/gadgets/proxy?url=http%3A%2F%2F1.bp.blogspot.com%2F-XQiwNpdqOxk%2FT_rKCzDh4nI%2FAAAAAAAAAQY%2FOfYBljhU6Lk%2Fs1600%2FSeparator.jpg&container=blogger&gadget=a&rewriteMime=image%2F*" /><br /> <p><h4>Serial Commands</h4> Have a look at the following presentation for a summary of the Serial commands used in this tutorial: <br />   <br /> <div> </div> </p> </div><p> <div> <!-- Concluding Comments --> </div> <br />  <br />  <div> <p> <!--separator --> <img src="https://images-blogger-opensocial.googleusercontent.com/gadgets/proxy?url=http%3A%2F%2F1.bp.blogspot.com%2F-XQiwNpdqOxk%2FT_rKCzDh4nI%2FAAAAAAAAAQY%2FOfYBljhU6Lk%2Fs1600%2FSeparator.jpg&container=blogger&gadget=a&rewriteMime=image%2F*" /><br /> <br /> </p> </div> </p><p> <div> If you like this page, please do me a favour and show your appreciation : <br /> <br />  <br /> Visit my <a href="https://plus.google.com/u/0/b/107402020974762902161/107402020974762902161/posts">ArduinoBasics Google + page</a>.<br /> Follow me on Twitter by looking for <a href="https://twitter.com/ArduinoBasics">ScottC @ArduinoBasics</a>.<br /> I can also be found on <a href="https://www.pinterest.com/ArduinoBasics/">Pinterest</a> and <a href="https://instagram.com/arduinobasics">Instagram</a>. <br /> Have a look at my videos on my <a href="https://www.youtube.com/user/ScottCMe/videos">YouTube channel</a>.<br /> </div> </p> <br /> <div> <p> <!--separator --> <img src="https://images-blogger-opensocial.googleusercontent.com/gadgets/proxy?url=http%3A%2F%2F1.bp.blogspot.com%2F-XQiwNpdqOxk%2FT_rKCzDh4nI%2FAAAAAAAAAQY%2FOfYBljhU6Lk%2Fs1600%2FSeparator.jpg&container=blogger&gadget=a&rewriteMime=image%2F*" /><br /> <br /> </p> </div> <p> However, if you do not have a google profile... <br />Feel free to share this page with your friends in any way you see fit. </p>

Arduino Heart Rate Monitor


Project Description


Heart Rate Monitors are very popular at the moment.
There is something very appealing about watching the pattern of your own heart beat. And once you see it, there is an unstoppable urge to try and control it. This simple project will allow you to visualize your heart beat, and will calculate your heart rate. Keep reading to learn how to create your very own heart rate monitor.


 

Parts Required:


Fritzing Sketch


 

 
 
 

Grove Base Shield to Module Connections


 


 

Arduino Sketch


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/* =================================================================================================
      Project: Arduino Heart rate monitor
       Author: Scott C
      Created: 21st April 2015
  Arduino IDE: 1.6.2
      Website: http://arduinobasics.blogspot.com/p/arduino-basics-projects-page.html
  Description: This is a simple sketch that uses a Grove Ear-clip Heart Rate sensor attached to an Arduino UNO,
               which sends heart rate data to the computer via Serial communication. You can see the raw data
               using the Serial monitor on the Arduino IDE, however, this sketch was specifically
               designed to interface with the matching Processing sketch for a much nicer graphical display.
               NO LIBRARIES REQUIRED.
=================================================================================================== */

#define Heart 2                            //Attach the Grove Ear-clip sensor to digital pin 2.
#define LED 4                              //Attach an LED to digital pin 4

boolean beat = false; /* This "beat" variable is used to control the timing of the Serial communication
                                           so that data is only sent when there is a "change" in digital readings. */

//==SETUP==========================================================================================
void setup() {
  Serial.begin(9600); //Initialise serial communication
  pinMode(Heart, INPUT); //Set digital pin 2 (heart rate sensor pin) as an INPUT
  pinMode(LED, OUTPUT); //Set digital pin 4 (LED) to an OUTPUT
}


//==LOOP============================================================================================
void loop() {
  if(digitalRead(Heart)>0){ //The heart rate sensor will trigger HIGH when there is a heart beat
    if<!beat){><span>//Only send data when it first discovers a heart beat - otherwise it will send a high value multiple times</span><br />      beat=<span>true</span>; <span>//By changing the beat variable to true, it stops further transmissions of the high signal</span><br />      <span>digitalWrite</span>(LED, <span>HIGH</span>); <span>//Turn the LED on </span><br />      <span><b>Serial</b></span>.<span>println</span>(1023); <span>//Send the high value to the computer via Serial communication.</span><br />    }<br />  } <span>else</span> { <span>//If the reading is LOW, </span><br />    <span>if</span>(beat){ <span>//and if this has just changed from HIGH to LOW (first low reading)</span><br />      beat=<span>false</span>; <span>//change the beat variable to false (to stop multiple transmissions)</span><br />      <span>digitalWrite</span>(LED, <span>LOW</span>); <span>//Turn the LED off.</span><br />      <span><b>Serial</b></span>.<span>println</span>(0); <span>//then send a low value to the computer via Serial communication.</span><br />    }<br />  }<br />}</pre> </td> </tr> </table></div></p> <br />  <br />   <br />  <br />  <p> <h4><a href="https://processing.org/download/?processing">Processing Sketch</a></h4> <br />  <div> <table> <tr> <td> <pre> 1<br /> 2<br /> 3<br /> 4<br /> 5<br /> 6<br /> 7<br /> 8<br /> 9<br /> 10<br /> 11<br /> 12<br /> 13<br /> 14<br /> 15<br /> 16<br /> 17<br /> 18<br /> 19<br /> 20<br /> 21<br /> 22<br /> 23<br /> 24<br /> 25<br /> 26<br /> 27<br /> 28<br /> 29<br /> 30<br /> 31<br /> 32<br /> 33<br /> 34<br /> 35<br /> 36<br /> 37<br /> 38<br /> 39<br /> 40<br /> 41<br /> 42<br /> 43<br /> 44<br /> 45<br /> 46<br /> 47<br /> 48<br /> 49<br /> 50<br /> 51<br /> 52<br /> 53<br /> 54<br /> 55<br /> 56<br /> 57<br /> 58<br /> 59<br /> 60<br /> 61<br /> 62<br /> 63<br /> 64<br /> 65<br /> 66<br /> 67<br /> 68<br /> 69<br /> 70<br /> 71<br /> 72<br /> 73<br /> 74<br /> 75<br /> 76<br /> 77<br /> 78<br /> 79<br /> 80<br /> 81<br /> 82<br /> 83<br /> 84<br /> 85<br /> 86<br /> 87<br /> 88<br /> 89<br /> 90<br /> 91<br /> 92<br /> 93<br /> 94<br /> 95<br /> 96<br /> 97<br /> 98<br /> 99<br />100<br />101<br />102<br />103<br />104<br />105<br />106<br />107<br />108<br />109<br />110<br />111<br />112<br />113<br />114<br />115<br />116<br />117<br />118<br />119<br />120<br />121<br />122<br />123<br />124<br />125<br />126<br />127<br />128<br />129<br />130<br />131<br />132<br />133<br />134<br />135<br />136<br />137<br />138<br />139<br />140<br />141<br />142<br />143<br />144<br />145<br />146<br />147<br />148<br />149<br />150<br />151<br />152<br />153<br />154<br />155<br />156<br />157<br />158<br />159<br />160<br />161<br />162<br />163<br />164<br />165<br />166<br />167<br />168<br />169<br />170<br />171<br />172<br />173<br />174<br />175<br />176<br />177<br />178<br />179<br />180<br />181<br />182<br />183<br />184<br />185<br />186<br />187<br />188<br />189<br />190<br />191<br />192<br />193<br />194<br />195<br />196<br />197<br />198<br />199<br />200<br />201<br />202<br />203<br />204<br />205<br />206<br />207<br />208<br />209<br />210<br />211<br />212<br />213<br />214<br /></pre> </td> <td> <pre><br /><span>/* =================================================================================================</span><br /><span>       Project: Arduino Heart rate monitor</span><br /><span>        Author: Scott C</span><br /><span>       Created: 21st April 2015</span><br /><span>Processing IDE: 2.2.1</span><br /><span>       Website: http://arduinobasics.blogspot.com/p/arduino-basics-projects-page.html</span><br /><span>   Description: A Grove Ear-clip heart rate sensor allows an Arduino UNO to sense your pulse.</span><br /><span>                The data obtained by the Arduino can then be sent to the computer via Serial communication</span><br /><span>                which is then displayed graphically using this Processing sketch.</span><br /><span>                </span><br /><span>=================================================================================================== */</span><br /><br /><span>import</span> processing.serial.*; <span>// Import the serial library to allow Serial communication with the Arduino</span><br /><br /><span>int</span> numOfRecs = 45; <span>// numOfRecs: The number of rectangles to display across the screen</span><br />Rectangle[] myRecs = <span>new</span> Rectangle[numOfRecs]; <span>// myRecs[]: Is the array of Rectangles. Rectangle is a custom class (programmed within this sketch)</span><br /><br />Serial myPort;                                         <br /><span>String</span> comPortString=<span>"0"</span>; <span>//comPortString: Is used to hold the string received from the Arduino</span><br /><span>float</span> arduinoValue = 0; <span>//arduinoValue: Is the float variable converted from comPortString</span><br /><span>boolean</span> beat = <span>false</span>; <span>// beat: Used to control for multiple high/low signals coming from the Arduino</span><br /><br /><span>int</span> totalTime = 0; <span>// totalTime: Is the variable used to identify the total time between beats</span><br /><span>int</span> lastTime = 0; <span>// lastTime: Is the variable used to remember when the last beat took place</span><br /><span>int</span> beatCounter = 0; <span>// beatCounter: Is used to keep track of the number of beats (in order to calculate the average BPM)</span><br /><span>int</span> totalBeats = 10; <span>// totalBeats: Tells the computer that we want to calculate the average BPM using 10 beats.</span><br /><span>int</span>[] BPM = <span>new</span> <span>int</span>[totalBeats]; <span>// BPM[]: Is the Beat Per Minute (BPM) array - to hold 10 BPM calculations</span><br /><span>int</span> sumBPM = 0; <span>// sumBPM: Is used to sum the BPM[] array values, and is then used to calculate the average BPM.</span><br /><span>int</span> avgBPM = 0; <span>// avgBPM: Is the variable used to hold the average BPM calculated value.</span><br /><br /><span>PFont</span> f, f2; <span>// f & f2 : Are font related variables. Used to store font properties. </span><br /><br /><br /><span>//==SETUP==============================================================================================</span><br /><span>void</span> <span><b>setup</b></span>(){<br />  <span>size</span>(<span>displayWidth</span>,<span>displayHeight</span>); <span>// Set the size of the display to match the monitor width and height</span><br />  <span>smooth</span>(); <span>// Draw all shapes with smooth edges.</span><br />  f = <span>createFont</span>(<span>"Arial"</span>,24); <span>// Initialise the "f" font variable - used for the "calibrating" text displayed at the beginning</span><br />  f2 = <span>createFont</span>(<span>"Arial"</span>,96); <span>// Initialise the "f2" font variable - used for the avgBPM display on screen</span><br />  <br />  <span>for</span>(<span>int</span> i=0; i<numOfRecs; i++){ <span>// Initialise the array of rectangles</span><br />    myRecs[i] = <span>new</span> Rectangle(i, numOfRecs);<br />  }<br />  <br />  <span>for</span>(<span>int</span> i=0; i<totalBeats; i++){ <span>// Initialise the BPM array</span><br />    BPM[i] = 0;<br />  }<br />  <br />  myPort = <span>new</span> Serial(<span>this</span>, Serial.<span>list</span>()[0], 9600); <span>// Start Serial communication with the Arduino using a baud rate of 9600</span><br />  myPort.bufferUntil(<span>'\n'</span>); <span>// Trigger a SerialEvent on new line</span><br />}<br /><br /><br /><span>//==DRAW==============================================================================================</span><br /><span>void</span> <span><b>draw</b></span>(){<br />  <span>background</span>(0); <span>// Set the background to BLACK (this clears the screen each time)</span><br />  drawRecs();                                           <span>// Method call to draw the rectangles on the screen</span><br />  drawBPM();                                            <span>// Method call to draw the avgBPM value to the top right of the screen</span><br />}<br /><br /><br /><span>//==drawRecs==========================================================================================</span><br /><span>void</span> drawRecs(){ <span>// This custom method will draw the rectangles on the screen </span><br />  myRecs[0].setSize(arduinoValue);                      <span>// Set the first rectangle to match arduinoValue; any positive value will start the animation.</span><br />  <span>for</span>(<span>int</span> i=numOfRecs-1; i>0; i--){ <span>// The loop counts backwards for coding efficiency - and is used to draw all of the rectangles to screen</span><br />    myRecs[i].setMult(i);                               <span>// setMulti creates the specific curve pattern. </span><br />    myRecs[i].setRed(avgBPM);                           <span>// The rectangles become more "Red" with higher avgBPM values</span><br />    myRecs[i].setSize(myRecs[i-1].getH());              <span>// The current rectangle size is determined by the height of the rectangle immediately to it's left</span><br />    <span>fill</span>(myRecs[i].getR(),myRecs[i].getG(), myRecs[i].getB()); <span>// Set the colour of this rectangle</span><br />    <span>rect</span>(myRecs[i].getX(), myRecs[i].getY(), myRecs[i].getW(), myRecs[i].getH()); <span>// Draw this rectangle</span><br />  }<br />}<br /><br /><br /><span>//==drawBPM===========================================================================================</span><br /><span>void</span> drawBPM(){ <span>// This custom method is used to calculate the avgBPM and draw it to screen.</span><br />  sumBPM = 0;                                           <span>// Reset the sumBPM variable</span><br />  avgBPM = 0;                                           <span>// Reset the avgBPM variable</span><br />  <span>boolean</span> calibrating = <span>false</span>; <span>// calibrating: this boolean variable is used to control when the avgBPM is displayed to screen</span><br />  <br />  <span>for</span>(<span>int</span> i=1; i<totalBeats; i++){<br />    sumBPM = sumBPM + BPM[i-1];                         <span>// Sum all of the BPM values in the BPM array.</span><br />    <span>if</span>(BPM[i-1]<1){ <span>// If any BPM values are equal to 0, then set the calibrating variable to true. </span><br />      calibrating = <span>true</span>; <span>// This will be used later to display "calibrating" on the screen.</span><br />    }<br />  }<br />  avgBPM = sumBPM/(totalBeats-1);                       <span>// Calculate the average BPM from all BPM values</span><br />                                                        <br />  <span>fill</span>(255); <span>// The text will be displayed as WHITE text</span><br />  <span>if</span>(calibrating){<br />    <span>textFont</span>(f);<br />    <span>text</span>(<span>"Calibrating"</span>, (4*<span>width</span>)/5, (<span>height</span>/5)); <span>// If the calibrating variable is TRUE, then display the word "Calibrating" on screen</span><br />    <span>fill</span>(0); <span>// Change the fill and stroke to black (0) so that other text is "hidden" while calibrating variable is TRUE</span><br />    <span>stroke</span>(0);<br />  } <span>else</span> {<br />    <span>textFont</span>(f2);<br />    <span>text</span>(avgBPM, (4*<span>width</span>)/5, (<span>height</span>/5)); <span>// If the calibrating variable is FALSE, then display the avgBPM variable on screen</span><br />    <span>stroke</span>(255); <span>// Change the stroke to white (255) to show the white line underlying the word BPM.</span><br />  }<br />  <br />   <span>textFont</span>(f);<br />   <span>text</span>(<span>"BPM"</span>, (82*<span>width</span>)/100, (<span>height</span>/11)); <span>// This will display the underlined word "BPM" when calibrating variable is FALSE.</span><br />   <span>line</span>((80*<span>width</span>)/100, (<span>height</span>/10),(88*<span>width</span>)/100, (<span>height</span>/10));<br />   <span>stroke</span>(0);<br />}<br /><br /><br /><span>//==serialEvent===========================================================================================</span><br /><span>void</span> serialEvent(Serial cPort){ <span>// This will be triggered every time a "new line" of data is received from the Arduino</span><br /> comPortString = cPort.readStringUntil(<span>'\n'</span>); <span>// Read this data into the comPortString variable.</span><br /> <span>if</span>(comPortString != <span>null</span>) { <span>// If the comPortString variable is not NULL then</span><br />   comPortString=<span>trim</span>(comPortString); <span>// trim any white space around the text.</span><br />   <span>int</span> i = <span>int</span>(<span>map</span>(<span>Integer</span>.<span>parseInt</span>(comPortString),1,1023,1,<span>height</span>)); <span>// convert the string to an integer, and map the value so that the rectangle will fit within the screen.</span><br />   arduinoValue = <span>float</span>(i); <span>// Convert the integer into a float value.</span><br />   <span>if</span> (!beat){<br />     <span>if</span>(arduinoValue>0){ <span>// When a beat is detected, the "trigger" method is called.</span><br />       trigger(<span>millis</span>()); <span>// millis() creates a timeStamp of when the beat occured.</span><br />       beat=<span>true</span>; <span>// The beat variable is changed to TRUE to register that a beat has been detected.</span><br />     }<br />   }<br />   <span>if</span> (arduinoValue<1){ <span>// When the Arduino value returns back to zero, we will need to change the beat status to FALSE.</span><br />     beat = <span>false</span>;<br />   }<br /> }<br />} <br /><br /><br /><span>//==trigger===========================================================================================</span><br /><span>void</span> trigger(<span>int</span> time){ <span>// This method is used to calculate the Beats per Minute (BPM) and to store the last 10 BPMs into the BPM[] array.</span><br />  totalTime = time - lastTime;                         <span>// totalTime = the current beat time minus the last time there was a beat.</span><br />  lastTime = time;                                     <span>// Set the lastTime variable to the current "time" for the next round of calculations.</span><br />  BPM[beatCounter] = 60000/totalTime;                  <span>// Calculate BPM from the totalTime. 60000 = 1 minute.</span><br />  beatCounter++;                                       <span>// Increment the beatCounter </span><br />  <span>if</span> (beatCounter>totalBeats-1){ <span>// Reset the beatCounter when the total number of BPMs have been stored into the BPM[] array.</span><br />    beatCounter=0;                                     <span>// This allows us to keep the last 10 BPM calculations at all times.</span><br />  }<br />}<br /><br /><br /><span>//==sketchFullScreen==========================================================================================</span><br /><span>boolean</span> sketchFullScreen() { <span>// This puts Processing into Full Screen Mode</span><br /> <span>return</span> <span>true</span>;<br />}<br /><br /><br /><span>//==Rectangle CLASS==================================================================================*********</span><br /><span>class</span> Rectangle{<br />  <span>float</span> xPos, defaultY, yPos, myWidth, myHeight, myMultiplier; <span>// Variables used for drawing rectangles</span><br />  <span>int</span> blueVal, greenVal, redVal; <span>// Variables used for the rectangle colour</span><br />  <br />  Rectangle(<span>int</span> recNum, <span>int</span> nRecs){ <span>// The rectangles are constructed using two variables. The total number of rectangles to be displayed, and the identification of this rectangle (recNum)</span><br />    myWidth = <span>displayWidth</span>/nRecs; <span>// The width of the rectangle is determined by the screen width and the total number of rectangles.</span><br />    xPos = recNum * myWidth;                                      <span>// The x Position of this rectangle is determined by the width of the rectangles (all same) and the rectangle identifier.</span><br />    defaultY=<span>displayHeight</span>/2; <span>// The default Y position of the rectangle is half way down the screen.</span><br />    yPos = defaultY;                                              <span>// yPos is used to adjust the position of the rectangle as the size changes.</span><br />    myHeight = 1;                                                 <span>// The height of the rectangle starts at 1 pixel</span><br />    myMultiplier = 1;                                             <span>// The myMultiplier variable will be used to create the funnel shaped path for the rectangles.</span><br />    redVal = 0;                                                   <span>// The red Value starts off being 0 - but changes with avgBPM. Higher avgBPM means higher redVal</span><br />    <br />    <span>if</span> (recNum>0){ <span>// The blue Value progressively increases with every rectangle (moving to the right of the screen)</span><br />      blueVal = (recNum*255)/nRecs;<br />    } <span>else</span> {<br />      blueVal = 0;<br />    }<br />    greenVal = 255-blueVal;                                       <span>// Initially, the green value is at the opposite end of the spectrum to the blue value.</span><br />  }<br />  <br />  <span>void</span> setSize(<span>float</span> newSize){ <span>// This is used to set the new size of each rectangle </span><br />    myHeight=newSize*myMultiplier;<br />    yPos=defaultY-(newSize/2);<br />  }<br />  <br />  <span>void</span> setMult(<span>int</span> i){ <span>// The multiplier is a function of COS, which means that it varies from 1 to 0.</span><br />    myMultiplier = <span>cos</span>(<span>radians</span>(i)); <span>// You can try other functions to experience different effects.</span><br />  }<br />  <br />  <span>void</span> setRed(<span>int</span> r){<br />    redVal = <span>int</span>(<span>constrain</span>(<span>map</span>(<span>float</span>(r), 60, 100, 0, 255),0,255)); <span>// setRed is used to change the redValue based on the "normal" value for resting BPM (60-100). </span><br />    greenVal = 255 - redVal;                                       <span>// When the avgBPM > 100, redVal will equal 255, and the greenVal will equal 0.</span><br />  }                                                                <span>// When the avgBPM < 60, redVal will equal 0, and greenVal will equal 255.</span><br />  <br />  <span>float</span> getX(){ <span>// get the x Position of the rectangle</span><br />    <span>return</span> xPos;<br />  }<br /> <br />  <span>float</span> getY(){ <span>// get the y Position of the rectangle</span><br />    <span>return</span> yPos;<br />  }<br />  <br />  <span>float</span> getW(){ <span>// get the width of the rectangle</span><br />    <span>return</span> myWidth;<br />  }<br />  <br />  <span>float</span> getH(){ <span>// get the height of the rectangle</span><br />    <span>return</span> myHeight;<br />  }<br />  <br />  <span>float</span> getM(){ <span>// get the Multiplier of the rectangle</span><br />    <span>return</span> myMultiplier;<br />  }<br />  <br />  <span>int</span> getB(){ <span>// get the "blue" component of the rectangle colour</span><br />    <span>return</span> blueVal;<br />  }<br />  <br />  <span>int</span> getR(){ <span>// get the "red" component of the rectangle colour</span><br />    <span>return</span> redVal;<br />  }<br />  <br />  <span>int</span> getG(){ <span>// get the "green" component of the rectangle colour</span><br />    <span>return</span> greenVal;<br />  }<br />}<br /><br /></pre> </td> </tr> </table></div></p> <br />  <br /> <p> <h4>Processing Code Discussion:</h4><br /> </p><p> The Rectangle class was created to store relevant information about each rectangle. By using a custom class, we were able to design our rectangles any way we wanted. These rectangles have properties and methods which allow us to easily control their position, size and colour. By adding some smart functionality to each rectangle, we were able to get the rectangle to automatically position and colour itself based on key values. </p> <p> The Serial library is used to allow communication with the Arduino. In this Processing sketch, the values obtained from the Arduino were converted to floats to allow easy calulations of the beats per minute (BPM). I am aware that I have over-engineered the serialEvent method somewhat, because the Arduino is only really sending two values. I didn't really need to convert the String. But I am happy with the end result, and it does the job I needed it to... </p> <div> <p> <div> <a href="http://4.bp.blogspot.com/-EVTCQ3vkgGc/VTnOarlOWSI/AAAAAAAABdc/MslEU5oirAY/s1600/Complete%2BWorkstation2.jpg"><img src="http://4.bp.blogspot.com/-EVTCQ3vkgGc/VTnOarlOWSI/AAAAAAAABdc/MslEU5oirAY/s1600/Complete%2BWorkstation2.jpg" /> </a> </div> </p> </div> </div><!--separator --><img src="https://images-blogger-opensocial.googleusercontent.com/gadgets/proxy?url=http%3A%2F%2F1.bp.blogspot.com%2F-XQiwNpdqOxk%2FT_rKCzDh4nI%2FAAAAAAAAAQY%2FOfYBljhU6Lk%2Fs1600%2FSeparator.jpg&container=blogger&gadget=a&rewriteMime=image%2F*" /><br /><p> <div> This project is quite simple. I designed it so that you could omit the Processing code if you wanted to. In that scenario, you would only be left with a blinking LED that blinks in time with your pulse. The Processing code takes this project to the next level. It provides a nice animation and calculates the beats per minute (BPM). <br />   <br /> I hope you liked this tutorial. Please feel free to share it, comment or give it a plus one. If you didn't like it, I would still appreciate your constructive feedback. </div> <br />  <div> <p> <!--separator --> <img src="https://images-blogger-opensocial.googleusercontent.com/gadgets/proxy?url=http%3A%2F%2F1.bp.blogspot.com%2F-XQiwNpdqOxk%2FT_rKCzDh4nI%2FAAAAAAAAAQY%2FOfYBljhU6Lk%2Fs1600%2FSeparator.jpg&container=blogger&gadget=a&rewriteMime=image%2F*" /><br /> <br /> </p> </div> </p><p> <div> If you like this page, please do me a favour and show your appreciation : <br /> <br />  <br /> Visit my <a href="https://plus.google.com/u/0/b/107402020974762902161/107402020974762902161/posts">ArduinoBasics Google + page</a>.<br /> Follow me on Twitter by looking for <a href="https://twitter.com/ArduinoBasics">ScottC @ArduinoBasics</a>.<br /> I can also be found on <a href="https://www.pinterest.com/ArduinoBasics/">Pinterest</a> and <a href="https://instagram.com/arduinobasics">Instagram</a>. <br /> Have a look at my videos on my <a href="https://www.youtube.com/user/ScottCMe/videos">YouTube channel</a>.<br /> </div> </p> <br />  <br />  <p> <div> <a href="http://3.bp.blogspot.com/-x_TA-qhOCzM/VTnULXoWhQI/AAAAAAAABds/quh02BWGsec/s1600/Slide1.JPG"><img src="http://3.bp.blogspot.com/-x_TA-qhOCzM/VTnULXoWhQI/AAAAAAAABds/quh02BWGsec/s1600/Slide1.JPG" /></a></div><br /> </p> <br />  <br />  <br />  <div> <p> <!--separator --> <img src="https://images-blogger-opensocial.googleusercontent.com/gadgets/proxy?url=http%3A%2F%2F1.bp.blogspot.com%2F-XQiwNpdqOxk%2FT_rKCzDh4nI%2FAAAAAAAAAQY%2FOfYBljhU6Lk%2Fs1600%2FSeparator.jpg&container=blogger&gadget=a&rewriteMime=image%2F*" /><br /> <br /> </p> </div> <p> However, if you do not have a google profile... <br />Feel free to share this page with your friends in any way you see fit. </p>

Arduino BeatBox

Create your very own Arduino BeatBox !

Home-made capacitive touch sensors are used to trigger the MP3 drum sounds stored on the Grove Serial MP3 player. I have used a number of tricks to get the most out of this module, and I was quite impressed on how well it did. Over 130 sounds were loaded onto the SDHC card. Most were drum sounds, but I added some farm animal noises to provide an extra element of surprise and entertainment. You can put any sounds you want on the module and play them back quickly. We'll put the Grove Serial MP3 module through it's paces and make it into a neat little BeatBox !!


Key learning objectives

  • How to make your own beatbox
  • How to make capacitive drum pad sensors without using resistors
  • How to speed up Arduino's Analog readings for better performance
  • How to generate random numbers on your Arduino


Parts Required:

Making the drum pads


 
 

Fritzing Sketch


 


 
 

Grove Connections


 


 
 

Grove Connections (without base shield)


 


 
 

Arduino Sketch


 
  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239

/* =================================================================================================
      Project: Arduino Beatbox
       Author: Scott C
      Created: 9th April 2015
  Arduino IDE: 1.6.2
      Website: http://arduinobasics.blogspot.com/p/arduino-basics-projects-page.html
  Description: This project uses home made capacitive sensors to trigger over 130 MP3 sounds
               on the Grove Serial MP3 player. 
               
               The ADCTouch library is used to eliminate the resistors from the Capacitive sensing circuit. 
               The code used for capacitive sensing was adapted from the ADCTouch library example sketches. 
               You can find the ADCTouch library and relevant example code here:
               http://playground.arduino.cc/Code/ADCTouch
               
               "Advanced Arduino ADC" is used to improve the analogRead() speed, and enhance the
               drum pad or capacitive sensor response time. The Advanced Arduino ADC code 
               was adapted from this site:
               http://www.microsmart.co.za/technical/2014/03/01/advanced-arduino-adc/
               
               
=================================================================================================== */
  #include <ADCTouch.h>
  #include <SoftwareSerial.h>
  
  
  //Global variables
  //===================================================================================================
  int potPin = A4; //Grove Sliding potentiometer is connected to Analog Pin 4
  int potVal = 0;
  byte mp3Vol = 0; //Variable used to control the volume of the MP3 player
  byte oldVol = 0;
  
  int buttonPin = 5; //Grove Button is connected to Digital Pin 5
  int buttonStatus = 0;
  
  byte SongNum[4] = {0x01,0x02,0x03,0x04}; //The first 4 songs will be assigned to the drum pads upon initialisation
  byte numOfSongs = 130; //Total number of MP3 songs/sounds loaded onto the SDHC card
  
  long randNumber; //Variable used to hold the random number - used to randomise the sounds.
  
  int ledState[4]; //Used to keep track of the status of all LEDs (on or off)
  int counter = 0;
  
  SoftwareSerial mp3(3, 4); // The Grove MP3 Player is connected to Arduino digital Pin 3 and 4 (Serial communication)
       
  int ref0, ref1, ref2, ref3; //reference values to remove offset
  int threshold = 100;
      
  // Define the ADC prescalers
  const unsigned char PS_64 = (1 << ADPS2) | (1 << ADPS1);
  const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
  
  
  
  //Setup()
  //===================================================================================================
  void setup(){
    //Initialise the Grove MP3 Module
    delay(2500); //Allow the MP3 module to power up
    mp3.begin(9600); //Begin Serial communication with the MP3 module
    setPlayMode(0x00);                        //0x00 = Single song - played once ie. not repeated. (default)
    
    //Define the Grove Button as an INPUT
    pinMode(buttonPin, INPUT);
    
    //Define the 4 LED Pins as OUTPUTs
    pinMode(8, OUTPUT); //Green LED
    pinMode(9, OUTPUT); //Blue LED
    pinMode(10, OUTPUT); //Red LED
    pinMode(11, OUTPUT); //Yellow LED
    
    //Make sure each LED is OFF, and store the state of the LED into a variable.
    for(int i=8;i<12;i++){
      digitalWrite(i, LOW);
      ledState[i-8]=0;
    } 
    
    //Double our clock speed from 125 kHz to 250 kHz
    ADCSRA &= ~PS_128;   // set up the ADC
    ADCSRA |= PS_64;    // set our own prescaler to 64
    
    //Create reference values to account for the capacitance of each pad.
    ref0 = ADCTouch.read(A0, 500);
    ref1 = ADCTouch.read(A1, 500); //Take 500 readings
    ref2 = ADCTouch.read(A2, 500);
    ref3 = ADCTouch.read(A3, 500);
    
     //This helps to randomise the drum pads.
     randomSeed(analogRead(0));
  }
  
  
  
  // Loop()
  //===================================================================================================
  void loop(){
     
    //Take a reading from the Grove Sliding Potentiometer, and set volume accordingly
    potVal = analogRead(potPin);
    mp3Vol = map(potVal, 0, 1023, 0,31); // Convert the potentometer reading (0 - 1023) to fit within the MP3 player's Volume range (0 - 31)
    if((mp3Vol>(oldVol+1))|(mp3Vol<(oldVol-1))){ // Only make a change to the Volume on the Grove MP3 player when the potentiometer value changes
      oldVol = mp3Vol;
      setVolume(mp3Vol);
      delay(10); // This delay is necessary with Serial communication to MP3 player
    }
    
    //Take a reading from the Pin attached to the Grove Button. If pressed, randomise the MP3 songs/sounds for each drum pad, and make the LEDs blink randomly.
    buttonStatus = digitalRead(buttonPin);
    if(buttonStatus==HIGH){
      SongNum[0]=randomSongChooser(1, 30);
      SongNum[1]=randomSongChooser(31, 60);
      SongNum[2]=randomSongChooser(61, 86);
      SongNum[3]=randomSongChooser(87, (int)numOfSongs);
      randomLEDBlink();
    }
    
    //Get the capacitive readings from each drum pad: 50 readings are taken from each pad. (default is 100)
    int value0 = ADCTouch.read(A0,50); // Green drum pad
    int value1 = ADCTouch.read(A1,50); // Blue drum pad
    int value2 = ADCTouch.read(A2,50); // Red drum pad
    int value3 = ADCTouch.read(A3,50); // Yellow drum pad
    
    //Remove the offset to account for the baseline capacitance of each pad.
    value0 -= ref0;       
    value1 -= ref1;
    value2 -= ref2;
    value3 -= ref3;
    
    
    //If any of the values exceed the designated threshold, then play the song/sound associated with that drum pad.
    //The associated LED will stay on for the whole time the drum pad is pressed, providing the value remains above the threshold.
    //The LED will turn off when the pad is not being touched or pressed.
    if(value0>threshold){
      digitalWrite(8, HIGH);
      playSong(00,SongNum[0]);
    }else{
      digitalWrite(8,LOW);
    }
    
    if(value1>threshold){
      digitalWrite(9, HIGH);
      playSong(00,SongNum[1]);
    }else{
      digitalWrite(9,LOW);
    }
    
    if(value2>threshold){
      digitalWrite(10, HIGH);
      playSong(00,SongNum[2]);
    }else{
      digitalWrite(10,LOW);
    }
    
    if(value3>threshold){
      digitalWrite(11, HIGH);
      playSong(00,SongNum[3]);
    }else{
      digitalWrite(11,LOW);
    }
  }
      
   
  // writeToMP3:
  // a generic function that simplifies each of the methods used to control the Grove MP3 Player
  //===================================================================================================
  void writeToMP3(byte MsgLEN, byte A, byte B, byte C, byte D, byte E, byte F){
    byte codeMsg[] = {MsgLEN, A,B,C,D,E,F};
    mp3.write(0x7E); //Start Code for every command = 0x7E
    for(byte i = 0; i<MsgLEN+1; i++){
      mp3.write(codeMsg[i]); //Send the rest of the command to the GROVE MP3 player
    }
  }
  
  
  //setPlayMode: defines how each song is to be played
  //===================================================================================================
  void setPlayMode(byte playMode){
    /* playMode options:
          0x00 = Single song - played only once ie. not repeated.  (default)
          0x01 = Single song - cycled ie. repeats over and over.
          0x02 = All songs - cycled 
          0x03 = play songs randomly                                           */
    writeToMP3(0x03, 0xA9, playMode, 0x7E, 0x00, 0x00, 0x00);  
  }
  
  
  //playSong: tells the Grove MP3 player to play the song/sound, and also which song/sound to play
  //===================================================================================================
  void playSong(byte songHbyte, byte songLbyte){
    writeToMP3(0x04, 0xA0, songHbyte, songLbyte, 0x7E, 0x00, 0x00);            
    delay(100);
  }
  
  
  //setVolume: changes the Grove MP3 player's volume to the designated level (0 to 31)
  //===================================================================================================
  void setVolume(byte Volume){
    byte tempVol = constrain(Volume, 0, 31); //Volume range = 00 (muted) to 31 (max volume)
    writeToMP3(0x03, 0xA7, tempVol, 0x7E, 0x00, 0x00, 0x00); 
  }
  
  
  //randomSongChooser: chooses a random song to play. The range of songs to choose from
  //is limited and defined by the startSong and endSong parameters.
  //===================================================================================================
  byte randomSongChooser(int startSong, int endSong){
    randNumber = random(startSong, endSong);
    return((byte) randNumber);
  }
  
  
  //randomLEDBlink: makes each LED blink randomly. The LEDs are attached to digital pins 8 to 12.
  //===================================================================================================
  void randomLEDBlink(){
   counter=8;
   for(int i=0; i<40; i++){
     int x = constrain((int)random(8,12),8,12);
     toggleLED(x);
     delay(random(50,100-i));
   }
     
    for(int i=8;i<12;i++){
      digitalWrite(i, HIGH);
    }
    delay(1000);
    for(int i=8;i<12;i++){
      digitalWrite(i, LOW);
      ledState[i-8]=0;
    }
  }
  
  
  //toggleLED: is used by the randomLEDBlink method to turn each LED on and off (randomly).
  //===================================================================================================
  void toggleLED(int pinNum){
    ledState[pinNum-8]= !ledState[pinNum-8];
    digitalWrite(pinNum, ledState[pinNum-8]);
  }


 

Arduino Code Discussion

You can see from the Arduino code above, that it uses the ADCTouch library. This library was chosen over the Capacitive Sensing Library to eliminate the need for a high value resistor which are commonly found in Capacitive Sensing projects).
 
To increase the speed of the Analog readings, I utilised one of the "Advanced Arduino ADC" techniques described by Guy van den Berg on this Microsmart website.
 
The readings are increased by modifying the Arduino's ADC clock speed from 125kHz to 250 kHz. I did notice an overall better response time with this modification. However, the Grove Serial MP3 player is limited by it's inability to play more than one song or sound at a time. This means that if you hit another drum pad while the current sound is playing, it will stop playing the current sound, and then play the selected sound. The speed at which it can perform this task was quite impressive. In fact it was much better than I thought it would be. But if you are looking for polyphonic playability, you will be dissapointed.
 
This Serial MP3 module makes use of a high quality MP3 audio chip known as the "WT5001". Therefore, you should be able to get some additional features and functionality from this document. Plus you may find some extra useful info from the Seeedstudio wiki. I have re-used some code from the Arduino Boombox tutorial... you will find extra Grove Serial MP3 functions on that page.
 
I will warn you... the Grove Serial MP3 player can play WAV files, however for some reason it would not play many of the sound files in this format. Once the sounds were converted to the MP3 format, I did not look back. So if you decide to take on this project, make sure your sound files are in MP3 format, you'll have a much better outcome.
 
I decided to introduce a random sound selection for each drum pad to extend the novelty of this instrument, which meant that I had to come up with a fancy way to illuminate the LEDs. I demonstrated some of my other LED sequences on my instagram account. I sometimes use instagram to show my work in progress.
 
Have a look at the video below to see this project in action, and putting the Grove Serial MP3 player through it's paces.
 

The Video


 


First there was the Arduino Boombox, and now we have the Arduino Beatbox..... who knows what will come next !
 
Whenever I create a new project, I like to improve my Arduino knowledge. Sometimes it takes me into some rather complicated topics. There is a lot I do not know about Arduino, but I am enjoying the journey. I hope you are too !! Please Google plus one this post if it helped you in any way. These tutorials are free, which means I survive on feedback and plus ones... all you have to do is just scroll a little bit more and click that button :)

 
 



If you like this page, please do me a favour and show your appreciation :

 
Visit my ArduinoBasics Google + page.
Follow me on Twitter by looking for ScottC @ArduinoBasics.
I can also be found on Pinterest and Instagram.
Have a look at my videos on my YouTube channel.


 
 

 
 
 



However, if you do not have a google profile...
Feel free to share this page with your friends in any way you see fit.