Become a subscriber (Free)

Join 29,000 other subscribers to receive subscriber sale discounts and other free resources.
:
:
Don't worry -- youre-mail address is totally secure. I promise to use it only to send you MicroZine.

ADXL345

The ADXL345 is a 3 axis accelerometer and there are two basic uses for this device:

  • Orientation: Determine which way is up using gravity.
  • Instantaneous force: Detect applied forces.

Typical applications include tilt and motion sensing e.g. self levelling platforms, drone orientation, angle of tilt measurement, drop sensing.

It can measure accelerations up to 16g with 13bit resolution translating to a resolution of 3.9mg (g representing gravity at 9.8m/s2).

adxl345 processing view on PC

To make it more useful, it has several built in functions:

  • Thresholds.
  • Tapping.
  • Falling.
  • Self test.

You can setup thresholds on each axis to allow detection of movement i.e. above a certain acceleration level it will generate an interrupt. You could use that for detecting if the contents of a box of sensitive equipment had been mishandled.

ADXL345 Breakout board

adxl345 breakout board


You can also detect single or double taping in any direction. Another built in function can detect free fall for drop sensing.

ADXL345 Specification

  Parameter
Value
  Voltage Supply (Vs)
2V0 ~ 3V6
  Digital Supply voltage (Vdd i/o)
1.7V ~ Vs
  Interface
i2C / SPI
  Resolution (2g to 16g)
10 ~13  bits
  Shock survival
10,000g
  Active current (ODR >=100Hz)
~150uA (170uA max)
  Active current (ODR <100Hz) ~30uA
  Standby mode (leakage current)
0.1uA
  Operating temperature
-40°C ~ 85°C

ADXL345 Block Diagram

ADXL345 block diagramFrom Analog devices ADXL345 datasheet.

Breakout board Specification

As above except for the power supply. The breakout board has a LDO 3V3 regulator so the input voltage to VCC must be:

 4.0V to 6V.

Also:

  • CS is pulled high by a 10k resistor (active). Can be 4k7 on some boards.
  • ADDR(SDO) is pulled low by a 4k7 resistor.
  • SCL is pulled high to 3V3 by a 4k7 resistor.
  • SDA is pulled high to 3V3 by a 4k7 resistor.
  • VDDIO is connected to VS and both connect to 3V3.

Since the I2C interface uses open drain outputs, the interface is compatible with a 5V system. This is true as the Arduino never drives out 5V it only tristates an output to let the voltage level pull to 3V3. To generate a zero it outputs a digital zero which is also compatible with the 3V3 interface.

Warning: If you use the chip in SPI mode then you will need level translators (when using a 5V controller) or a controller board that only uses 3V3 throughout.

Breakout Board ICs


ADXL345 breakout board Chips (ICs)
Note: Note: The addition of a 3V3 regulator means the board can be used in a 5V system if I2C mode is used.

ADXL345 Datasheet

Download here.

ADXL345 Breakout board GY-291 Schematic

adxl345 breakout board schematic

ADXL345 Interface to Arduino

Using the ADXL345 with the Arduino is quite easy if you use the I2C interface, as this allows to controller to operate at 5V and the ADXL345 to operate at 3V3.

Note: In I2C mode the SDO pin is an input, selecting an address.

I2C Address

For I2C mode operation the chip has an address pin. On the breakout board this is pulled low giving an I2C address of:

State of ADDR/SDO pin
I2C Address (hex)
I2C Address (binary)
ADDR pulled high 0x1D
%0001-1101
ADDR pulled low 0x53 %0101-0011


Note: The ALT ADDRESS pin is an output in SPI mode, for SDO.

ADXL345 Output Data Rate

The ODR is 100Hz set by bits in the BW_RATE register. In the library use setRate() and the following defined values:

 ADXL345_RATE_3200 // Must use SPI mode
 ADXL345_RATE_1600 // Must use SPI mode
 ADXL345_RATE_800  // Must use I2C rate of >=400kHz
 ADXL345_RATE_400  // Must use I2C rate of >=200kHz
 ADXL345_RATE_200  // Must use I2C rate of >=100kHz
 ADXL345_RATE_100 (default)
 ADXL345_RATE_50
 ADXL345_RATE_25
 ADXL345_RATE_12P5
 ADXL345_RATE_6P25
 ADXL345_RATE_3P13
 ADXL345_RATE_1P56
 ADXL345_RATE_0P78
 ADXL345_RATE_0P39
 ADXL345_RATE_0P20

Changing the data rate is useful for power saving (by going slow).

At 100Hz and above the current consumption is 140uA (p14 of datasheet) - except for 1600Hz (90uA). The minimum you can get is at 0.39Hz (and below) with 23uA used.

ADXL345 Resolution

You can select the acceleration range from the following values:

   2g, 4g, 8g, 16g.

The same scaling factor is used in all resolutions because the internal DAC resolution changes from 10bits to 13 bits as each resolution is selected. So each bit is always worth 3.9mg:

Calculation g/LSB
Result
2/pow(2,10-1)
0.003906
4/pow(2,11-1) 0.003906
8/pow(2,12-1)
0.003906
16/pow(2,13-1)
0.003906

Note the '-1' allows for the sign bit to give positive or negative results.  

Using 16g mode gives maximum dynamic range.

However an extract from the datasheet shows the actual deviation from the above ideal values (Sensitivity deviation from ideal):

Sensitivity deviation from ideal mg per lsb
If you restrict the range of the adxl345 to 10bits then it becomes less sensitive (fairly obvious). For full range you get the typical sensitivity of 3.9mg/LSB and 3.5 ~ 4.3mg/LSB min ~ max deviation (this is set using the FULL_RES bit). Why you would restrict to 10bits is something I don't understand - seems pointless.

Why not ±90°

Why can't the ADXL345 accelerometer indicate ±90° ?

If you run the program below you will see that the accelerometer is extremely good at indicating tilt at low angles (on a flat surface) to about 70°, but does not reach ±90°. In fact it can't seem to reach that magic number ±90°!

At first,I thought there was something wrong with the accelerometer since no one seems to talk about this. Why should it not be possible to measure all angles?

It turns out that the sensitivity of the accelerometer decreases with increasing angle and follows a near sinusoidal response, so accuracy decreases the closer you get to ±90° of tilt.

"The sensor is a polysilicon surface-micromachined structure built on top of a silicon wafer. Polysilicon springs suspend the structure over the surface of the wafer and provide a resistance against forces due to applied acceleration."  [datasheet]

You can imagine the sensor as a beam suspended on springs, with the capacitance between the beam and the support base giving the acceleration measurement. When the beam is perpendicular to the acceleration field small tilt changes will have a large effect as gravity acts over a larger area.

As the beam tilts vertically, the sensor becomes less sensitive (interacting with the gravity vector less) until, at full vertical orientation, it can not return a reading since the gravity vector has no effect on the beam.

There is a very good discussion of accelerometer sensitivity in Analogue Devices Application note AN-1057 by C Fisher here. The following diagram is from that application note:

accelerometer tilt angle sensitivity 1 degree step

The diagram shows that around 0° ~ 23° tilt you only need a sensitivity of 16mg/LSB to resolve 1° steps, and around 60° tilt you need 8mg, and around 80° you need 4mg.  This is why the ADXl345 can not display 90° as its sensitivity is too coarse to resolve tilt at that angle (3.8mg). So the ADXL345 is good for tilt up to about ±80°. This is for the case where you want to resolve tilt measurement to within 1°.

TIP: Increase resolution by oversampling to resolve smaller angles.

Why can't I measure yaw?

Yaw is the rotation about the z axis - or compass heading. You may think that the ADXL345 z axis is not working but it is!

When you rotate the accelerometer about the x or y axis, sensors experience more or less of the gravity vector and therefore output different values of acceleration.

When you rotate the accelerometer about the z axis the sensor experiences the same value of gravity vector so you can't measure yaw.

This is why accelerometers are used in conjunction with a gyroscope or magnetometer for measuring yaw values.

What is the z accelerometer useful for?

So then the question becomes why do you need a z-accelerometer measurement?

The z axis accelerometer indicates deviation from vertical. In conjunction with either x or y accelerometer values you can calculate pitch and roll (deviation from vertical in the x or y directions).

Hardware Connections:

You can use an Arduino Uno or Nano (the Nano is convenient for solderless breadboard use as it fits into one quite nicely). Here the ADXL345 is used on the Arduino in I2C mode so just connect SDA, SCL, power and ground:

Arduino Uno/Nano Connection
ADXL345 Connection
A4
SDA
A5
SCL
GND
GND
5V
Vcc

