Showing posts with label Electro. Show all posts
Showing posts with label Electro. Show all posts

Monday, January 23, 2012

Understanding Servo Motors

"Servo motors have three wires: power, ground, and signal. The power wire is typically red, and should be connected to the 5V pin on the Arduino board. The ground wire is typically black or brown and should be connected to a ground pin on the Arduino board. The signal pin is typically yellow, orange or white and should be connected to a digital pin on the Arduino board. Note servos draw considerable power, so if you need to drive more than one or two, you'll probably need to power them from a separate supply (i.e. not the +5V pin on your Arduino). Be sure to connect the grounds of the Arduino and external power supply together."

I bought my Servo motors from InMotion who imported them from SparkFun.

It's easy to control a Servo with Arduino using the libraries distributed with the Arduino IDE, but with only three wires, how is that controlled?

A servo motor expects a PWM signal with a very specific period and duty time.
Usually a 20ms period and a 1ms to 2ms as duty time.

On a regular servo the minimal duty cycle means a 0º position, the maximum corresponds to 180º and half way equals 90º.
On a full rotation servo, each period to motor rotates acording to the duty cycle.
Under 1,5ms rotates counter-clockwise and above 1,5ms rotates clockwise.

Controlling a servo from Arduino:

To test the theoretical knowledge I tried to run this simple sketch:

