pulse sensor + arduino mkr1000 to calculate BPM - arduino
tldr; what is an easy/logical way (for a beginner) to calculate BPM using pulse sensor and mkr1000? I don't want any visualizations or processing sketch, but just print BPM values
Please bear with me, I am a newbie at this and i've tried my best to understand this and fix this issue, but in vain.
I am using the pulse sensor (SEN-11574) with Arduino mkr1000 to calculate the BPM and print it in serial monitor. I was able to get raw readings using their starter code
// 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);
}
However the real problem is that I am unable to calculate the BPM using their example code available on their website here
From what I understand, the interrupt timer function in the Interrupt.ino file is not compatible with mkr1000. Attached is this code for your reference.
// THIS IS THE TIMER 2 INTERRUPT SERVICE ROUTINE.
// Timer 2 makes sure that we take a reading every 2 miliseconds
ISR(TIMER2_COMPA_vect){ // triggered when Timer2 counts to 124
cli(); // disable interrupts while we do this
Signal = analogRead(pulsePin); // read the Pulse Sensor
sampleCounter += 2; // keep track of the time in mS with this variable
int N = sampleCounter - lastBeatTime; // monitor the time since the last beat to avoid noise
// 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
digitalWrite(blinkPin,HIGH); // turn on pin 13 LED
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
sei(); // enable interrupts again
return; // IBI value is unreliable so discard it
}
// 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
// QS FLAG IS NOT CLEARED INSIDE THIS ISR
}
}
if (Signal < thresh && Pulse == true){ // when the values are going down, the beat is over
digitalWrite(blinkPin,LOW); // turn off pin 13 LED
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 = 530; // 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
}
sei(); // enable interrupts when youre done!
}// end isr
On the interrupt-notes file they mention another work-around for processors that are not compatible with this code, but even after hours of following the intructions, the code didn't work, again with errors with timer interrupt functions.
Next, I used this guide but again, it didn't work either and just prints raw signal value that constantly changes (S1023). The code is attached (2 tabs):
/* Pulse Sensor Amped 1.4 by Joel Murphy and Yury Gitman http://www.pulsesensor.com
Adapted by sdizdarevic
---------------------- Notes ---------------------- ----------------------
This code:
1) Blinks an LED to User's Live Heartbeat PIN 6
2) Fades an LED to User's Live HeartBeat
3) Determines BPM
4) Prints All of the Above to Serial
Read Me:
https://github.com/WorldFamousElectronics/PulseSensor_Amped_Arduino/blob/master/README.md
---------------------- ---------------------- ----------------------
*/
// Variables
int pulsePin = 0; // Pulse Sensor purple wire connected to analog pin 0
int blinkPin = 6; // pin to blink led at each beat
//int fadePin = 5; // pin to do fancy classy fading blink at each beat
//int fadeRate = 0; // used to fade LED on with PWM on fadePin
// Volatile Variables, used in the interrupt service routine!
volatile int BPM; // int that holds raw Analog in 0. updated every 2mS
volatile int Signal; // holds the incoming raw data
volatile int IBI = 600; // int that holds the time interval between beats! Must be seeded!
volatile boolean Pulse = false; // "True" when User's live heartbeat is detected. "False" when not a "live beat".
volatile boolean QS = false; // becomes true when Arduoino finds a beat.
volatile int rate[10]; // array to hold last ten IBI values
volatile unsigned long sampleCounter = 0; // used to determine pulse timing
volatile unsigned long lastBeatTime = 0; // used to find IBI
volatile int P =512; // used to find peak in pulse wave, seeded
volatile int T = 512; // used to find trough in pulse wave, seeded
volatile int thresh = 525; // used to find instant moment of heart beat, seeded
volatile int amp = 100; // used to hold amplitude of pulse waveform, seeded
volatile boolean firstBeat = true; // used to seed rate array so we startup with reasonable BPM
volatile boolean secondBeat = false; // used to seed rate array so we startup with reasonable BPM
// Regards Serial OutPut -- Set This Up to your needs
static boolean serialVisual = false; // Set to 'false' by Default. Re-set to 'true' to see Arduino Serial Monitor ASCII Visual Pulse
void setup(){
pinMode(blinkPin,OUTPUT); // pin that will blink to your heartbeat!
//pinMode(fadePin,OUTPUT); // pin that will fade to your heartbeat!
Serial.begin(115200); // we agree to talk fast!
//interruptSetup(); // sets up to read Pulse Sensor signal every 2mS
// IF YOU ARE POWERING The Pulse Sensor AT VOLTAGE LESS THAN THE BOARD VOLTAGE,
// UN-COMMENT THE NEXT LINE AND APPLY THAT VOLTAGE TO THE A-REF PIN
// analogReference(EXTERNAL);
}
// Where the Magic Happens
void loop(){
//
//
Signal = analogRead(pulsePin); // read the Pulse Sensor
sampleCounter += 2; // keep track of the time in mS with this variable
int N = sampleCounter - lastBeatTime; // monitor the time since the last beat to avoid noise
// 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
digitalWrite(blinkPin,HIGH); // turn on pin 13 LED
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
return; // IBI value is unreliable so discard it
}
// 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
// QS FLAG IS NOT CLEARED INSIDE THIS ISR
}
}
if (Signal < thresh && Pulse == true){ // when the values are going down, the beat is over
digitalWrite(blinkPin,LOW); // turn off pin 13 LED
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 = 512; // 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
}
serialOutput() ;
if (QS == true){ // A Heartbeat Was Found
// BPM and IBI have been Determined
// Quantified Self "QS" true when arduino finds a heartbeat
// fadeRate = 255; // Makes the LED Fade Effect Happen
// Set 'fadeRate' Variable to 255 to fade LED with pulse
serialOutputWhenBeatHappens(); // A Beat Happened, Output that to serial.
QS = false; // reset the Quantified Self flag for next time
}
// ledFadeToBeat(); // Makes the LED Fade Effect Happen
delay(20); // take a break
}
/*void ledFadeToBeat(){
fadeRate -= 15; // set LED fade value
fadeRate = constrain(fadeRate,0,255); // keep LED fade value from going into negative numbers!
//analogWrite(fadePin,fadeRate); // fade LED
}
*/
SerialHandling file:
//////////
///////// All Serial Handling Code,
///////// It's Changeable with the 'serialVisual' variable
///////// Set it to 'true' or 'false' when it's declared at start of code.
/////////
void serialOutput(){ // Decide How To Output Serial.
if (serialVisual == true){
arduinoSerialMonitorVisual('-', Signal); // goes to function that makes Serial Monitor Visualizer
} else{
sendDataToSerial('S', Signal); // goes to sendDataToSerial function
}
}
// Decides How To OutPut BPM and IBI Data
void serialOutputWhenBeatHappens(){
if (serialVisual == true){ // Code to Make the Serial Monitor Visualizer Work
Serial.print("*** Heart-Beat Happened *** "); //ASCII Art Madness
Serial.print("BPM: ");
Serial.print(BPM);
Serial.print(" ");
} else{
sendDataToSerial('B',BPM); // send heart rate with a 'B' prefix
sendDataToSerial('Q',IBI); // send time between beats with a 'Q' prefix
}
}
// Sends Data to Pulse Sensor Processing App, Native Mac App, or Third-party Serial Readers.
void sendDataToSerial(char symbol, int data ){
Serial.print(symbol);
Serial.println(data);
}
// Code to Make the Serial Monitor Visualizer Work
void arduinoSerialMonitorVisual(char symbol, int data ){
const int sensorMin = 0; // sensor minimum, discovered through experiment
const int sensorMax = 1024; // sensor maximum, discovered through experiment
int sensorReading = data;
// map the sensor range to a range of 12 options:
int range = map(sensorReading, sensorMin, sensorMax, 0, 11);
// do something different depending on the
// range value:
switch (range) {
case 0:
Serial.println(""); /////ASCII Art Madness
break;
case 1:
Serial.println("---");
break;
case 2:
Serial.println("------");
break;
case 3:
Serial.println("---------");
break;
case 4:
Serial.println("------------");
break;
case 5:
Serial.println("--------------|-");
break;
case 6:
Serial.println("--------------|---");
break;
case 7:
Serial.println("--------------|-------");
break;
case 8:
Serial.println("--------------|----------");
break;
case 9:
Serial.println("--------------|----------------");
break;
case 10:
Serial.println("--------------|-------------------");
break;
case 11:
Serial.println("--------------|-----------------------");
break;
}
}
Serial monitor only displays these numbers that are constantly changing:
S797
S813
S798
S811
S822
S802
S821
S819
S818
S806
S797
S797
S812
S816
S794
S820
S821
S808
S816
S820
S803
S810
S811
S806
S822
S817
S811
S822
S800
S820
S799
S800
S815
S809
S820
S822
S821
S809
S796
S821
S816
S798
S820
All in all, I was hoping if someone could help me with the code to calculate BPM in a more basic/ easy manner without having to deal with visualization of the BPM.
Sorry for the long post, thanks!
This is how i did it, to overpass the absence of interrupt on my board:
#define pulsePin A0
// VARIABLES
int rate[10];
unsigned long sampleCounter = 0;
unsigned long lastBeatTime = 0;
unsigned long lastTime = 0, N;
int BPM = 0;
int IBI = 0;
int P = 512;
int T = 512;
int thresh = 512;
int amp = 100;
int Signal;
boolean Pulse = false;
boolean firstBeat = true;
boolean secondBeat = true;
boolean QS = false;
void setup() {
Serial.begin(9600);
}
void loop() {
if (QS == true) {
Serial.println("BPM: "+ String(BPM));
QS = false;
} else if (millis() >= (lastTime + 2)) {
readPulse();
lastTime = millis();
}
}
void readPulse() {
Signal = analogRead(pulsePin);
sampleCounter += 2;
int N = sampleCounter - lastBeatTime;
detectSetHighLow();
if (N > 250) {
if ( (Signal > thresh) && (Pulse == false) && (N > (IBI / 5) * 3) )
pulseDetected();
}
if (Signal < thresh && Pulse == true) {
Pulse = false;
amp = P - T;
thresh = amp / 2 + T;
P = thresh;
T = thresh;
}
if (N > 2500) {
thresh = 512;
P = 512;
T = 512;
lastBeatTime = sampleCounter;
firstBeat = true;
secondBeat = true;
}
}
void detectSetHighLow() {
if (Signal < thresh && N > (IBI / 5) * 3) {
if (Signal < T) {
T = Signal;
}
}
if (Signal > thresh && Signal > P) {
P = Signal;
}
}
void pulseDetected() {
Pulse = true;
IBI = sampleCounter - lastBeatTime;
lastBeatTime = sampleCounter;
if (firstBeat) {
firstBeat = false;
return;
}
if (secondBeat) {
secondBeat = false;
for (int i = 0; i <= 9; i++) {
rate[i] = IBI;
}
}
word runningTotal = 0;
for (int i = 0; i <= 8; i++) {
rate[i] = rate[i + 1];
runningTotal += rate[i];
}
rate[9] = IBI;
runningTotal += rate[9];
runningTotal /= 10;
BPM = 60000 / runningTotal;
QS = true;
}
The sensor I used is a DFRobot Piezo Disc Vibration Sensor Module.
void setup() {
Serial.begin(57600);
}
void loop() {
int avg = 0;
for(int i=0;i<64;i++){
avg+=analogRead(A2);
}
Serial.println(avg/64,DEC);
delay(5);
}
void setup() {
Serial.begin(57600);
}
void loop() {
int avg = 0;
for(int i=0;i<64;i++){
avg+=analogRead(A2);
}
Serial.println(avg/64,DEC);
delay(5);
}
When defining an arbitrary threshold (e.g. half of the maximum measured value), the rising edge of the signal will pass the threshold once per heartbeat, making measuring it as simple as measuring the time between two successive beats. For less jitter, I chose to calculate the heart rate using the average of the last 16 time differences between the beats.
code that calculates the heart rate and outputs the average heart rate over the last 16 beats at every beat:
int threshold = 60;
int oldvalue = 0;
int newvalue = 0;
unsigned long oldmillis = 0;
unsigned long newmillis = 0;
int cnt = 0;
int timings[16];
void setup() {
Serial.begin(57600);
}
void loop() {
oldvalue = newvalue;
newvalue = 0;
for(int i=0; i<64; i++){ // Average over 16 measurements
newvalue += analogRead(A2);
}
newvalue = newvalue/64;
// find triggering edge
if(oldvalue<threshold && newvalue>=threshold){
oldmillis = newmillis;
newmillis = millis();
// fill in the current time difference in ringbuffer
timings[cnt%16]= (int)(newmillis-oldmillis);
int totalmillis = 0;
// calculate average of the last 16 time differences
for(int i=0;i<16;i++){
totalmillis += timings[i];
}
// calculate heart rate
int heartrate = 60000/(totalmillis/16);
Serial.println(heartrate,DEC);
cnt++;
}
delay(5);
}
int threshold = 60;
int oldvalue = 0;
int newvalue = 0;
unsigned long oldmillis = 0;
unsigned long newmillis = 0;
int cnt = 0;
int timings[16];
void setup() {
Serial.begin(57600);
}
void loop() {
oldvalue = newvalue;
newvalue = 0;
for(int i=0; i<64; i++){ // Average over 16 measurements
newvalue += analogRead(A2);
}
newvalue = newvalue/64;
// find triggering edge
if(oldvalue<threshold && newvalue>=threshold){
oldmillis = newmillis;
newmillis = millis();
// fill in the current time difference in ringbuffer
timings[cnt%16]= (int)(newmillis-oldmillis);
int totalmillis = 0;
// calculate average of the last 16 time differences
for(int i=0;i<16;i++){
totalmillis += timings[i];
}
// calculate heart rate
int heartrate = 60000/(totalmillis/16);
Serial.println(heartrate,DEC);
cnt++;
}
delay(5);
}
If you would like to try this at home, just connect the analog output of the sensor to A2 (or change the code) and connect the 5V and GND lines of the sensor.
Related
Send Arduino serial commands while plotting
I have a simple PD Arduino controller to spin a motor. I want to use it to demonstrate system responses graphically. I have it working so I can give a target position using the serial monitor, but I want to be able to see the serial plot output at the same time. There seems to be a similar dialogue box in the Serial Plotter, but commands sent from there don't seem to be recognized. Is there a way to plot incoming serial data while also sending commands as described above? I don't mind if I need additional libraries, but I can't see why it shouldn't work natively since I can already send commands while receiving info using the Serial Monitor. Maybe I'm misunderstanding that process. Any help would be very appreciated. See full code below: // Clockwise rotation direction. #define CW 1 // Counter clockwise rotation direction. #define CCW 0 // Frequency of output PWM signal. #define PWM_FREQ 25000 // Update rate in microseconds. #define CYCLE_TIME 1000 // Rate of sending position data to PC. #define PLOT_RATE 200 #define PLOT_COUNTER CYCLE_TIME/PLOT_RATE // IO pins. // // The pin connected to ENBble A on the driver. const int ENB = 14; // Pins connected to IN3 and IN4 on the driver (for controlling the rotation direction). const int IN4 = 15; const int IN3 = 16; // Signal A wire of the encoder. const int ENCA = 17; // Signal B wire of the encoder. const int ENCB = 18; // Value of ENCA. int enca = 0; // Value of ENCB. int encb = 0; // Value of IN3. int in3 = 0; // Value of IN4. int in4 = 0; // Motors position measure by encoder. volatile long int motorPos = 0; // Communication variables. // // The byte sent over serial to Teensy. int incomingByte = 0; // Input buffer for receiving user input over serial. char inputBuffer[8]; int bufferCnt = 0; // Counter for sending position over serial for plotting purposes. int pltCounter = 0; // Controller variables./ / // Last motor position. long int lastPos = 0; // Target motor position. int targetPos = 0; // Position at the start of the control loop. int currentPos = 0; // Position at the start of the previous control loop. int prevPos = 0; // Change in position (for approximating the derivative). int dP = 0; // Position error. int pError = 0; // P term of the controller. int pTerm = 0; // D term of the controller. int dTerm = 0; // Speed (= voltage = duty cycle). Controller output mapped to duty cycle range. int spd = 0; // Controller output. int contOut = 0; // Ratio for transforming counts to degrees (1920 count / 360 deg) float ratio = static_cast<float>(360)/static_cast<float>(1920); // Controller tunable parameters. // // P gain. const int kP = 10; // D gain. const int kD = 0; // Error in encoder pulses correponding to the minimum duty cycle. const int minErr = 0; // Error in encoder pulses corresponding to the maximum duty cycle. const int maxErr = 1024; // minDutyCycle and maxDutyCycle depend on PWM frequency and can be determined in dc_motor_speed_control . For example for frequency of 25k, // minDutyCycle = 120 (Motor starts to move), // maxDutyCycle = 190 (Motor speed reaches its maximum given the supplied voltage). const int minDutyCycle = 120; const int maxDutyCycle = 190; // Controller update rate variables. // // Difference in time between desired cycle period and its execution time (without any delay()s). int cycleDiff; // Control loop start time. long int startTime; // Control loop end time. long int endTime; // Plotting float motorPosDeg = 0; //Plotter p; void setup() { Serial.begin(9600); // Initialize the pins. pinMode(IN3,OUTPUT); pinMode(IN4,OUTPUT); pinMode(ENB,OUTPUT); pinMode(ENCA,INPUT); pinMode(ENCB,INPUT); analogWriteFrequency(ENB, PWM_FREQ); // Set the initial rotation direction. setDirection(CCW); // Start with the motor at rest. analogWrite(ENB,0); // Encoder interrupt. attachInterrupt(digitalPinToInterrupt(ENCA), encoderAISRising, RISING); attachInterrupt(digitalPinToInterrupt(ENCB), encoderBISRising, RISING); //p.Begin(); //p.AddTimeGraph("Position v Time", 1000, "Position", motorPosDeg); } // *** Encoder interrupt routines. See "Understanding Quadrature Encoded Signals" here: https://www.pjrc.com/teensy/td_libs_Encoder.html" *** // void encoderAISRising(){ if(digitalRead(ENCB) == HIGH) motorPos++; else motorPos--; attachInterrupt(digitalPinToInterrupt(ENCA), encoderAISFalling, FALLING); } void encoderAISFalling(){ if(digitalRead(ENCB) == LOW) motorPos++; else motorPos--; attachInterrupt(digitalPinToInterrupt(ENCA), encoderAISRising, RISING); } void encoderBISRising(){ if(digitalRead(ENCA) == LOW) motorPos++; else motorPos--; attachInterrupt(digitalPinToInterrupt(ENCB), encoderBISFalling, FALLING); } void encoderBISFalling(){ if(digitalRead(ENCA) == HIGH) motorPos++; else motorPos--; attachInterrupt(digitalPinToInterrupt(ENCB), encoderBISRising, RISING); } // *** ***// // Default rotation direction is CCW. void setDirection(bool dir){ // CCW if (dir == CCW){ digitalWrite(IN3,HIGH); digitalWrite(IN4,LOW); }else{ digitalWrite(IN3,LOW); digitalWrite(IN4,HIGH); } } void loop() { if (Serial.available() > 0) { // Read the incoming bytes, until a next line character (Enter) is encountered. while (1){ incomingByte = Serial.read(); // We have read all the bytes. if (incomingByte == '\n' || incomingByte == '\r'){ Serial.read(); break; }else{ // Store the byte in the buffer and move on to the next. inputBuffer[bufferCnt] = incomingByte; bufferCnt++; } } // Add a NULL character to the end of the array. Required for using atoi. inputBuffer[bufferCnt] = '\0'; bufferCnt = 0; // Convert string to integer. targetPos = atoi(inputBuffer); targetPos = targetPos / ratio; } // int i = 0; // if (i % 2 == 0){ // targetPos = 360; // } else { // targetPos = 0; // } startTime = micros(); // Get the latest motor position. currentPos = motorPos; // Position error. //pError = targetPos - motorPos; pError = targetPos - currentPos; // P term of the controller. pTerm = kP * pError; dP = currentPos - prevPos; // D term of the controller. CYCLE_TIME/1000 normalizes the denominator, otherwise dTerm would always be zero (integer division). dTerm = kD * (dP/(CYCLE_TIME/1000)); contOut = pTerm + dTerm; // Set the target duty cycle (i.e. speed (i.e. voltage)). // Error (in terms of encoder pulses) in the range minErr-maxErr is mapped to speed range corresponding to minDutyCycle-maxDutyCycle. // 4 parameters to tune here. spd = map(abs(contOut),minErr,maxErr,minDutyCycle,maxDutyCycle); // Set the direction according to sign of position error (CCW is positive), and then speed. // One optimization would be calling analogWrite(ENB,abs(spd)) at the start or end of the loop instead // (at the expense of readibility). if (pError > 0){ setDirection(CCW); analogWrite(ENB,abs(spd)); }else if (pError < 0){ setDirection(CW); analogWrite(ENB,abs(spd)); } if (pltCounter == PLOT_COUNTER){ float mtrPos = static_cast<float>(motorPos); motorPosDeg = mtrPos * ratio; Serial.print(int(motorPosDeg)); Serial.println(); pltCounter = 0; } pltCounter++; prevPos = currentPos; cycleDiff = micros() - startTime; // Adjust the update rate. if (cycleDiff < CYCLE_TIME){ delayMicroseconds(CYCLE_TIME - cycleDiff); } //i++; }
From what i understand of the plot function it utilizes the main arduino connexion to work. Based on how the arduino uart work you can only have 1 com port connexion per com port. This means you can either have the plot or command line open for each uart connexion. It is possible with different version of arduino to have multiple com ports. On the arduino uno there is only one com port "Serial". On the mega i think there are 3 uart ports. If you use a external FTDI UART board you can have the plot window open for serial0 and have the FTDI board connected on Serial1 to have the command line window open. You will have to change your code a little to send commands to serial1. Here are a couple links to help you. https://docs.arduino.cc/tutorials/communication/TwoPortReceive https://docs.arduino.cc/built-in-examples/communication/MultiSerialMega https://www.amazon.fr/AZDelivery-Adaptateur-FT232RL-s%C3%A9rie-book/dp/B01N9RZK6I?th=1
Arduino vl53l0x sensor
I'm trying to make a toilet sensorish trigger using vl53l0x sensor, I'm having trouble firing an action while my hand is in front of the sensor for 5 seconds or so, while I've tried different versions of blinkwithoutdelay sketches, and other methods found online, all of them, trigger the 5 seconds, after I pulled my hand off the sensor, which is not what I want. Thanks in advance, I posted my sketch to what I got so far. Thanks in advance! // Library for TOF SENSOR #include <Wire.h> #include <VL53L0X.h> VL53L0X sensor; // Time calculation unsigned long startTime; unsigned long endTime; // store end time here unsigned long duration; // duration stored byte timerRunning; void setup() { // put your setup code here, to run once: Serial.begin(9600); Wire.begin(); sensor.init(); sensor.setTimeout(500); // Start continuous back-to-back mode (take readings as // fast as possible). To use continuous timed mode // instead, provide a desired inter-measurement period in // ms (e.g. sensor.startContinuous(100)). sensor.startContinuous(); } void loop() { // put your main code here, to run repeatedly: delay(1000); int tofdata = sensor.readRangeContinuousMillimeters(); int distance = tofdata / 10; // convert mm to cm Serial.print( distance ); // print new converted data Serial.println( " cm" ); // Code for presence detection if ( timerRunning == 0 && distance <= 20 ){ startTime = millis() / 1000; Serial.println("time started, starting count"); timerRunning = 1; } if ( timerRunning == 1 && distance >= 20 ){ endTime = millis() / 1000; timerRunning = 0; duration = endTime - startTime; Serial.println ("Presence detected for seconds: "); Serial.print(duration); } }
If want it to fire after the hand has been in front of the sensor for 5 seconds try this: void loop() { // Get distance delay(1000); int tofdata = sensor.readRangeContinuousMillimeters(); int distance = tofdata / 10; // convert mm to cm // Code for presence detection if (distance <= 20 ) { // Object is close, check if timer is running if (!timerRunning) { // Timer not running. Start timer startTime = millis(); Serial.println("time started, starting count"); timerRunning = 1; } else { // Has 5 seconds passed? uint32_t elapsed_time = millis() - startTime ; if (elapsed_time >= 5000) { // YES. DO SOMETHING HERE // and reset timerRunning = 0; } } } else { // Object is not close. timerRunning = 0; }
(Arduino) Counting with cases
I am working on a stereo controller and have 1 rotary encoder with a push button. When I push the button it cycles through the options and the rotary encoder lets me set the intensity. I want the individual intensities to remain when I am switching back and forth. When I turn the bass to 50% and then set the volume to 80% I want to come back and the base still be at 50%. The problem I am having is that the intensities are transferring over. For prototyping I am using 3 LEDS. I can set individual brightness but when I go to change the next LED it automatically changes to the intensity of the previous LED. The reasoning behind this is that when I set the bass and treble and the volume I don't want the values jumping around when I come back to change something. I want to pick off where it left off. I think the structure I am going for is a counter based on cases. A common variable outside the case is incremented by the rotary encoder and then stored in case if that is possible. /* ** Rotary Encoder Example ** Use the Sparkfun Rotary Encoder to vary brightness of LED ** ** Sample the encoder at 200Hz using the millis() function */ int brightness = 0; // how bright the LED is, start at half brightness int fadeAmount = 30; // how many points to fade the LED by unsigned long currentTime; unsigned long loopTime; const int pin_A = 4; // pin 12 const int pin_B = 5; // pin 11 unsigned char encoder_A; unsigned char encoder_B; unsigned char encoder_A_prev=0; const int green = 11; const int blue = 10; const int red=9; int last_bright=0; int mode = 0; // Selector State (Initial state = ALL OFF) int val = 0; // Pin 13 HIGH/LOW Status int butState = 0; // Last Button State int modeState = 0; int selected=710; int greenvol=0; int redvol=0; int bluevol=0; int select_bright=0; void setup() { // declare pin 9 to be an output: pinMode(9, OUTPUT); pinMode(10, OUTPUT); pinMode(11, OUTPUT); pinMode(pin_A, INPUT); pinMode(pin_B, INPUT); currentTime = millis(); loopTime = currentTime; } void loop() { // get the current elapsed time currentTime = millis(); brightness=select_bright; if(currentTime >= (loopTime + 5)){ // 5ms since last check of encoder = 200Hz encoder_A = digitalRead(pin_A); // Read encoder pins encoder_B = digitalRead(pin_B); if((!encoder_A) && (encoder_A_prev)){ // A has gone from high to low if(encoder_B) { // B is high so clockwise // increase the brightness, dont go over 255 if(brightness + fadeAmount <= 255) brightness += fadeAmount; } else { // B is low so counter-clockwise // decrease the brightness, dont go below 0 if(brightness - fadeAmount >= 0) brightness -= fadeAmount; } } encoder_A_prev = encoder_A; // Store value of A for next time // set the brightness of pin 9: analogWrite(selected, brightness); last_bright=brightness; loopTime = currentTime; // Updates loopTime } // end of rotary encoder val = digitalRead(8); delay(5); // If we see a change in button state, increment mode value if (val != butState && val == HIGH){ mode++; } butState = val; // Keep track of most recent button state // No need to keep setting pins *every* loop if (modeState != mode) // If no keys have been pressed yet don't execute // the switch code below { switch ( mode ) { case 2: selected=red; select_bright=redvol; redvol=last_bright; break; case 3: selected=green; select_bright=greenvol; greenvol = last_bright; break; default: selected=blue; select_bright=bluevol; bluevol = last_bright; mode = 1; break; } } }
I'd store the brightness value in an array and then use an index to change only one led. Here is a (i hope) working example. Try it and see if it fits your needs ;) I made some other changes (you can see them in the comments). Anyway I suggest you to add at least debouncing on the encoder and the button pins the complete encoder checking, i.e. check if either A or B changed, and in both directions. Here is the code; just let me know ;) byte fadeAmount = 30; const byte pin_button = 8; const byte pin_A = 4; // pin 12 const byte pin_B = 5; // pin 11 unsigned long loopTime; unsigned char encoder_A; unsigned char encoder_B; unsigned char encoder_A_prev=0; // Array to store the brightness of the // red (0), green (1) and blue (2) leds byte brightnesses[3]; byte lastbrightnesses[3]; byte currentLed; // Pins for red (0), green (1) and blue (2) leds byte led_pins[] = {9, 10, 11}; void setup() { pinMode(pin_button, INPUT); pinMode(pin_A, INPUT); pinMode(pin_B, INPUT); // set the brightnesses to their initial states // and the lastbrightnesses to ANOTHER value for (currentLed=0; currentLed<3; i++) { pinMode(led_pins[currentLed], OUTPUT); brightnesses[currentLed] = 255; lastbrightnesses[currentLed] = 0; } currentLed = 0; loopTime = millis() - 5; } void loop() { // I prefer this instead of yours // because this is overflow-safe if((millis() - loopTime) >= 5) { loopTime += 5; // Check encoder encoder_A = digitalRead(pin_A); encoder_B = digitalRead(pin_B); if((!encoder_A) && (encoder_A_prev)){ // A has gone from high to low if(encoder_B) { // B is high so clockwise // Again, this is overflow-safe // And it compensates for not reaching the end of the values if(brightnesses[currentLed] <= 255 - fadeAmount) brightnesses[currentLed] += fadeAmount; else brightnesses[currentLed] = 255; } else { // B is low so counter-clockwise // decrease the brightness, dont go below 0 if(brightnesses[currentLed] >= fadeAmount) brightnesses[currentLed] -= fadeAmount; else brightnesses[currentLed] = 0; } } encoder_A_prev = encoder_A; // Store value of A for next time // I'd read the button every 5ms too val = digitalRead(pin_button); if (val != butState && val == HIGH){ currentLed++; if (currentLed >= 3) currentLed = 0; butState = val; } } // Here you can also check only currentLed instead // of every led if you can only change it through // the encoder byte i; for (i=0; i<3; i++) { if (lastbrightnesses[i] != brightnesses[i]) { analogWrite(led_pins[i], brightnesses[i]); lastbrightnesses[i] = brightnesses[i]; } } }
How to know Arduino Sampling Rate
/* fft_adc_serial.pde guest openmusiclabs.com 7.7.14 example sketch for testing the fft library. it takes in data on ADC0 (Analog0) and processes them with the fft. the data is sent out over the serial port at 115.2kb. */ #define LOG_OUT 1 // use the log output function #define FFT_N 256 // set to 256 point fft #include <FFT.h> // include the library unsigned long time; void setup() { Serial.begin(115200); // use the serial port TIMSK0 = 0; // turn off timer0 for lower jitter ADCSRA = 0xe5; // set the adc to free running mode ADMUX = 0x40; // use adc0 DIDR0 = 0x01; // turn off the digital input for adc0 } void loop() { while(1) { // reduces jitter cli(); // UDRE interrupt slows this way down on arduino1.0 for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples while(!(ADCSRA & 0x10)); // wait for adc to be ready ADCSRA = 0xf5; // restart adc byte m = ADCL; // fetch adc data byte j = ADCH; int k = (j << 8) | m; // form into an int k -= 0x0200; // form into a signed int k <<= 6; // form into a 16b signed int fft_input[i] = k; // put real data into even bins Serial.print("input "); Serial.print(i); Seirla.print(" = "); Serial.println(k); fft_input[i+1] = 0; // set odd bins to 0 } fft_window(); // window the data for better frequency response fft_reorder(); // reorder the data before doing the fft fft_run(); // process the data in the fft fft_mag_log(); // take the output of the fft sei(); Serial.println("start"); for (byte i = 0 ; i < FFT_N/2 ; i++) { Serial.print("\t output"); Serial.print(i); Serial.println(fft_log_out[i]); // send out the data } } } Im using this FFT example code for FFT cli(); // UDRE interrupt slows this way down on arduino1.0 for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples while(!(ADCSRA & 0x10)); // wait for adc to be ready ADCSRA = 0xf5; // restart adc byte m = ADCL; // fetch adc data byte j = ADCH; int k = (j << 8) | m; // form into an int k -= 0x0200; // form into a signed int k <<= 6; // form into a 16b signed int fft_input[i] = k; // put real data into even bins Serial.print("input "); Serial.print(i); Seirla.print(" = "); Serial.println(k); fft_input[i+1] = 0; // set odd bins to 0 } in this input part How much input time period? Theres no delay(); function in this example while(!(ADCSRA & 0x10)); // wait for adc to be ready this line work like delay() function? and this function how long wait for Analog0?
The sample rate is set in wiring.c: https://code.google.com/p/arduino/source/browse/trunk/hardware/cores/arduino/wiring.c?r=565#210 So on an 16mHz arduino has a maximum sample rate of at 9600hz, but the real sample rate highly depends on on the delay you have between conversions. As your baud rate is pretty high and you don't do a lot of calculation it should somehow be next to 9600hz. update: there's a more accurate answer here: https://arduino.stackexchange.com/a/701
Arduino calculating the frequency - what am I doing wrong here?
I'm a newbie when it comes to electronics and Arduino - so the best way is to just to play around with it, right? I have started a small project that utilize and LDR (Light Density Resistor) and want to use it to calculate the frequency that a light beam is blocked or turned off. For debugging purposes I setup a small LED that blinks at a defined frequency (5 Hz etc.) and use a LCD to display the output. I have a problem with my top right corner... It seems as it performs wrongly. It was the intention that it should show the registered frequency, but while debugging I have set it to show the number of counts in an interval of 5 sec (5,000 msec). But it appears as 24 is the max no matter what frequency I set (When I get it to show the right number [5 sec x 5 Hz = 25] I will divide by the time interval and get the results in Hz). It also shows 24.0 for 9 Hz etc.. I also have this: YouTube video ...but some fumbling in the beginning caused the LED to move a bit so it counted wrong. But in the end it "works".. But the 24.0 keeps being constant This is my code: #include <LiquidCrystal.h> LiquidCrystal lcd(7, 8, 9, 10, 11 , 12); int booBlocked = 0; int counter = 0; int checkValue = counter + 1; int ledPin = 3; // LED connected to digital pin 3 int value = LOW; // previous value of the LED long previousMillis = 0; // will store last time LED was updated long freqency = 5; // Hz (1/sec) long thousand = 1000; long interval = thousand / freqency; // milliseconds //long interval = 59; // interval at which to blink (milliseconds) int tValue = 0; // Threshold value used for counting (are calibrated in the beginning) long pMillis = 0; long inter = 5000; int pCount = 0; float freq = 0; // Calculated blink frequency... void setup() { lcd.begin(16, 2); lcd.setCursor(0,1); lcd.print(interval); lcd.setCursor(4,1); lcd.print("ms"); pinMode(ledPin, OUTPUT); // sets the digital pin as output lcd.setCursor(0,0); lcd.print(freqency); lcd.setCursor(4,0); lcd.print("Hz"); } void loop() { // Print LDR sensor value to the display int sensorValue = analogRead(A0); lcd.setCursor(7,1); lcd.print(sensorValue); delay(100); if (millis() > 5000){ doCount(sensorValue); updateFreq(); lcd.setCursor(7+5,0); lcd.print(freq); } else { setThresholdValue(sensorValue); lcd.setCursor(7+5,1); lcd.print(tValue); } // LED BLINK if (millis() - previousMillis > interval) { previousMillis = millis(); // remember the last time we blinked the LED // if the LED is off turn it on and vice-versa. if (value == LOW) value = HIGH; else value = LOW; digitalWrite(ledPin, value); } } void updateFreq(){ long now = millis(); long t = now - pMillis; if (t >= 10000) { freq = (float) (counter - pCount); //freq = ((float) (counter - pCount)) / (float) 10.0; pMillis = now; // remember the last time we blinked the LED pCount = counter; } } void setThresholdValue(int sensorValue){ if (sensorValue > int(tValue/0.90)){ tValue = int (sensorValue*0.90); } } void doCount(int sensorValue){ // Count stuff if (sensorValue < tValue){ booBlocked = 1; //lcd.setCursor(0,0); //lcd.print("Blocked"); } else { booBlocked = 0; //lcd.setCursor(0,0); //lcd.print(" "); } if (booBlocked == 1) { if (counter != checkValue){ counter = counter + 1; lcd.setCursor(7,0); lcd.print(counter); } } else { if (counter == checkValue){ checkValue = checkValue + 1; } } } UPDATE A more "clean" code (please see my own answer) #include <LiquidCrystal.h> // Initiate the LCD display LiquidCrystal lcd(7, 8, 9, 10, 11 , 12); // see setup at http://lassenorfeldt.weebly.com/1/post/2013/02/ardunio-lcd.html long updateInterval = 150; // ms long updateTime = 0; // Declare the pins int ledPin = 3; // LED connected to digital pin 3 // LED setup int value = LOW; // previous value of the LED long previousMillis = 0; // will store last time LED was updated long freqency = 16; // Hz (1/sec) long thousand = 1000; long blinkInterval = thousand / freqency; // milliseconds //// LDR counter variables //// // Counting vars static int counter = 0; int booBlocked = 0; int checkValue = counter + 1; // Calibration vars long onBootCalibrationTime = 5000; // time [time] to use for calibration when the system is booted static int threshold = 0; // Value used for counting (calibrated in the beginning) float cutValue = 0.90; // Procent value used to allow jitting in the max signal without counting. // Frequency vars float freq = 0; // Calculated blink frequency... long frequencyInterval = 5000; // time [ms] long pMillis = 0; int pCount = 0; void setup() { // Setup the pins pinMode(ledPin, OUTPUT); // sets the digital pin as output // display static values lcd.begin(16, 2); lcd.setCursor(0,0); lcd.print(freqency); lcd.setCursor(4,0); lcd.print("Hz"); lcd.setCursor(0,1); lcd.print(blinkInterval); lcd.setCursor(4,1); lcd.print("ms"); // Setup that allows loggin Serial.begin(9600); // Allows to get a readout from Putty (windows 7) } void loop() { long time = millis(); int sensorValue = analogRead(A0); // Blink the LED blinkLED(time); // Calibrate or Count (AND calculate the frequency) via the LDR if (time < onBootCalibrationTime){ setThresholdValue(sensorValue); } else { doCount(sensorValue); updateFreq(time); } // Update the LCD if (time > updateTime){ updateTime += updateInterval; // set the next time to update the LCD // Display the sensor value lcd.setCursor(7,1); lcd.print(sensorValue); // Display the threshold value used to determined if blocked or not lcd.setCursor(7+5,1); lcd.print(threshold); // Display the count lcd.setCursor(7,0); lcd.print(counter); // Display the calculated frequency lcd.setCursor(7+5,0); lcd.print(freq); } } void blinkLED(long t){ if (t - previousMillis > blinkInterval) { previousMillis = t; // remember the last time we blinked the LED // if the LED is off turn it on and vice-versa. if (value == LOW) value = HIGH; else value = LOW; digitalWrite(ledPin, value); } } void setThresholdValue(int sValue){ if (sValue > int(threshold/cutValue)){ threshold = int (sValue*cutValue); } } void doCount(int sValue){ if (sValue < threshold){ booBlocked = 1; } else { booBlocked = 0; } if (booBlocked == 1) { if (counter != checkValue){ counter = counter + 1; } } else { if (counter == checkValue){ checkValue = checkValue + 1; } } } void updateFreq(long t){ long inter = t - pMillis; if (inter >= frequencyInterval) { freq = (counter - pCount) / (float) (inter/1000); pMillis = t; // remember the last time we blinked the LED pCount = counter; } } This code does not fix my question, but is just more easy to read.
The issue with your plan is that a light density resistor is going to pick up all the ambient light around and therefore be completely environment sensitive. Have any other project hopes? This one seems like an engineering learning experience, not a coding one. Have you thought of motor projects? Personally I'm more into home automation, but motor projects are almost instantly rewarding.
I'd recommend to re-write your doCount() function along these lines to make things simpler and easier to grasp: void doCount(int sensorValue){ static int previousState; int currentState; if ( previousState == 0 ) { currentState = sensorValue > upperThreshold; } else { currentState = sensorValue > lowerThreshold; } if ( previousState != 0 ) { if ( currentState == 0 ) { counter++; } } previousState = currentState; } Let lowerThreshold and upperThreshold be, for example, 90% and 110%, respectively, of your former tValue, and you have a hysteresis to smoothen the reaction to noisy ADC read-outs.
I think i found one of the bugs.. I was using a delay() which caused some trouble.. I cleaned up the code: #include <LiquidCrystal.h> // Initiate the LCD display LiquidCrystal lcd(7, 8, 9, 10, 11 , 12); // see setup at http://lassenorfeldt.weebly.com/1/post/2013/02/ardunio-lcd.html long updateInterval = 150; // ms long updateTime = 0; // Declare the pins int ledPin = 3; // LED connected to digital pin 3 // LED setup int value = LOW; // previous value of the LED long previousMillis = 0; // will store last time LED was updated long freqency = 16; // Hz (1/sec) long thousand = 1000; long blinkInterval = thousand / freqency; // milliseconds //// LDR counter variables //// // Counting vars static int counter = 0; int booBlocked = 0; int checkValue = counter + 1; // Calibration vars long onBootCalibrationTime = 5000; // time [time] to use for calibration when the system is booted static int threshold = 0; // Value used for counting (calibrated in the beginning) float cutValue = 0.90; // Procent value used to allow jitting in the max signal without counting. // Frequency vars float freq = 0; // Calculated blink frequency... long frequencyInterval = 5000; // time [ms] long pMillis = 0; int pCount = 0; void setup() { // Setup the pins pinMode(ledPin, OUTPUT); // sets the digital pin as output // display static values lcd.begin(16, 2); lcd.setCursor(0,0); lcd.print(freqency); lcd.setCursor(4,0); lcd.print("Hz"); lcd.setCursor(0,1); lcd.print(blinkInterval); lcd.setCursor(4,1); lcd.print("ms"); // Setup that allows loggin Serial.begin(9600); // Allows to get a readout from Putty (windows 7) } void loop() { long time = millis(); int sensorValue = analogRead(A0); // Blink the LED blinkLED(time); // Calibrate or Count (AND calculate the frequency) via the LDR if (time < onBootCalibrationTime){ setThresholdValue(sensorValue); } else { doCount(sensorValue); updateFreq(time); } // Update the LCD if (time > updateTime){ updateTime += updateInterval; // set the next time to update the LCD // Display the sensor value lcd.setCursor(7,1); lcd.print(sensorValue); // Display the threshold value used to determined if blocked or not lcd.setCursor(7+5,1); lcd.print(threshold); // Display the count lcd.setCursor(7,0); lcd.print(counter); // Display the calculated frequency lcd.setCursor(7+5,0); lcd.print(freq); } } void blinkLED(long t){ if (t - previousMillis > blinkInterval) { previousMillis = t; // remember the last time we blinked the LED // if the LED is off turn it on and vice-versa. if (value == LOW) value = HIGH; else value = LOW; digitalWrite(ledPin, value); } } void setThresholdValue(int sValue){ if (sValue > int(threshold/cutValue)){ threshold = int (sValue*cutValue); } } void doCount(int sValue){ if (sValue < threshold){ booBlocked = 1; } else { booBlocked = 0; } if (booBlocked == 1) { if (counter != checkValue){ counter = counter + 1; } } else { if (counter == checkValue){ checkValue = checkValue + 1; } } } void updateFreq(long t){ long inter = t - pMillis; if (inter >= frequencyInterval) { freq = (counter - pCount) / (float) (inter/1000); pMillis = t; // remember the last time we blinked the LED pCount = counter; } } Its not as precise as I wished.. but I believe that this is might due to the way I blink the LED. I also discovered that float cutValue = 0.90; has an influence... lowering the bar to 0.85 decrease the calculated frequency.. ??
I changed the code completely after Albert was so kind to help me out using his awesome FreqPeriodCounter library I also added a potentiometer to control the frequency Here is my code: #include <FreqPeriodCounter.h> #include <LiquidCrystal.h> // FrequencyCounter vars const byte counterPin = 3; // Pin connected to the LDR const byte counterInterrupt = 1; // = pin 3 FreqPeriodCounter counter(counterPin, micros, 0); // LCD vars LiquidCrystal lcd(7, 8, 9, 10, 11 , 12); // see setup at http://lassenorfeldt.weebly.com/1/post/2013/02/ardunio-lcd.html long updateInterval = 200; // ms long updateTime = 0; // LED vars int ledPin = 5; // LED connected to digital pin 3 int value = LOW; // previous value of the LED float previousMillis = 0; // will store last time LED was updated static float freqency; // Hz (1/sec) static float pfreqency; static float blinkInterval; // milliseconds boolean logging = true; // Logging by sending to serial // Use potentiometer to control LED frequency int potPin = 5; // select the input pin for the potentiometer int val = 0; // variable to store the value coming from the sensor void setup(void){ // Setup the pins pinMode(ledPin, OUTPUT); // sets the digital pin as output val = analogRead(potPin); freqency = map(val, 0, 1023, 0, 25); // Hz (1/sec) pfreqency = freqency; blinkInterval = 1000 / (freqency*2); // milliseconds // LCD display static values lcd.begin(16, 2); lcd.setCursor(0,0); lcd.print(freqency); lcd.setCursor(4,0); lcd.print("Hz"); lcd.setCursor(14,0); lcd.print("Hz"); lcd.setCursor(0,1); lcd.print(blinkInterval); lcd.setCursor(4,1); lcd.print("ms"); // attachInterrupt(counterInterrupt, counterISR, CHANGE); // Logging if (logging) {Serial.begin(9600);} } void loop(void){ // Loop vars float time = (float) millis(); float freq = (float) counter.hertz(10)/10.0; // Blink the LED blinkLED(time); if (logging) { if(counter.ready()) Serial.println(counter.hertz(100)); } // Update the LCD if (time > updateTime){ updateTime += updateInterval; // set the next time to update the LCD lcdNicePrint(7+3, 0, freq); lcd.setCursor(14,0); lcd.print("Hz"); val = analogRead(potPin); freqency = map(val, 0, 1023, 1, 30); if (freqency != pfreqency){ pfreqency = freqency; blinkInterval = 1000 / (freqency*2); // milliseconds lcdNicePrint(0,0, freqency); lcd.setCursor(4,0); lcd.print("Hz"); lcd.setCursor(0,1); lcd.print(blinkInterval); lcd.setCursor(4,1); lcd.print("ms"); } } } void lcdNicePrint(int column, int row, float value){ lcd.setCursor(column, row); lcd.print("00"); if (value < 10) {lcd.setCursor(column+1, row); lcd.print(value);} else {lcd.setCursor(column, row); lcd.print(value);} } void blinkLED(long t){ if (t - previousMillis > blinkInterval) { previousMillis = t; // remember the last time we blinked the LED // if the LED is off turn it on and vice-versa. if (value == LOW) value = HIGH; else value = LOW; digitalWrite(ledPin, value); } } void counterISR() { counter.poll(); }