ADXL345 interfacing with the Arduino is simply to connecting the I2C interface as above.

Software

I2Cdev library

The I2Cdevlib has ADXL345 library code as well as code for many other devices.

https://github.com/jrowberg/i2cdevlib

This library has a lot of features, supported chips, and can operate on multiple processors but it is a little more involved to install and you can not use the automatic Arduino zip file installer.

Unzip the file (ic2devlib-master) then navigate to the Arduino directory within ic2devlib-master. Copy the directories ADXL345 and I2Cdev to the Arduino libraries directory, usually found here (on windows):

    C:\Users\<User name>\Documents\Arduino\libraries

ADXL345 Self Test Sketch

Because the device is a mechanical system the ADXL345 includes a self test circuit that imposes an electrostatic field on the physical measuring elements. These has a similar effect to gravitational acceleration adding to the existing acceleration element.

Note: Datasheet page 31 has more on using the self-test.

The following program tests the chip at 3.3V (the supply voltage changes the test parameters). The program will output the results to the serial monitor and gives you a PASS/FAIL indication. You can also observe raw g values, roll and pitch.


Use this sketch if you thing that the AXL345 is not working.

// By John Main © best-microcontroller-projects.com
// ADXL345 Self Test, show g and roll pitch values
#include "math.h"
#include "Wire.h"
#include "I2Cdev.h" // Has MIT license.
#include "ADXL345.h"

ADXL345 accel;

#define LED_PIN LED_BUILTIN // (Arduino is 13, Teensy is 6, nano? so use LED_BUILTIN)
bool toggleLED = false;
static byte showAngles = 0; // Display operation

void setup() {
    Wire.begin();
    Serial.begin(115200);

    // initialize device
    Serial.println( F("Starting I2C devices...") );
    accel.initialize();

    Serial.println( F("Checking ADXL345...") );
    if(accel.testConnection())
      Serial.println( F("ADXL345 comms Ok.") );
    else {
       Serial.println( F("ADXL345 comms failed.") );
       while(1); // Hang on error.
    }
    Serial.println(F("Enter t - Self test, s - Show angles"));

    accel.setFullResolution(1); // 0 => 10 bit mode.
    accel.setRate(ADXL345_RATE_100);  // This is default but shows the value.
    accel.setLowPowerEnabled(0);
    accel.setRange(3); // 0 => 2g, 3 => 16g

    pinMode(LED_PIN, OUTPUT);
}

// Get readings for self test - A set of n averaged results.
void ADXL345GetAvgN(int16_t *xi,int16_t *yi,int16_t *zi,uint8_t n) {
int16_t x,y,z;
int32_t ax,ay,az;
uint8_t i;

    ax=0; ay=0; az=0;
    for(i=0;i<n;i++) {
      accel.getAcceleration(&x, &y, &z);
      ax += x; ay += y; az +=z;
      delay(100); // Don't read faster than 100Hz: (10*100ms=1s 1s/10=100ms)
    }
    *xi = ax/n; *yi = ay/n; *zi = az/n;
}

void print_minmax(int vmin,int vmax) {
  Serial.print('(');Serial.print(vmin);Serial.print(" ~ ");Serial.print(vmax);Serial.print(')');
}

// This function setsup the relevant parameters while preserving them e.g. range
void ADXL345SelfTest(void) {
uint16_t fr,st,rt,lp,ra;
    fr = accel.getFullResolution();
    rt = accel.getRate();
    lp = accel.getLowPowerEnabled();
    ra = accel.getRange();

    int16_t avg_x=0, avg_y=0, avg_z=0;
    int16_t avg_stx=0, avg_sty=0, avg_stz=0;
    int16_t ax,ay,az;
    int16_t x,y,z;
    uint8_t i;

    // Setup operating mode required for self test.
    accel.setFullResolution(0); // 0 => 10 bit mode.
    accel.setRate(ADXL345_RATE_100);
    accel.setLowPowerEnabled(0);
    accel.setRange(3); // 3 => 16g

    ADXL345GetAvgN(&avg_x, &avg_y, &avg_z, 10);

    accel.setSelfTestEnabled(1);
    ADXL345GetAvgN(&avg_stx,&avg_sty,&avg_stz,5);    // Let device settle for >=4 samples.
    ADXL345GetAvgN(&avg_stx, &avg_sty, &avg_stz, 10);
    accel.setSelfTestEnabled(0);

    // Display results
    x = avg_stx-avg_x; y = avg_sty-avg_y; z = avg_stz-avg_z;
    Serial.print("\nstx-x\t");Serial.print(x);Serial.print("\t");
    Serial.print("sty-y\t");Serial.print(y);Serial.print("\t");
    Serial.print("stz-z\t");Serial.print(z);Serial.print("\t");

    // 3V3 error limit scale factors.
    #define scale_factor_xy  1.77;
    #define scale_factor_z   1.47;
    float vmin,vmax;

    Serial.print('\n');

    //Value limits are from ADXL345 datasheet - Tables 14 and 18.
    vmin = 6 * scale_factor_xy; vmax = 67 * scale_factor_xy;
    Serial.print( (x>=vmin && x <vmax) ? "X PASS " : "X FAIL " );
    print_minmax(vmin,vmax); Serial.print('\n');

    vmin = -67 * scale_factor_xy; vmax = -6 * scale_factor_xy;
    Serial.print( (y>=vmin && y <vmax) ? "Y PASS " : "Y FAIL " );
    print_minmax(vmin,vmax); Serial.print('\n');

    vmin = 10 * scale_factor_z; vmax = 110 * scale_factor_z;
    Serial.print( (z>=vmin && z <vmax) ? "Z PASS " : "Z FAIL " );
    print_minmax(vmin,vmax);Serial.print('\n');

    accel.setFullResolution(fr);
    accel.setRate(rt);
    accel.setLowPowerEnabled(lp);
    accel.setRange(ra);
}

void showAccelAngles(void) {
  float x,y,z;
  int16_t ax,ay,az;
   // Show angles
   // Datasheet: OPERATION AT VOLTAGES OTHER THAN 2.5 V
   // 3v3 X,Y 25mg too high, z 20mg too low
   // 3V3 lsb value 265/g   (g/265)=0.03698
   // 2V5 lsb value 256/g   (g/256)=0.03828 z axis unaffected by voltage supply.
   #define ADXL345_LSBVAL_3V3 3.698E-3
   #define ADXL345_LSBVAL_2V5 3.828E-3

   accel.getAcceleration(&ax, &ay, &az);
   x = ax*ADXL345_LSBVAL_3V3 - 25E-3;
   y = ay*ADXL345_LSBVAL_3V3 - 25E-3;
   z = az*ADXL345_LSBVAL_2V5 + 20e-3;

   float fNum;
   Serial.print(F("g values: "));
   fNum=x;Serial.print(fNum); Serial.print("\t");
   fNum=y;Serial.print(fNum); Serial.print("\t");
   fNum=z;Serial.print(fNum); Serial.print("\t");

   float r = sqrt(x*x + y*y + z*z);

   // Angle from x,y axis to gravity vector.
   int roll   = 180/M_PI * ( M_PI/2 - (acos(y/r) ) );
   int pitch  = 180/M_PI * ( M_PI/2 - (acos(x/r) ) );

   Serial.print(F("Roll ")); Serial.print(roll); Serial.print(' ');
   Serial.print(F("Pitch "));Serial.print(pitch);Serial.print(' ');
   Serial.print('\n');
}

void loop() {
float x,y,z;
static byte ch;

   if(Serial.available()) {
     ch=Serial.read();
   }

   if(ch=='t') {
      Serial.println(F("Testing..."));
      ADXL345SelfTest();
      showAngles = 0;
   }
   else if(ch=='s')
      showAngles = 1;

   if (showAngles) showAccelAngles();

   toggleLED = !toggleLED;
   digitalWrite(LED_PIN, toggleLED);
   delay(200);
}


[File:adxl345_self_test.ino]

Self Test Program Output

Type 't' to start a self-test and 's to output g, roll and pitch values.

The following shows typical output from the program:

Starting I2C devices...
Checking ADXL345...
ADXL345 comms Ok.
Enter t - Self test, s - Show angles
Testing...

