This program displays the 3 axis output from an ADXL345 Accelerometer and 16F628A in Hi-Tech C. Specifically the little GY-291 board available cheap on eBay. There are pull-ups on the board to solve the 3 volt problem.
I use Nigel Goodwin's tutorials in asm... as a starting place for C programs and subroutines.
Thank you Nigel and Ian.
I use Nigel Goodwin's tutorials in asm... as a starting place for C programs and subroutines.
Thank you Nigel and Ian.
C:
// ADXL345 Accelerometer and 16F628a in Hi-Tech C
// Using Bit Bang I2C on RA6 & RA7 and LCD on port B
// This uses up all but 167 bytes of program memory
// the div_t averaging routine uses 414 bytes
// The wiring for the LCD using Hitachi HD44780 is at
// http://www.winpicprog.co.uk/pic_tutorial_lcd_board.htm
#include <pic.h> // pic specific identifiers
#include <stdlib.h>
#include <stdio.h>
#define _XTAL_FREQ 4000000 // Xtal speed
__CONFIG(0x3D38); // Config bits
char IDDV =0;
#define BW_RATE 44 //0x2C
#define POWER_CTL 45 //0x2D
#define DATA_FORMAT 49 //0x31
#define DATAX0 50 //0x32
#define DATAX1 51 //0x33
#define DATAY0 52 //0x34
#define DATAY1 53 //0x35
#define DATAZ0 54 //0x36
#define DATAZ1 55 //0x37
#define FIFO_CTL 56 //0x38 1010011 0x53 Device
#define CHIP_Write 0xA6 // adxl345 address for writing 10100110 0xA6 Write
#define CHIP_Read 0xA7 // and reading 10100111 0xA7 Read
//#define DEVICE1 (0x53)
#define LCD_PORT PORTB //
#define LCD_TRIS TRISB
#define LCD_RS RB4
#define LCD_RW RB6
#define LCD_E RB7
#define I2C_PORT PORTA // I2C port configuration
#define I2C_TRIS TRISA
#define SDAI RA7
#define SCLI RA6
#define SDA TRISA7 // in C we can control the input / output
#define SCL TRISA6 // by one simple command.
// Required prototypes
void LCD_init(void), LCD_cmd(unsigned char ch), LCD_busy(void);
void LCD_printC(const char *str), LCD_printR(char *str);
void LCD_goto(char line, char column), LCD_clr(void);
void LCD_cur(unsigned char ch), pulse_E(void), LCD_hex(int value);
void LCD_char(unsigned char ch), LCD_charD(unsigned char ch);
void convert(int numb);
unsigned char HEX_Table[] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
0x37, 0x38, 0x39, 0x41, 0x42, 0x43,
0x44, 0x45, 0x46};
// variables
unsigned char TenK, Thou, Hund, Tens, Ones;
void I2C_Sendnack(void), I2C_ack(void), I2C_Stop(void), clock(void);
void I2C_Start(void), I2C_Write(unsigned char ch);
char I2C_nack(), E_Write(int addr, unsigned char ch);
unsigned char I2C_Read(void);
unsigned char E_Read(int addr);
void ini_adxl345()
{
E_Write(FIFO_CTL,0x9f);
E_Write(DATA_FORMAT,0x09);
E_Write(BW_RATE,0x0d);
E_Write(POWER_CTL,0x08); // activate
}
unsigned char LCDbuffer[17];// a screen buffer big enough for 16 chars + terminator
char ErrFlags; // Read error. (I don't use it, but you might!)
// The SDA and SCL pins are ALWAYS set at 0 we use tristated pins to
// control the control.. while SDA and SCL are inputs the external pullup
// resistors give a high conditon whilst when SDA or SCL are outputs
// the control lines are pulled low.
void main(void) // program entry
{
int index = 0; // text variable
OPTION_REG = 0x88; // timer pre-scaler
CMCON = 0x7; // Comparitors off
LCD_TRIS = 0b00000000; // LCD port as outputs
I2C_TRIS = 0b11111111; // I2C port as inputs
__delay_ms(150);
RA6 = 0; // SDC clock
RA7 = 0; // SDA Data
I2C_PORT = 0;
LCD_init(); // Initalise screen
ini_adxl345(); // Initalise Accelerometer
__delay_ms(30); // Helps Initalise screen
// LCD_goto(1,0);
// LCD_printC("Writing..");
/*
LCD_goto(1,0);
int id, pow, bw_rate;
id= E_Read(IDDV); // should be 229
__delay_ms(10);
pow=E_Read(0x2D); //should be 8 to activate
__delay_ms(10);
bw_rate =E_Read(0x2C); //BW_RATE 0x2C is 13
sprintf(LCDbuffer,"id=%3d pow=%3d BW_RATE=%3d",id,pow,bw_rate);
LCD_printR(LCDbuffer); // use sprintf to format
*/
signed long x,y,z;
signed long xhi,xlo,yhi,ylo,zhi,zlo;
signed long Xaccumulate, Yaccumulate, Zaccumulate;
signed long Xaverage, Yaverage, Zaverage;
int i;
while(1) // endless Loop
{
Xaccumulate = Yaccumulate = Zaccumulate = 0;
for (i=0; i<16; i++) { // Read sequentially 16 times then get an average.
ErrFlags = 0; // Clear error
I2C_Start();
I2C_Write(CHIP_Write);
if(!I2C_nack()) ErrFlags = 1; // Whoops!! problems
I2C_Write((unsigned char) DATAX0 & 0xff); // DATAX0 is the first of 6 bytes
if(!I2C_nack()) ErrFlags = 1; // to read sequentially
I2C_Start();
I2C_Write(CHIP_Read); //
if(!I2C_nack()) ErrFlags = 1;
xlo = I2C_Read(); // read character
I2C_ack();
xhi = I2C_Read(); // read character
I2C_ack();
ylo = I2C_Read(); // read character
I2C_ack();
yhi = I2C_Read(); // read character
I2C_ack();
zlo = I2C_Read(); // read character
I2C_ack();
zhi = I2C_Read(); // read character
I2C_Sendnack();
I2C_Stop();
Xaccumulate += ((xhi<<8) | xlo); //Xaccumulate = Xaccumulate + (xhi*256 + xlo)
Yaccumulate += ((yhi<<8) | ylo);
Zaccumulate += ((zhi<<8) | zlo);
} // for loop
// x= (xhi<<8) | xlo;
// y= (yhi<<8) | ylo;
// z= (zhi<<8) | zlo;
// Calculate average accelerometer readings over last 16 samples
/* *** Other methods of dividing gave me results in the +/- thousands ***
DIV From Hi-Tech C manual
Synopsis
#include <stdlib.h>
div_t div (int numer, int demon)
Description
The div() function computes the quotient and remainder of the numerator divided by the denominator.
Example
#include <stdlib.h>
#include <stdio.h>
void
main (void)
{
div_t x;
x = div(12345, 66);
printf("quotient = %d, remainder = %d\n", x.quot, x.rem);
}
See Also
udiv(), ldiv(), uldiv()
Return Value
Returns the quotient and remainder into the div_t structure.
*/
div_t xavg ; // div_t is a structure explained above
div_t yavg ;
div_t zavg ;
xavg = div(Xaccumulate, 16);
yavg = div(Yaccumulate, 16);
zavg = div(Zaccumulate, 16);
LCD_goto(1,0);
sprintf(LCDbuffer,"X=%5d",xavg.quot);
LCD_printR(LCDbuffer); // use sprintf to format
LCD_goto(1,9);
sprintf(LCDbuffer,"Y=%5d",yavg.quot);
LCD_printR(LCDbuffer); // use sprintf to format
LCD_goto(2,4);
sprintf(LCDbuffer,"Z=%5d",zavg.quot);
LCD_printR(LCDbuffer); // use sprintf to format
//__delay_ms(25);
__delay_ms(250); // Just so the numbers don't change too fast.
/*
// This reads byte registers one at a time.
x=(E_Read(DATAX1)*256) | (E_Read(DATAX0));
y=(E_Read(DATAY1)*256) | (E_Read(DATAY0));
z=(E_Read(DATAZ1)*256) | (E_Read(DATAZ0));
LCD_goto(1,0);
sprintf(LCDbuffer,"x=%5d",x);
LCD_printR(LCDbuffer); // use sprintf to format
LCD_goto(1,12);
sprintf(LCDbuffer,"y=%5d",y);
LCD_printR(LCDbuffer); // use sprintf to format
LCD_goto(2,0);
sprintf(LCDbuffer,"z=%5d",z);
LCD_printR(LCDbuffer); // use sprintf to format
*/
} //while
} //main(void)
// Write to eeprom this returns a 0 if it fails or a 1 if all gooes well
// For byte eeproms and RTC devices.. comment out the Hi address byte
// and the I2C_nack() that follows it in both these functions.
// This is random writing. Write to a specified address
char E_Write(int addr, unsigned char ch)
{
I2C_Start(); // Send a start condition
I2C_Write(CHIP_Write); // chip write address
if(!I2C_nack()) return 0; // wait for ack
// I2C_Write((unsigned char) (addr >> 8 & 0xff)); // Comment out if single byte addess
// if(!I2C_nack()) return 0; // wait for ack
I2C_Write((unsigned char) addr & 0xff); // low address
if(!I2C_nack()) return 0; // wait for ack
I2C_Write(ch); // Write values to Eeprom
if(!I2C_nack()) return 0;
I2C_Stop(); // Send a stop.
return 1; // All went well
}
// The function takes an address and Returns a character
// This is random reading. Read from a specified addess
unsigned char E_Read(int addr)
{
unsigned char byte;
unsigned char ch;
ErrFlags = 0; // Clear error
I2C_Start();
I2C_Write(CHIP_Write);
if(!I2C_nack()) return 1; // Whoops!! problems
// I2C_Write((unsigned char)( addr >> 8 & 0xff)); // Comment out if single byte addess
// if(!I2C_nack()) return 1;
I2C_Write((unsigned char) addr & 0xff); //
if(!I2C_nack()) return 1;
I2C_Start();
I2C_Write(CHIP_Read); //
if(!I2C_nack()) return 1;
ch = I2C_Read(); // read character
I2C_Sendnack();
I2C_Stop();
return ch;
}
void I2C_Start() // start combo
{
SDA = 1;
SCL = 1;
SDA = 0; // bring SDA low while SCL is high
SCL = 0;
}
void I2C_Stop() // stop combo
{
SCL = 0;
SDA = 0;
SCL = 1;
SDA = 1; // bring SDA high while SCL is high
}
unsigned char I2C_Read()
{
char index;
unsigned char byte = 0; // initialize in byte
for(index = 0x80; index > 0 ;index>>=1) // using index as a mask
{ // cycles through bit 7 to bit 0
if(SDAI) byte += index; // read in the SDA line
clock();
}
return byte; // 8 bits in...
}
void I2C_Write(unsigned char ch)
{
char index;
for(index = 0x80; index > 0 ;index>>=1) // using index as mask
{
if(ch & index) // bit high or low
SDA = 1;
else
SDA = 0;
clock();
}
}
void I2C_ack() // generate an ack
{
SDA = 0;
clock();
SDA = 1;
}
void I2C_Sendnack() // generate a not ack
{
SDA = 1;
clock();
}
char I2C_nack() // recive a not ack
{
unsigned char timeout = 255;
SDA = 1;
SCL = 1;
while(SDAI) // wait till SDA goes low
{
if(timeout-- == 0) return 0; // whoops!! no ack recieved
}
SCL = 0;
return 1;
}
void clock() // Might work without the nop
{
SCL=1;
asm("nop");
SCL=0;
}
void convert(int numb) // Takes a interger number
{ // and converts to single
TenK = numb / 10000; // decimal numbers.
Thou = (numb % 10000)/ 1000; //
Hund = (numb % 1000) / 100;
Tens = (numb % 100) / 10;
Ones = numb % 10;
}
// In C we can use Pointers, Pointers are advanced programming
// and can tie you in knots. The simplest pointer to use is the
// array pointer using "rom char" allows the pointer to
// point to constant character in code section.
void LCD_printC(const char * str) // This passes the start a ROM character array
{ // by default the pointer points to data section
while(*str != 0) // while the character pointed to isn't 0
LCD_char(*str++); // print out the character, then increment
} // the pointer down the array
void LCD_printR(char * str) // This passes the start of a RAM character array
{ // by default the pointer points to data section
while(*str != 0) // while the character pointed to isn't 0
LCD_char(*str++); // print out the character, then increment
} // the pointer down the array
void LCD_init()
{
LCD_cmd(0x20); // 4 bit
LCD_cmd(0x28); // display shift
LCD_cmd(0x6); // character mode
LCD_cmd(0xc); // display on / off and cursor
LCD_clr(); // clear display
}
void LCD_hex(int value)
{
char data;
data = value >> 4 & 0xf;
data = HEX_Table[data]; // send upper nibble
LCD_char(data);
data = value & 0xf; // send lower nibble
data = HEX_Table[data];
LCD_char(data);
}
void LCD_goto(char line, char column) // combines line and lineW
{
unsigned char data = 0x80; // default to 1
if(line == 2)data = 0xc0; // change to 2
data += column; // add in column
LCD_cmd(data);
}
void LCD_clr()
{
LCD_cmd(1); // Clr screen
}
void LCD_cur(char on)
{
unsigned char cur = 0xc; // cursor off
if(on) cur = 0xd; // cursor on
LCD_cmd(cur);
}
void LCD_busy()
{
unsigned char BUSY = 0;
while(1)
{
LCD_TRIS = 0x0f; // port to read mode
LCD_RS = 0x0;
LCD_RW = 0x1; // set to read
LCD_E = 0x1;
BUSY = LCD_PORT & 0xf; // high byte comes first
__delay_us(5); // so busy flag is on bit 3
LCD_E = 0x0;
LCD_E = 0x1;
__delay_us(5); // dummy read
LCD_E = 0x0;
LCD_RW = 0x0; // set to write
LCD_TRIS = 0x00; // port to write mode
if(!(BUSY & 0x8 )) return; // AND with bit 3
}
}
void LCD_cmd(unsigned char ch)
{
LCD_PORT = ch >> 4 & 0xf;
LCD_RS = 0;
pulse_E();
LCD_PORT = ch & 0xf;
LCD_RS = 0;
pulse_E();
__delay_ms(5);
}
void LCD_charD(unsigned char ch)
{
ch+=0x30;
LCD_char(ch);
}
void LCD_char(unsigned char ch)
{
LCD_PORT = ch >> 4 & 0xf;
LCD_RS = 1;
pulse_E();
LCD_PORT = ch & 0xf;
LCD_RS = 1;
pulse_E();
__delay_ms(5);;
}
void pulse_E()
{
LCD_E = 1;
__delay_us(1);
LCD_E = 0;
}
Attachments
Last edited: