Tutorial: Arduino and Numeric Keypads – Part Two
Use larger numeric keypads in this addendum to chapter forty-two of a series originally titled “Getting Started/Moving Forward with Arduino!” by John Boxall – a series of articles on the Arduino universe. The first chapter is here, the complete series is detailed here. Any files from tutorials will be found here.
Welcome back fellow arduidans!
This is the second part of our numeric keypad tutorial – in which we use the larger keypads with four rows of four buttons. For example:
Again, the keypad looks like a refugee from the 1980s – however it serves a purpose. Notice that there are eight connections at the bottom instead of seven – the extra connection is for the extra column of buttons – A~D. This example again came from Futurlec. For this tutorial you will need the data sheet for the pinouts, so download it from here (.pdf).
To use this keypad is very easy, if you haven’t already done so, download the numeric keypad Arduino library from here, copy the “Keypad” folder into your ../arduino-002x/libraries folder, then restart the Arduino IDE.
Now for our first example – just to check all is well. From a hardware perspective you will need:
- An Arduino Uno or 100% compatible board
- A 4×4 numeric keypad
- An LCD of some sort. We will be using an I2C-interface model. If you are unsure about LCD usage, please see this tutorial
- If you don’t have an LCD – that’s ok. Our demonstration sketch also sends the key presses to the serial monitor. Just delete the lines referring to Wire, LCD etc.
- Keypad row 1 (pin eight) to Arduino digital 5
- Keypad row 2 (pin 1) to Arduino digital 4
- Keypad row 3 (pin 2) to Arduino digital 3
- Keypad row 4 (pin 4) to Arduino digital 2
- Keypad column 1 (pin 3) to Arduino digital 9
- Keypad column 2 (pin 5) to Arduino digital 8
- Keypad column 3 (pin 6) to Arduino digital 7
- Keypad column 4 (pin 7) to Arduino digital 6
- the extra column in the array char keys[]
- the extra pin in the array colPins[]
- and the byte COLS = 4.
/* Example 42.3 - Numeric keypad and I2C LCD
http://tronixstuff.wordpress.com/tutorials > chapter 42a
Uses Keypad library for Arduino
http://www.arduino.cc/playground/Code/Keypad
by Mark Stanley, Alexander Brevig */
#include "Keypad.h"
#include "Wire.h" // for I2C LCD
#include "LiquidCrystal_I2C.h" // for I2C bus LCD module http://bit.ly/eNf7jM
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
char keys[ROWS][COLS] =
{{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}};
byte rowPins[ROWS] = {
5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {
9, 8, 7, 6}; //connect to the column pinouts of the keypad
int count=0;
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
void setup()
{
Serial.begin(9600);
lcd.init(); // initialize the lcd
lcd.backlight(); // turn on LCD backlight
}
void loop()
{
char key = keypad.getKey();
if (key != NO_KEY)
{
lcd.print(key);
Serial.print(key);
count++;
if (count==17)
{
lcd.clear();
count=0;
}
}
}
And our action video:
Now for another example – we will repeat the keypad switch from chapter 42 – but allow the letters into the PIN, and use the LCD instead of LEDs for the status. In the following example, the PIN is 12AD56. Please remember that the functions correctPIN() and incorrectPIN() are example functions for resulting PIN entry – you would replace these with your own requirements, such as turning something on or off. You can download the sketch from here.
// Example 42.4 - Six-character keypad switch
// http://tronixstuff.wordpress.com/tutorials > chapter 42a
#include "Keypad.h"
#include "Wire.h" // for I2C LCD
#include "LiquidCrystal_I2C.h" // for I2C bus LCD module http://bit.ly/eNf7jM
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
char keys[ROWS][COLS] =
{{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}};
byte rowPins[ROWS] = {
5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {
9, 8, 7, 6}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
char PIN[6]={'1','2','A','D','5','6'}; // our secret (!) number
char attempt[6]={
0,0,0,0,0,0}; // used for comparison
int z=0;
void setup()
{
lcd.init(); // initialize the lcd
lcd.backlight(); // turn on LCD backlight
lcd.print(" Enter PIN...");
}
void correctPIN() // do this if correct PIN entered
{
lcd.print("* Correct PIN *");
delay(1000);
lcd.clear();
lcd.print(" Enter PIN...");
}
void incorrectPIN() // do this if incorrect PIN entered
{
lcd.print(" * Try again *");
delay(1000);
lcd.clear();
lcd.print(" Enter PIN...");
}
void checkPIN()
{
int correct=0;
for (int q=0; q<6; q++)
{
if (attempt[q]==PIN[q])
{
correct++;
}
}
if (correct==6)
{
correctPIN();
} else
{
incorrectPIN();
}
for (int zz=0; zz<6; zz++) // wipe attempt
{
attempt[zz]=0;
}
}
void readKeypad()
{
char key = keypad.getKey();
if (key != NO_KEY)
{
switch(key)
{
case '*':
z=0;
break;
case '#':
delay(100); // for extra debounce
lcd.clear();
checkPIN();
break;
default:
attempt[z]=key;
z++;
}
}
}
void loop()
{
readKeypad();
}
Now let’s see it in action:
So now you have the ability to use twelve and sixteen-button keypads with your Arduino systems.
Have fun and keep checking into tronixstuff.com. Why not follow things on twitter, Google+, subscribe for email updates or RSS using the links on the right-hand column, or join our Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other – and we can all learn something.
Tutorial: Arduino Port Manipulation
This is chapter forty-three of a series originally titled “Getting Started/Moving Forward with Arduino!” by John Boxall – a series of articles on the Arduino universe. The first chapter is here, the complete series is detailed here. Any files from tutorials will be found here.
[Updated 19/01/13]
In this article we are going to revisit the I/O pins, and use what is called “Port Manipulation” to control them in a much faster manner than using digitalWrite()/digitalRead().
Why?
Speed! Using this method allows for much faster I/O control, and we can control or read groups of I/O pins simultaneously, not one at a time;
Memory! Using this method reduces the amount of memory your sketch will use.
Once again I will try and keep things as simple as possible. This article is written for Arduino boards that use the ATmega168 or ATmega328 microcontrollers (used in Arduino Duemilanove/Uno, Freetronics Eleven/EtherTen, etc). My Arduino Mega is out at the moment, so I will update the tutorial for Mega users when it is replaced. This tutorial is not applicable to the Arduino DUE.
First, we’ll use the I/O as outputs. There are three port registers that we can alter to set the status of the digital and analogue I/O pins. A port register can be thought of as a special byte variable that we can change which is read by the microcontroller, therefore controlling the state of various I/O ports. We have three port registers to work with:
- D – for digital pins seven to zero (bank D)
- B – for digital pins thirteen to eight (bank B)
- C – for analogue pins five to zero (bank … C!)
Register C can control analogue pins seven to zero if using an Arduino with the TQFP style of ATmega328, such as the Nano or Freetronics EtherTen). For example:
It is very simple to do so. In void setup(), we use
DDRy = Bxxxxxxxx
where y is the register type (B/C/D) and xxxxxxxx are eight bits that determine if a pin is to be an input or output. Use 0 for input, and 1 for output. The LSB (least-significant bit [the one on the right!]) is the lowest pin number for that register. Next, to control a bank of pins, use
PORTy = Bxxxxxxxx
where y is the register type (B/C/D) and xxxxxxxx are eight status bits – 1 for HIGH, 0 for LOW. This is demonstrated in the following example:
// Example 43.1
// tronixstuff.wordpress.com/tutorials > chapter 43
// John Boxall - October 2011
// Digital 0~7 set to outputs, then on/off using port manipulation
void setup()
{
DDRD = B11111111; // set PORTD (digital 7~0) to outputs
}
void loop()
{
PORTD = B11110000; // digital 4~7 HIGH, digital 3~0 LOW
delay(1000);
PORTD = B00001111; // digital 4~7 LOW, digital 3~0 HIGH
delay(1000);
}
It sets digital pins 7~0 to output in void setup(). Then it alternates turning on and off alternating halves of digital pins 0~7.
At the start I mentioned that using port manipulation was a lot faster than using regular Arduino I/O functions. How fast? To test the speed of port manipulation vs. using digitalWrite(), we will use the following circuit:
… and analyse the output at digital pins zero and seven using a digital storage oscilloscope. Our first test sketch turns on and off digital pins 0~7 without any delay between PORTD commands – in other words, as fast as possible. The sketch:
// Example 43.1.1
// tronixstuff.wordpress.com/tutorials > chapter 43
// John Boxall - October 2011
// Digital 0~7 set to outputs, then on/off using port manipulation
void setup()
{
DDRD = B11111111; // set PORTD (digital 7~0) to outputs
}
void loop()
{
PORTD = B11111111;
PORTD = B00000000;
}
In the image below, digital zero is channel one, and digital seven is channel three:
Wow – check the frequency measurements – 1.1432 MHz! Interesting to note the longer duration of time when the pins are low vs. high.
[Update] Well it turns out that the extra time in LOW includes the time for the Arduino to go back to the top of void loop(). This can be demonstrated in the following sketch. We turn the pins on and off five times instead of once:
// Example 43.1.2
// tronixstuff.wordpress.com/tutorials > chapter 43
// John Boxall - October 2011
void setup()
{
DDRD = B11111111; // set PORTD (digital 7~0) to outputs
}
void loop()
{
PORTD = B11111111;
PORTD = B00000000;
PORTD = B11111111;
PORTD = B00000000;
PORTD = B11111111;
PORTD = B00000000;
PORTD = B11111111;
PORTD = B00000000;
PORTD = B11111111;
PORTD = B00000000;
}
And the results from the MSO. You can see the duty cycle is much closer to 50% until the end of the sketch, at which point around 660 nanoseconds is the time used between the end of the last LOW period and the start of the next HIGH:
Next we do it the normal way, using this sketch:
// Example 43.2
// tronixstuff.wordpress.com/tutorials > chapter 43
// John Boxall - October 2011
// Digital 0~7 set to outputs, then on/off using digitalWrite()
void setup()
{
for (int a=0; a<8; a++)
{
pinMode(a, OUTPUT);
}
}
void loop()
{
for (int a=0; a<8; a++)
{
digitalWrite(a, HIGH);
}
for (int a=0; a<8; a++)
{
digitalWrite(a, LOW);
}
}
And the results:
That was a lot slower – we’re down to 14.085 kHz, with a much neater square-wave output. Could some CPU time be saved by not using the for loop? We tested once more with the following sketch:
// Example 43.3
// tronixstuff.wordpress.com/tutorials > chapter 43
// John Boxall - October 2011
// Digital 0~7 set to outputs, then on/off using individual digitalWrite()
void setup()
{
for (int a=0; a<8; a++)
{
pinMode(a, OUTPUT);
}
}
void loop()
{
digitalWrite(0, HIGH);
digitalWrite(1, HIGH);
digitalWrite(2, HIGH);
digitalWrite(3, HIGH);
digitalWrite(4, HIGH);
digitalWrite(5, HIGH);
digitalWrite(6, HIGH);
digitalWrite(7, HIGH);
digitalWrite(0, LOW);
digitalWrite(1, LOW);
digitalWrite(2, LOW);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
digitalWrite(5, LOW);
digitalWrite(6, LOW);
digitalWrite(7, LOW);
}
and the results:
A small speed boost, the frequency has increased to 14.983 kHz. Hopefully you can now understand the benefits of using port manipulation. However there are a few things to take note of:
- You can’t control digital pins 0 and 1 (in bank D) and use the serial monitor/port. For example if you set pin zero to output, it can’t receive data!
- Always document your sketch – take pity on others who may need to review it later on and become puzzled about wchich bits are controlling or reading what!
// Example 43.4
// tronixstuff.wordpress.com/tutorials > chapter 43
// John Boxall - October 2011
// Fun with 8 LEDs on digital 7~0
void setup()
{
DDRD = B11111111; // set PORTD (digital 7~0)
// to output
}
byte a = B11111111;
byte b = B00000001;
byte c = B10000000;
byte e = B10101010;
void krider()
{
for (int k=0; k<5; k++)
{
for (int z=0; z<8; z++)
{
PORTD = b << z;
delay(100);
}
for (int z=0; z<8; z++)
{
PORTD = c >> z;
delay(100);
}
}
}
void onOff()
{
for (int k=0; k<10; k++)
{
PORTD = a;
delay(100);
PORTD = 0;
delay(100);
}
}
void invBlink()
{
for (int z=0; z<10; z++)
{
PORTD = e;
delay(100);
PORTD = ~e;
delay(100);
}
}
void binaryCount()
{
for (int z=0; z<256; z++)
{
PORTD = z;
delay(100);
}
PORTD=0;
}
void loop()
{
invBlink();
delay(500);
binaryCount();
delay(500);
krider();
delay(500);
onOff();
}
And here it is in real life:
Now to use the I/O pins as inputs. Again, it is very simple to do so. In void setup(), we use
DDRy = Bxxxxxxxx
where y is the register type (B/C/D) and xxxxxxxx are eight bits that determine if a pin is to be an input or output. Use 0 for input. The LSB (least-significant bit [the one on the right!]) is the lowest pin number for that register. Next, to read the status of the pins we simply read the byte:
PINy
where y is the register type (B/C/D).
So if you were using port B as inputs, and digital pins 8~10 were high, and 11~13 were low, PINB would be equal to B00000111. Really, that’s it!
Now for another demonstration using both inputs and outputs. We will use a push-wheel switch from Chapter 40 on our inputs (digital pins 8~11), and a seven segment LED display for output (on digtal pins 7~0 – segments dp then a~f). The following sketch reads the input from the switch, which returns 0~9 in binary-coded decimal. This value is then used in the function void disp() to retrieve the matching byte from the array “segments”, which contains the appropriate outputs to drive the seven segment LED display unit. Here is the sketch (download):
// Example 43.5
// tronixstuff.wordpress.com/tutorials > chapter 43
// John Boxall - October 2011
// inputs and outputs
byte segments[] = {
B01111110, B00110000, B01101101, B01111001, B00110011, B01011011, B01011111, B01110000, B01111111, B01111011};
// digital pins 7~0 connected to display pins dp,a~g
void setup()
{
DDRB = B00000000; // set PORTB (digital 13~8) to inputs
DDRD = B11111111; // set PORTD (digital 7~0) to outputs
}
void disp(int z)
{
PORTD = segments[z];
}
void loop()
{
disp(PINB);
delay(100);
}
And the ubiquitous demonstration video:
By now I hope you have an understanding of using port manipulation for your benefit. With a little effort your sketches can be more efficient in terms of speed and memory space, and also allow nifty simultaneous reading of input pins.
Have fun and keep checking into tronixstuff.com. Why not follow things on twitter, Google+, subscribe for email updates or RSS using the links on the right-hand column, or join our Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other – and we can all learn something.
Tutorial: Arduino and Numeric Keypads
Use numeric keypads with Arduino in chapter forty-two of a series originally titled “Getting Started/Moving Forward with Arduino!” by John Boxall – a series of articles on the Arduino universe. The first chapter is here, the complete series is detailed here. Any files from tutorials will be found here.
Welcome back fellow arduidans!
This is part one of two chapters that will examine another useful form of input – the numeric keypad; and some applications that hopefully may be of use. Here is the example we will be working with:
It seems quite similar to the keypad from a 1980s-era Dick Smith Electronics cordless phone. Turning the keypad over we find seven pins:
Personally I like this type of connection, as it makes prototyping very easy using a breadboard – you just push it in. Looking at the back the pins are numbered seven to one (left to right). My example was from Futurlec of all places. You can also find types that have solder pads. At this point you need to download the data sheet.pdf, as it shows the pinouts for the rows and columns. At first glance trying to establish a way of reading the keypad with the Arduino does seem troublesome – however the basic process is to ‘scan’ each row and then test if a button has been pressed.
If your keypad has more than seven pins or contacts – and the data sheet was not supplied, you will need to manually determine which contacts are for the rows and columns. This can be done using the continuity function of a multimeter (the buzzer). Start by placing one probe on pin 1, the other probe on pin 2, and press the keys one by one. Make a note of when a button completes the circuit, then move onto the next pin. Soon you will know which is which. For example, on the example keypad pins 1 and 5 are for button “1″, 2 and 5 for “4″, etc…
In the interest of keeping things simple and relatively painless we will use the numeric keypad Arduino library. Download the library from here, copy the “Keypad” folder into your ../arduino-002x/libraries folder, then restart the Arduino IDE.
Now for our first example. From a hardware perspective you will need
- An Arduino Uno or 100% compatible board
- A numeric keypad
- An LCD of some sort. We will be using an I2C-interface model. If you are unsure about LCD usage, please see this tutorial
- If you don’t have an LCD – that’s ok. After installing the keypad library, select File>Examples>Keypad>Examples>HelloKeypad in the IDE.
- Keypad row 1 to Arduino digital 5
- Keypad row 2 to Arduino digital 4
- Keypad row 3 to Arduino digital 3
- Keypad row 4 to Arduino digital 2
- Keypad column 1 to Arduino digital 8
- Keypad column 2 to Arduino digital 7
- Keypad column 3 to Arduino digital 6
/* Example 42.1 - Numeric keypad and I2C LCD
http://tronixstuff.wordpress.com/tutorials > chapter 42
Uses Keypad library for Arduino
http://www.arduino.cc/playground/Code/Keypad
by Mark Stanley, Alexander Brevig */
#include "Keypad.h"
#include "Wire.h" // for I2C LCD
#include "LiquidCrystal_I2C.h" // for I2C bus LCD module http://bit.ly/eNf7jM
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
// keypad type definition
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] =
{{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}};
byte rowPins[ROWS] = {
5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {
8, 7, 6}; // connect to the column pinouts of the keypad
int count=0;
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
void setup()
{
lcd.init(); // initialize the lcd
lcd.backlight(); // turn on LCD backlight
}
void loop()
{
char key = keypad.getKey();
if (key != NO_KEY)
{
lcd.print(key);
count++;
if (count==17)
{
lcd.clear();
count=0;
}
}
}
For the non-believers, here it is in action:
As you can see the library really does all the work for us. In the section below the comment “keypad type definition” we have defined how many rows and columns make up the keypad. Furthermore which digital pins connect to the keypad’s row and column pins. If you have a different keypad such as a 16-button version these will need to be modified. Furthermore you can also map out what the buttons will represent in the array “keys”. Then all of these variables are passed to the library in the function Keypad keypad = Keypad() etc.
Reading the buttons pressed is accomplished in void loop()… it reads the keypad by placing the current value into the char variable “key”. The if… statement tests if a button has been pressed. You can reproduce this loop within your own sketch to read values and then move forward to other functions. Let’s do that now in our next example.
Keypad Switch
Using our existing example hardware we can turn something on or off by using the keypad – replicating what can be found in some alarm systems and so on. Our goal with this example is simple – the systems waits for a PIN to be entered. If the PIN is correct, do something. If the PIN is incorrect, do something else. What the actions are can be up to you, but for the example we will turn on or off a digital output. This example is to give you a concept and framework to build you own ideas with.
The hardware is the same as the previous example but without the LCD. Instead, we have a 560 ohm resistor followed by an LED to GND from digital pin ten. Now for the sketch. You can download it from here.
// Example 42.2 - Six-digit keypad switch
// http://tronixstuff.wordpress.com/tutorials > chapter 42
#include "Keypad.h"
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] =
{{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}};
byte rowPins[ROWS] = {
5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {
8, 7, 6}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
char PIN[6]={'1','2','3','4','5','6'}; // our secret (!) number
char attempt[6]={
0,0,0,0,0,0}; // used for comparison
int z=0;
void setup()
{
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
incorrectPIN();
}
void correctPIN() // do this if correct PIN entered
{
digitalWrite(11, LOW);
digitalWrite(10, HIGH);
}
void incorrectPIN() // do this if incorrect PIN entered
{
digitalWrite(10, LOW);
digitalWrite(11, HIGH);
}
void checkPIN()
{
int correct=0;
for (int q=0; q<6; q++)
{
if (attempt[q]==PIN[q])
{
correct++;
}
}
if (correct==6)
{
correctPIN();
} else
{
incorrectPIN();
}
for (int zz=0; zz<6; zz++) // wipe attempt
{
attempt[zz]=0;
}
}
void readKeypad()
{
char key = keypad.getKey();
if (key != NO_KEY)
{
switch(key)
{
case '*':
z=0;
break;
case '#':
delay(100); // for extra debounce
checkPIN();
break;
default:
attempt[z]=key;
z++;
}
}
}
void loop()
{
readKeypad();
}
And the ubiquitous demonstration video:
This sketch is somewhat more complex. It starts with the usual keypad setting up and so on. We have two arrays, attempt and PIN. PIN holds the number which will successfully activate the switch, and attempt is used to store the key presses entered by the user. Users must press ‘*’ then the PIN then ‘#’ to activate the switch.
The comparison to check for accuracy is in the function checkPIN(). It compares the contents of PIN against attempt. If they match, the function correctPIN() is called. If the entered PIN is incorrect, the function incorrectPIN() is called. We also call the function incorrectPIN() in void setup to keep things locked down in case of a power failure or a system reset.
You can now see that such a complex device can be harnessed very easily, and could have a variety of uses. In part two, we will look at the 16-digit
Have fun and keep checking into tronixstuff.com. Why not follow things on twitter, Google+, subscribe for email updates or RSS using the links on the right-hand column, or join our Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other – and we can all learn something.
Breaking up an automatic room deodoriser – round two
Again we attempt to break down an automatic room deodoriser.
Updated 18/03/2013
Today we are going to tear down another automatic room deodoriser. Why?
Well the first attempt beat me, so it was time to even the score and try again with another type. The supermarket had the following units for $7.99, which seemed a little too cheap:
The “satisfaction guarantee” gave me a chuckle, the thought of writing to SC Johnson complaining that their products were not that hackable would be interesting. But would it be hackable at all? Let’s find out. The packaging promises a squirt of scent when the unit detects motion, then holds out for 30 minutes until the next release. The word motion hints that there would be a PIR inside the unit. However the instructions mention that the unit does not work that well in dark or bright rooms – which is odd, as PIRs usually work in the dark. Hmm. This unit is somewhat smaller than the previous attempt, yet still offers us a pair of alkaline AA cells:
Moving on, time to start the disassembly process. The rear shows four screws, easily removed:
revealing the fun things:
The motor drive is reduced twice, which then has a geared arm which causes the vertical motion to pressure the cylinder to release the scent. The whole mess of gears was lubricated generously, the whole lot literally came out with the touch of a finger. Removing the gears and goop reveals the motor and control boards, which clipped out easily:
Interesting – a labelled motor. Very good, what looks like to be a 3V DC motor. The control board is made up of two PCBs, a smaller module that holds a control IC of some sort, and the larger, lesser-densely populated board with the button, status LED and “motion detector”. Let’s have a close-up of that PCB:
So we have the button, which causes the motor to run; a yellow LED which blinks once every five seconds; and out motion detector in the black casing. The motion detector seemed rather familiar, so I removed the black housing around it with some pliers, which revealed this:
Huh – that looks just like an LED. The metal object inside the clear casing was even identical to what you would see inside an LED. However, foolishly I broke it off the PCB when removing the housing, so could not get any voltage to it. From reading the instructions earlier on – that mention the light/dark issue, causes me to ponder if this is some sort of light-dependent sensor?
No – it is a photodiode! However the motor looked quite worthwhile. Curious to see what is driving it, I hooked up Mr Fluke to see what happens:
No surprises there, almost three volts DC forward voltage. After applying forward current the circuit applies a quick reverse current to release, thereby causing the gears and arm to ‘squeeze’ down on the scent cylinder. So now we have a circuit board that runs on 3V, which can output 3V for a few seconds every 30 minutes – or at the press of a button.
With regards to current, another measurement was taken:
When free-running, the motor draws around 45 milliamps – and the stall current (that is, the current drawn when I force the spindle to stop) is around 675 milliamps. That is quite a strong little motor, and worth the effort. In general, this has been a good tear down, we scored some AA cells, a good motor and gears, some stink spray, and a timing circuit that could have uses elsewhere. So overall a win – the score has evened with the deodoriser world! High resolution photos available on flickr.
In the meanwhile have fun and keep checking into tronixstuff.com. Why not follow things on twitter, Google+, subscribe for email updates or RSS using the links on the right-hand column? And join our friendly Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other – and we can all learn something.
Kit Review – Silicon Chip Low Capacitance Meter adaptor for DMMs
Hello readers
Time again for another kit review. In the spirit of promoting all things electronic and Australian, today we are going to look at a kit that was published in our electronics magazine Silicon Chip (March 2010) – their Low-capacitance meter adaptor for DMMs. Simply put, it converts capacitance (from a theoretical 1 picofarad) to millivolts, which you can then read with almost any digital multimeter. This is useful as even more expensive multimeters (such as my Fluke 233) only measure down to 1 nanofarad (1000 picofarads). Although this kit is available on the Australian market, the retailers will export to those abroad. If you are outside Australia and having trouble sourcing one, send me an email. Moving on…
Here is our unassuming finished product:
Please note that this is not an open-source product, so you need to either purchase the kit of parts, or a back-issue of Silicon Chip magazine, March 2010 for the schematic and instructions. Now it is time to get started. But before that, how does it work?
Without giving too much away, a very rough explanation would be that a square wave signal is formed, then cleaned up through a Schmitt trigger-inverter. This square wave is then split into two, one signal passing through the capacitor under test and some resistors, and the other signal passing through a calibration variable capacitor and the same value resistors – thereby both signals pass through two different RC circuits. Finally the two signals are fed through a XOR gate, which creates a series of positive pulses that are a function of the capacitor under test.
Kit assembly was not that difficult, like anything just take your time, read the instructions carefully, and don’t rush things. If you are happy with your through-hole soldering skills, and have a power drill, this kit will be easy for you to work with. Unusually for some kits, this one comes with almost everything you need:
The quality of the included housing is very good, there are metal threaded inserts for the screws; and even through the ICs are simple 74xx-series, sockets have been included. Resistors are metal film, the trimpots are enclosed multiturns – all very nice. I am a little disappointed with the housing/adhesive label combination however, in the past various kits from Jaycar would have a box with a nice silk-screened, hole-punched front panel. Such is life. The PCB is solder-masked and silk-screened, however a little less denser than PCBs from other kit suppliers:
And thus brings a slight issue with the housing and the PCB – either the PCB is too wide, or the box is too narrow. A quick clip of the PCB with some cutters will fix that:
The instructions are quite good – they are a reprint of the magazine article, and slightly modified by the kit production company. Furthermore, the silk-screening on the PCB makes things a breeze. The simple passives were easy to install, however take care not to overheat the variable capacitor, their casings can melt rather quickly:
Following that, the ICs were inserted, and the rotary switch. From experience, one should trim the shaft down to about a 25mm length before soldering it into the board. Take very good care when placing the rotary switch, there is a lump on the switch which matches the small circle at 8 o’clock on the PCB diagram. Finally, don’t forget to alter the switch so it only has four selections. Soldering it in can look difficult, but is not. Just push it into the PCB, checking it is flush, even and all the way in. Then bend a couple of the pins over, invert the PCB and solder away – as such:
Now it is time to start on the enclosure. Each end has two banana-type sockets, the left are the full binding-post, and the right are just sockets. Carefully mark where you want to start the holes – the positions are vertically half-way, and horizontally 15mm in from the edge, however double-check yourself. Always check the fit of the socket while drilling, as it is easy to go too far and make the holes too large – at which point you’ll have to buy another enclosure.
Once you have the sockets fitted – on the left:
and on the right:
… you will need to solder the socket rear to the PCB pins (left) and a small link to the PCB pins (right). It is important to get a good, solid connection – as these sockets may come under a lot of use later on. Next it is time to start on the housing. If you can, photocopy the label so you have a drilling template:
You will notice in the above photo one of my favourite tools, a tapered reamer. Using that, you can carefully turn a small hole into a larger hole, without risking making a mess with a drill. Again, cut the rotary switch’s shaft before soldering:
And as punishment for using twitter at the same time, I had ended up drilling the back instead of the front. D’oh. However cosmetic appearance is secondary to functionality, so all is well. Next was to install the PP3 battery snap. The battery will be a tight fit, so a length of heatshrink has been supplied in order to avoid the battery case shorting with the PCB pin:
And finally we have finished soldering:
Now it is time for calibration. And for me to get a little cranky, which is quite rare as I am somewhat easygoing. Calibration requires three 1% tolerance capacitors, 100 pF, 1000 pF and 10000 pF. And they are not included with the kit. And can not be purchased from any of the kit retailers. So they had to be ordered from Farn… element-14 at a reasonable expense. Considering the kit production company also imports, wholesales and retails electronic components, they could have bought a volume of these special capacitors and added a few dollars to the price of the kit. Such is life. So here are the little buggers:
From top to bottom:
- Silvered-mica 100 picofarad 1% tolerance, element-14 # 1264880, RS # 495745;
- Polystyrene 1000 picofarad 1% tolerance, element-14 # 9520651, RS # 495868 (silvered mica) and
- Polystyrene 10000 picofarad 1% tolerance, element-14 # 3358951, RS # 495953 (silvered mica)
However it is worth the effort to chase them down. There is no point using this kit if you calibrate with normal capacitors; their tolerance can be as much as 20 percent either way. Thankfully the calibration process is quite simple. You will need a small, plastic flat-blade screwdriver to make the adjustments, as your body has stray energy which can alter the capacitance measurements.
Before starting, connect your multimeter to the output sockets and set the range to millivolts – then adjust the variable capacitor until you have the meter display as close to zero as possible. This is used to ‘null out’ stray capacitance. Next, set the dial to A, connect the 100 pF capacitor to the input posts, and adjust VR3 until the meter displays one volt DC – this represents 100.0 picofarads:
I could not for the life of me get this to 1 volt. After fitting the case at the end, I tried again with the case on with the same result. It is very important to get the capacitor as close as possible to the binding posts, with such small values stray capacitance can affect the result. However in my line of work, one-tenth of a picofarad is not relevant. For now. Next, set the dial to B, connect the 1000 pF capacitor, and adjust VR2 until the meter displays 1 volt – this represents 1000 picofarads:
Excellent – spot on. Unfortunately the leads on my 10000 pF capacitor were not long enough to attach into the binding posts, so that step had to be passed. I will have to re-order the correct part next week and calibrate then. However the other two setting are basically working perfectly, which is a good indication for the general performance of the kit. Kudos to Jim Rowe from Silicon Chip magazine for this design.
Before closing up the enclosure, I decided to wrap the battery with some paper, as having it rub up against other parts is not a good idea:
Now for a test run – time to measure the smallest capacitors I have in stock, first a 4.7 picofarad ceramic:
and next, a 12 picofarad ceramic:
Excellent, we can call these readings a success. I was also quite amazed that the tolerance of the cheap ceramic capacitors was so low. Note that in real-life, you may not be able to have the capacitor under test directly connected to the binding posts. In these cases you will need a short set of heavy-gauge leads to the test capacitor. If you do this, you will need to adjust the variable capacitor to reset the display to account for stray capacitance in the leads.
In conclusion, this kit has proved very successful, with regards to assembly, the quality of components and instructions, and of course the final result. I made a few errrors with regards to the housing, but that didn’t affect the final result. And for less than fifty Australian dollars, I have a very low value capacitance meter. However in due course I would consider the purchase of a full LCR meter for greater accuracy and ease of frequent use (some can measure down to 0.1 picofarad). But for the time being, this has been an excellent, educational and affordable solution.
You can purchase the kit directly from Jaycar.
So have fun and keep checking into tronixstuff.com. Why not follow things on twitter, Google+, subscribe for email updates or RSS using the links on the right-hand column, or join our Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other – and we can all learn something.
High resolution images are available on flickr.
[Note - The kit was purchased by myself personally and reviewed without notifying the manufacturer or retailer]
Otherwise, have fun, be good to each other – and make something! ![]()
Tutorial: Arduino and the I2C bus – Part One
This is part one of several tutorials on how to use the I2C bus with Arduino, and chapter twenty of a series originally titled “Getting Started/Moving Forward with Arduino!” by John Boxall – A tutorial on the Arduino universe. The first chapter is here, the complete series is detailed here.
[Updated 10/01/2013]
In this first of several tutorials we are going to investigate the I2C data bus, and how we can control devices using it with our Arduino systems. The I2C bus can be a complex interface to master, so I will do my best to simplify it for you. In this article we will learn the necessary theory, and then apply it by controlling a variety of devices. Furthermore it would be in your interest to have an understanding of the binary, binary-coded decimal and hexadecimal number systems.
But first of all, what is it?
I2C is an acronym for “Inter-Integrated Circuit”. In the late 1970s, Philips’ semiconductor division (now NXP) saw the need for simplifying and standardising the data lines that travel between various integrated circuits in their products. Their solution was the I2C bus. This reduced the number of wires to two (SDA – data, and SCL – clock). Here is a nice introductory video from NXP:
Why would we want to use I2C devices?
As there are literally thousands of components that use the I2C interface! And our Arduino boards can control them all. There are many applications, such a real-time clocks, digital potentiometers, temperature sensors, digital compasses, memory chips, FM radio circuits, I/O expanders, LCD controllers, amplifiers, and so on. And you can have more than one on the bus at any time, in fact the maximum number of I2C devices used at any one time is 112.
From a hardware perspective, the wiring is very easy. Those of you with an Arduino Duemilanove, Uno or 100% compatible board, you will be using pins A4 for SDA (data) and A5 for SCL (clock).
If you are using an Arduino Mega, SDA is pin 20 and SCL is 21, so note that shields with I2C need to be specifically for the Mega. If you have another type of board, check your data sheet or try the Arduino team’s hardware website. And finally, if you are using a bare DIP ATmega328-PU microcontroller, you will use pins 27 for SDA and 28 for SCL.
The bus wiring is simple:

If you are only using one I2C device, the pull-up resistors are (normally) not required, as the ATmega328 microcontroller in our Arduino has them built-in. However if you are running a string of devices, use two 10 kilo ohm resistors. Like anything, some testing on a breadboard or prototype circuit will determine their necessity. Sometimes you may see in a particular device’s data sheet the use of different value pull-up resistors – for example 4.7k ohm. If so, heed that advice. The maximum length of an I2C bus is around one metre, and is a function of the capacitance of the bus. This distance can be extended with the use of a special IC, which we will examine during the next I2C chapter.
Each device can be connected to the bus in any order, and devices can be masters or slaves. In our Arduino situation, the board is the master and the devices on the I2C bus are the slaves. We can write data to a device, or read data from a device. By now you should be thinking “how do we differentiate each device on the bus?”… Each device has a unique address. We use that address in the functions described later on to direct our read or write requests to the correct device. It is possible to use two devices with identical addresses on an I2C bus, but that will be discussed in a later article.
As like most devices, we make use of an Arduino library, in this case <wire.h>. Then use the function Wire.begin(); inside of void setup() and we’re ready to go.
Sending data from our Arduino to the I2C devices requires two things: the unique device address (we need this in hexadecimal) and at least one byte of data to send. For example, the address of the part in example 20.1 (below) is 00101111 (binary) which is 0X2F in hexadecimal. Then we want to set the wiper value, which is a value between 0 and 127, or 0×00 and 0x7F in hexadecimal. So to set the wiper to zero, we would use the following three functions:
Wire.beginTransmission(0x2F); // part address is 0x2F or 0101111b
This sends the device address down the SDA (data) line of the bus. It travels along the bus, and “notifies” the matching device that it has some data coming…
Wire.write(69); // sends 69 down the bus
This sends the byte of data to the device – into the device register (or memory of sorts), which is waiting for it with open arms. Any other devices on the bus will ignore this. Note that you can only perform one I2C operation at a time! Then when we have finished sending data to the device, we “end transmission”. This tells the device that we’re finished, and frees up the I2C bus for the next operation:
Wire.endTransmission();
Some devices may have more than one register, and require more bytes of data in each transmission. For example, the DS1307 real-time clock IC has eight registers to store timing data, each requiring eight bits of data (one byte):
However with the DS1307 - the entire lot need to be rewritten every time. So in this case we would use eight wire.send(); functions every time. Each device will interpret the byte of data sent to it, so you need the data sheet for your device to understand how to use it.
Receiving data from an I2C device into our Arduino requires two things: the unique device address (we need this in hexadecimal) and the number of bytes of data to accept from the device. Receiving data at this point is a two stage process. If you review the table above from the DS1307 data sheet, note that there is eight registers, or bytes of data in there. The first thing we need to do is have the I2C device start reading from the first register, which is done by sending a zero to the device:
Wire.beginTransmission(device_address);
Wire.write(0);
Wire.endTransmission();
Now the I2C device will send data from the first register when requested. We now need to ask the device for the data, and how many bytes we want. For example, if a device held three bytes of data, we would ask for three, and store each byte in its own variable (for example, we have three variables of type byte: a, b, and c. The first function to execute is:
Wire.requestFrom(device_address, 3);
Which tells the device to send three bytes of data back to the Arduino. We then immediately follow this with:
*a = Wire.read();
*b = Wire.read();
*c = Wire.read();
We do not need to use Wire.endTransmission() when reading data. Now that the requested data is in their respective variables, you can treat them like any ordinary byte variable.
For a more detailed explanation of the I2C bus, read this explanatory document by NXP. Now let’s use our I2C knowledge by controlling a range of devices…
Example 20.1
A new part for today, the Microchip MCP4018T digital linear potentiometer. The value of this model is 10 kilo ohms. Inside this tiny, tiny SMD part is a resistor array consisting of 127 elements and a wiper that we control by sending a value of between 0 and 127 (in hexadecimal) down the I2C bus. This is a volatile digital potentiometer, it forgets the wiper position when the power is removed. However naturally there is a compromise with using such a small part, it is only rated for 2.5 milliamps – but used in conjunction with op amps and so on. For more information, please consult the data sheet.
As this is an SMD part, for breadboard prototyping purposes it needed to be mounted on a breakout board. Here it is in raw form:
Above the IC is a breakout board. Consider that the graph paper is 5mm square! It is the incorrect size, but all I have. However soldering was bearable. Put a drop of solder on one pad of the breakout board, then hold the IC with tweezers in one hand, and reheat the solder with the other hand – then push the IC into place. A few more tiny blobs of solder over the remaining pins, and remove the excess with solder wick. Well … it worked for me:
Our example schematic is as follows:
As you can see, the part is simple to use, your signal enters pin 6 and the result of the voltage division is found on pin 5. Please note that this is not a replacement for a typical mechanical potentiometer, we can’t just hook this up as a volume or motor-speed control! Again, please read the data sheet.
Control is very simple, we only need to send one byte of data down, the hexadecimal reference point for the wiper, e.g.:
Wire.beginTransmission(0x2F); // part address is 0x2F or 0101111b
Wire.write(0x3F); //
Wire.endTransmission();
Here is a quick demonstration that moves the wiper across all points: (download)
/* Example 20.1 Microchip MCP4018 digital potentiometer demonstration sketch http://tronixstuff.com/tutorials > chapter 20 CC by-sa v3.0 */
int dt = 2000; // used for delay duration byte rval = 0x00; // used for value sent to potentiometer
#include "Wire.h" #define pot_address 0x2F // each I2C object has a unique bus address, the MCP4018 is 0x2F or 0101111 in binary
void setup()
{
Wire.begin();
Serial.begin(9600);
}
void potLoop()
// sends values of 0x00 to 0x7F to pot in order to change the resistance
// equates to 0~127
{
for (rval=0; rval<128; rval++)
{
Wire.beginTransmission(pot_address);
Wire.write(rval); //
Wire.endTransmission();
Serial.print(" sent - ");
Serial.println(rval, HEX);
delay(dt);
}
}
void loop()
{
potLoop();
}
and a video demonstration:
Example 20.2
Now we will read some data from an I2C device. Our test subject is the ST Microelectronics CN75 temperature sensor. Again, we have another SMD component, but the CN75 is the next stage larger than the part from example 20.1. Thankfully this makes the soldering process much easier, however still requiring some delicate handiwork:
First, a small blob of solder, then slide the IC into it. Once that has cooled, you can complete the rest and solder the header pins into the breakout board:
Our example schematic is as follows:
Pins 5, 6 and 7 determine the final three bits of the device address – in this case they are all set to GND, which sets the address to 1001000. This allows you to use multiple sensors on the same bus. Pin 3 is not used for basic temperature use, however it is an output for the thermostat functions, which we will examine in the next chapter.
As a thermometer it can return temperatures down to the nearest half of a degree Celsius. Although that may not be accurate enough, it was designed for automotive and thermostat use. For more details please read the data sheet. The CN75 stores the temperature data in two bytes, let’s call them A and B. So we use
Wire.requestFrom(cn75address, 2)
with the second paramater as 2, as we want two bytes of data. Which we then store using the following functions:
*a = Wire.read(); // first received byte stored here
*b = Wire.read(); // second received byte stored here
where *a and *b are variables of the type byte.
And as always, there is a twist to decoding the temperature from these bytes. Here are two example pieces of sample data:
Example bytes one: 00011001 10000000
Example bytes two: 11100111 00000000
The bits in each byte note particular values… the most significant bit (leftmost) of byte A determines whether it is below or above zero degrees – 1 for below zero. The remaining seven bits are the binary representation of the integer part of the temperature; if it is below zero, we subtract 128 from the value of the whole byte and multiply by -1. The most significant bit of byte B determines the fraction, either zero or half a degree. So as you will see in the following example sketch (download), there is some decision making done in showCN75data():
/* Example 20.2 ST Microelectronics CN75 Digital Temperature sensor demonstration sketch CC by-sa v3.0 */
#include "Wire.h" #define cn75address 0x48 // with pins 5~7 set to GND, the device address is 0x48
void setup()
{
Wire.begin(); // wake up I2C bus
Serial.begin(9600);
}
void getCN75data(byte *a, byte *b)
{
// move the register pointer back to the first register
Wire.beginTransmission(cn75address); // "Hey, CN75 @ 0x48! Message for you"
Wire.write(0); // "move your register pointer back to 00h"
Wire.endTransmission(); // "Thanks, goodbye..."
// now get the data from the CN75 Wire.requestFrom(cn75address, 2); // "Hey, CN75 @ 0x48 - please send me the contents of your first two registers" *a = Wire.read(); // first received byte stored here *b = Wire.read(); // second received byte stored here }
void showCN75data()
{
byte aa,bb;
float temperature=0;
getCN75data(&aa,&bb);
if (aa>127) // check for below zero degrees
{
temperature=((aa-128)*-1);
if (bb==128) // check for 0.5 fraction
{
temperature-=0.5;
}
}
else // it must be above zero degrees
{
temperature=aa;
if (bb==128) // check for 0.5 fraction
{
temperature+=0.5;
}
}
Serial.print("Temperature = ");
Serial.print(temperature,1);
Serial.println(" degrees C");
delay(1000);
}
void loop()
{
showCN75data();
}
And here is the result from the serial monitor:
Example 20.3
Now that we know how to read and write data to devices on the I2C bus – here is an example of doing both, with a very popular device – the Maxim DS1307 real-time clock IC. Before moving on, consider reading their good data sheet. For those of you new to the world of tronixstuff, we use this part quite often, for example with our Arduino RTC shield and modifications, or blinky – the one-eyed clock. It is an 8-pin DIP IC that allows timing with accuracy down to a few seconds a day:

Furthermore, it also has a programmable square-wave generator. Connection and use is quite simple:
However some external components are required: a 32.768 kHz crystal, a 3V battery for time retention when the power is off, and a 10k ohm pullup resistor is required if using as a square-wave generator, and 10k ohm pull-up resistors on the SCL and SDA lines. You can use the SQW and timing simultaneously. If we have a more detailed look at the register map for the DS1307:
We see that the first seven registers are for timing data, the eighth is the square-wave control, and then another eight RAM registers. In this chapter we will look at the first eight only. Hopefully you have noticed that various time parameters are represented by less than eight bits of data – the DS1307 uses binary-coded decimal. But don’t panic, we have some functions to do the conversions for us.
However, in general - remember that each bit in each register can only be zero or one – so how do we represent a register’s contents in hexadecimal? First, we need to find the binary representation, then convert that to hexadecimal. So, using the third register of the DS1307 as an example, and a time of 12:34 pm – we will read from left to right. Bit 7 is unused, so it is 0. Bit 6 determines whether the time kept is 12- or 24-hour time. So we’ll choose 1 for 12-hour time. Bit 5 (when bit 6 is 0) is the AM/PM indicator – choose 1 for PM. Bit 4 represents the left-most digit of the time, that is the 1 in 12:34 pm. So we’ll choose 1. Bits 3 to 0 represent the BCD version of 2 which is 0010.
So to store 12pm as hours we need to write 00110010 as hexadecimal into the hours register – which is 0×32.
Reading data from the DS1307 should be easy for you now, reset the register pointed, then request seven bytes of data and receive them into seven variables. The device address is 0×68. For example:
Wire.beginTransmission(0x68);
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
*second = bcdToDec(Wire.read();
*minute = bcdToDec(Wire.read();
*hour = bcdToDec(Wire.read();
*dayOfWeek = bcdToDec(Wire.read());
*dayOfMonth = bcdToDec(Wire.read());
*month = bcdToDec(Wire.read());
*year = bcdToDec(Wire.read());
At which point the time data will need to be converted to decimal numbers, which we will take care of in the example sketch later. Setting the time, or controlling the square-wave output is another long operation – you need to write seven variables to set the time or eight to change the square-wave output. For example, the time:
Wire.beginTransmission(0x68);
Wire.write(0);
Wire.write(decToBcd(second));
Wire.write(decToBcd(minute));
Wire.write(decToBcd(hour));
Wire.write(decToBcd(dayOfWeek));
Wire.write(decToBcd(dayOfMonth));
Wire.write(decToBcd(month));
Wire.write(decToBcd(year));
Wire.endTransmission();
The decToBcd is a function defined in our example to convert the decimal numbers to BCD suitable for the DS1307.
You can also address each register individually. We will demonstrate doing this with an explanation of how to control the DS1037′s in built square-wave generator (download sketch):
/*
DS1307 Square-wave machine
Used to demonstrate the four different square-wave outputs from Maxim DS1307
See page nine of data sheet for more information
John Boxall - tronixstuff.wordpress.com
*/
#include "Wire.h"
#define DS1307_I2C_ADDRESS 0x68 // each I2C object has a unique bus address, the DS1307 is 0x68
void setup()
{
Wire.begin();
}
void sqw1() // set to 1Hz
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0x07); // move pointer to SQW address
Wire.write(0x10); // sends 0x10 (hex) 00010000 (binary)
Wire.endTransmission();
}
void sqw2() // set to 4.096 kHz
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0x07); // move pointer to SQW address
Wire.write(0x11); // sends 0x11 (hex) 00010001 (binary)
Wire.endTransmission();
}
void sqw3() // set to 8.192 kHz
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0x07); // move pointer to SQW address
Wire.write(0x12); // sends 0x12 (hex) 00010010 (binary)
Wire.endTransmission();
}
void sqw4() // set to 32.768 kHz (the crystal frequency)
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0x07); // move pointer to SQW address
Wire.write(0x13); // sends 0x13 (hex) 00010011 (binary)
Wire.endTransmission();
}
void sqwOff()
// turns the SQW off
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0x07); // move pointer to SQW address
Wire.write(0x00); // turns the SQW pin off
Wire.endTransmission();
}
void loop()
{
sqw1();
delay(5000);
sqw2();
delay(5000);
sqw3();
delay(5000);
sqw4();
delay(5000);
sqwOff();
delay(5000);
}
Here is the SQW output in action – we measure the frequency using my very old Tek CFC-250:
For further DS1307 examples, I will not repeat myself and instead direct you to the list of many tronixstuff articles that make use of the DS1307.
So there you have it – hopefully an easy to understand introduction to the world of the I2C bus and how to control the devices within. Part two of the I2C tutorial has now been published, as well as an article about the NXP SAA1064 LED display driver IC and the Microchip MC23017 16-bit port expander IC.
Have fun and keep checking into tronixstuff.com. Why not follow things on twitter, Google+, subscribe for email updates or RSS using the links on the right-hand column, or join our Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other – and we can all learn something.
Kit Review – adafruit industries wave shield
Hello readers
Today we are going introduce another useful kit from adafruit industries – their waveshild Arduino shield kit. The purpose of this shield is to play audio files sourced from a computer, at the request of an Arduino sketch. It is an interesting product in that it meets one of the needs of the original concept of Arduino, that is:
… It’s intended for artists, designers, hobbyists, and anyone interested in creating interactive objects or environments. (arduino.cc)
Yes – yes indeed. For a while I had seen this kit, and though that there wasn’t much point to it. But if you spend a few moments contemplating how the control of sounds or recorded voice could be used, suddenly you have a “light bulb moment” and come up with all sorts of things, both crazy and sensible. So less talk and more solder!
Once again, this kit arrives in typical adafruit packaging, a simple reusable antistatic bag:
and emptying the contents onto the desk reveals the following:
And before anyone asks me, no the parts don’t arrange themselves as they fall out of the bag. If they did, we’d have some much larger problems in the world. At first glance I was worried that not all of the parts had been included, however this is kit version 1.1, and there will be empty spaces on the PCB. Speaking of which, once again it is a nice thick, solder-masked and nicely silk screened PCB.
The pre-assembly checklist, assembly instructions and all other documentation and required software links can be found on the adafruit website. After checking off the included parts against the adafruit bill of materials, it was time to start. You will need a few extra things, for example a speaker if necessary, an SD memory card (up to one gigabyte in size) – and in my case two 8-pin IC sockets. When you live in an area where finding specialised ICs is difficult or just time-consuming, IC sockets are very cheap insurance.
The first item to solder in is the SD card, and this is a surface-mount part. But don’t let that worry you, it ‘clicks’ into the PCB, and you then just hold it down with one hand while holding some solder, and with the other hand heat each pad for two seconds and let some solder flow over the pads:
And you don’t need to solder in the last three, narrower contacts of the reader – they are not used. Everything else is standard through hole, nothing much to worry about apart from burning yourself while listening to the radio. Except for one resistor, R6 – the one next to IC4. If you solder in the resistor first, even though it sits normally – it is about one millimetre too close to the IC. So if you are going to assemble this, solder in IC4 before R6:
However it isn’t anything to panic about, just something to keep an eye out for. Moving forward, everything else went in easily:
The last basic soldering to take care of is the expansion pins for the shield to able to mate with other shields. The easiest way to solder these in is to first drop the new pins into an existing, matching board – as such:
Then drop the waveshield on top of the pins and solder away:
And finally, some links from the circuit to the digital pins… Then lo and behold, we’re finished:

