IT ALL FALLS APART

THE ‘PulseIn’ PROBLEM

It was here I ran into an issue that derailed the entire project. Simply put, I was using the ‘pulseIn’ function to read the low and high peaks of my oscilator and used the time between them to calculate the frequency (pitch). This would allow me to control my LED strip with the pitch of my synth, with different colors/speeds for when it played a bass or lead part.

As shown in the video, ‘pulseIn’ writes to the serial port each time its triggered, blocking the rest of the actions in the loop. This mean all other data is only sent when the pulse is recived. At lower frequencies this becomes unusable.

After some research I found many people have had this same issue. For some it was solved with interrupts, forcing the other data though between pulse readings. After many attempts and hours spent trying to get the interrupts in place I simply couldn’t make it work. The issue is that the interrupts require their own clock, and I could not make this accurate / fast enough to update between each wave cycle.

On top of this I had already had problems with interrupts causing issues when using the FastLED library and the midi output together so had to disable them.

The code showing where I was at before this change is below.

I had to rethink this whole element of my project.




//include OSC read library
#include <Wire.h>

// Include NewPing Library
#include "NewPing.h"

//include LED library
#define FASTLED_ALLOW_INTERRUPTS 0
#include <FastLED.h>


//DISTANCE SENSOR SETUP
//---------------------------------------------------------------------------------
//set sonar pins
#define TRIGGER_PIN1  3
#define ECHO_PIN1     2
#define TRIGGER_PIN2  5
#define ECHO_PIN2     4

//set max distance to avoid crossing the streams
// Maximum Distance is 400 cm
#define MAX_DISTANCE 30

//setup library for distance sensors 
NewPing sonar1(TRIGGER_PIN1, ECHO_PIN1, MAX_DISTANCE);

NewPing sonar2(TRIGGER_PIN2, ECHO_PIN2, MAX_DISTANCE);



//declare vars for distance sensor
int duration1, distance1;
int duration2, distance2;

int tempVal = 127;

//number of samples per ms for sonars (ABOVE 1 WILL EFFECT LED PUSLE SMOOTHNESS ON LEONARDO BOARD
int iterations = 1;

int pitchOut1;
int pitchOut2;
//---------------------------------------------------------------------------------

//OSC READ SETUP
//---------------------------------------------------------------------------------
int OSC4speed;
int OSC4colour;

int pulsePin = 7; // Input signal connected to Pin 12 of Arduino

int pulseHigh; // Integer variable to capture High time of the incoming pulse

int pulseLow; // Integer variable to capture Low time of the incoming pulse

float pulseTotal; // Float variable to capture Total time of the incoming pulse

float frequency; // Calculated Frequency
//---------------------------------------------------------------------------------
//LED SETUP
//---------------------------------------------------------------------------------

#define NUM_STRIPS 2



//LFO LED:
//--------------
// How many leds in each strip
#define NUM_LEDS1 8

// LFO LEDs output pin
#define DATA_PIN1 10

// Define the array of leds
CRGB leds1[NUM_LEDS1];

//var for LFO
int LFO;
//--------------

//OSC LED:
//--------------
#define NUM_LEDS2 8

CRGB leds2[NUM_LEDS2];

#define PIN 6
//---------------

CLEDController *controllers[NUM_STRIPS];
//uint8_t gBrightness1 = LFO;
uint8_t gBrightness2 = 64;


//MIDI SETUP
//---------------------------------------------------------------------------------
//declare vars for MIDI CCs
int val = 0; //initial pot values. need one for the first value and a second to test if there has been a change made. This needs to be done for all 3 pots.
int lastVal = 0;
int val2 = 0;
int lastVal2 = 0;
//---------------------------------------------------------------------------------



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

  

  pinMode(pulsePin, INPUT);
   
  //attachInterrupt(digitalPinToInterrupt(pulsePin), blink, RISING);

  //fastLED setup/pin set (LFO)
   controllers[0] = &FastLED.addLeds<NEOPIXEL, DATA_PIN1>(leds1, NUM_LEDS1);  // GRB ordering is assumed

   //fast LED setup/pin set (OSC)
    controllers[1] = &FastLED.addLeds<WS2811, PIN, GRB>(leds2, NUM_LEDS2).setCorrection( TypicalLEDStrip );
}

