W E L C O M E

Namaste and Welcome to the "Nuts About Electronics" Blog.

I am an electronics hobbyist based in India. Recently, I rediscovered my childhood passion in tinkering with electronic circuits. I created this blog to share some of my projects, as well as provide some useful information to other hobbyists in India, where many electronic components are hard to find.

Please note that the projects as well as code in this blog are provided "as is", with no guarantees. Working with electricity, electronic components, soldering irons, etc. requires safety precautions - please use your common sense.

Good luck with your projects, and above all, have FUN!

MV

Monday, August 3, 2009

Making a 12-bit Serial DAC



I recently built a 12-bit serial DAC, using a pair of 74HC595 shift registers and a R/2R ladder. I know that the entire circuit can be replaced with a single IC. But I did for 2 reasons (1) To learn about R/2R ladder DACs and (2) I could not find 12-bit DAC ICs here. The end result might be wobbly, but it sure is cheap! (Rs. 25 vs Rs. 300).


Note

Since posting this, I have found that this method is not particularly accurate. See for instance the post here.


The Circuit

The main components here are the pair of 74HC595 shift registers, the R/2R resistor ladder and the LM358 Op Amp.



The shift registers are used to shift out the serial 12-bit data. Since we are sending 12 bits, we can't use the built in shiftOut() method, and have to resort to some direct port manipulation code for the same. The shift registers are connected to the Arduino as shown in the schematic on the Arduino ShiftOut tutorial.

The R/2R ladder is the core of the DAC. I used a set of single 100 K Ohm 1% resistors. You can read details about the R/2R ladders here.

The LM358 is configured as a voltage follower, since it isolates the R/2R network with a high input impedance.

The power supply to the Op Amp is separate 9V battery. I tried powering it with just the 5V from the Arduino, but it does not operate very well at inputs close to the supply voltage.

The Code


/*
* ShiftOutTest
*
* MV (http://electro-nut.blogspot.com/)
*
* This tests a 2 x 74HC595 + R/2R Ladder 12-bit DAC
*
*/

// 74HC595 pins
int pin_SH_CP = 6;
int pin_ST_CP = 7;
int pin_DS = 5;

// values
int readings[] = {
0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200,
1300,1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300,
2400, 2500, 2600, 2700,
2800, 2900, 3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700, 3800,
3900, 4000, 4096};

int N = sizeof(readings)/sizeof(int);

void setup()
{
pinMode(pin_SH_CP, OUTPUT);
pinMode(pin_ST_CP, OUTPUT);
pinMode(pin_DS, OUTPUT);
}


void loop()
{
for(int i = 0; i < N; i++) {
// ST_CP low
digitalWrite(pin_ST_CP, LOW);

// shift 12 LSB-first bits of data to shift register
shiftOut12(readings[i]);

// ST_CP high
digitalWrite(pin_ST_CP, HIGH);

// change this delay to suit your reading needs
delay(1000);
}
}

// shift out 12 bits of data
void shiftOut12(int data)
{
for(int i = 0; i < 12; i++) {
// SH_CP low
//PORTD &= ~(1<<6);
digitalWrite(pin_SH_CP, LOW);
// DS
// is i-th bit of data high?
if(data & (1<<i)) {
PORTD |= (1<<5);
}
else {
PORTD &= ~(1<<5);
}
// SH_CP high
//PORTD |= (1<<6);
digitalWrite(pin_SH_CP, HIGH);
}
// SH_CP low
//PORTD &= ~(1<<6);
digitalWrite(pin_SH_CP, LOW);
}



Results

I took 42 readings using a multimeter (enlisted the help of my wonderful wife - thanks, dear!), and the response does look very linear:



In a real application, I'd definitely got for a serial DAC IC - but it was nice to discover that it can be done this way!

Acknowledgments

Thanks to the excellent Arduino Forum and its members for helpful posts and discussions.

References

1. The Arduino ShiftOut Tutorial

http://www.arduino.cc/en/Tutorial/ShiftOut

2. Practical Electronics for Inventors by Paul Scherz


[...CLICK HERE to read the full post...]

Saturday, August 1, 2009

The Karplus-Strong Algorithm