void setup() {
  // put your setup code here, to run once:
  pinMode(9, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly: 
  digitalWrite(9, HIGH);
  delay(2);
  digitalWrite(9, LOW);
  delay(18);
}

Worked fine!


But for the best control, why not use a tested and proven library?

So I used Arduino's IDE Sweep example that rotates the Servo from side to side (0 to 180 degrees and back) using a class designed for that purpose.
The Sweep example seems simple and self-explanatory for me to give more detail about it.

In my full rotation servo I noticed that it rotated more going counter-clockwise than when moving clockwise.

I don't know why does it happen...

Thursday, January 19, 2012

Nokia 5110 LCD

I bought a SparkFun Nokia 5110 LCD through InMotion. Both sites have the datasheet and example documentation for how to use it.
Adafruit also sells this and documents its use with another excellent Ladyada tutorial.

Here it is with connectors already soldered:


The soldering is pretty bad. Maybe I should buy a new tip for my soldering iron...

This screen supports direct connection to an Arduino (5V), but in doing so we push it to the datasheet defined limits, so to it is best to reduce all signals to a confortable 3.3V.

My Arduino Duomilanove only outputs 5V signals, so in order to translate those signals to 3.3V, the simplest way is to use a Voltage Divider.
I used this site to calculate the best resistor values to use for this case (10kOhm and ~5kOhm).
Adafruit offers a free level shifter with the LCD that can be used as a more efficient Voltage Divider.

Also to light up the 4 leds used as backlight I used a 22Ohm resistor, so that I could connect to a 5V signal on the Arduino in order to control them with PWM.


And here it is using the Arduino example code 2:

Wednesday, January 18, 2012

Electronics Stores

Here are my favorite electronics stores:

Portuguese:

Aquario (Porto) - Nice collection of generic electric components, ICs and tools, but not for hobbyist electronics, like sensors, motors or other robotics components;

InMotion (On-line) - Nice catalog with products from SparkFun and Pololu, etc. Usually they offer the shipping costs at Christmas. It is possible to order SparkFun items by mail that aren't on their catalog.

PTRobotics (On-line) - Like InMotion, they have a very good catalog of products.

Found a link on a forum with their own list: LusoRobotica

Worldwide:

Sparkfun (US) - Best generic store, but the shipping costs can be very high for a direct order. The most common items can be found in distributors around the world.

Adafruit (US) - Main competitor for SparkFun. Can't tell wich is best.

Pololu (US) - Best store for motors and related products, shipping costs have the same problem as SparkFun;

eBay stores (mostly China) - Sometimes we can find great deals with free shipping from high trust rated sellers.

Friday, January 13, 2012

Electronics Components

Here I'll be updating some links about electronics components, as a wiki with the best information I can find.

- Zener Diodes

Thursday, November 17, 2011

First Hack - The LED Strip

Finally finished my first hack.

I needed a light for my kitchen counter, so I ordered a LED Strip from eBay and hacked an AC adapter to include an ON / OFF button and to connect it to mains without using a power socket.

So here's the theoretical work:

To cover the surface of my counter I used 48 segments of the LED strip (about 2 meters). Each segment has 3 white SMD leds (type 3528) and a 150 Ohm resistor. For it to work it needs a 12V power source with sufficient current output.
After learning from [ladyada] about these strips I figured that the theoretical current each segment needs to function at it's maximum is 16 mA. That is:
12V total - (3 leds * 3.2V) / 150R = 0.016A

For the total 48 segments that's 768 mA, resulting in under 10W lighting!!!
For that I bought a SMPS AC adapter in order to guarantee the regulated 12V while using that much current. An average (unregulated) AC adapter wouldn't provide nor the 12V neither near the maximum 1A stated. [ladyada] also shed me some lights on that matter.

White LED StripSuitable AC AdapterThe best switch button I could find

For the practical work:

As you will see for yourself, the tools weren't exactly the best suited for the job: a kitchen knife to cut, a soldering iron to remove plastic, a hammer and a nail to open holes...

The innards of a power outletMains power derivationAdhesive cable duct

In order to cut the space for the switch button in the AC adapter, my kitchen knife wasn't enough, so I used my soldering iron to heat a metal needle and a kind of a thick clip used by stores to keep shirts folded in it's package. Even so it was a hard work.

Pierced top cover from the AC AdapterCreating the space for the switch buttonThe working conditions

Then I just needed to solder the switch button and the wire to the board and cover it all with electrical tape.

The final cutConnecting the switch buttonThat's a wrap

And there we have it!
Our working LED Strip!


Tuesday, September 6, 2011

Project: NiteLite

Problem: I would like to be able to go to my kitchen at night without having to turn on the fluorescent ceiling lamp for a short stay.

Solution:
I will try to build a night light with a motion sensor to light some leds and a luminosity sensor to turn the device on only in the dark.

For me to understand better about circuitry I will avoid using micro-controllers as well.

More details in a few days...

Monday, July 25, 2011

PIR Motion Sensor

Finally got some time (and patience) to try out one of the first electronic components I bought. The SparkFun PIR Motion Sensor.

It's use on Arduino is quite simple. When a motion is detected the black (the GND wire is brown on this sensor!) wire carries a LOW state.

I tested it based on what I found on this site .

Providing 5V from the Arduino to the PIR might make it unstable, as the board has a 5V regulator in it. So it is better to connect it to a 12V power source. The signal will come out with a 5V limit, so you don't need to worry about ruining your Arduino.


Anyhow, you'll see it being used in a personal project very soon (I hope)!

Tuesday, June 7, 2011

7 Segment Display

So now it's time to control a 7 Segment Display.

I got mine from Sparkfun.
There you can find the datasheet as well as some examples of how to use.



It has 16 pins and for you to be able to use all digits, it multiplexes the anodes. There's a cathode for each pin and 8 anodes for the digit segments and the following dot.
Because of these common anodes, we can only light up one digit at a time for them to show different results.

To control it I used an Arduino connected to a Shift Register. As its specs are 2.1V on 20mA, for the 5V output from the Arduino we need 150 Ohm resistors.
I only have 3 at the moment, and there are 7 output pins on the display to connect to.

So I used some serial (100 Ohm + 47 Ohm) and parallel (220 Ohm + 470 Ohm).
If you need to refresh your theory on calculating resistors or reading the values, hail to Wikipedia.

This is the simplified circuit, without resistors, so that it is easier to view what the connections are.

The next photos are for the complete setup, but can be somewhat confusing. Sorry about that...





The basic usage of this setup is to control what pins from the shift register sink current from the displays anodes and which digit is lit on a given moment with the Arduino.

And now for some code:
//
// thylux
// 7-Segment 4-digit display control using a 74HC595N shift register
//
// This driver only supports writing the digits for the moment
// As the Shift Register controls the anodes (sink current), we need to set the outputs as LOW to turn a light ON

// Display definitions
//
//  __A__
// |     |          Vcc < 2.1V, 20mA --> R = 150 Ohm
// F     B          
// |__G__|
// |     |
// E     C          DIG1 = 1, DIG2 = 2, DIG3 = 6, DIG4 = 8, COLON_P = 4, APOSTROPHE_P = 10
// |__D__|        A = 14, B = 16, C = 13, D = 3, E = 5, F = 11, G = 15, DP = 7, COLON_N = 12, APOSTROPHE_N = 9
//

// Shift Register definitions
//
//   VCC Q0  DAT ENB LAT CLK RES OVR
// ---+---+---+---+---+---+---+---+---        Vcc < 5V, 70mA --> R = 72 Ohm
// |                                  |        Qn < 20mA
// D             74HC595N              |
// |                                  |
// ---+---+---+---+---+---+---+---+---
//   Q1  Q2  Q3  Q4  Q5  Q6  Q7  GND
//

// Display connection to Shift Register (direct breadboard connections)
// Q1 -> B, Q2 -> G, Q3 -> A, Q4 -> C, Q5 -> D, Q6 -> F, Q7 -> E

// Character mapping
//                 HBGACDFE
byte chars[11] = {B10100000, // 0
          B10110111, // 1 
          B10001010, // 2
          B10000011, // 3
          B10010101, // 4
          B11000001, // 5
          B11000000, // 6
          B10100111, // 7
          B10000000, // 8
          B10000101, // 9
                  B11111111};// blank

// Arduino pin definition
int _LATCH = 12;
int _CLOCK = 11;
int _DATA = 10;
int _DIG1 = 7;
int _DIG2 = 6;
int _DIG3 = 5;
int _DIG4 = 4;

#define _BUFF_SIZE   4
#define _SHOWTIME    50

// initializes the buffer with empty characters
byte buffer[_BUFF_SIZE] = { chars[10], chars[10], chars[10], chars[10] };
int digits[_BUFF_SIZE] = { _DIG1, _DIG2, _DIG3, _DIG4 };

void setup()
{
  pinMode(_LATCH, OUTPUT);
  pinMode(_CLOCK, OUTPUT);
  pinMode(_DATA, OUTPUT);

  // TODO: Can a 555 reduce these 4 pins to 1?
  pinMode(_DIG1, OUTPUT);
  pinMode(_DIG2, OUTPUT);
  pinMode(_DIG3, OUTPUT);
  pinMode(_DIG4, OUTPUT);
    
  Serial.begin(9600);
}

void loop()
{
  for(int i = 0; i < 100; i++)
  {
    fillBuffer(i);
    for(int j = 0; j < _SHOWTIME; j++)
      writeScreen();
  }
  
  // Clean the latch for the next execution
  // TODO : needed???
  digitalWrite(_LATCH, LOW); // Begin Write
  shiftOut(_DATA, _CLOCK, LSBFIRST, chars[10]);
  digitalWrite(_LATCH, HIGH);  // End Write
}

void fillBuffer(int num)
{
  bool cleanChar = false;
  
  if(num==0)
  {
    buffer[_BUFF_SIZE - 1] = chars[0];
    return;
  }
    
  for(int i = _BUFF_SIZE - 1; i >= 0; i--)
  {
    if(num==0 && cleanChar) // We need to make sure that all the unused buffer positions are cleaned
      buffer[i] = chars[10];
    else
    {
      buffer[i] = chars[num > 9 ? num%10 : num];
      num/=10;
      cleanChar = true;
    }
  }
}

void writeScreen()
{
  for(int i = 0; i < _BUFF_SIZE; i++)
  {
    for(int i = 0; i < _BUFF_SIZE; i++)
      // TODO: find if it is possible to turn HIGH and LOW an entire PORT
      digitalWrite(digits[i], LOW);
      
    /*
    shiftOut(dataPin, clockPin, bitOrder, value)

    dataPin:     the pin on which to output each bit (int)
    clockPin:     the pin to toggle once the dataPin has been set to the correct value (int)
    bitOrder:     which order to shift out the bits; either MSBFIRST or LSBFIRST. (Most Significant Bit First, or, Least Significant Bit First)
    value:         the data to shift out. (byte) 
    */
    
    digitalWrite(_LATCH, LOW); // Begin Write
    shiftOut(_DATA, _CLOCK, LSBFIRST, buffer[i]);
    digitalWrite(_LATCH, HIGH);  // End Write
    
    digitalWrite(digits[i], HIGH);
    
    delay(3);
  }
}

I believe that this code could be more efficient (a quick side note - Performant isn't a word), so I'll look up ways to make it better. As a proof of concept, works just fine!

Monday, April 25, 2011

Arduino Standalone

After setting a Arduino on a Breadboard I also needed to be able to make work without a computer or an Arduino Board to provide power.

The ATMega needs a 5V power source, and I want to be able to power it on any regular wall wart. How can this be done?

Small electronics need some kind of rectifier to take the Alternate Current (AC) you get in your house outlets (220V in most of europe) to something as small as 5-12V of Direct current (DC) (if you want to know more about AC and DC you can read the 'War of Currents' article on Wikipedia).

To be able to ensure a smooth 5V DC to the circuit, I used a 7805 rectifier. In order to use it correctly you need a diode and two capacitors. Here's the schematic I used.

This rectifier has an input limit of 40V DC (but it is recommended to use from 7 to 12V), so we still need an AC-DC adapter capable of providing the recommended input to the 7805.

To test it all, I connected a LED to the Arduino running a Blink example:

Sunday, April 17, 2011

Breaduino

In order to use the Arduino IC on a real board, we need to learn how to use it.
There's a common type of Arduino configuration for this called Breaduino (derived for Arduino on a Breadboard).

What I want to use is the minimal configuration, in order to avoid buying an external crystal oscillator, knowing that it is possible to use the IC's internal oscillator.

These oscillators are what sets the pace for a circuit. The faster the oscillator can go, the faster can the IC make calculations.

My Arduino is a Duemilanove an has an ATMega328p IC. In the datasheet it is stated that we can use an external oscillator up to 20 MHz (for Arduino we should use one at 16 MHz). The internal oscillator runs at 8 Mhz, but these frequencies can be divided by 8 using configuration (I'll write more about it in the end).

Once again the Arduino site has very good references and tutorials:
- Arduino To Breadboard
- Standalone
- Disabling Auto Reset (You'll need this one, even not being mentioned on the above tutorials)

If you look for the 'Minimal Circuit (Eliminating the External Clock)' sections you'll find an illustrated guide on how to configure the Arduino IDE and to connect the IC to the breadboard for both burning the bootloader and programming the IC.

After reading all of these and much more, I still couldn't burn a bootloader for using the internal oscillator on the ATMega328. Because of that I read and learned about understanding the configurations of the IDE, programming the ATMega by command line using AVRdude, and setting the fuses (configuration of the IC) in order to configure its behavior.

So why couldn't I burn the bootloader using the Minimal Circuit?
All my ATMega came preloaded with the regular Arduino Bootloader for use with the Arduino Board. That way they are configured to work with an external 16 MHz crystal.
So, because of that, the ATMega that I was trying to burn a bootloader into wasn't working. It needed the external crystal as configured for me to be able to burn a different bootloader.

Some of the errors I've seen because of this (both on Arduino IDE and running avrdude by command line):
- avrdude: Yikes! Invalid device signature;
- avrdude: Device signature = 0x00000000;
- avrdude: Expected signature for ATMEGA328P is 1E 95 0F;
- avrdude: stk500_getsync(): not in sync: resp=0x00;
- avrdude: stk500_getsync(): not in sync: resp=0x15;

Well, I had to buy a 16 MHz crystal after all.

To sum it up, what I had to do was:
1) In the \hardware\arduino\boards.txt add the breadboard settings below
##############################################################

atmega328bb.name=ATmega328 on a breadboard (8 MHz internal clock)

atmega328bb.upload.protocol=stk500
atmega328bb.upload.maximum_size=30720
atmega328bb.upload.speed=57600

atmega328bb.bootloader.low_fuses=0xE2
atmega328bb.bootloader.high_fuses=0xD8
atmega328bb.bootloader.extended_fuses=0x07
atmega328bb.bootloader.path=atmega
atmega328bb.bootloader.file=ATmegaBOOT_168_pro_8MHz.hex
atmega328bb.bootloader.unlock_bits=0x3F
atmega328bb.bootloader.lock_bits=0x0F

atmega328bb.build.mcu=atmega328p
atmega328bb.build.f_cpu=8000000L
atmega328bb.build.core=arduino
Note that these settings are not the same as downloaded with breadboard.zip from the Arduino site;

2) On Arduino IDE, load the ArduinoISP sketch of the Examples tab to the Arduino Board;

3) Set the hardware as in the images on the ArduinoToBreadboard tutorial (with the external crystal). Also you will need to disable the Auto-Reset feature if your board has it (and Duemilanove does have it);

4) (Optional) I read the comments on the ArduinoISP sketch and it talks about some pins you can use to light up some status LEDs. I used them to help me understand what was happening;