During the initial testing and experimenting, I was going to use a set of earphones to listen to the output, however instead ended up installing a small 0.25 watt 8 ohm speaker. The solder pads for the speaker are between the rear of the headphone socket and C9. If you decide to use both headphones and a speaker, the circuit is designed in such a way as the headphone socket will cut off the speaker when headphones are in use. adafruit also sell the waveshield party pack which includes a memory card and speaker to save you shopping around.
Note that this shield will need digital pins 2~5 and 10~13 – as noted in Jon Oxer’s new website – shieldlist.org.
Now that the hardware has been taken care of, let’s get our Arduino talking and grooving. The first thing to do is install the wavehc library into your Arduino IDE software. The library and related buffering use a fair amount of memory, so if you are running an Arduino with the old ’168 MCU, it’s time to find the $6 and upgrade to the ATmega328.
Next, visit the tronixstuff file repository. Download the waveshieldtest.pde sketch; and also download this audio file onto the SD card. Finally, insert the SD card, upload the sketch, insert your headphones and the board should play the file. Don’t forget to turn the volume up a little, yours may be set to off by default.
Now that we know it is working, it is time to examine how we can control things in more detail. The most important thing is to have your .wav sound files in the correct format. The maximum sampling rate is 22 kHz, depth of 16-bit, and in mono PCM format. You can download an open-source audio editor package to do the conversions for you here. ladyada has also written a good conversion tutorial for you here.
Apart from converting audio files for playback, if you want to get some backchat you will need to find a speech-synthesiser. You can make use of the AT+T Labs Natural Voices (R) Text to Speech demo website for this. Just enter some text, and then you can download the .wav file:
Now let’s have a quick look at how we can play files on demand, to let our own projects make some noise. Please download the sketch waveshieldtest2.pde. Although there is a large amount of code in there, what we’re interested in is just the void loop(); function. To play a .wav file, such as “wisdom.wav”, just use
playcomplete("wisdom.wav");
So you can just mash that sketch and your own code together to get some files playing, however don’t forget your attributions to the original authors. Here is a … longer demonstration of waveshieldtest2.pde:
And there we have it. We will expand on waveshield usage more in an upcoming project - my Talking Clock of Wisdom, so stay tuned for that box of fun. Furthermore, I hope you found this review interesting, and helped motivate you to make some crazy talking objects or music boxes!
You can purchase the waveshield kit directly from adafruit industries.
As always, thank you for reading and I look forward to your comments and so on. Furthermore, don’t be shy in pointing out errors or places that could use improvement. Please subscribe using one of the methods at the top-right of this web page to receive updates on new posts. Or join our Google Group. High resolution images are available on flickr.
[Note - The kit was purchased by myself personally and reviewed without notifying the manufacturer or retailer]
Otherwise, have fun, be good to each other – and make something! ![]()























































































