Showing posts with label LED. Show all posts
Showing posts with label LED. Show all posts

Sunday, July 4, 2021

Two against One

 







Clip above shows Attiny85 chip controlling two 10mm LEDs with the single pin. This post discusses schematic and programming of such a solution.

There are two ways to control LEDs with microcontrollers (like Attiny85).
One way would be to connect LED cathode to the chip pin and LED anode through the current limiting resistor to the power supply '+'.  To light up the LED you just need to program pin low. To turn it off  you need to program it high.

Another way would be to connect LED cathode to the ground and LED anode through the current limiting resistor to the  chip pin. To light up the LED you need to program pin high and low otherwise.
Which way to prefer? I can't tell. I myself often choose it based on how well it corresponds to controls of other devices in particular project.

But there are not that many pins on the chip like Attiny85. What if number of pin available is less than number of LEDs needed to be controlled.
On the circuit diagram above you see the method  of controlling two LEDs with single pin. It based on three important facts:
  1. Any LED has some forward voltage. For Green/White 10mm used here it exceeds 3 V.
  2. Microcontrollers pins may be programmed not only to provide output signal but to collect input as well, If pin is programmed for input it presents itself for external components as a circuit with very high resistance.
  3. Human eye can't see light blinking if its frequency exceeds 50 Hz. If circuit switches LED off/on fast enough (more than 50 times per seconds) you will see it as always lighted.
Rules to controller LEDs here are next:
  • If pin set high green LED is dark and white LED is lighted.
  • If pin set low green LED is lighted and white LED is dark.
  • If pin set into input mode both LEDs supposed to be dark, because sum of forward voltages on both LEDs exceeds power supply voltage,
I assembled the circuit and programmed it , but result was  disappointing. Setting pin into input mode did not turn both LEDs off, They were lighted up. The light was  less bright than normally but still visible.  Would resistors increase help? Alas not that much. LEDs dimmed a little but not fully. Obviously I need either decrease power voltage or look for LEDs with bigger forward voltage,
Then idea came to mine mind: what if I add to the circuit extra devices with some forward voltage.
Here you see each LED sequentially connected to  the silicon diode . Forward voltage of diode reaches 1 V,  which makes whole forward voltage of both (LED and silicone diode) ~ 4 V.  Obviously it is better to decrease value of resistor to keep current the same  (~20 mA). And this circuit solved the problem.  I believe it is not bad solution taking in to consideration that silicon diode cost pennies, Below you can see C program to run the test. 

#include <avr/io.h>
#define 	F_CPU   1000000UL
#include <util/delay.h>

typedef enum {OUT_LOW, OUT_HIGH} OutputLevel;

