Maker Pro
Maker Pro

C programming code question!

ohea180

Feb 11, 2012
7
Joined
Feb 11, 2012
Messages
7
im doing a project using the sparkfun package tracker for measuring vibration while out at sea.
just wondering how to change the measurement up to +/-16g? the datasheet for the accelerometer ADXL345 says the measurement range is “user selectable” to ±2, ±4, ±8, ±16g!

In the datasheet for the accelerometer (adxl345) it says the following:

Table 21. g Range Setting
Setting
D1 D0 g Range
0 0 ±2 g
0 1 ±4 g
1 0 ±8 g
1 1 ±16 g

Now in the c code for the adxl345 i found this:

adxl345_write(DATA_FORMAT, RANGE_1); //Configure the Accelerometer for +/-8g

And in the h code for the adxl345 i found this:

//Data Format Bits
#define RANGE_0 (1<<0)
#define RANGE_1 (1<<1)
#define JUSTIFY (1<<2)
#define FULL_RES (1<<3)

#define INT_INVERT (1<<5)
#define SPI (1<<6)
#define SELF_TEST (1<<7)


So i know its set to 8g i just dont know how to change it 2 16g as im new to programming.

Any help with be brilliant
Kind regrads
Damien
 

jackorocko

Apr 4, 2010
1,284
Joined
Apr 4, 2010
Messages
1,284
What is the table referring to when it says D1 and D0? Are you sure these aren't hardware jumpers or something similar?

Links would help to possibly.
 
Last edited:

jackorocko

Apr 4, 2010
1,284
Joined
Apr 4, 2010
Messages
1,284
wait a minute, post the whole code that is relevant to this line. Or you could just post the whole code.

Code:
adxl345_write(DATA_FORMAT, RANGE_1);	//Configure the Accelerometer for +/-8g

edit: how is the adxl345_write function implemented? Can you post the code that is relevant to that function. I think without looking at the code in depth, you might be able to do this.

Code:
adxl345_write(DATA_FORMAT, RANGE_0);
adxl345_write(DATA_FORMAT, RANGE_1);
 
Last edited:

ohea180

Feb 11, 2012
7
Joined
Feb 11, 2012
Messages
7
the following is the whole c file for the accelerometer:

/*
ADXL345 Library

This libary contains functions to interact with the ADXL345 Triple Axis Digital Accelerometer from Analog Devices written for the ATmega328p
In order to use this libary, define the appropriate pins in the ADXL345.h file

created 20 Aug 2009
by Ryan Owens
http://www.sparkfun.com

*/
#include "ADXL345.h"
#include <stdlib.h>
#include <stdio.h>
#include "LPC214x.h"
#include "spi0.h"
#include "PackageTracker.h"
#include "rprintf.h"


void initAccel(void){

adxl345_write(DATA_FORMAT, RANGE_1); //Configure the Accelerometer for +/-8g


//Set Accel. to Interrupt. Interrupt will occur on EINT2 pin.
adxl345_write(THRESH_FF, 0x0E); //Set Accelerometer Threshold to 600 mg
//adxl345_write(THRESH_FF, 0x14); //Set Accelerometer Threshold to 600 mg

adxl345_write(TIME_FF, 0x0A); //Free Fall will trigger after falling for a minimum of 100ms.

adxl345_write(BW_RATE, 0x07); //Set Output Rate to 100 Hz
adxl345_write(INT_MAP, ~FREE_FALL); //Map the Free Fall interrupt to pin INT1; all other interrupts to INT2
adxl345_write(INT_ENABLE, FREE_FALL); //Activate the 'Free Fall' Interrupt
adxl345_write(POWER_CTL, MEASURE); //Put the Accelerometer into measurement mode
}

int accelX(void){
char high_byte, low_byte=0;
int value=0;

high_byte = adxl345_read(DATAX1);
low_byte = adxl345_read(DATAX0);
value = (high_byte << 8) | low_byte;

return value;
}

int accelY(void){
char high_byte, low_byte=0;
int value=0;

high_byte = adxl345_read(DATAY1);
low_byte = adxl345_read(DATAY0);
value = (high_byte << 8) | low_byte;

return value;
}

int accelZ(void){
char high_byte, low_byte=0;
int value=0;

high_byte = adxl345_read(DATAZ1);
low_byte = adxl345_read(DATAZ0);
value = (high_byte << 8) | low_byte;

return value;
}

void powerdownAccel(void){
SelectAccelerometer();
//SPI0_send(WRITE | Ctrl_Reg1);
//SPI0_send(~PD);
UnselectAccelerometer();
}

char adxl345_read(char register_address){
char read_address=0x80 | register_address;
char register_value=0;
int spcr_setting=0;

spcr_setting = S0SPCR; //Save the current SPI Control Register Settings
S0SPCR = 0x38; // Master, no interrupt enable, 8 bits, Active Low SCK pin, CPHA=1

SelectAccelerometer();
delay_ms(1);
SPI0_send(read_address);
register_value=SPI0_recv();
delay_ms(1);
UnselectAccelerometer();

S0SPCR = spcr_setting;
return register_value;
}

void adxl345_write(char register_address, char register_value){
int spcr_setting=0;

spcr_setting = S0SPCR; //Save the current SPI Control Register Settings
S0SPCR = 0x38; // Master, no interrupt enable, 8 bits, Active Low SCK pin, CPHA=1

SelectAccelerometer();
delay_ms(1);
SPI0_send(register_address);
SPI0_send(register_value);
delay_ms(1);
UnselectAccelerometer();

S0SPCR = spcr_setting;
}



And this the whole h file for the accelerometer:


char adxl345_read(char address);
void adxl345_write(char address, char value);
void adxl345_hw_setup(void);

void initAccel(void);

int accelX(void);
int accelY(void);
int accelZ(void);
void powerdownAccel(void);

//**********************************************************
//
// Macros
//
//**********************************************************
#define SelectAccel() IOCLR0 = CHIP_SELECT
#define UnselectAccel() IOSET0 = CHIP_SELECT
#define READ 0x8000
#define WRITE 0x0000

//**********************************************************
//
// Pin Definitions
//
//**********************************************************
//Definitions for PackageTracker
#define CHIP_SELECT (1<<17)


//ADXL Register Map
#define DEVID 0x00 //Device ID Register
#define THRESH_TAP 0x1D //Tap Threshold
#define OFSX 0x1E //X-axis offset
#define OFSY 0x1F //Y-axis offset
#define OFSZ 0x20 //Z-axis offset
#define DUR 0x21 //Tap Duration
#define Latent 0x22 //Tap latency
#define Window 0x23 //Tap window
#define THRESH_ACT 0x24 //Activity Threshold
#define THRESH_INACT 0x25 //Inactivity Threshold
#define TIME_INACT 0x26 //Inactivity Time
#define ACT_INACT_CTL 0x27 //Axis enable control for activity and inactivity detection
#define THRESH_FF 0x28 //free-fall threshold
#define TIME_FF 0x29 //Free-Fall Time
#define TAP_AXES 0x2A //Axis control for tap/double tap
#define ACT_TAP_STATUS 0x2B //Source of tap/double tap
#define BW_RATE 0x2C //Data rate and power mode control
#define POWER_CTL 0x2D //Power Control Register
#define INT_ENABLE 0x2E //Interrupt Enable Control
#define INT_MAP 0x2F //Interrupt Mapping Control
#define INT_SOURCE 0x30 //Source of interrupts
#define DATA_FORMAT 0x31 //Data format control
#define DATAX0 0x32 //X-Axis Data 0
#define DATAX1 0x33 //X-Axis Data 1
#define DATAY0 0x34 //Y-Axis Data 0
#define DATAY1 0x35 //Y-Axis Data 1
#define DATAZ0 0x36 //Z-Axis Data 0
#define DATAZ1 0x37 //Z-Axis Data 1
#define FIFO_CTL 0x38 //FIFO control
#define FIFO_STATUS 0x39 //FIFO status

//Power Control Register Bits
#define WU_0 (1<<0) //Wake Up Mode - Bit 0
#define WU_1 (1<<1) //Wake Up mode - Bit 1
#define SLEEP (1<<2) //Sleep Mode
#define MEASURE (1<<3) //Measurement Mode
#define AUTO_SLP (1<<4) //Auto Sleep Mode bit
#define LINK (1<<5) //Link bit

//Interrupt Enable/Interrupt Map/Interrupt Source Register Bits
#define OVERRUN (1<<0)
#define WATERMARK (1<<1)
#define FREE_FALL (1<<2)
#define INACTIVITY (1<<3)
#define ACTIVITY (1<<4)
#define DOUBLE_TAP (1<<5)
#define SINGLE_TAP (1<<6)
#define DATA_READY (1<<7)

//Data Format Bits
#define RANGE_0 (1<<0)
#define RANGE_1 (1<<1)
#define JUSTIFY (1<<2)
#define FULL_RES (1<<3)

#define INT_INVERT (1<<5)
#define SPI (1<<6)
#define SELF_TEST (1<<7)


thanks again for the help
 

(*steve*)

¡sǝpodᴉʇuɐ ǝɥʇ ɹɐǝɥd
Moderator
Jan 21, 2010
25,510
Joined
Jan 21, 2010
Messages
25,510
Just be careful that changing the range doesn't result in a reduction in sensitivity. It may be sensible to use the lowest range you can.

How many ships can pull 7G in a turn? (says me wondering at the idea of sailors in G-suits)
 

ohea180

Feb 11, 2012
7
Joined
Feb 11, 2012
Messages
7
i tried it jacko but no luck, the code complies without error but the board doesnt record when turned on

Hey steve, thanks for the advice, i have the datasheet for the accelerometer and it lists the different sensitivity for differents ranges so should be ok there. Im using it on the RIBs though not the main vessels so its just in case theres a peck over 16g from a sudden impact
 

timothy48342

Nov 28, 2011
218
Joined
Nov 28, 2011
Messages
218
I am just now being exposed to microcontrollers and the Adrino, but I am proficient in C/C++, and I looked through the code and from what I see, when adxl345_write gets executed it does basically 4 things:
1) prepare the device to recieve data.
2) send the code for the register to be modified. (DATA_FORMAT)
3) send 8 bits for the content.
4) end receiving data

What I think this would do....
Code:
adxl345_write(DATA_FORMAT, RANGE_0);
adxl345_write(DATA_FORMAT, RANGE_1);

...is first clear out 7 bits and just put a 1 in D0, and then clear out even that and just put a 1 in bit D1, so that the final result for the DATA_FORMAT register is just 0b00000010.

You want 0b??????11 with the ? bits left are as they were.

Woudn't you want to first read that register and store it, then OR it with 0b00000011, then write the result back in so as not to disturb the content of the other bits?

-t
(I Know I don't know much about this yet. This is thoughts from a newbie.)
 

KrisBlueNZ

Sadly passed away in 2015
Nov 28, 2011
8,393
Joined
Nov 28, 2011
Messages
8,393
RANGE_0 and RANGE_1 correspond to bits 0 and 1 of the data register, which, between them, select the measurement range. Each bit can be 1 or 0, so with two bits, there are four ranges. Before you read the accelerometer, you write a value to the data format register using adxl345_write(). The second parameter to that function is the appropriate combination of RANGE_0 and RANGE_1 that selects the desired range.
For a range of ±2G those bits need to be 0 and 0, so you use adxl345_write(DATA_FORMAT, 0). That's because for 2G range, both of those bits should be zero.
For ±4G use adxl345_write(DATA_FORMAT, RANGE_0) to set bit 0 of the range bit pair.
For ±8G use adxl345_write(DATA_FORMAT, RANGE_1) to set bit 1 of the range bit pair. That's how it was written originally.
For ±16G use adxl345_write(DATA_FORMAT, RANGE_1 | RANGE_0) to set both bits of the range bit pair.
For better clarity, I would #define four more constants:
#define RANGE_2G 0
#define RANGE_4G RANGE_0
#define RANGE_8G RANGE_1
#define RANGE_16G (RANGE_1 | RANGE_0)
Then you can say, somewhere near the start of your program:
#define MY_G_RANGE RANGE16G // or whichever range you want to use
and in the code where you're reading the accelerometer, use:
adxl345_write(DATA_FORMAT, MY_G_RANGE)
If you later decide you want to use a different G range, you change the #define of MY_G_RANGE, which should be somewhere early in the program. This is much more maintainable approach than looking all through the code for instances of adxl345_write() and changing the parameter.
 
Last edited:

jackorocko

Apr 4, 2010
1,284
Joined
Apr 4, 2010
Messages
1,284
tim, I will admit I know nothing about the uC used in this application. But is the purpose of saving those settings then? I am still a little lost on what the write function actually does. But you are probably on the right track and the OP should take your advice.

Kris, how does that work though. What does | do, as the function only accepts a char? I am not very proficient with C so some clarification would certainly be appreciated. thanks
 
Last edited:

ohea180

Feb 11, 2012
7
Joined
Feb 11, 2012
Messages
7
finally got it working :D

i tried what you said kris and was getting the same problem as before with jacko, the board wasnt saving anyting to the sd card. I had messed around a little with the sleep and wake times awhile back and found that there was a max wake time i could have. So seeing as i was changing the range i tried reducing the wake time and it started recording again. Dont really know why just happy its recording to +/- 16g now!

Thanks a million everyone for the help as this should make my results away more accurate :)
 

KrisBlueNZ

Sadly passed away in 2015
Nov 28, 2011
8,393
Joined
Nov 28, 2011
Messages
8,393
The vertical bar is a bitwise OR.
The two constants defined in the header file, RANGE_0 and RANGE_1, are:
RANGE_0 00000001 binary (from 1 << 0 which means 1 shifted left by zero bits)
RANGE_1 00000010 binary (from 1 << 1 which means 1 shifted left by 1 bit).
The bottom two bits in the data format register can have four possible combinations of values, and these are created from zero, one, or both of the RANGE_* constants. For the 16G range, you need both bits set, so you have to combine RANGE_0 and RANGE_1. You can add them, or bitwise-OR them; both have the same effect, but bitwise OR makes it a bit clearer what's happening.
I'm glad you (ohea180) got it working! I recommend defining those four constants, RANGE_2G, RANGE_4G, RANGE_8G and RANGE_16G, for clarity.
Edit: corrected "logical OR" to "bitwise OR" three times above.
 
Last edited:

jackorocko

Apr 4, 2010
1,284
Joined
Apr 4, 2010
Messages
1,284
Very well kris, I see. Some times Logical OR & AND are || and && respectively. Guess it just depends on the uC?

Anyway, I wondered what the 1<<? format was, now I know.
 

KrisBlueNZ

Sadly passed away in 2015
Nov 28, 2011
8,393
Joined
Nov 28, 2011
Messages
8,393
jackorocko, sorry, my mistake. The | operator is a BITWISE OR, not LOGICAL. You're right, logical operations are two characters. I've corrected my previous posting.
 
Top