Muhammed Jaseel
Published © MIT

Accelerometer (ADXL 345) Interfacing with PC (Python GUI)

I interfaced ADXL 345 Accelerometer to PC using ATTiny45 Microcontroller.

IntermediateProtip3 hours1,912
Accelerometer (ADXL 345) Interfacing with PC (Python GUI)

Things used in this project

Hardware components

ADXL 345
×1
ATtiny85
Microchip ATtiny85
you can use both ATtiny 45 and 85
×1
LilyPad FTDI Basic Breakout - 5V
SparkFun LilyPad FTDI Basic Breakout - 5V
for interfacing with PC
×1

Story

Read more

Custom parts and enclosures

Eagle File board

Eagle file Schematics

Schematics

Eagle Screenshot

I attached complete eaglefile

Code

Neil's C Code

C/C++
You Can Burn this C Code to ATtiny45
//
// hello.ADXL343.c
//
// ADXL343 accelerometer hello-world
//    9600 baud FTDI interface
//
// Neil Gershenfeld 11/8/15
// (c) Massachusetts Institute of Technology 2015
//
// This work may be reproduced, modified, distributed,
// performed, and displayed for any purpose. Copyright is
// retained and must be preserved. The work is provided
// as is; no warranty is provided, and users accept all 
// liability.
//

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

#define output(directions,pin) (directions |= pin) // set port direction for output
#define input(directions,pin) (directions &= (~pin)) // set port direction for input
#define set(port,pin) (port |= pin) // set port pin
#define clear(port,pin) (port &= (~pin)) // clear port pin
#define pin_test(pins,pin) (pins & pin) // test for port pin
#define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
#define bit_delay_time 102 // bit delay for 9600 with overhead
#define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay
#define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay

#define serial_port PORTB
#define serial_direction DDRB
#define serial_pin_out (1 << PB2)

#define I2C_slave_address 0x53 // ADXL345 alt address
#define I2C_delay() _delay_us(5)
#define SCL_pin (1 << PB3)
#define SCL_pins PINB
#define SCL_port PORTB
#define SCL_direction DDRB
#define SDA_pin (1 << PB4)
#define SDA_pins PINB
#define SDA_port PORTB
#define SDA_direction DDRB

void SCL_write(char bit) {
   //
   // write SCL bit
   //
   if (bit == 0) {
      output(SCL_direction,SCL_pin);
      clear(SCL_port,SCL_pin);
      }
   else {
      input(SCL_direction,SCL_pin);
      while (pin_test(SCL_pins,SCL_pin) == 0); // check for clock stretching
      }
   }

void SDA_write(char bit) {
   //
   // write SDA bit
   //
   if (bit == 0) {
      output(SDA_direction,SDA_pin);
      clear(SDA_port,SDA_pin);
      }
   else
      input(SDA_direction,SDA_pin);
   }

void I2C_init() {
   //
   // initialize I2C lines
   //
   SDA_write(1);
   SCL_write(1);
   } 

char I2C_master_write_byte(unsigned char byte) {
   //
   // master write I2C byte
   //
   unsigned char bit;
   //
   // loop over bits
   //
   for (bit = 0; bit < 8; ++bit) {
      if ((byte & 0x80) == 0)
         SDA_write(0);
      else
         SDA_write(1);
      SCL_write(1);
      I2C_delay();
      SCL_write(0);
      I2C_delay();
      byte <<= 1;
      }
   //
   // check for ACK
   //
   SDA_write(1);
   SCL_write(1);
   I2C_delay();
   if (pin_test(SDA_pins,SDA_pin) != 0) {
      //
      // no ACK, return 1
      //
      return 1;	
      }
   //
   // yes ACK, return 0
   //
   SCL_write(0);
   I2C_delay();
   return 0;
   }	

char I2C_master_write(unsigned char* data, unsigned char nbytes, unsigned char slave_address) {
   //
   // I2C master write
   //
   unsigned char index,ret,slave_address_write;
   //
   // send start
   //
   SDA_write(0);
   I2C_delay();
   SCL_write(0);	
   I2C_delay();
   //
   // send slave address
   //
   slave_address_write = slave_address << 1;
   if (I2C_master_write_byte(slave_address_write) != 0)
      //
      // no ACK, return 1
      //
      return 1;
   //
   // loop over bytes
   //
   for (index = 0; index < nbytes; ++index) {
      ret = I2C_master_write_byte(data[index]);
      if (ret != 0)
         //
         // no ACK, return 1
         //
         break;
      //
      // yes ACK, continue
      //	
      }
   //
   // send stop
   //
   SCL_write(1);
   I2C_delay();
   SDA_write(1);
   I2C_delay();
   return ret;
   }

