Pages: [1]   Go Down
Author Topic: Creating specific PWM routine with POT adjustments and no delay()  (Read 908 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 24
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm needing to create a PWM routine with a variable frequency and variable pulsewidth, controlled through two POTs.

The frequency should be adjustable, from 1-200 Hz
The pulsewidth should be adjustable, from 100-300 uS

It seemed pretty simple but I'm no programmer and basically pieced this together from code snippets I've found so I'm thinking there is a simpler, better way of doing this?  Also since I'm counting microseconds in a 'long' I'm not sure what will happen when this variable overflows?

I tried it with a simple delayMicroseconds() at first and ran into timing issues trying to read the pots AND keep the pulse going steady.

Anyway here's my code:

Code:
// constants won't change. Used here to set pin numbers:
const int frequencyPin = A0;    // pin that the frequency sensor is attached to
const int pulsewidthPin = A5;    // pin that the pulse-width sensor is attached to
const int outputPin = 9;        // pin that the LED is attached to

// Variables will change:
long previousMicros = 0;        // will store last time LED was updated
long period = 0;           // period at which to blink (microseconds)

int frequencyValue = 0;         // the frequency value
int frequencyMin = 1023;        // minimum frequency value
int frequencyMax = 0;           // maximum frequency value

int pulsewidthValue = 0;         // the pulsewidth value
int pulsewidthMin = 1023;        // minimum pulsewidth value
int pulsewidthMax = 0;           // maximum pulsewidth value


void setup() {
  // set the digital pin as output:
  pinMode(outputPin, OUTPUT);

  // turn on LED to signal the start of the calibration period:
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);

  // calibrate during the first five seconds
  while (millis() < 5000) {
    frequencyValue = analogRead(frequencyPin);
    pulsewidthValue = analogRead(pulsewidthPin);

    // record the maximum frequency value
    if (frequencyValue > frequencyMax) {
      frequencyMax = frequencyValue;
    }

    // record the minimum frequency value
    if (frequencyValue < frequencyMin) {
      frequencyMin = frequencyValue;
    }
   
    // record the maximum pulsewidth value
    if (pulsewidthValue > pulsewidthMax) {
      pulsewidthMax = pulsewidthValue;
    }

    // record the minimum pulsewidth value
    if (pulsewidthValue < pulsewidthMin) {
      pulsewidthMin = pulsewidthValue;
    } 
}
}

void loop() {
  // read the sensor:
  frequencyValue = analogRead(frequencyPin);
  pulsewidthValue = analogRead(pulsewidthPin);

  // apply the calibration to the frequency reading
  frequencyValue = map(frequencyValue, frequencyMin, frequencyMax, 1, 200);

  // in case the frequency value is outside the range seen during calibration
  frequencyValue = constrain(frequencyValue, 1, 200);

  // apply the calibration to the pulsewidth reading
  pulsewidthValue = map(pulsewidthValue, pulsewidthMin, pulsewidthMax, 100, 300);

  // in case the pulsewidth value is outside the range seen during calibration
  pulsewidthValue = constrain(pulsewidthValue, 100, 300);


  // check to see if it's time to blink the LED; that is, if the
  // difference between the current time and last time you blinked
  // the LED is bigger than the interval at which you want to
  // blink the LED.
 
  unsigned long currentMicros = micros();  // this will hold the current time
  period = 1000000/frequencyValue;  // calculate the time between on-pulses
 
  if(currentMicros - previousMicros > period) {
    // save the last time you blinked the LED
    previousMicros = currentMicros;   

    digitalWrite(outputPin, HIGH);
    delayMicroseconds(pulsewidthValue);
    digitalWrite(outputPin, LOW);
  }
}
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 178
Posts: 12288
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
The frequency should be adjustable, from 1-200 Hz

In increments of?

Quote
The pulsewidth should be adjustable, from 100-300 uS

In increments of?

How much problem will it cause If the pulses are occasionally wrong (not the correct frequency or not the correct width)?

What else do you plan your Arduino to be doing?
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 24
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The exact number of increments in either field doesn't concern me too greatly, the more the better of course but steps of 10-20Hz for the frequency and maybe 25 uS steps on the pulsewidth would be fine.

I'm occasionally getting some wrong pulses as it is with my code, part of the reason I'm looking for an alternative.  Incorrect pulse width would be my primary concern.  If the wrong pulses are missed pulses that's OK.  However I never want a pulse greater than 300 uS.  Incorrect frequency shouldn't be as big of a concern.

Additionally the arduino will be outputting the frequency and pulsewidth information to an LCD readout.

Thank you!
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 178
Posts: 12288
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Processor / board?
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 180
Posts: 8108
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I came across a library called Timer1 that makes it easy to set the frequency and duty cycle of one of the hardware timers.  Perhaps the source for that would help with frequency and pulsewidth.  Or maybe the timer could control the frequency and generate an interrupt and the interrupt routine could do the pulse width in software.
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

0
Offline Offline
Newbie
*
Karma: 0
Posts: 24
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That Timer1 library sounds like it could be very useful, if you can find the link I'd be very grateful.

And I'm running an arduino duemilanove with the 328 uC.
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 180
Posts: 8108
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If you click on the "Playground" link above and type Timer1 into the search box the first result is:

http://www.arduino.cc/playground/Code/Timer1
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

0
Offline Offline
Newbie
*
Karma: 0
Posts: 24
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks johnwasser, this works great.


I did notice however I no longer have direct control over the pulse width as its own entity, but rather as a fraction of the period, in a 10-bit range. (0-1023)

I would agree this is probably the best way to do normal PWM tasks but in my case I need to maintain a specific pulse width regardless of a changing frequency.

I'm having a tough time wrapping my head around the math equation required to create a 100-300 uS pulse for any given period (or frequency) and expressed as a number 0-1023.


I'm sure I'll think of it within a few days but my brain is NOT wired for programming...
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 178
Posts: 12288
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


How do you feel about specifying the pulse period rather than the pulse frequency?
Logged

Pages: [1]   Go Up
Jump to: