Hardware components | ||||||
| × | 1 | ||||
![]() |
| × | 1 | |||
![]() |
| × | 1 |
Hi Makers,
What I am going to doI want to make an accelerometer board that will communicate with a GUI.
I have an ADXL 345 accelerometer, I am going to interface with Attiny45 and communicate to GUI via serial using I2C.
I2C Connection Between ADXL 345 and ATtiny45What is I2C?
The Inter-integrated Circuit (I2C) Protocol is a protocol intended to allow multiple “slave” digital integrated circuits (“chips”) to communicate with one or more “master” chips, I2C connection requires only 2 wires (SDA and SCL) it is very useful in low pin microcontrollers.
I designed circuit in eagle, I used pinhead Component library for adding 6 Pin header for my accelerometer board.
I milled PCB using Roland Modela Milling Machine.
I used this C code: http://academy.cba.mit.edu/classes/input_devices/accel/hello.ADXL343.c
And this Python code: http://academy.cba.mit.edu/classes/input_devices/accel/hello.ADXL343.py
This is the final working video.
//
// 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]);
}
}
#
# 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()
Comments
Please log in or sign up to comment.