stx-x    59    sty-y    -18    stz-z    88   
X PASS (10 ~ 118)
Y PASS (-118 ~ -10)
Z PASS (14 ~ 161)
g values: -0.17    -0.02    1.05    Roll 0 Pitch -9
g values: -0.21    0.00    1.08    Roll 0 Pitch -11
g values: -0.18    -0.01    1.03    Roll 0 Pitch -9
g values: -0.17    -0.02    1.07    Roll -1 Pitch -9
g values: -0.17    -0.02    1.07    Roll 0 Pitch -8
g values: -0.01    -0.03    1.00    Roll -1 Pitch 0
g values: -0.69    -0.06    0.77    Roll -3 Pitch -41
g values: -1.30    -0.15    0.36    Roll -6 Pitch -73
g values: 0.24    -0.21    0.95    Roll -12 Pitch 13
g values: 0.22    -0.42    0.96    Roll -23 Pitch 11
g values: -0.06    -0.82    0.87    Roll -43 Pitch -2
g values: -0.01    0.05    1.01    Roll 2 Pitch 0

Sketch Example 2

This program outputs only roll and pitch values - these are used to show a processing simulation of the orientation of the accelerometer. This is the type of view produced by the processing code for the Arduino sketch below:

adxl345 processing view on PC



// By John Main © best-microcontroller-projects.com
// This sketch outputs serial data as 2 parameters (roll and pitch)
// for display in processing code on PC.

#include "math.h"
#include "Wire.h"
#include "I2Cdev.h"
#include "ADXL345.h"

#define LED_PIN LED_BUILTIN
// Macros to allow 0 ~ 180 mapped to -90 to 90

ADXL345 accel;

bool blinkState = false;

void setup() {

    Wire.begin();
    Serial.begin(115200);

    accel.initialize();

    accel.setRate(ADXL345_RATE_100);  // This is default but shows the value.
    accel.setFullResolution(1); // 0 => 10 bit mode.
    accel.setLowPowerEnabled(0);
    accel.setRange(0); // 0 => 2g, 3 => 16g

    pinMode(LED_PIN, OUTPUT);
}

void loop() {
float r,x,y,z;
int16_t ax, ay, az;

  // Datasheet: OPERATION AT VOLTAGES OTHER THAN 2.5 V
  // 3v3 X,Y 25mg too high, z 20mg too low
  // 3V3 lsb value 265/g c  (g/265)=0.03698
  // 2V5 lsb value 256/g   (g/256)=0.03828 z axis unaffected by voltage supply.
  #define ADXL345_LSBVAL_3V3 3.698E-3
  #define ADXL345_LSBVAL_2V5 3.828E-3

  accel.getAcceleration(&ax, &ay, &az);
  x = ax*ADXL345_LSBVAL_3V3 - 25E-3;
  y = ay*ADXL345_LSBVAL_3V3 - 25E-3;
  z = az*ADXL345_LSBVAL_2V5 + 20e-3;

  r = sqrt(x*x+y*y+z*z);
  // Angle from x,y axis to gravity vector.
  int roll   = 180/M_PI * ( M_PI/2 - (acos(y/r) ) );
  int pitch  = 180/M_PI * ( M_PI/2 - (acos(x/r) ) );

  Serial.print(roll); Serial.print(' ');
  Serial.print(pitch);Serial.print(' ');
  Serial.print('\n');

  // blink LED to indicate activity
  blinkState = !blinkState;
  digitalWrite(LED_PIN, blinkState);
  delay(50);
}


[File:degrees-roll-pitch.ino]

Processing Sketch

This shows the orientation of the accelerometer as a 3d image on screen - it mimics the orientation of the accelerometer in real time.

Download processing here.

Note: Change the Serial port to your own one. When you run the program below the output text screen will show the available serial ports. Change COM19 to match yours.


// By John Main © best-microcontroller-projects.com
// This sketch accepts serial data as 2 parameters (roll and pitch)
// and displays a 3d representation of the accelerometer.
import processing.serial.*;

Serial myPort;
String inString;  // Input string from serial port
int lf = 10;      // ASCII linefeed
float rx,ry,rz;
float mouseZoom;

float RAD_TO_DEGREE = 180/PI;
float DEGREE_TO_RAD = PI/180;


void setup() {
  size(400,400,P3D);

  print("-----------------------------");
  print("START");
  print("--------------------\n");
  // List all the available serial ports:
  printArray(Serial.list());

  // Open the port you are using at the rate you want:
  // Replace COMP19 with whatever port you want to use.
  myPort = new Serial(this, "COM19", 115200);
  myPort.bufferUntil(ENTER);

  mouseZoom= width/2;
}

void mouseWheel(MouseEvent event) {
  float e = event.getCount();
  mouseZoom += e*10;
}

