I am new to the Arduino and programming languages all together. The current problem is with my mechanical engineering senior project. I set out to design and build a self-calibrating bench-top wind tunnel for testing cup-anemometers (wind speed sensors). I built a dc power supply for use with a PWM/microcontroller board I designed to control the fan motor and thus the wind speed. My code includes functions to increment the PWM setting slowly in order to not allow the user to start at full power (stall current would be very high). I used two 4-digit seven-segment displays to output the current speed setting and the measured wind speed from the anemometer.
The anemometer reading code works fine, but the functions that manipulate my PWM setting lock up after running for roughly 30 seconds. Ive observed this on both the serial port and the digital readouts. My guess is that the memory is getting used up and then it fails. The weird thing is that the anemometer reading function continues to work and so does the analogRead (pot to change PWM setting), but the PWM value being analogWrite()'ed the motor controller gets locked up.
I have isolated the code that carries out these functions. The code for reading the wind speed uses external interrupts and when commented out, does not remedy the problem. So I decided to leav it out.
int previousMillis = 0;
int prevPWM = 0;
unsigned long display1;
void setup() {
Serial.begin(9600);
}
void loop() {
//reads pin 5(pot), maps it to 255 for use with analogWrite()
int pwm = map(analogRead(5), 0, 1023, 0, 255);
int time = millis();
boolean timeIntervalElapsed = time > (previousMillis + 50);
boolean pwmChanged = pwm != prevPWM;
if( timeIntervalElapsed && pwmChanged ) {
//if user has changed the setting from what it was before,
//check if they turned it up or down
//if up, increment PWM
//that will happen every 50 millis until prevPWM = PWM
previousMillis = time;
boolean pwmPositiveChange = (pwm - prevPWM) > 0;
if( pwmPositiveChange ) {
prevPWM++;
}
else {
//when user turns PWM down, decrement (3 times faster)
prevPWM--;
prevPWM--;
prevPWM--;
}
}
if (prevPWM > 5) {
//dont change the PWM output unless setting has gone above 5
analogWrite(9, prevPWM);
}
else {
//otherwise, just make PWM output 0
analogWrite(9, 0);
}
//that was to eliminate the motor flicking on and off when
//setting is turned all the way down(electrical noise)
display1 = prevPWM * 40;
//maps to range of 0 - 10,000 to avoid floating point math
//when creating values to write on each digit of the display
Serial.print(display1);
Serial.print("\t");
Serial.println(pwm);
}
The extra components on the board are for opto-isolation and gate-signal amplification (10volt gate on the MOSFET).
Here is the finished board with all of the components.
After about 49 days, millis wraps to zero. This line of code will not work correctly for 50 milliseconds after the wrap...
boolean timeIntervalElapsed = time > (previousMillis + 50);
I believe it's possible for prevPWM to become less than zero. While it shouldn't affect the application's function, it may make motor startup a tiny bit sluggish. I suggest clamping prevPWM after adjusting it...
Thank you Coding Badly. That turned out to be exactly the problem. It makes sense. The function stopped working around 32 seconds after starting. 32 seconds being near the limit of an int (32,767milliSeconds). However, I do not understand what you mean when you say that you believe prevPWM can be negative. If you just make it unsigned, shouldn't that eliminate the issue? Or do you mean that say 1-2=65,535?
However, I do not understand what you mean when you say that you believe prevPWM can be negative.
Because it's incremented by 1 and decremented by 3 you could have something like this (I think)...
Delta New Value
----- ---------
+1 +1
+1 +2
+1 +3
+1 +4
-3 +1
-3 -2
If you just make it unsigned, shouldn't that eliminate the issue?
Oh no! Don't do that. You've definately chosen the correct datatype. If you make it unsigned, instead of becoming negative, the value will wrap to a very large positive value.
Sorry Coding Badly, I see what you mean now. You would rather it go negative and still be close to the value it should be than stay positive and rap to 65,535. This way the "clamping" function that you suggested will work. That is very interesting how you noticed the decrementing by 3 might make it negative. I wrote the code and never even considered that.
No need to apologize! Far too often, I get in a hurry and reply before understanding. I just wanted to make certain there wasn't something in your code that I had missed or something that I didn't understand.
Or do you mean that say 1-2=65,535?
I don't understand.
I think you do.
I think I don't! (with apologies to Roger Rabbit)
Putting that particular reply after that particular quote was one very bad idea! I've said it before and I'll say it again, "DON'T reply to technical questions right before bed!"
I wrote the code and never even considered that.
The PID algorithm, in it's most basic form, can "windup"; the internal integral values continue increasing even though the control point has reached its limit. Under certain conditions, when "winding down", the output can change very dramatically; even swing fully from one extreme to the other.
In a past life, I occasionally worked with large dangerous expensive things (engines, motors, valves, the usual stuff). It was rather important that the equipment not be subjected to fast changes (like trying to take a valve from fully closed to full open in one swing); very similar to what you're doing. Imagine combining a large dangerous expensive thing that doesn't tolerate extreme changes with a PID algorithm missing anit-windup. Just the sort of thing that upset the customer.
Fortunately, I had a boss that drilled in us the importance of including limit checking (like anti-windup). I guess I've done it enough that my brain does it automatically.