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

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.

Andrew_S_C

Thanks again for all of the help. Looks to me to be getting close to a solution to my problem.

To summarise my understanding on the recent feedback…

Have a variable 'period' that is set to the desired cycle time (i.e. 1 / frequency). So, 'period' set to 50mS would give a 20Hz frequency.
Have a variable 'dutycycle' that takes an analog (say potentiometer) reading expressed as a range value of 0-1023 and maps these limits to 15% and 85% duty cycle min and max values
Have variables 'onTime' and 'offTime' and calculate the values of these needed usng the duty cycle and period values.
Use the loop with If statements to then move between the High and Low output signal status based on the previous signal status and the time. The increment the time with a variable 'lastChange'

The challenges I still see for me to get to a working solution are…

1.   How does the potentiometer input circuit (to adjust the duty cycle between 15% and 85%) get recognised and fit in with this example code? I'm looking to set the motor at any speed in the range
2.   The very useful example code from wvmarle does not compile. It has the error "  'dutyCycle' was not declared in this scope". From my reading of the code, 'duty cycle' was declared as a float variable - but this is where my weak knowledge of Arduino code is exposed. What is wrong?
3.   I'm assuming I also need to declare the Arduino pins for input and output. For example:
       const int potPin = A0;    // Analog input pin that the potentiometer attached to
       const int outPin = 9;      // PWM output pin that the Motor or LED is attached to
       Or have I got this wrong?

On the questions raised by 6v6gt…
How to get this into a sketch and use of a potentiometer. Plan to use a pot maybe with pad switches for speed presets (if I'm feeling confident!). I had originally envisaged a 10K potentiometer input into pin A0. My remaining sketch challenges above probably set out my other needs re the sketch.

On using an LCD screen, I actually don't need to show the input treadmill speed (and with it time and distance) of the treadmill as I have already built a box with a 1602 LCD display that takes reed sensor feedback on treadmill motor rotations to generate the readings. So once past the use of Arduino serial readout in trialing it, and once the motor turns I can do final calibration. Hope that makes sense.

Thanks again for all of the support.

wvmarle

1.
That's the map() function taking care of. Every time loop() runs, it is calculated.

2.
No surprise it doesn't compile. Did you notice setup() is missing as well? There is more missing such as pin declarations indeed (which you can better declare as const byte rather than const int - more efficient). I didn't try to compile it, it's meant to get you started. You have to fill in the rest of the details (and maybe fix some typos in the process).

A pot can be connected easily, and will do great. One end to GND, the other end to Vcc, wiper to A0. That's it.
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. I had added setup and pin declarations: A0 input from the pot which, same as per my previous design, has the pot wired as you describe) and;  pin 13 for the PWM output. It did not successfully compile. It did not seem to like the declaration of 'duty cycle'. I'll take another look.

wvmarle

Please post your current sketch and we'll have a look at what's going wrong.
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