Go Down

Topic: Creating Square Waves with Programmable Frequencies? (Read 1 time) previous topic - next topic

PeterH

The tone library seems like the easiest way to produce a variable frequency square wave.
I only provide help via the forum - please do not contact me for private consultancy.

GoForSmoke

To generate a 300 Hz wave you need to switch LOW to HIGH to LOW etc 600 times a second, once every 1,666 usec. 5 Hz, every 100,000 usec.

pseudocode:
loop()
{
  now = micros();
  if ( now - lastTime >= halfCycle )
  {
     // change the pin 
      lastTime=now;
  }
  // any other code like watching for serial available or sensor data goes here
}

Learn BlinkWithoutDelay to learn to switch things on and off at proper times together. You want to generate frequency and monitor it at the same time, the basics are in BlinkWithoutDelay.

But for your use, change millis() timing to micros(). Accuracy will be 4 usec but how much does that matter when the interval is well over 1000?

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

ArduinoTom

Ok, using that logic from BlinkWithoutDelay, how about coding it like this?  Based on the math posted above, it would seem that the procesor is plenty fast enough to handle an interrupt 300 times per second while still executing the loop code, right? 

Code: [Select]


const int trimPot = A0;            //voltage divider to adjust speedometer output
const int speedPin =  21;          //pin for new pulse going to speedometer
int pulseState = LOW;             //newPulseState used to set the pulse
unsigned long currentMicros = 0;   //to measure new pulse   
unsigned long previousMicros= 0;   //to measure new pulse 
unsigned long currentSpeed = 0;    //to measure incoming pulse
unsigned long previousSpeed = 0;   //to measure incoming pulse
unsigned long interval = 0;        //calculated new pulse length

void setup()
{
pinMode(speedPin, OUTPUT);   
attachInterrupt (3, iSr, CHANGE);
}

void loop()
{
   currentMicros = micros();  //get the current micros count
   if(currentMicros - previousMicros > interval) //check to see if it's time to change
    {
    previousMicros = currentMicros;   //keep track of the last time pulse changed
    if (pulseState == LOW) pulseState = HIGH; else pulseState = LOW;
    digitalWrite(speedPin, pulseState);  //flip the state of the new sqaure wave
    }
}

void iSr()
{
  currentSpeed=micros();
  interval=(currentSpeed-previousSpeed)*(analogRead(trimPot)/512); 
  previousSpeed=currentSpeed;
}


GoForSmoke

You need to make variables accessed by the ISR volatile, as in volatile unsigned long currentMicros.

A 104 usec analog read in an ISR? Oh no. Interrupts are off inside an ISR.

How about set a flag in the ISR that tells your regular code it's time to cook the interval?

if(currentMicros - previousMicros >= interval)

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

ArduinoTom

Appreciate your help.  How about like this:

Code: [Select]

const int trimPot = A0;            //voltage divider to adjust speedometer output
const int speedPin = 21;          //pin for new speed pulse train
int pulseState = LOW;             // state used to set the pulse
volatile unsigned long currentMicros = 0;   //to measure new pulse   
volatile unsigned long previousMicros= 0;   //to mark prior pulse 
unsigned long currentSpeed = 0;    //to measure incoming pulse
unsigned long previousSpeed = 0;   //to mark prior pulse
unsigned long interval = 1;        //original pulse length
float adjustPercent = 1; //adjustment to original pulse length

void setup()
{
pinMode(speedPin, OUTPUT);   
pinMode(13, OUTPUT);
attachInterrupt (3, iSr, CHANGE);
}

void loop()
{
   currentMicros = micros();  //get the current micros count
   adjustPercent = (analogRead(trimPot)/512);
   interval=interval*adjustPercent;
   if(currentMicros - previousMicros > interval) //check to see if it's time to change
    {
    previousMicros = currentMicros;   //keep track of the last time pulse changed
    if (pulseState == LOW) pulseState = HIGH; else pulseState = LOW;
    digitalWrite(13, pulseState); //show pulse train on built in LED
    digitalWrite(speedPin, pulseState);  //flip the state of the new sqaure wave
    }
}

void iSr()
{
  currentSpeed=micros();
  interval=(currentSpeed-previousSpeed);  //how long since last change
  previousSpeed=currentSpeed;
}


Go Up