Go Down

Topic: Need a low frequency (can preset at each value of 15Hz to 25Hz) PWM signal (Read 1 time) previous topic - next topic

Andrew_S_C

Thanks for looking at this. I have now gone to the other extreme - defined every variable possible so it does compile but does not produce the PWM output signal. Also think there is at least one } too many though only compiles with all of these in it. Anything you spot would be welcome...


sketch code:
//Purpose: To produce a PWM signal output at 20Hz frequency and a duty cycle that has a minm of 15% and max'm of 85%, the pot adjusted for any value in bewtween
// Arduino UNO board design: Has an input pot resistance value from pot wiper into pin A0 (pot has VCC from 5v pin and Ov from Grd pin). PWM signal ouput defined on pin 9
// Testing: currently using oscillosocpe on output pin 9, unloaded.
// Previous code worked at 30.5Hz, successfully varying LED brightness but frequency was too high for motor controller to work and turn the motor.
// STATUS: DOES COMPILE SUCCESSFULLY BUT NO PWM OUTPUT SIGNAL NOW PRODUCED ON PIN 9.

const int potPin = A0;    // Analog input pin that has the potentiometer wiper resistance value
const int outPin = 9;     // PWM output pin that Motor Controller) (or LED in testing) is attached to

unsigned long dutyCycle;  // Defines the duty cycle, the % of the period (the cycle time) the PWM pulse is high
unsigned long period;     // Defines the cycle time ( 1 / frequency) for PWM output
unsigned long lastChange; // The variable for incrementing the time through the loop

unsigned long signal;     // The variable holding the value of Hi or Lo output that is derived through the loop

void setup() {

unsigned int period = 50;            // 50 ms period, to be used to set the output signal at 20Hz frequency
unsigned long lastChange = 0;        // Not sure why need lastchange defined in code above with this here - but does not compile without it!
float dutyCycle; // 20% duty cycle.  // Again, Not sure why need dutyCycle defined in code above with this here  - but does not compile without it!
bool signal = LOW;
 }
void loop() {
 
  dutyCycle = map(analogRead(potPin), 0, 1023, 1500, 8500) / 10000.0; // returns 15% to 85% duty cycle range based on pot rotation reading 0-1023.
  unsigned int onTime = period * dutyCycle;                           // defines the high duration in mS
  unsigned int offTime = period * (1 - dutyCycle);                    // defines the low duration in mS
 
  if (signal == HIGH) {
    if (millis() - lastChange > onTime) {
      signal = LOW;
      lastChange += onTime;
    }
  else {
    if (millis() - lastChange > offTime) {
      signal = HIGH;
      lastChange += offTime;
    }
  }
  digitalWrite(outPin, signal);
  }
}

Thanks again for reviewing this.

wvmarle

This compiles just fine for me:
Code: [Select]

// Purpose: To produce a PWM signal output at 20Hz frequency and a duty cycle that has a minm of 15 % and max'm of 85%, the pot adjusted for any value in bewtween
// Arduino UNO board design: Has an input pot resistance value from pot wiper into pin A0 (pot has VCC from 5v pin and Ov from Grd pin). PWM signal ouput defined on pin 9
// Testing: currently using oscillosocpe on output pin 9, unloaded.
// Previous code worked at 30.5Hz, successfully varying LED brightness but frequency was too high for motor controller to work and turn the motor.
// STATUS: DOES COMPILE SUCCESSFULLY BUT NO PWM OUTPUT SIGNAL NOW PRODUCED ON PIN 9.

const byte potPin = A0;   // Analog input pin that has the potentiometer wiper resistance value
const byte outPin = 9;    // PWM output pin that Motor Controller) (or LED in testing) is attached to

float dutyCycle;          // Defines the duty cycle, the % of the period (the cycle time) the PWM pulse is high
unsigned long period;     // Defines the cycle time ( 1 / frequency) for PWM output
unsigned long lastChange; // The variable for incrementing the time through the loop
byte outState = LOW;      // The variable holding the value of Hi or Lo output that is derived through the loop

void setup() {
  period = 50000;         // 50,000 us period, to be used to set the output signal at 20Hz frequency.
}
void loop() {

  dutyCycle = map(analogRead(potPin), 0, 1023, 1500, 8500) / 10000.0; // returns 15% to 85% duty cycle range based on pot rotation reading 0-1023.
  unsigned long onTime = period * dutyCycle;                          // defines the high duration in us.
  unsigned long offTime = period * (1 - dutyCycle);                   // defines the low duration in us.

  if (outState == HIGH) {
    if (micros() - lastChange > onTime) {
      outState = LOW;
      lastChange += onTime;
    }
    else {
      if (micros() - lastChange > offTime) {
        outState = HIGH;
        lastChange += offTime;
      }
    }
    digitalWrite(outPin, outState);
  }
}