void loop() {


//Serial.println(LFO);

//SONAR READ LOOP
//---------------------------------------------------------------------------------
   //fire pulses from distance sensors
  duration1 = sonar1.ping_median(iterations);
  duration2 = sonar2.ping_median(iterations);
  
  // Determine distance from duration
  // Use 343 metres per second as speed of sound
  
  distance1 = (duration1 / 2) * 0.0343;
  distance2 = (duration2 / 2) * 0.0343;
  
  // Send results to Serial Monitor
  //Serial.print("Distance = ");


  //set limits and create sonar reading
  if (distance1 >= 30 || distance1 <= 0) {
    pitchOut1 = 30;
  }
  else {
    pitchOut1 = distance1;
   // delay(10);
  }
  //delay(10);

    if (distance2 >= 30 || distance2 <= 0) {
    pitchOut2 = 30;
  }
  else {
    pitchOut2 = distance2;
    //delay(10);
  }
  //delay(10);
//---------------------------------------------------------------------------------

//MIDI WRITE LOOP
//---------------------------------------------------------------------------------
//map sonar reading to midi scaling
     pitchOut1 = map(distance1, 30, 0 , 0, 127);
     pitchOut2 = map(distance2, 30, 0 , 0, 127);

//MIDI message conversion     
   val = pitchOut1;   // Divide by 8 to get range of 0-127 for midi
   if (val != lastVal) // If the value does not = the last value the following command is made.
   {
   MIDImessage(176,1,val);}         // 176 = CC command (channel 1 control change), 
   lastVal = val;

   val2 = pitchOut2;   // Divide by 8 to get range of 0-127 for midi
   if (val2 != lastVal2) 
   {
   MIDImessage(176,2,val2);}         // 176 = CC command, 2 = Which Control, val = value read from Potentionmeter 2
   lastVal2 = val2;
   
//delay(5); //short delay to help prevent slight fluctuations
//---------------------------------------------------------------------------------

//LFO READ, LED SEND
//---------------------------------------------------------------------------------
  //Readings and output for LFO LEDS.

  int sensorValue = analogRead(A0); // read the input on analog pin 0:
  
  int voltage1 = sensorValue;// Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  
  //Serial.println(voltage1); // print out the value:
  
  LFO = map(voltage1, 0, 800, 0, 255); //scale LFO volt readings to LED peramiters

  //control LED pulses / colours for LFO
  for(int i = 0; i < NUM_LEDS1; (i++)) {
    
    leds1[i] = CRGB::Blue;
    controllers[0]->showLeds(LFO);
}
//---------------------------------------------------------------------------------

//OSC READ + LED VAR WRITE
//---------------------------------------------------------------------------------

pulseHigh = pulseIn(pulsePin, HIGH);

pulseLow = pulseIn(pulsePin, LOW);

pulseTotal = pulseHigh + pulseLow; // Time period of the pulse in microseconds

frequency = 1000000 / pulseTotal; // Frequency in Hertz (Hz)


//Serial.println(pulseTotal);

//delay(1);



    // read the input on analog pin 0:
  
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  //float voltage = OscValue;
  // print out the value you read:
  int OscValue = frequency;
 if (OscValue > 30 && OscValue < 3000) {
  OSC4speed = map(OscValue, 30, 3000, 20, 1);
  OSC4colour = map(OscValue, 30, 3000, 0, 255);
}
   Serial.println(OscValue);
  
  



    //call / control OSC LED effect
    CylonBounce(0xff, 0, OSC4colour, 1, OSC4speed, 10);
//---------------------------------------------------------------------------------
 }

//MIDI WRITE/SEND
void MIDImessage(byte command, byte data1, byte data2) //pass values out through standard Midi Command
{
   Serial.write(command);
   Serial.write(data1);
   Serial.write(data2);
   
}

//LED STUFF
void CylonBounce(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay){

  for(int i = 0; i < NUM_LEDS2-EyeSize-2; i++) {
    setAll(0,0,0);
    setPixel(i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue);
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10);
    showStrip();
    delay(SpeedDelay);
  }

  delay(ReturnDelay);

  for(int i = NUM_LEDS2-EyeSize-2; i > 0; i--) {
    setAll(0,0,0);
    setPixel(i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue);
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10);
    showStrip();
    delay(SpeedDelay);
  }
 
  delay(ReturnDelay);
}

void showStrip() {

 #ifndef ADAFRUIT_NEOPIXEL_H
   // FastLED
 controllers[1]->showLeds(gBrightness2);
   
 #endif
}

void setPixel(int Pixel, byte red, byte green, byte blue) {

 #ifndef ADAFRUIT_NEOPIXEL_H
   // FastLED
   leds2[Pixel].r = red;
   leds2[Pixel].g = green;
   leds2[Pixel].b = blue;
 #endif
}

void setAll(byte red, byte green, byte blue) {
  for(int i = 0; i < NUM_LEDS2; i++ ) {
    setPixel(i, red, green, blue);
  }
  showStrip();
}

Leave a comment

Your email address will not be published. Required fields are marked *