初始化提交
This commit is contained in:
5
arduino-cli/libraries/PulseSensorPlayground/.gitattributes
vendored
Normal file
5
arduino-cli/libraries/PulseSensorPlayground/.gitattributes
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
examples/ linguist-documentation=false
|
||||
*.ino linguist-language=Arduino
|
||||
*.cpp linguist-language=Arduino
|
||||
*.hpp linguist-language=Arduino
|
||||
*.h linguist-language=Arduino
|
||||
21
arduino-cli/libraries/PulseSensorPlayground/LICENSE
Normal file
21
arduino-cli/libraries/PulseSensorPlayground/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2017 World Famous Electroncs LLC, Brooklyn, New York.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,159 @@
|
||||
|
||||

|
||||
# [PulseSensor.com](https://pulsesensor.com) Playground
|
||||
```
|
||||
This Playground is a collection of code for the most popular uses of PulseSensor and Arduino.
|
||||
|
||||
- The playgroud includes a number of projects, with the code already written-out and commented! 🤘
|
||||
- Use this code to get started quickly, or do advanced stuff. 👍
|
||||
- Switch between projects right in the Arduino IDE (software). 💻
|
||||
- Contritube your projects code back to the GitHub hive-mind. 🐝
|
||||
```
|
||||
|
||||
---
|
||||
## Install the PulseSensor Playground Library !
|
||||
<details><summary><code>How To Install: </code> 🤓</summary>
|
||||
|
||||
An Arduino Library is a collection of code and examples on a specific topic or device. For example, our PulseSensor Playground Library is a collection of code and projects made just for your PulseSensor and Arduino.
|
||||
|
||||
(**NOTE** If you do not have Arduino, you can download it [here](https://www.arduino.cc/en/Main/Software))
|
||||
|
||||
To install the PulseSensor Playground Library, in Arduino, to go
|
||||
`Sketch > Include Library > Manage Library...`
|
||||
|
||||
<img src="https://github.com/yury-g/MyCodePlayground/blob/master/images/ManageLibraries.png" width="550">
|
||||
|
||||
|
||||
In the Library Manager: Search for and Select
|
||||
`"PulseSensor.com`
|
||||
|
||||
<img src="https://github.com/yury-g/MyCodePlayground/blob/master/images/SearchForPulseSensor.png" width="550">
|
||||
|
||||
|
||||
Install or update to the lastest version.👍
|
||||
|
||||
<img src="https://github.com/yury-g/MyCodePlayground/blob/master/images/InstallLatestVersion.png" width="550">
|
||||
|
||||
|
||||
Hurray! Once this library is installed you will see our examples in Arduino's dropdown!
|
||||
To select an example project, go to:
|
||||
`File > Examples > PulseSensor Playground > GettingStartedProject`
|
||||
<img src="https://github.com/yury-g/MyCodePlayground/blob/master/images/ExamplesPlaygroundGettingStartedMenuPullDown.png" width="550">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
More Info On Libraries in General 👉 [https://www.arduino.cc/en/Guide/Libraries](https://www.arduino.cc/en/Guide/Libraries).
|
||||
|
||||
|
||||
</div>
|
||||
</details>
|
||||
|
||||
---
|
||||
## Playground Project Descriptions:
|
||||
|
||||
|
||||
### Getting Started Project:
|
||||
Plug your sensor in for the first time! Blink an LED with your pulse, live.
|
||||
|
||||
- [**Project Page**](https://pulsesensor.com/pages/code-and-guide)
|
||||
|
||||
<img src="https://cdn.shopify.com/s/files/1/0100/6632/files/PulseSensor_GettingStarted_bb_1024x1024.png?v=1511986616" width="400">
|
||||
---
|
||||
|
||||
### Calculate BPM:
|
||||
Focus-in on the code that calculates a user's HeartRate Beats Per Minute, "BPM".
|
||||
See the best practises to get the best signal.
|
||||
|
||||
- [**Project Page**](https://pulsesensor.com/pages/getting-advanced)
|
||||
|
||||
<img src="https://cdn.shopify.com/s/files/1/0100/6632/files/PulseSensor_GettingAdvanced_bb_1024x1024.png?v=1511986194" width="400">
|
||||
---
|
||||
|
||||
### Make A Sound to a live Heartbeat:
|
||||
Transform the heartbeat into a live "beep" with a speaker.
|
||||
|
||||
- [**Project Page**](https://pulsesensor.com/pages/pulse-sensor-speaker-tutorial)
|
||||
|
||||
<img src="https://cdn.shopify.com/s/files/1/0100/6632/files/PulseSensor_Speaker_bb_61a0333f-e868-4123-961d-7456a31fa928_1024x1024.png?v=1510863829" width="400">
|
||||
---
|
||||
|
||||
### Move a Motor to a live Heartbeat:
|
||||
Make a servo motor pulse to your live heartbeat.
|
||||
|
||||
- [**Project Page**](https://pulsesensor.com/pages/pulse-sensor-servo-tutorial)
|
||||
|
||||
<img src="https://cdn.shopify.com/s/files/1/0100/6632/files/PulseSensor_Servo_bb_87fce9fc-dc47-4208-b708-a7edb6df58a2_1024x1024.png?v=1510863990" width="400">
|
||||
---
|
||||
|
||||
### Connect Two (or more) Pulse Sensors:
|
||||
Use 2 or more Pulse Sensors on one Arduino.
|
||||
|
||||
- [**Project Page**](https://pulsesensor.com/pages/two-or-more-pulse-sensors)
|
||||
|
||||
<img src="https://cdn.shopify.com/s/files/1/0100/6632/files/2_PulseSensors_bb_grande.png?v=1516733684" width="400">
|
||||
---
|
||||
|
||||
### Processing Visualizer:
|
||||
|
||||
Get detailed visualization of the heart's pulse and behavior. Send the PulseSensor data into Processing!
|
||||
|
||||
- [**Project Page**](https://pulsesensor.com/pages/getting-advanced)
|
||||
|
||||
<img src="https://cdn.shopify.com/s/files/1/0100/6632/files/ScreenShot_1024x1024.png?v=1491857113" width="400">
|
||||
|
||||
---
|
||||
|
||||
### Pulse Transit Time:
|
||||
|
||||
Use two Pulse Sensors on different parts of your body to measure Pulse Transit Time!
|
||||
|
||||
- [**Project Page**](https://pulsesensor.com/pages/pulse-transit-time)
|
||||
|
||||
<img src="https://cdn.shopify.com/s/files/1/0100/6632/files/PulseSensor_PTT-17042_grande.jpg?v=1517336059" width="400">
|
||||
|
||||
---
|
||||
|
||||
## Connecting the Harware 😎
|
||||
1. Prepare the sensor, with the Kit parts.
|
||||
|
||||
<img src="https://cdn.shopify.com/s/files/1/0100/6632/products/PulseSensorKit-Labeled-Contents_1_2048x2048.jpg?v=1348506345" width="400">
|
||||
|
||||
2. See the recommended wiring for your specific project
|
||||
|
||||
<img src="https://github.com/WorldFamousElectronics/PulseSensorStarterProject/raw/master/connections.png" width="400">
|
||||
|
||||
<img src="https://github.com/WorldFamousElectronics/PulseSensorStarterProject/raw/master/Arduino-LEDonPin13-PulseSensor-Pic.jpg" width="400">
|
||||
|
||||
---
|
||||
|
||||
## The Functions Guide
|
||||
|
||||
We put together a [HANDY GUIDE](https://github.com/biomurph/PulseSensorPlayground/blob/master/resources/PulseSenaor%20Playground%20Tools.md) to the function-ality of our library. Check it out if you want to dive into the inner workings!
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting Your Signal:
|
||||
|
||||
<details><summary><code> Ugh, Where's the Beat ? </code>😵</summary>
|
||||
If you're having trouble seeing a heartbeat, make sure that you are using 'Goldilocks' pressure on the Pulse Sensor: Not too hard, not too soft. Squeezing the Pulse Sensor too hard against your skin will make the heartbeat go away, and not enough pressure will cause too much noise to creep in!
|
||||
|
||||
If you are seeing way too many Beats Per Minute, or you are getting lots of noise, try adjusting the Threshold setting. The Threshold variable tells Arduino when to find a pulse that is legit. Adjust this number (noted below with arrows) up for less sensitivity and down for more sensitivity. In the [**StarterProject**](https://pulsesensor.com/pages/code-and-guide) you can find the Threshold variable as shown in the pic below:
|
||||
|
||||

|
||||
|
||||
In the other examples, the `THRESHOLD` is defined at the top of the code.
|
||||
|
||||
</div>
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Give and Get Feedback
|
||||
The [Issues Tab](https://github.com/WorldFamousElectronics/PulseSensorStarterProject/issues) will get you the quickest answers to common techinal questions.
|
||||
|
||||
|
||||
---
|
||||
|
||||
#### Legal: PulseSensor.com® World Famous Electronics llc. in Brooklyn, NY. USA
|
||||
191
arduino-cli/libraries/PulseSensorPlayground/README.md
Normal file
191
arduino-cli/libraries/PulseSensorPlayground/README.md
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||

|
||||
## [PulseSensor.com](https://pulsesensor.com) Playground
|
||||
[](https://youtu.be/Pt0fJvIeryY)
|
||||
|
||||
```
|
||||
This Playground is a collection of code for the most popular uses of PulseSensor and Arduino.
|
||||
|
||||
- Use this code to get started quickly, or do advanced stuff. 👍
|
||||
- Playground code is already written-out and commented! 🤘
|
||||
- Switch between projects right in the Arduino IDE (software). 💻
|
||||
- Contribute your project's code back to the GitHub hive-mind. 🐝
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Buy Verified "PulseSensor.com"
|
||||
<b><a href="https://github.com/WorldFamousElectronics/PulseSensorPlayground/wiki/Buy-%22Verified-PulseSensor.com%22"> Where to buy Verified Sensors 💰 </a> </b>
|
||||
|
||||
---
|
||||
|
||||
|
||||
## Connecting the Harware 😎
|
||||
<b><details><summary><code> Easy Setup </code> </summary></b>
|
||||
|
||||
1. Prepare the sensor, with the Kit parts.
|
||||
|
||||
<img src="https://cdn.shopify.com/s/files/1/0100/6632/products/PulseSensorKit-Labeled-Contents_1_2048x2048.jpg?v=1348506345" width="400">
|
||||
|
||||
2. See the recommended wiring for your specific project
|
||||
|
||||
<img src="https://github.com/WorldFamousElectronics/PulseSensorStarterProject/raw/master/connections.png" width="400">
|
||||
|
||||
<img src="https://github.com/WorldFamousElectronics/PulseSensorStarterProject/raw/master/Arduino-LEDonPin13-PulseSensor-Pic.jpg" width="400">
|
||||
|
||||
</div>
|
||||
</details>
|
||||
|
||||
|
||||
|
||||
|
||||
## Loading the Playground
|
||||
<b><details><summary><code> Steps For Loading the Playground in Arduino </code> 🤓</summary></b>
|
||||
###
|
||||
|
||||
An Arduino Library is a collection of code and examples on a specific topic or device. For example, our PulseSensor Playground Library is a collection of code and projects made just for your PulseSensor and Arduino.
|
||||
|
||||
(**NOTE** If you do not have Arduino, you can download it [here](https://www.arduino.cc/en/Main/Software))
|
||||
|
||||
To install the PulseSensor Playground Library, in Arduino, to go
|
||||
`Sketch > Include Library > Manage Library...`
|
||||
|
||||
<img src="https://github.com/yury-g/MyCodePlayground/blob/master/images/ManageLibraries.png" width="500">
|
||||
|
||||
|
||||
In the Library Manager: Search for and Select
|
||||
`"PulseSensor.com`
|
||||
|
||||
<img src="https://github.com/yury-g/MyCodePlayground/blob/master/images/SearchForPulseSensor.png" width="500">
|
||||
|
||||
|
||||
Install or update to the latest version.👍
|
||||
|
||||
<img src="https://github.com/yury-g/MyCodePlayground/blob/master/images/InstallLatestVersion.png" width="500">
|
||||
|
||||
|
||||
Hurray! Once this library is installed you will see our examples in Arduino's dropdown!
|
||||
To select an example project, go to:
|
||||
`File > Examples > PulseSensor Playground > GettingStartedProject`
|
||||
<img src="https://github.com/yury-g/MyCodePlayground/blob/master/images/ExamplesPlaygroundGettingStartedMenuPullDown.png" width="500">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
More Info On Libraries in General 👉 [https://www.arduino.cc/en/Guide/Libraries](https://www.arduino.cc/en/Guide/Libraries).
|
||||
|
||||
|
||||
</div>
|
||||
</details>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Playground Project Descriptions:
|
||||
<b><details><summary><code>Tinker and Experiment with Popular Projects </code> 👩🏽💻👩🏻🔬</summary></b>
|
||||
|
||||
### The "Getting Started" Project:
|
||||
Plug your sensor in for the first time! Blink an LED with your pulse, live.
|
||||
|
||||
- [**Project Page**](https://pulsesensor.com/pages/code-and-guide)
|
||||
|
||||
<img src="https://cdn.shopify.com/s/files/1/0100/6632/files/PulseSensor_GettingStarted_bb_1024x1024.png?v=1511986616" width="400">
|
||||
---
|
||||
|
||||
### Calculate BPM:
|
||||
Focus-in on the code that calculates a user's HeartRate Beats Per Minute, "BPM".
|
||||
See the best practises to get the best signal.
|
||||
|
||||
- [**Project Page**](https://pulsesensor.com/pages/getting-advanced)
|
||||
|
||||
<img src="https://cdn.shopify.com/s/files/1/0100/6632/files/PulseSensor_GettingAdvanced_bb_1024x1024.png?v=1511986194" width="400">
|
||||
---
|
||||
|
||||
### Make A Sound to a live Heartbeat:
|
||||
Transform the heartbeat into a live "beep" with a speaker.
|
||||
|
||||
- [**Project Page**](https://pulsesensor.com/pages/pulse-sensor-speaker-tutorial)
|
||||
|
||||
<img src="https://cdn.shopify.com/s/files/1/0100/6632/files/PulseSensor_Speaker_bb_61a0333f-e868-4123-961d-7456a31fa928_1024x1024.png?v=1510863829" width="400">
|
||||
---
|
||||
|
||||
### Move a Motor to a live Heartbeat:
|
||||
Make a servo motor pulse to your live heartbeat.
|
||||
|
||||
- [**Project Page**](https://pulsesensor.com/pages/pulse-sensor-servo-tutorial)
|
||||
|
||||
<img src="https://cdn.shopify.com/s/files/1/0100/6632/files/PulseSensor_Servo_bb_87fce9fc-dc47-4208-b708-a7edb6df58a2_1024x1024.png?v=1510863990" width="400">
|
||||
---
|
||||
|
||||
### Connect Two (or more) Pulse Sensors:
|
||||
Use 2 or more Pulse Sensors on one Arduino.
|
||||
|
||||
- [**Project Page**](https://pulsesensor.com/pages/two-or-more-pulse-sensors)
|
||||
|
||||
<img src="https://cdn.shopify.com/s/files/1/0100/6632/files/2_PulseSensors_bb_grande.png?v=1516733684" width="400">
|
||||
---
|
||||
|
||||
### Processing Visualizer:
|
||||
|
||||
Get detailed visualization of the heart's pulse and behavior. Send the PulseSensor data into Processing!
|
||||
|
||||
- [**Project Page**](https://pulsesensor.com/pages/processing-visualization)
|
||||
|
||||
<img src="https://cdn.shopify.com/s/files/1/0100/6632/files/ScreenShot_1024x1024.png?v=1491857113" width="400">
|
||||
|
||||
---
|
||||
|
||||
### Pulse Transit Time:
|
||||
|
||||
Use two Pulse Sensors on different parts of your body to measure Pulse Transit Time!
|
||||
|
||||
- [**Project Page**](https://pulsesensor.com/pages/pulse-transit-time)
|
||||
|
||||
<img src="https://cdn.shopify.com/s/files/1/0100/6632/files/PulseSensor_PTT-17042_grande.jpg?v=1517336059" width="400">
|
||||
|
||||
---
|
||||
|
||||
</div>
|
||||
</details>
|
||||
|
||||
|
||||
|
||||
## Developer Resources:
|
||||
|
||||
<b><details><summary><code> Troubleshooting / Issues / Function Guide </code> </summary></b>
|
||||
|
||||
### The Functions Guide
|
||||
|
||||
We put together a [HANDY GUIDE](https://github.com/WorldFamousElectronics/PulseSensorPlayground/blob/master/resources/PulseSensor%20Playground%20Tools.md) to the function-ality of our library. Check it out if you want to dive into the inner workings!
|
||||
|
||||
---
|
||||
|
||||
### Troubleshooting Your Signal:
|
||||
|
||||
<b><details><summary><code> Ugh, Where's the Beat ? </code>😵</summary></b>
|
||||
If you're having trouble seeing a heartbeat, make sure that you are using 'Goldilocks' pressure on the Pulse Sensor: Not too hard, not too soft. Squeezing the Pulse Sensor too hard against your skin will make the heartbeat go away, and not enough pressure will cause too much noise to creep in!
|
||||
|
||||
If you are seeing way too many Beats Per Minute, or you are getting lots of noise, try adjusting the Threshold setting. The Threshold variable tells Arduino when to find a pulse that is legit. Adjust this number (noted below with arrows) up for less sensitivity and down for more sensitivity. In the [**StarterProject**](https://pulsesensor.com/pages/code-and-guide) you can find the Threshold variable as shown in the pic below:
|
||||
|
||||

|
||||
|
||||
In the other examples, the `THRESHOLD` is defined at the top of the code.
|
||||
|
||||
</div>
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
### Give and Get Feedback
|
||||
The [Issues Tab](https://github.com/WorldFamousElectronics/PulseSensorStarterProject/issues) will get you the quickest answers to common techinal questions.
|
||||
|
||||
|
||||
---
|
||||
|
||||
#### Legal: PulseSensor.com® World Famous Electronics llc. in Brooklyn, NY. USA
|
||||
|
||||
</div>
|
||||
</details>
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
/* PulseSensor Starter Project and Signal Tester
|
||||
* The Best Way to Get Started With, or See the Raw Signal of, your PulseSensor.com™ & Arduino.
|
||||
*
|
||||
* Here is a link to the tutorial
|
||||
* https://pulsesensor.com/pages/code-and-guide
|
||||
*
|
||||
* WATCH ME (Tutorial Video):
|
||||
* https://www.youtube.com/watch?v=RbB8NSRa5X4
|
||||
*
|
||||
*
|
||||
-------------------------------------------------------------
|
||||
1) This shows a live human Heartbeat Pulse.
|
||||
2) Live visualization in Arduino's Cool "Serial Plotter".
|
||||
3) Blink an LED on each Heartbeat.
|
||||
4) This is the direct Pulse Sensor's Signal.
|
||||
5) A great first-step in troubleshooting your circuit and connections.
|
||||
6) "Human-readable" code that is newbie friendly."
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// Variables
|
||||
int PulseSensorPurplePin = 0; // Pulse Sensor PURPLE WIRE connected to ANALOG PIN 0
|
||||
int LED13 = 13; // The on-board Arduion LED
|
||||
|
||||
|
||||
int Signal; // holds the incoming raw data. Signal value can range from 0-1024
|
||||
int Threshold = 550; // Determine which Signal to "count as a beat", and which to ingore.
|
||||
|
||||
|
||||
// The SetUp Function:
|
||||
void setup() {
|
||||
pinMode(LED13,OUTPUT); // pin that will blink to your heartbeat!
|
||||
Serial.begin(9600); // Set's up Serial Communication at certain speed.
|
||||
|
||||
}
|
||||
|
||||
// The Main Loop Function
|
||||
void loop() {
|
||||
|
||||
Signal = analogRead(PulseSensorPurplePin); // Read the PulseSensor's value.
|
||||
// Assign this value to the "Signal" variable.
|
||||
|
||||
Serial.println(Signal); // Send the Signal value to Serial Plotter.
|
||||
|
||||
|
||||
if(Signal > Threshold){ // If the signal is above "550", then "turn-on" Arduino's on-Board LED.
|
||||
digitalWrite(LED13,HIGH);
|
||||
} else {
|
||||
digitalWrite(LED13,LOW); // Else, the sigal must be below "550", so "turn-off" this LED.
|
||||
}
|
||||
|
||||
|
||||
delay(10);
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
|
||||
/* Getting_BPM_to_Monitor prints the BPM to the Serial Monitor, using the least lines of code and PulseSensor Library.
|
||||
* Tutorial Webpage: https://pulsesensor.com/pages/getting-advanced
|
||||
*
|
||||
--------Use This Sketch To------------------------------------------
|
||||
1) Displays user's live and changing BPM, Beats Per Minute, in Arduino's native Serial Monitor.
|
||||
2) Print: "♥ A HeartBeat Happened !" when a beat is detected, live.
|
||||
2) Learn about using a PulseSensor Library "Object".
|
||||
4) Blinks LED on PIN 13 with user's Heartbeat.
|
||||
--------------------------------------------------------------------*/
|
||||
|
||||
#define USE_ARDUINO_INTERRUPTS true // Set-up low-level interrupts for most acurate BPM math.
|
||||
#include <PulseSensorPlayground.h> // Includes the PulseSensorPlayground Library.
|
||||
|
||||
// Variables
|
||||
const int PulseWire = 0; // PulseSensor PURPLE WIRE connected to ANALOG PIN 0
|
||||
const int LED13 = 13; // The on-board Arduino LED, close to PIN 13.
|
||||
int Threshold = 550; // Determine which Signal to "count as a beat" and which to ignore.
|
||||
// Use the "Gettting Started Project" to fine-tune Threshold Value beyond default setting.
|
||||
// Otherwise leave the default "550" value.
|
||||
|
||||
PulseSensorPlayground pulseSensor; // Creates an instance of the PulseSensorPlayground object called "pulseSensor"
|
||||
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(9600); // For Serial Monitor
|
||||
|
||||
// Configure the PulseSensor object, by assigning our variables to it.
|
||||
pulseSensor.analogInput(PulseWire);
|
||||
pulseSensor.blinkOnPulse(LED13); //auto-magically blink Arduino's LED with heartbeat.
|
||||
pulseSensor.setThreshold(Threshold);
|
||||
|
||||
// Double-check the "pulseSensor" object was created and "began" seeing a signal.
|
||||
if (pulseSensor.begin()) {
|
||||
Serial.println("We created a pulseSensor Object !"); //This prints one time at Arduino power-up, or on Arduino reset.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void loop() {
|
||||
|
||||
int myBPM = pulseSensor.getBeatsPerMinute(); // Calls function on our pulseSensor object that returns BPM as an "int".
|
||||
// "myBPM" hold this BPM value now.
|
||||
|
||||
if (pulseSensor.sawStartOfBeat()) { // Constantly test to see if "a beat happened".
|
||||
Serial.println("♥ A HeartBeat Happened ! "); // If test is "true", print a message "a heartbeat happened".
|
||||
Serial.print("BPM: "); // Print phrase "BPM: "
|
||||
Serial.println(myBPM); // Print the value inside of myBPM.
|
||||
}
|
||||
|
||||
delay(20); // considered best practice in a simple sketch.
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
Code to detect pulses from the PulseSensor,
|
||||
using an interrupt service routine.
|
||||
|
||||
Here is a link to the tutorial\
|
||||
https://pulsesensor.com/pages/ATtiny
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
|
||||
/*
|
||||
Every Sketch that uses the PulseSensor Playground must
|
||||
define USE_ARDUINO_INTERRUPTS before including PulseSensorPlayground.h.
|
||||
Here, #define USE_ARDUINO_INTERRUPTS true tells the library to use
|
||||
interrupts to automatically read and process PulseSensor data.
|
||||
|
||||
See ProcessEverySample.ino for an example of not using interrupts.
|
||||
*/
|
||||
#define USE_ARDUINO_INTERRUPTS true
|
||||
#include <PulseSensorPlayground.h>
|
||||
#include <SoftwareSerial.h>
|
||||
/*
|
||||
The format of our output.
|
||||
|
||||
Set this to PROCESSING_VISUALIZER if you're going to run
|
||||
the Processing Visualizer Sketch.
|
||||
See https://github.com/WorldFamousElectronics/PulseSensor_Amped_Processing_Visualizer
|
||||
|
||||
Set this to SERIAL_PLOTTER if you're going to run
|
||||
the Arduino IDE's Serial Plotter.
|
||||
*/
|
||||
const int OUTPUT_TYPE = PROCESSING_VISUALIZER;
|
||||
|
||||
/*
|
||||
Pinout:
|
||||
PULSE_INPUT = Analog Input. Connected to the pulse sensor
|
||||
purple (signal) wire.
|
||||
PULSE_BLINK = digital Output. Connected to an LED (and 220 ohm resistor)
|
||||
that will flash on each detected pulse.
|
||||
PULSE_FADE = digital Output. PWM pin onnected to an LED (and resistor)
|
||||
that will smoothly fade with each pulse.
|
||||
NOTE: PULSE_FADE must be a pin that supports PWM. Do not use
|
||||
pin 9 or 10, because those pins' PWM interferes with the sample timer.
|
||||
*/
|
||||
const int PULSE_INPUT = A1;
|
||||
const int PULSE_BLINK = 1; // Pin 13 is the on-board LED
|
||||
const int PULSE_FADE = 0;
|
||||
const int THRESHOLD = 550; // Adjust this number to avoid noise when idle
|
||||
const int TX_PIN = 3; // Using software serial
|
||||
const int RX_PIN = 4;
|
||||
|
||||
/*
|
||||
All the PulseSensor Playground functions.
|
||||
*/
|
||||
PulseSensorPlayground pulseSensor;
|
||||
SoftwareSerial pulseUART(TX_PIN,RX_PIN);
|
||||
|
||||
void setup() {
|
||||
/*
|
||||
Use 115200 baud because that's what the Processing Sketch expects to read,
|
||||
and because that speed provides about 11 bytes per millisecond.
|
||||
|
||||
If we used a slower baud rate, we'd likely write bytes faster than
|
||||
they can be transmitted, which would mess up the timing
|
||||
of readSensor() calls, which would make the pulse measurement
|
||||
not work properly.
|
||||
*/
|
||||
pulseUART.begin(115200);
|
||||
|
||||
// Configure the PulseSensor manager.
|
||||
|
||||
pulseSensor.analogInput(PULSE_INPUT);
|
||||
pulseSensor.blinkOnPulse(PULSE_BLINK);
|
||||
pulseSensor.fadeOnPulse(PULSE_FADE);
|
||||
|
||||
pulseSensor.setSerial(pulseUART);
|
||||
pulseSensor.setOutputType(OUTPUT_TYPE);
|
||||
pulseSensor.setThreshold(THRESHOLD);
|
||||
|
||||
// Now that everything is ready, start reading the PulseSensor signal.
|
||||
if (!pulseSensor.begin()) {
|
||||
/*
|
||||
PulseSensor initialization failed,
|
||||
likely because our particular Arduino platform interrupts
|
||||
aren't supported yet.
|
||||
|
||||
If your Sketch hangs here, try PulseSensor_BPM_Alternative.ino,
|
||||
which doesn't use interrupts.
|
||||
*/
|
||||
for(;;) {
|
||||
// Flash the led to show things didn't work.
|
||||
digitalWrite(PULSE_BLINK, LOW);
|
||||
delay(50);
|
||||
digitalWrite(PULSE_BLINK, HIGH);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
/*
|
||||
Wait a bit.
|
||||
We don't output every sample, because our baud rate
|
||||
won't support that much I/O.
|
||||
*/
|
||||
delay(20);
|
||||
|
||||
// write the latest sample to Serial.
|
||||
pulseSensor.outputSample();
|
||||
|
||||
/*
|
||||
If a beat has happened since we last checked,
|
||||
write the per-beat information to Serial.
|
||||
*/
|
||||
if (pulseSensor.sawStartOfBeat()) {
|
||||
pulseSensor.outputBeat();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Code to detect pulses from the PulseSensor,
|
||||
using an interrupt service routine.
|
||||
|
||||
Here is a link to the tutorial\
|
||||
https://pulsesensor.com/pages/ATtiny
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
|
||||
/*
|
||||
Every Sketch that uses the PulseSensor Playground must
|
||||
define USE_ARDUINO_INTERRUPTS before including PulseSensorPlayground.h.
|
||||
Here, #define USE_ARDUINO_INTERRUPTS true tells the library to use
|
||||
interrupts to automatically read and process PulseSensor data.
|
||||
|
||||
See ProcessEverySample.ino for an example of not using interrupts.
|
||||
*/
|
||||
#define USE_ARDUINO_INTERRUPTS true
|
||||
#include <PulseSensorPlayground.h>
|
||||
|
||||
/*
|
||||
Pinout:
|
||||
PULSE_INPUT = Analog Input. Connected to the pulse sensor
|
||||
purple (signal) wire.
|
||||
PULSE_BLINK = digital Output. Connected to an LED (and 220 ohm resistor)
|
||||
that will flash on each detected pulse.
|
||||
PULSE_FADE = digital Output. PWM pin onnected to an LED (and resistor)
|
||||
that will smoothly fade with each pulse.
|
||||
NOTE: PULSE_FADE must be a pin that supports PWM. Do not use
|
||||
pin 9 or 10, because those pins' PWM interferes with the sample timer.
|
||||
*/
|
||||
const int PULSE_INPUT = A1;
|
||||
const int PULSE_BLINK = 1; // Pin 13 is the on-board LED
|
||||
const int PULSE_FADE = 0;
|
||||
const int THRESHOLD = 550; // Adjust this number to avoid noise when idle
|
||||
|
||||
/*
|
||||
All the PulseSensor Playground functions.
|
||||
*/
|
||||
PulseSensorPlayground pulseSensor;
|
||||
|
||||
void setup() {
|
||||
// Configure the PulseSensor manager.
|
||||
|
||||
pulseSensor.analogInput(PULSE_INPUT);
|
||||
pulseSensor.blinkOnPulse(PULSE_BLINK);
|
||||
pulseSensor.fadeOnPulse(PULSE_FADE);
|
||||
pulseSensor.setThreshold(THRESHOLD);
|
||||
|
||||
// Now that everything is ready, start reading the PulseSensor signal.
|
||||
if (!pulseSensor.begin()) {
|
||||
/*
|
||||
PulseSensor initialization failed,
|
||||
likely because our particular Arduino platform interrupts
|
||||
aren't supported yet.
|
||||
|
||||
If your Sketch hangs here, try PulseSensor_BPM_Alternative.ino,
|
||||
which doesn't use interrupts.
|
||||
*/
|
||||
for(;;) {
|
||||
// Flash the led to show things didn't work.
|
||||
digitalWrite(PULSE_BLINK, LOW);
|
||||
delay(50);
|
||||
digitalWrite(PULSE_BLINK, HIGH);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
/*
|
||||
When we're not outputting serial messages
|
||||
there's not much to do here.
|
||||
In case you want to add more behavior to the sketch
|
||||
you can use sawStartOfBeat() or isInsideBeat()
|
||||
to have the sketch do stuff when there's a beat.
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
Code to detect pulses from the PulseSensor,
|
||||
using an interrupt service routine.
|
||||
|
||||
Here is a link to the tutorial\
|
||||
https://pulsesensor.com/pages/getting-advanced
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
|
||||
/*
|
||||
Every Sketch that uses the PulseSensor Playground must
|
||||
define USE_ARDUINO_INTERRUPTS before including PulseSensorPlayground.h.
|
||||
Here, #define USE_ARDUINO_INTERRUPTS true tells the library to use
|
||||
interrupts to automatically read and process PulseSensor data.
|
||||
|
||||
See ProcessEverySample.ino for an example of not using interrupts.
|
||||
*/
|
||||
#define USE_ARDUINO_INTERRUPTS true
|
||||
#include <PulseSensorPlayground.h>
|
||||
|
||||
/*
|
||||
The format of our output.
|
||||
|
||||
Set this to PROCESSING_VISUALIZER if you're going to run
|
||||
the Processing Visualizer Sketch.
|
||||
See https://github.com/WorldFamousElectronics/PulseSensor_Amped_Processing_Visualizer
|
||||
|
||||
Set this to SERIAL_PLOTTER if you're going to run
|
||||
the Arduino IDE's Serial Plotter.
|
||||
*/
|
||||
const int OUTPUT_TYPE = SERIAL_PLOTTER;
|
||||
|
||||
/*
|
||||
Pinout:
|
||||
PULSE_INPUT = Analog Input. Connected to the pulse sensor
|
||||
purple (signal) wire.
|
||||
PULSE_BLINK = digital Output. Connected to an LED (and 220 ohm resistor)
|
||||
that will flash on each detected pulse.
|
||||
PULSE_FADE = digital Output. PWM pin onnected to an LED (and resistor)
|
||||
that will smoothly fade with each pulse.
|
||||
NOTE: PULSE_FADE must be a pin that supports PWM. Do not use
|
||||
pin 9 or 10, because those pins' PWM interferes with the sample timer.
|
||||
*/
|
||||
const int PULSE_INPUT = A0;
|
||||
const int PULSE_BLINK = 13; // Pin 13 is the on-board LED
|
||||
const int PULSE_FADE = 5;
|
||||
const int THRESHOLD = 550; // Adjust this number to avoid noise when idle
|
||||
|
||||
/*
|
||||
All the PulseSensor Playground functions.
|
||||
*/
|
||||
PulseSensorPlayground pulseSensor;
|
||||
|
||||
void setup() {
|
||||
/*
|
||||
Use 115200 baud because that's what the Processing Sketch expects to read,
|
||||
and because that speed provides about 11 bytes per millisecond.
|
||||
|
||||
If we used a slower baud rate, we'd likely write bytes faster than
|
||||
they can be transmitted, which would mess up the timing
|
||||
of readSensor() calls, which would make the pulse measurement
|
||||
not work properly.
|
||||
*/
|
||||
Serial.begin(115200);
|
||||
|
||||
// Configure the PulseSensor manager.
|
||||
|
||||
pulseSensor.analogInput(PULSE_INPUT);
|
||||
pulseSensor.blinkOnPulse(PULSE_BLINK);
|
||||
pulseSensor.fadeOnPulse(PULSE_FADE);
|
||||
|
||||
pulseSensor.setSerial(Serial);
|
||||
pulseSensor.setOutputType(OUTPUT_TYPE);
|
||||
pulseSensor.setThreshold(THRESHOLD);
|
||||
|
||||
// Now that everything is ready, start reading the PulseSensor signal.
|
||||
if (!pulseSensor.begin()) {
|
||||
/*
|
||||
PulseSensor initialization failed,
|
||||
likely because our particular Arduino platform interrupts
|
||||
aren't supported yet.
|
||||
|
||||
If your Sketch hangs here, try PulseSensor_BPM_Alternative.ino,
|
||||
which doesn't use interrupts.
|
||||
*/
|
||||
for(;;) {
|
||||
// Flash the led to show things didn't work.
|
||||
digitalWrite(PULSE_BLINK, LOW);
|
||||
delay(50);
|
||||
digitalWrite(PULSE_BLINK, HIGH);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
/*
|
||||
Wait a bit.
|
||||
We don't output every sample, because our baud rate
|
||||
won't support that much I/O.
|
||||
*/
|
||||
delay(20);
|
||||
|
||||
// write the latest sample to Serial.
|
||||
pulseSensor.outputSample();
|
||||
|
||||
/*
|
||||
If a beat has happened since we last checked,
|
||||
write the per-beat information to Serial.
|
||||
*/
|
||||
if (pulseSensor.sawStartOfBeat()) {
|
||||
pulseSensor.outputBeat();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
Sketch to handle each sample read from a PulseSensor.
|
||||
Typically used when you don't want to use interrupts
|
||||
to read PulseSensor voltages.
|
||||
|
||||
Here is a link to the tutorial that discusses this code
|
||||
https://pulsesensor.com/pages/getting-advanced
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
|
||||
/*
|
||||
Every Sketch that uses the PulseSensor Playground must
|
||||
define USE_ARDUINO_INTERRUPTS before including PulseSensorPlayground.h.
|
||||
Here, #define USE_ARDUINO_INTERRUPTS false tells the library to
|
||||
not use interrupts to read data from the PulseSensor.
|
||||
|
||||
If you want to use interrupts, simply change the line below
|
||||
to read:
|
||||
#define USE_ARDUINO_INTERRUPTS true
|
||||
|
||||
Set US_PS_INTERRUPTS to false if either
|
||||
1) Your Arduino platform's interrupts aren't yet supported
|
||||
by PulseSensor Playground, or
|
||||
2) You don't wish to use interrupts because of the side effects.
|
||||
|
||||
NOTE: if US_PS_INTERRUPTS is false, your Sketch must
|
||||
call pulse.sawNewSample() at least once every 2 milliseconds
|
||||
to accurately read the PulseSensor signal.
|
||||
*/
|
||||
#define USE_ARDUINO_INTERRUPTS false
|
||||
#include <PulseSensorPlayground.h>
|
||||
|
||||
/*
|
||||
The format of our output.
|
||||
|
||||
Set this to PROCESSING_VISUALIZER if you're going to run
|
||||
the Processing Visualizer Sketch.
|
||||
See https://github.com/WorldFamousElectronics/PulseSensor_Amped_Processing_Visualizer
|
||||
|
||||
Set this to SERIAL_PLOTTER if you're going to run
|
||||
the Arduino IDE's Serial Plotter.
|
||||
*/
|
||||
const int OUTPUT_TYPE = SERIAL_PLOTTER;
|
||||
|
||||
/*
|
||||
Pinout:
|
||||
PULSE_INPUT = Analog Input. Connected to the pulse sensor
|
||||
purple (signal) wire.
|
||||
PULSE_BLINK = digital Output. Connected to an LED (and 220 ohm resistor)
|
||||
that will flash on each detected pulse.
|
||||
PULSE_FADE = digital Output. PWM pin onnected to an LED (and resistor)
|
||||
that will smoothly fade with each pulse.
|
||||
NOTE: PULSE_FADE must be a pin that supports PWM.
|
||||
If USE_INTERRUPTS is true, Do not use pin 9 or 10 for PULSE_FADE,
|
||||
because those pins' PWM interferes with the sample timer.
|
||||
*/
|
||||
const int PULSE_INPUT = A0;
|
||||
const int PULSE_BLINK = 13; // Pin 13 is the on-board LED
|
||||
const int PULSE_FADE = 5;
|
||||
const int THRESHOLD = 550; // Adjust this number to avoid noise when idle
|
||||
|
||||
/*
|
||||
samplesUntilReport = the number of samples remaining to read
|
||||
until we want to report a sample over the serial connection.
|
||||
|
||||
We want to report a sample value over the serial port
|
||||
only once every 20 milliseconds (10 samples) to avoid
|
||||
doing Serial output faster than the Arduino can send.
|
||||
*/
|
||||
byte samplesUntilReport;
|
||||
const byte SAMPLES_PER_SERIAL_SAMPLE = 10;
|
||||
|
||||
/*
|
||||
All the PulseSensor Playground functions.
|
||||
*/
|
||||
PulseSensorPlayground pulseSensor;
|
||||
|
||||
void setup() {
|
||||
/*
|
||||
Use 115200 baud because that's what the Processing Sketch expects to read,
|
||||
and because that speed provides about 11 bytes per millisecond.
|
||||
|
||||
If we used a slower baud rate, we'd likely write bytes faster than
|
||||
they can be transmitted, which would mess up the timing
|
||||
of readSensor() calls, which would make the pulse measurement
|
||||
not work properly.
|
||||
*/
|
||||
Serial.begin(115200);
|
||||
|
||||
// Configure the PulseSensor manager.
|
||||
pulseSensor.analogInput(PULSE_INPUT);
|
||||
pulseSensor.blinkOnPulse(PULSE_BLINK);
|
||||
pulseSensor.fadeOnPulse(PULSE_FADE);
|
||||
|
||||
pulseSensor.setSerial(Serial);
|
||||
pulseSensor.setOutputType(OUTPUT_TYPE);
|
||||
pulseSensor.setThreshold(THRESHOLD);
|
||||
|
||||
// Skip the first SAMPLES_PER_SERIAL_SAMPLE in the loop().
|
||||
samplesUntilReport = SAMPLES_PER_SERIAL_SAMPLE;
|
||||
|
||||
// Now that everything is ready, start reading the PulseSensor signal.
|
||||
if (!pulseSensor.begin()) {
|
||||
/*
|
||||
PulseSensor initialization failed,
|
||||
likely because our Arduino platform interrupts
|
||||
aren't supported yet.
|
||||
|
||||
If your Sketch hangs here, try changing USE_PS_INTERRUPT to false.
|
||||
*/
|
||||
for(;;) {
|
||||
// Flash the led to show things didn't work.
|
||||
digitalWrite(PULSE_BLINK, LOW);
|
||||
delay(50);
|
||||
digitalWrite(PULSE_BLINK, HIGH);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
/*
|
||||
See if a sample is ready from the PulseSensor.
|
||||
|
||||
If USE_INTERRUPTS is true, the PulseSensor Playground
|
||||
will automatically read and process samples from
|
||||
the PulseSensor.
|
||||
|
||||
If USE_INTERRUPTS is false, this call to sawNewSample()
|
||||
will, if enough time has passed, read and process a
|
||||
sample (analog voltage) from the PulseSensor.
|
||||
*/
|
||||
if (pulseSensor.sawNewSample()) {
|
||||
/*
|
||||
Every so often, send the latest Sample.
|
||||
We don't print every sample, because our baud rate
|
||||
won't support that much I/O.
|
||||
*/
|
||||
if (--samplesUntilReport == (byte) 0) {
|
||||
samplesUntilReport = SAMPLES_PER_SERIAL_SAMPLE;
|
||||
|
||||
pulseSensor.outputSample();
|
||||
|
||||
/*
|
||||
At about the beginning of every heartbeat,
|
||||
report the heart rate and inter-beat-interval.
|
||||
*/
|
||||
if (pulseSensor.sawStartOfBeat()) {
|
||||
pulseSensor.outputBeat();
|
||||
}
|
||||
}
|
||||
|
||||
/*******
|
||||
Here is a good place to add code that could take up
|
||||
to a millisecond or so to run.
|
||||
*******/
|
||||
}
|
||||
|
||||
/******
|
||||
Don't add code here, because it could slow the sampling
|
||||
from the PulseSensor.
|
||||
******/
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
Sketch to handle each sample read from a PulseSensor.
|
||||
Typically used when you don't want to use interrupts
|
||||
to read PulseSensor voltages.
|
||||
|
||||
Here is a link to the tutorial that discusses this code
|
||||
>> Comming Soon! <<
|
||||
|
||||
Use this code as a basic example when targeting STM32 boards.
|
||||
Open your Arduino > Preferences window, and add this to your Additional Boards Manager URLs:
|
||||
|
||||
https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/master/STM32/package_stm_index.json
|
||||
|
||||
Then, go to Tools > Board > Boards Manager to install the STM32 core.
|
||||
|
||||
This example targets the Nucleo 64 F401RE
|
||||
If you are using a different Nucleo board, you may have to change some of the
|
||||
board parameters. Here are the drop-down selections that I used.
|
||||
|
||||
Board: Nucleo-64
|
||||
Board Part Number: Nucleo F401RE
|
||||
Serial Interface: Enable first third (USART to 3 if available)
|
||||
USB Interace: None
|
||||
Upload Method: STlink
|
||||
Optimize: Smallest (-Os defalut)
|
||||
|
||||
This sketch uses Serial1 to communicate with your computer.
|
||||
Attach an FTDI or other USB > Serial breakout to the pins
|
||||
|
||||
tx: D8 (Arduino Pin)
|
||||
rx: D2 (Arduino Pin)
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
|
||||
/*
|
||||
Every Sketch that uses the PulseSensor Playground must
|
||||
define USE_ARDUINO_INTERRUPTS before including PulseSensorPlayground.h.
|
||||
Here, #define USE_ARDUINO_INTERRUPTS false tells the library to
|
||||
not use interrupts to read data from the PulseSensor.
|
||||
|
||||
If you want to use interrupts, simply change the line below
|
||||
to read:
|
||||
#define USE_ARDUINO_INTERRUPTS true
|
||||
|
||||
Set US_PS_INTERRUPTS to false if either
|
||||
1) Your Arduino platform's interrupts aren't yet supported
|
||||
by PulseSensor Playground, or
|
||||
2) You don't wish to use interrupts because of the side effects.
|
||||
|
||||
NOTE: if US_PS_INTERRUPTS is false, your Sketch must
|
||||
call pulse.sawNewSample() at least once every 2 milliseconds
|
||||
to accurately read the PulseSensor signal.
|
||||
*/
|
||||
#define USE_ARDUINO_INTERRUPTS false
|
||||
#include <PulseSensorPlayground.h>
|
||||
|
||||
/*
|
||||
The format of our output.
|
||||
|
||||
Set this to PROCESSING_VISUALIZER if you're going to run
|
||||
the Processing Visualizer Sketch.
|
||||
See https://github.com/WorldFamousElectronics/PulseSensor_Amped_Processing_Visualizer
|
||||
|
||||
Set this to SERIAL_PLOTTER if you're going to run
|
||||
the Arduino IDE's Serial Plotter.
|
||||
*/
|
||||
const int OUTPUT_TYPE = SERIAL_PLOTTER;
|
||||
|
||||
/*
|
||||
Pinout:
|
||||
PULSE_INPUT = Analog Input. Connected to the pulse sensor
|
||||
purple (signal) wire.
|
||||
PULSE_BLINK = digital Output. Connected to an LED (and 220 ohm resistor)
|
||||
that will flash on each detected pulse.
|
||||
PULSE_FADE = digital Output. PWM pin onnected to an LED (and resistor)
|
||||
that will smoothly fade with each pulse.
|
||||
NOTE: PULSE_FADE must be a pin that supports PWM.
|
||||
If USE_INTERRUPTS is true, Do not use pin 9 or 10 for PULSE_FADE,
|
||||
because those pins' PWM interferes with the sample timer.
|
||||
*/
|
||||
const int PULSE_INPUT = A0;
|
||||
const int PULSE_BLINK = 13; // Pin 13 is the on-board LED
|
||||
const int PULSE_FADE = 5;
|
||||
const int THRESHOLD = 550; // Adjust this number to avoid noise when idle
|
||||
|
||||
/*
|
||||
samplesUntilReport = the number of samples remaining to read
|
||||
until we want to report a sample over the serial connection.
|
||||
|
||||
We want to report a sample value over the serial port
|
||||
only once every 20 milliseconds (10 samples) to avoid
|
||||
doing Serial output faster than the Arduino can send.
|
||||
*/
|
||||
byte samplesUntilReport;
|
||||
const byte SAMPLES_PER_SERIAL_SAMPLE = 10;
|
||||
|
||||
/*
|
||||
All the PulseSensor Playground functions.
|
||||
*/
|
||||
PulseSensorPlayground pulseSensor;
|
||||
|
||||
void setup() {
|
||||
/*
|
||||
Use 115200 baud because that's what the Processing Sketch expects to read,
|
||||
and because that speed provides about 11 bytes per millisecond.
|
||||
|
||||
If we used a slower baud rate, we'd likely write bytes faster than
|
||||
they can be transmitted, which would mess up the timing
|
||||
of readSensor() calls, which would make the pulse measurement
|
||||
not work properly.
|
||||
*/
|
||||
Serial1.begin(115200);
|
||||
|
||||
// Configure the PulseSensor manager.
|
||||
pulseSensor.analogInput(PULSE_INPUT);
|
||||
pulseSensor.blinkOnPulse(PULSE_BLINK);
|
||||
pulseSensor.fadeOnPulse(PULSE_FADE);
|
||||
|
||||
pulseSensor.setSerial(Serial1);
|
||||
pulseSensor.setOutputType(OUTPUT_TYPE);
|
||||
pulseSensor.setThreshold(THRESHOLD);
|
||||
|
||||
// Skip the first SAMPLES_PER_SERIAL_SAMPLE in the loop().
|
||||
samplesUntilReport = SAMPLES_PER_SERIAL_SAMPLE;
|
||||
|
||||
// Now that everything is ready, start reading the PulseSensor signal.
|
||||
if (!pulseSensor.begin()) {
|
||||
/*
|
||||
PulseSensor initialization failed,
|
||||
likely because our Arduino platform interrupts
|
||||
aren't supported yet.
|
||||
|
||||
If your Sketch hangs here, try changing USE_PS_INTERRUPT to false.
|
||||
*/
|
||||
for(;;) {
|
||||
// Flash the led to show things didn't work.
|
||||
digitalWrite(PULSE_BLINK, LOW);
|
||||
delay(50);
|
||||
digitalWrite(PULSE_BLINK, HIGH);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
/*
|
||||
See if a sample is ready from the PulseSensor.
|
||||
|
||||
If USE_INTERRUPTS is true, the PulseSensor Playground
|
||||
will automatically read and process samples from
|
||||
the PulseSensor.
|
||||
|
||||
If USE_INTERRUPTS is false, this call to sawNewSample()
|
||||
will, if enough time has passed, read and process a
|
||||
sample (analog voltage) from the PulseSensor.
|
||||
*/
|
||||
if (pulseSensor.sawNewSample()) {
|
||||
/*
|
||||
Every so often, send the latest Sample.
|
||||
We don't print every sample, because our baud rate
|
||||
won't support that much I/O.
|
||||
*/
|
||||
if (--samplesUntilReport == (byte) 0) {
|
||||
samplesUntilReport = SAMPLES_PER_SERIAL_SAMPLE;
|
||||
|
||||
pulseSensor.outputSample();
|
||||
|
||||
/*
|
||||
At about the beginning of every heartbeat,
|
||||
report the heart rate and inter-beat-interval.
|
||||
*/
|
||||
if (pulseSensor.sawStartOfBeat()) {
|
||||
pulseSensor.outputBeat();
|
||||
}
|
||||
}
|
||||
|
||||
/*******
|
||||
Here is a good place to add code that could take up
|
||||
to a millisecond or so to run.
|
||||
*******/
|
||||
}
|
||||
|
||||
/******
|
||||
Don't add code here, because it could slow the sampling
|
||||
from the PulseSensor.
|
||||
******/
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
Arduino Sketch to detect pulses from two PulseSensors
|
||||
and measures the time between! This can be used to derive
|
||||
Pulse Transit Time (PTT)
|
||||
|
||||
Here is a link to the PTT tutorial
|
||||
https://pulsesensor.com/pages/pulse-transit-time
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
|
||||
/*
|
||||
Every Sketch that uses the PulseSensor Playground must
|
||||
define USE_ARDUINO_INTERRUPTS before including PulseSensorPlayground.h.
|
||||
Here, #define USE_ARDUINO_INTERRUPTS false tells the library to
|
||||
not use interrupts to read data from the PulseSensor.
|
||||
|
||||
If you want to use interrupts, simply change the line below
|
||||
to read:
|
||||
#define USE_ARDUINO_INTERRUPTS true
|
||||
|
||||
Set US_PS_INTERRUPTS to false if either
|
||||
1) Your Arduino platform's interrupts aren't yet supported
|
||||
by PulseSensor Playground, or
|
||||
2) You don't wish to use interrupts because of the side effects.
|
||||
|
||||
NOTE: if US_PS_INTERRUPTS is false, your Sketch must
|
||||
call pulse.sawNewSample() at least once every 2 milliseconds
|
||||
to accurately read the PulseSensor signal.
|
||||
*/
|
||||
#define USE_ARDUINO_INTERRUPTS true
|
||||
#include <PulseSensorPlayground.h>
|
||||
|
||||
|
||||
/*
|
||||
The format of our output.
|
||||
|
||||
Set this to PROCESSING_VISUALIZER if you're going to run
|
||||
the multi-sensor Processing Visualizer Sketch.
|
||||
See https://github.com/WorldFamousElectronics/PulseSensorAmped_2_Sensors
|
||||
|
||||
Set this to SERIAL_PLOTTER if you're going to run
|
||||
the Arduino IDE's Serial Plotter.
|
||||
*/
|
||||
const int OUTPUT_TYPE = PROCESSING_VISUALIZER;
|
||||
|
||||
/*
|
||||
Number of PulseSensor devices we're reading from.
|
||||
*/
|
||||
const int PULSE_SENSOR_COUNT = 2;
|
||||
|
||||
/*
|
||||
PULSE_POWERx = the output pin that the red (power) pin of
|
||||
the first PulseSensor will be connected to. PulseSensor only
|
||||
draws about 4mA, so almost any micro can power it from a GPIO.
|
||||
If you don't want to use pins to power the PulseSensors, you can remove
|
||||
the code dealing with PULSE_POWER0 and PULSE_POWER1.
|
||||
PULSE_INPUTx = Analog Input. Connected to the pulse sensor
|
||||
purple (signal) wire.
|
||||
PULSE_BLINKx = digital Output. Connected to an LED (must have at least
|
||||
470 ohm resistor) that will flash on each detected pulse.
|
||||
PULSE_FADEx = digital Output. PWM pin onnected to an LED (must have
|
||||
at least 470 ohm resistor) that will smoothly fade with each pulse.
|
||||
|
||||
NOTE: PULSE_FADEx must be pins that support PWM.
|
||||
If USE_INTERRUPTS is true, Do not use pin 9 or 10 for PULSE_FADEx
|
||||
because those pins' PWM interferes with the sample timer.
|
||||
*/
|
||||
const int PULSE_INPUT0 = A0;
|
||||
const int PULSE_BLINK0 = 13; // Pin 13 is the on-board LED
|
||||
const int PULSE_FADE0 = 5;
|
||||
|
||||
const int PULSE_INPUT1 = A1;
|
||||
const int PULSE_BLINK1 = 12;
|
||||
const int PULSE_FADE1 = 11;
|
||||
|
||||
const int THRESHOLD = 550; // Adjust this number to avoid noise when idle
|
||||
|
||||
/*
|
||||
All the PulseSensor Playground functions.
|
||||
We tell it how many PulseSensors we're using.
|
||||
*/
|
||||
PulseSensorPlayground pulseSensor(PULSE_SENSOR_COUNT);
|
||||
|
||||
/*
|
||||
Variables used to determine PTT.
|
||||
NOTE: This code assumes the Pulse Sensor on analog pin 0 is closer to he heart.
|
||||
*/
|
||||
unsigned long lastBeatSampleNumber[PULSE_SENSOR_COUNT];
|
||||
int PTT;
|
||||
|
||||
void setup() {
|
||||
/*
|
||||
Use 250000 baud because that's what the Processing Sketch expects to read,
|
||||
and because that speed provides about 25 bytes per millisecond,
|
||||
or 50 characters per PulseSensor sample period of 2 milliseconds.
|
||||
|
||||
If we used a slower baud rate, we'd likely write bytes faster than
|
||||
they can be transmitted, which would mess up the timing
|
||||
of readSensor() calls, which would make the pulse measurement
|
||||
not work properly.
|
||||
*/
|
||||
Serial.begin(250000);
|
||||
|
||||
/*
|
||||
Configure the PulseSensor manager,
|
||||
telling it which PulseSensor (0 or 1)
|
||||
we're configuring.
|
||||
*/
|
||||
|
||||
pulseSensor.analogInput(PULSE_INPUT0, 0);
|
||||
pulseSensor.blinkOnPulse(PULSE_BLINK0, 0);
|
||||
pulseSensor.fadeOnPulse(PULSE_FADE0, 0);
|
||||
|
||||
pulseSensor.analogInput(PULSE_INPUT1, 1);
|
||||
pulseSensor.blinkOnPulse(PULSE_BLINK1, 1);
|
||||
pulseSensor.fadeOnPulse(PULSE_FADE1, 1);
|
||||
|
||||
pulseSensor.setSerial(Serial);
|
||||
pulseSensor.setOutputType(OUTPUT_TYPE);
|
||||
pulseSensor.setThreshold(THRESHOLD);
|
||||
|
||||
|
||||
// Now that everything is ready, start reading the PulseSensor signal.
|
||||
if (!pulseSensor.begin()) {
|
||||
/*
|
||||
PulseSensor initialization failed,
|
||||
likely because our Arduino platform interrupts
|
||||
aren't supported yet.
|
||||
|
||||
If your Sketch hangs here, try changing USE_ARDUINO_INTERRUPTS to false.
|
||||
*/
|
||||
for (;;) {
|
||||
// Flash the led to show things didn't work.
|
||||
digitalWrite(PULSE_BLINK0, LOW);
|
||||
delay(50);
|
||||
digitalWrite(PULSE_BLINK0, HIGH);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
/*
|
||||
Wait a bit.
|
||||
We don't output every sample, because our baud rate
|
||||
won't support that much I/O.
|
||||
*/
|
||||
delay(20);
|
||||
|
||||
// write the latest sample to Serial.
|
||||
pulseSensor.outputSample();
|
||||
|
||||
/*
|
||||
If a beat has happened on a given PulseSensor
|
||||
since we last checked, write the per-beat information
|
||||
about that PulseSensor to Serial.
|
||||
*/
|
||||
for (int i = 0; i < PULSE_SENSOR_COUNT; ++i) {
|
||||
if (pulseSensor.sawStartOfBeat(i)) {
|
||||
pulseSensor.outputBeat(i);
|
||||
|
||||
lastBeatSampleNumber[i] = pulseSensor.getLastBeatTime(i);
|
||||
if(i == 1){
|
||||
PTT = lastBeatSampleNumber[1] - lastBeatSampleNumber[0];
|
||||
pulseSensor.outputToSerial('|',PTT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
Code to detect pulses from the PulseSensor
|
||||
and move a servo motor to the beat.
|
||||
uses an interrupt service routine.
|
||||
|
||||
Here is a link to the tutorial
|
||||
https://pulsesensor.com/pages/pulse-sensor-servo-tutorial
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
|
||||
/*
|
||||
Include Servo.h BEFORE you include PusleSensorPlayground.h
|
||||
*/
|
||||
#include <Servo.h>
|
||||
|
||||
/*
|
||||
Every Sketch that uses the PulseSensor Playground must
|
||||
define USE_ARDUINO_INTERRUPTS before including PulseSensorPlayground.h.
|
||||
Here, #define USE_ARDUINO_INTERRUPTS true tells the library to use
|
||||
interrupts to automatically read and process PulseSensor data.
|
||||
|
||||
See ProcessEverySample.ino for an example of not using interrupts.
|
||||
*/
|
||||
#define USE_ARDUINO_INTERRUPTS true
|
||||
#include <PulseSensorPlayground.h>
|
||||
|
||||
/*
|
||||
The format of our output.
|
||||
|
||||
Set this to PROCESSING_VISUALIZER if you're going to run
|
||||
the Processing Visualizer Sketch.
|
||||
See https://github.com/WorldFamousElectronics/PulseSensor_Amped_Processing_Visualizer
|
||||
|
||||
Set this to SERIAL_PLOTTER if you're going to run
|
||||
the Arduino IDE's Serial Plotter.
|
||||
*/
|
||||
const int OUTPUT_TYPE = SERIAL_PLOTTER;
|
||||
|
||||
/*
|
||||
Pinout:
|
||||
PULSE_INPUT = Analog Input. Connected to the pulse sensor
|
||||
purple (signal) wire.
|
||||
PULSE_BLINK = digital Output. Connected to an LED (and 220 ohm resistor)
|
||||
that will flash on each detected pulse.
|
||||
PULSE_FADE = digital Output. PWM pin onnected to an LED (and resistor)
|
||||
that will smoothly fade with each pulse.
|
||||
NOTE: PULSE_FADE must be a pin that supports PWM. Do not use
|
||||
pin 9 or 10, because those pins' PWM interferes with the sample timer.
|
||||
*/
|
||||
const int PULSE_INPUT = A0;
|
||||
const int PULSE_BLINK = 13; // Pin 13 is the on-board LED
|
||||
const int PULSE_FADE = 5;
|
||||
const int THRESHOLD = 550; // Adjust this number to avoid noise when idle
|
||||
|
||||
/*
|
||||
All the PulseSensor Playground functions.
|
||||
*/
|
||||
PulseSensorPlayground pulseSensor;
|
||||
|
||||
/*
|
||||
Make a heart servo, the pin to control it with, and a servo position variable
|
||||
*/
|
||||
Servo heart;
|
||||
const int SERVO_PIN = 6;
|
||||
int pos = 90;
|
||||
|
||||
void setup() {
|
||||
/*
|
||||
Use 115200 baud because that's what the Processing Sketch expects to read,
|
||||
and because that speed provides about 11 bytes per millisecond.
|
||||
|
||||
If we used a slower baud rate, we'd likely write bytes faster than
|
||||
they can be transmitted, which would mess up the timing
|
||||
of readSensor() calls, which would make the pulse measurement
|
||||
not work properly.
|
||||
*/
|
||||
Serial.begin(115200);
|
||||
// set up the heart servo on SERVO_PULSE
|
||||
// set servo position to pos (90 degrees, mid position)
|
||||
heart.attach(SERVO_PIN);
|
||||
heart.write(pos);
|
||||
|
||||
// Configure the PulseSensor manager.
|
||||
pulseSensor.analogInput(PULSE_INPUT);
|
||||
pulseSensor.blinkOnPulse(PULSE_BLINK);
|
||||
pulseSensor.fadeOnPulse(PULSE_FADE);
|
||||
|
||||
pulseSensor.setSerial(Serial);
|
||||
pulseSensor.setOutputType(OUTPUT_TYPE);
|
||||
pulseSensor.setThreshold(THRESHOLD);
|
||||
|
||||
// Now that everything is ready, start reading the PulseSensor signal.
|
||||
if (!pulseSensor.begin()) {
|
||||
/*
|
||||
PulseSensor initialization failed,
|
||||
likely because our particular Arduino platform interrupts
|
||||
aren't supported yet.
|
||||
|
||||
If your Sketch hangs here, try changing USE_ARDUINO_INTERRUPTS to false.
|
||||
which doesn't use interrupts.
|
||||
*/
|
||||
for(;;) {
|
||||
// Flash the led to show things didn't work.
|
||||
digitalWrite(PULSE_BLINK, LOW);
|
||||
delay(50);
|
||||
digitalWrite(PULSE_BLINK, HIGH);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
/*
|
||||
Wait a bit.
|
||||
We don't output every sample, because our baud rate
|
||||
won't support that much I/O.
|
||||
*/
|
||||
delay(20);
|
||||
|
||||
// write the latest sample to Serial.
|
||||
pulseSensor.outputSample();
|
||||
|
||||
// write the latest analog value to the heart servo
|
||||
moveServo(pulseSensor.getLatestSample());
|
||||
|
||||
/*
|
||||
If a beat has happened since we last checked,
|
||||
write the per-beat information to Serial.
|
||||
*/
|
||||
if (pulseSensor.sawStartOfBeat()) {
|
||||
pulseSensor.outputBeat();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Map the Pulse Sensor Signal to the Servo range
|
||||
Pulse Sensor = 0 <> 1023
|
||||
Servo = 0 <> 180
|
||||
Modify as you see fit!
|
||||
*/
|
||||
void moveServo(int value){
|
||||
pos = map(value,0,1023,0,180);
|
||||
heart.write(pos);
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
Code to detect pulses from the PulseSensor,
|
||||
using an interrupt service routine.
|
||||
|
||||
>>>> THIS EXAMPLE OUTPUTS USES TONE COMMAND <<<<
|
||||
>>>> TO MAKE A SPEAKER BEEP WITH HEARTBEAT! <<<<
|
||||
|
||||
Here is a link to the tutorial
|
||||
https://pulsesensor.com/pages/pulse-sensor-speaker-tutorial
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
|
||||
/*
|
||||
Every Sketch that uses the PulseSensor Playground must
|
||||
define USE_ARDUINO_INTERRUPTS before including PulseSensorPlayground.h.
|
||||
Here, #define USE_ARDUINO_INTERRUPTS true tells the library to use
|
||||
interrupts to automatically read and process PulseSensor data.
|
||||
|
||||
See ProcessEverySample.ino for an example of not using interrupts.
|
||||
*/
|
||||
#define USE_ARDUINO_INTERRUPTS true
|
||||
#include <PulseSensorPlayground.h>
|
||||
|
||||
/*
|
||||
The format of our output.
|
||||
|
||||
Set this to PROCESSING_VISUALIZER if you're going to run
|
||||
the Processing Visualizer Sketch.
|
||||
See https://github.com/WorldFamousElectronics/PulseSensor_Amped_Processing_Visualizer
|
||||
|
||||
Set this to SERIAL_PLOTTER if you're going to run
|
||||
the Arduino IDE's Serial Plotter.
|
||||
*/
|
||||
const int OUTPUT_TYPE = SERIAL_PLOTTER;
|
||||
|
||||
/*
|
||||
Pinout:
|
||||
PULSE_INPUT = Analog Input. Connected to the pulse sensor
|
||||
purple (signal) wire.
|
||||
PULSE_BLINK = digital Output. Connected to an LED (and 220 ohm resistor)
|
||||
that will flash on each detected pulse.
|
||||
PULSE_FADE = digital Output. PWM pin onnected to an LED (and resistor)
|
||||
that will smoothly fade with each pulse.
|
||||
NOTE: PULSE_FADE must be a pin that supports PWM. Do not use
|
||||
pin 9 or 10, because those pins' PWM interferes with the sample timer.
|
||||
*/
|
||||
const int PULSE_INPUT = A0;
|
||||
const int PULSE_BLINK = 13; // Pin 13 is the on-board LED
|
||||
const int PULSE_FADE = 5;
|
||||
const int THRESHOLD = 550; // Adjust this number to avoid noise when idle
|
||||
|
||||
/*
|
||||
All the PulseSensor Playground functions.
|
||||
*/
|
||||
PulseSensorPlayground pulseSensor;
|
||||
|
||||
/*
|
||||
Setup the things we need for driving the Speaker
|
||||
NOTE: Speaker MUST be AC coupled! Connect PIN_SPEAKER to red speaker wire.
|
||||
Then connect black speaker wire to + side of electrolytic capacitor.
|
||||
Then connect - side of electrolytic capacitor to GND.
|
||||
Capacitor value should be 1uF or higher!
|
||||
Follow this tutorial:
|
||||
[link]
|
||||
*/
|
||||
const int PIN_SPEAKER = 2; // speaker on pin2 makes a beep with heartbeat
|
||||
|
||||
|
||||
void setup() {
|
||||
/*
|
||||
Use 115200 baud because that's what the Processing Sketch expects to read,
|
||||
and because that speed provides about 11 bytes per millisecond.
|
||||
|
||||
If we used a slower baud rate, we'd likely write bytes faster than
|
||||
they can be transmitted, which would mess up the timing
|
||||
of readSensor() calls, which would make the pulse measurement
|
||||
not work properly.
|
||||
*/
|
||||
Serial.begin(115200);
|
||||
|
||||
// Configure the PulseSensor manager.
|
||||
|
||||
pulseSensor.analogInput(PULSE_INPUT);
|
||||
pulseSensor.blinkOnPulse(PULSE_BLINK);
|
||||
pulseSensor.fadeOnPulse(PULSE_FADE);
|
||||
|
||||
pulseSensor.setSerial(Serial);
|
||||
pulseSensor.setOutputType(OUTPUT_TYPE);
|
||||
pulseSensor.setThreshold(THRESHOLD);
|
||||
|
||||
// Now that everything is ready, start reading the PulseSensor signal.
|
||||
if (!pulseSensor.begin()) {
|
||||
/*
|
||||
PulseSensor initialization failed,
|
||||
likely because our particular Arduino platform interrupts
|
||||
aren't supported yet.
|
||||
|
||||
If your Sketch hangs here, try changing USE_ARDUINO_INTERRUPTS to false.
|
||||
which doesn't use interrupts.
|
||||
*/
|
||||
for(;;) {
|
||||
// Flash the led to show things didn't work.
|
||||
digitalWrite(PULSE_BLINK, LOW);
|
||||
delay(50);
|
||||
digitalWrite(PULSE_BLINK, HIGH);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
/*
|
||||
Wait a bit.
|
||||
We don't output every sample, because our baud rate
|
||||
won't support that much I/O.
|
||||
*/
|
||||
delay(20);
|
||||
|
||||
// write the latest sample to Serial.
|
||||
pulseSensor.outputSample();
|
||||
|
||||
/*
|
||||
If a beat has happened since we last checked,
|
||||
write the per-beat information to Serial.
|
||||
write a frequency to the PIN_SPEAKER
|
||||
NOTE: Do not set the optional duration of tone! That is blocking!
|
||||
*/
|
||||
if (pulseSensor.sawStartOfBeat()) {
|
||||
pulseSensor.outputBeat();
|
||||
tone(PIN_SPEAKER,1047); // tone(pin,frequency)
|
||||
}
|
||||
|
||||
/*
|
||||
The Pulse variable is true only for a short time after the heartbeat is detected
|
||||
Use this to time the duration of the beep
|
||||
*/
|
||||
if(pulseSensor.isInsideBeat() == false){
|
||||
noTone(PIN_SPEAKER);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
Code to detect pulses from the PulseSensor,
|
||||
using an interrupt service routine and
|
||||
using SoftwareSerial for Serial output.
|
||||
|
||||
Here is a link to the tutorial that discusses this coe
|
||||
https://pulsesensor.com/pages/getting-advanced
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
|
||||
#define USE_ARDUINO_INTERRUPTS true // we want the Playground to use interrupts
|
||||
#include <PulseSensorPlayground.h>
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
/*
|
||||
The format of our output.
|
||||
|
||||
Set this to PROCESSING_VISUALIZER if you're going to run
|
||||
the Processing Visualizer Sketch.
|
||||
See https://github.com/WorldFamousElectronics/PulseSensor_Amped_Processing_Visualizer
|
||||
|
||||
Set this to SERIAL_PLOTTER if you're going to run
|
||||
the Arduino IDE's Serial Plotter.
|
||||
*/
|
||||
const int OUTPUT_TYPE = SERIAL_PLOTTER;
|
||||
|
||||
/*
|
||||
PIN_RX = Serial Receive pin (input into Arduino)
|
||||
PIN_TX = Serial Transmit pin (output from Arduino)
|
||||
|
||||
In most cases, you'll want to wire the Arduino PIN_RX
|
||||
to the TRANSMIT pin of the external serial device,
|
||||
and the Arduino PIN_TX to the RECEIVE pin of the
|
||||
external device.
|
||||
*/
|
||||
const int PIN_RX = 7;
|
||||
const int PIN_TX = 8;
|
||||
|
||||
const int PULSE_INPUT = A0;
|
||||
const int PULSE_BLINK = 13; // Pin 13 is the on-board LED
|
||||
const int PULSE_FADE = 5; // Must be a PWM pin other than 9 or 10.
|
||||
const int THRESHOLD = 550; // Adjust this number to avoid noise when idle
|
||||
|
||||
/*
|
||||
Our software serial controller.
|
||||
*/
|
||||
SoftwareSerial ourSerial(PIN_RX, PIN_TX);
|
||||
|
||||
PulseSensorPlayground pulseSensor;
|
||||
|
||||
void setup() {
|
||||
|
||||
ourSerial.begin(115200);
|
||||
|
||||
// Configure the PulseSensor manager.
|
||||
|
||||
pulseSensor.analogInput(PULSE_INPUT);
|
||||
pulseSensor.blinkOnPulse(PULSE_BLINK);
|
||||
pulseSensor.fadeOnPulse(PULSE_FADE);
|
||||
|
||||
pulseSensor.setSerial(ourSerial);
|
||||
pulseSensor.setOutputType(OUTPUT_TYPE);
|
||||
pulseSensor.setThreshold(THRESHOLD);
|
||||
|
||||
if (!pulseSensor.begin()) {
|
||||
/*
|
||||
* PulseSensor initialization failed,
|
||||
* likely because our particular Arduino platform interrupts
|
||||
* aren't supported yet.
|
||||
*
|
||||
* If your Sketch hangs here, try changing USE_ARDUINO_INTERRUPTS to false.
|
||||
*/
|
||||
for(;;) {
|
||||
// Flash the led to show things didn't work.
|
||||
digitalWrite(PULSE_BLINK, LOW);
|
||||
delay(50);
|
||||
digitalWrite(PULSE_BLINK, HIGH);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
delay(20);
|
||||
|
||||
pulseSensor.outputSample();
|
||||
|
||||
if (pulseSensor.sawStartOfBeat()) {
|
||||
pulseSensor.outputBeat();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
Arduino Sketch to detect pulses from two PulseSensors.
|
||||
|
||||
Here is a link to the tutorial
|
||||
https://pulsesensor.com/pages/two-or-more-pulse-sensors
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
|
||||
/*
|
||||
Every Sketch that uses the PulseSensor Playground must
|
||||
define USE_ARDUINO_INTERRUPTS before including PulseSensorPlayground.h.
|
||||
Here, #define USE_ARDUINO_INTERRUPTS false tells the library to
|
||||
not use interrupts to read data from the PulseSensor.
|
||||
|
||||
If you want to use interrupts, simply change the line below
|
||||
to read:
|
||||
#define USE_ARDUINO_INTERRUPTS true
|
||||
|
||||
Set US_PS_INTERRUPTS to false if either
|
||||
1) Your Arduino platform's interrupts aren't yet supported
|
||||
by PulseSensor Playground, or
|
||||
2) You don't wish to use interrupts because of the side effects.
|
||||
|
||||
NOTE: if US_PS_INTERRUPTS is false, your Sketch must
|
||||
call pulse.sawNewSample() at least once every 2 milliseconds
|
||||
to accurately read the PulseSensor signal.
|
||||
*/
|
||||
#define USE_ARDUINO_INTERRUPTS true
|
||||
#include <PulseSensorPlayground.h>
|
||||
|
||||
|
||||
/*
|
||||
The format of our output.
|
||||
|
||||
Set this to PROCESSING_VISUALIZER if you're going to run
|
||||
the multi-sensor Processing Visualizer Sketch.
|
||||
See https://github.com/WorldFamousElectronics/PulseSensorAmped_2_Sensors
|
||||
|
||||
Set this to SERIAL_PLOTTER if you're going to run
|
||||
the Arduino IDE's Serial Plotter.
|
||||
*/
|
||||
const int OUTPUT_TYPE = SERIAL_PLOTTER;
|
||||
|
||||
/*
|
||||
Number of PulseSensor devices we're reading from.
|
||||
*/
|
||||
const int PULSE_SENSOR_COUNT = 2;
|
||||
|
||||
/*
|
||||
PULSE_POWERx = the output pin that the red (power) pin of
|
||||
the first PulseSensor will be connected to. PulseSensor only
|
||||
draws about 4mA, so almost any micro can power it from a GPIO.
|
||||
If you don't want to use pins to power the PulseSensors, you can remove
|
||||
the code dealing with PULSE_POWER0 and PULSE_POWER1.
|
||||
PULSE_INPUTx = Analog Input. Connected to the pulse sensor
|
||||
purple (signal) wire.
|
||||
PULSE_BLINKx = digital Output. Connected to an LED (must have at least
|
||||
470 ohm resistor) that will flash on each detected pulse.
|
||||
PULSE_FADEx = digital Output. PWM pin onnected to an LED (must have
|
||||
at least 470 ohm resistor) that will smoothly fade with each pulse.
|
||||
|
||||
NOTE: PULSE_FADEx must be pins that support PWM.
|
||||
If USE_INTERRUPTS is true, Do not use pin 9 or 10 for PULSE_FADEx
|
||||
because those pins' PWM interferes with the sample timer.
|
||||
*/
|
||||
const int PULSE_INPUT0 = A0;
|
||||
const int PULSE_BLINK0 = 13; // Pin 13 is the on-board LED
|
||||
const int PULSE_FADE0 = 5;
|
||||
|
||||
const int PULSE_INPUT1 = A1;
|
||||
const int PULSE_BLINK1 = 12;
|
||||
const int PULSE_FADE1 = 11;
|
||||
|
||||
const int THRESHOLD = 550; // Adjust this number to avoid noise when idle
|
||||
|
||||
/*
|
||||
All the PulseSensor Playground functions.
|
||||
We tell it how many PulseSensors we're using.
|
||||
*/
|
||||
PulseSensorPlayground pulseSensor(PULSE_SENSOR_COUNT);
|
||||
|
||||
void setup() {
|
||||
/*
|
||||
Use 250000 baud because that's what the Processing Sketch expects to read,
|
||||
and because that speed provides about 25 bytes per millisecond,
|
||||
or 50 characters per PulseSensor sample period of 2 milliseconds.
|
||||
|
||||
If we used a slower baud rate, we'd likely write bytes faster than
|
||||
they can be transmitted, which would mess up the timing
|
||||
of readSensor() calls, which would make the pulse measurement
|
||||
not work properly.
|
||||
*/
|
||||
Serial.begin(250000);
|
||||
|
||||
/*
|
||||
Configure the PulseSensor manager,
|
||||
telling it which PulseSensor (0 or 1)
|
||||
we're configuring.
|
||||
*/
|
||||
|
||||
pulseSensor.analogInput(PULSE_INPUT0, 0);
|
||||
pulseSensor.blinkOnPulse(PULSE_BLINK0, 0);
|
||||
pulseSensor.fadeOnPulse(PULSE_FADE0, 0);
|
||||
|
||||
pulseSensor.analogInput(PULSE_INPUT1, 1);
|
||||
pulseSensor.blinkOnPulse(PULSE_BLINK1, 1);
|
||||
pulseSensor.fadeOnPulse(PULSE_FADE1, 1);
|
||||
|
||||
pulseSensor.setSerial(Serial);
|
||||
pulseSensor.setOutputType(OUTPUT_TYPE);
|
||||
pulseSensor.setThreshold(THRESHOLD);
|
||||
|
||||
|
||||
// Now that everything is ready, start reading the PulseSensor signal.
|
||||
if (!pulseSensor.begin()) {
|
||||
/*
|
||||
PulseSensor initialization failed,
|
||||
likely because our Arduino platform interrupts
|
||||
aren't supported yet.
|
||||
|
||||
If your Sketch hangs here, try changing USE_ARDUINO_INTERRUPTS to false.
|
||||
*/
|
||||
for (;;) {
|
||||
// Flash the led to show things didn't work.
|
||||
digitalWrite(PULSE_BLINK0, LOW);
|
||||
delay(50);
|
||||
digitalWrite(PULSE_BLINK0, HIGH);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
/*
|
||||
Wait a bit.
|
||||
We don't output every sample, because our baud rate
|
||||
won't support that much I/O.
|
||||
*/
|
||||
delay(20);
|
||||
|
||||
// write the latest sample to Serial.
|
||||
pulseSensor.outputSample();
|
||||
|
||||
/*
|
||||
If a beat has happened on a given PulseSensor
|
||||
since we last checked, write the per-beat information
|
||||
about that PulseSensor to Serial.
|
||||
*/
|
||||
for (int i = 0; i < PULSE_SENSOR_COUNT; ++i) {
|
||||
if (pulseSensor.sawStartOfBeat(i)) {
|
||||
pulseSensor.outputBeat(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
Arduino Sketch to detect pulses from two PulseSensors.
|
||||
|
||||
Here is a link to the tutorial
|
||||
https://pulsesensor.com/pages/two-or-more-pulse-sensors
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
|
||||
/*
|
||||
Every Sketch that uses the PulseSensor Playground must
|
||||
define USE_ARDUINO_INTERRUPTS before including PulseSensorPlayground.h.
|
||||
Here, #define USE_ARDUINO_INTERRUPTS false tells the library to
|
||||
not use interrupts to read data from the PulseSensor.
|
||||
|
||||
If you want to use interrupts, simply change the line below
|
||||
to read:
|
||||
#define USE_ARDUINO_INTERRUPTS true
|
||||
|
||||
Set US_PS_INTERRUPTS to false if either
|
||||
1) Your Arduino platform's interrupts aren't yet supported
|
||||
by PulseSensor Playground, or
|
||||
2) You don't wish to use interrupts because of the side effects.
|
||||
|
||||
NOTE: if US_PS_INTERRUPTS is false, your Sketch must
|
||||
call pulse.sawNewSample() at least once every 2 milliseconds
|
||||
to accurately read the PulseSensor signal.
|
||||
*/
|
||||
#define USE_ARDUINO_INTERRUPTS false
|
||||
#include <PulseSensorPlayground.h>
|
||||
|
||||
|
||||
/*
|
||||
The format of our output.
|
||||
|
||||
Set this to PROCESSING_VISUALIZER if you're going to run
|
||||
the multi-sensor Processing Visualizer Sketch.
|
||||
See https://github.com/WorldFamousElectronics/PulseSensorAmped_2_Sensors
|
||||
|
||||
Set this to SERIAL_PLOTTER if you're going to run
|
||||
the Arduino IDE's Serial Plotter.
|
||||
*/
|
||||
const int OUTPUT_TYPE = SERIAL_PLOTTER;
|
||||
|
||||
/*
|
||||
Number of PulseSensor devices we're reading from.
|
||||
*/
|
||||
const int PULSE_SENSOR_COUNT = 2;
|
||||
|
||||
/*
|
||||
PULSE_POWERx = the output pin that the red (power) pin of
|
||||
the first PulseSensor will be connected to. PulseSensor only
|
||||
draws about 4mA, so almost any micro can power it from a GPIO.
|
||||
If you don't want to use pins to power the PulseSensors, you can remove
|
||||
the code dealing with PULSE_POWER0 and PULSE_POWER1.
|
||||
PULSE_INPUTx = Analog Input. Connected to the pulse sensor
|
||||
purple (signal) wire.
|
||||
PULSE_BLINKx = digital Output. Connected to an LED (must have at least
|
||||
470 ohm resistor) that will flash on each detected pulse.
|
||||
PULSE_FADEx = digital Output. PWM pin onnected to an LED (must have
|
||||
at least 470 ohm resistor) that will smoothly fade with each pulse.
|
||||
|
||||
NOTE: PULSE_FADEx must be pins that support PWM.
|
||||
If USE_INTERRUPTS is true, Do not use pin 9 or 10 for PULSE_FADEx
|
||||
because those pins' PWM interferes with the sample timer.
|
||||
*/
|
||||
const int PULSE_INPUT0 = A0;
|
||||
const int PULSE_BLINK0 = 13; // Pin 13 is the on-board LED
|
||||
const int PULSE_FADE0 = 5;
|
||||
|
||||
const int PULSE_INPUT1 = A1;
|
||||
const int PULSE_BLINK1 = 12;
|
||||
const int PULSE_FADE1 = 11;
|
||||
|
||||
const int THRESHOLD = 550; // Adjust this number to avoid noise when idle
|
||||
|
||||
/*
|
||||
samplesUntilReport = the number of samples remaining to read
|
||||
until we want to report a sample over the serial connection.
|
||||
|
||||
We want to report a sample value over the serial port
|
||||
only once every 20 milliseconds (10 samples) to avoid
|
||||
doing Serial output faster than the Arduino can send.
|
||||
*/
|
||||
byte samplesUntilReport;
|
||||
const byte SAMPLES_PER_SERIAL_SAMPLE = 10;
|
||||
|
||||
/*
|
||||
All the PulseSensor Playground functions.
|
||||
We tell it how many PulseSensors we're using.
|
||||
*/
|
||||
PulseSensorPlayground pulseSensor(PULSE_SENSOR_COUNT);
|
||||
|
||||
void setup() {
|
||||
/*
|
||||
Use 250000 baud because that's what the Processing Sketch expects to read,
|
||||
and because that speed provides about 25 bytes per millisecond,
|
||||
or 50 characters per PulseSensor sample period of 2 milliseconds.
|
||||
|
||||
If we used a slower baud rate, we'd likely write bytes faster than
|
||||
they can be transmitted, which would mess up the timing
|
||||
of readSensor() calls, which would make the pulse measurement
|
||||
not work properly.
|
||||
*/
|
||||
Serial.begin(250000);
|
||||
|
||||
/*
|
||||
Configure the PulseSensor manager,
|
||||
telling it which PulseSensor (0 or 1)
|
||||
we're configuring.
|
||||
*/
|
||||
|
||||
pulseSensor.analogInput(PULSE_INPUT0, 0);
|
||||
pulseSensor.blinkOnPulse(PULSE_BLINK0, 0);
|
||||
pulseSensor.fadeOnPulse(PULSE_FADE0, 0);
|
||||
|
||||
pulseSensor.analogInput(PULSE_INPUT1, 1);
|
||||
pulseSensor.blinkOnPulse(PULSE_BLINK1, 1);
|
||||
pulseSensor.fadeOnPulse(PULSE_FADE1, 1);
|
||||
|
||||
pulseSensor.setSerial(Serial);
|
||||
pulseSensor.setOutputType(OUTPUT_TYPE);
|
||||
pulseSensor.setThreshold(THRESHOLD);
|
||||
|
||||
// Skip the first SAMPLES_PER_SERIAL_SAMPLE in the loop().
|
||||
samplesUntilReport = SAMPLES_PER_SERIAL_SAMPLE;
|
||||
|
||||
// Now that everything is ready, start reading the PulseSensor signal.
|
||||
if (!pulseSensor.begin()) {
|
||||
/*
|
||||
PulseSensor initialization failed,
|
||||
likely because our Arduino platform interrupts
|
||||
aren't supported yet.
|
||||
|
||||
If your Sketch hangs here, try changing USE_ARDUINO_INTERRUPTS to false.
|
||||
*/
|
||||
for (;;) {
|
||||
// Flash the led to show things didn't work.
|
||||
digitalWrite(PULSE_BLINK0, LOW);
|
||||
delay(50);
|
||||
digitalWrite(PULSE_BLINK0, HIGH);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
if (pulseSensor.sawNewSample()) {
|
||||
|
||||
if (--samplesUntilReport == (byte) 0) {
|
||||
samplesUntilReport = SAMPLES_PER_SERIAL_SAMPLE;
|
||||
|
||||
pulseSensor.outputSample();
|
||||
|
||||
/*
|
||||
If a beat has happened on a given PulseSensor
|
||||
since we last checked, write the per-beat information
|
||||
about that PulseSensor to Serial.
|
||||
*/
|
||||
|
||||
for (int i = 0; i < PULSE_SENSOR_COUNT; ++i) {
|
||||
if (pulseSensor.sawStartOfBeat(i)) {
|
||||
pulseSensor.outputBeat(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******
|
||||
Here is a good place to add code that could take up
|
||||
to a millisecond or so to run.
|
||||
*******/
|
||||
}
|
||||
|
||||
/******
|
||||
Don't add code here, because it could slow the sampling
|
||||
from the PulseSensor.
|
||||
******/
|
||||
}
|
||||
47
arduino-cli/libraries/PulseSensorPlayground/keywords.txt
Normal file
47
arduino-cli/libraries/PulseSensorPlayground/keywords.txt
Normal file
@@ -0,0 +1,47 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map PulseSensor Playground
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
PulseSensorPlayground KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
analogInput KEYWORD2
|
||||
begin KEYWORD2
|
||||
blinkOnPulse KEYWORD2
|
||||
fadeOnPulse KEYWORD2
|
||||
getBeatsPerMinute KEYWORD2
|
||||
getInterBeatIntervalMs KEYWORD2
|
||||
getLatestSample KEYWORD2
|
||||
isInsideBeat KEYWORD2
|
||||
outputBeat KEYWORD2
|
||||
outputSample KEYWORD2
|
||||
sawNewSample KEYWORD2
|
||||
setSerial KEYWORD2
|
||||
setOutputType KEYWORD2
|
||||
sawStartOfBeat KEYWORD2
|
||||
setThreshold KEYWORD2
|
||||
getLastBeatTime KEYWORD2
|
||||
outputToSerial KEYWORD2
|
||||
getPulseAmplitude KEYWORD2
|
||||
pause KEYWORD2
|
||||
resume KEYWORD2
|
||||
isPaused KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Instances (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
MICROS_PER_READ LITERAL1
|
||||
PROCESSING_VISUALIZER LITERAL1
|
||||
SERIAL_PLOTTER LITERAL1
|
||||
@@ -0,0 +1,9 @@
|
||||
name=PulseSensor Playground
|
||||
version=1.5.1
|
||||
author=Joel Murphy, Yury Gitman, Brad Needham
|
||||
maintainer=Joel Murphy, Yury Gitman
|
||||
sentence=Support at PulseSensor.com
|
||||
paragraph=Code and Examples for PulseSensor from PulseSensor.com
|
||||
category=Other
|
||||
url=https://github.com/WorldFamousElectronics/PulseSensorPlayground
|
||||
architectures=*
|
||||
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
A central Playground object to manage a set of PulseSensors.
|
||||
See https://www.pulsesensor.com to get started.
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
#include <PulseSensorPlayground.h>
|
||||
|
||||
// Define the "this" pointer for the ISR
|
||||
PulseSensorPlayground *PulseSensorPlayground::OurThis;
|
||||
|
||||
|
||||
PulseSensorPlayground::PulseSensorPlayground(int numberOfSensors) {
|
||||
// Save a static pointer to our playground so the ISR can read it.
|
||||
OurThis = this;
|
||||
|
||||
// Dynamically create the array to minimize ram usage.
|
||||
SensorCount = (byte) numberOfSensors;
|
||||
Sensors = new PulseSensor[SensorCount];
|
||||
|
||||
#if PULSE_SENSOR_TIMING_ANALYSIS
|
||||
// We want sample timing analysis, so we construct it.
|
||||
pTiming = new PulseSensorTimingStatistics(MICROS_PER_READ, 500 * 30L);
|
||||
#endif // PULSE_SENSOR_TIMING_ANALYSIS
|
||||
}
|
||||
|
||||
boolean PulseSensorPlayground::PulseSensorPlayground::begin() {
|
||||
|
||||
for (int i = 0; i < SensorCount; ++i) {
|
||||
Sensors[i].initializeLEDs();
|
||||
}
|
||||
|
||||
// Note the time, for non-interrupt sampling and for timing statistics.
|
||||
NextSampleMicros = micros() + MICROS_PER_READ;
|
||||
|
||||
SawNewSample = false;
|
||||
Paused = false;
|
||||
|
||||
#if PULSE_SENSOR_MEMORY_USAGE
|
||||
// Report the RAM usage and hang.
|
||||
printMemoryUsage();
|
||||
for (;;);
|
||||
#endif // PULSE_SENSOR_MEMORY_USAGE
|
||||
|
||||
// Lastly, set up and turn on the interrupts.
|
||||
|
||||
if (UsingInterrupts) {
|
||||
if (!PulseSensorPlaygroundSetupInterrupt()) {
|
||||
Stream *pOut = SerialOutput.getSerial();
|
||||
if (pOut) {
|
||||
pOut->print(F("Interrupts not supported on this platform\n"));
|
||||
}
|
||||
// The user requested interrupts, but they aren't supported. Say so.
|
||||
Paused = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PulseSensorPlayground::analogInput(int inputPin, int sensorIndex) {
|
||||
if (sensorIndex != constrain(sensorIndex, 0, SensorCount)) {
|
||||
return; // out of range.
|
||||
}
|
||||
Sensors[sensorIndex].analogInput(inputPin);
|
||||
}
|
||||
|
||||
void PulseSensorPlayground::blinkOnPulse(int blinkPin, int sensorIndex) {
|
||||
if (sensorIndex != constrain(sensorIndex, 0, SensorCount)) {
|
||||
return; // out of range.
|
||||
}
|
||||
Sensors[sensorIndex].blinkOnPulse(blinkPin);
|
||||
}
|
||||
|
||||
void PulseSensorPlayground::fadeOnPulse(int fadePin, int sensorIndex) {
|
||||
if (sensorIndex != constrain(sensorIndex, 0, SensorCount)) {
|
||||
return; // out of range.
|
||||
}
|
||||
Sensors[sensorIndex].fadeOnPulse(fadePin);
|
||||
}
|
||||
|
||||
boolean PulseSensorPlayground::sawNewSample() {
|
||||
/*
|
||||
If using interrupts, this function reads and clears the
|
||||
'saw a sample' flag that is set by the ISR.
|
||||
|
||||
When not using interrupts, this function sees whether it's time
|
||||
to sample and, if so, reads the sample and processes it.
|
||||
|
||||
First, check to see if the sketch has paused the Pulse Sensor sampling
|
||||
*/
|
||||
|
||||
if (UsingInterrupts) {
|
||||
// Disable interrupts to avoid a race with the ISR.
|
||||
DISABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
boolean sawOne = SawNewSample;
|
||||
SawNewSample = false;
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
|
||||
return sawOne;
|
||||
}else{
|
||||
if(Paused){
|
||||
SawNewSample = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Time the sample as close as you can when not using interrupts
|
||||
|
||||
unsigned long nowMicros = micros();
|
||||
if ((long) (NextSampleMicros - nowMicros) > 0L) {
|
||||
return false; // not time yet.
|
||||
}
|
||||
NextSampleMicros = nowMicros + MICROS_PER_READ;
|
||||
|
||||
#if PULSE_SENSOR_TIMING_ANALYSIS
|
||||
if (pTiming->recordSampleTime() <= 0) {
|
||||
pTiming->outputStatistics(SerialOutput.getSerial());
|
||||
for (;;); // Hang because we've disturbed the timing.
|
||||
}
|
||||
#endif // PULSE_SENSOR_TIMING_ANALYSIS
|
||||
|
||||
// Act as if the ISR was called.
|
||||
onSampleTime();
|
||||
|
||||
SawNewSample = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PulseSensorPlayground::onSampleTime() {
|
||||
// Typically called from the ISR.
|
||||
|
||||
/*
|
||||
Read the voltage from each PulseSensor.
|
||||
We do this separately from processing the voltages
|
||||
to minimize jitter in acquiring the signal.
|
||||
*/
|
||||
for (int i = 0; i < SensorCount; ++i) {
|
||||
Sensors[i].readNextSample();
|
||||
}
|
||||
|
||||
// Process those voltages.
|
||||
for (int i = 0; i < SensorCount; ++i) {
|
||||
Sensors[i].processLatestSample();
|
||||
Sensors[i].updateLEDs();
|
||||
}
|
||||
|
||||
// Set the flag that says we've read a sample since the Sketch checked.
|
||||
SawNewSample = true;
|
||||
}
|
||||
|
||||
int PulseSensorPlayground::getLatestSample(int sensorIndex) {
|
||||
if (sensorIndex != constrain(sensorIndex, 0, SensorCount)) {
|
||||
return -1; // out of range.
|
||||
}
|
||||
return Sensors[sensorIndex].getLatestSample();
|
||||
}
|
||||
|
||||
int PulseSensorPlayground::getBeatsPerMinute(int sensorIndex) {
|
||||
if (sensorIndex != constrain(sensorIndex, 0, SensorCount)) {
|
||||
return -1; // out of range.
|
||||
}
|
||||
return Sensors[sensorIndex].getBeatsPerMinute();
|
||||
}
|
||||
|
||||
int PulseSensorPlayground::getInterBeatIntervalMs(int sensorIndex) {
|
||||
if (sensorIndex != constrain(sensorIndex, 0, SensorCount)) {
|
||||
return -1; // out of range.
|
||||
}
|
||||
return Sensors[sensorIndex].getInterBeatIntervalMs();
|
||||
}
|
||||
|
||||
boolean PulseSensorPlayground::sawStartOfBeat(int sensorIndex) {
|
||||
if (sensorIndex != constrain(sensorIndex, 0, SensorCount)) {
|
||||
return false; // out of range.
|
||||
}
|
||||
return Sensors[sensorIndex].sawStartOfBeat();
|
||||
}
|
||||
|
||||
boolean PulseSensorPlayground::isInsideBeat(int sensorIndex) {
|
||||
if (sensorIndex != constrain(sensorIndex, 0, SensorCount)) {
|
||||
return false; // out of range.
|
||||
}
|
||||
return Sensors[sensorIndex].isInsideBeat();
|
||||
}
|
||||
|
||||
void PulseSensorPlayground::setSerial(Stream &output) {
|
||||
SerialOutput.setSerial(output);
|
||||
}
|
||||
|
||||
void PulseSensorPlayground::setOutputType(byte outputType) {
|
||||
SerialOutput.setOutputType(outputType);
|
||||
}
|
||||
|
||||
void PulseSensorPlayground::setThreshold(int threshold, int sensorIndex) {
|
||||
if (sensorIndex != constrain(sensorIndex, 0, SensorCount)) {
|
||||
return; // out of range.
|
||||
}
|
||||
Sensors[sensorIndex].setThreshold(threshold);
|
||||
}
|
||||
|
||||
void PulseSensorPlayground::outputSample() {
|
||||
SerialOutput.outputSample(Sensors, SensorCount);
|
||||
}
|
||||
|
||||
void PulseSensorPlayground::outputBeat(int sensorIndex) {
|
||||
SerialOutput.outputBeat(Sensors, SensorCount, sensorIndex);
|
||||
}
|
||||
|
||||
void PulseSensorPlayground::outputToSerial(char s, int d) {
|
||||
SerialOutput.outputToSerial(s,d);
|
||||
}
|
||||
|
||||
int PulseSensorPlayground::getPulseAmplitude(int sensorIndex) {
|
||||
if (sensorIndex != constrain(sensorIndex, 0, SensorCount)) {
|
||||
return -1; // out of range.
|
||||
}
|
||||
return Sensors[sensorIndex].getPulseAmplitude();
|
||||
}
|
||||
|
||||
unsigned long PulseSensorPlayground::getLastBeatTime(int sensorIndex) {
|
||||
if (sensorIndex != constrain(sensorIndex, 0, SensorCount)) {
|
||||
return -1; // out of range.
|
||||
}
|
||||
return Sensors[sensorIndex].getLastBeatTime();
|
||||
}
|
||||
|
||||
boolean PulseSensorPlayground::isPaused() {
|
||||
return Paused;
|
||||
}
|
||||
|
||||
boolean PulseSensorPlayground::pause() {
|
||||
if (UsingInterrupts) {
|
||||
if (!PulseSensorPlaygroundDisableInterrupt()) {
|
||||
Stream *pOut = SerialOutput.getSerial();
|
||||
if (pOut) {
|
||||
pOut->print(F("Could not pause Pulse Sensor\n"));
|
||||
}
|
||||
return false;
|
||||
}else{
|
||||
// DOING THIS HERE BECAUSE IT COULD GET CHOMPED IF WE DO IN resume BELOW
|
||||
for(int i=0; i<SensorCount; i++){
|
||||
Sensors[i].resetVariables();
|
||||
}
|
||||
Paused = true;
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
// do something here?
|
||||
Paused = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
boolean PulseSensorPlayground::resume() {
|
||||
if (UsingInterrupts) {
|
||||
if (!PulseSensorPlaygroundEnableInterrupt()) {
|
||||
Stream *pOut = SerialOutput.getSerial();
|
||||
if (pOut) {
|
||||
pOut->print(F("Could not resume Pulse Sensor\n"));
|
||||
}
|
||||
return false;
|
||||
}else{
|
||||
Paused = false;
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
// do something here?
|
||||
Paused = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if PULSE_SENSOR_MEMORY_USAGE
|
||||
void PulseSensorPlayground::printMemoryUsage() {
|
||||
char stack = 1;
|
||||
extern char *__data_start;
|
||||
extern char *__data_end;
|
||||
extern char *__bss_start;
|
||||
extern char *__bss_end;
|
||||
extern char *__heap_start;
|
||||
extern char *__heap_end;
|
||||
|
||||
int data_size = (int)&__data_end - (int)&__data_start;
|
||||
int bss_size = (int)&__bss_end - (int)&__data_end;
|
||||
int heap_end = (int)&stack - (int)&__malloc_margin;
|
||||
int heap_size = heap_end - (int)&__bss_end;
|
||||
int stack_size = RAMEND - (int)&stack + 1;
|
||||
int available = (RAMEND - (int)&__data_start + 1);
|
||||
available -= data_size + bss_size + heap_size + stack_size;
|
||||
|
||||
Stream *pOut = SerialOutput.getSerial();
|
||||
if (pOut) {
|
||||
pOut->print(F("data "));
|
||||
pOut->println(data_size);
|
||||
pOut->print(F("bss "));
|
||||
pOut->println(bss_size);
|
||||
pOut->print(F("heap "));
|
||||
pOut->println(heap_size);
|
||||
pOut->print(F("stack "));
|
||||
pOut->println(stack_size);
|
||||
pOut->print(F("total "));
|
||||
pOut->println(data_size + bss_size + heap_size + stack_size);
|
||||
}
|
||||
}
|
||||
#endif // PULSE_SENSOR_MEMORY_USAGE
|
||||
@@ -0,0 +1,441 @@
|
||||
/*
|
||||
A central Playground object to manage a set of PulseSensors.
|
||||
See https://www.pulsesensor.com to get started.
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
|
||||
/*
|
||||
NOTE: Every Sketch that uses the PulseSensor Playground
|
||||
must define the variable USE_ARDUINO_INTERRUPTS *before* including
|
||||
PulseSensorPlayground.h. If you don't, you will get a compiler error
|
||||
about "undefined reference to `PulseSensorPlayground::UsingInterrupts".
|
||||
|
||||
In particular, if your Sketch wants the Playground to use interrupts
|
||||
to read and process PulseSensor data, your Sketch must contain the
|
||||
following two lines, in order:
|
||||
#define USE_ARDUINO_INTERRUPTS true
|
||||
#include <PulseSensorPlayground.h>
|
||||
|
||||
If, instead, your Sketch does not use interrupts to read PulseSensor
|
||||
data, your Sketch must instead contain the
|
||||
following two lines, in order:
|
||||
#define USE_ARDUINO_INTERRUPTS false
|
||||
#include <PulseSensorPlayground.h>
|
||||
|
||||
See utility/interrupts.h for details.
|
||||
|
||||
Internal, developer note: in the Playground code, don't use
|
||||
USE_ARDUINO_INTERRUPTS as a variable; instead, refer to
|
||||
PulseSensorPlayground::UsingInterrupts, which is a static variable
|
||||
that reflects what the Sketch defined USE_ARDUINO_INTERRUPTS to.
|
||||
Because USE_ARDUINO_INTERRUPTS is defined *only* in the user's Sketch,
|
||||
it doesn't exist when the various Playground modules are compiled.
|
||||
|
||||
See further notes in interrupts.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PULSE_SENSOR_PLAYGROUND_H
|
||||
#define PULSE_SENSOR_PLAYGROUND_H
|
||||
|
||||
/*
|
||||
If you wish to perform timing statistics on your non-interrupt Sketch:
|
||||
|
||||
Uncomment the line below: #define PULSE_SENSOR_TIMING_ANALYSIS true
|
||||
Compile and download your Sketch.
|
||||
Start the Arduino IDE Serial Monitor.
|
||||
Wait about 30 seconds. The Sketch should then print 3 numbers and hang.
|
||||
The three numbers are:
|
||||
Minimum variation (microseconds) from the 2 millisecond sample time.
|
||||
Average variation in that number.
|
||||
Maximum variation in that number.
|
||||
For example and output of -4 0 18 says that samples were made between
|
||||
4 microseconds short of 2 milliseconds, and 18 microseconds longer,
|
||||
with an average sample time right at 2 milliseconds (0 microseconds offset).
|
||||
|
||||
If the average number is larger than, say, 50 microseconds, your Sketch
|
||||
is taking too much time per loop(), causing inaccuracies in the
|
||||
measured signal, heart rate, and inter-beat interval.
|
||||
|
||||
You should aim for an average offset of under 50 microseconds.
|
||||
|
||||
NOTES:
|
||||
|
||||
1) This is an approximate measure, because interrupts can occur that
|
||||
the timing statistics cannot measure.
|
||||
|
||||
2) These statistics compile only for non-interrupt Sketches. If your
|
||||
Sketch uses Interrupts to sample the PulseSensor signal, enabling
|
||||
this timing analysis will have no effect and will print nothing.
|
||||
|
||||
3) Because timing analysis results are printed on Serial, you cannot
|
||||
use the Arduino IDE Serial Plotter or the Processing Visualizer to
|
||||
examine output when timing analysis is enabled.
|
||||
|
||||
4) If the average is a negative number, your assumed Arduino clock
|
||||
speed may be incorrect. For example, if you compiled for an 8MHz clock
|
||||
and your Arduino actually runs at 16MHz, you would likely see an
|
||||
average offset of something like -1000.
|
||||
|
||||
*/
|
||||
#define PULSE_SENSOR_TIMING_ANALYSIS false
|
||||
//#define PULSE_SENSOR_TIMING_ANALYSIS true
|
||||
|
||||
/*
|
||||
If you wish to print the amount of memory used before your Sketch
|
||||
starts:
|
||||
|
||||
Uncomment the line below: #define PULSE_SENSOR_MEMORY_USAGE true
|
||||
Compile and download your Sketch.
|
||||
Start the Arduino IDE Serial Monitor
|
||||
Your Sketch will start normally, then print memory usage, then hang.
|
||||
|
||||
The memory usage consists of five numbers:
|
||||
data = bytes of global, uninitialized data storage (int x;)
|
||||
bss = bytes of global, initialized data storage (int x = 5;)
|
||||
heap = bytes of dynamically allocated memory (new Stream;)
|
||||
stack = bytes of local variables (those defined within a function)
|
||||
total = the total of data, bss, heap, and stack memory used.
|
||||
|
||||
The amount of flash memory used is printed by the Arduino IDE
|
||||
when compilation finishes, with a printout such as:
|
||||
Sketch uses 5036 bytes (15%) of program storage space.
|
||||
|
||||
NOTE: you must call pulse.setSerial(Serial) in your Sketch's setup().
|
||||
*/
|
||||
#define PULSE_SENSOR_MEMORY_USAGE false
|
||||
// #define PULSE_SENSOR_MEMORY_USAGE true
|
||||
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "utility/PulseSensor.h"
|
||||
#include "utility/PulseSensorSerialOutput.h"
|
||||
#include "utility/PulseSensorTimingStatistics.h"
|
||||
|
||||
class PulseSensorPlayground {
|
||||
public:
|
||||
/*
|
||||
The number of microseconds per sample of data from the PulseSensor.
|
||||
1 millisecond is 1,000 microseconds.
|
||||
|
||||
Refer to this value as PulseSensorPlayground::MICROS_PER_READ
|
||||
*/
|
||||
static const unsigned long MICROS_PER_READ = (2 * 1000L); // usecs per sample.
|
||||
|
||||
//---------- PulseSensor Manager functions
|
||||
|
||||
/*
|
||||
Construct the one PulseSensor Playground manager,
|
||||
that manages the given number of PulseSensors.
|
||||
Your Sketch should declare either PulseSensorPlayground() for one sensor
|
||||
or PulseSensorPlayground(n) for n PulseSensors.
|
||||
|
||||
For example:
|
||||
PulseSensorPlayground pulse();
|
||||
or
|
||||
PulseSensorPlayground pulse(2); // for 2 PulseSensors.
|
||||
*/
|
||||
PulseSensorPlayground(int numberOfSensors = 1);
|
||||
|
||||
/*
|
||||
Start reading and processing data from the PulseSensors.
|
||||
|
||||
Your Sketch should make all necessary PulseSensor configuration calls
|
||||
before calling begin().
|
||||
|
||||
If the Sketch defined USE_ARDUINO_INTERRUPTS as true, this function
|
||||
sets up and turns on interrupts for the PulseSensor.
|
||||
|
||||
If instead the Sketch defined USE_ARDUINO_INTERRUPTS as false,
|
||||
it initializes what's necessary for the Sketch to process
|
||||
PulsSensor signals. See sawNewSample(), below.
|
||||
|
||||
Returns true if successful, false if unsuccessful.
|
||||
Returns false if PulseSensorPlayground doesn't yet support
|
||||
interrupts on this Arduino platform and the user's Sketch
|
||||
did a #define USE_ARDUINO_INTERRUPTS true.
|
||||
|
||||
If begin() returns false, you can either use a different
|
||||
type of Arduino platform, or you can change your Sketch's
|
||||
definition of USE_ARDUINO_INTERRUPTS to false:
|
||||
#define USE_ARDUINO_INTERRUPTS false
|
||||
*/
|
||||
boolean begin();
|
||||
|
||||
/*
|
||||
Returns true if a new sample has been read from each PulseSensor.
|
||||
You'll likely want to add this call to your Sketch's loop()
|
||||
only if you either 1) want to do something with each sample of the
|
||||
PulseSensor signals, or 2) your Sketch doesn't use interrupts
|
||||
to read from the PulseSensors.
|
||||
|
||||
NOTE: If your Sketch defined USE_ARDUINO_INTERRUPTS as false,
|
||||
you must call pulse.sawNewSample() frequently (at least
|
||||
once every 2 milliseconds) to assure that PulseSensor signals
|
||||
are read accurately.
|
||||
A typical loop() that doesn't use interrupts will contain:
|
||||
if (pulse.sawNewSample()) {
|
||||
int latest = pulse.getLatestSample();
|
||||
...do whatever you want with the sample read from the PulseSensor.
|
||||
}
|
||||
*/
|
||||
boolean sawNewSample();
|
||||
|
||||
//---------- Per-PulseSensor functions
|
||||
|
||||
/*
|
||||
By default, the Playground assumes the PulseSensor is connected to A0.
|
||||
If your PulseSensor is connected to a different analog input pin,
|
||||
call pulse.analogInput(pin) or pulse.analogInput(pin, sensorIndex).
|
||||
|
||||
inputPin = the analog input this PulseSensor is connected to.
|
||||
sensorIndex = optional, index (0..numberOfSensors - 1)
|
||||
of the PulseSensor to configure.
|
||||
*/
|
||||
void analogInput(int inputPin, int sensorIndex = 0);
|
||||
|
||||
/*
|
||||
By default, the Playground doesn't blink LEDs automatically.
|
||||
|
||||
If you wish the Playground to automatically blink an LED
|
||||
during each detected pulse,
|
||||
call pulse.blinkOnPulse(blinkPin) or
|
||||
pulse.blinkOnPulse(blinkPin, sensorIndex).
|
||||
|
||||
blinkPin = the pin to blink on each pulse, which you've connected
|
||||
to an LED and 220 ohm resistor, or the built in LED pin
|
||||
on your Arduino (for example, pin 13 on Arduino Uno).
|
||||
sensorIndex = optional, index (0..numberOfSensors - 1)
|
||||
of the PulseSensor to configure.
|
||||
*/
|
||||
void blinkOnPulse(int blinkPin, int sensorIndex = 0);
|
||||
|
||||
/*
|
||||
By default, the Playground doesn't blink LEDs automatically.
|
||||
|
||||
If you wish the Playground to automatically blink a fading LED
|
||||
during each detected pulse,
|
||||
call fadeOnPulse(fadePin) or fadeOnPulse(fadePin, sensorIndex).
|
||||
|
||||
NOTE: the fade pin must be a PWM (Pulse-Width Modulation) pin.
|
||||
|
||||
fadePin = the PWM pin to blink and fade on each pulse,
|
||||
which is connected to an LED and a current-limit resistor.
|
||||
sensorIndex = optional, index (0..numberOfSensors - 1)
|
||||
of the PulseSensor to configure.
|
||||
*/
|
||||
void fadeOnPulse(int fadePin, int sensorIndex = 0);
|
||||
|
||||
/*
|
||||
(Internal to library - do not call from a Sketch)
|
||||
Perform all the processing necessary when it's time to
|
||||
read from all the PulseSensors and process their signals.
|
||||
*/
|
||||
void onSampleTime();
|
||||
|
||||
/*
|
||||
Returns the most recently read analog value from the given PulseSensor
|
||||
(range: 0..1023).
|
||||
|
||||
sensorIndex = optional, index (0..numberOfSensors - 1)
|
||||
of the PulseSensor of interest.
|
||||
*/
|
||||
int getLatestSample(int sensorIndex = 0);
|
||||
|
||||
/*
|
||||
Returns the latest beats-per-minute measure for the given PulseSensor.
|
||||
|
||||
The internal beats-per-minute measure is updated per-PulseSensor,
|
||||
when a beat is detected from that PulseSensor.
|
||||
|
||||
sensorIndex = optional, index (0..numberOfSensors - 1)
|
||||
of the PulseSensor of interest.
|
||||
*/
|
||||
int getBeatsPerMinute(int sensorIndex = 0);
|
||||
|
||||
/*
|
||||
Returns the latest IBI (inter-beat interval, in milliseconds) measure
|
||||
for the given PulseSensor.
|
||||
|
||||
The internal IBI measure is updated per-PulseSensor,
|
||||
when a beat is detected from that PulseSensor.
|
||||
|
||||
sensorIndex = optional, index (0..numberOfSensors - 1)
|
||||
of the PulseSensor of interest.
|
||||
*/
|
||||
int getInterBeatIntervalMs(int sensorIndex = 0);
|
||||
|
||||
/*
|
||||
Returns true if a new heartbeat (pulse) has been detected
|
||||
from the given PulseSensor since the last call to sawStartOfBeat()
|
||||
on this PulseSensor.
|
||||
|
||||
Typical use in loop():
|
||||
if (pulse.sawStartOfBeat()) {
|
||||
...do what you want to do per-heartbeat.
|
||||
}
|
||||
|
||||
sensorIndex = optional, index (0..numberOfSensors - 1)
|
||||
of the PulseSensor of interest.
|
||||
*/
|
||||
boolean sawStartOfBeat(int sensorIndex = 0);
|
||||
|
||||
/*
|
||||
Returns true if the given PulseSensor signal is currently
|
||||
inside a heartbeat. That is, returns true if the signal is above
|
||||
the automatically-set threshold of a beat, false otherwise.
|
||||
|
||||
Typical use in loop():
|
||||
if (pulse.isInsideBeat()) {
|
||||
...do what you want while in the beat.
|
||||
} else {
|
||||
...do what you want while between beats.
|
||||
}
|
||||
|
||||
sensorIndex = optional, index (0..numberOfSensors - 1)
|
||||
of the PulseSensor of interest.
|
||||
*/
|
||||
boolean isInsideBeat(int sensorIndex = 0);
|
||||
|
||||
//---------- Serial Output functions
|
||||
|
||||
/*
|
||||
By default, the Playround doesn't output serial data automatically.
|
||||
|
||||
If you want to output serial pulse data, call pulse.setSerial(Serial),
|
||||
pulse.setSerial(Serial1), or whatever Serial stream you like.
|
||||
|
||||
output = the Stream to write data to. Serial, Serial1, Serial2,
|
||||
etc., and a SoftwareSerial are valid parameters to pass.
|
||||
*/
|
||||
void setSerial(Stream &output);
|
||||
|
||||
/*
|
||||
By default, Playground output is in SERIAL_PLOTTER format.
|
||||
|
||||
If you want output in a different format, call this function once
|
||||
sometime before calling pulse.begin().
|
||||
|
||||
Remember to call pulse.setSerial() if you want serial output.
|
||||
|
||||
outputType = SERIAL_PLOTTER to output to the Arduino Serial Plotter,
|
||||
PROCESSSING_VISUALIZER to output to the Processing Sketch
|
||||
that draws the PulseSensor output.
|
||||
*/
|
||||
void setOutputType(byte outputType);
|
||||
|
||||
/*
|
||||
By default, the threshold value is 530.
|
||||
threshold is used to find the heartbeat
|
||||
adjust this value up in the setup function to avoid noise.
|
||||
*/
|
||||
void setThreshold(int threshold, int sensorIndex = 0);
|
||||
|
||||
/*
|
||||
Output the current signal information for each PulseSensor,
|
||||
in the previously-set outputType.
|
||||
|
||||
If your Sketch wants to plot samples, it should call this function
|
||||
every so often.
|
||||
*/
|
||||
void outputSample();
|
||||
|
||||
/*
|
||||
Serial print data with prefix.
|
||||
Used exclusively with the Pulse Sensor Processing sketch.
|
||||
*/
|
||||
void outputToSerial(char symbol, int data);
|
||||
|
||||
/*
|
||||
Returns the current amplitude of the pulse waveform.
|
||||
*/
|
||||
int getPulseAmplitude(int sensorIndex = 0);
|
||||
|
||||
/*
|
||||
Returns the sample number when the last beat was found. 2mS resolution.
|
||||
*/
|
||||
unsigned long getLastBeatTime(int sensorIndex = 0);
|
||||
|
||||
/*
|
||||
Output the current per-beat information for each PulseSensor,
|
||||
in the previously-set outputType.
|
||||
|
||||
If your Sketch wants to plot beat information, it should call this
|
||||
function every time a beat is detected.
|
||||
|
||||
Typical use:
|
||||
if (pulse.sawStartOfBeat()) {
|
||||
pulse.outputBeat();
|
||||
}
|
||||
*/
|
||||
void outputBeat(int sensorIndex = 0);
|
||||
|
||||
// check to see if the library is sampling (on interrupt OR in software)
|
||||
boolean isPaused();
|
||||
|
||||
// option to pause Pulse Sensor sampling in order to do other stuff
|
||||
// this function will only tell the timer to stop interrupting
|
||||
// does not return PWM or other fuctionality to effected pins
|
||||
boolean pause();
|
||||
|
||||
// restart sampling the Pulse Sensor after a pause
|
||||
boolean resume();
|
||||
|
||||
|
||||
// (internal to the library) "this" pointer for the ISR.
|
||||
static PulseSensorPlayground *OurThis;
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
Configure and enable interrupts to read samples.
|
||||
Call only if PulseSensorPlayground::UsingInterrupts is true.
|
||||
|
||||
This function is defined (vs. declared here) in interrupts.h
|
||||
*/
|
||||
// void setupInterrupt();
|
||||
// boolean disableInterrupt();
|
||||
// boolean enableInterrupt();
|
||||
|
||||
#if PULSE_SENSOR_MEMORY_USAGE
|
||||
/*
|
||||
Print our RAM usage. See PULSE_SENSOR_MEMORY_USAGE
|
||||
*/
|
||||
void printMemoryUsage();
|
||||
#endif // PULSE_SENSOR_MEMORY_USAGE
|
||||
|
||||
/*
|
||||
If true, the Sketch wants to use interrupts to read the PulseSensor(s).
|
||||
|
||||
This variable is defined (vs. declared here) in interrupts.h
|
||||
*/
|
||||
static boolean UsingInterrupts;
|
||||
boolean Paused;
|
||||
byte SensorCount; // number of PulseSensors in Sensors[].
|
||||
PulseSensor *Sensors; // use Sensors[idx] to access a sensor.
|
||||
volatile unsigned long NextSampleMicros; // Desired time to sample next.
|
||||
volatile boolean SawNewSample; // "A sample has arrived from the ISR"
|
||||
PulseSensorSerialOutput SerialOutput; // Serial Output manager.
|
||||
#if PULSE_SENSOR_TIMING_ANALYSIS // Don't use ram and flash we don't need.
|
||||
PulseSensorTimingStatistics *pTiming;
|
||||
#endif // PULSE_SENSOR_TIMING_ANALYSIS
|
||||
};
|
||||
|
||||
/*
|
||||
We include interrupts.h here instead of above
|
||||
because it depends on variables and functions we declare (vs. define)
|
||||
in PulseSensorPlayground.h.
|
||||
*/
|
||||
#include "utility/Interrupts.h"
|
||||
|
||||
#endif // PULSE_SENSOR_PLAYGROUND_H
|
||||
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
Interrupt handling helper functions for PulseSensors.
|
||||
See https://www.pulsesensor.com to get started.
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
|
||||
/*
|
||||
Any Sketch using the Playground must do one of two things:
|
||||
1) #define USE_ARDUINO_INTERRUPTS true - if using interrupts;
|
||||
2) #define USE_ARDUINO_INTERRUPTS false - if not using interrupts.
|
||||
|
||||
Only the Sketch must define USE_ARDUINO_INTERRUPTS.
|
||||
If the Sketch doesn't define USE_ARDUINO_INTERRUPTS, or if some other file
|
||||
defines it as well, a link error will result.
|
||||
|
||||
See notes in PulseSensorPlayground.h
|
||||
|
||||
The code below is rather convoluted, with nested #if's.
|
||||
This structure is used to achieve two goals:
|
||||
1) Minimize the complexity the user has to deal with to use or
|
||||
not use interrupts to sample the PulseSensor data;
|
||||
2) Create an ISR() only if the Sketch uses interrupts. Defining an
|
||||
ISR(), even if not used, may interfere with other libraries' use
|
||||
of interrupts.
|
||||
|
||||
The nesting goes something like this:
|
||||
if the Sketch is being compiled... #if defined(USE_ARDUINO_INTERRUPTS)
|
||||
if the user wants to use interrupts... #if USE_ARDUINO_INTERRUPTS
|
||||
#if's for the various Arduino platforms... #if defined(__AVR_ATmega328P__)...
|
||||
|
||||
RULES of the constant USE_ARDUINO_INTERRUPTS:
|
||||
1) This file, interrupts.h, should be the only file that uses USE_ARDUINO_INTERRUPTS
|
||||
(although PulseSensorPlayground's comments talk about it to the user).
|
||||
If other code in the library wants to know whether interrupts are being used,
|
||||
that code should use PulseSensorPlayground::UsingInterrupts, which is true
|
||||
if the Sketch wants to use interrupts.
|
||||
1) Always use #if USE_ARDUINO_INTERRUPTS inside an #if defined(USE_ARDUINO_INTERRUPTS).
|
||||
If you don't first test the #if defined(...), a compile error will occur
|
||||
when compiling the library modules.
|
||||
2) USE_ARDUINO_INTERRUPTS is defined only when this file is being included
|
||||
by the user's Sketch; not when the rest of the library is compiled.
|
||||
3) USE_ARDUINO_INTERRUPTS is true if the user wants to use interrupts;
|
||||
it's false if they don't.
|
||||
*/
|
||||
|
||||
#ifndef PULSE_SENSOR_INTERRUPTS_H
|
||||
#define PULSE_SENSOR_INTERRUPTS_H
|
||||
|
||||
|
||||
//TODO: if noInterrupts() and interrupts() are defined for Arduino 101,
|
||||
// Use them throughout and eliminate these DISABLE/ENAGLE macros.
|
||||
//
|
||||
// Macros to link to interrupt disable/enable only if they exist
|
||||
// The name is long to avoid collisions with Sketch and Library symbols.
|
||||
#if defined(__arc__)||(ARDUINO_SAMD_MKR1000)||(ARDUINO_SAMD_MKRZERO)||(ARDUINO_SAMD_ZERO)\
|
||||
||(ARDUINO_ARCH_SAMD)||(ARDUINO_ARCH_STM32)||(ARDUINO_STM32_STAR_OTTO)||(ARDUINO_ARCH_NRF5)\
|
||||
||(ARDUINO_ARCH_NRF52)
|
||||
|
||||
#define DISABLE_PULSE_SENSOR_INTERRUPTS
|
||||
#define ENABLE_PULSE_SENSOR_INTERRUPTS
|
||||
#else
|
||||
#define DISABLE_PULSE_SENSOR_INTERRUPTS cli()
|
||||
#define ENABLE_PULSE_SENSOR_INTERRUPTS sei()
|
||||
#endif
|
||||
|
||||
|
||||
// SAVED FOR FUTURE SUPPORT OF TEENSY INTERRUPTS
|
||||
#if defined(__MK66FX1M0__)||(__MK64FX512__)||(__MK20DX256__)||(__MK20DX128__)
|
||||
// #include <FlexiTimer2.h>
|
||||
#endif
|
||||
|
||||
// FOR BOARDS USING THE ESP32 WIFI MODULE
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
// can't use analogWrite yet...
|
||||
#define NO_ANALOG_WRITE = 1
|
||||
#endif
|
||||
/*
|
||||
(internal to the library)
|
||||
Sets up the sample timer interrupt for this Arduino Platform.
|
||||
|
||||
Returns true if successful, false if we don't yet support
|
||||
the timer interrupt on this Arduino.
|
||||
|
||||
NOTE: This is the declaration (vs. definition) of this function.
|
||||
See the definition (vs. declaration) of this function, below.
|
||||
*/
|
||||
boolean PulseSensorPlaygroundSetupInterrupt();
|
||||
boolean PulseSensorPlaygroundDisableInterrupt();
|
||||
boolean PulseSensorPlaygroundEnableInterrupt();
|
||||
|
||||
#if defined(USE_ARDUINO_INTERRUPTS) // that is, if the Sketch is including us...
|
||||
|
||||
/*
|
||||
(internal to the library) True if the Sketch uses interrupts to
|
||||
sample
|
||||
We need to define USE_PS_INTERRUPTS once per Sketch, whether or not
|
||||
the Sketch uses interrupts.
|
||||
Not doing this or doing it for every file that includes interrupts.h
|
||||
would cause a link error.
|
||||
|
||||
To refer to this variable, use "PulseSensorPlayground::UsingInterrupts".
|
||||
|
||||
See PulseSensorPlayground.h
|
||||
*/
|
||||
boolean PulseSensorPlayground::UsingInterrupts = USE_ARDUINO_INTERRUPTS;
|
||||
|
||||
boolean PulseSensorPlaygroundSetupInterrupt() {
|
||||
|
||||
#if !USE_ARDUINO_INTERRUPTS
|
||||
/*
|
||||
The Sketch doesn't want interrupts,
|
||||
so we won't waste Flash space and create complexity
|
||||
by adding interrupt-setup code.
|
||||
*/
|
||||
return true;
|
||||
|
||||
#else
|
||||
// This code sets up the sample timer interrupt
|
||||
// based on the type of Arduino platform.
|
||||
|
||||
/*
|
||||
NOTE: when you change the #if's in this function,
|
||||
be sure to add similar #if's (if necessary) to the ISR() defined
|
||||
below.
|
||||
*/
|
||||
|
||||
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__)
|
||||
|
||||
// check to see if the Servo library is in use
|
||||
#if defined Servo_h
|
||||
// #error "Servos!! Beware" // break compiler for testing
|
||||
// Initializes Timer2 to throw an interrupt every 2mS
|
||||
// Interferes with PWM on pins 3 and 11
|
||||
TCCR2A = 0x02; // Disable PWM and go into CTC mode
|
||||
TCCR2B = 0x05; // don't force compare, 128 prescaler
|
||||
#if F_CPU == 16000000L // if using 16MHz crystal
|
||||
OCR2A = 0XF9; // set count to 249 for 2mS interrupt
|
||||
#elif F_CPU == 8000000L // if using 8MHz crystal
|
||||
OCR2A = 0X7C; // set count to 124 for 2mS interrupt
|
||||
#endif
|
||||
TIMSK2 = 0x02; // Enable OCR2A match interrupt DISABLE BY SETTING TO 0x00
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
// #define _useTimer2
|
||||
return true;
|
||||
#else
|
||||
// Initializes Timer1 to throw an interrupt every 2mS.
|
||||
// Interferes with PWM on pins 9 and 10
|
||||
TCCR1A = 0x00; // Disable PWM and go into CTC mode
|
||||
TCCR1C = 0x00; // don't force compare
|
||||
#if F_CPU == 16000000L // if using 16MHz crystal
|
||||
TCCR1B = 0x0C; // prescaler 256
|
||||
OCR1A = 0x007C; // count to 124 for 2mS interrupt
|
||||
#elif F_CPU == 8000000L // if using 8MHz crystal
|
||||
TCCR1B = 0x0B; // prescaler = 64
|
||||
OCR1A = 0x00F9; // count to 249 for 2mS interrupt
|
||||
#endif
|
||||
TIMSK1 = 0x02; // Enable OCR1A match interrupt DISABLE BY SETTING TO 0x00
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
return true;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
|
||||
// check to see if the Servo library is in use
|
||||
#if defined Servo_h
|
||||
// #error "Servos!! Beware" // break compiler for testing
|
||||
// Initializes Timer1 to throw an interrupt every 2mS.
|
||||
// Interferes with PWM on pins 9 and 10
|
||||
TCCR1A = 0x00; // Disable PWM and go into CTC mode
|
||||
TCCR1C = 0x00; // don't force compare
|
||||
#if F_CPU == 16000000L // if using 16MHz crystal
|
||||
TCCR1B = 0x0C; // prescaler 256
|
||||
OCR1A = 0x007C; // count to 124 for 2mS interrupt
|
||||
#elif F_CPU == 8000000L // if using 8MHz crystal
|
||||
TCCR1B = 0x0B; // prescaler = 64
|
||||
OCR1A = 0x00F9; // count to 249 for 2mS interrupt
|
||||
#endif
|
||||
TIMSK1 = 0x02; // Enable OCR1A match interrupt
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
return true;
|
||||
|
||||
#else
|
||||
// Initializes Timer2 to throw an interrupt every 2mS
|
||||
// Interferes with PWM on pins 3 and 11
|
||||
TCCR2A = 0x02; // Disable PWM and go into CTC mode
|
||||
TCCR2B = 0x05; // don't force compare, 128 prescaler
|
||||
#if F_CPU == 16000000L // if using 16MHz crystal
|
||||
OCR2A = 0XF9; // set count to 249 for 2mS interrupt
|
||||
#elif F_CPU == 8000000L // if using 8MHz crystal
|
||||
OCR2A = 0X7C; // set count to 124 for 2mS interrupt
|
||||
#endif
|
||||
TIMSK2 = 0x02; // Enable OCR2A match interrupt
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
// #define _useTimer2
|
||||
return true;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATtiny85__)
|
||||
GTCCR = 0x00; // Disable PWM, don't connect pins to events
|
||||
OCR1A = 0x7D; // Set top of count to 125. Timer match throws the interrupt
|
||||
OCR1C = 0x7D; // Set top of the count to 125. Timer match resets the counter
|
||||
#if F_CPU == 16000000L
|
||||
TCCR1 = 0x89; // Clear Timer on Compare, Set Prescaler to 256
|
||||
#elif F_CPU == 8000000L
|
||||
TCCR1 = 0x88; // Clear Timer on Compare, Set Prescaler to 128
|
||||
#elif F_CPU == 1000000L
|
||||
TCCR1 = 0x85 // Clear Timer on Compare, Set Prescaler to 16
|
||||
#endif
|
||||
bitSet(TIMSK,6); // Enable interrupt on match between TCNT1 and OCR1A
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
return true;
|
||||
|
||||
#else
|
||||
return false; // unknown or unsupported platform.
|
||||
#endif
|
||||
|
||||
#endif // USE_ARDUINO_INTERRUPTS
|
||||
}
|
||||
|
||||
boolean PulseSensorPlaygroundDisableInterrupt(){
|
||||
#if USE_ARDUINO_INTERRUPTS
|
||||
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__)
|
||||
// check to see if the Servo library is in use
|
||||
#if defined Servo_h
|
||||
DISABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
TIMSK2 = 0x00; // Disable OCR2A match interrupt
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
return true;
|
||||
#else
|
||||
DISABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
TIMSK1 = 0x00; // Disable OCR1A match interrupt
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
return true;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
// check to see if the Servo library is in use
|
||||
#if defined Servo_h
|
||||
DISABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
TIMSK1 = 0x00; // Disable OCR1A match interrupt
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
return true;
|
||||
#else
|
||||
DISABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
TIMSK2 = 0x00; // Disable OCR2A match interrupt
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
return true;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATtiny85__)
|
||||
DISABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
bitClear(TIMSK,6); // Disable interrupt on match between TCNT1 and OCR1A
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
return true;
|
||||
#endif
|
||||
|
||||
// #else
|
||||
return false; // unknown or unsupported platform.
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
boolean PulseSensorPlaygroundEnableInterrupt(){
|
||||
#if USE_ARDUINO_INTERRUPTS
|
||||
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__) // || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
// check to see if the Servo library is in use
|
||||
#if defined Servo_h
|
||||
DISABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
TIMSK2 = 0x02; // Enable OCR2A match interrupt
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
return true;
|
||||
#else
|
||||
DISABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
TIMSK1 = 0x02; // Enable OCR1A match interrupt
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
return true;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
// check to see if the Servo library is in use
|
||||
#if defined Servo_h
|
||||
DISABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
TIMSK1 = 0x02; // Enable OCR1A match interrupt
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
return true;
|
||||
#else
|
||||
DISABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
TIMSK2 = 0x02; // Enable OCR2A match interrupt
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
return true;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATtiny85__)
|
||||
DISABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
bitSet(TIMSK,6); // Enable interrupt on match between TCNT1 and OCR1A
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
return true;
|
||||
#endif
|
||||
|
||||
// #else
|
||||
return false; // unknown or unsupported platform.
|
||||
#endif
|
||||
}
|
||||
|
||||
#if USE_ARDUINO_INTERRUPTS
|
||||
/*
|
||||
We create the Interrupt Service Routine only if the Sketch is
|
||||
using interrupts. If we defined it when we didn't use it,
|
||||
the ISR() will inappropriately intercept timer interrupts that
|
||||
we don't use when not using interrupts.
|
||||
|
||||
We define the ISR that handles the timer that
|
||||
PulseSensorPlaygroundSetupInterrupt() set up.
|
||||
NOTE: Make sure that this ISR uses the appropriate timer for
|
||||
the platform detected by PulseSensorPlaygroundSetupInterrupt(), above.
|
||||
*/
|
||||
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATtiny85__)
|
||||
#if defined Servo_h
|
||||
ISR(TIMER2_COMPA_vect)
|
||||
{
|
||||
DISABLE_PULSE_SENSOR_INTERRUPTS; // disable interrupts while we do this
|
||||
|
||||
PulseSensorPlayground::OurThis->onSampleTime();
|
||||
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS; // enable interrupts when you're done
|
||||
}
|
||||
#else
|
||||
ISR(TIMER1_COMPA_vect)
|
||||
{
|
||||
DISABLE_PULSE_SENSOR_INTERRUPTS; // disable interrupts while we do this
|
||||
|
||||
PulseSensorPlayground::OurThis->onSampleTime();
|
||||
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS; // enable interrupts when you're done
|
||||
}
|
||||
#endif
|
||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#if defined Servo_h
|
||||
ISR(TIMER1_COMPA_vect)
|
||||
{
|
||||
DISABLE_PULSE_SENSOR_INTERRUPTS; // disable interrupts while we do this
|
||||
|
||||
PulseSensorPlayground::OurThis->onSampleTime();
|
||||
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS; // enable interrupts when you're done
|
||||
}
|
||||
#else
|
||||
ISR(TIMER2_COMPA_vect)
|
||||
{
|
||||
DISABLE_PULSE_SENSOR_INTERRUPTS; // disable interrupts while we do this
|
||||
|
||||
PulseSensorPlayground::OurThis->onSampleTime();
|
||||
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS; // enable interrupts when you're done
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__MK66FX1M0__)||(__MK64FX512__)||(__MK20DX256__)||(__MK20DX128__)
|
||||
// Interrupts not supported yet for Teensy
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // USE_ARDUINO_INTERRUPTS
|
||||
|
||||
#endif // defined(USE_ARDUINO_INTERRUPTS)
|
||||
|
||||
#endif // PULSE_SENSOR_INTERRUPTS_H
|
||||
// #endif
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
PulseSensor measurement manager.
|
||||
See https://www.pulsesensor.com to get started.
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
#include <PulseSensorPlayground.h>
|
||||
|
||||
/*
|
||||
Internal constants controlling the rate of fading for the FadePin.
|
||||
|
||||
FADE_SCALE = FadeLevel / FADE_SCALE is the corresponding PWM value.
|
||||
FADE_LEVEL_PER_SAMPLE = amount to decrease FadeLevel per sample.
|
||||
MAX_FADE_LEVEL = maximum FadeLevel value.
|
||||
|
||||
The time (milliseconds) to fade to black =
|
||||
(MAX_FADE_LEVEL / FADE_LEVEL_PER_SAMPLE) * sample time (2ms)
|
||||
*/
|
||||
#define FADE_SCALE 10
|
||||
#define FADE_LEVEL_PER_SAMPLE 12
|
||||
#define MAX_FADE_LEVEL (255 * FADE_SCALE)
|
||||
|
||||
/*
|
||||
Constructs a Pulse detector that will process PulseSensor voltages
|
||||
that the caller reads from the PulseSensor.
|
||||
*/
|
||||
PulseSensor::PulseSensor() {
|
||||
// Initialize the default configuration
|
||||
InputPin = A0;
|
||||
BlinkPin = -1;
|
||||
FadePin = -1;
|
||||
|
||||
// Initialize (seed) the pulse detector
|
||||
sampleIntervalMs = PulseSensorPlayground::MICROS_PER_READ / 1000;
|
||||
resetVariables();
|
||||
}
|
||||
|
||||
void PulseSensor::resetVariables(){
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
rate[i] = 0;
|
||||
}
|
||||
QS = false;
|
||||
BPM = 0;
|
||||
IBI = 750; // 750ms per beat = 80 Beats Per Minute (BPM)
|
||||
Pulse = false;
|
||||
sampleCounter = 0;
|
||||
lastBeatTime = 0;
|
||||
P = 512; // peak at 1/2 the input range of 0..1023
|
||||
T = 512; // trough at 1/2 the input range.
|
||||
threshSetting = 550; // used to seed and reset the thresh variable
|
||||
thresh = 550; // threshold a little above the trough
|
||||
amp = 100; // beat amplitude 1/10 of input range.
|
||||
firstBeat = true; // looking for the first beat
|
||||
secondBeat = false; // not yet looking for the second beat in a row
|
||||
FadeLevel = 0; // LED is dark.
|
||||
}
|
||||
|
||||
void PulseSensor::analogInput(int inputPin) {
|
||||
InputPin = inputPin;
|
||||
}
|
||||
|
||||
void PulseSensor::blinkOnPulse(int blinkPin) {
|
||||
BlinkPin = blinkPin;
|
||||
}
|
||||
|
||||
void PulseSensor::fadeOnPulse(int fadePin) {
|
||||
FadePin = fadePin;
|
||||
}
|
||||
|
||||
void PulseSensor::setThreshold(int threshold) {
|
||||
DISABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
threshSetting = threshold;
|
||||
thresh = threshold;
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
}
|
||||
|
||||
int PulseSensor::getLatestSample() {
|
||||
return Signal;
|
||||
}
|
||||
|
||||
int PulseSensor::getBeatsPerMinute() {
|
||||
return BPM;
|
||||
}
|
||||
|
||||
int PulseSensor::getInterBeatIntervalMs() {
|
||||
return IBI;
|
||||
}
|
||||
|
||||
int PulseSensor::getPulseAmplitude() {
|
||||
return amp;
|
||||
}
|
||||
|
||||
unsigned long PulseSensor::getLastBeatTime() {
|
||||
return lastBeatTime;
|
||||
}
|
||||
|
||||
boolean PulseSensor::sawStartOfBeat() {
|
||||
// Disable interrupts to avoid a race with the ISR.
|
||||
DISABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
boolean started = QS;
|
||||
QS = false;
|
||||
ENABLE_PULSE_SENSOR_INTERRUPTS;
|
||||
|
||||
return started;
|
||||
}
|
||||
|
||||
boolean PulseSensor::isInsideBeat() {
|
||||
return Pulse;
|
||||
}
|
||||
|
||||
void PulseSensor::readNextSample() {
|
||||
// We assume assigning to an int is atomic.
|
||||
Signal = analogRead(InputPin);
|
||||
}
|
||||
|
||||
void PulseSensor::processLatestSample() {
|
||||
// Serial.println(threshSetting);
|
||||
// Serial.print('\t');
|
||||
// Serial.println(thresh);
|
||||
sampleCounter += sampleIntervalMs; // keep track of the time in mS with this variable
|
||||
int N = sampleCounter - lastBeatTime; // monitor the time since the last beat to avoid noise
|
||||
|
||||
// Fade the Fading LED
|
||||
FadeLevel = FadeLevel - FADE_LEVEL_PER_SAMPLE;
|
||||
FadeLevel = constrain(FadeLevel, 0, MAX_FADE_LEVEL);
|
||||
|
||||
// find the peak and trough of the pulse wave
|
||||
if (Signal < thresh && N > (IBI / 5) * 3) { // avoid dichrotic noise by waiting 3/5 of last IBI
|
||||
if (Signal < T) { // T is the trough
|
||||
T = Signal; // keep track of lowest point in pulse wave
|
||||
}
|
||||
}
|
||||
|
||||
if (Signal > thresh && Signal > P) { // thresh condition helps avoid noise
|
||||
P = Signal; // P is the peak
|
||||
} // keep track of highest point in pulse wave
|
||||
|
||||
// NOW IT'S TIME TO LOOK FOR THE HEART BEAT
|
||||
// signal surges up in value every time there is a pulse
|
||||
if (N > 250) { // avoid high frequency noise
|
||||
if ( (Signal > thresh) && (Pulse == false) && (N > (IBI / 5) * 3) ) {
|
||||
Pulse = true; // set the Pulse flag when we think there is a pulse
|
||||
IBI = sampleCounter - lastBeatTime; // measure time between beats in mS
|
||||
lastBeatTime = sampleCounter; // keep track of time for next pulse
|
||||
|
||||
if (secondBeat) { // if this is the second beat, if secondBeat == TRUE
|
||||
secondBeat = false; // clear secondBeat flag
|
||||
for (int i = 0; i <= 9; i++) { // seed the running total to get a realisitic BPM at startup
|
||||
rate[i] = IBI;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstBeat) { // if it's the first time we found a beat, if firstBeat == TRUE
|
||||
firstBeat = false; // clear firstBeat flag
|
||||
secondBeat = true; // set the second beat flag
|
||||
// IBI value is unreliable so discard it
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// keep a running total of the last 10 IBI values
|
||||
word runningTotal = 0; // clear the runningTotal variable
|
||||
|
||||
for (int i = 0; i <= 8; i++) { // shift data in the rate array
|
||||
rate[i] = rate[i + 1]; // and drop the oldest IBI value
|
||||
runningTotal += rate[i]; // add up the 9 oldest IBI values
|
||||
}
|
||||
|
||||
rate[9] = IBI; // add the latest IBI to the rate array
|
||||
runningTotal += rate[9]; // add the latest IBI to runningTotal
|
||||
runningTotal /= 10; // average the last 10 IBI values
|
||||
BPM = 60000 / runningTotal; // how many beats can fit into a minute? that's BPM!
|
||||
QS = true; // set Quantified Self flag (we detected a beat)
|
||||
FadeLevel = MAX_FADE_LEVEL; // If we're fading, re-light that LED.
|
||||
}
|
||||
}
|
||||
|
||||
if (Signal < thresh && Pulse == true) { // when the values are going down, the beat is over
|
||||
Pulse = false; // reset the Pulse flag so we can do it again
|
||||
amp = P - T; // get amplitude of the pulse wave
|
||||
thresh = amp / 2 + T; // set thresh at 50% of the amplitude
|
||||
P = thresh; // reset these for next time
|
||||
T = thresh;
|
||||
}
|
||||
|
||||
if (N > 2500) { // if 2.5 seconds go by without a beat
|
||||
thresh = threshSetting; // set thresh default
|
||||
P = 512; // set P default
|
||||
T = 512; // set T default
|
||||
lastBeatTime = sampleCounter; // bring the lastBeatTime up to date
|
||||
firstBeat = true; // set these to avoid noise
|
||||
secondBeat = false; // when we get the heartbeat back
|
||||
QS = false;
|
||||
BPM = 0;
|
||||
IBI = 600; // 600ms per beat = 100 Beats Per Minute (BPM)
|
||||
Pulse = false;
|
||||
amp = 100; // beat amplitude 1/10 of input range.
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void PulseSensor::initializeLEDs() {
|
||||
if (BlinkPin >= 0) {
|
||||
pinMode(BlinkPin, OUTPUT);
|
||||
digitalWrite(BlinkPin, LOW);
|
||||
}
|
||||
if (FadePin >= 0) {
|
||||
#ifndef NO_ANALOG_WRITE
|
||||
pinMode(FadePin, OUTPUT);
|
||||
analogWrite(FadePin, 0); // turn off the LED.
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void PulseSensor::updateLEDs() {
|
||||
if (BlinkPin >= 0) {
|
||||
if(Pulse){
|
||||
digitalWrite(BlinkPin, HIGH);
|
||||
}else{
|
||||
digitalWrite(BlinkPin,LOW);
|
||||
}
|
||||
}
|
||||
|
||||
if (FadePin >= 0) {
|
||||
#ifndef NO_ANALOG_WRITE
|
||||
analogWrite(FadePin, FadeLevel / FADE_SCALE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
PulseSensor measurement manager.
|
||||
See https://www.pulsesensor.com to get started.
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
#ifndef PULSE_SENSOR_H
|
||||
#define PULSE_SENSOR_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
class PulseSensor {
|
||||
public:
|
||||
// Constructs a PulseSensor manager using a default configuration.
|
||||
PulseSensor();
|
||||
|
||||
// sets variables to default start values
|
||||
void resetVariables();
|
||||
|
||||
// Sets the analog input pin this PulseSensor is connected to.
|
||||
void analogInput(int inputPin);
|
||||
|
||||
// Configures to blink the given pin while inside a pulse.
|
||||
void blinkOnPulse(int blinkPin);
|
||||
|
||||
// Configures to fade the given, starting on start of pulse.
|
||||
void fadeOnPulse(int fadePin);
|
||||
|
||||
// Returns the sample most recently-read from this PulseSensor.
|
||||
int getLatestSample();
|
||||
|
||||
// Returns the latest beats-per-minute measurement on this PulseSensor.
|
||||
int getBeatsPerMinute();
|
||||
|
||||
// Returns the latest inter-beat interval (milliseconds) on this PulseSensor.
|
||||
int getInterBeatIntervalMs();
|
||||
|
||||
// Reads and clears the 'saw start of beat' flag, "QS".
|
||||
boolean sawStartOfBeat();
|
||||
|
||||
// Returns true if this PulseSensor signal is inside a beat vs. outside.
|
||||
boolean isInsideBeat();
|
||||
|
||||
// Returns the latest amp value.
|
||||
int getPulseAmplitude();
|
||||
|
||||
// Returns the sample number of the most recent detected pulse.
|
||||
unsigned long getLastBeatTime();
|
||||
|
||||
//COULD move these to private by having a single public function the ISR calls.
|
||||
// (internal to the library) Read a sample from this PulseSensor.
|
||||
void readNextSample();
|
||||
|
||||
// (internal to the library) Process the latest sample.
|
||||
void processLatestSample();
|
||||
|
||||
// (internal to the library) Set up any LEDs the user wishes.
|
||||
void initializeLEDs();
|
||||
|
||||
// (internal to the library) Update the Blink and Fade LED states.
|
||||
void updateLEDs();
|
||||
|
||||
// (internal to the library) Updtate the thresh variables.
|
||||
void setThreshold(int threshold);
|
||||
|
||||
|
||||
private:
|
||||
// Configuration
|
||||
int InputPin; // Analog input pin for PulseSensor.
|
||||
int BlinkPin; // pin to blink in beat, or -1.
|
||||
int FadePin; // pin to fade on beat, or -1.
|
||||
|
||||
// Pulse detection output variables.
|
||||
// Volatile because our pulse detection code could be called from an Interrupt
|
||||
volatile int BPM; // int that holds raw Analog in 0. updated every call to readSensor()
|
||||
volatile int Signal; // holds the latest incoming raw data (0..1023)
|
||||
volatile int IBI; // int that holds the time interval (ms) between beats! Must be seeded!
|
||||
volatile boolean Pulse; // "True" when User's live heartbeat is detected. "False" when not a "live beat".
|
||||
volatile boolean QS; // The start of beat has been detected and not read by the Sketch.
|
||||
volatile int FadeLevel; // brightness of the FadePin, in scaled PWM units. See FADE_SCALE
|
||||
volatile int threshSetting; // used to seed and reset the thresh variable
|
||||
volatile int amp; // used to hold amplitude of pulse waveform, seeded (sample value)
|
||||
volatile unsigned long lastBeatTime; // used to find IBI. Time (sampleCounter) of the previous detected beat start.
|
||||
|
||||
// Variables internal to the pulse detection algorithm.
|
||||
// Not volatile because we use them only internally to the pulse detection.
|
||||
unsigned long sampleIntervalMs; // expected time between calls to readSensor(), in milliseconds.
|
||||
int rate[10]; // array to hold last ten IBI values (ms)
|
||||
unsigned long sampleCounter; // used to determine pulse timing. Milliseconds since we started.
|
||||
int P; // used to find peak in pulse wave, seeded (sample value)
|
||||
int T; // used to find trough in pulse wave, seeded (sample value)
|
||||
int thresh; // used to find instant moment of heart beat, seeded (sample value)
|
||||
boolean firstBeat; // used to seed rate array so we startup with reasonable BPM
|
||||
boolean secondBeat; // used to seed rate array so we startup with reasonable BPM
|
||||
};
|
||||
#endif // PULSE_SENSOR_H
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
Formatting of Serial output from PulseSensors.
|
||||
See https://www.pulsesensor.com to get started.
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
#include "PulseSensorSerialOutput.h"
|
||||
|
||||
PulseSensorSerialOutput::PulseSensorSerialOutput() {
|
||||
pOutput = NULL;
|
||||
OutputType = SERIAL_PLOTTER;
|
||||
}
|
||||
|
||||
void PulseSensorSerialOutput::setSerial(Stream &output) {
|
||||
pOutput = &output;
|
||||
}
|
||||
|
||||
Stream *PulseSensorSerialOutput::getSerial() {
|
||||
return pOutput;
|
||||
}
|
||||
|
||||
void PulseSensorSerialOutput::setOutputType(byte outputType) {
|
||||
OutputType = outputType;
|
||||
}
|
||||
|
||||
void PulseSensorSerialOutput::outputSample(PulseSensor sensors[], int numSensors) {
|
||||
if (!pOutput) {
|
||||
return; // no serial output object has been set.
|
||||
}
|
||||
|
||||
switch (OutputType) {
|
||||
case SERIAL_PLOTTER:
|
||||
if (numSensors == 1) {
|
||||
pOutput->print(sensors[0].getBeatsPerMinute());
|
||||
pOutput->print(F(","));
|
||||
pOutput->print(sensors[0].getInterBeatIntervalMs());
|
||||
pOutput->print(F(","));
|
||||
pOutput->println(sensors[0].getLatestSample());
|
||||
} else {
|
||||
for (int i = 0; i < numSensors; ++i) {
|
||||
if (i != 0) {
|
||||
pOutput->print(F(","));
|
||||
}
|
||||
pOutput->print(sensors[i].getLatestSample());
|
||||
// Could output BPM and IBI here.
|
||||
}
|
||||
pOutput->println();
|
||||
}
|
||||
break;
|
||||
|
||||
case PROCESSING_VISUALIZER:
|
||||
// Don't print bpm and ibi here; they're printed per-beat.
|
||||
if (numSensors == 1) {
|
||||
outputToSerial('S', sensors[0].getLatestSample());
|
||||
} else {
|
||||
// PulseSensor 0 = a; #1 = b; #2 = c, etc.
|
||||
for(int i = 0; i < numSensors; ++i){
|
||||
outputToSerial('a' + i, sensors[i].getLatestSample());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// unknown output type: no output
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PulseSensorSerialOutput::outputBeat(PulseSensor sensors[], int numSensors, int sensorIndex) {
|
||||
if (!pOutput) {
|
||||
return; // no serial output object has been set.
|
||||
}
|
||||
|
||||
switch (OutputType) {
|
||||
case SERIAL_PLOTTER:
|
||||
/*
|
||||
The plotter doesn't understand occasionally-printed data,
|
||||
so we print nothing per-beat.
|
||||
*/
|
||||
break;
|
||||
|
||||
case PROCESSING_VISUALIZER:
|
||||
if (numSensors == 1) {
|
||||
outputToSerial('B', sensors[sensorIndex].getBeatsPerMinute());
|
||||
outputToSerial('Q', sensors[sensorIndex].getInterBeatIntervalMs());
|
||||
} else {
|
||||
// PulseSensor 0 = A, M; #1 = B, N; etc.
|
||||
outputToSerial('A' + sensorIndex
|
||||
, sensors[sensorIndex].getBeatsPerMinute());
|
||||
outputToSerial('M' + sensorIndex
|
||||
, sensors[sensorIndex].getInterBeatIntervalMs());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// unknown output type: no output
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// // testing feedback
|
||||
// void printThreshSetting() {
|
||||
//
|
||||
// }
|
||||
|
||||
void PulseSensorSerialOutput::outputToSerial(char symbol, int data) {
|
||||
if (!pOutput) {
|
||||
return; // no serial output object has been set.
|
||||
}
|
||||
|
||||
pOutput->print(symbol);
|
||||
pOutput->println(data);
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
Serial output formatter for the PulseSensor Playground.
|
||||
This object knows all about the formats for our Serial output.
|
||||
See https://www.pulsesensor.com to get started.
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
#ifndef PULSE_SENSOR_SERIAL_OUTPUT_H
|
||||
#define PULSE_SENSOR_SERIAL_OUTPUT_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "PulseSensor.h" // to access PulseSensor state.
|
||||
|
||||
/*
|
||||
Destinations for serial output:
|
||||
PROCESSING_VISUALIZER = write to the Processing Visualizer Sketch.
|
||||
SERIAL_PLOTTER = write to the Arduino IDE Serial Plotter.
|
||||
*/
|
||||
#define PROCESSING_VISUALIZER ((byte) 1)
|
||||
#define SERIAL_PLOTTER ((byte) 2)
|
||||
|
||||
class PulseSensorSerialOutput {
|
||||
public:
|
||||
|
||||
/*
|
||||
Constructs a default Serial output manager.
|
||||
*/
|
||||
PulseSensorSerialOutput();
|
||||
|
||||
/*
|
||||
Tells the library what Serial output to use,
|
||||
such as Serial, Serial1, or a SoftwareSerial.
|
||||
*/
|
||||
void setSerial(Stream &output);
|
||||
|
||||
/*
|
||||
Find what Serial stream we are configured to print to.
|
||||
|
||||
Returns a pointer to the Serial we're configured for
|
||||
(for example Serial, Serial1, or a SoftwareSerial object),
|
||||
or NULL if no Serial output has been set up.
|
||||
*/
|
||||
Stream *getSerial();
|
||||
|
||||
/*
|
||||
Sets the format (destination) of the Serial Output:
|
||||
SERIAL_PLOTTER or PROCESSING_VISUALIZER.
|
||||
*/
|
||||
void setOutputType(byte outputType);
|
||||
|
||||
/*
|
||||
Output the Signal data for all PulseSensors
|
||||
*/
|
||||
void outputSample(PulseSensor sensors[], int numberOfSensors);
|
||||
|
||||
/*
|
||||
Output the per-beat data (Beats per Minute, Inter-beat Interval)
|
||||
for the given PulseSensor.
|
||||
|
||||
sensorIndex = the sensor to output beat information about.
|
||||
Usually is the PulseSensor that a beat was detected on.
|
||||
*/
|
||||
void outputBeat(PulseSensor sensors[], int numberOfSensors, int sensorIndex);
|
||||
|
||||
/*
|
||||
Write the given data prefixed by the given symbol.
|
||||
*/
|
||||
void outputToSerial(char symbol, int data);
|
||||
|
||||
private:
|
||||
// If non-null, the output stream to print to. If null, don't print.
|
||||
Stream *pOutput;
|
||||
|
||||
// The destination of data: PROCESSING_VISUALIZER or SERIAL_PLOTTER
|
||||
int OutputType;
|
||||
|
||||
};
|
||||
#endif // PULSE_SENSOR_SERIAL_OUTPUT_H
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
Sample time statistics functions.
|
||||
Designed to provide insite into the timing accuracy of
|
||||
programs that read data from a PulseSensor.
|
||||
See PulseSensorPlayground.h PULSE_SENSOR_TIMING_ANALYSIS
|
||||
|
||||
See https://www.pulsesensor.com to get started.
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
#include <PulseSensorPlayground.h>
|
||||
|
||||
PulseSensorTimingStatistics::PulseSensorTimingStatistics(
|
||||
long sampleIntervalMicros, int samplesToMeasure) {
|
||||
SamplesDesired = samplesToMeasure;
|
||||
SampleIntervalMicros = sampleIntervalMicros;
|
||||
|
||||
resetStatistics();
|
||||
}
|
||||
|
||||
void PulseSensorTimingStatistics::resetStatistics() {
|
||||
SamplesSeen = 0;
|
||||
MinJitterMicros = 0;
|
||||
MaxJitterMicros = 0;
|
||||
OffsetsSum = 0.0;
|
||||
LastSampleMicros = 0L;
|
||||
}
|
||||
|
||||
int PulseSensorTimingStatistics::recordSampleTime() {
|
||||
unsigned long nowMicros = micros();
|
||||
|
||||
if (SamplesSeen > 0) {
|
||||
long offsetMicros =
|
||||
(long) (nowMicros - LastSampleMicros) - SampleIntervalMicros;
|
||||
offsetMicros = constrain(offsetMicros, -32767, 32767);
|
||||
|
||||
OffsetsSum += (float) offsetMicros;
|
||||
|
||||
if (MinJitterMicros > offsetMicros) {
|
||||
MinJitterMicros = offsetMicros;
|
||||
}
|
||||
if (MaxJitterMicros < offsetMicros) {
|
||||
MaxJitterMicros = offsetMicros;
|
||||
}
|
||||
}
|
||||
|
||||
LastSampleMicros = nowMicros;
|
||||
++SamplesSeen;
|
||||
|
||||
return (SamplesDesired - SamplesSeen);
|
||||
}
|
||||
|
||||
void PulseSensorTimingStatistics::outputStatistics(Stream *pOut) {
|
||||
if (!pOut) {
|
||||
return; // not configured for Serial output.
|
||||
}
|
||||
pOut->print(MinJitterMicros);
|
||||
pOut->print(" ");
|
||||
pOut->print(getAverageOffsetMicros());
|
||||
pOut->print(" ");
|
||||
pOut->println(MaxJitterMicros);
|
||||
}
|
||||
|
||||
int PulseSensorTimingStatistics::getAverageOffsetMicros() {
|
||||
// the number of offsets is the number of samples - 1.
|
||||
if (SamplesSeen - 1 <= 0) {
|
||||
return 0;
|
||||
}
|
||||
return (int) ((OffsetsSum + 0.5) / (SamplesSeen - 1));
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Sample time statistics functions.
|
||||
Designed to provide insite into the timing accuracy of
|
||||
programs that don't use interrupts to read data from a PulseSensor.
|
||||
|
||||
See https://www.pulsesensor.com to get started.
|
||||
|
||||
Copyright World Famous Electronics LLC - see LICENSE
|
||||
Contributors:
|
||||
Joel Murphy, https://pulsesensor.com
|
||||
Yury Gitman, https://pulsesensor.com
|
||||
Bradford Needham, @bneedhamia, https://bluepapertech.com
|
||||
|
||||
Licensed under the MIT License, a copy of which
|
||||
should have been included with this software.
|
||||
|
||||
This software is not intended for medical use.
|
||||
*/
|
||||
#ifndef PULSE_SENSOR_TIMING_STATISTICS_H
|
||||
#define PULSE_SENSOR_TIMING_STATISTICS_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
/*
|
||||
Timing statistics show how accurate the beats per minute
|
||||
and inter-beat interval measurements are.
|
||||
|
||||
An average offset other than zero shows that samples were recorded
|
||||
at a rate different from the expected rate.
|
||||
For example, for an expected sample interval of 2000 microseconds
|
||||
(500 samples per second), an offset of 60 microseconds indicates that
|
||||
samples were recorded at a rate 3% slower than expected, which in turn
|
||||
shows that the measured beats per minute and inter-beat interval
|
||||
have a 3% error due to timing offset.
|
||||
|
||||
A large span between minimum and maximum jitter shows that sometimes
|
||||
the sampling loop was slow or fast. This could be due to, for example,
|
||||
unexpectedly slow code that executes only every so often.
|
||||
*/
|
||||
class PulseSensorTimingStatistics {
|
||||
public:
|
||||
/*
|
||||
Constructs an object for measuring statistics about the timing
|
||||
of samples from the PulseSensor.
|
||||
|
||||
sampleIntervalMicros = expected time between samples, in microseconds.
|
||||
samplesToMeasure = number of samples to measure timing over.
|
||||
*/
|
||||
PulseSensorTimingStatistics(long sampleIntervalMicros, int samplesToMeasure);
|
||||
|
||||
/*
|
||||
(re)start the collection of timing statistics.
|
||||
Called automatically by the PulseSensorTimingStatistics constructor.
|
||||
*/
|
||||
void resetStatistics();
|
||||
|
||||
|
||||
/*
|
||||
Record the fact that we just now read the PulseSensor output.
|
||||
|
||||
Returns the number of samples remaining to be recorded.
|
||||
The caller should stop calling recordSampleTime() once
|
||||
this function returns 0.
|
||||
*/
|
||||
int recordSampleTime();
|
||||
|
||||
/*
|
||||
Serial prints the sample timing statistics.
|
||||
*/
|
||||
void outputStatistics(Stream *pOut);
|
||||
|
||||
int getMinJitterMicros() {
|
||||
return MinJitterMicros;
|
||||
}
|
||||
int getMaxJitterMicros() {
|
||||
return MaxJitterMicros;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the average offset seen so far, in microseconds.
|
||||
*/
|
||||
int getAverageOffsetMicros();
|
||||
|
||||
private:
|
||||
long SampleIntervalMicros; // desired sample interval, in microseconds.
|
||||
int SamplesDesired; // total number of samples we want to record.
|
||||
unsigned long LastSampleMicros; // time (microseconds) of the previous sample.
|
||||
int MinJitterMicros; // minimum offset seen.
|
||||
int MaxJitterMicros; // maximum offset seen.
|
||||
float OffsetsSum; // sum of offsets so far.
|
||||
int SamplesSeen; // number of samples seen so far.
|
||||
};
|
||||
#endif // PULSE_SENSOR_TIMING_STATISTICS_H
|
||||
Reference in New Issue
Block a user