|
|
View previous topic :: View next topic |
Author |
Message |
sephers2
Joined: 10 Oct 2013 Posts: 1
|
PIC and ADXL345 SPI Accelerometer |
Posted: Thu Oct 10, 2013 3:19 pm |
|
|
Hi everyone,
I'm trying to get an ADXL345 SPI Accelerometer working with my PIC16F722 (using CCS) however everything appearing on my pc is just random numbers, but they will only change when the microcontroller is reset...it's like it can produce one reading and then that's it...
Code: | #include <16f722.h>
#include <string.h>
#fuses INTRC_IO, NOPROTECT, NOBROWNOUT, NOWDT, NOPLLEN, PUT, MCLR, NOPROTECT
#use delay(clock=8M)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,bits=8,stop=1)
void main(){
int data_in, address;
setup_oscillator(OSC_8MHZ);
setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4 );
delay_ms(200);
//Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
output_low(PIN_C2); //Select Accel
spi_write(0x31);
spi_write(0x01);
output_high(PIN_C2); //DeSelect Accel
//Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
output_low(PIN_C2); //Select Accel
spi_write(0x2D);
spi_write(0x08);
output_high(PIN_C2); //DeSelect Accel
delay_ms(20);
while(1){
output_high(PIN_B0);
//Ensure that bit 7 is set (read mode)
address = 0x80 | 0x32; //0x32 is the register address
//address = address | 0x40; //This is for the multibyte option
output_low(PIN_C2); //Select Accel
spi_write(address);
data_in = spi_read();
output_high(PIN_C2); //DeSelect Accel
delay_ms(5);
output_low(PIN_B0);
printf("%u\r",data_in);
delay_ms(5);
}
} |
Any help would be greatly appreciated |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1908
|
|
Posted: Thu Oct 10, 2013 4:24 pm |
|
|
Code: | #include <18F4680.h>
#device adc=10
#FUSES WDT
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES INTRC_IO //Internal RC oscillator, no clock out
#FUSES NOPROTECT //Code not protected from reading
#FUSES BROWNOUT //Reset when brownout detected
#FUSES BORV28 //Brownout reset at 2.8V
#FUSES PUT //Power Up Timer
#FUSES NOCPD //No EE protection
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWRT //Program memory not write protected
#FUSES NOWRTD //Data EEPROM not write protected
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#FUSES NOPBADEN //PORTB pins are configured as digital I/O on RESET
#FUSES BBSIZ4K //4K words Boot Block size
#FUSES NOWRTC //configuration not registers write protected
#FUSES NOWRTB //Boot block not write protected
#FUSES NOEBTR //Memory not protected from table reads
#FUSES NOEBTRB //Boot block not protected from table reads
#FUSES NOCPB //No Boot Block code protection
#FUSES NOLPT1OSC //Timer1 configured for higher power operation
#FUSES MCLR //Master Clear pin enabled
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#use delay(clock=8000000,RESTART_WDT)
#use spi(MASTER, DI=PIN_C4, DO=PIN_C5, CLK=PIN_C3)
#include <lcd_driver.c>
#include <math.h>
// Jan 4 2011
// this is a completely tested and working example/driver to read the
// x,y,z accelerations from an ADXL345 accelerometer and convert
// to angle
// both PIC and ADXL run @3.3V (LCD too) so no level converters are required
// PIC runs @8MHz from internal oscillator
#use fast_io (B)
#use fast_io (C)
int1 refresh_screen = FALSE;
#define CS PIN_C0
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
unsigned int16 x_accel, y_accel, z_accel;
float x_g, y_g, z_g;
float theta;
#include <Accelerometer Driver.c>
#include <Trig Functions.c>
#int_EXT1
void EXT1_isr(void) {
refresh_screen = TRUE;
}
void main() {
setup_oscillator(OSC_8MHZ|OSC_INTRC|OSC_31250|OSC_PLL_OFF); // setup internal oscillator to run @ 8MHz
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_CLOCK_DIV_2|ADC_TAD_MUL_0);
setup_psp(PSP_DISABLED);
setup_spi(SPI_MASTER | SPI_MODE_3 | SPI_CLK_DIV_4);
setup_wdt(WDT_ON);
setup_timer_0(RTCC_OFF);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
setup_ccp1(CCP_OFF);
setup_comparator(NC_NC_NC_NC);
//enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
// LCD connections as per lcd_driver.c (same as that included in the CCS drivers)
// The LCD is connected as shown on the Lab-X1 schematic:
// PIC pin D0 - LCD D0
// PIC pin D1 - LCD D1
// PIC pin D2 - LCD D2
// PIC pin D3 - LCD D3
// PIC pin D4 - LCD D4
// PIC pin D5 - LCD D5
// PIC pin D6 - LCD D6
// PIC pin D7 - LCD D7
// PIC pin E0 - LCD RS
// PIC pin E1 - LCD E
// PIC pin E2 - LCD R/W
// port B
// B0 - unused - OUTPUT
// B1 - INT1 - input
// B2 - INT2 - input
// B3 - unused - OUTPUT
// B4 - unused - OUTPUT
// B5 - unused - OUTPUT
// B6 - unused - OUTPUT
// B7 - unused - OUTPUT
//port_b_pullups(TRUE);
set_tris_b(0x06);
output_b(0x00);
clear_interrupt(INT_EXT1);
ext_int_edge(1, L_TO_H);
enable_interrupts(INT_EXT1);
// port C
// C0 - /CS - OUTPUT
// C1 - unused - OUTPUT
// C2 - unused - OUTPUT
// C3 - SCLK - OUTPUT
// C4 - MISO - INPUT
// C5 - MOSI - OUTPUT
// C6 - unused - OUTPUT
// C7 - unused - OUTPUT
output_c(0xff);
set_tris_c(0x10);
setup_accelerometer();
set_tris_e(0x00);
delay_ms(100);
lcd_init();
delay_ms(100);
lcd_putc("\fAccelerometer Test");
delay_ms(1000);
while (TRUE) {
restart_wdt();
if (refresh_screen == TRUE) {
refresh_screen = FALSE;
read_accel();
calc_angle(Y_PARALLEL_TO_PIPE);
printf(lcd_putc,"\fAngle=%f", theta);
lcd_putc(0xdf);
}
}
} |
Code: | Accelerometer Driver.c:
#define WRITE 0x00
#define READ 0x80
#define MULTIBYTE_TRANSFER 0x40
#define BW_RATE_REGISTER 0x2c
#define NO_POWER_SAVING 0x00
#define HZ6_25 0x06
#define DATA_FORMAT_REGISTER 0x31
#define DATA_FORMAT_VALUE 0x0b
#define FIFO_CONTROL_REGISTER 0x38
#define FIFO_CONTROL_VALUE 0x00
#define DATA_REG 0x32
#define POWER_CONTROL_REGISTER 0x2d
#define POWER_CONTROL_VALUE 0x08
#define INT_ENABLE_REGISTER 0x2e
#define INT_ENABLE_VALUE 0x80
#define INT_MAP_REGISTER 0x2f
#define INT_MAP_VALUE 0x7f
#define SIGN_BIT 9
#define ACCEL_MASK 0x01ff
int8 read_accel_register(int8 reg) {
int8 register_value;
output_low(CS);
delay_us(10);
spi_write(READ | reg);
register_value = spi_read(0x00);
delay_us(10);
output_high(CS);
return (register_value);
}
void setup_accelerometer(void) {
// set interrupt enable register
output_low(CS);
delay_us(1);
spi_write(WRITE | INT_ENABLE_REGISTER);
spi_write(INT_ENABLE_VALUE);
delay_us(1);
output_high(CS);
// set interrupt map register
output_low(CS);
delay_us(1);
spi_write(WRITE | INT_MAP_REGISTER);
spi_write(INT_MAP_VALUE);
delay_us(1);
output_high(CS);
// set data format register appropriately
output_low(CS);
delay_us(1);
spi_write(WRITE | DATA_FORMAT_REGISTER);
spi_write(DATA_FORMAT_VALUE);
delay_us(1);
output_high(CS);
// set rate register to 6.25Hz conversion, no power saving mode
output_low(CS);
delay_us(1);
spi_write(WRITE | BW_RATE_REGISTER);
spi_write(NO_POWER_SAVING | HZ6_25);
delay_us(1);
output_high(CS);
// set FIFO control register
output_low(CS);
delay_us(1);
spi_write(WRITE | FIFO_CONTROL_REGISTER);
spi_write(FIFO_CONTROL_VALUE);
delay_us(1);
output_high(CS);
// set power control register appropriately
output_low(CS);
delay_us(1);
spi_write(WRITE | POWER_CONTROL_REGISTER);
spi_write(POWER_CONTROL_VALUE);
delay_us(1);
output_high(CS);
}
void read_accel(void) {
int32 scratch;
float scale;
int1 neg_x = FALSE;
int1 neg_y = FALSE;
int1 neg_z = FALSE;
x_accel = 0;
y_accel = 0;
z_accel = 0;
output_low(CS);
delay_us(1);
spi_write(READ | MULTIBYTE_TRANSFER | DATA_REG);
x_accel = spi_read(0); // x low byte
x_accel = x_accel | ((int32)spi_read(0) << 8); // x high byte
y_accel = spi_read(0); // y low byte
y_accel = y_accel | ((int32)spi_read(0) << 8); // y high byte
z_accel = spi_read(0); // z low byte
z_accel = z_accel | ((int32)spi_read(0) << 8); // z high byte
delay_us(1);
output_high(CS);
if (bit_test(x_accel, SIGN_BIT)) {
neg_x = TRUE;
x_accel = ~x_accel;
x_accel++;
x_accel = x_accel & ACCEL_MASK;
}
else {
neg_x = FALSE;
}
if (bit_test(y_accel, SIGN_BIT)) {
neg_y = TRUE;
y_accel = ~y_accel;
y_accel++;
y_accel = y_accel & ACCEL_MASK;
}
else {
neg_y = FALSE;
}
if (bit_test(z_accel, SIGN_BIT)) {
neg_z = TRUE;
z_accel = ~z_accel;
z_accel++;
z_accel = z_accel & ACCEL_MASK;
}
else {
neg_z = FALSE;
}
// had problems when prototyping this as the 2 methods for calculating angle didn't agree due to
// gain imbalances in the x, y and z accelerations
// workaround is to note that all accelerations must add up to 1 g, so normalize
// each by the the total magnitude to compensate
scratch = ((int32)x_accel * (int32)x_accel) + ((int32)y_accel * (int32)y_accel) + ((int32)z_accel * (int32)z_accel);
scale = sqrt((float)scratch);
x_g = x_accel / scale;
if (neg_x == TRUE) {
x_g = -1 * x_g;
}
y_g = y_accel / scale;
if (neg_y == TRUE) {
y_g = -1 * y_g;
}
z_g = z_accel / scale;
if (neg_z == TRUE) {
z_g = -1 * z_g;
}
} |
Trig Functions.c:
Code: | #define X_PARALLEL_TO_PIPE 0
#define Y_PARALLEL_TO_PIPE 1
#define Z_PARALLEL_TO_PIPE 2
void calc_angle(int8 which) {
float denominator, theta1, theta2;
int1 add_180_to_theta1 = FALSE;
int1 add_360_to_theta2 = FALSE;
int1 rotate_90 = FALSE;
// if x axis is parallel to pipe
// theta (based on y) = sin^-1(-y/cos(sin^-1(x)))
// theta (based on z) = cos^-1(z/cos(sin^-1(x)))
// if y axis is parallel to pipe
// theta (based on z) = sin^-1(-z/cos(sin^-1(y)))
// theta (based on x) = cos^-1(x/cos(sin^-1(y)))
// if z axis is parallel to pipe
// theta (based on x) = sin^-1(-x/cos(sin^-1(z)))
// theta (based on y) = cos^-1(y/cos(sin^-1(z)))
// y parallel to pipe seems to be the most accurate
switch (which) {
case X_PARALLEL_TO_PIPE:
denominator = cos(asin(x_g));
theta1 = asin((-1 * y_g)/denominator);
theta2 = acos(z_g/denominator);
if (z_g < 0) {
add_180_to_theta1 = TRUE;
}
if (y_g >= 0) {
add_360_to_theta2 = TRUE;
}
break;
case Y_PARALLEL_TO_PIPE:
denominator = cos(asin(y_g));
theta1 = asin((-1 * z_g)/denominator);
theta2 = acos(x_g/denominator);
if (x_g < 0) {
add_180_to_theta1 = TRUE;
}
if (z_g >= 0) {
add_360_to_theta2 = TRUE;
}
rotate_90 = TRUE;
break;
case Z_PARALLEL_TO_PIPE:
denominator = cos(asin(z_g));
theta1 = asin((-1 * x_g)/denominator);
theta2 = acos(y_g/denominator);
if (y_g < 0) {
add_180_to_theta1 = TRUE;
}
if (x_g >= 0) {
add_360_to_theta2 = TRUE;
}
rotate_90 = TRUE;
break;
}
theta1 = theta1 * (180 / (4 * atan(1.0)));
if (add_180_to_theta1 == TRUE) {
theta1 = (-1 * theta1) + 180;
}
if (theta1 < 0) {
theta1 = theta1 + 360;
}
theta2 = theta2 * (180 / (4 * atan(1.0)));
if (add_360_to_theta2 == TRUE) {
theta2 = (-1 * theta2) + 360;
}
if ((theta1 > 270) && (theta2 < 90)) {
theta2 = theta2 + 360;
}
else if ((theta2 > 270) && (theta1 < 90)) {
theta1 = theta1 + 360;
}
theta = (theta1 + theta2) / 2;
if (rotate_90 == TRUE) {
theta = theta + 90;
}
if (theta > 360) {
theta = theta - 360;
}
} |
|
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|