Arduino 12: Transistors

Several people wrote in about my earlier post concerning relays, noting that it’s a bit risky to control a relay from the Arduino as you can easily fry the IC chip. A  safer method is to use a transistor, which basically accomplishes the same thing (and more cheaply):it lets a small current control a much larger one. This lets you use the Arduino to turn large electric devices on and off when they are running off a large separate power supply.

There are two type of transistor: NPN (negative-positive-negative) and PNP.  The difference is whether you want to turn the transistor on with a signal that is a high voltage (5 V) or low (ground). NPN transistors are turned on with a high voltage, and that’s what we will use.

Transistors have three pins, with a plastic top with one side flattened. If you are looking at the flat side, the pins from left to right are called the collector, base and emitter. The middle pin, the base, is where you connect the control signal from the Arduino. The collector pin on the left is wired to the device, and the device must be connected to its own positive power supply terminal. The emitter pin on the right is connected to ground for the Arduino, AND to the ground of the outside power supply. The Arduino and the device being controlled must have a common ground.

To have the Arduino run a motor, first put the transistor in a breadboard. Connect the ground on the Arduino to the ground channel on the breadboard, and the ground channel to the emitter pin on the transistor. Wire pin 9 on the Arduino to the base pin of he transistor. Wire the collector to one of the motor terminals, then the other motor terminal to the positive terminal of a battery pack. Then wire the negative terminal of the battery pack back to the ground channel on the breadboard.

This code has the Arduino pulse the motor on and off at 1 second intervals.

int transistorPin = 9;

 

void setup(){

pinMode(transistorPin, OUTPUT);

}

 

void loop(){

digitalWrite(transistorPin, HIGH);

delay(1000);

digitalWrite(transistorPin, LOW);

delay(1000);

}

 

Michael Margolis’ “Arduino Cookbook”

I just bought a copy of Michael Margolis’ “Arduino Cookbook” from O’Reilly Press, and it almost makes this blog feel redundant. This is exactly what I’ve been looking for as a teacher – snippets of code to let you do just about anything you want with the Arduino board. I haven’t had time to go through it in depth, but if your priority is to get your project up and running rather than learning how to code from the Arduino reference webpage, this book is for you. Very highly recommended.

Arduino 11: A Character LCD

A character LCD makes user interaction with your projects a lot easier, but programming one can be a bit difficult. Luckily release 17 of the Arduino software has an excellent library, LiquidCrystal.h, which simplifies matters. The LCD must have a driver compatible with the Hitachi HD44780 for the library to work, so check your spec sheet. Such a display will have a 14-pin interface (16 if it is backlit). It’s nice to have the holes for the interface pins all in a line as in the diagram below, so that you can solder a 14 pin header straight across, and the display will neatly pop into a breadboard.

Pin Sym Function Pin Sym function
1 Vss Ground 9 D2 Data bit
2 Vdd +5V 10 D3 “”
3 VL Contrast 11 D4 “”
4 RS Data input 12 D5 “”
5 R/W Read/write-low 13 D6 “”
6 E Enable 14 D7 “”
7 D0 Data bit 15 backlight
8 D1 “” 16 backlight

Check your spec sheet for the pin numbering – the first hole isn’t always 1! Pins 1 and 2 go to ground and +5V to power the board. If your display has a backlight, pins 15 and 16 can go to ground and +5V as well. Pin 3 should go to the middle pin of a potentiometer, whose ends also go to ground and +5V, to control display contrast. All the other pins are directed to digital output pins on the Arduino. Pins 4, 5, and 6 are control pins, and 7 through 14 are data pins. The Arduino library can send data to the LCD in 4-bit mode, meaning it only needs LCD pins 11-14 (data bits 4,5,6 and 7). Therefore pins 7-10 on the LCD can be left unattached, freeing up Arduino pins for other uses.

Example

Note that in the schematic, pins D2, D3 etc refer to the digital output pins on the Arduino (not the data pins on the LCD as in the table above).  The only part used besides the LCD is a 10K potentiometer on pin 3 of the LCD for contrast control.

The program follows.

#include <LiquidCrystal.h>
int rs = 12;
int rw = 11; // or you could ground lcd pin11
int e = 10;
int d4 = 5;
int d5 = 4;
int d6 = 3;
int d7 = 2;
int row = 16;
int col = 2;
LiquidCrystal lcd(rs, rw, e, d4, d5, d6, d7);
void setup() {
   lcd.begin(col, row);
   lcd.print("hello, world!");
}
void loop() {

   for (int n=0; n<10; n++) {
      lcd.setCursor(0,1); //rows and columns start at 0
      lcd.print(n);
      delay(500);
   }
}

Programming Notes