As part of my ongoing audio projects with Arduino, I was looking for a programmatic way of generating complex sounds. It is simple enough to create a pure tone with a sine wave. But real sounds are complex, with mixtures of overtones or frequencies that rise and fall over time. I recently found an interesting algorithm called "Karplus-Strong string synthesis" which simulates the sound of a plucked string. I wrote a program in Python to explore this algorithm, and I think the sounds produced by this algorithm are just amazing.

First, listen to the 2 samples below, produced by the algorithm:

1. simple.wav
2. ks.wav

Now for the code that produced these:

Here is a simple Python program that generates the sound from a single plucked string, and writes it out to a WAV file.


############################################################
#
# karplus-simple.py
#
# Author: MV (http://electro-nut.blogspot.com/)
#
# Generates a plucked string sound WAV file using the
# Karplus-Strong algorithm. (Simple version.)
#
############################################################
from math import sin, pi
from array import array
from random import random

import wave

# KS params
SR = 44100
f = 220
N = SR/f

# WAV params
NCHANNELS = 1
SWIDTH = 2
FRAME_RATE = 44100
NFRAMES = 44100
NSAMPLES = 44100
# max - 128 for 8-bit, 32767 for 16-bit
MAX_VAL= 32767

# pluck
buf = [random() - 0.5 for i in range(N)]

#init samples
samples = []

# KS - ring buffer
bufSize = len(buf)
for i in range(NSAMPLES):
samples.append(buf[0])
avg = 0.996*0.5*(buf[0] + buf[1])
buf.append(avg)
buf.pop(0)

# samples to 16-bit to string
tmpBuf = [int(x*MAX_VAL) for x in samples]
data = array('h', tmpBuf).tostring()

# write out WAV file
file = wave.open('simple.wav', 'wb')
file.setparams((NCHANNELS, SWIDTH, FRAME_RATE, NFRAMES,
'NONE', 'noncompressed'))
file.writeframes(data)
file.close()


Here is a more object oriented version of the code above, which lets you mix sounds from multiple string plucks.


############################################################
#
# karplus.py
#
# Author: MV (http://electro-nut.blogspot.com/)
#
# Generates a plucked string sound WAV file using the
# Karplus-Strong algorithm.
#
############################################################
from math import sin, pi
from array import array
from random import random
import wave

# KS params
SR = 44100
f = 220

# WAV params
NCHANNELS = 1
SWIDTH = 2
FRAME_RATE = 44100
NFRAMES = 44100
NSAMPLES = 44100*2
# max - 128 for 8-bit, 32767 for 16-bit
MAX_VAL= 32767

class String:
def __init__(self, freq, SR):
self.freq = freq
self.N = SR/freq
# 'pluck' string
def pluck(self):
self.buf = [random() - 0.5 for i in range(self.N)]
# return current sample, increment step
def sample(self):
val = self.buf[0]
avg = 0.996*0.5*(self.buf[0] + self.buf[1])
self.buf.append(avg)
self.buf.pop(0)
return val

str1, str2 = String(196, SR), String(440, SR)

str1.pluck()
str2.pluck()

samples = []

for i in range(NSAMPLES):
sample = str1.sample()
if(i > NSAMPLES/8):
sample += str2.sample()
samples.append(sample)

# samples to 16-bit to string
tmpBuf = [int(x*MAX_VAL) for x in samples]
data = array('h', tmpBuf).tostring()

# write out WAV file
file = wave.open('ks.wav', 'wb')
file.setparams((NCHANNELS, SWIDTH, FRAME_RATE, NFRAMES,
'NONE', 'noncompressed'))
file.writeframes(data)
file.close()



It remains to be seen how I can adapt this to the Arduino. But it has been a fun project!

References

1. You can read details about the algorithm here:

http://en.wikipedia.org/wiki/Karplus-Strong_string_synthesis

2. Here is a programming assignment from Princeton which started me off on this project:

http://www.cs.princeton.edu/courses/archive/spring09/cos126/assignments/guitar.html



[...CLICK HERE to read the full post...]

Friday, July 24, 2009

Book on Atmel AVR