Fixed various types in the process, and changed millis() to micros() for better resolution of your duty cycle. You have only 50 ms, so a 1 ms resolution is a bit crude. I also changed the name of signal to something that's not red coloured (I've bad experience with such red coloured names so simply avoid them).
Quality of answers is related to the quality of questions. Good questions will get good answers. Useless answers are a sign of a poor question.

Andrew_S_C

Thanks for going through the code and making the mods.

Alas, I've loaded it up and it has the same problem as the version I last added to the forum - it does compile fine BUT there is absolutely no signal output on pin 9 (as per my previous forum entry and in the sketch headlines on STATUS).

To check that my Arduino circuit wiring has not gone awry, I re-loaded the code I wrote for 30.5Hz. It worked fine - oscilloscope shows ~30Hz signal and able to change the duty cycle in range 15% to 85% by adjusting the pot. LED changes brightness as I change the pot.

So, this new version with a lower frequency may compile but there is still something not right with the  code. I've looked through your latest version and can't see an obvious error. I can't now determine whether its a simple line error in the text or the code structure itself isn't suitable.

If you have any ideas on where the error lies, that would be most helpful.

wvmarle

Of course, your if blocks are wrong, specifically the else part is linked to the wrong block. That's why you have indentation (and yours was really messed up - that was the first routine fix, ctrl-T in the IDE), makes those things easier to track!
Now you mentioned it I saw it almost instantly (largely thanks to that indentation), didn't look for any other issues when fixing the type declarations.

Small difference - big effects :-)

Code: [Select]

// Purpose: To produce a PWM signal output at 20Hz frequency and a duty cycle that has a minm of 15 % and max'm of 85%, the pot adjusted for any value in bewtween
// Arduino UNO board design: Has an input pot resistance value from pot wiper into pin A0 (pot has VCC from 5v pin and Ov from Grd pin). PWM signal ouput defined on pin 9
// Testing: currently using oscillosocpe on output pin 9, unloaded.
// Previous code worked at 30.5Hz, successfully varying LED brightness but frequency was too high for motor controller to work and turn the motor.
// STATUS: DOES COMPILE SUCCESSFULLY BUT NO PWM OUTPUT SIGNAL NOW PRODUCED ON PIN 9.

const byte potPin = A0;   // Analog input pin that has the potentiometer wiper resistance value
const byte outPin = 9;    // PWM output pin that Motor Controller) (or LED in testing) is attached to

float dutyCycle;          // Defines the duty cycle, the % of the period (the cycle time) the PWM pulse is high
unsigned long period;     // Defines the cycle time ( 1 / frequency) for PWM output
unsigned long lastChange; // The variable for incrementing the time through the loop
byte outState = LOW;      // The variable holding the value of Hi or Lo output that is derived through the loop

void setup() {
  period = 50000;         // 50,000 us period, to be used to set the output signal at 20Hz frequency.
}
void loop() {

  dutyCycle = map(analogRead(potPin), 0, 1023, 1500, 8500) / 10000.0; // returns 15% to 85% duty cycle range based on pot rotation reading 0-1023.
  unsigned long onTime = period * dutyCycle;                          // defines the high duration in us.
  unsigned long offTime = period * (1 - dutyCycle);                   // defines the low duration in us.

  if (outState == HIGH) {
    if (micros() - lastChange > onTime) {
      outState = LOW;
      lastChange += onTime;
    }
  }
  else {
    if (micros() - lastChange > offTime) {
      outState = HIGH;
      lastChange += offTime;
    }
  }
  digitalWrite(outPin, outState);
}
Quality of answers is related to the quality of questions. Good questions will get good answers. Useless answers are a sign of a poor question.

Andrew_S_C

Hi, a big thank you. Your error-spot looks to largely have fixed the fundamentals. It compiles and produces a PWM signal whose duty cycle changes as the pot is adjusted.

