The personal website of Scott W Harden
June 10th, 2013

Precision Temperature Measurement

In an effort to resume previous work [A, B, C, D] on developing a crystal oven for radio frequency transmitter / receiver stabilization purposes, the first step for me was to create a device to accurately measure and log temperature. I did this with common, cheap components, and the output is saved to the computer (over 1,000 readings a second). Briefly, I use a LM335 precision temperature sensor ($0.70 on mouser) which outputs voltage with respect to temperature. It acts like a Zener diode where the breakdown voltage relates to temperature. 2.95V is 295K (Kelvin), which is 22ºC / 71ºF. Note that Kelvin is just ºC + 273.15 (the difference between freezing and absolute zero). My goal was to use the ADC of a microcontroller to measure the output. The problem is that my ADC (one of 6 built into the ATMEL ATMega8 microcontroller) has 10-bit resolution, reporting steps from 0-5V as values from 0-1024. Thus, each step represents 0.0049V (0.49ºC / 0.882ºF). While ~1ºF resolution might be acceptable for some temperature measurement or control applications, I want to see fractions of a degree because radio frequency crystal temperature stabilization is critical. Here's a video overview.

This is the circuit came up with. My goal was to make it cheaply and what I had on hand. It could certainly be better (more stable, more precise, etc.) but this seems to be working nicely. The idea is that you set the gain (the ratio of R2/R1) to increase your desired resolution (so your 5V of ADC recording spans over just several ºF you're interested in), then set your "base offset" temperature that will produce 0V. In my design, I adjusted so 0V was room temperature, and 5V (maximum) was body temperature. This way when I touched the sensor, I'd watch temperature rise and fall when I let go. Component values are very non-critical. LM324 is powered 0V GND and +5V Vcc. I chose to keep things simple and use a single rail power supply. It is worth noting that I ended-up using a 3.5V Zener diode for the positive end of the potentiometer rather than 5V. If your power supply is well regulated 5V will be no problem, but as I was powering this with USB I decided to go for some extra stability by using a Zener reference.

On the microcontroller side, analog-to-digital measurement is summed-up pretty well in the datasheet. There is a lot of good documentation on the internet about how to get reliable, stable measurements. Decoupling capacitors, reference voltages, etc etc. That's outside the scope of today's topic. In my case, the output of the ADC went into the ATMega8 ADC5 (PC5, pin 28). Decoupling capacitors were placed at ARef and AVcc, according to the datasheet. Microcontroller code is at the bottom of this post.

To get the values to the computer, I used the USART capability of my microcontroller and sent ADC readings (at a rate over 1,000 a second) over a USB adapter based on an FTDI FT232 chip. I got e-bay knock-off FTDI evaluation boards which come with a USB cable too (they're about $6, free shipping). Yeah, I could have done it cheaper, but this works effortlessly. I don't use a crystal. I set fuse settings so the MCU runs at 8MHz, and thanks to the nifty online baud rate calculator determined I can use a variety of transfer speeds (up to 38400). At 1MHz (if DIV8 fuse bit is enabled) I'm limited to 4800 baud. Here's the result, it's me touching the sensor with my finger (heating it), then letting go.

Touching the temperature sensor with my finger, voltage rose exponentially. When removed, it decayed exponentially - a temperature RC circuit, with capacitance being the specific heat capacity of the sensor itself. Small amounts of jitter are expected because I'm powering the MCU from unregulated USB +5V.[/caption]

I spent a while considering fancy ways to send the data (checksums, frame headers, error correction, etc.) but ended-up just sending it old fashioned ASCII characters. I used to care more about speed, but even sending ASCII it can send over a thousand ADC readings a second, which is plenty for me. I ended-up throttling down the output to 10/second because it was just too much to log comfortable for long recordings (like 24 hours). In retrospect, it would have made sense to catch all those numbers and do averaging on the on the PC side.

I keep my house around 70F at night when I'm there, and you can see the air conditioning kick on and off. In the morning the AC was turned off for the day, temperature rose, and when I got back home I turned the AC on and it started to drop again.[/caption]

On the receive side, I have nifty Python with PySerial ready to catch data coming from the microcontroller. It's decoded, turned to values, and every 1000 receives saves a numpy array as a NPY binary file. I run the project out of my google drive folder, so while I'm at work I can run the plotting program and it loads the NPY file and shows it - today it allowed me to realize that my roommate turned off the air conditioning after I left, because I saw the temperature rising mid-day. The above graph is temperature in my house for the last ~24 hours. That's about it! Here's some of the technical stuff.

AVR ATMega8 microcontroller code:

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

/*
8MHZ: 300,600,1200,2400,4800,9600,14400,19200,38400
1MHZ: 300,600,1200,2400,4800
*/
#define USART_BAUDRATE 38400
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

/*
ISR(ADC_vect)
{
    PORTD^=255;
}
*/

void USART_Init(void){
    UBRRL = BAUD_PRESCALE;
    UBRRH = (BAUD_PRESCALE >> 8);
    UCSRB = (1<<TXEN);
    UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); // 9N1
}

void USART_Transmit( unsigned char data ){
    while ( !( UCSRA & (1<<UDRE)) );
    UDR = data;
}

void sendNum(long unsigned int byte){
    if (byte==0){
        USART_Transmit(48);
    }
    while (byte){
        USART_Transmit(byte%10+48);
        byte-=byte%10;
        byte/=10;
    }

}

unsigned int readADC(char adcn){
    ADMUX = 0b0100000+adcn;
    ADCSRA |= (1<<ADSC); // reset value
    while (ADCSRA & (1<<ADSC)) {}; // wait for measurement
    return ADC>>6;
}

void ADC_Init(){
    // ADC Enable, Prescaler 128
    ADCSRA = (1<<ADEN)  | 0b111;
}

int main(void){
    //DDRD=255;
    USART_Init();
    ADC_Init();
    for(;;){
        sendNum(readADC(5));
        USART_Transmit('n');
        _delay_ms(100);
    }
}

Here is the Python code to receive the data and log it to disk:

import serial, time
import numpy
ser = serial.Serial("COM15", 38400, timeout=100)

line=ser.readline()[:-1]
t1=time.time()
lines=0

data=[]

while True:
    line=ser.readline()[:-1]

    if "," in line:
        line=line.split(",")
        for i in range(len(line)):
            line[i]=line[i][::-1]
    else:
        line=[line[::-1]]
    temp=int(line[0])
    lines+=1
    data.append(temp)
    print "#",
    if lines%1000==999:
        numpy.save("DATA.npy",data)
        print
        print line
        print "%d lines in %.02f sec (%.02f vals/sec)"%(lines,
                time.time()-t1,lines/(time.time()-t1))

Here is the Python code to plot the data that has been saved:

import numpy
import pylab

data=numpy.load("DATA.npy")
print data
data=data*.008 #convert to F
xs=numpy.arange(len(data))/9.95  #vals/sec
xs=xs/60.0# minutes
xs=xs/60.0# hours

pylab.plot(xs,data)
pylab.grid(alpha=.5)
pylab.axis([None,None,0*.008,1024*.008])
pylab.ylabel(r'$Delta$ Fahrenheit')
pylab.xlabel("hours")
pylab.show()
Markdown source code last modified on January 18th, 2021
---
title: Precision Temperature Measurement
date: 2013-06-10 22:25:27
tags: microcontroller, old
---

# Precision Temperature Measurement

__In an effort to resume previous work \[[A](http://www.swharden.com/blog/2010-11-24-atmega48-lm335-max232-serial-port-multi-channel-temperature-measurement/), [B](http://www.swharden.com/blog/2010-11-28-crystal-oven-experiments/), [C](http://www.swharden.com/blog/2010-08-27-hacking-together-a-crystal-oven-part-2/), [D](http://www.swharden.com/blog/2010-08-26-minimalist-crystal-oven/)\] on developing a crystal oven for radio frequency transmitter / receiver stabilization purposes, the first step for me was to create a device to accurately measure and log temperature.__ I did this with common, cheap components, and the output is saved to the computer (over 1,000 readings a second). Briefly, I use a [LM335 precision temperature sensor](http://www.ti.com/lit/ds/symlink/lm335.pdf) ([$0.70 on mouser](http://www.mouser.com/ProductDetail/STMicroelectronics/LM335Z/?qs=sGAEpiMZZMusbZ2pNxAMx3IjjBanxLGdnwZerf04Dlo%3d)) which outputs voltage with respect to temperature. It acts like a [Zener diode](http://en.wikipedia.org/wiki/Zener_diode) where the breakdown voltage relates to temperature. 2.95V is 295K (Kelvin), which is 22ºC / 71ºF. Note that Kelvin is just ºC + 273.15 (the difference between freezing and [absolute zero](http://en.wikipedia.org/wiki/Absolute_zero)). My goal was to use the [ADC ](http://en.wikipedia.org/wiki/Analog_digital_converter)of a microcontroller to measure the output. The problem is that my [ADC ](http://en.wikipedia.org/wiki/Analog_digital_converter)(one of 6 built into the [ATMEL ATMega8 microcontroller](http://www.atmel.com/Images/Atmel-2486-8-bit-AVR-microcontroller-ATmega8_L_datasheet.pdf)) has 10-bit resolution, reporting steps from 0-5V as values from 0-1024. Thus, each step represents 0.0049V (0.49ºC / 0.882ºF). While ~1ºF resolution might be acceptable for _some_ temperature measurement or control applications, I want to see fractions of a degree because radio frequency crystal temperature stabilization is critical. Here's a video overview.

![](https://www.youtube.com/embed/LTPncC2e3Zo)

__This is the circuit came up with.__ My goal was to make it cheaply and what I had on hand. It could certainly be better (more stable, more precise, etc.) but this seems to be working nicely. The idea is that you set the gain (the ratio of R2/R1) to increase your desired resolution (so your 5V of ADC recording spans over just several ºF you're interested in), then set your "base offset" temperature that will produce 0V. In my design, I adjusted so 0V was room temperature, and 5V (maximum) was body temperature. This way when I touched the sensor, I'd watch temperature rise and fall when I let go.  Component values are very non-critical. LM324 is powered 0V GND and +5V Vcc. I chose to keep things simple and use a single rail power supply. It is worth noting that I ended-up using a 3.5V Zener diode for the positive end of the potentiometer rather than 5V.  If your power supply is well regulated 5V will be no problem, but as I was powering this with USB I decided to go for some extra stability by using a Zener reference.

<div class="text-center img-border">

[![](precision-thermometer-LM335-LM324-microcontroller_thumb.jpg)](precision-thermometer-LM335-LM324-microcontroller.jpg)

</div>

__On the microcontroller side, analog-to-digital measurement is summed-up pretty well in the datasheet.__ There is a lot of good documentation on the internet about how to get reliable, stable measurements. Decoupling capacitors, reference voltages, etc etc. That's outside the scope of today's topic. In my case, the output of the ADC went into the ATMega8 ADC5 (PC5, pin 28). Decoupling capacitors were placed at ARef and AVcc, according to the datasheet. Microcontroller code is at the bottom of this post.

<div class="text-center">

![](photo-3.jpg)

</div>

__To get the values to the computer, I used the USART capability of my microcontroller and sent ADC readings (at a rate over 1,000 a second) over a USB adapter based on an FTDI FT232 chip.__ I got e-bay knock-off FTDI evaluation boards which come with a USB cable too (they're about $6, free shipping). Yeah, I could have done it cheaper, but this works effortlessly. I don't use a crystal. I set [fuse settings](http://www.engbedded.com/fusecalc) so the MCU runs at 8MHz, and thanks to the [nifty online baud rate](http://www.wormfood.net/avrbaudcalc.php) calculator determined I can use a variety of transfer speeds (up to 38400). At 1MHz (if DIV8 fuse bit is enabled) I'm limited to 4800 baud. Here's the result, it's me touching the sensor with my finger (heating it), then letting go.

<div class="text-center">

[![](finger-touch_thumb.jpg)](finger-touch.png)

</div>

Touching the temperature sensor with my finger, voltage rose exponentially. When removed, it decayed exponentially - a temperature RC circuit, with capacitance being the specific heat capacity of the sensor itself. Small amounts of jitter are expected because I'm powering the MCU from unregulated USB +5V.[/caption]

__I spent a while considering fancy ways to send the data__ (checksums, frame headers, error correction, etc.) but ended-up just sending it old fashioned ASCII characters. I used to care more about speed, but even sending ASCII it can send over a thousand ADC readings a second, which is plenty for me. I ended-up throttling down the output to 10/second because it was just too much to log comfortable for long recordings (like 24 hours). In retrospect, it would have made sense to catch all those numbers and do averaging on the on the PC side.

<div class="text-center">

[![](ac2_thumb.jpg)](ac2.png)

</div>

I keep my house around 70F at night when I'm there, and you can see the air conditioning kick on and off. In the morning the AC was turned off for the day, temperature rose, and when I got back home I turned the AC on and it started to drop again.[/caption]

__On the receive side, I have nifty Python with [PySerial ](http://pyserial.sourceforge.net/)ready to catch data coming from the microcontroller. __It's decoded, turned to values, and every 1000 receives [saves a numpy array as a NPY binary file](http://docs.scipy.org/doc/numpy/reference/generated/numpy.save.html). I run the project out of my google drive folder, so while I'm at work I can run the plotting program and it loads the NPY file and shows it - today it allowed me to realize that my roommate turned off the air conditioning after I left, because I saw the temperature rising mid-day. The above graph is temperature in my house for the last ~24 hours. That's about it! Here's some of the technical stuff.

AVR ATMega8 microcontroller code:

```c
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

/*
8MHZ: 300,600,1200,2400,4800,9600,14400,19200,38400
1MHZ: 300,600,1200,2400,4800
*/
#define USART_BAUDRATE 38400
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

/*
ISR(ADC_vect)
{
    PORTD^=255;
}
*/

void USART_Init(void){
    UBRRL = BAUD_PRESCALE;
    UBRRH = (BAUD_PRESCALE >> 8);
    UCSRB = (1<<TXEN);
    UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); // 9N1
}

void USART_Transmit( unsigned char data ){
    while ( !( UCSRA & (1<<UDRE)) );
    UDR = data;
}

void sendNum(long unsigned int byte){
    if (byte==0){
        USART_Transmit(48);
    }
    while (byte){
        USART_Transmit(byte%10+48);
        byte-=byte%10;
        byte/=10;
    }

}

unsigned int readADC(char adcn){
    ADMUX = 0b0100000+adcn;
    ADCSRA |= (1<<ADSC); // reset value
    while (ADCSRA & (1<<ADSC)) {}; // wait for measurement
    return ADC>>6;
}

void ADC_Init(){
    // ADC Enable, Prescaler 128
    ADCSRA = (1<<ADEN)  | 0b111;
}

int main(void){
    //DDRD=255;
    USART_Init();
    ADC_Init();
    for(;;){
        sendNum(readADC(5));
        USART_Transmit('n');
        _delay_ms(100);
    }
}
```

Here is the Python code to receive the data and log it to disk:

```python
import serial, time
import numpy
ser = serial.Serial("COM15", 38400, timeout=100)

line=ser.readline()[:-1]
t1=time.time()
lines=0

data=[]

while True:
    line=ser.readline()[:-1]

    if "," in line:
        line=line.split(",")
        for i in range(len(line)):
            line[i]=line[i][::-1]
    else:
        line=[line[::-1]]
    temp=int(line[0])
    lines+=1
    data.append(temp)
    print "#",
    if lines%1000==999:
        numpy.save("DATA.npy",data)
        print
        print line
        print "%d lines in %.02f sec (%.02f vals/sec)"%(lines,
                time.time()-t1,lines/(time.time()-t1))
```

Here is the Python code to plot the data that has been saved:

```python
import numpy
import pylab

data=numpy.load("DATA.npy")
print data
data=data*.008 #convert to F
xs=numpy.arange(len(data))/9.95  #vals/sec
xs=xs/60.0# minutes
xs=xs/60.0# hours

pylab.plot(xs,data)
pylab.grid(alpha=.5)
pylab.axis([None,None,0*.008,1024*.008])
pylab.ylabel(r'$Delta$ Fahrenheit')
pylab.xlabel("hours")
pylab.show()
```
May 19th, 2013

Wireless Microcontroller / PC Interface for $3.21

Here I demonstrate a dirt-cheap method of transmitting data from any microchip to any PC using $3.21 in parts. I've had this idea for a while, but finally got it working tonight. On the transmit side, I'm having a an ATMEL AVR microcontroller (ATMega48) transmit data (every number from 0 to 200 over and over) wirelessly using 433mhz wireless modules. The PC receives the data through the microphone port of a sound card, and a cross-platform Python script I wrote decodes the data from the audio and graphs it on the screen. I did something similar back in 2011, but it wasn't wireless, and the software wasn't nearly as robust as it is now.

This is a proof-of-concept demonstration, and part of a larger project. I think there's a need for this type of thing though! It's unnecessarily hard to transfer data from a MCU to a PC as it is. There's USB (For AVR V-USB is a nightmare and requires a precise, specific clock speed, DIP chips don't have native USB, and some PIC DIP chips do but then you have to go through driver hell), USART RS-232 over serial port works (but who has serial ports these days?), or USART over USB RS-232 interface chips (like FTDI FT-232, but surface mount only), but both also require precise, specific clock speeds. Pretend I want to just measure temperature once a minute. Do I really want to etch circuit boards and solder SMT components? Well, kinda, but I don't like feeling forced to. Some times you just want a no-nonsense way to get some numbers from your microchip to your computer. This project is a funky out-of-the-box alternative to traditional methods, and one that I hope will raise a few eyebrows.

Ultimately, I designed this project to eventually allow multiple "bursting" data transmitters to transmit on the same frequency routinely, thanks to syncing and forced-sync-loss (read on). It's part of what I'm tongue-in-cheek calling the Scott Harden RF Protocol (SH-RFP). In my goal application, I wish to have about 5 wireless temperature sensors all transmitting data to my PC. The receive side has some error checking in that it makes sure pulse sizes are intelligent and symmetrical (unlike random noise), and since each number is sent twice (with the second time being in reverse), there's another layer of error-detection. This is *NOT* a robust and accurate method to send critical data. It's a cheap way to send data. It is very range limited, and only is intended to work over a distance of ten or twenty feet. First, let's see it in action!

The RF modules are pretty simple. At 1.56 on ebay (with free shipping), they're cheap too! I won't go into detail documenting the ins and out of these things (that's done well elsewhere). Briefly, you give them +5V (VCC), 0V (GND), and flip their data pin (ATAD) on and off on the transmitter module, and the receiver module's DATA pin reflects the same state. The receiver uses a gain circuit which continuously increases gain until signal is detected, so if you're not transmitting it WILL decode noise and start flipping its output pin. Note that persistent high or low states are prone to noise too, so any protocol you use these things for should have rapid state transitions. It's also suggested that you maintain an average 50% duty cycle. These modules utilize amplitude shift keying (ASK) to transmit data wirelessly. The graphic below shows what that looks like at the RF level. Transmit and receive is improved by adding a quarter-wavelength vertical antenna to the "ANT" solder pad. At 433MHz, that is about 17cm, so I'm using a 17cm copper wire as an antenna.

Transmitting from the microcontroller is easy as pie! It’s just a matter of copying-in a few lines of C. It doesn’t rely on USART, SPI, I2C, or any other protocol. Part of why I developed this method is because I often use ATTiny44A which doesn’t have USART for serial interfacing. The “SH-RFP” is easy to implement just by adding a few lines of code. I can handle that. How does it work? I can define it simply by a few rules:

  • Pulses can be one of 3 lengths: A (0), B (1), or C (break).
  • Each pulse represents high, then low of that length.

To send a packet:

  • prime synchronization by sending ten ABCs
  • indicate we’re starting data by sending C.
  • for each number you want to send:
  • send your number bit by bit (A=0, B=1)
  • send your number bit by bit (A=1, B=0)
  • indicate number end by sending C.
  • tell PC to release the signal by sending ten Cs.

Decoding is the same thing in reverse. I use an eBay sound card at $1.29 (with free shipping) to get the signal into the PC. Synchronization is required to allow the PC to know that real data (not noise) is starting. Sending the same number twice (once with reversed bit polarity) is a proof-checking mechanisms that lets us throw-out data that isn’t accurate.

From a software side, I’m using PyAudio to collect data from the sound card, and the PythonXY distribution to handle analysis with numpy, scipy, and plotting with QwtPlot, and general GUI functionality with PyQt. I think that’s about everything.

The demonstration interface is pretty self-explanatory. The top-right shows a sample piece of data. The top left is a histogram of the number of samples of each pulse width. A clean signal should have 3 pulses (A=0, B=1, C=break). Note that you’re supposed to look at the peaks to determine the best lengths to tell the software to use to distinguish A, B, and C. This was intentionally not hard-coded because I want to rapidly switch from one microcontroller platform to another which may be operating at a different clock speed, and if all the sudden it’s running 3 times slower it will be no problem to decide on the PC side. Slick, huh? The bottom-left shows data values coming in. The bottom-right graphs those values. Rate reporting lets us know that I'm receiving over 700 good data points a second. That's pretty cool, especially considering I'm recording at 44,100 Hz.

All source code (C files for an ATMega48 and Python scripts for the GUI) can be viewed here: SHRFP project on GitHub

If you use these concepts, hardware, or ideas in your project, let me know about it! Send me an email showing me your project – I’d love to see it. Good luck!

Markdown source code last modified on January 18th, 2021
---
title: Wireless Microcontroller / PC Interface for $3.21
date: 2013-05-19 01:32:46
tags: microcontroller, old, python
---

# Wireless Microcontroller / PC Interface for $3.21

__Here I demonstrate a dirt-cheap method of transmitting data from any microchip to any PC using $3.21 in parts.  __I've had this idea for a while, but finally got it working tonight. On the transmit side, I'm having a an ATMEL AVR microcontroller (ATMega48) transmit data (every number from 0 to 200 over and over) wirelessly using 433mhz wireless modules. The PC receives the data through the microphone port of a sound card, and a cross-platform Python script I wrote decodes the data from the audio and graphs it on the screen. I [did something similar back in 2011](http://www.swharden.com/blog/2011-07-09-sound-card-microcontrollerpc-communication/), but it wasn't wireless, and the software wasn't nearly as robust as it is now.

__This is a proof-of-concept demonstration, and part of a larger project.__ I think there's a need for this type of thing though! It's unnecessarily hard to transfer data from a MCU to a PC as it is. There's USB (For AVR [V-USB](http://www.obdev.at/products/vusb/index.html) is a nightmare and requires a precise, specific clock speed, DIP chips don't have native USB, and some PIC DIP chips do but then you have to go through driver hell), [USART RS-232 over serial port](http://www.swharden.com/blog/2009-05-14-simple-case-avrpc-serial-communication-via-max232/) works (but who has serial ports these days?), or USART over USB RS-232 interface chips (like [FTDI FT-232](http://www.ftdichip.com/Products/ICs/FT232R.htm), but surface mount only), but both also require precise, specific clock speeds. Pretend I want to just measure temperature once a minute. Do I _really_ want to etch circuit boards and solder SMT components? Well, kinda, but I don't like feeling forced to. Some times you just want a no-nonsense way to get some numbers from your microchip to your computer. This project is a funky out-of-the-box alternative to traditional methods, and one that I hope will raise a few eyebrows.

<div class="text-center img-border">

[![](c31_thumb.jpg)](c31.jpg)

</div>

__Ultimately, I designed this project to eventually allow multiple "bursting" data transmitters to transmit on the same frequency__ __routinely__, thanks to syncing and forced-sync-loss (read on). It's part of what I'm tongue-in-cheek calling the _Scott Harden RF Protocol_ (SH-RFP). In my goal application, I wish to have about 5 wireless temperature sensors all transmitting data to my PC.  The receive side has some error checking in that it makes sure pulse sizes are intelligent and symmetrical (unlike random noise), and since each number is sent twice (with the second time being in reverse), there's another layer of error-detection.  This is \*NOT\* a robust and accurate method to send critical data. It's a cheap way to send data. It is very range limited, and only is intended to work over a distance of ten or twenty feet. First, let's see it in action!

![](https://www.youtube.com/embed/GJHFldPwZvM)

__The RF modules are pretty simple. [At 1.56 on ebay](http://www.ebay.com/itm/KDQ11-NEW-1PCS-433MHZ-RF-TRANSMITTER-AND-RECEIVER-LINK-KIT-FOR-ARDUINO-SCA-1710-/350797631746?pt=LH_DefaultDomain_0&hash=item51ad2b1102) (with free shipping), they're cheap too!__ I won't go into detail documenting the ins and out of these things (that's done well elsewhere). Briefly, you give them +5V (VCC), 0V (GND), and flip their data pin (ATAD) on and off on the transmitter module, and the receiver module's DATA pin reflects the same state. The receiver uses a gain circuit which continuously increases gain until signal is detected, so if you're not transmitting it WILL decode noise and start flipping its output pin. Note that persistent high or low states are prone to noise too, so any protocol you use these things for should have rapid state transitions. It's also suggested that you maintain an average 50% duty cycle. These modules utilize [amplitude shift keying](http://en.wikipedia.org/wiki/Amplitude-shift_keying) (ASK) to transmit data wirelessly. The graphic below shows what that looks like at the RF level. Transmit and receive is improved by adding a quarter-wavelength vertical antenna to the "ANT" solder pad. At 433MHz, that is about 17cm, so I'm using a 17cm copper wire as an antenna.

__Transmitting from the microcontroller is easy as pie!__ It’s just a matter of copying-in a few lines of C.  It doesn’t rely on USART, SPI, I2C, or any other protocol. Part of why I developed this method is because I often use ATTiny44A which doesn’t have USART for serial interfacing. The “SH-RFP” is easy to implement just by adding a few lines of code. I can handle that.  How does it work? I can define it simply by a few rules:

*   Pulses can be one of 3 lengths: A (0), B (1), or C (break).
*   Each pulse represents high, then low of that length.

To send a packet:

*   prime synchronization by sending ten ABCs
*   indicate we’re starting data by sending C.
*   for each number you want to send:
  *   send your number bit by bit (A=0, B=1)
  *   send your number bit by bit (A=1, B=0)
  *   indicate number end by sending C.
*   tell PC to release the signal by sending ten Cs.

Decoding is the same thing in reverse. I use an [eBay sound card at $1.29](search.ebay.com/usb-sound-card) (with free shipping) to get the signal into the PC. </span> Synchronization is required to allow the PC to know that real data (not noise) is starting. Sending the same number twice (once with reversed bit polarity) is a proof-checking mechanisms that lets us throw-out data that isn’t accurate.

__From a software side,__ I’m using PyAudio to collect data from the sound card, and the PythonXY distribution to handle analysis with numpy, scipy, and plotting with QwtPlot, and general GUI functionality with PyQt. I think that’s about everything.

<div class="text-center img-border">

[![](SHRFP_thumb.jpg)](SHRFP.png)

</div>

__The demonstration interface is pretty self-explanatory.__ The top-right shows a sample piece of data. The top left is a histogram of the number of samples of each pulse width. A clean signal should have 3 pulses (A=0, B=1, C=break). Note that you’re supposed to look at the peaks to determine the best lengths to tell the software to use to distinguish A, B, and C. This was intentionally not hard-coded because I want to rapidly switch from one microcontroller platform to another which may be operating at a different clock speed, and if all the sudden it’s running 3 times slower it will be no problem to decide on the PC side. Slick, huh? The bottom-left shows data values coming in. The bottom-right graphs those values. Rate reporting lets us know that I'm receiving over 700 good data points a second. That's pretty cool, especially considering I'm recording at 44,100 Hz.

All source code (C files for an ATMega48 and Python scripts for the GUI) can be viewed here: [SHRFP project on GitHub](https://github.com/swharden/AVR-projects/tree/master/ATMega48%202013-05-14%20SHRFP%20monitor)

If you use these concepts, hardware, or ideas in your project, let me know about it! Send me an email showing me your project – I’d love to see it. Good luck!

May 7th, 2013

AVR Programming in 64-bit Windows 7

A majority of the microcontroller programming I do these days involves writing C for the ATMEL AVR series of microcontrollers. I respect PIC, but I find the open/free atmosphere around AVR to be a little more supportive to individual, non-commercial cross-platform programmers like myself. With that being said, I've had a few bumps along the way getting unofficial AVR programmers to work in Windows 7. Previously, I had great success with a $11 (shipped) clone AVRISP-mkII programmer from fun4diy.com. It was the heart of a little AVR development board I made and grew to love (which had a drop-in chip slot and also a little breadboard all in one) seen in a few random blog posts over the years. Recently it began giving me trouble because, despite downloading and installing various drivers and packages, I couldn't get it to work with Windows Vista or windows 7. I needed to find another option. I decided against the official programmer/software because the programmer is expensive (for a college student) and the software (AVR studio 6) is terribly bloated for LED-blink type applications. "AStudio61.exe" is 582.17 Mb. Are you kidding me? Half a gig to program a microchip with 2kb of memory? Rediculous. I don't use arduino because I'm comfortable working in C and happy reading datasheets. Furthermore, I like programming chips hot off the press, without requiring a special boot loader.

I got everything running on Windows 7 x64 with the following:

Here's the "hello world" of microchip programs (it simply blinks an LED). I'll assume the audience of this page knows the basics of microcontroller programming, so I won't go into the details. Just note that I'm using an ATMega48 and the LED is on pin 9 (PB6). This file is named "blink.c".

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

int main (void)
{
    DDRB = 255;
    while(1)
    {
        PORTB ^= 255;
        _delay_ms(500);
    }
}

Here's how I compiled the code:

avr-gcc -mmcu=atmega48 -Wall -Os -o blink.elf blink.c
avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex

In reality, it is useful to put these commands in a text file and call them "compile.bat" Here's how I program the AVR. I used AVRDudess! I've been using raw AVRDude for years. It's a little rough around the edges, but this GUI interface is pretty convenient. I don't even feel the need to include the command to program it from the command line! If I encourage nothing else by this post, I encourage (a) people to use and support AVRDudess, and (b) AVRDudess to continue developing itself as a product nearly all hobby AVR programmers will use. Thank you 21-year-old Zak Kemble.

And finally, the result. A blinking LED. Up and running programming AVR microcontrollers in 64-bit Windows 7 with an unofficial programmer, and never needing to install bloated AVR Studio software.

Markdown source code last modified on January 18th, 2021
---
title: AVR Programming in 64-bit Windows 7
date: 2013-05-07 18:14:58
tags: microcontroller, old
---

# AVR Programming in 64-bit Windows 7

__A majority of the microcontroller programming I do these days involves writing C for the ATMEL AVR series of microcontrollers.__ I respect PIC, but I find the open/free atmosphere around AVR to be a little more supportive to individual, non-commercial cross-platform programmers like myself. With that being said, I've had a few bumps along the way getting unofficial AVR programmers to work in Windows 7. Previously, I had great success with a $11 (shipped) [clone AVRISP-mkII programmer](http://fun4diy.com/AVRISP_mkII.htm)  from fun4diy.com. It was the heart of a little AVR development board I made and grew to love (which had a drop-in chip slot and also a little breadboard all in one) seen in a [few](http://www.swharden.com/blog/2010-12-28-full-auto-rapidfire-mouse-modification/) random blog [posts](http://www.swharden.com/blog/2010-05-24-solar-powered-qrss-beacon/) over the years. Recently it began giving me trouble because, despite downloading and installing various drivers and packages, I couldn't get it to work with Windows Vista or windows 7. I needed to find another option. I decided against the official programmer/software because the programmer is expensive (for a college student) and the software (AVR studio 6) is terribly bloated for LED-blink type applications. "AStudio61.exe" is 582.17 Mb. Are you kidding me? Half a gig to program a microchip with 2kb of memory? Rediculous.  I don't use [arduino](http://en.wikipedia.org/wiki/Arduino) because I'm comfortable working in C and happy reading datasheets. Furthermore, I like programming chips hot off the press, without requiring a special boot loader.

<div class="text-center img-border">

[![](2013-05-05-22.57.01_thumb.jpg)](2013-05-05-22.57.01.jpg)

</div>

I got everything running on Windows 7 x64 with the following:

* **Programmer:** USBTinyISP (eBay, $8.50 free shipping)___It's a branch of an unofficial AvrISP-mkII project. [Ladyada.net provides](http://www.ladyada.net/make/usbtinyisp/) code, [schematics](http://www.ladyada.net/make/usbtinyisp/make.html), and even an option to buy a [built-it-yourself kit](http://www.adafruit.com/category/16) for $~22 (+shipping) through adafruit. However I found them [pre-assembled with SMT components for $8.48 shipped on eBay](http://www.ebay.com/sch/usbtiny). _

* **Drivers:** Find them on the[ Ladyada page](http://www.ladyada.net/make/usbtinyisp/download.html). (Free)___There are links at the top for 32-bit and 64-bit windows._

* **Compiler Software:** [WinAvr](http://winavr.sourceforge.net/index.html) (Free)___This is windows software. Linux users want a different flavor of AVR-GCC and should see my previous post on [programming AVR in Ubuntu Linux](http://www.swharden.com/blog/2013-01-06-avr-programming-in-linux/)_

* **Programming Software:** [AVRDudess](http://blog.zakkemble.co.uk/avrdudess-a-gui-for-avrdude/) (Free)___This is actually a GUI for [AVRDude](http://www.ladyada.net/make/usbtinyisp/avrdude.html), a command line driven programmer. It has a [great tutorial](http://www.ladyada.net/learn/avr/avrdude.html) though. I accidentally keep thinking (and searching) for this program by the incorrect title AVRDudette._


__Here's the "hello world" of microchip programs (it simply blinks an LED).__ I'll assume the audience of this page knows the basics of microcontroller programming, so I won't go into the details. Just note that I'm using an ATMega48 and the LED is on pin 9 (PB6). This file is named "blink.c".

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

int main (void)
{
    DDRB = 255;
    while(1)
    {
        PORTB ^= 255;
        _delay_ms(500);
    }
}
```

__Here's how I compiled the code:__

```bash
avr-gcc -mmcu=atmega48 -Wall -Os -o blink.elf blink.c
avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex
```

_In reality, it is useful to put these commands in a text file and call them "compile.bat"_
__Here's how I program the AVR.__ I used [AVRDudess](http://blog.zakkemble.co.uk/avrdudess-a-gui-for-avrdude/)! I've been using raw AVRDude for years. It's a little rough around the edges, but this GUI interface is pretty convenient. I don't even feel the need to include the command to program it from the command line! If I encourage nothing else by this post, I encourage (a) people to use and support AVRDudess, and (b) AVRDudess to continue developing itself as a product nearly all hobby AVR programmers will use. Thank you 21-year-old Zak Kemble.

<div class="text-center img-border">

[![](2013-05-05-22.56.20_thumb.jpg)](2013-05-05-22.56.20.jpg)

</div>

__And finally, the result.__ A blinking LED. Up and running programming AVR microcontrollers in 64-bit Windows 7 with an unofficial programmer, and never needing to install bloated AVR Studio software.

<div class="text-center img-border">

[![](2013-05-05-23.05.53_thumb.jpg)](2013-05-05-23.05.53.jpg)

</div>
April 14th, 2013

Simple DIY ECG + Pulse Oximeter (version 2)

⚠️ Check out my newer ECG designs:

Of the hundreds of projects I've shared over the years, none has attracted more attention than my DIY ECG machine on the cheap posted almost 4 years ago. This weekend I re-visited the project and made something I'm excited to share! The original project was immensely popular, my first featured article on Hack-A-Day, and today "ECG" still represents the second most searched term by people who land on my site. My gmail account also has had 194 incoming emails from people asking details about the project. A lot of it was by frustrated students trying to recreate the project running into trouble because it was somewhat poorly documented. Clearly, it's a project that a wide range of people are interested in, and I'm happy to revisit it bringing new knowledge and insight to the project. I will do my best to document it thoroughly so anyone can recreate it!

The goal of this project is to collect heartbeat information on a computer with minimal cost and minimal complexity. I accomplished this with fewer than a dozen components (all of which can be purchased at RadioShack). It serves both as a light-based heartbeat monitor (similar to a pulse oximeter, though it's not designed to quantitatively measure blood oxygen saturation), and an electrocardiogram (ECG) to visualize electrical activity generated by heart while it contracts. Let's jump right to the good part - this is what comes out of the machine:

That's my actual heartbeat. Cool, right? Before I go into how the circuit works, let's touch on how we measure heartbeat with ECG vs. light (like a pulse oximeter). To form a heartbeat, the pacemaker region of the heart (called the SA node, which is near the upper right of the heart) begins to fire and the atria (the two top chambers of the heart) contract. The SA node generates a little electrical shock which stimulated a synchronized contraction. This is exactly what defibrillators do when a heart has stopped beating. When a heart attack is occurring and a patient is undergoing ventricular fibrillation, it means that heart muscle cells are contracting randomly and not in unison, so the heart quivers instead of pumping as an organ. Defibrillators synchronize the heart beat with a sudden rush of current over the heart to reset all of the cells to begin firing at the same time (thanks Ron for requesting a more technical description). If a current is run over the muscle, the cells (cardiomyocytes) all contract at the same time, and blood moves. The AV node (closer to the center of the heart) in combination with a slow conducting pathway (called the bundle of His) control contraction of the ventricles (the really large chambers at the bottom of the heart), which produce the really large spikes we see on an ECG. To measure ECG, optimally we'd place electrodes on the surface of the heart. Since that would be painful, we do the best we can by measuring voltage changes (often in the mV range) on the surface of the skin. If we amplify it enough, we can visualize it. Depending on where the pads are placed, we can see different regions of the heart contract by their unique electrophysiological signature. ECG requires sticky pads on your chest and is extremely sensitive to small fluctuations in voltage. Alternatively, a pulse oximeter measures blood oxygenation and can monitor heartbeat by clipping onto a finger tip. It does this by shining light through your finger and measuring how much light is absorbed. This goes up and down as blood is pumped through your finger. If you look at the relationship between absorbency in the red vs. infrared wavelengths, you can infer the oxygenation state of the blood. I'm not doing that today because I'm mostly interested in detecting heart beats.

For operation as a pulse oximeter-type optical heartbeat detector (a photoplethysmograph which produces a photoplethysmogram), I use a bright red LED to shine light through my finger and be detected by a phototransistor (bottom left of the diagram). I talk about how this works in more detail in a previous post. Basically the phototransistor acts like a variable resistor which conducts different amounts of current depending on how much light it sees. This changes the voltage above it in a way that changes with heartbeats. If this small signal is used as the input, this device acts like a pulse oximeter.

For operation as an electrocardiograph (ECG), I attach the (in) directly to a lead on my chest. One of them is grounded (it doesn't matter which for this circuit - if they're switched the ECG just looks upside down), and the other is recording. In my original article, I used pennies with wires soldered to them taped to my chest as leads. Today, I'm using fancier sticky pads which are a little more conductive. In either case, one lead goes in the center of your chest, and the other goes to your left side under your arm pit. I like these sticky pads because they stick to my skin better than pennies taped on with electrical tape. I got 100 Nikomed Nikotabs EKG Electrodes 0315 on eBay for $5.51 with free shipping (score!). Just gator clip to them and you're good to go!

In both cases, I need to build a device to amplify small signals. This is accomplished with the following circuit. The core of the circuit is an LM324 quad operational amplifier. These chips are everywhere, and extremely cheap. It looks like Thai Shine sells 10 for $2.86 (with free shipping). That's about a quarter each. Nice! A lot of ECG projects use instrumentation amplifiers like the AD620 (which I have used with fantastic results), but these are expensive (about $5.00 each). The main difference is that instrumentation amplifiers amplify the difference between two points (which reduces noise and probably makes for a better ECG machine), but for today an operational amplifier will do a good enough job amplifying a small signal with respect to ground. I get around the noise issue by some simple filtering techniques. Let's take a look at the circuit.

This project utilizes one of the op-amps as a virtual ground. One complaint of using op-amps in simple projects is that they often need + and - voltages. Yeah, this could be done with two 9V batteries to generate +9V and -9V, but I think it's easier to use a single power source (+ and GND). A way to get around that is to use one of the op-amps as a current source and feed it half of the power supply voltage (VCC), and use the output as a virtual ground (allowing VCC to be your + and 0V GND to be your -). For a good description of how to do this intelligently, read the single supply op amps web page. The caveat is that your signals should remain around VCC/2, which can be done if it is decoupled by feeding it through a series capacitor. The project works at 12V or 5V, but was designed for (and has much better output) at 12V. The remaining 3 op-amps of the LM324 serve three unique functions:

STAGE 1: High gain amplifier. The input signals from either the ECG or pulse oximeter are fed into a chain of 3 opamp stages. The first is a preamplifier. The output is decoupled through a series capacitor to place it near VCC/2, and amplified greatly thanks to the 1.8Mohm negative feedback resistor. Changing this value changes initial gain.

STAGE 2: active low-pass filter. The 10kOhm variable resistor lets you adjust the frequency cutoff. The opamp serves as a unity gain current source / voltage follower that has high input impedance when measuring the output f the low-pass filter and reproduces its voltage with a low impedance output. There's some more information about active filtering on this page. It's best to look at the output of this stage and adjust the potentiometer until the 60Hz noise (caused by the AC wiring in the walls) is most reduced while the lower-frequency component of your heartbeat is retained. With the oximeter, virtually no noise gets through. Because the ECG signal is much smaller, this filter has to be less aggressive, and this noise is filtered-out by software (more on this later).

STAGE 3: final amplifier with low-pass filter. It has a gain of ~20 (determined by the ratio of the 1.8kOhm to 100Ohm resistors) and lowpass filtering components are provided by the 22uF capacitor across the negative feedback resistor. If you try to run this circuit at 5V and want more gain (more voltage swing), consider increasing the value of the 1.8kOhm resistor (wit the capacitor removed). Once you have a good gain, add different capacitor values until your signal is left but the noise reduced. For 12V, these values work fine. Let's see it in action!

Now for the second half - getting it into the computer. The cheapest and easiest way to do this is to simply feed the output into a sound card! A sound card is an analog-to-digital converter (ADC) that everybody has and can sample up to 48 thousand samples a second! (overkill for this application) The first thing you should do is add an output potentiometer to allow you to drop the voltage down if it's too big for the sound card (in the case of the oximeter) but but also allow full-volume in the case of sensitive measurements (like ECG). Then open-up sound editing software (I like GoldWave for Windows or Audacity for Linux, both of which are free) and record the input. You can do filtering (low-pass filter at 40Hz with a sharp cutoff) to further eliminate any noise that may have sneaked through. Re-sample at 1,000 Hz (1kHz) and save the output as a text file and you're ready to graph it! Check it out.

Here are the results of some actual data recorded and processed with the method shown in the video. let's look at the pulse oximeter first.

That looks pretty good, certainly enough for heartbeat detection. There's obvious room for improvement, but as a proof of concept it's clearly working. Let's switch gears and look at the ECG. It's much more challenging because it's signal is a couple orders of magnitude smaller than the pulse oximeter, so a lot more noise gets through. Filtering it out offers dramatic improvements!

Here's the code I used to generate the graphs from the text files that GoldWave saves. It requires Python, Matplotlib (pylab), and Numpy. In my case, I'm using 32-bit 2.6 versions of everything.

# DIY Sound Card ECG/Pulse Oximeter
# by Scott Harden (2013) http://www.SWHarden.com

import pylab
import numpy

f=open("light.txt")
raw=f.readlines()[1:]
f.close()

data = numpy.array(raw,dtype=float)
data = data-min(data) #make all points positive
data = data/max(data)*100.0 #normalize
times = numpy.array(range(len(data)))/1000.0
pylab.figure(figsize=(15,5))
pylab.plot(times,data)
pylab.xlabel("Time Elapsed (seconds)")
pylab.ylabel("Amplitude (% max)")
pylab.title("Pulse Oximeter - filtered")
pylab.subplots_adjust(left=.05,right=.98)
pylab.show()

Future directions involve several projects I hope to work on soon. First, it would be cool to miniaturize everything with surface mount technology (SMT) to bring these things down to the size of a postage stamp. Second, improved finger, toe, or ear clips (or even taped-on sensors) over long duration would provide a pretty interesting way to analyze heart rate variability or modulation in response to stress, sleep apnea, etc. Instead of feeding the signal into a computer, one could send it to a micro-controller for processing. I've made some darn-good progress making multi-channel cross-platform USB option for getting physiology data into a computer, but have some work still to do. Alternatively, this data could be graphed on a graphical LCD for an all-in-one little device that doesn't require a computer. Yep, lots of possible projects can use this as a starting point.

Notes about safety: If you're worried about electrical shock, or unsure of your ability to make a safe device, don't attempt to build an ECG machine. For an ECG to work, you have to make good electrical contact with your skin near your heart, and some people feel this is potentially dangerous. Actually, some people like to argue about how dangerous it actually is, as seen on Hack-A-Day comments and my previous post comments. Some people have suggested the danger is negligible and pointed-out that it's similar to inserting ear-bud headphones into your ears. Others have suggested that it's dangerous and pointed-out that milliamps can kill a person. Others contest that pulses of current are far more dangerous than a continuous applied current. Realists speculate that virtually no current would be delivered by this circuit if it is wired properly. Rational, cautionary people worried about it reduce risk of accidental current by applying bidirectional diodes at the level of the chest leads, which short any current (above 0.7V) similar to that shown here. Electrically-savvy folks would design an optically decoupled solution. Intelligent folks who abstain from arguing on the internet would probably consult the datasheets regarding ECG input protection. In all cases, don't attach electrical devices to your body unless you are confident in their safety. As a catch-all, I present the ECG circuit for educational purposes only, and state that it may not be safe and should not be replicated There, will that cover me in court in case someone tapes wires to their chest and plugs them in the wall socket?

LET ME KNOW WHAT YOU THINK! If you make this, I'm especially interested to see how it came out. Take pictures of your projects and send them my way! If you make improvements, or take this project further, I'd be happy to link to it on this page. I hope this page describes the project well enough that anyone can recreate it, regardless of electronics experience. Finally, I hope that people are inspired by the cool things that can be done with surprisingly simple electronics. Get out there, be creative, and go build something cool!

Markdown source code last modified on January 18th, 2021
---
title: Simple DIY ECG + Pulse Oximeter (version 2)
date: 2013-04-14 16:00:14
tags: diyECG, microcontroller, old
---

# Simple DIY ECG + Pulse Oximeter (version 2)

> **⚠️ Check out my newer ECG designs:** 
* [**Sound Card ECG with AD8232**](https://swharden.com/blog/2019-03-15-sound-card-ecg-with-ad8232/)
* [**Single op-amp ECG**](https://swharden.com/blog/2016-08-08-diy-ecg-with-1-op-amp/)

__Of the hundreds of projects I've shared over the years, none has attracted more attention than my [DIY ECG machine on the cheap](http://www.swharden.com/blog/2009-08-14-diy-ecg-machine-on-the-cheap/) posted almost 4 years ago. This weekend I re-visited the project and made something I'm excited to share!__  The original project was immensely popular, my [first featured article on Hack-A-Day](http://hackaday.com/2009/08/22/collect-and-analyze-ecg-data/), and today "ECG" still represents the second most searched term by people who land on my site. My gmail account also has had 194 incoming emails from people asking details about the project. A lot of it was by frustrated students trying to recreate the project running into trouble because it was somewhat poorly documented. Clearly, it's a project that a wide range of people are interested in, and I'm happy to revisit it bringing new knowledge and insight to the project. I will do my best to document it thoroughly so anyone can recreate it!

<div class="text-center img-border">

[![](diy-ecg-pulse-oximeter-lm324-opamp-sound-card_thumb.jpg)](diy-ecg-pulse-oximeter-lm324-opamp-sound-card.jpg)

</div>

__The goal of this project is to collect heartbeat information on a computer with minimal cost and minimal complexity.__  I accomplished this with fewer than a dozen components (all of which can be purchased at RadioShack). It serves both as a light-based heartbeat monitor (similar to a pulse oximeter, though it's not designed to quantitatively measure blood oxygen saturation), and an electrocardiogram (ECG) to visualize electrical activity generated by heart while it contracts. Let's jump right to the good part - this is what comes out of the machine:

<div class="text-center">

[![](pulse-ecg-filtered-a_thumb.jpg)](pulse-ecg-filtered-a.png)

</div>

<strong>That's <em>my</em> actual heartbeat. Cool, right? Before I go into how the circuit works, let's touch on how we measure heartbeat with ECG vs. light (like a pulse oximeter).</strong>  To form a heartbeat, the pacemaker region of the heart (called the SA node, which is near the upper right of the heart) begins to fire and the atria (the two top chambers of the heart) contract. The SA node generates a little electrical shock which stimulated a synchronized contraction. <span style="text-decoration: line-through;">This is exactly what defibrillators do when a heart has stopped beating.</span> When a heart attack is occurring and a patient is undergoing ventricular fibrillation, it means that heart muscle cells are contracting randomly and not in unison, so the heart quivers instead of pumping as an organ. Defibrillators synchronize the heart beat with a sudden rush of current over the heart to reset all of the cells to begin firing at the same time (thanks Ron for requesting a more technical description).  If a current is run over the muscle, the cells (cardiomyocytes) all contract at the same time, and blood moves. The AV node (closer to the center of the heart) in combination with a slow conducting pathway (called the bundle of His) control contraction of the ventricles (the really large chambers at the bottom of the heart), which produce the really large spikes we see on an ECG.  <strong>To measure ECG</strong>, optimally we'd place electrodes on the surface of the heart. Since that would be painful, we do the best we can by measuring voltage changes (often in the mV range) on the surface of the skin. If we amplify it enough, we can visualize it. Depending on where the pads are placed, we can see different regions of the heart contract by their unique electrophysiological signature. ECG requires sticky pads on your chest and is extremely sensitive to small fluctuations in voltage. Alternatively, <strong>a pulse oximeter measures blood oxygenation and can monitor heartbeat by clipping onto a finger tip</strong>. It does this by shining light through your finger and measuring how much light is absorbed. This goes up and down as blood is pumped through your finger. If you look at the relationship between absorbency in the red vs. infrared wavelengths, you can infer the oxygenation state of the blood. I'm not doing that today because I'm mostly interested in detecting heart beats.

<strong>For operation as a pulse oximeter-type optical heartbeat detector (a <em>photoplethysmograph</em> which produces a <a href="http://en.wikipedia.org/wiki/Photoplethysmogram"><em>photoplethysmogram</em></a>),</strong> I use a bright red LED to shine light through my finger and be detected by a phototransistor (bottom left of the diagram). I talk about how this works in more detail <a href="http://www.swharden.com/blog/2012-12-06-single-wavelength-pulse-oximeter/">in a previous post</a>. Basically the phototransistor acts like a variable resistor which conducts different amounts of current depending on how much light it sees. This changes the voltage above it in a way that changes with heartbeats. If this small signal is used as the input, this device acts like a pulse oximeter.

<div class="text-center img-border">

[![](2013-04-14-11.36.39_thumb.jpg)](2013-04-14-11.36.39.jpg)

</div>

<strong>For operation as an electrocardiograph (ECG)</strong>, I attach the (in) directly to a lead on my chest. One of them is grounded (it doesn't matter which for this circuit - if they're switched the ECG just looks upside down), and the other is recording. In my <a href="http://www.swharden.com/blog/2009-08-14-diy-ecg-machine-on-the-cheap/">original article</a>, I used pennies with wires soldered to them taped to my chest as leads. Today, I'm using fancier sticky pads which are a little more conductive. In either case, one lead goes in the center of your chest, and the other goes to your left side under your arm pit. I like these sticky pads because they stick to my skin better than pennies taped on with electrical tape. I got <a href="http://www.ebay.com/sch/i.html?_trksid=m570.l3201&_nkw=100+NIKOMED+NIKOTABS+EKG+ELECTRODES+0315&_sacat=0">100 Nikomed Nikotabs EKG Electrodes 0315</a> on eBay for $5.51 with free shipping (score!). Just gator clip to them and you're good to go!

<div class="text-center img-border">

[![](2013-04-14-15.06.20_thumb.jpg)](2013-04-14-15.06.20.jpg)

</div>

__In both cases, I need to build a device to amplify small signals__. This is accomplished with the following circuit. The core of the circuit is an [LM324 quad operational amplifier](http://www.ti.com/lit/ds/symlink/lm124-n.pdf).  These chips are everywhere, and extremely cheap. It looks like [Thai Shine sells 10 for $2.86](http://www.thaishine.com/servlet/the-910/10-x-LM324N-LM324/Detail) (with free shipping). That's about a quarter each. Nice!  A lot of ECG projects use instrumentation amplifiers like the AD620 (which I have used with [fantastic results](http://www.swharden.com/blog/2012-06-14-multichannel-usb-analog-sensor-with-atmega48/)), but these are expensive (about $5.00 each). The main difference is that instrumentation amplifiers amplify the difference between two points (which reduces noise and probably makes for a better ECG machine), but for today an operational amplifier will do a good enough job amplifying a small signal with respect to ground. I get around the noise issue by some simple filtering techniques. Let's take a look at the circuit.

<div class="text-center img-border">

[![](lm324-opamp-pulse-oximeter-ecg-schematic_thumb.jpg)](lm324-opamp-pulse-oximeter-ecg-schematic.jpg)

</div>

<strong>This project utilizes one of the op-amps as a <a href="http://en.wikipedia.org/wiki/Virtual_ground">virtual ground</a>.</strong> One complaint of using op-amps in simple projects is that they often need + and - voltages. Yeah, this <a href="http://cdn.head-fi.org/8/80/801b6a4a_principle.gif">could be done with two 9V batteries</a> to generate +9V and -9V, but I think it's easier to use a single power source (+ and GND). A way to get around that is to use one of the op-amps as a current source and feed it half of the power supply voltage (VCC), and use the output as a virtual ground (allowing VCC to be your + and 0V GND to be your -). For a good description of how to do this intelligently, read the <a href="http://www.swarthmore.edu/NatSci/echeeve1/Ref/SingleSupply/SingleSupply.html">single supply op amps web page</a>. The caveat is that your signals should remain around VCC/2, which can be done if it is decoupled by feeding it through a series capacitor. The project works at 12V or 5V, but was designed for (and has much better output) at 12V. The remaining 3 op-amps of the LM324 serve three unique functions:

<strong>STAGE 1: High gain amplifier.</strong> The input signals from either the ECG or pulse oximeter are fed into a chain of 3 opamp stages. The first is a preamplifier. The output is decoupled through a series capacitor to place it near VCC/2, and amplified greatly thanks to the 1.8Mohm negative feedback resistor. Changing this value changes initial gain.

<strong>STAGE 2: active low-pass filter.</strong> The 10kOhm variable resistor lets you adjust the frequency cutoff. The opamp serves as a unity gain current source / voltage follower that has high input impedance when measuring the output f the low-pass filter and reproduces its voltage with a low impedance output. There's some <a href="http://www.electronics-tutorials.ws/filter/filter_5.html">more information about active filtering on this page</a>. It's best to look at the output of this stage and adjust the potentiometer until the 60Hz noise (caused by the AC wiring in the walls) is most reduced while the lower-frequency component of your heartbeat is retained. With the oximeter, virtually no noise gets through. Because the ECG signal is much smaller, this filter has to be less aggressive, and this noise is filtered-out by software (more on this later).

<strong>STAGE 3: final amplifier with low-pass filter.</strong> It has a gain of ~20 (determined by the ratio of the 1.8kOhm to 100Ohm resistors) and lowpass filtering components are provided by the 22uF capacitor across the negative feedback resistor. If you try to run this circuit at 5V and want more gain (more voltage swing), consider increasing the value of the 1.8kOhm resistor (wit the capacitor removed). Once you have a good gain, add different capacitor values until your signal is left but the noise reduced. For 12V, these values work fine. Let's see it in action!

<iframe frameborder="0" height="360" src="http://www.youtube.com/embed/bKAJsZJvMI0?list=UUs3-qUELPY-2AOHa7Q_db5w" width="640"></iframe>

<strong>Now for the second half - getting it into the computer.</strong> The cheapest and easiest way to do this is to simply feed the output into a sound card! A sound card is an analog-to-digital converter (ADC) that <em>everybody</em> has and can sample up to 48 thousand samples a second! (overkill for this application) The first thing you should do is add an output potentiometer to allow you to drop the voltage down if it's too big for the sound card (in the case of the oximeter) but but also allow full-volume in the case of sensitive measurements (like ECG). Then open-up sound editing software (I like <a href="http://www.goldwave.com/">GoldWave</a> for Windows or <a href="http://audacity.sourceforge.net/">Audacity</a> for Linux, both of which are free) and record the input. You can do filtering (low-pass filter at 40Hz with a sharp cutoff) to further eliminate any noise that may have sneaked through. Re-sample at 1,000 Hz (1kHz) and save the output as a text file and you're ready to graph it! Check it out.

<iframe frameborder="0" height="360" src="http://www.youtube.com/embed/9BFS9D3x_sY?list=UUs3-qUELPY-2AOHa7Q_db5w" width="640"></iframe>

__Here are the results__ of some actual data recorded and processed with the method shown in the video. let's look at the pulse oximeter first.

<div class="text-center">

[![](pulse-ecg-filtered-a_thumb.jpg)](pulse-ecg-filtered-a.png)

</div>

<strong>That looks pretty good, certainly enough for heartbeat detection.</strong> There's obvious room for improvement, but as a proof of concept it's clearly working. Let's switch gears and look at the ECG. It's much more challenging because it's signal is a couple orders of magnitude smaller than the pulse oximeter, so a lot more noise gets through. Filtering it out offers dramatic improvements!

<div class="text-center">

[![](pulse-oximeter-a_thumb.jpg)](pulse-oximeter-a.png)
[![](pulse-oximeter-b_thumb.jpg)](pulse-oximeter-b.png)

</div>

<strong>Here's the code</strong> I used to generate the graphs from the text files that GoldWave saves. It requires <a href="http://www.Python.org">Python</a>, <a href="http://matplotlib.org/">Matplotlib (pylab)</a>, and <a href="http://www.scipy.org/Download">Numpy</a>. In my case, I'm using 32-bit 2.6 versions of everything.

```python
# DIY Sound Card ECG/Pulse Oximeter
# by Scott Harden (2013) http://www.SWHarden.com

import pylab
import numpy

f=open("light.txt")
raw=f.readlines()[1:]
f.close()

data = numpy.array(raw,dtype=float)
data = data-min(data) #make all points positive
data = data/max(data)*100.0 #normalize
times = numpy.array(range(len(data)))/1000.0
pylab.figure(figsize=(15,5))
pylab.plot(times,data)
pylab.xlabel("Time Elapsed (seconds)")
pylab.ylabel("Amplitude (% max)")
pylab.title("Pulse Oximeter - filtered")
pylab.subplots_adjust(left=.05,right=.98)
pylab.show()
```

<strong>Future directions involve several projects</strong> I hope to work on soon. First, it would be cool to miniaturize everything with surface mount technology (SMT) to bring these things down to the size of a postage stamp. Second, improved finger, toe, or ear clips (or even taped-on sensors) over long duration would provide a pretty interesting way to analyze heart rate variability or modulation in response to stress, sleep apnea, etc. Instead of feeding the signal into a computer, one could send it to a micro-controller for processing. I've made some <a href="http://www.swharden.com/blog/2012-06-14-multichannel-usb-analog-sensor-with-atmega48/">darn-good progress making multi-channel cross-platform USB option for getting physiology data into a computer</a>, but have some work still to do. Alternatively, this data could be graphed on a <a href="http://learn.adafruit.com/system/assets/assets/000/000/899/medium800/graphiclcd.jpg?1342115751">graphical LCD</a> for an all-in-one little device that doesn't require a computer. Yep, lots of possible projects can use this as a starting point.

<strong>Notes about safety:</strong> If you're worried about electrical shock, or unsure of your ability to make a safe device, don't attempt to build an ECG machine. For an ECG to work, you have to make good electrical contact with your skin near your heart, and some people feel this is potentially dangerous. Actually, some people like to argue about how dangerous it actually is, as seen on <a href="http://hackaday.com/2009/08/22/collect-and-analyze-ecg-data/#comments">Hack-A-Day comments</a> and my <a href="http://www.swharden.com/blog/2009-08-14-diy-ecg-machine-on-the-cheap/#comments">previous post comments</a>. Some people have suggested the danger is negligible and pointed-out that it's similar to inserting ear-bud headphones into your ears. Others have suggested that it's dangerous and pointed-out that <a href="http://hypertextbook.com/facts/2000/JackHsu.shtml">milliamps can kill a person</a>. Others contest that pulses of current are far more dangerous than a continuous applied current. Realists speculate that virtually no current would be delivered by this circuit if it is wired properly. Rational, cautionary people worried about it reduce risk of accidental current by applying bidirectional diodes at the level of the chest leads, which short any current (above 0.7V) similar to <a href="http://www.extremecircuits.net/2010/07/ecg-amplifier-by-tlc274.html">that shown here</a>. Electrically-savvy folks would design an optically decoupled solution. Intelligent folks who abstain from arguing on the internet would probably consult the <a href="http://www.analog.com/static/imported-files/tech_articles/MS-2160.pdf">datasheets regarding ECG input protection</a>. In all cases, don't attach electrical devices to your body unless you are confident in their safety. As a catch-all, I present the ECG circuit for educational purposes only, and state that it may not be safe and should not be replicated  There, will that cover me in court in case someone tapes wires to their chest and plugs them in the wall socket?

<strong>LET ME KNOW WHAT YOU THINK!</strong> If you make this, I'm especially interested to see how it came out. Take pictures of your projects and send them my way! If you make improvements, or take this project further, I'd be happy to link to it on this page. I hope this page describes the project well enough that anyone can recreate it, regardless of electronics experience. Finally, I hope that people are inspired by the cool things that can be done with surprisingly simple electronics. Get out there, be creative, and go build something cool!
January 6th, 2013

AVR Programming in Linux

It is not difficult to program ATMEL AVR microcontrollers with linux, and I almost exclusively do this because various unofficial (inexpensive) USB AVR programmers are incompatible with modern versions of windows (namely Windows Vista and Windows 7). I am just now setting-up a new computer station in my electronics room (running Ubuntu Linux 12.04), and to make it easy for myself in the future I will document everything I do when I set-up a Linux computer to program microcontrollers.

Install necessary software

sudo apt-get install gcc-avr avr-libc uisp avrdude

Connect the AVR programmer

This should be intuitive for anyone who has programmed AVRs before. Visit the datasheet of your MCU, identify pins for VCC (+), GND (-), MOSI, MISO, SCK, and RESET, then connect them to the appropriate pins of your programmer.

Write a simple program in C

I made a file "main.c" and put the following inside. It's the simplest-case code necessary to make every pin on PORTD (PD0, PD1, ..., PD7) turn on and off repeatedly, sufficient to blink an LED.

#include <avr/io.h>
#include <util/delay.h>

int main (void)
{
 DDRD = 255; // MAKE ALL PORT D PINS OUTPUTS

 while(1) {
  PORTD = 255;_delay_ms(100); // LED ON
  PORTD = 0;  _delay_ms(100); // LED OFF
 }

 return 0;
}

Compile the code (generate a HEX file)

avr-gcc -w -Os -DF_CPU=2000000UL -mmcu=atmega8 -c -o main.o main.c
avr-gcc -w -mmcu=atmega8 main.o -o main
avr-objcopy -O ihex -R .eeprom main main.hex

note that the arguments define CPU speed and chip model - this will need to be customized for your application

Program the HEX firmware onto the AVR

sudo avrdude -F -V -c avrispmkII -p ATmega8 -P usb -U flash:w:main.hex

note that this line us customized based on my connection (-P flag, USB in my case) and programmer type (-c flag, AVR ISP mkII in my case)

When this is run, you will see something like this:

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

avrdude: Device signature = 0x1e9307
avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "main.hex"
avrdude: input file main.hex auto detected as Intel Hex
avrdude: writing flash (94 bytes):

Writing | ################################################## | 100% 0.04s

avrdude: 94 bytes of flash written

Your Program should now be loaded!

Sit back and watch your LED blink.

  • TIP 1: I'm using a clone AVRISP mkII from Fun4DIY.com which is only $11 (shipped!). I glued it to a perf-board with a socket so I can jumper its control pins to any DIP AVR (80 pins or less). I also glued a breadboard for my convenience, and added LEDs (with ground on one of their pins) for easy jumpering to test programs. You can also build your own USB AVR ISP (free schematics and source code) from the USBtinyISP project website.

  • TIP 2: Make a shell script to run your compiling / flashing commands with a single command. Name them according to architecture. i.e., "build-m8" or "build-t2313". Make the first line delete all .hex files in the directory, so it stalls before it loads old .hex files if the compile is unsuccessful. Make similar shell scripts to program fuses. i.e., "fuse-m8-IntClock-8mhz", "fuse-m8-IntClock-1mhz", "fuse-m8-ExtCrystal".

  • TIP 3: Use a nice text editor well suited for programming. I love Geany.

Markdown source code last modified on January 18th, 2021
---
title: AVR Programming in Linux
date: 2013-01-06 14:51:19
tags: microcontroller, old
---

# AVR Programming in Linux

__It is not difficult to program ATMEL AVR microcontrollers with linux, and I almost exclusively do this because various unofficial (inexpensive) USB AVR programmers are incompatible with modern versions of windows (namely Windows Vista and Windows 7).__ I am just now setting-up a new computer station in my electronics room (running Ubuntu Linux 12.04), and to make it easy for myself in the future I will document everything I do when I set-up a Linux computer to program microcontrollers.

<div class="text-center img-border">

[![](mcu-programmer-far_thumb.jpg)](mcu-programmer-far.jpg)

</div>

### Install necessary software

```bash
sudo apt-get install gcc-avr avr-libc uisp avrdude
```

### Connect the AVR programmer

This should be intuitive for anyone who has programmed AVRs before. Visit the datasheet of your MCU, identify pins for VCC (+), GND (-), MOSI, MISO, SCK, and RESET, then connect them to the appropriate pins of your programmer.

### Write a simple program in C

I made a file "main.c" and put the following inside. It's the simplest-case code necessary to make every pin on PORTD (PD0, PD1, ..., PD7) turn on and off repeatedly, sufficient to blink an LED.

```c
#include <avr/io.h>
#include <util/delay.h>

int main (void)
{
 DDRD = 255; // MAKE ALL PORT D PINS OUTPUTS

 while(1) {
  PORTD = 255;_delay_ms(100); // LED ON
  PORTD = 0;  _delay_ms(100); // LED OFF
 }

 return 0;
}
```

### Compile the code (generate a HEX file)

```bash
avr-gcc -w -Os -DF_CPU=2000000UL -mmcu=atmega8 -c -o main.o main.c
avr-gcc -w -mmcu=atmega8 main.o -o main
avr-objcopy -O ihex -R .eeprom main main.hex
```

_note that the arguments define CPU speed and chip model - this will need to be customized for your application_

### Program the HEX firmware onto the AVR

```bash
sudo avrdude -F -V -c avrispmkII -p ATmega8 -P usb -U flash:w:main.hex
```

_note that this line us customized based on my connection (-P flag, USB in my case) and programmer type (-c flag, AVR ISP mkII in my case)_

When this is run, you will see something like this:

```
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

avrdude: Device signature = 0x1e9307
avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "main.hex"
avrdude: input file main.hex auto detected as Intel Hex
avrdude: writing flash (94 bytes):

Writing | ################################################## | 100% 0.04s

avrdude: 94 bytes of flash written
```

### Your Program should now be loaded!

Sit back and watch your LED blink.

<div class="text-center img-border">

[![](mcu-programmer-close_thumb.jpg)](mcu-programmer-close.jpg)

</div>

* __TIP 1:__ I'm using a clone AVRISP mkII from [Fun4DIY.com](http://fun4diy.com/AVRISP_mkII.htm) which is only $11 (shipped!). I glued it to a perf-board with a socket so I can jumper its control pins to any DIP AVR (80 pins or less). I also glued a breadboard for my convenience, and added LEDs (with ground on one of their pins) for easy jumpering to test programs. You can also build your own USB AVR ISP (free schematics and source code) from the [USBtinyISP](http://www.ladyada.net/make/usbtinyisp/) project website.

* __TIP 2:__ Make a shell script to run your compiling / flashing commands with a single command. Name them according to architecture. i.e., "build-m8" or "build-t2313". Make the first line delete all .hex files in the directory, so it stalls before it loads old .hex files if the compile is unsuccessful.  Make similar shell scripts to program fuses. i.e., "fuse-m8-IntClock-8mhz", "fuse-m8-IntClock-1mhz", "fuse-m8-ExtCrystal".

* __TIP 3:__ Use a nice text editor well suited for programming. I love [Geany](http://www.geany.org/).
Pages