5) Upload the ArduinoISP sketch (confirm that you have the correct board configured in the IDE - in my case 'Arduino Duemilanove or Nano w/ ATMega328');

6) Make sure once again that all hardware is well connected.

7) Select the ATMega328 on a breadboard (8MHz internal clock) and burn the bootloader 'w/ Arduino as ISP'. It will take a while.

8) Now that the bootloader is set, you can upload a sketch. Don't forget to remove the ATMega from the Arduino Board, so that the ATMega on the breadboard is the one used. Also, don't forget to connect only the VCC, GND, RX and TX pins (one of my mistakes was to leave the crystal connected and because of that I couldn't upload sketches);

[edit]
A tip about setting extended_fuses (efuse):
This fuse controls the brown out detector and it can influence the correct working of the controller if you use less than 5V to power it.
There are only 4 possible values for this fuse so the controller  might only read those 2 bits in the full 2 bytes reserved for the fuse.
If you can't burn a bootloader because the efuse doesn't match the expected efuse (like 0xFF != 0x07) it means that that kind of controller expects that bits 2 to 7 are the opposite of what you set (remember that they won't be really needed), so you might need to adjust the value for the fuse accordingly.

So here are the values you need with bits 2 to 7 ON and OFF:
OFF(1)       ON(0)       Meaning
0xFF   <->   0x07    =   Brown-out detection disabled
0xFE   <->   0x06    =   Brown-out detection at VCC=1.8V
0xFD   <->   0x05    =   Brown-out detection at VCC=2.7V (Arduino 5V default)
0xFC   <->   0x04    =   Brown-out detection at VCC=4.3V

Thursday, April 14, 2011

Saturday, April 2, 2011

New Project. BIG!

I have a new ambitious project in hands.
It involves much more that what I know now, but I'm confident that I'll be able to accomplish it!

I will use shift registers, RGB LEDs, Arduino on breadboard, 7 segment displays, etc.
And of course, all I learn will be posted here.

First step is to learn how to use the ATMega328 (Arduino IC) on a breadboard, so that I can use it on a board for the final 'product'.

Tuesday, March 29, 2011

What is PWM?

Here is a nice article on what is Pulse Width Modulation: PWM

Basically, with PWM you can simulate a voltage by turning the pin on and off (HIGH and LOW, 5V and 0V) according to a certain frequency.
The amount of time in a cycle that the pin is on and off (duty cycle) determines the resulting voltage between the pin and the component.

On Arduino, PWM values are output with analogWrite() using values between 0 and 255.

P.S.: Here's another great article about PWM that you should read.

Thursday, March 17, 2011

The Curious Case of Pull-Up / Push-Down Resistors

What are pull-up resistors? And push-down resistors?
While trying to find answers to these questions on-line, I could only find sources too advanced for me to understand (I'm still a newbie after all).

But only after coming across some phenomena while playing with my RGB LEDs, did I understand what's the idea.

You see, one might think that if a circuit is open (like a switch) that the potential (voltage) is 0V, but actually because of the static electricity in the environment, that isn't entirely true.
There are components that need so little energy to work, that they might be influenced by that electricity.

What happened to me was that while having a LED connected only to GND, when I touched the other lead, it would light up a little.
When I tried to use a push button in a circuit connecting only one end to an output pin and the other end to an input pin of the Arduino, the Arduino would read strange values either I did or didn't press the push button.

So, these pull-up / push-down resistors are to compensate for this extra energy, forcing the circuit to a stable state.

In the push button case, I had to use a resistor in parallel with the input pin of the Arduino, so that when the button isn't pressed, it would always read 0V (LOW).

The difference between pull-up and push-down is where you use that resistor, either connecting the component to GND or to the source.

I hope to have simplified it enough. What do you think?

Monday, January 24, 2011

RGB LED

This weekend I started playing with a RGB LED. This LEDs have 3 separate light emitting materials. One for red (R), other for green(G) e the last for blue(B).

As you can see in the image below, there are 4 leads. This LED has a common cathode, which means that all 3 parts share the connection to GND.


From up to down, we have Blue, Green, Ground and Red.

To start experimenting, I searched for a generic datasheet, as I don't know any reference for this LED. It recommended a 20mA current and stated that the typical voltages are 2.0V (Red) and 3.2V (Green and Blue).
As I was drawing power to the breadboard from the Arduino (only for power), I did the math for the resistors.

V=R.I
(5-2)/0.02=150 Ohm
(5-3.2)/0.02=90 Ohm

There where 3 150 Ohm resistors in the anti-static bag the LED came in, but I decided to use 100 Ohm resistors for green and blue.

So, the simplest test was to light each one at a time:

Check!
Check!
Check!

Next step, how about lighting all at once?
It would be nice, but there was a problem. When I disconnected the GND from the breadboard, I accidentally let it touch the lead for the red color. Without a resistor to limit the current passing at the moment, it burned out in a second.

So what could I do with a 'limp led'? I tried to combine the green and the blue colors to see the effect, but I ended up getting a slightly lighter blue.
When I read the datasheet I noticed that the brightness (measured in candela) of the 3 colors isn't the same. It also looks like the blue color is more diffuse (spreads all around) as the green light appears more directional. I filmed it try to show what I mean, but the colors aren't very noticeable.



The good news is that I ordered a 100 RGB led pack on eBay, so if all goes well, I will try again soon.

One hint: I read that PWM is the way to go in order to combine colors...

P.S. The LEDs have arrived, all working and with some free resistors. Thank you giorgio11185!

Wednesday, January 12, 2011

Make: Presents

I like Collin Cunningham's videos a lot. They are fun and simple and give me motivation for my home projects.

Here's a compilation of some of his videos about the basics of electronics.

Saturday, January 8, 2011

Piezo 101

To learn how to use a Piezo Buzzer I followed this tutorial.
They say that piezos have polarity, but the one I have doesn't show what it is, or if it has any.

What is polarity?
It is best explained on Wikipedia, but basically it defines a single right way to connect a component to the circuit, depending on the direction of the current flow. Components like resistances don't have polarity, so they can be connected either way. Polarity matters for most electrical objects like diodes (LEDs are diodes) or speakers.


I couldn't find a datasheet to the exact name (PKM22EPP-40) and neither on the manufacturer (muRata) datasheets for similar components.
But after reading this I found the explanation for the reference name (not helpful...).

So I tried the program supplied using a 330K resistance so that I could test for polarity reducing the risk of burning the piezo.
It generated a very low sound either way I connected it.

With a 10K resistance, the sound is louder, but still kind of weird.
Then I tried 470 Ohm and 47 Ohm with the same results.

So I dropped the resistances, and the sound isn't much louder, but still as annoying.
And this piezo has no polarity after all.


(Something wrong with the processing of the video from Blogger that makes the sound out of sync...)

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

So for the next test I tried this example from Adafruit, and got better results. The sound is clearer, and not as annoying.

The basic difference from the previous example is the use of digitalWrite instead of analogWrite to the piezo.
But what difference does it make? Well that is [TO BE SEARCHED].

Saturday, December 4, 2010

Big LED Matrix

In my last post I built a 5x7 LED matrix. After reading this hackaday article, I decided to expand my LED matrix to the most.


In order to reuse the board I had to grow on the columns, which are 7 leds each.
So I soldered 7 more columns to a total of 12. With the existing 7 rows, I will need now 19 pins of the Arduino, the same as in the Jack-o-lantern (14+5), but my matrix totals 84 leds, against 70 of the mentioned article.


As I'm lighting by column, I can send a current of 20mA for the 7 leds to total the same safe 140mA to the Arduino.

In the previous post I also mentioned the issue when each pin of the Arduino can only support a 40mA current. To solve it we need to connect transistors to the matrix cathodes, for diverting that current to a real GND pin. That way, the Arduino pins that were connected to the cathodes will now connect to the base pin of each transistor, and the other pins will receive the total column current and send it to GND.
Notice that the GND pins can only support up to 200mA.


There are two types of transistors we can use in this case.
Here's the basic lecture I read on their differences.
In this case the difference will be how to program the Arduino. Using NPN transistors means we need to set the pin to HIGH to light a led column, an using PNP transistors the pin has to be LOW.

I wanted to use PNP transistors because that way I could save my NPN for other projects. But after some tests on finding the best resistor to attach to the base, I didn't achieve any satisfactory result, in comparison to the currents I could obtain using NPN transistors.

According to the math, I should be using 100 Ohm resistors for each line, and 2.2k Ohm resistors for the base of each transistor, but after some tests with a multimeter, those numbers were quite different from the reality.
I ended up using 47 Ohm for the lines and 1k Ohm for the transistors.
[WILL TRY TO UNDERSTAND THIS BETTER]

I used a flat ribbon for the wires to the Arduino. The male connector soldered on the board may look as a tidy way to use, but it's a nighmare to solder the wires, so I wouldn't recommend to use it for this kind of amateur project...

To finish the hardware I applied hot glue on the connections for isolation and fixation.


Now it's time for the software...

//
// Controlo de uma matriz de LEDs 12x7
// thylux
//
int L01 = 4;
int L02 = 6;
int L03 = 5;
int L04 = 8;
int L05 = 10;
int L06 = 12;
int L07 = 11;
int C01 = A5;
int C02 = A4;
int C03 = A3;
int C04 = A2;
int C05 = A1;
int C06 = A0;
int C07 = 0;
int C08 = 1;
int C09 = 2;
int C10 = 3;
int C11 = 7;
int C12 = 9;

void setup()
{
  // Positivos
  pinMode(L01, OUTPUT);
  pinMode(L02, OUTPUT);
  pinMode(L03, OUTPUT);
  pinMode(L04, OUTPUT);
  pinMode(L05, OUTPUT);
  pinMode(L06, OUTPUT);
  pinMode(L07, OUTPUT);
  // Negativos
  pinMode(C01, OUTPUT);
  pinMode(C02, OUTPUT);
  pinMode(C03, OUTPUT);
  pinMode(C04, OUTPUT);
  pinMode(C05, OUTPUT);
  pinMode(C06, OUTPUT);
  pinMode(C07, OUTPUT);
  pinMode(C08, OUTPUT);
  pinMode(C09, OUTPUT);
  pinMode(C10, OUTPUT);
  pinMode(C11, OUTPUT);
  pinMode(C12, OUTPUT);

  //Serial.begin(9600);
}

int freq = 1000 / 600; // Hz
void loop()
{
  //char debug[10];
  
  // Demo
  for(int i = 1; i <= 12; i++)
  {
      for(int j=0; j<7; j++)
      {
        light(i, (byte) 2^j);
        delay(100);
      }
        
      //pot = map(analogRead(A0), 0, 1023, 0, 500);
      //delay(pot);
    
      //sprintf(debug, "i:%d j:%d", i, j);
      //debug[9]='\0';
      //Serial.println(debug);
  }
  
  int i=0;
  while(i<10000)
  {
      writeSymbol('a');
      i++;
  }
  
  i = 0;
  while(i<10000)
  {
      writeSymbol('b');
      i++;
  }
}

void writeMessage(char* msg)
{
  for(int i = 0; i < sizeof(msg); i++)
    writeSymbol(msg[i]);
}

void writeSymbol(char chr)
{
  switch(chr)
  {
      case 'a':
      case 'A':
        light(1, B1111100);
        light(2, B0010010);
        light(3, B0010001);
        light(4, B0010010);
        light(5, B1111100);
        break;
      case 'b':
      case 'B':
        light(1, B1111111);
        light(2, B1001001);
        light(3, B1001001);
        light(4, B1001001);
        light(5, B0111110);
        break;
  }
}

// Ilumina os LED indicados na coluna
void light(int column, byte data)
{
  reset();
  
  switch(column)
  {
      case 1: digitalWrite(C01, HIGH); break;
      case 2: digitalWrite(C02, HIGH); break;
      case 3: digitalWrite(C03, HIGH); break;
      case 4: digitalWrite(C04, HIGH); break;
      case 5: digitalWrite(C05, HIGH); break;
      case 6: digitalWrite(C06, HIGH); break;
      case 7: digitalWrite(C07, HIGH); break;
      case 8: digitalWrite(C08, HIGH); break;
      case 9: digitalWrite(C09, HIGH); break;
      case 10: digitalWrite(C10, HIGH); break;
      case 11: digitalWrite(C11, HIGH); break;
      case 12: digitalWrite(C12, HIGH); break;
  }
  
  digitalWrite(L01, data & B0000001 ? HIGH : LOW);
  digitalWrite(L02, data & B0000010 ? HIGH : LOW);
  digitalWrite(L03, data & B0000100 ? HIGH : LOW);
  digitalWrite(L04, data & B0001000 ? HIGH : LOW);
  digitalWrite(L05, data & B0010000 ? HIGH : LOW);
  digitalWrite(L06, data & B0100000 ? HIGH : LOW);
  digitalWrite(L07, data & B1000000 ? HIGH : LOW);
  
  delay(freq);
}

void reset()
{
  digitalWrite(L01, LOW);
  digitalWrite(L02, LOW);
  digitalWrite(L03, LOW);
  digitalWrite(L04, LOW);
  digitalWrite(L05, LOW);
  digitalWrite(L06, LOW);
  digitalWrite(L07, LOW);
  
  digitalWrite(C01, LOW);
  digitalWrite(C02, LOW);
  digitalWrite(C03, LOW);
  digitalWrite(C04, LOW);
  digitalWrite(C05, LOW);
  digitalWrite(C06, LOW);
  digitalWrite(C07, LOW);
  digitalWrite(C08, LOW);
  digitalWrite(C09, LOW);
  digitalWrite(C10, LOW);
  digitalWrite(C11, LOW);
  digitalWrite(C12, LOW);
}

Note:
During my initial tests I couldn't understand why the columns connected to pin 0 (RX) and pin 1 (TX) were always HIGH.
I found later that it was caused by turning on Serial communication with Serial.begin().
The Serial was used to send debug information to the computer, so if you try to debug my program don't be alarmed by some row/column of leds not behaving as intended.

Friday, November 26, 2010

LED Matrix

After a very frail Pringles Led Matrix that kept falling apart, I turned myself to a perforated board.
Better restart on the basics...

So I built a new 5x7 LED Matrix:

(Yes, this newbie is soldering on the wrong side of the board...
For all the other newbies that might let this one pass, those circles around the holes are to help soldering the components and should be on the lower side.)

I chose to use 7 anode rows and 5 cathode columns, for no particular reason.

To test the connections I used a 9V battery and a 220 Ohm resistor. That creates a current of 27mA during the test. My Leds support 30mA max, so it's fine for testing purposes.


As this matrix will be controlled by an Arduino, the circuit voltage will be 5V. So I soldered 100 Ohm resistors to the columns, so that at any given time the lit LED closing the circuit receives the datasheet recommended 20mA at 5V. I chose to connect the resistors with the columns because that way I would only need 5 resistors. I could connect them to the rows, as they would have the same effect on the circuit.


In order to connect the rows without touching the columns, I use a screwdriver to help me bend the ends.


This circuit has 12 ends, and all must connect to the Arduino. The simplest form to connect them is by linking each end to an Arduino pin. As the resulting circuit is still very frail and hard to manage, and I didn't have enough parts to make a better solution, I connected the Arduino to a breadboard so I could test the circuit.
You will notice a potentiometer also connected to the Arduino. I used it to control the refresh rate of the matrix, by defining the value passed to the delay function between each pass.


The hardest part was to connect the circuit to the breadboard, because I had very little space to maneuver the LEDs ends below the board. Also I only had some already cut wires (in groups of 5 for each length) for use with a breadboard, that are not fit for this kind of connections. As you can see I had to use two wires with claw ends for the two remaining pins. Connected to those claws are ends I had to cut of broken LEDs, in order to connect to the breadboard below.



Well now to program the Arduino:
//
// Controlo de uma matriz de LEDs 5x7
// thylux
//

void setup() 
{
// Positivos
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
// Negativos
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);

//Serial.begin(9600);
}

int freq = 1000 / 600; // Hz
int b[5][7];
int pot = 0;

//   2   3   4   5   6   7   8 
// -----------------------------
// |7 1|6 1|5 1|4 1|3 1|2 1|1 1| 9
// ----------------------------- 
// |7 2|6 2|5 2|4 2|3 2|2 2|1 2| 10
// -----------------------------
// |7 3|6 3|5 3|4 3|3 3|2 3|1 3| 11
// -----------------------------
// |7 4|6 4|5 4|4 4|3 4|2 4|1 4| 12
// -----------------------------
// |7 5|6 5|5 5|4 5|3 5|2 5|1 5| 13
// -----------------------------

void loop() 
{
//char debug[10];

// Demo
for(int i = 1; i <= 5; i++)
{
for(int j = 1; j <= 7; j++)
{
light(i, j);
pot = map(analogRead(A0), 0, 1023, 0, 500);
delay(pot);

/*sprintf(debug, "i:%d j:%d", i, j);
debug[9]='\0';
Serial.println(debug);*/
}
}

int i=0;
while(i<1000)
{
write('a');
i++;
}
}

void write(char chr)
{ 
switch(chr)
{
case 'a':
case 'A':
b[0][0]=1; b[1][0]=1; b[2][0]=1; b[3][0]=1; b[4][0]=1;
b[0][1]=1; b[1][1]=0; b[2][1]=0; b[3][1]=0; b[4][1]=1;
b[0][2]=1; b[1][2]=0; b[2][2]=0; b[3][2]=0; b[4][2]=1;
b[0][3]=1; b[1][3]=1; b[2][3]=1; b[3][3]=1; b[4][3]=1;
b[0][4]=1; b[1][4]=0; b[2][4]=0; b[3][4]=0; b[4][4]=1;
b[0][5]=1; b[1][5]=0; b[2][5]=0; b[3][5]=0; b[4][5]=1;
b[0][6]=1; b[1][6]=0; b[2][6]=0; b[3][6]=0; b[4][6]=1;

}

for(int i = 1; i <= 5; i++)
{
for(int j = 1; j <= 7; j++)
{
if(b[i-1][j-1] == 1)
light(i, j);
}
}
}

// Ilumina apenas o LED indicado de acordo com a posicao na matriz
void light(int line, int column)
{
reset();

switch(column)
{
case 1: digitalWrite(2, HIGH); break;
case 2: digitalWrite(3, HIGH); break;
case 3: digitalWrite(4, HIGH); break;
case 4: digitalWrite(5, HIGH); break;
case 5: digitalWrite(6, HIGH); break;
case 6: digitalWrite(7, HIGH); break;
case 7: digitalWrite(8, HIGH); break;
}

switch(line)
{
case 1: digitalWrite(9, LOW); break;
case 2: digitalWrite(10, LOW); break;
case 3: digitalWrite(11, LOW); break;
case 4: digitalWrite(12, LOW); break;
case 5: digitalWrite(13, LOW); break;
}

pot = analogRead(0);
if(pot <= 0)
pot = 1;

pot = 1000/(600+(400/pot));
Serial.println(pot);

delay(pot);
}

void reset()
{
for(int i = 2; i<=8; i++)
digitalWrite(i, LOW);
for(int i = 9; i<=13; i++)
digitalWrite(i, HIGH);
}


This is just a basic program to try out the matrix. It lights only 1 LED at any given time and defines a very high refresh rate, so that to our eyes it would seem that all LEDs are on at the same time (persistance of vision - POV).
We use digitalWrite() to define if the pin(i) will provide 5V (HIGH) or act as GND - 0V (LOW).
To light a LED we need to HIGH the anode controlling pin and to LOW the cathode controlling pin.
With analogRead() we can read a number between 0 and 1023 from an analog pin, and with a potentiometer connected to it, we can physically control variables, as the delay between the lighting of a LED. For a friendlier range of values there is the map() function.

So after some programming this is the end result:



After some research for other Led Matrices on the web I found an interesting tutorial on hackaday. Now I will try to use more Leds on my matrix to make the best use of Arduino.
But there are some things to take into consideration...

My Led Matrix works because I'm only lighting ONE led a a time. If I tried to light more than two Leds in the same row/column at the same time I would burn my Arduino.
As you can see in the datasheet, each pin can only support 40mA. In lighting 1 Led, in this matrix, it creates a current of 20mA (as defined above). With 2 Leds lid, 40mA will run on the circuit.
As you probably can already tell, this current could be supplied by two different pins, but it would be received on another pin connected as output, or would use same input and different outputs. These pins are not real GND, only regular pins set at 0V to create the electron flow. And they can only support 40mA of it...

So to correct this issue I should be using transistors, but that I'll talk about in the next post (part 2).