user50517: 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).

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

user7508: That is how it is supposed to be. In this fast PWM mode, the duty cycle
is (OCR1A+1)/(ICR1+1). If you want a duty cycle of zero, you have to
disengage the PWM and turn the pin to OUTPUT LOW.
This is what the Arduino's analogWrite() does: it treats the
value 0 as a special case. Note that 255 is also treated as a special
case, although that is not useful.
Edit 1: about analogWrite() being messed up.
analogWrite(9, value) sets OCR1A to a value between 1 and 254 (0 and
255 being handled in a different manner). The duty cycle you get is, as
I wrote before (OCR1A+1)/(ICR1+1). This is not what your test
function expects.
I suggest you ditch analogWrite() and instead set directly OCR1A.
Edit 2: Once you have taken control of a PWM channel at low-level,
by writing directly to the hardware registers, you should not use
the Arduino functions digitalWrite() nor analogWrite() on the
associated pin. These functions assume those hardware registers are
controlled solely by the Arduino core, and they will fiddle with them in
a way that will likely break your program.
To set the duty cycle to zero, disable the PWM mode and set the pin to
LOW:
TCCR1A &= ~_BV(COM1A1);  // disable PWM on pin OC1A = PB1
PORTB  &= _BV(PB1);      // set PB1 to LOW


50517: <p>I'm trying to control a heating element with PWM with an <a href="https://en.wikipedia.org/wiki/List_of_Arduino_boards_and_compatible_systems#Official" rel="nofollow noreferrer">Arduino Nano</a>, but the problem is even if I set the duty cycle to 0 it gives a tiny spike.</p>
<p>I want to generate a square wave of 1Hz and that's why I override the default PWM registers.</p>
<p>Here is the code:</p>
<pre><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);
}
</code></pre>
<p>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).</p>
<p><a href="https://i.stack.imgur.com/i5YCj.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/i5YCj.png" alt="Enter image description here" /></a></p>
<p>I'm getting the same results with the Nano and Uno. My IDE version is 1.8.14.</p>
<p>How can I fix this problem?</p>
<p>Here is my temperature control function:</p>
<pre><code>void Compute()
{
    unsigned long now = millis();
    int timeChange = (now - lastTime);

    if(timeChange&gt;=SampleTime)
    {
        /*Compute all the working error variables*/
        double error = Setpoint - temprature;

        if (error &lt;= 0)
        {
            Output = 0;
            Serial.println(&quot;level: 0&quot;);
        }
        else if (error &lt;= 1)
        {
            Output = 5;
            Serial.println(&quot;level: 1&quot;);
        }
        else if (error &lt;= 2)
        {
            Output = 30;
            Serial.println(&quot;level: 2&quot;);
        }
        else if (error &lt;= 3)
        {
            Output = 50;
            Serial.println(&quot;level: 3&quot;);
        }
        else if (error &lt;= 10)
        {
            Output = 60;
            Serial.println(&quot;level: 4&quot;);
        }
        else if (error &lt;= 100)
        {
            Output = 200;
            Serial.println(&quot;level: 5&quot;);
        }
        else
        {
            Output = 255;
            Serial.println(&quot;level: 6&quot;);
        }

        analogWrite(HEATER_OUTPUT, Output);
        //OCR1A = map(Output, 0, 255, 0, 62499);
        delay(10);

        lastErr = error;
        lastTime = now;
    }
}
</code></pre>
<p>The problem is that after I override the PWM registers, the <code>analogWrite()</code> seems messed up. It's not working, and for all the values of <code>Output</code>, the result is almost the same.</p>
<h3>UPDATE 22/06/2021</h3>
<p>I'm still struggling to fix this, if I use <code>analogWrite()</code> or <code>digitalWrite()</code> to turn off the PWM pin, the further changes on <code>OCR1A</code> 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 <code>OCR1A</code> are not taking into action.</p>
<p>I wrote a test function</p>
<pre><code>void testPWM3() {

    Serial.println(&quot;f: 1Hz | on 0s&quot;);
    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(&quot;f: 1Hz | on 125ms&quot;);
    OCR1A =  1953;
    delay(5000);

    Serial.println(&quot;f: 1Hz | on 250ms&quot;);
    OCR1A =  3906;
    delay(5000);

    Serial.println(&quot;f: 1Hz | on 500ms&quot;);
    OCR1A =  7812;
    delay(5000);

    Serial.println(&quot;f: 1Hz | on 1sec&quot;);
    digitalWrite(HEATER_OUTPUT, HIGH);  // this works
    delay(5000);
}
</code></pre>
<p>Any advice on this will be greatly helpful, thank you</p>
 7508: <p>That is how it is supposed to be. In this fast PWM mode, the duty cycle
is <code>(OCR1A+1)/(ICR1+1)</code>. If you want a duty cycle of zero, you have to
disengage the PWM and turn the pin to <code>OUTPUT</code> <code>LOW</code>.</p>
<p>This is <a href="https://github.com/arduino/ArduinoCore-avr/blob/1.8.3/cores/arduino/wiring_analog.c#L112-L115" rel="nofollow noreferrer">what the Arduino's <code>analogWrite()</code> does</a>: it treats the
value 0 as a special case. Note that 255 is also treated as a special
case, although that is not useful.</p>
<p><strong>Edit 1</strong>: about <code>analogWrite()</code> being messed up.</p>
<p><code>analogWrite(9, value)</code> sets <code>OCR1A</code> to a value between 1 and 254 (0 and
255 being handled in a different manner). The duty cycle you get is, as
I wrote before <code>(OCR1A+1)/(ICR1+1)</code>. This is <strong>not</strong> what your test
function expects.</p>
<p>I suggest you ditch <code>analogWrite()</code> and instead set directly <code>OCR1A</code>.</p>
<p><strong>Edit 2</strong>: Once you have taken control of a PWM channel at low-level,
by writing directly to the hardware registers, you should <strong>not</strong> use
the Arduino functions <code>digitalWrite()</code> nor <code>analogWrite()</code> on the
associated pin. These functions assume those hardware registers are
controlled solely by the Arduino core, and they will fiddle with them in
a way that will likely break your program.</p>
<p>To set the duty cycle to zero, disable the PWM mode and set the pin to
LOW:</p>
<pre class="lang-cpp prettyprint-override"><code>TCCR1A &amp;= ~_BV(COM1A1);  // disable PWM on pin OC1A = PB1
PORTB  &amp;= _BV(PB1);      // set PB1 to LOW
</code></pre>