void draw() {
  int x,y=70,ysep=20;
  background(80);
  fill(#ffffff);
  translate(100,180);

  if (inString!=null) {
    inString =  trim(inString);
    text("received: " + inString, 10,y);y+=ysep;//50
    int[] nums = int( split(inString,' ') );
    text("roll " + nums[0],10,y);y+=ysep; // 70
    text("pitch " + nums[1],10,y);y+=ysep;
    rx = nums[0];
    ry = nums[1];
  }

  pushMatrix();
  // FOV START
  float fov = 0.6086836; float aspect=1; float cameraZ=636.74;
  perspective(fov, aspect, cameraZ/10.0, cameraZ*10.0);
  // END FOV

  // Angle camera view to left and above (1st 2 params).
  camera((width/2)*0.4, height/2*0.05, (height/2) / tan(PI/6), width/2, height/2, 0.5, 0, 1, 0);

  translate(200,200);

  stroke(#F4F52F); // Axes
  box(170,1,1);
  box(1,1,60);
  stroke(0);
  // Axes - processing    : y down x right z out of page
  // Axes - accelerometer : y - into page, x right, z up.
  rotateX(-rx * DEGREE_TO_RAD);
  rotateZ(-ry * DEGREE_TO_RAD); // Different z axis for accelerometer.

  fill(#6598C9,100);
  box(150,10,40);
  fill(#F52FF2,100);
  translate(0,10,0);
  box(150,10,40);

  popMatrix();

}

void serialEvent(Serial myPort) {
      inString = myPort.readString();
}


[File:roll_pitch.pde]

Deep Dive into MEMS

This a cutting edge university level tutorial on mems and micromachined structures with specific coverage of oscillator applications.

This provides a fascinating look at the world of micromachining from structures created between 1989 and the present day (Video released in Feb 2019). The tutorial is from 2018.

It starts off showing how structures are created using transistor etching techniques. The talk is given Professor Clark Nguyen - He was Bill Tang's undergraduate researcher when MEMS was being invented.

This is a great video to see cutting edge techniques - it is very advanced but starts off slowly, describing early designs - very good to dip into.



New! Comments

Have your say about what you just read! Leave me a comment in the box below.



Privacy Policy | Contact | About Me

Site Map | Terms of Use



Visit our Facebook Page:
To Visit Click Here


Recent Articles

  1. A Real Time Clock design (DS1307) with a PIC microcontroller

    Real Time Clock Design (FREE): A Free and Complete RTC design using the DS1307 and a PIC micro (16F88) also re-targetable. This PIC project uses an I2C Clock chip and 7-segment display to create a fou…

    Read more

  2. How to use the ADXL345 for movement sensing and more.

    With the ADXL345 acellerometer you can detect up to 16g! You can also find out how to use it for tap detection and more.

    Read more

  3. Arduino Interrupt : There are Some You May Never Have Heard About!

    Arduino Interrupt Tutorial: Find out how many external there are on an Arduino Uno - The answer is more than two!

    Read more

  4. Easy Switch Debounce

    Switch debounce: Three different ways to debounce input push switches with one amazing method that you can't miss.

    Read more

  5. How to use the ADS1115

    A tutorial on using the ADS1115 precision 16 bit ADC for low power use.

    Read more

  6. ESP8266 Webserver in Lua

    ESP8266 Webserver: This code shows you how to use lua to create a webserver using html button inputs to contrtol an LED on the ESP module.

    Read more

Readers Comments

"I wanted to thank
you so so so much
for all the information
you have provided in
your site it's

SUPERB and FANTASTIC."

- Ranish Pottath

"This site really is
the best and my favorite.
I find here many useful
projects and tips."

- Milan

bursach<at>gmail.com<

"Awesome site,
very, very easy and nice
to navigate!"


- Matt
matt_tr<at>
wolf359.cjb.net


Learn Microcontrollers

"Interested in
Microcontrollers?"

Sign up for The
Free 7 day guide:

FREE GUIDE : CLICK HERE


"I am a newbie to PIC
and I wanted to say
 how great your
site has been for me."


- Dave

de_scott<at>bellsouth.net

"Your site is a great
and perfect work.
congratulations."


- Suresh

integratredinfosys<at>
yahoo.com

"I couldn't find the correct
words to define
yourweb site.

Very useful, uncovered,
honest and clear.

Thanks so much for
your time and works.
Regards."


- Anon

Back to Top

/