Hi and happy new year,
This is my first post in the forum, but I've been lurking around here for a couple of years reading and learning from you guys before I took the plunge to join and share some knowledge. I thought as a first post I'd share a useful little bit of code I wrote to use as an include with proton to really take all the hard work out of using accelerometers with proton.
At this point it is only fair to pass credit onto Les at myamicus.co.uk who wrote a good tutorial and sample code currently at
http://www.myamicus.co.uk/content.php?270-MMA7260-Accelerometer-Interface - that I modified to make it into an include that can easily be called upon by any subsequent programs.
'--------------------------------------------------------------------
' Variables + Declarations
'--------------------------------------------------------------------
'device = 18f4550 'device identifier to allow test compilations
'only assigned as the default chip in proton compiler doesn't have
'enough ram to cope with this program
'--------------------------------------------------------------------
'The following variables MUST be assigned values in the main program
Dim Sensitivity As Byte 'Accelerometer Max G-force
Dim Channel_X As Byte 'ADC Channel to read X Axis from
Dim Channel_Y As Byte 'ADC Channel to read Y Axis from
Dim Channel_Z As Byte 'ADC Channel to read Z Axis from
Dim ADC_Sample_Width_Bits As Word 'How Many Bits Resolution ADC is set at
Dim VDD As Float 'VDD Voltage used in system
'--------------------------------------------------------------------
Dim Bandwidth_Calc As Word
Dim ADC_Increments As Dword 'To be calculate as 2 to the power(ADC_Resolution)
let Bandwidth_Calc = ADC_Sample_Width_Bits
let ADC_Increments = 1 'make it 1 so as we can double it again and again
'as part of the process of converting a decimal number into a binary power
'ie ADC_Sample_Width_Bits = 8 = binary 11111111 = 255 = ((1 * (2*2*2*2*2*2*2*2)-1)
While Bandwidth_Calc > 0 ' while loop
let ADC_Increments = ADC_Increments * 2 'double ADC_Increments for every bit
Dec Bandwidth_Calc 'of ADC_Sample_Width_Bits
Wend
let ADC_Increments = ADC_Increments - 1 ' minus one to represent the Right Most Bit being a 1 not a 2
'--------------------------------------------------------------------------------------------------
Symbol AD_Inc_Factor = VDD / ADC_Increments ' ADC to voltage conversion (VDD / ADC resolution)
Symbol cDegreeConversion = 180.0 / 3.14159265 ' Conversion from radians to degrees
Dim Resultant As Float ' Holds the result of the multiple sqr
Dim ResultantX As Float ' Holds the result of fGravity_X squared
Dim ResultantY As Float ' Holds the result of fGravity_Y squared
Dim ResultantZ As Float ' Holds the result of fGravity_Z squared
Dim Square_Temp As Float ' Holds the result of the multiple sqr
Dim Volts_Per_G As Float
Dim Angle_X As Byte ' Holds the inclination angle of the X axis
Dim Angle_Y As Byte ' Holds the inclination angle of the Y axis
Dim Angle_Z As Byte ' Holds the inclination angle of the Z axis
Dim Gravity_X As Float ' Holds the result of the X axis g-force calculation
Dim Gravity_Y As Float ' Holds the result of the Y axis g-force calculation
Dim Gravity_Z As Float ' Holds the result of the Z axis g-force calculation
Symbol Zero_G_X = 1.57 ' Zero g voltage level for X axis, as measured
Symbol Zero_G_Y = 1.55 ' Zero g voltage level for Y axis, as measured
Symbol Zero_G_Z = 1.65 ' Zero g voltage level for Z axis, as measured
Dim X_Force As Word ' Holds the median filtered result from the ADC
Dim Y_Force As Word ' Holds the median filtered result from the ADC
Dim Z_Force As Word ' Holds the median filtered result from the ADC
Dim X_Axis_Volts As Float ' Holds the voltage output from the channel
Dim Y_Axis_Volts As Float ' Holds the voltage output from the channel
Dim Z_Axis_Volts As Float ' Holds the voltage output from the channel
'
' Variables used by the bubble sort routine
'
Dim SortIndex As Byte
Dim Swap_Occured_Flag As Bit
Dim Sort_Swap_Temp As Word
Dim Sort_Result As Sort_Swap_Temp
Symbol ADC_SamplesToTake = 9 ' The amount of samples to take for the bubble sort
Dim Working_Sample_Array[ADC_SamplesToTake] As Word
Declare Adin_Res = ADC_Sample_Width_Bits ' X-bit result required
Declare Adin_Tad = FRC ' RC OSC chosen
Declare Adin_Stime = 50 ' Allow 50us sample time
'--------------------------------------------------------------------
' Read the X output from the accelerometer (Forward-Backward)
'
' Input : None
' Output : X_Force holds the filtered result from the ADC
' X_Axis_Volts holds the voltage output from the channel
' Notes : None
'--------------------------------------------------------------------
ReadChannel_X:
'--------------------------------------------------------------------
For SortIndex = (ADC_SamplesToTake - 1) To 0 Step -1 ' Create a loop for the amount of samples to take
Working_Sample_Array[SortIndex] = ADIn Channel_X ' Read the channel into the filter array
' Read the value from channel 0 of the ADC and place in variable Var1.
DelayUS 2 ' A small delay to allow the ADC's capacitor to re-charge
Next ' Close the loop
GoSub MedianFilter ' Perform a median filter on the samples
X_Force = Sort_Result ' Transfer the result of the filter
X_Axis_Volts = X_Force * AD_Inc_Factor ' Convert to a voltage
Return
'--------------------------------------------------------------------
' Read the Y output from the accelerometer (Side to Side)
'
' Input : None
' Output : Y_Force holds the filtered result from the ADC
' Y_Axis_Volts holds the voltage output from the channel
' Notes : None
'--------------------------------------------------------------------
ReadChannel_Y:
'--------------------------------------------------------------------
For SortIndex = (ADC_SamplesToTake - 1) To 0 Step -1 ' Create a loop for the amount of samples to take
Working_Sample_Array[SortIndex] = ADIn Channel_Y ' Read the channel into the filter array
DelayUS 2 ' A small delay to allow the ADC's capacitor to re-charge
Next ' Close the loop
GoSub MedianFilter ' Perform a median filter on the samples
Y_Force = Sort_Result ' Transfer the result of the filter
Y_Axis_Volts = Y_Force * AD_Inc_Factor ' Convert to a voltage
Return
'--------------------------------------------------------------------
' Read the Z output from the accelerometer (Up and Down)
'
' Input : None
' Output : Z_Force holds the filtered result from the ADC
' Z_Axis_Volts holds the voltage output from the channel
' Notes : None
'--------------------------------------------------------------------
ReadChannel_Z:
'--------------------------------------------------------------------
For SortIndex = (ADC_SamplesToTake - 1) To 0 Step -1 ' Create a loop for the amount of samples to take
Working_Sample_Array[SortIndex] = ADIn Channel_Z ' Read the channel into the filter array
DelayUS 2 ' A small delay to allow the ADC's capacitor to re-charge
Next ' Close the loop
GoSub MedianFilter ' Perform a median filter on the samples
Z_Force = Sort_Result ' Transfer the result of the filter
Z_Axis_Volts = Z_Force * AD_Inc_Factor ' Convert to a voltage
Return
'--------------------------------------------------------------------
' The main program loop starts here
Main:
' Set_1_5g() ' Set accelerometer sensitivity
'
' Open the ADC and make AN0, AN1, and AN2 analogue inputs
'
' OpenADC'(ADC_FOSC_64 & ADC_RIGHT_JUST & ADC_2_TAD, ADC_REF_VDD_VSS, ADC_1ANA & ADC_2ANA & ADC_3ANA)
'
' Display the accelerometer values on the serial terminal
'
' While 1 = 1 ' Create an infinite loop
GoSub ReadChannel_X ' Read X channel
GoSub ReadChannel_Y ' Read Y channel
GoSub ReadChannel_Z ' Read Z channel
'--------------------------------------------------------------------
' Implement a bubble sorting median filter
'
' Input : Working_Sample_Array holds the values to sort
' Output : wSortResult holds the median of the values
' Notes : None
'
'--------------------------------------------------------------------
Repeat
Swap_Occured_Flag = 0 ' Clear flag that indicates swap.
SortIndex = 0
Repeat ' For each cell of the array...
If Working_Sample_Array[SortIndex] > Working_Sample_Array[SortIndex + 1] Then ' Move larger values up.
Sort_Swap_Temp = Working_Sample_Array[SortIndex] ' ..by swapping them.
Working_Sample_Array[SortIndex] = Working_Sample_Array[SortIndex + 1]
Working_Sample_Array[SortIndex + 1] = Sort_Swap_Temp
Swap_Occured_Flag = 1 ' Set bit if swap occurred.
EndIf
Inc SortIndex
Until SortIndex > ADC_SamplesToTake ' Check next cell of the array.
Until Swap_Occured_Flag = 0
' Keep sorting until no more swaps.
'--------------------------------------------------------------------
MedianFilter:
'--------------------------------------------------------------------
Sort_Result = Working_Sample_Array[ADC_SamplesToTake / 2] ' Extract the middle (median) value
Return
'--------------------------------------------------------------------
Calculations:
'--------------------------------------------------------------------
Gravity_X = (X_Axis_Volts - Zero_G_X) / Volts_Per_G
Gravity_Y = (Y_Axis_Volts - Zero_G_Y) / Volts_Per_G
Gravity_Z = (Z_Axis_Volts - Zero_G_Z) / Volts_Per_G
'
' Convert the gravity measurements to angles
'
ResultantX = Gravity_X * Gravity_X
ResultantY = Gravity_Y * Gravity_Y
ResultantZ = Gravity_Z * Gravity_Z
Resultant = Sqr(ResultantX + ResultantY + ResultantZ)
'
' Convert to integer degrees
'
Angle_X = (ACos(Gravity_X / Resultant)) * cDegreeConversion
Angle_Y = (ACos(Gravity_Y / Resultant)) * cDegreeConversion
Angle_Z = (ACos(Gravity_Z / Resultant)) * cDegreeConversion
The Code is pretty long winded and very well commented, as is my programming style, so it should be easy enough to follow..... But if anyone has any problems with it I'll happily help. Basically the way I work it is I saved this as accelerometer.inc in the directory with the rest of the other proton includes, then I start the main program by:
Device = 18F25K20
Include "accelerometer.inc"
'--------------------------------------------------------------------
'The following variables MUST be assigned values in the main program
Let Sensitivity = 3 'Accelerometer Max G-force
Let Channel_X = 0 'ADC Channel to read X Axis from
Let Channel_Y = 1 'ADC Channel to read Y Axis from
Let Channel_Z = 2 'ADC Channel to read Z Axis from
Let ADC_Sample_Width_Bits = 10 'How Many Bits Resolution ADC is set at
Let VDD = 4.55 'VDD Voltage used in system
'--------------------------------------------------------------------
GoTo ReadChannel_X 'calls the subroutine to read the x channel of the accelerometer
While X_Force <> 0
HSerOut [ Dec X_Force ]
Wend
Best wishes, and happy new year....
/Jay