#define pinOut(bit, outLevel) \
(DDRB |= (1 << ( DDB##bit)));\
switch(outLevel) \
{\
	case OUT_LOW: (PORTB &= ~(1 << (DDB##bit))); break;\
	case OUT_HIGH: (PORTB |= (1 << (DDB##bit))); break;\
}

#define pinIn(bit) \
((DDRB &= ~(1 << (DDB##bit))),\
(PORTB &= ~(1 << (PORTB##bit))),\
(PINB & (1 << (PORTB##bit))))

int main(void)
{
    while (1) 
    {
		for (int i=0; i < 100; i++) { // White & Green
			pinOut(2,OUT_HIGH);
			_delay_ms(5.0);
			pinOut(2,OUT_LOW);
			_delay_ms(5.0);
		}
		for (int i=0; i < 100; i++) { // White
			pinOut(2,OUT_HIGH);
			_delay_ms(5.0);
			pinIn(2);
			_delay_ms(5.0);
		}
		for (int i=0; i < 100; i++) { // Green
			pinOut(2,OUT_LOW);
			_delay_ms(5.0);
			pinIn(2);
			_delay_ms(5.0);
		}
		for (int i=0; i < 100; i++) { // No light
			pinIn(2);
			_delay_ms(10.0);
		}
    }
}

But one may ask why this? Why not charlieplexing?  Indeed charlieplexing is well known technique which utilizes facts of of pin high resistance while  in input mode, and non-ability of human eye to see  high frequency light oscillation. It can provide LEDs/pin ratio not only 2 but much bigger. To compare  let us look at charlieplexing example with the same LED/pin  ratio: 2. There is need to have three pins to control six LEDs.  But how to control just four LEDs, or two? Not possible. And in addition you need to connect/solder five components to the single dot which for DYI project presents some challenge. 


So in a conclusion: even if charlieplexing is great there could be  cases when method described in this post is a valuable solution.

Update 07/05/2021. I put link to this post on the AVR subreddit . And I got some comments that there actually different schematic exists which allows to control two LEDs with the single pin without need of silicon diodes.

Indeed such circuit works perfectly. But again nothing is free. It consumes ~ 20 mA even if both LEDs are off. Meanwhile for circuit  with silicon diodes consumption during dark time is much smaller. So which circuit to choose is really question of use case and preferences.

Monday, October 19, 2020

It Is a Halloween Time

Recently I upgraded our windows Halloween decoration with two items. Both are LED installations. Each is controlled by Attiny85 chip.

This one is the pumpkin with multi-colored eyes:


You can find place with source code, circuit diagram and some details here: https://github.com/jumbleview/pumpkin


This one is lighted ghost image.


Source code and circuit diagram is here: https://github.com/jumbleview/casper

Some additional description published on "Instructables".

Below is the video of three projects (two mentioned above plus my old project: "Moon with the Bat silhouette") installed in our home window.





Saturday, December 31, 2016

In the Moonlight

This is the moon simulator with bat silhouette which I made as a decor for this  Halloween.


The core part of the project is twelve backlight white LED modules ( I bought them from the adafruit). LEDs are controlled by Atmega328 micro controller. The schematic of the project is fairly simple:




Adm here you can see project assembly with some internals visible:




Twelve LED modules put in the middle of sandwich made out of two Plexiglas  sheets attached with the help of Velcro strips.  Paper Bat attached to the front of the moon with Velcro as well as front and back cardboard shields .

 Program to control the device is short enough to be present entirely in this blog:

/*
 * moon.c
 * Created: 10/22/2016 1:14:19 PM
 *  Author: jumbleview
 */ 
#include <avr/io.h>
#include <avr/interrupt.h>
#include "./pt-1.4/pt.h" // http://dunkels.com/adam/pt/

typedef enum {OUT_LOW, OUT_HIGH} OutputLevel;
volatile uint16_t pulses;

#define pinOut(port, bit, outLevel) \
(DDR##port |= (1 << ( DD##port##bit)));\
switch(outLevel) \
{\
 case OUT_LOW: (PORT##port &= ~(1 << (PORT##port##bit))); break;\
 case OUT_HIGH: (PORT##port |= (1 << (PORT##port##bit))); break;\
}
void clearAll()
{ // set all outputs low
 DDRB = 0xFF; PORTB = 0;
 DDRC = 0xFF; PORTC = 0;
 DDRD = 0xFF; PORTD = 0;
}
void activateTimer0()
{
 cli();
 pulses = 0;
 TCCR0A=0; // Normal operation
 TCCR0B=2; // f divider 64  : about 2 ms for interrupt ...
 TIMSK0 = 1; // for system clock f= 1Mhz (CKDIV8 set)
 sei();
}
struct pt wpt; // protothread descriptor

int moonlight(struct pt* mlpt)
{
 PT_BEGIN(mlpt);  // New Moon 
  PT_YIELD(mlpt); 
   pinOut(C,5,OUT_HIGH); pinOut(B,1,OUT_HIGH);
  PT_YIELD(mlpt);
   pinOut(D,0,OUT_HIGH); pinOut(B,2,OUT_HIGH);
  PT_YIELD(mlpt);
   pinOut(D,1,OUT_HIGH); pinOut(B,0,OUT_HIGH);
  PT_YIELD(mlpt); // First Quarter   
   pinOut(D,2,OUT_HIGH); pinOut(D,7,OUT_HIGH);
  PT_YIELD(mlpt);
   pinOut(D,3,OUT_HIGH); pinOut(D,6,OUT_HIGH);
  PT_YIELD(mlpt);
   pinOut(D,4,OUT_HIGH); pinOut(D,5,OUT_HIGH);
   pinOut(C,0,OUT_HIGH); pinOut(C,1,OUT_HIGH);
  PT_YIELD(mlpt);  // Full Moon + Red Eyes
  PT_YIELD(mlpt); 
   pinOut(C,0,OUT_LOW); pinOut(C,1,OUT_LOW);
   pinOut(C,5,OUT_LOW); pinOut(B,1,OUT_LOW);
  PT_YIELD(mlpt);
   pinOut(D,0,OUT_LOW); pinOut(B,2,OUT_LOW);
  PT_YIELD(mlpt);
   pinOut(D,1,OUT_LOW); pinOut(B,0,OUT_LOW);
  PT_YIELD(mlpt);  // Third Quarter
   pinOut(D,2,OUT_LOW); pinOut(D,7,OUT_LOW);
  PT_YIELD(mlpt);
   pinOut(D,3,OUT_LOW); pinOut(D,6,OUT_LOW);
  PT_YIELD(mlpt);
   pinOut(D,4,OUT_LOW); pinOut(D,5,OUT_LOW);
  PT_RESTART(mlpt); // New Moon
 PT_END(mlpt);
}
ISR(TIMER0_OVF_vect)
{
 pulses++;
 uint16_t mod =pulses%750;
 if (mod == 0){
  moonlight(&wpt);  
 }
}
int main(void)
{
 PT_INIT(&wpt); // initiate protothread structure...
 clearAll();
 activateTimer0();
    while(1) { }
}

To  compile and load program into the controller memory I used Atmel Studio 6.1. Code includes three header files.

  • File "io.h" contains definitions to work with input/output (comes with Studio installation)
  • File "interrupt.h" is defining interrupt vectors (comes with Studio installation)
  • File "pt.h" is Adam Dunkels implementation of protothread library.
Protothred library deserves some additional notes. I included it to my programming  tool box recently and nowadays use it any time I need to program embedded devices in "C ". It provides multitasking framework and allows to code device states efficiently and conveniently.  I highly recommend to try it for any programmer  who works with micro-controllers in "C".

As you can see device is simple to made and program. Some additional details you can find in my "Instructables" project.

The only problem I see is relatively high project price. Mostly it is the price of LED modules ($2.50 for each). Nothing could be done here. To gain some additional benefits I decided to substitute  Bat with Reindeer so the device is quite usable  as winter decor: