Manual PWW and duty cycle?

I am making a hot wire bender the same as resistance wire or a hot wire cutter. I think it would be better to have very low frequencies to save loss on heat and power with faster switching times with the mosfet so I would start off with 1Hz frequency even. The lowest pwm you can get is 32.5Hz or so I believe by changing a prescaler but I think that is much too fast switching for a heat strip unlike a led light where it would be obvious or not look good my concern is lower heat from switching times on the mosfet. Turning on and off only once per second wont mean too much for a heat strip.

I would like to be able to set a certain duty cycle AKA high for 300 LOW for 700 for example. This should be 30% duty cycle at 1Hz if I am not mistaken. I would then like to use a potentiometer or analogRead to change the duty cycle and frequency also if possible.

Ideally I would like some code almost exactly like the analogInput example. I believe that example has a fixed 50% duty cycle but changes the frequency of the pwm. If I could find a simple example

This would save me from manually changing the blink example times to create fixed duty cycle and frequency and then rewriting the code each time till the temp is right.

So if you cant have both pwm and duty cycle I would like to be able to keep it at 1 second cycles (1HZ) but just change the times for example the on off times would always add up to one second. 300 on 700 off is 30% then turn the pot and the code changes to 400 on 600 off for 40% etc. And then if possible have a variable at the top i can change in case I want to turn it from 400 to 40 on and 60 off etc. or 150 on 350 off If I want to change from one second freq. to 2 per second.

In this example which is analog input ( http://arduino.cc/en/Tutorial/AnalogInput ) from what i can see the time its on an doff uses the same sensorValue there for the pwm changes and the duty cylce is always 50% because the time of the on off delay is the same. I would like to be able to make that vary but always add up to lets say one second or 1Hz.

This is my first real project so forgive me I can think of ways to do this maybe something like if onDelay goes down by x then offDelay goes up by x. This way if you start with a 50% 50% cycle and you push a button once it makes the on go to 49% that makes the off go to 51%, or using a potentiometer instead of a push button of course would be ideal. But I have no idea how to code this if anyone can guide me a bit or tell me if my idea is way off etc.

int sensorPin = A0;    // select the input pin for the potentiometer
int ledPin = 13;      // select the pin for the LED
int sensorValue = 0;  // variable to store the value coming from the sensor

void setup() {
  // declare the ledPin as an OUTPUT:
  pinMode(ledPin, OUTPUT);  
}

void loop() {
  // read the value from the sensor:
  sensorValue = analogRead(sensorPin);    
  // turn the ledPin on
  digitalWrite(ledPin, HIGH);  
  // stop the program for <sensorValue> milliseconds:
  delay(sensorValue);          
  // turn the ledPin off:        
  digitalWrite(ledPin, LOW);  
  // stop the program for for <sensorValue> milliseconds:
  delay(sensorValue);                  
}
void loop() {
  // read the value from the sensor:
  sensorValue = analogRead(sensorPin);

  constrain(sensorValue, 0, 1000);   // Make sure sensorValue is never more than 1000
    
  // turn the ledPin on
  digitalWrite(ledPin, HIGH);  
  // stop the program for <sensorValue> milliseconds:
  delay(sensorValue);          
  // turn the ledPin off:        
  digitalWrite(ledPin, LOW);  
  // stop the program for for <sensorValue> milliseconds:

  delay(1000 - sensorValue);   
       
}

The change in the last line is the important one. But analogReads can go to 1023, so I added a constrain statement to keep it under 1000. You may want to map the reading from your pot differently, but this should give you the idea.

Thank you and that is interesting but I am not sure how that helps me exactly. Whatever the sensor value it still turns it off and on for the same ammount of time whatever the sensor value is.

This could work i think as long as you can add something like I think there are inverted or inverse numbers like if it puts HIGH at 191 out of 255 that is basically a 75% cylce then it would put low not at the same 191 but the opposite of 191 which would be 64 if i am correct.

This way no matter what the sensorvalue comes back as for the HIGH time on it will tell the LOW time to be the opposite so it always equals out in the end to 255.

If I can get this code down the next step is to figure out how do make it from based on one second or 1000 to based on 500 if i want 2HZ and 250 if I want 4HZ etc. Would I try something like this at that point: constrain(sensorValue, 0, 500); or constrain(sensorValue, 0, 250);

and my last question is does teh constrain scale the values like 1024 scaled to 1000 or does it just cut of the last 24? if it scales then my hunch about changing ti to 250 or 500 may be correct? I am starting to get excited learning real stuff here.

What if you had to invert the value from a potentiometer that is hard wired backwards from the way you would like it. if the pot read 192 and you wanted it to say 64 instead how do you do that.

I heard one time if you go from 255 to 266 it restarts as a 0 so couldn't I just delay the sensorvalue plus half of 256 so 128?

something like this:

delay(sensorValue+128);

would something like that work?

You didn't read my code changes very well. Think about some numbers. What if sensorValue is 300? Then what is 1000 - sensorValue? It's 700. That's your 1Hz at 30% duty. 300 on and 700 off.

If sensorValue is 700 then 1000 - 700 == 300. So then it's 70%, 700 on and 300 off.

Try it with any number. It's dirt simple mathematics.

You can change the 1000 to whatever you want to alter the frequency, so long as you make sure sensorValue doesn't go over that number and try to put a negative number in a delay. But this is how you change the duty cycle with the sensorValue.

digitalWrite(ledPin, HIGH);  
  // stop the program for <sensorValue> milliseconds:
  delay(sensorValue);          
  // turn the ledPin off:        
  digitalWrite(ledPin, LOW);  
  // stop the program for for <sensorValue> milliseconds:

  delay(1000 - sensorValue);

In other words, map your sensorReading to calculate an ON time. Then use your desired frequency to calculate a total time. The total time - the ON time must be the OFF time. Right?

Oh now I see I didn't notice the 1000-sensorvalue part. Its amazing how much i learned today gave me some more confidence. I actually came up with something else if you care not sure its gonna work its just what came up with. but yes I agree with you yours makes sense to me now.

I saw the part about mapping and I realized that is what people did in another sketch I saw converting 0-255 and 0-1023 of course. So as I was reading it it actually showed me how to reverse the numbers.

val = map(val, 0, 255, 255, 0)

I could also use it instead of constrain like this to get a nice milliseconds response without loosing any numbers in the range.

val = map(val, 0, 255, 0, 1000)

so my thinking was to make 2 int at the beginning and i don't even know if this is correct you can check my code but val is the raw value from the sensor

so to sum up I would like to read the sensor it returns 0-1023. I would like to then map that to 0-1000. next i want to set a variable A (on time) to be the same as val or the mapped 0-1000 sensor value. I would then like to set a variable B which is the valA mapped backwards so it returns the opposite number. I tell it do delay valA after HIGH and ValB after LOW.

My next logic was if I wanted to change the cycle from 1000 (1 per second) to 500 (2 per second) i could just do it like this valA = map(val, 0, 1023, 0, 500); (changing it from 1000 to 500)

int ledPin = 9;      // LED connected to digital pin 9
int analogPin = A0;   // potentiometer connected to analog pin A0
int val = 0;         // variable to store the read value
int valA = 0;        //I put this 0 here because I saw everyone else doing it
int valB = 0;        // I did it again here I am not even sure if I need valA and valB up here

void setup()
{
  pinMode(ledPin, OUTPUT);   // sets the pin as output
}

void loop()
{
  val = analogRead(analogPin);   // read the input pin
  valA = map(val, 0, 1023, 0, 1000); // maps the values from 0-1023 to 0-1000 for use as milliseconds on time
  valB =map(valA, 0, 1000, 1000, 0); //reverses the number range for use as milliseconds off time
  // turn the ledPin on
  digitalWrite(ledPin, HIGH);
  // stop the program for <sensorValue> milliseconds:
  delay(valA);   
   // turn the ledPin off:        
  digitalWrite(ledPin, LOW);
   // stop the program for for <sensorValue> milliseconds:
  delay(valB);   
 
}

UPDATE:
I uploaded it and changed it to led pin 13 just to test and it my code worked. I just cant believe it I am amazed.

I would do the subtraction instead of the reverse map to save a bit of code size, but it sounds like you've got the picture.

Delta_G:
I would do the subtraction instead of the reverse map to save a bit of code size, but it sounds like you've got the picture.

Yes thank you so much and its great to have more than one solution I am trying to learn here instead of copy and paste took my first big step today. added karma for you.

ghost2501:
Yes thank you so much and its great to have more than one solution I am trying to learn here instead of copy and paste took my first big step today. added karma for you.

Thanks!

ghost2501:
The lowest pwm you can get is 32.5Hz or so I believe by changing a prescaler but I think that is much too fast switching for a heat strip unlike a led light where it would be obvious or not look good my concern is lower heat from switching times on the mosfet.

Really, the switching time of a MOSFET is many, many orders of magnitude less than 32.5 Hz. That frequency is definitely not too fast. At that frequency any heat loss from switching would not even be measurable. But it's your dime.

I'm with aarg, although a wire is indeed slow enough to use a 1Hz PWM it's just fine to use the hardware PWM of the Arduino. Up until, lets say, 1kHz the losses are low. So if you use a 32Hz PWM there s no problem at all.

The code of Delta_G will work and as long as the Arduino doesn't need to do anything else it's fine. (But you could have used a simple 555 timer :grin: ) But far as the Arduino goes it's doing nothing. 1 second is very very slow for an Arduino and it can do a lot more in the mean time. BUT, you have to get rid of the delay. Look at Blink without delay for that.

PS And just to give you a heads up if you want to do more with an Arduino, DON'T use floats :smiley: They are slow and not needed in almost every case. It's a mistake (let by Arduino tutorials) that every newbie makes. Just saying :wink:

When you say not to use floats what part of my code are you referring to I am not sure by reading the float definition I am sure. My understanding of a float is a number with a decimal point in it like 3.14 but i am just learning.

Also one more thing I had the idea about if you have 0-1023 cant you add 512 or would it be 511 so the number is always opposite. This way I could just use the raw sensor reading and then put val =(val+512) for the off delay.

ghost2501:
When you say not to use floats what part of my code are you referring to I am not sure by reading the float definition I am sure. My understanding of a float is a number with a decimal point in it like 3.14 but i am just learning.

Yup, a float is a number that allows a decimal point. They're practically useless except in very specific situations. They're slow, and eat up a bunch of code space anytime you need to do a calculation with them. They're imprecise. Floats allow 6 digits of precision and calculations often need to be rounded. You'd be shocked at how many people are surprised when 2 * 2 == 3.9999999 and not 4.

It is far easier to use an integer type for all this math. With a long variable you get 9 digits of precision, the calculations are way way faster, it doesn't bloat the code nearly as much, and the results are always exact to the 9 digits of precision.

The trick is to eliminate the decimal point. If you need meters to three decimal places then use millimeters instead so they're always integer numbers. If you need millimeters to 3 decimals then use micrometers. This is called fixed point math.

The only time you really need floats is when the range of numbers and the precision needed don't add up. For example if you had to multiply a distance in km by a distance in mm and both numbers needed 6 digits of precision. Then you'd be stuck using floats because you can't fit both of those into the same 9 digits.

But those cases are rare. Usually you are working with distances or temperatures or some other property that isn't going to vary over three or four orders of magnitude. In those cases using float variable is silly and wasteful.

I came up with this to replicate my earlier code haven't tried it yet. Also Thanks for the explanaion was I using floats in my previous examples I am not sure?

int ledPin = 13;
int analogPin = A0;
int val = 0;

void setup() {
 pinMode(ledPin, OUTPUT);
}

void loop() {
val = analogRead(analogPin); 
digitalWrite(ledPin, HIGH);
delay(val);
digitalWrite(ledPin, LOW);
delay(val+511);
}

So if the on time is 300ms you want the off time to be 811ms? And if the on time is 500ms you want the off time to be 1011ms?

That doesn't sound anything like your original description.

Thank you Delta_G! That's exactly why and a lot of Arduino Tutorials do this wrong.

And no, you were not using floats in your code. But from experience that's usually the next step for people like you (so, learning people). They are like, mm, now I need a decimal place so i'll use float. So it was a heads up, don't start to use float in the next step of learning about Arduino :smiley:

And as Delta_G says, I don't think that's what you want. Because the 1Hz doesn't need to be precise I would do

const byte LedPin = 13;
const byte AnalogPin = A0;
int val = 0;

void setup() {
	pinMode(LedPin, OUTPUT);
}

void loop() {
	val = analogRead(analogPin); 
	digitalWrite(LedPin, HIGH);
	delay(val);
	digitalWrite(LedPin, LOW);
	delay(1023 - val);
}

This gives (kind of) 1Hz. A little bit slower but he :wink:

Also I assigned the pins to a const byte instead of a int. This way you free up memory. And, because they are const, changed the first letter to a capital. That's best practice so you know the variable is a const (and can't be written to, only read).

First letter capital is usually for types, class names, and header names.

Constants are usually all caps with underscores for spaces if you're following convention.

That's not the convention I'm used to. But, as I read that's more common with C# as it is with C++. But they both agree ALL_CAP is for defines.

var => thisIsVar
const => ThisIsConst (PascalCasing)
class/object => ThisIsClass (not suposed to write to so same as const) (PascalCasing )
define => THIS_IS_DEFINE