Go Down

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

Andrew_S_C

Hi,

I am replacing the PWM signal input to my treadmill. It is to the motor controller board that then drives the 2.5HP motor. . 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.

I am very new to Arduino coding. I have successfully put together a potentiometer analog input and pin 9 output that has a PWM output that gives the 15% to 85% duty cycle range using the mapping of input range 0-1023 to output 0-255. It is successful in adjusting an LED brightness (but not to get the motor to work).

The problem is that the lowest frequency I have been able to set the Arduino circuit is 30.5Hz by using the code line:
TCCR1B = TCCR1B & B11111000 | B00000101

The motor control board does not work at this frequency and is known to be very sensitive to the input frequency of the PWM (known to be somewhere in the range 15Hz-25Hz depending on the board).

I'm seeking help with a source for the Arduino code needed to specifically have a lower PWM frequency, where I can put in a variable in the code that allows me to preset to an exact frequency (and still vary the duty cycle by potentiometer adjustment). I have read a lot of material but have found it baffling with quite a lot of tables and considerations - sometimes with example code that, when I try it, does not quite do the job. Any helpers on a solution to this?

I know I can build a dual ic555 timer circuit to do the same job (with fine tune variable resistors to set the frequency) but this feels like giving-in and would prefer to use Arduino with its coded control.

6v6gt

Quote
15Hz-25Hz depending on the board
That is a very low frequency. You could do that easily in the loop just using millis() instead of using a built in timer.
You are planning to use an opto coupler or some other means of isolation from the motor control board ?

wvmarle

Indeed, just use millis() timing. Look at Blink Without Delay, modify that. Unless the device has to do a lot more work, this will do just fine.

How do you plan to do a 555 circuit? They normally can't provide duty cycles of >50%.
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 early feedback.

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. I've not seen the BlinkWithoutDelay function before so will look into that - thanks.

The ic555 solution, is my last-resort fallback option if I can't get the Arduino circuit to work. It consists of two ic555s in series, the first sets the frequency, the second the duty cycle. More details on this (and links to others) that people have posted are on http://el34world.com/Misc/Cnc/TreadmillMotor1.htm

The motor controller board comes with a opto-coupler for isolation so should be protected (to some degree) from my breadboard testing.

If anyone has a "set very low PWM frequency" known working code that still allows for a wide duty cycle variation within it, please let me know.

wvmarle

If anyone has a "set very low PWM frequency" known working code that still allows for a wide duty cycle variation within it, please let me know.
Blink Without Delay (and even good old Blink) does exactly that. Very low PWM frequency (by default 0.5 or 1 Hz), 50% duty cycle. Changing the on and off times gives you any duty cycle you need.
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.

wvmarle

A few comments on that dual 555 schematic:
- instead of two 555s you can also use a 556.
- C1 and C2 should be film capacitors, much better stability when it comes to timing. This person used an electrolytic for C1 and 3x ceramic for C2. Especially ceramics give quite unstable results.
- C2 can be replaced by a single 330 nF cap. No need to have three in parallel. That's probably because of what he happened to have on hand (just like that 2.2µ electrolytic).
- that 0.68µ cap can indeed be necessary; a bigger value will work fine as well. It's for power supply decoupling. Better would be to use one larger electrolytic and a smaller ceramic in parallel (e.g. 10µF and 100 nF).
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.

cloxart

I recently worked on an application that required a 20Hz PWM. Indeed the lowest possible frequency on arduino PWMs is 30.5 Hz, so I did it in loop using millis.
Then the application got more complicated and to avoid all concerns about loosing the correct timing I made the main application running on one arduino and I have a second board running just the timing code. the two are easily connected via I2C so from the first arduino I can set both frequency and duty cycle at run time.
hope this helps

wvmarle

You can use timer interrupts as well for this. Those work for much longer intervals, and are not affected by other tasks. I've used it for blinking an led during a long running, otherwise blocking task. No need for a second Arduino! Just set the interrupt to fire and set the output accordingly, together with the length of the next interval (for duty cycle changes).
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 again for all of the feedback so far.
 
I must be missing something. I have investigated the Blink Without Delay function and some example circuits/code. They do produce a low frequency but they have the duty cycle locked at 50%. The only example I saw where the duty cycle could be changed actually then changed the frequency as well.

For this project I need a signal that has a fixed duration low frequency (unchanging so the motor controller recognises the signal) whilst also being able to change the duty cycle (over a 15% to 85% range to change the motor speed) within that fixed frequency. So far, I'm not seeing Blink Without Delay as the solution for this need. But I may have not spotted how to set up the code to do this.

If anyone can point me to Blink Without Delay example code that a) has a fixed low frequency and b) allows the duty cycle to be varied as above (say, with a potentiometer) without changing the frequency, that would be very helpful.

6v6gt

Of course, an unmodified blink without delay will not fulfill all your requirements, but it is very close:

Lets say you want a frequency of 20Hz.
If you want a 10% duty cycle, that is  5ms ON and 45mS OFF
If you want a 20% duty cycle, that is 10ms ON and 40mS OFF
etc.
etc.

Therefore:
The ON period =    ( 10 * DC / Freq ) milliseconds,  where DC is duty cycle in % and Frequency in Herz
The OFF period =   ( 10 * (100 - DC ) / Freq ) milliseconds.

So all you want is the blink sketch with variable on and off times.

Do you want to be able to vary the frequency, and if so, within what range ?
You've already said the duty cycle is from 15% to 85 %

How do you want to enter these parameters into the sketch, say with a potentiometer ?
How do you want to display the selected parameters (if at all) ? with a 1602 LCD ?

wvmarle

Exactly, like that. Just calculate the on/off periods. The same if you would use timer interrupts, then the moment the interrupt is called set the pin and reset the timer to reflect onTime or offTime as appropriate.

Code: [Select]

unsigned int period = 500; // 500 ms period.
float dutyCycle; // 20% duty cycle.
unsigned long lastChange = 0;
bool signal = LOW;

void loop() {
  dutyCycle = map(analogRead(potPin), 0, 1023, 1500, 8500) / 10000.0; // returns 0.15-0.85 based on the analog reading 0-1023.
  unsigned int onTime = period * dutyCycle;
  unsigned int offTime = period * (1 - dutyCycle);
  if (signal == HIGH) {
    if (millis() - lastChange > onTime) {
      signal = LOW;
      lastChange += onTime;
    }
  else {
    if (millis() - lastChange > offTime) {
      signal = HIGH;
      lastChange += offTime;
    }
  }
  digitalWrite(outPin, signal);
}


This should do. Not tested or even compiled.
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.

Go Up