The Japanino, Fading LEDs

Outputting an analog signal is a little different than for inputting one.

When we use the analogRead() command, an analog-to-digital (ADC converter) reads the value of the voltage at the input pin at that moment, and translates it to a binary value between 0 and 1023. The actual number depends on the ratio of the analog signal to the value of VCC (the Japanino power supply voltage). That is, if the input is 2V and VCC is 4.5 (from the battery pack) the digital value will be a little higher than if VCC was 5V (from an AC power supply). (There's also a small delay time required between calls to analogRead() in order to allow the A-to-D conversion to occur.)

But, when we output an analog voltage to an output pin by using analogWrite(), we're actually using a 473 Hz square wave with a pulse width that varies based on the output we want. In order to have a solid DC outut value, we need to use some kind of filtering to smooth out the pulses. The interface circuit given in the Japanino to SX-150 synth driver project uses a 0.0047 uF capacitor and a 22 K ohm resistor.

The syntax is: analogWrite(pin, value);

Where
   pin is one of the PWM pins (D2, D3 and D6 and D9-11).
   value is 0 (for always off/ 0V) to 255 (always on/ VCC).

It's pretty obvious here that reading an analog voltage is nothing like outputing one. If you have the P.O.V., it's really easy to play with the analogWrite() command. Just grab the Fade sketch from the Arduino site, compile and send it to the Japanino. If we strip the comments out and simplify the code, we can see that really it's just a for-loop running from 0 to 255 and back, and outputting it to pin 9. We don't need to set up the pin first, so setup() can be left empty.

    void setup() {
    }

   void loop() {
       for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) {
          analogWrite(9, fadeValue);
          delay(30);
       }
       for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) {
          analogWrite(9, fadeValue);
          delay(30);
       }
    }

-------------------------------

By itself, this sketch is kind of useless, and it doesn't make use of the fact that there are 3 PWM (pulse-width modulated) pins connected to the P.O.V. In fact, if you wanted to, you could modify the P.O.V. wiring to connect it to all 6 PMW pins. It's more interesting to turn this sketch into a function call, convert the delay() commands into calls to millis(), and make the pins fade in alternating phases. While the following sketch is a little harder to read, it is now pretty easy to toss into some other, bigger sketch.

    // Fade as a function call sketch.

    #define fadeStep 1  // Steps per fade, from 0 to 255.
    #define fadeTime 10 // Pauses between fade steps.
    #define ledPin 9    // First PWM analog pin is D9 (and D10 & D11).
    #define fadeMax 255 // analogWrite() takes values from 0 to 255.

    long int fadeTimer=millis(); // Set start value for timer.
    boolean fadeDir = 1; // Pick 0 or 1 to start, does't matter.
    int fadeValue = 0; // Fade runs from 0 to 255, then returns to 0.

   void setup() {
       // Left empty
    }

   void loop() {
       if(millis() - fadeTimer > fadeTime) {
          fadeLED(ledPin,       fadeDir);
          fadeLED(ledPin + 1, ! fadeDir); // D10 Invert fade
          fadeLED(ledPin + 2,   fadeDir); // D11 Plain fade
          fadeTimer = millis();
       }
    }

    void fadeLED(int iLED, int iDir) {
       fadeValue += fadeStep;
       if(fadeValue > fadeMax) {
          fadeDir   =! fadeDir;
          fadeValue =  0;
       }
       if(iDir) {
          analogWrite(iLED, fadeValue);
       } else {
          analogWrite(iLED, fadeMax - fadeValue);
       }
    }

------------------------------------------

It's easy to invert the fade - just write "255 - fadeValue".  It's a bit more of a challenge to fade the LEDs at different phases.  The easiest approach is to just replace the fadeValue and fadeDir variables with arrays to track each pin's progress through the fade individually.  We could then do something like:

    //  Fade with Phase sketch.

    #define fadeStep 5  // Steps per fade, from 0 to 255.
    #define fadeTime 5  // Pauses between fade steps.
    #define ledPin 9    // First PWM analog pin is D9 (and D10 & D11).
    #define fadeMax 255 // analogWrite() takes values from 0 to 255.

    long int fadeTimer=millis(); // Set start value for timer.
    boolean fadeDir[] = {0, 0, 1};
    int fadeValue[]   = {0, 128, 0};

    void setup() {
       // Left empty
    }

    void loop() {
       if(millis() - fadeTimer > fadeTime) {
          for(int i = 0; i<3; i++) {
             fadeLED_phased(i);
             fadeTimer = millis();
           }
       }
    }

    void fadeLED_phased(int iLEDptr) {
       fadeValue[iLEDptr] += fadeStep;
       if(fadeValue[iLEDptr] > fadeMax) {
          fadeDir[iLEDptr]   =! fadeDir[iLEDptr];
          fadeValue[iLEDptr] =  0;
       }
       if(fadeDir[iLEDptr]) {
          analogWrite(iLEDptr + ledPin, fadeValue[iLEDptr]);
       } else {
          analogWrite(iLEDptr + ledPin, fadeMax - fadeValue[iLEDptr]);
       }
    } 

------------------------------------------

One thing to mention about the above code is that if you connect the LED directly to a Japanino pin without a series resistor in place, then it's going to glow really bright and the fading may not be as obvious.  This is because the sketch is spending so much time in the area where the LED is effectively "saturated" and not as much where it's fairly dark.  To compensate for this, and to make the fading more apparent, you can change fadeMax to 200 or even 150.  Try different values to see what the impact is on the LEDs you're using.

Return to Main Index