The Arduino platform is an excellent introduction for the novice to the microcontroller. But at some point, you might feel like digging deeper into the subject. You might have seen direct port manipulation code or code that uses interrupts, and wondered where you could read more about this stuff. I recently purchased Barnett's book above, and the second chapter titled "The Atmel RISC Processors" goes into details of the AVR architecture, timers, interrupts, communication protocols, etc. I highly recommend this book. Although the Indian edition shown is the first edition, it still gives a comprehensive, relevant introduction to the subject. It is available at the IISC bookstore (TATA) in Bangalore for about Rs. 320.
[...CLICK HERE to read the full post...]

Thursday, July 9, 2009

Arduino based Temperature Display














This project is part of a bigger project of mine, and it displays the ambient temperature on a set of 2 Common Cathode 7-Segment LED displays. The temperature sensor is the LM35 IC, which outputs voltage calibrated to degrees centigrade.

The LM35 is connected to the analog input of the Arduino board. The code running on Arduino then averages 10 temperature readings to reduce jitter, and then outputs the 2 digit integer temperature value to the 7-Segment display. To achieve the latter, it uses a set of 2 shift registers (IC 74HC595). This is a technique that minimizes the number of output pins required by Arduino to drive the display. You can read about it in detail here:

http://www.arduino.cc/en/Tutorial/ShiftOut

Code

The following code shows how to read the analog input from the LM35 and use shiftOut() to send data to IC 74HC595. There is also an optional countDown() method here which runs down from 99 to 0, for testing.


/*
* TempDisplay
* by MV - http://electro-nut.blogspot.com/
*
* Displaying ambient temeprature on a 2 x Common Cathode 7-Segment Displays
* Using 74HC595 shift register and the shiftOut() built in function
* Using LM35 to sense temperature.
*
* REFERENCES
*
* http://www.arduino.cc/en/Tutorial/ShiftOut
*
*/

// set this to 1 to run 99-0 countdown
#define TEST_MODE 0

int val = 0; // variable to store the value coming from the sensor
int lm35Pin = 0;
int DEBUG = 1;

//Pin connected to ST_CP of 74HC595
int latchPin = 8;
//Pin connected to SH_CP of 74HC595
int clockPin = 12;
////Pin connected to DS of 74HC595
int dataPin = 11;

// 7-segment digits 0-9
// 74HC595-->7-Segment pin Mapping:
// {Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7} --> {DP, a, b, c, d, e, f, g}
byte digits[] = {
B01111110, B00110000, B01101101, B01111001, B00110011, B01011011,
B01011111, B01110000, B01111111, B01111011
};

// set up
void setup() {
if(DEBUG) {
Serial.begin(9600);
}

//set pins to output because they are addressed in the main loop
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);

}

// Main loop
void loop() {

#ifdef _TEST_MODE
countDown();
#else
// read the value from LM35.
// read 10 values for averaging.
val = 0;
for(int i = 0; i < 10; i++) {
val += analogRead(lm35Pin);
delay(500);
}

// convert to temp:
// temp value is in 0-1023 range
// LM35 outputs 10mV/degree C. ie, 1 Volt => 100 degrees C
// So Temp = (avg_val/1023)*5 Volts * 100 degrees/Volt
float temp = val*50.0/1023.0;
int tempInt = (int)temp;
displayNum(tempInt);

// serial output for debugging
if(DEBUG) {
Serial.println(temp);
}
#endif

}

// Display 2 digit number
void displayNum(int num)
{
// get digit 0
int dig0 = num % 10;
// get digit 1
int dig1 = (num/10) % 10;

// shift out digits
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, digits[dig1]);
shiftOut(dataPin, clockPin, MSBFIRST, digits[dig0]);
digitalWrite(latchPin, HIGH);
}

// test function to count down from 99 to 0
void countDown()
{
// display numbers
for(int i = 0; i < 100; i++) {
displayNum(100-i);
delay(500);
}
}



Conclusion

There is not much original here, the Arduino page on ShiftOut pretty much explains everything.