The first line of your program is a call to the library:

#include <LiquidCrystal.h>

The following functions are in the LiquidCrystal library:

LiquidCrystal(rs, rw, e, d4, d5, d6, d7);

Where the arguments rs, rw, etc are the pin numbers on the Arduino that correspond to the specified pins on the LCD. This command goes right after the include statement, and before the void setup() statement. Note the rw pin must also be grounded.

lcd.begin(col, row);

sets the number of rows and columns on the display.

lcd.print(data);

prints the data to the LCD. Data can be a string in quotes, or a variable.

lcd.clear();

clears the lcd and moves the cursor to the top left corner.

lcd.setCursor(c,r);

moves the cursor to column c, row r (columns run 0-15, rows 0-1).

Arduino 10: Servos

A servo is a special-purpose motor. Instead of spinning continuously, a servo is meant to rotate to a specific angle (usually only between 0 and 180 degrees) and hold there. Servos are typically used as actuators, to control the throttle on an engine or the angle of a flap on a model plane, for example. Typically servos have three wires: red to +5V power, black to ground, and a white or colored control line for the angle information, which we would run to a digital output on the Arduino.

The Arduino software comes with a servo library that makes it easy to handle servos (though note that software version 16 and older will only control a servo on pins 9 or 10). A library is a pre-made set of small programs that someone wrote, which you can use just as if they were commands built-in to the programming language. To make use of a library, you have to include it in your program right at the beginning. In the Arduino program editor, from the top menu select Sketch > Import Library, and from the drop-down menu select Servo. This inserts the line in your program

#include <Servo.h>

The command #include < > does just what it says, it includes all the code form a given library in your program.  The name of the library goes in the angle brackets < >. Library file names always end in .h, like Servo.h does.

Example: Connect a servo, which we’ll simply call s, to digital pin 9 on the Arduino, and connect the +5V and ground pins to the servo as appropriate. Upload the following program.

#include <Servo.h>
Servo s;
void setup(){
   s.attach(9);
   s.write(0);
}
void loop(){
   for (int angle=1; angle<180;angle++){
      s.write(angle);
      delay(10);
   }
   for (int angle=180;angle>0;angle--){
      s.write(angle);
      delay(10);
   }
}

There are three commands in the servo library that are most useful. First,

Servo name;

declares a variable name for your servo “object”. This goes at the beginning of the program with your other variable declarations. Next in the setup function, use

name.attach(pinNumber);

where name is the name you gave your servo, and pinNumber is the digital pin to which you attached the servo. This is sort of like declaring a pin mode to be output. Finally

name.write(angle);

turns the servo to an angle between 0 and 180 degrees.

For a second example, control the servo with a potentiometer. Keep the servo attached as before. Now connect the middle pin of a 10K potentiometer to analog pin 0 on the Arduino, one end pin to +5V, and the other end to ground. As an error check, the program prints out the raw reading from the potentiometer, which should vary between 0 and 1023 as you turn it. Upload the following program:

#include <Servo.h>
Servo s;
int reading = 0;
int angle = 0;
int potPin = 0;
void setup(){
   s.attach(9);
   s.write(0);
   Serial.begin(9600);
}
void loop(){
   reading = analogRead(potPin);
   angle = map(reading, 0, 1023, 0, 179);
   Serial.println(reading);
   s.write(angle);
   delay(10);
}

Note the use of the map function.

var1 = map(var2, fromLow, fromHigh, toLow, toHigh);

If you have some data in var2 that can vary in the range fromLow to fromHigh, map will proportionally map the value to a new range between toLow and tohigh and store the result in var1. In this case, the potentiometer returns a value from 0 to 1023, but we want to map that to the servo range of 0 to 179 degrees.

Arduino 9: The H-Bridge

An H-Bridge is like an electric double-switch, or double-relay. A small current from the Arduino at one of two pins can turn on a much larger current at two other pins. This is useful for controlling two-state devices, like motors that you want to run both forwards and backwards. For this project I used an SN75441 H-bridge chip.

Example:

Have the Arduino read the state of a switch to control a high-voltage motor running forwards and backwards. Use a 9V battery to power the Arduino (remember to change the jumper pin), so Vin is 9V. Connect the two motor wires directly to the H-bridge chip pins labeled “Motor”, and connect both pins 4 and 5 of the H-bridge to ground.

Schematic:

D2, D3 and D4 are digital pins on the Arduino

Program:

int motorPin0 = 2;

int motorPin1 = 3;

int switchPin = 4;

int state = 0;

void setup() {

pinMode(motorPin0, OUPUT);

pinMode(motorPin1, OUTPUT);

pinMode(switchPin, INPUT);

}