void I2C_master_read_byte(unsigned char* data, unsigned char index, unsigned char nbytes) {
   //
   // master read I2C byte
   //
   unsigned char byte,bit;
   SDA_write(1);
   byte = 0;
   //
   // loop over bits
   //
   for (bit = 0; bit < 8; ++bit)  {
      SCL_write(1);
      I2C_delay();
      if (pin_test(SDA_pins,SDA_pin) != 0)
         byte |= (1 << (7-bit));
      SCL_write(0);
      I2C_delay();
      }
   data[index] = byte;
   if (index < (nbytes-1)) {
      //
      // not done, send ACK
      //
      SDA_write(0);
      SCL_write(1);
      I2C_delay();
      SCL_write(0);
      SDA_write(1);
      I2C_delay();
      }
   else {
      //
      // done, send NACK
      //
      SDA_write(1);
      SCL_write(1);
      I2C_delay();
      SCL_write(0);
      I2C_delay();
      }
   }	

char I2C_master_read(unsigned char* data, unsigned char nbytes, unsigned char slave_address) {
   //
   // I2C master read
   //
   unsigned char index,slave_address_read;
   //
   // send start
   //
   SDA_write(0);
   I2C_delay();
   SCL_write(0);	
   I2C_delay();
   //
   // send slave address
   //
   slave_address_read = (slave_address << 1) + 1;
   if (I2C_master_write_byte(slave_address_read) == 1)
      //
      // no ACK, return 1
      //
      return 1;
   //
   // loop over bytes
   //
   for (index = 0; index < nbytes; ++index)
      I2C_master_read_byte(data,index,nbytes);
   //
   // send stop
   //
   SCL_write(1);
   I2C_delay();
   SDA_write(1);
   I2C_delay();
   return 0;
   }	

void put_char(volatile unsigned char *port, unsigned char pin, char txchar) {
   //
   // send character in txchar on port pin
   //    assumes line driver (inverts bits)
   //
   // start bit
   //
   clear(*port,pin);
   bit_delay();
   //
   // unrolled loop to write data bits
   //
   if bit_test(txchar,0)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,1)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,2)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,3)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,4)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,5)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,6)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,7)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   //
   // stop bit
   //
   set(*port,pin);
   bit_delay();
   //
   // char delay
   //
   bit_delay();
   }

int main(void) {
   //
   // main
   //
   unsigned char data[6];
   unsigned char ret;
   //
   // set clock divider to /1
   //
   CLKPR = (1 << CLKPCE);
   CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
   //
   // initialize output pins
   //
   set(serial_port, serial_pin_out);
   output(serial_direction, serial_pin_out);
   //
   // main loop
   //
   I2C_init();
   data[0] = 0x2D; // POWER_CTL register
   data[1] = 8; // turn on measure bit
   ret = I2C_master_write(data,2,I2C_slave_address);
   while (1) {
      /*
      //
      // read device ID
      //
      data[0] = 0x00; // device ID register
      ret = I2C_master_write(data,1,I2C_slave_address);
      ret = I2C_master_read(data,1,I2C_slave_address);
      put_char(&serial_port,serial_pin_out,data[0]);
      */
      //
      // send framing
      //
      put_char(&serial_port,serial_pin_out,1);
      put_char(&serial_port,serial_pin_out,2);
      put_char(&serial_port,serial_pin_out,3);
      put_char(&serial_port,serial_pin_out,4);
      //
      // read and send data
      //
      data[0] = 0x32; // X0 register
      ret = I2C_master_write(data,1,I2C_slave_address);
      ret = I2C_master_read(data,6,I2C_slave_address);
      put_char(&serial_port,serial_pin_out,data[0]);
      put_char(&serial_port,serial_pin_out,data[1]);
      put_char(&serial_port,serial_pin_out,data[2]);
      put_char(&serial_port,serial_pin_out,data[3]);
      put_char(&serial_port,serial_pin_out,data[4]);
      put_char(&serial_port,serial_pin_out,data[5]);
      }
   }

Neil'a Python Code

C/C++
Run this Python Script in your machine
#
# hello.reflect.45.py
#
# receive and display synchronous light reflection 
# hello.light.45.py serial_port
#
# Neil Gershenfeld
# CBA MIT 10/25/12
#
# (c) Massachusetts Institute of Technology 2012
# Permission granted for experimental and personal use;
# license for commercial sale available from MIT
#