As you can see above, the temperature does change.(But don't try this and burn down your IC or worse, your house!)

References

For details on 74HC595 and shiftOut:

http://www.arduino.cc/en/Tutorial/ShiftOut

For details on LM35:

http://www.facstaff.bucknell.edu/mastascu/elessonshtml/Sensors/TempLM35.html

[...CLICK HERE to read the full post...]

Friday, July 3, 2009

2 Books on Practical Electronics

Here are 2 excellent books on practical electronics I refer to frequently:

#1 "Getting Started in Electronics" by Forrest Mims

http://www.amazon.com/Getting-Started-Electronics-Forrest-Mims/dp/0945053282/ref=pd_bxgy_b_text_b

#2 "Practical Electronics for Inventors" by Paul Scherz

http://www.amazon.com/Practical-Electronics-Inventors-Paul-Scherz/dp/0071452818/ref=sr_1_1?ie=UTF8&s=books&qid=1246611203&sr=8-1

#1 is also available as a PDF online. I am not sure about the legality of it, so I can't post a link. But one could always use Google to find out. ;-)
[...CLICK HERE to read the full post...]

Thursday, July 2, 2009

Hacking a Toy Train with Arduino


Getting back into hobby electronics after 2 decades, I am amazed and thrilled too see the new powerful toy in town - the mircocontroller. After some research, I decided to get an Atmel based Arduino board to experiment with. Since Arduino is not easily available in India, I got a Freeduino board from Bhasha Technologies.

As a first "newbie" project with the Arduino, I decided to try and hack my son's remote controlled toy train. The remote has five buttons on it - forward/reverse, stop, horn and a "speed up" button. I wanted to control the first four buttons from my computer. The idea is that a program running on the computer would output key strokes to the serial port. The code running on the Arduino board would read these characters from the serial port,and activate the right switch on the remote control.

To activate the switches, I used an opto-isolator, which isolates the remote's electrical circuit from that of the Arduino board. I used an MCT2E available here for about Rs. 8. To the left is a simple circuit that shows how this works.


This image shows the switches inside the remote.


Here, I have soldered wires to the contact points on to the switches to an external connector.


This image shows how the optocouplers are connected to the Arduino board.

Processing Code running on the Computer

The Arduino board is connected to my computer, via a USB cable, which creates a virtual serial port (COM6 on mine). To send serial data based on a key press, I used the Processing Language. (See code below.)

/**
* Train
*
* Writes pressed key value to serial port.
*
*/

import processing.serial.*;

Serial myPort; // Create object from Serial class
int val; // Data received from the serial port

void setup()
{
size(200, 200);
// I know that the first port in the serial list on my mac
// is always my FTDI adaptor, so I open Serial.list()[0].
// On Windows machines, this generally opens COM1.
// Open whatever port is the one you're using.
String portName = Serial.list()[0];
print(portName);
myPort = new Serial(this, portName, 9600);
}

void draw() {
background(255);
if(keyPressed) {
print(key);
myPort.write(key);
}
}
Code that runs on the Arduino Board

Arduino uses a language called Wiring. The code below reads the serial port, and activates digital pins 13, 12, 10 or 9, which are connected to 4 optocouplers, which in turn "press" the remote's buttons.

/*
* Train
* by MV
*
* Pins 13,12,10,9 mapped to controls on toy train
*
* http://
*/

int stopPin = 13;
int hornPin = 12;
int forwardPin = 11;
int reversePin = 10;

void setup() {
pinMode(stopPin, OUTPUT);
pinMode(hornPin, OUTPUT);
pinMode(forwardPin, OUTPUT);
pinMode(reversePin, OUTPUT);

Serial.begin(9600); // Start serial communication at 9600 bps
}

void loop() {

char val = 0;

if (Serial.available()) { // If data is available to read,
val = Serial.read(); // read it and store it in val
}

if(val == 's') {
press(stopPin);
}
else if(val == 'h') {
press(hornPin);
}
else if(val == 'f') {
press(forwardPin);
}
else if(val == 'r') {
press(reversePin);
}
else {
delay(100); // Wait 100 milliseconds for next reading
}
}

void press(int pin)
{
digitalWrite(pin, HIGH);
delay(200);
digitalWrite(pin, LOW);
}



Conclusion

The high point of my project was pressing 'h' on my computer and hearing the train whistle go "Toot Toot"!

Hope that was interesting, and hope it gives Arduino newbies (like myself) some circuit bending ideas.

Relevant Links

http://arduino.cc/

http://www.processing.org/

[...CLICK HERE to read the full post...]