View previous topic :: View next topic |
Author |
Message |
jacqueskleynhans
Joined: 10 Apr 2008 Posts: 109 Location: Cape Town, South Africa
|
LIS3L02AL Final code Need Help |
Posted: Tue Sep 02, 2008 3:24 am |
|
|
Hi Guys im so close to finishing this dam code i can smell victory just the final tweaks thats killing me.
I wote a program for the the LIS3L02AL measuring and calibrating its 3 axis output and displaying g values. I tried to write the code with ease of understanding and reading in mind. Code as goes as follows.
I know its a lot but please help me out so that i can post this code in the CODE BIN. For future use to someone
Code: | #include <18F452.h>
#device *=16 ADC=10 ICD=true
//#fuses HS,NOWDT,NOPROTECT, NOPUT, NOLVP, NOBROWNOUT
#fuses HS,NOWDT,NOPROTECT, NOWRT, NOCPD, NOLVP, NOBROWNOUT, NOPUT
#include <hardware18F452.h>
#include <global.h>
#include <Timer.c>
#include <Calibration.c>
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)
#inline
void nop()
{
#asm
NOP
#endasm
}
void init()
{
timer0_init();
// Start watchdog timer with default configuration
// restart_wdt();
// Configure all Ports for ADC
Setup_ADC_Ports(AN0_AN1_AN2_AN4_VSS_VREF);
// Initialize the port output data latches
PORT_A = 0;
PORT_B = 0;
PORT_C = 0;
PORT_D = 0;
PORT_E = 0;
// Setup data direction registers (1 = input)
Set_Tris_A(0b111111);
Set_Tris_B(0b00000000);
Set_Tris_C(0b10000000);
Set_Tris_D(0b00000000);
Set_Tris_E(0b111);
port_b_pullups(true);
// Initialize and restart watchdog timer
// setup_counters(WDT,WDT_36MS);
// setup_counters(WDT,WDT_ON);
// restart_wdt();
// Setup AD clock
SETUP_ADC( ADC_CLOCK_DIV_8);
//Usart Asysnchronous registers setup
SPBRG = 25;
TXSTA = 0b00100100;
}
void main()
{
init();
enable_interrupts(GLOBAL);
//Setting Initial values
System = CAL;
Timer0Done = false;
SampleCount = 0;
// Main program loop
while(true)
{
int8 i;
float tempx, tempy, tempz;
// Housekeeping
// restart_wdt();
switch(System)
{
case CAL:
{
Adc_Get_Data();
Cal_Constant();
printf("end of constants\n\r");
System = SAMPLE;
break;
}
case SAMPLE:
{
if(Timer0Done)
{
Sample_Data();
SampleCount++;
Timer0Done = false;
if(SampleCount>=128) System = PRINTARRAYS;
}
break;
}
case PRINTARRAYS:
{
for(i=0;i<128;i++)
{
tempx = Compensate_X(XArray[i]);
tempy = Compensate_Y(YArray[i]);
tempz = Compensate_Z(ZArray[i]);
}
printf("X:%3.3f Y:%3.3f Z:%3.3f ",tempx,tempy,tempz);
Timer0Done = false;
SampleCount = 0;
System = SAMPLE;
break;
}
default: break;
} // end switch
} //end while
}
| quick run through in case 1 i ask the user to orientate the device 9 ways to get values in which in "Cal_Constants" i used to work out some line calibration constants. Code follows Code: |
int8 cnt2;
printf("Orientate Xaxis for +G and press any key to continue.\n\r");
getc();
X1 = Y1 = Z1 =X2 = Y2 = Z2 = X3 = Y3 = Z3 = 0;
set_adc_channel(XCHAN); // Select the A/D channel
delay_us(20); // Aquisition time
for(cnt2 = 0; cnt2 < 8; cnt2++)
{
delay_us(3);
adc_value = read_adc(); // Read from specified channel
X1 += adc_value; // read the raw adc value
}
X1 >>= 3; // Average the value
printf("Orientate Xaxis for 0G and press any key to continue.\n\r");
getc();
set_adc_channel(XCHAN); // Select the A/D channel
delay_us(20); // Aquisition time
for(cnt2 = 0; cnt2 < 8; cnt2++)
{
delay_us(3);
adc_value = read_adc(); // Read from specified channel
X2 += adc_value; // Read the raw adc value
}
X2 >>= 3; // Average the value
printf("Orientate Xaxis for -G and press any key to continue.\n\r");
getc();
set_adc_channel(XCHAN); // Select the A/D channel
delay_us(20); // Aquisition time
for(cnt2 = 0; cnt2 < 8; cnt2++)
{
delay_us(3);
adc_value = read_adc(); // Read from specified channel
X3 += adc_value; // Read the raw adc value
}
X3 >>= 3; // Average the value
printf("Orientate Yaxis for +G and press any key to continue.\n\r");
getc();
set_adc_channel(YCHAN); // Select the A/D channel
delay_us(20); // Aquisition time
for(cnt2 = 0; cnt2 < 8; cnt2++)
{
delay_us(3);
adc_value = read_adc(); // Read from specified channel
Y1 += adc_value; // Read the raw adc value
}
Y1 >>= 3; // Average the value
printf("Orientate Yaxis for 0G and press any key to continue.\n\r");
getc();
set_adc_channel(YCHAN); // Select the A/D channel
delay_us(20); // Aquisition time
for(cnt2 = 0; cnt2 < 8; cnt2++)
{
delay_us(3);
adc_value = read_adc(); // Read from specified channel
Y2 += adc_value; // Read the raw adc value
}
Y2 >>= 3; // Average the value
printf("Orientate Yaxis for -G and press any key to continue.\n\r");
getc();
set_adc_channel(YCHAN); // Select the A/D channel
delay_us(20); // Aquisition time
for(cnt2 = 0; cnt2 < 8; cnt2++)
{
delay_us(3);
adc_value = read_adc(); // Read from specified channel
Y3 += adc_value; // Read the raw adc value
}
Y3 >>= 3; // Average the value
printf("Orientate Zaxis for +G and press any key to continue.\n\r");
getc();
set_adc_channel(ZCHAN); // Select the A/D channel
delay_us(20); // Aquisition time
for(cnt2 = 0; cnt2 < 8; cnt2++)
{
delay_us(3);
adc_value = read_adc(); // Read from specified channel
Z1 += adc_value; // Read the raw adc value
}
Z1 >>= 3; // Average the value
printf("Orientate Zaxis for 0G and press any key to continue.\n\r");
getc();
set_adc_channel(ZCHAN); // Select the A/D channel
delay_us(20); // Aquisition time
for(cnt2 = 0; cnt2 < 8; cnt2++)
{
delay_us(3);
adc_value = read_adc(); // Read from specified channel
Z2 += adc_value; // Read the raw adc value
}
Z2 >>= 3; // Average the value
printf("Orientate Zaxis for -G and press any key to continue.\n\r");
getc();
set_adc_channel(ZCHAN); // Select the A/D channel
delay_us(20); // Aquisition time
for(cnt2 = 0; cnt2 < 8; cnt2++)
{
delay_us(3);
adc_value = read_adc(); // Read from specified channel
Z3 += adc_value; // read the raw adc value
}
Z3 >>= 3; // Average the value
} |
Calibration constants
Code: |
void Cal_Constant(void)
{
//X1 = Y1 = Z1 = +G values
//X2 = Y2 = Z2 = 0G values
//X3 = Y3 = Z3 = -G values
// Calibration Line:
// Equation for a line is Y = MX+B
// Our value is derived from the line eqation thus g becomes.
// g = an+b for positive values
// g = cn+d for negative values
// P0 = 0g values (values for the respective axis will be later substituted in)
// P1 = +g values (values for the respective axis will be later substituted in)
// p2 = -g values (values for the respective axis will be later substituted in)
// g = an+b (positive)
// 0 = a(P0)+b
// 1 = a(P1)+b
//Solve for a and b
// b = -aP0
// and b also becomes = 1-aP1
// a = -b/P0
// substitute a to get b
// so b becomes 1-(-b/P0)P1
// from this b = (1+b(P1/P0))
// then 1 = b - b(P1/P0)
// Finaly b becomes: 1/(1-P1/P0)
// As we know a = -b/P0 we can substitute because we know b
// a becomes : -1/(1-P1/P0)P0 = -1/(P0-P1) = 1/(P1-P0)
// g = cn+d (negative)
// 0 = c(P0)+d
//-1 = c(P2)+d
// Solve for c and d
// d = -1-cP2
// d = -(1+cP2)
// and d also becomes = -cP0
// from this c becomes -d/P0
// substitute c into first d
// d = -(1+cP2) this becomes
// d = -(1+(d/P0)P2)
// d = (-1+dP2/P0)
// d = dP2/P0 - 1
// d(1-P2/P0) = -1
// so then d becomes: (-1/(1-P2/P0)) = 1/(P2/P0-1)
// from this c can be calculated
// we know c = -d/P0
// when we sub in d we get: -1/((P2/P0 - 1)P0) = -1/(P2 - P0) = 1/(P0 - P2)
//FROM THIS:
//X calibration constants beacomes
A_X = 1/(X1-X2);
B_X = 1/(1-(X1/X2));
C_X = 1/(X2-X3);
D_X = 1/((X3/X2)-1);
//Y calibration constants beacomes
A_Y = 1/(Y1-Y2);
B_Y = 1/(1-(Y1/Y2));
C_Y = 1/(Y2-Y3);
D_Y = 1/((Y3/Y2)-1);
//Z calibration constants beacomes
A_Z = 1/(Z1-Z2);
B_Z = 1/(1-(Z1/Z2));
C_Z = 1/(Z2-Z3);
D_Z = 1/((Z3/Z2)-1);
} |
In the next state i read the the adc when ever i receive a TMR0 interrupt
then i increment the sampletimer variable and when the timer reaches 127 i print. To save some space in my micro i decided to save the data as int16 and just before i print to convert them to g's and then print but this is where my problem occurs.
Interrupt routine
Code: |
//Timer0 interrupt routine
#int_timer0
void timer0_isr(void)
{
TMR0L = TMR0_INIT;
Timer0Done = TRUE;
}
|
and my get samples code
Code: |
void Sample_Data(void)
{
//Measure_Xout(); // Get reading from adc
set_adc_channel(XCHAN); // Select the A/D channel
delay_us(20); // Aquisition time
XArray[SampleCount] = read_adc();
//Measure_Yout(); // Get reading from adc
set_adc_channel(YCHAN); // Select the A/D channel
delay_us(20); // Aquisition time
YArray[SampleCount] = read_adc();
//Measure_Zout(); // Get reading from adc
set_adc_channel(ZCHAN); // Select the A/D channel
delay_us(20); // Aquisition time
ZArray[SampleCount] = read_adc();
}
|
So this leaves us to the PRINTARRAYS state in my machine. Pasing the float. From putty terminal i get an reading every 10 sec for some reason.
my compensation code uses calibration constants from the first state.
here it goes.
Code: |
float Compensate_X(int16 xval)
{
//X1 = +G values
//X2 = 0G values
//X3 = -G values
if(xval > X2) XG = ((A_X*xval) + B_X);
else XG = ((C_X*xval) + D_X);
return(XG);
}
float Compensate_Y(int16 yval)
{
// Y1 = +G values
// Y2 = 0G values
// Y3 = -G values
if(yval > Y2) YG = ((A_Y*yval) + B_Y);
else YG = ((C_Y*yval) + D_Y);
return(YG);
}
float Compensate_Z(int16 zval)
{
// Z1 = +G values
// Z2 = 0G values
// Z3 = -G values
if(zval > Z2) ZG = ((A_Z*zval) + B_Z);
else ZG = ((C_Z*zval) + D_Z);
return(ZG);
}
|
Please any i need some help figuring this out so i can get on to my other work.
Kindest Regards
Jacques Kleynhans _________________ "THE ONLY EASY DAY WAS YESTERDAY"
Last edited by jacqueskleynhans on Tue Sep 02, 2008 10:34 am; edited 1 time in total |
|
|
jacqueskleynhans
Joined: 10 Apr 2008 Posts: 109 Location: Cape Town, South Africa
|
Just to add something |
Posted: Tue Sep 02, 2008 5:54 am |
|
|
Im using compiler 4.057
Kind Regards
Jacques Kleynhans _________________ "THE ONLY EASY DAY WAS YESTERDAY" |
|
|
jacqueskleynhans
Joined: 10 Apr 2008 Posts: 109 Location: Cape Town, South Africa
|
Need Help |
Posted: Tue Sep 02, 2008 10:37 am |
|
|
Hope someone can help me.
Kindest Regards
Jacques _________________ "THE ONLY EASY DAY WAS YESTERDAY" |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Sep 02, 2008 1:20 pm |
|
|
There are several reasons for you getting little response:
1) It is a very long story with way too much code. Next time try to reduce your program to the smallest possible part still representing your problem. Post maximum 20 - 30 lines.
2) Your program is incomplete. Important variable declarations are missing, no #fuses line, etc. When posting a program make sure we can copy / paste the program without modifications into our compiler.
And most important:
3) You don't say what your problem is... |
|
|
jacqueskleynhans
Joined: 10 Apr 2008 Posts: 109 Location: Cape Town, South Africa
|
** |
Posted: Tue Sep 02, 2008 1:46 pm |
|
|
fuses are top.
OO yea u got a point no problem statement:
My problem is in the printarrays section. When i read a value to the array x,y or z it is stored directly from read_adc(). Just before printing i do the compensate routine but i dont think my int to float conversion is correct.
Code: | void Sample_Data(void)
{
//Measure_Xout(); // Get reading from adc
set_adc_channel(XCHAN); // Select the A/D channel
delay_us(20); // Aquisition time
XArray[SampleCount] = read_adc();
//Measure_Yout(); // Get reading from adc
set_adc_channel(YCHAN); // Select the A/D channel
delay_us(20); // Aquisition time
YArray[SampleCount] = read_adc();
//Measure_Zout(); // Get reading from adc
set_adc_channel(ZCHAN); // Select the A/D channel
delay_us(20); // Aquisition time
ZArray[SampleCount] = read_adc();
} |
Then when i try the printf it does nothing:
Code: |
case PRINTARRAYS:
{
for(i=0;i<128;i++)
{
tempx = Compensate_X(XArray[i]);
tempy = Compensate_Y(YArray[i]);
tempz = Compensate_Z(ZArray[i]);
}
printf("X:%3.3f Y:%3.3f Z:%3.3f ",tempx,tempy,tempz);
Timer0Done = false;
SampleCount = 0;
System = SAMPLE;
break;
} |
Thats my problem _________________ "THE ONLY EASY DAY WAS YESTERDAY" |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1933 Location: Norman, OK
|
|
Posted: Tue Sep 02, 2008 2:30 pm |
|
|
OK, when you say:
Quote: | Then when i try the printf it does nothing: |
Does that mean you get nothing at all from the printf or just zeros where you expect numbers?
If you get nothing, have you put a printf at the start of the PRINTARRAYS case to make sure that it actually gets there? |
|
|
jacqueskleynhans
Joined: 10 Apr 2008 Posts: 109 Location: Cape Town, South Africa
|
** |
Posted: Tue Sep 02, 2008 3:07 pm |
|
|
I am suppose, if everything works get out 3g values namely
X:
Y:
Z:
These numbers are supposed to be floats but every now and again eg: 10-20sec i get X:1 Y:512 Z:0 which means nothing to me or at least is not the values im looking for. What bugs me is that where are the rest of the values i mean even if the info in the arrays are wrong there are suppose to be something right.
I know for a fact the first part eg (Orientation section) is right so im doing something wrong in getting the value from the adc and doing the compensation just before printing.
I have the suspicion that my problem lies in the compensation subroutine
when i return the float. _________________ "THE ONLY EASY DAY WAS YESTERDAY" |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Sep 02, 2008 3:18 pm |
|
|
OK, my mistake, the #fuses are there.
Can use post the #use delay() line?
Like I said, the declaration for a lot of important variables is not shown. Especially I want to see the declaration of:
- XArray
- A_X, B_X, C_X, D_X
- X1, X2
- XG
- SampleCount
- System
Post the timer0_init() function.
Post the definition of CAL, SAMPLE and PRINTARRAYS |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Sep 02, 2008 3:28 pm |
|
|
Quote: | What bugs me is that where are the rest of the values |
1. Post the total number of lines of output from your program
that you expect to see. These are the lines that are displayed with
printf. How many lines should there be ?
Also post a example of the data that you expect to see in the output
(post a few sample lines of output).
2. Post what you currently get for the output. |
|
|
jacqueskleynhans
Joined: 10 Apr 2008 Posts: 109 Location: Cape Town, South Africa
|
** |
Posted: Tue Sep 02, 2008 4:08 pm |
|
|
ckielstra:
This is from my Calibration.h Code: | // Variable definitions
unsigned int16 X1, X2, X3;
unsigned int16 Y1, Y2, Y3;
unsigned int16 Z1, Z2, Z3;
unsigned int16 adc_value;
float A_X,B_X,A_Y,B_Y,A_Z,B_Z;
float C_X,D_X,C_Y,D_Y,C_Z,D_Z;
float XG, YG, ZG;
//Function declarations
void Adc_Get_Data();
void Cal_Constant();
void Sample_Data(void);
float Compensate_X(int16 xval);
float Compensate_Y(int16 yval);
float Compensate_Z(int16 zval);
|
from my global.h Code: | // Constants
// Clock frequency
#define OSC_FREQ 4000000
#define BAUD_RATE 9600
#use delay(clock=OSC_FREQ,RESTART_WDT)
#use rs232(baud=BAUD_RATE,xmit=TX,rcv=RX,parity=N,bits=8,RESTART_WDT,STREAM=streamed)
// Global variable
unsigned int16 XArray[128]; //64 bytes
unsigned int16 YArray[128]; //64 bytes
unsigned int16 ZArray[128]; //64 bytes
//ADC channel constants
#define XCHAN 1
#define YCHAN 2
#define ZCHAN 4
// State Machine accelerometer
// Global variable
unsigned int16 System;
unsigned int16 SampleCount;
// Global constant
#define CAL 0
#define SAMPLE 1
#define PRINTARRAYS 2
|
timer0_init: Code: |
#include <Timer.h>
//Timer0 Initializasion
void timer0_init(void)
{
//Setup for timer0
set_timer0(RTCC_INTERNAL|RTCC_8_BIT|RTCC_DIV_1);
TMR0L = TMR0_INIT;
enable_interrupts(INT_TIMER0);
}
//Timer0 interrupt routine
#int_timer0
void timer0_isr(void)
{
TMR0L = TMR0_INIT;
Timer0Done = TRUE;
} |
timer.h Code: |
//Global Variables
Boolean Timer0Done;
//Global Constants
#define TMR0_INIT 6
//Function Declarations
void timer0_init(void); |
FOR PCM programmer
As i understand it the array saves up 127 values then goes to printarrays section and systematically do the compensate routines whiles clocking the values out on the serial.
What i see on the output: First 9 lines those Orientation question that prompts after that i get the the test print Code: | printf("end of constants\n\r"); | and then nothing. I did the testing on my PIC development board picdem2plus demo board. so i was trying to get something while repeatedly pressing reset and then one and only one X:1 Y:512 Z:0
appeared.
So im stumped. I must just add i left the WDT masked out for testing purposes.
Regards _________________ "THE ONLY EASY DAY WAS YESTERDAY" |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Sep 02, 2008 4:22 pm |
|
|
Quote: | case PRINTARRAYS:
{
for(i=0;i<128;i++)
{
tempx = Compensate_X(XArray[i]);
tempy = Compensate_Y(YArray[i]);
tempz = Compensate_Z(ZArray[i]);
}
printf("X:%3.3f Y:%3.3f Z:%3.3f ",tempx,tempy,tempz);
Timer0Done = false;
SampleCount = 0;
System = SAMPLE;
break;
} |
Is the problem really this simple ? Is the problem that you put the
printf statement outside the for() loop, instead of inside it ? |
|
|
jacqueskleynhans
Joined: 10 Apr 2008 Posts: 109 Location: Cape Town, South Africa
|
** |
Posted: Tue Sep 02, 2008 4:59 pm |
|
|
gave me a scare!! but i didnt solve all i get on my output is: Quote: | Orientate Xaxis for +G and press any key to continue.
Orientate Xaxis for 0G and press any key to continue.
Orientate Xaxis for -G and press any key to continue.
Orientate Yaxis for +G and press any key to continue.
Orientate Yaxis for 0G and press any key to continue.
Orientate Yaxis for -G and press any key to continue.
Orientate Zaxis for +G and press any key to continue.
Orientate Zaxis for 0G and press any key to continue.
Orientate Zaxis for -G and press any key to continue.
end of constants
Orientate Xaxis for +G and press any key to continue.
Orientate Xaxis for 0G and press any key to continue.
Orientate Xaxis for -G and press any key to continue.
Orientate Yaxis for +G and press any key to continue.
Orientate Yaxis for 0G and press any key to continue.
Orientate Yaxis for -G and press any key to continue.
Orientate Zaxis for +G and press any key to continue.
Orientate Zaxis for 0G and press any key to continue.
Orientate Zaxis for -G and press any key to continue.
end of constants
Orientate Xaxis for +G and press any key to continue.
Orientate Xaxis for 0G and press any key to continue.
Orientate Xaxis for -G and press any key to continue.
Orientate Yaxis for +G and press any key to continue.
Orientate Yaxis for 0G and press any key to continue.
Orientate Yaxis for -G and press any key to continue.
Orientate Zaxis for +G and press any key to continue.
Orientate Zaxis for 0G and press any key to continue.
Orientate Zaxis for -G and press any key to continue.
end of constants
Orientate Xaxis for +G and press any key to continue.
Orientate Xaxis for 0G and press any key to continue.
Orientate Xaxis for -G and press any key to continue.
Orientate Yaxis for +G and press any key to continue.
Orientate Yaxis for 0G and press any key to continue.
Orientate Yaxis for -G and press any key to continue.
Orientate Zaxis for +G and press any key to continue.
Orientate Zaxis for 0G and press any key to continue.
Orientate Zaxis for -G and press any key to continue.
end of constants
|
Sigh _________________ "THE ONLY EASY DAY WAS YESTERDAY" |
|
|
jacqueskleynhans
Joined: 10 Apr 2008 Posts: 109 Location: Cape Town, South Africa
|
** |
Posted: Tue Sep 02, 2008 5:08 pm |
|
|
think i have narrowed it down i add printf's through my whole code. The timer interrupt i think is not firing. so its in a loop waiting for the interrupt to give the TRUE.
Hmmm _________________ "THE ONLY EASY DAY WAS YESTERDAY" |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Sep 02, 2008 5:31 pm |
|
|
Nice one!!!
Code: | set_timer0(RTCC_INTERNAL|RTCC_8_BIT|RTCC_DIV_1);
| Try setup_timer_0() instead !!!!! |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Sep 02, 2008 5:42 pm |
|
|
A few minor issues: Code: | #use rs232(baud=BAUD_RATE,xmit=TX,rcv=RX,parity=N,bits=8,RESTART_WDT,STREAM=streamed)
| Add the ERRORS directive. This tells the compiler to add code for restarting the UART after input buffer overflows (only space for 3 characters).
Code: | #device *=16 ADC=10 ICD=true | *=16 has no effect on the PIC18 and can be removed. The PIC18 only has one pointer type and you can not configure it.
Code: | unsigned int16 System;
unsigned int16 SampleCount; | Both variables can be changed into an int8 to save a little bit ROM and RAM.
The int16 type is defined as unsigned, so now you are declaring 'unsigned unsigned'. It doesn't hurt, but all extra code without purpose is cluttering your program.
The Cal_Constants function has 9 times a repeating pattern of code. This asks for implementing a sub-function. Makes for easier code maintenance and reduces code size.
Last edited by ckielstra on Tue Sep 02, 2008 5:57 pm; edited 1 time in total |
|
|
|