from Tkinter import *
import serial

WINDOW = 600 # window size
eps = 0.9 # filter time constant
filter = 0.0 # filtered value
nloop = 100.0 # number of loops accumulated
amp = 25.0 # difference amplitude

def idle(parent,canvas):
   global filter, eps
   #
   # idle routine
   #
   byte2 = 0
   byte3 = 0
   byte4 = 0
   ser.flush()
   while 1:
      #
      # find framing 
      #
      byte1 = byte2
      byte2 = byte3
      byte3 = byte4
      byte4 = ord(ser.read())
      if ((byte1 == 1) & (byte2 == 2) & (byte3 == 3) & (byte4 == 4)):
         break
   on_low = ord(ser.read())
   on_high = ord(ser.read())
   on_value = (256*on_high + on_low)/nloop
   x = int(.25*WINDOW + (.9-.25)*WINDOW*on_value/1024.0)
   canvas.itemconfigure("text_on",text="on %.1f"%on_value)
   canvas.coords('rect1_on',.25*WINDOW,.05*WINDOW,x,.2*WINDOW)
   canvas.coords('rect2_on',x,.05*WINDOW,.9*WINDOW,.2*WINDOW)
   off_low = ord(ser.read())
   off_high = ord(ser.read())
   off_value = (256*off_high + off_low)/nloop
   x = int(.25*WINDOW + (.9-.25)*WINDOW*off_value/1024.0)
   canvas.itemconfigure("text_off",text="off %.1f"%off_value)
   canvas.coords('rect1_off',.25*WINDOW,.25*WINDOW,x,.4*WINDOW)
   canvas.coords('rect2_off',x,.25*WINDOW,.9*WINDOW,.4*WINDOW)
   filter = (1-eps)*filter + eps*amp*(on_value-off_value)
   x = int(.25*WINDOW + (.9-.25)*WINDOW*filter/1024.0)
   canvas.itemconfigure("text_diff",text="diff %.1f"%filter)
   canvas.coords('rect1_diff',.25*WINDOW,.45*WINDOW,x,.6*WINDOW)
   canvas.coords('rect2_diff',x,.45*WINDOW,.9*WINDOW,.6*WINDOW)
   canvas.update()
   parent.after_idle(idle,parent,canvas)

#
#  check command line arguments
#
if (len(sys.argv) != 2):
   print "command line: hello.light.45.py serial_port"
   sys.exit()
port = sys.argv[1]
#
# open serial port
#
ser = serial.Serial(port,9600)
ser.setDTR()
#
# set up GUI
#
root = Tk()
root.title('hello.reflect.45.py (q to exit)')
root.bind('q','exit')
canvas = Canvas(root, width=WINDOW, height=.65*WINDOW, background='white')
#
canvas.create_text(.125*WINDOW,.125*WINDOW,text=".33",font=("Helvetica", 24),tags="text_on",fill="#0000b0")
canvas.create_rectangle(.25*WINDOW,.05*WINDOW,.3*WINDOW,.2*WINDOW, tags='rect1_on', fill='#b00000')
canvas.create_rectangle(.3*WINDOW,.05*WINDOW,.9*WINDOW,.2*WINDOW, tags='rect2_on', fill='#0000b0')
#
canvas.create_text(.125*WINDOW,.325*WINDOW,text=".33",font=("Helvetica", 24),tags="text_off",fill="#0000b0")
canvas.create_rectangle(.25*WINDOW,.25*WINDOW,.3*WINDOW,.4*WINDOW, tags='rect1_off', fill='#b00000')
canvas.create_rectangle(.3*WINDOW,.25*WINDOW,.9*WINDOW,.4*WINDOW, tags='rect2_off', fill='#0000b0')
#
canvas.create_text(.125*WINDOW,.525*WINDOW,text=".33",font=("Helvetica", 24),tags="text_diff",fill="#0000b0")
canvas.create_rectangle(.25*WINDOW,.45*WINDOW,.3*WINDOW,.6*WINDOW, tags='rect1_diff', fill='#b00000')
canvas.create_rectangle(.3*WINDOW,.45*WINDOW,.9*WINDOW,.6*WINDOW, tags='rect2_diff', fill='#0000b0')
canvas.pack()
#
# start idle loop
#
root.after(100,idle,root,canvas)
root.mainloop()

Credits

Muhammed Jaseel

Muhammed Jaseel

4 projects • 20 followers
I am a Maker and Developer

Comments