Alas, it's not without its issues. Using oscilloscope readings...
The voltage output (at hi state) is about 60% of that of the 30Hz design (and any other pin 9 design I've created). Not clear why.
Also the low state output signal has sine wave noise within it (about 2 cycles within each down state) - at about 20% of the hi state voltage (rather than a clean constant lo at 0v state). Again, not sure why.

I checked wiring and reloaded the 30Hz code just to compare and did not have either problem. Net, the LED no longer comes on at differing brightness levels. Strange, can't think of an obvious cause.

So massive progress but no quite there. I'll try a few code preset value adjustments and see what happens.




Andrew_S_C

Result. Having had problems with the code, I progressively stripped it back to a simple LED flashing circuit peeling away code to find the problem. Took some time. In the end the code "pinMode(outPin,OUTPUT)" was needed in Void Setup. With this in place, all of the noise on the output signal disappeared.

So now have a 20Hz PWM signal (can preset at any other frequency) and can adjust the duty cycle in range 15% to 85% (again can preset the range required). Brilliant outcome... now just need to try it with the treadmill controller board and find the exact frequency needed to trigger motion.

Thank you to all contributors, most of all wvmarle who stuck with me through the strange problems. A1.

Final code is below with explanation of Purpose, Design, Testing and Working Status upfront.

// Purpose: Produce PWM signal at 20Hz frequency and duty cycle of min'm of 15 % and max'm of 85%, the pot
// rotated for any value in between. For use to control LED brightness or as input signal to motor controller

// Design: Arduino UNO with 1K ohm input pot. Resistance value, pot wiper into pin A0
// pot has VCC from 5v pin and Ov from Grd pin). Output PWM signal is on pin 13.
// V4 has the line of code pinMode(outPin,OUTPUT); that removed the noisy Lo output signal in earlier versions.

// To preset the frequency, set the cycle time in the code , set variable 'period' (in uS) (1 / frequency)

// Testing: Oscillosocpe on output pin 13, unloaded, then with external LED. Yet to test on motor controller

// Working status OPERATIONAL. PRODUCES PWM 20 Hz OUTPUT SIGNAL, VARYING POT CHANGES THE DUTY CYLE #15% TO 85%

const byte potPin = A0;   // Analog input pin that has the potentiometer wiper resistance value
const byte outPin = 13;   // PWM output pin that Motor Controller) (or LED in testing) is attached to

float dutyCycle;          // Defines the duty cycle, the % of the period (the cycle time) the PWM pulse is high
unsigned long period;     // Defines the cycle time ( 1 / frequency) for PWM output
unsigned long lastChange; // The variable for incrementing the time through the loop
int outState = 0;;        // The variable holding value of Hi or Lo output that is derived through the loop


void setup() {
  pinMode(outPin,OUTPUT);   //ADD THIS CODE LINE TO STOP THE NOISE PROBLEM
  period = 33000;         // 50,000 us period, to be used to set the output signal at 20Hz frequency.
}

void loop() {

  dutyCycle = map(analogRead(potPin), 0, 1023, 8500, 1500) / 10000.0; // returns 15% to 85% duty cycle range based on pot rotation reading 0-1023.
  unsigned long onTime = period * dutyCycle;                          // defines the high duration in us.
  unsigned long offTime = period * (1 - dutyCycle);                   // defines the low duration in us.

  if (outState == HIGH) {
    if (micros() - lastChange > onTime) {
      outState = LOW;
      lastChange += onTime;
    }
  }
  else {
    if (micros() - lastChange > offTime) {
      outState = HIGH;
      lastChange += offTime;
    }
  }
  digitalWrite(outPin, outState);
}

PaulMurrayCbr

I know the controller board needs a 5v (@ Hi) input signal frequency of somewhere between 15 and 25Hz (I need to preset to each frequency value and, by trial and error, find the exact frequency that triggers the motor movement. The duty cycle will be in the range of 15% to 85% for the motor speed range.

A loop command may work but I've been concerned that just using the delay function would mess up the duty cycle percentage which is crucial to motor speed setting.
25Hz is 40 millis. If 40 divisions is a bit inaccurate, then use micros.

I  suffix variables with the unit of measurement, so microseconds is us.

Code: [Select]

double frequency_Hz = 20.0; // adjust this to what your board needs
uint32_t wavelength_us = 1000000.0 /  frequency_Hz;

double dutycycle_pct = 35;
uint32_t ontime_us = (double) wavelength_us * dutycycle_pct / 100.0;

uint32_t cycleStart_us;

void setup() {
   cycleStart_us = micros();
   pinMode(pin, OUTPUT);
   digitalWrite(pin, HIGH);
}

void loop() {
  uint32_t us = micros() - cycleStart_us;
  while(us >=  wavelength_us) {
    // this method of adjusting the cyclestart gives more accurate cycles
    cycleStart_us += wavelength_us;
    us -= wavelength_us; 
  }

  digitalWrite(pin, us < ontime_us ? HIGH : LOW);
}
http://paulmurraycbr.github.io/ArduinoTheOOWay.html

Go Up