void loop() {

state = digitalRead(switchPin);

switch(state) {

case 0:

digitalWrite(motorPin0, HIGH);

digitalWrite(motorPin1, LOW);

break;

case 1:

digitalWrite(motorPin0, LOW);

digitalWrite(motorPin1, HIGH);

break;

}

}

Note the use of the switch statement:

switch(variable){

case value1:

(code block here);

break;

case value2:

(code block here);

break;

case value3:

(code block here);

break;

default:

(code block here);

break;

}

Where variable can take on the values value1, value2, value3, etc. (which are usually integer values), and based on the value of variable, different code is run. The default option is run if the value of variable doesn’t match any of the other cases. The keyword break tells the program to jump to the end of the switch statement, skipping the code in between.

Arduino 8: Relays

A relay is a switch that allows a small current from the Arduino to turn on or off a device drawing a much larger current.  This is usually a concern if you want the Arduino to control an electric motor, which will typically want to draw more current than the Arduino can handle. Relays are the key to turning your Arduino into a controller for any motorized project, and are great fun in combination with any motorized construction kit like Lego, K’Nex or FischerTechnik. I bought a set of Fischertechnik Mechanic and Static kits with a grant a few years back, and combined with the Arduinos they make wonderful platforms for computer-controlled mechanical models, like working elevators and light-seeking robots.

Relays come in different shapes, but typically have four pins:   an input voltage Vin from a power supply, ground, a data pin to turn the relay on or off (this is what the Arduino does), and an output voltage pin to the device you want to control.  Buy a relay that can be controlled by 5V DC (the Arduino) – the output depends on what you want to control with it. Lots of larger motors want 12V DC or so, so get a relay that can handle a bit more than that. The relay should come with a spec sheet telling you which pin is which. If not, Google “relay spec sheet” and the part number, and you’ll probably find the document online.

Image made with Fritzing (http://fritzing.org/)

In this project we have the Arduino read the state of a pushbutton, and use that to turn a small DC motor on and off. You might wonder what’s the point – just wire the pushbutton to the motor power supply and forget the Arduino. The point is, the pushbutton can be replaced by any sensor, so the Arduino can use any input signal to trigger the motor.  Use a 9V battery to power the Arduino and motor, so it doesn’t have to run off the weaker supply delivered by the USB cable. This means you need to get a 9V battery clip (or wall power supply), and solder it to a 2.1mm center-positive plug to fit the Arduino power connector. The new Duemilanove board will automatically sense the power supply when connected, but older boards have a little jumper next to the USB connector that needs to be switched from USB to EXT.

In the picture, the top left pin of the relay is the data pin, going to pin 13; the bottom right pin is ground; the pin just right of that is Vin on the Arduino; and the bottom right pin goes to the motor’s + terminal. The other motor terminal goes to ground. The pushbutton has one terminal connected to +5V, the other connected both to digital input pin 2 and to a 10K resistor leading to ground.

Program:

int buttonPin = 2;
int relayPin = 13;
int state=0;
void setup() {
pinMode(buttonPin, INPUT);
pinMode(relayPin, OUTPUT);
}
void loop() {
state = digitalRead(buttonPin);
if (state==HIGH) {
digitalWrite(relayPin, HIGH);
} else {
digitalWrite(relayPin, LOW);
}
delay(100);
}

Arduino 7: While-loops

You often want to perform a set of code only while a certain condition is true. If the code is just a line or two, you can use an if-statement to handle it. However when a condition is driving most of the program, and you want a lot of code to depend on it, a while-loop is a conditional structure that’s easier to read.

while (condition) {…}

will repeat all the code in the curly braces as long as the logical condition is true. Usually this condition tests the state of a variable, so you need to update the state of the variable somewhere inside the curly braces for the condition check to work. However you also need to think about what happens when the condition fails. Then the code in the braces won’t run – but since the whole procedure keeps looping, presumably you still want to check the condition, because the condition might occur again. So remember to also update the state of the variable in the code outside the curly braces as well.

This sample program will flash LED’s on pins 8, 9 and 10 (each on a 220-ohm resistor to ground) as long as a light sensor (on analog pin 0) reads an input below some value in threshold, but turns them off when the room light is too bright. There’s also code to print out the output of the light sensor, since you need to tune the value of the variable threshold to fit your lighting conditions.

int light=0;
int sensorPin = 0;
int threshold = 100;
void setup() {
Serial.begin(9600);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
}
void loop() {
light = analogRead(sensorPin);
Serial.println(light);
while (light < threshold) {
for (int n=8; n<11; n++) {
digitalWrite(n, HIGH);
delay(100);
digitalWrite(n, LOW);
}
light = analogRead(sensorPin);
}
}