Skip to main content
Arduino

You are not logged in. Your edit will be placed in a queue until it is peer reviewed.

We welcome edits that make the post easier to understand and more valuable for readers. Because community members review edits, please try to make the post substantially better than how you found it, for example, by fixing grammar or adding additional resources and hyperlinks.

Required fields*

Required fields*

Can’t set duty cycle to 0% with custom PWM

I'm trying to control a heating element with PWM with an Arduino Nano, but the problem is even if I set the duty cycle to 0 it gives a tiny spike.

I want to generate a square wave of 1Hz and that's why I override the default PWM registers.

Here is the code:

// Set up fast PWM on the Arduino Uno at 1 Hz on digital pin D9
void setup() {
 // set I/O pins
 pinMode(LDR_INPUT, INPUT); // A0
 pinMode(HEATER_OUTPUT, OUTPUT); // D9
 // Enable the PWM output OC1A on digital pins 9
 TCCR1A = _BV(COM1A1) | _BV(WGM11);
 // Set fast PWM and prescaler of 256 on timer 1
 TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS12);
 // Set the PWM frequency to 1Hz: 16MHz/(256 * 1Hz) - 1 = 62499
 ICR1 = 62499;
 // OCR1A = 32149; // this gives me duty cycle of 50%, working fine
 OCR1A = 0; // but this is not working
 //allow PWM timers to start
 delay(10);
}

For testing, I connected an LED to the PWM pin (D9) and these are the spikes from the LDR reading from analog pin A0 (I don't have an oscilloscope).

Enter image description here

I'm getting the same results with the Nano and Uno. My IDE version is 1.8.14.

How can I fix this problem?

Here is my temperature control function:

void Compute()
{
 unsigned long now = millis();
 int timeChange = (now - lastTime);
 if(timeChange>=SampleTime)
 {
 /*Compute all the working error variables*/
 double error = Setpoint - temprature;
 if (error <= 0)
 {
 Output = 0;
 Serial.println("level: 0");
 }
 else if (error <= 1)
 {
 Output = 5;
 Serial.println("level: 1");
 }
 else if (error <= 2)
 {
 Output = 30;
 Serial.println("level: 2");
 }
 else if (error <= 3)
 {
 Output = 50;
 Serial.println("level: 3");
 }
 else if (error <= 10)
 {
 Output = 60;
 Serial.println("level: 4");
 }
 else if (error <= 100)
 {
 Output = 200;
 Serial.println("level: 5");
 }
 else
 {
 Output = 255;
 Serial.println("level: 6");
 }
 analogWrite(HEATER_OUTPUT, Output);
 //OCR1A = map(Output, 0, 255, 0, 62499);
 delay(10);
 lastErr = error;
 lastTime = now;
 }
}

The problem is that after I override the PWM registers, the analogWrite() seems messed up. It's not working, and for all the values of Output, the result is almost the same.

UPDATE 22/06/2021

I'm still struggling to fix this, if I use analogWrite() or digitalWrite() to turn off the PWM pin, the further changes on OCR1A regs are not taking action. whatever values I gave to the OCR1A the pin remains low, if I manually make the pin high with digitalWrite or analogWrite the pin remains high forever the changes on OCR1A are not taking into action.

I wrote a test function

void testPWM3() {
 Serial.println("f: 1Hz | on 0s");
 digitalWrite(HEATER_OUTPUT, LOW); // turn off the pwm pin to get full of (0% duty cycle)
 delay(5000);
 /*
 After turning off the pin with digitalWrite() further changes on OCR1A reg are not taken into action
 */
 digitalWrite(HEATER_OUTPUT, HIGH);
 Serial.println("f: 1Hz | on 125ms");
 OCR1A = 1953;
 delay(5000);
 Serial.println("f: 1Hz | on 250ms");
 OCR1A = 3906;
 delay(5000);
 Serial.println("f: 1Hz | on 500ms");
 OCR1A = 7812;
 delay(5000);
 Serial.println("f: 1Hz | on 1sec");
 digitalWrite(HEATER_OUTPUT, HIGH); // this works
 delay(5000);
}

Any advice on this will be greatly helpful, thank you

Answer*

Draft saved
Draft discarded
Cancel
6
  • Thank you for your response, I have tried that, but the analogWrite is not working properly in my case, updated the question. Commented Jun 20, 2021 at 14:25
  • You mean not working properly in a way different from how this answer explains perfectly well? Commented Jun 20, 2021 at 14:27
  • @timemage, this is a great answer, I got what he says, with analogWrite() I'm getting clean off PWM, but with analogWrite(9,128) I'm supposed to get a duty-cycle of 50%, but what I'm getting is a really thin pulse.. Commented Jun 20, 2021 at 14:46
  • Re "analogWrite(9,128) I'm supposed to get a duty-cycle of 50%": No, you are not. Read my answer more carefully. Commented Jun 20, 2021 at 14:47
  • 1
    oh damn me, so for getting 50% I have to give half of ICR1 right..? Commented Jun 20, 2021 at 14:49

lang-cpp

AltStyle によって変換されたページ (->オリジナル) /