This is the start of my program:
using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Presentation.Shapes;
using Microsoft.SPOT.Touch;
using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;
using Gadgeteer.Modules.Seeed;
namespace Hinge.Recorder
{
public partial class Program
{
// Sensors data arrays
public ArrayList AccData = new ArrayList();
public ArrayList Acc2Data = new ArrayList();
public ArrayList CompassData = new ArrayList();
public ArrayList Compass2Data = new ArrayList();
// Recorders
private System.IO.StreamWriter swAcc;
private System.IO.StreamWriter swAcc2;
private System.IO.StreamWriter swCompass;
private System.IO.StreamWriter swCompass2;
public int numberOfEntriesAcc, numberOfEntriesCompass;
static long startTime;
public bool recorderRunning = false;
public static GT.StorageDevice _storage;
// This method is run when the mainboard is powered up or reset.
void ProgramStarted()
{
/*******************************************************************************************
Modules added in the Program.gadgeteer designer view are used by typing
their name followed by a period, e.g. button. or camera.
Many modules generate useful events. Type +=<tab><tab> to add a handler to an event, e.g.:
button.ButtonPressed +=<tab><tab>
If you want to do something periodically, use a GT.Timer and handle its Tick event, e.g.:
GT.Timer timer = new GT.Timer(1000); // every second (1000ms)
timer.Tick +=<tab><tab>
timer.Start();
*******************************************************************************************/
// Use Debug.Print to show messages in Visual Studio's "Output" window during debugging.
Debug.Print("Program Started");
InitializeStorage();
InitializeSensors();
}
void InitializeSensors()
{
//Sensors events
accelerometer.MeasurementComplete += new Accelerometer.MeasurementCompleteEventHandler(accelerometer_MeasurementComplete);
accelerometer2.MeasurementComplete += new Accelerometer.MeasurementCompleteEventHandler(accelerometer2_MeasurementComplete);
compass.MeasurementComplete += new Compass.MeasurementCompleteEventHandler(compass_MeasurementComplete);
compass2.MeasurementComplete += new Compass.MeasurementCompleteEventHandler(compass2_MeasurementComplete);
//Sensors Settings
accelerometer.MeasurementRange = Accelerometer.Range.EightG;
accelerometer.ContinuousMeasurementInterval = new TimeSpan(0, 0, 0, 0, 20);
accelerometer2.MeasurementRange = Accelerometer.Range.EightG;
accelerometer2.ContinuousMeasurementInterval = new TimeSpan(0, 0, 0, 0, 20);
compass.ContinuousMeasurementInterval = new TimeSpan(0, 0, 0, 0, 20);
compass2.ContinuousMeasurementInterval = new TimeSpan(0, 0, 0, 0, 20);
button.ButtonPressed += button_ButtonPressed;
}
And this is the cs file from the accelerometer software which referenced from my project:
using System;
using Microsoft.SPOT;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using GTI = Gadgeteer.Interfaces;
namespace Gadgeteer.Modules.Seeed
{
/// <summary>
/// An Accelerometer Gadgeteer module, based on the Freescale Semiconductor MMA7455L Three Axis Accelerometer IC.
/// </summary>
public class Accelerometer : GTM.Module
{
// Note: A constructor summary is auto-generated by the doc builder.
/// <summary></summary>
/// <param name="socketNumber">The socket that this module is plugged in to.</param>
public Accelerometer(int socketNumber)
{
// This finds the Socket instance from the user-specified socket number.
// This will generate user-friendly error messages if the socket is invalid.
// If there is more than one socket on this module, then instead of "null" for the last parameter,
// put text that identifies the socket to the user (e.g. "S" if there is a socket type S)
Socket socket = Socket.GetSocket(socketNumber, true, this, null);
offsets = new CalibrationOffsets(0, 0, 0);
// This creates an GTI.InterruptInput interface. The interfaces under the GTI namespace provide easy ways to build common modules.
// This also generates user-friendly error messages automatically, e.g. if the user chooses a socket incompatible with an interrupt input.
this.int1 = new GTI.InterruptInput(socket, GT.Socket.Pin.Three, GTI.GlitchFilterMode.Off, GTI.ResistorMode.PullDown, GTI.InterruptMode.RisingEdge, this);
i2c = new GTI.I2CBus(socket, 0x1D, 50, this);
// This registers a handler for the interrupt event of the interrupt input (which is below)
this.int1.Interrupt += new GTI.InterruptInput.InterruptEventHandler(int1_Interrupt);
continuousTimer = new Gadgeteer.Timer(new TimeSpan(0, 0, 0, 0, 200));
continuousTimer.Tick += new Timer.TickEventHandler(continuousTimer_Tick);
OperatingMode = Mode.Measurement;
MeasurementRange = Range.TwoG;
}
private GTI.InterruptInput int1;
private GTI.I2CBus i2c;
private GT.Timer continuousTimer;
private bool continuousMeasurement = false;
private Range range = Range.TwoG;
private bool autoResetThresholdDetection = false;
// Used to store calibration settings in non-volatile memory
private static ExtendedWeakReference calibrationEWR = null;
[Serializable]
private class CalibrationOffsets
{
public int X = 0;
public int Y = 0;
public int Z = 0;
public CalibrationOffsets(int x, int y, int z)
{
X = x;
Y = y;
Z = z;
}
}
private CalibrationOffsets offsets;
private enum Mode
{
Standby = 0,
Measurement = 1,
LevelDetection = 2,
PulseDetection = 3
}
private Mode OperatingMode
{
get
{
byte b = ReadByte(Register.MCTL);
return (Mode)(b & 0x03); // Read bits 0 and 1
}
set
{
// Always set bits: Bit7 = 0, Bit6 (DRPD) = 1, Bit5 (SPI3W) = 0, Bit4 (STON) = 0
Write(Register.MCTL, (byte)(0x40 | (((byte)range) << 2) | (byte)value));
}
}
/// <summary>
/// Measurement range.
/// </summary>
public enum Range
{
/// <summary>
/// +/- 8G measurement range
/// </summary>
EightG = 0,
/// <summary>
/// +/- 2G measurement range
/// </summary>
TwoG = 1,
/// <summary>
/// +/- 4G measurement range
/// </summary>
FourG = 2
}
/// <summary>
/// Sets or gets the measurement range.
/// </summary>
public Range MeasurementRange
{
get
{
byte b = ReadByte(Register.MCTL);
range = (Range)((b & 0x0C) >> 2); // Read bits 2 and 3
return range;
}
set
{
// Always set bits: Bit7 = 0, Bit6 (DRPD) = 1, Bit5 (SPI3W) = 0, Bit4 (STON) = 0
this.range = value;
Write(Register.MCTL, (byte)(0x40 | (((byte)range) << 2) | (byte)OperatingMode));
}
}
/// <summary>
/// A set of acceleration readings.
/// </summary>
public class Acceleration
{
/// <summary>
/// Acceleration in the X axis, in g.
/// </summary>
public double X { get; private set; }
/// <summary>
/// Acceleration in the Y axis, in g.
/// </summary>
public double Y { get; private set; }
/// <summary>
/// Acceleration in the Z axis, in g.
/// </summary>
public double Z { get; private set; }
public Acceleration(double x, double y, double z)
{
this.X = x;
this.Y = y;
this.Z = z;
}
/// <summary>
/// Provides a string representation of the <see cref="Acceleration"/> instance.
/// </summary>
/// <returns>A string describing the values contained in the object.</returns>
public override string ToString()
{
return "X: " + X.ToString("f2") + " Y: " + Y.ToString("f2") + " Z: " + Z.ToString("f2");
}
}
/// <summary>
/// Gets or sets the interval at which continuous measurements are taken.
/// </summary>
/// <remarks>
/// The default value for this property is 100 milliseconds.
/// </remarks>
public TimeSpan ContinuousMeasurementInterval
{
get
{
return continuousTimer.Interval;
}
set
{
continuousTimer.Stop();
continuousTimer.Interval = value;
if (continuousMeasurement) continuousTimer.Start();
}
}
/// <summary>
/// Obtains a single reading from the <see cref="Accelerometer"/> and raises the <see cref="MeasurementComplete"/> event when complete.
/// </summary>
/// <returns>This method returns the current acceleration, in g's (gravity units).</returns>
public Acceleration RequestMeasurement()
{
// We use the 8-bit resolution mode (register XOUT8), because this can be used in 8G, 2G and 4G.
// For 10-bit a different register (XOUTL) is needed and it is just 8G.
// Ref: MMA7455L.pdf, Measurement Mode p.9
//
// Calibration procedure is described in Freescale application note AN3745 (Ref.: MMA7455L.pdf, Offset Drift p.24)
Read(Register.XOUT8, _readBuffer24);
// Decode Two's Complement values.
int x = ((((_readBuffer24[0] >> 7) == 1) ? -128 : 0) + (_readBuffer24[0] & 0x7F)) + offsets.X;
int y = ((((_readBuffer24[1] >> 7) == 1) ? -128 : 0) + (_readBuffer24[1] & 0x7F)) + offsets.Y;
int z = ((((_readBuffer24[2] >> 7) == 1) ? -128 : 0) + (_readBuffer24[2] & 0x7F)) + offsets.Z;
Acceleration acceleration = new Acceleration(ConvertDataToG(x), ConvertDataToG(y), ConvertDataToG(z));
OnMeasurementCompleteEvent(this, acceleration);
return acceleration;
}
private double ConvertDataToG(int data)
{
switch (this.range)
{
case Range.TwoG: return ((double)data / 128) * 2;
case Range.FourG: return ((double)data / 128) * 4;
case Range.EightG: return ((double)data / 128) * 8;
default: throw new ArgumentOutOfRangeException();
}
}
/// <summary>
/// Calibrates the accelerometer.
/// </summary>
/// <param name="referenceAcceleration">An acceleration representing the resting orientation of the accelerometer.</param>
public void Calibrate(Acceleration referenceAcceleration)
{
OperatingMode = Mode.Measurement;
Range b = MeasurementRange;
Read(Register.XOUT8, _readBuffer24);
// Decode Two's Complement values.
int x = ((((_readBuffer24[0] >> 7) == 1) ? -128 : 0) + (_readBuffer24[0] & 0x7F));
int y = ((((_readBuffer24[1] >> 7) == 1) ? -128 : 0) + (_readBuffer24[1] & 0x7F));
int z = ((((_readBuffer24[2] >> 7) == 1) ? -128 : 0) + (_readBuffer24[2] & 0x7F));
double gravityValue = 0;
switch (MeasurementRange)
{
case Range.TwoG :
gravityValue = 64;
break;
case Range.FourG:
gravityValue = 32;
break;
case Range.EightG:
gravityValue = 16;
break;
}
offsets.X = -x + (int)(gravityValue * referenceAcceleration.X);
offsets.Y = -y + (int)(gravityValue * referenceAcceleration.Y);
offsets.Z = -z + (int)(gravityValue * referenceAcceleration.Z);
}
/// <summary>
/// Calibrates the accelerometer. Make sure that the accelerometer is not moving and is resting on a flat surface when calling this method. Use the overload method to specify an
/// arbitrary orientation to calibrate.
/// </summary>
public void Calibrate()
{
Calibrate(new Acceleration(0, 0, 1));
}
/// <summary>
/// Saves the calibration values to non-volatile memory.
/// </summary>
public void SaveCalibration()
{
if (calibrationEWR == null)
{
calibrationEWR = ExtendedWeakReference.RecoverOrCreate(typeof(CalibrationOffsets), 0, ExtendedWeakReference.c_SurviveBoot | ExtendedWeakReference.c_SurvivePowerdown);
calibrationEWR.Priority = (int)ExtendedWeakReference.PriorityLevel.NiceToHave;
}
calibrationEWR.Target = offsets;
}
/// <summary>
/// Loads previously saved calibration settings.
/// </summary>
/// <returns>True if previously saved settinsg were found. False otherwise.</returns>
public bool LoadCalibration()
{
if (calibrationEWR == null)
{
calibrationEWR = ExtendedWeakReference.RecoverOrCreate(typeof(CalibrationOffsets), 0, ExtendedWeakReference.c_SurviveBoot | ExtendedWeakReference.c_SurvivePowerdown);
calibrationEWR.Priority = (int)ExtendedWeakReference.PriorityLevel.NiceToHave;
}
CalibrationOffsets savedOffsets = (CalibrationOffsets)calibrationEWR.Target;
if (savedOffsets != null)
{
offsets = savedOffsets;
return true;
}
else
{
offsets = new CalibrationOffsets(0, 0, 0);
}
return false;
}
/// <summary>
/// Enables automatic detection and notification when an acceleration threshold is exceeded. This results in the <see cref="ThresholdExceeded"/> event being raised. Continous measurement is disabled when threshold detection mode is enabled.
/// </summary>
/// <param name="threshold">Acceleration threshold, between -8.0 and 8.0 G.</param>
/// <param name="enableX">Enable threshold detection in the X axis.</param>
/// <param name="enableY">Enable threshold detection in the Y axis.</param>
/// <param name="enableZ">Enable threshold detection in the Z axis.</param>
/// <param name="absolute">Absoulte threshold detection. If set to true the sign of the threshold is ignored, and the absolute value of the acceleration is compared with the absolute value of the threshold. If set to false, the sign of the threshold will be taken into account, the event will only be raised if the acceleration falls below a negative threshold or above a positive threshold.</param>
/// <param name="detectFreefall">Freefall detection. If set to true, the <see cref="ThresholdExceeded"/> event will be raised when the acceleration in all the enabled axes is less than the absolute threshold. In order to detect freefall correctly, set the threshold to a small value and enable detection on all axes.</param>
/// <param name="autoReset">Automatically reset the thershold detection. If set to false, the <see cref="ThresholdExceeded"/> will be raised only once, until the <see cref="ResetThresholdDetection"/> method is called manually. If set to true, the <see cref="ResetThresholdDetection"/> will be called automatically, and the event will be continously raised as long as the thershold conditions are exceeded.</param>
public void EnableThresholdDetection(double threshold, bool enableX, bool enableY, bool enableZ, bool absolute, bool detectFreefall, bool autoReset)
{
StopContinuousMeasurements();
OperatingMode = Mode.LevelDetection;
MeasurementRange = Range.EightG;
autoResetThresholdDetection = autoReset;
byte b = 0x00;
b |= (byte) ((enableX ? 0 : 1)<< 3);
b |= (byte) ((enableY ? 0 : 1)<< 4);
b |= (byte) ((enableZ ? 0 : 1)<< 5);
b |= (byte)((absolute ? 0 : 1) << 6);
Write(Register.CTL1, b);
b = 0x00;
b |= (byte)((detectFreefall ? 1 : 0));
Write(Register.CTL2, b);
if (absolute)
{
int thresholdValue = System.Math.Abs((int) ((threshold / 8.0) * 128.0));
Write(Register.LDTH, (byte)(thresholdValue & 0x7F));
}
else
{
byte thresholdValue = (byte)((threshold / 8.0) * 128.0);
Write(Register.LDTH, (byte)(thresholdValue));
}
// Clear the interrupts
ResetThresholdDetection();
}
/// <summary>
/// Reset the threshold detection process, configured by the <see cref="EnableThresholdDetection"/> method.
/// </summary>
public void ResetThresholdDetection()
{
// Clear the interrupts
Write(Register.INTRST, 0x03);
Write(Register.INTRST, 0x00);
}
void int1_Interrupt(GTI.InterruptInput sender, bool value)
{
if (OperatingMode == Mode.LevelDetection)
{
OnThresholdExceededEvent(this);
if (autoResetThresholdDetection)
{
ResetThresholdDetection();
}
}
}
/// <summary>
/// Starts continuous measurements.
/// </summary>
/// <remarks>
/// When this method is called, <see cref="Accelerometer"/> begins taking continuous measurements.
/// At each <see cref="ContinuousMeasurementInterval"/>, it calls the <see cref="RequestMeasurement"/> method,
/// which raises the <see cref="MeasurementComplete"/> event.
/// </remarks>
public void StartContinuousMeasurements()
{
this.OperatingMode = Mode.Measurement;
continuousMeasurement = true;
continuousTimer.Start();
}
/// <summary>
/// Stops continuous measurements.
/// </summary>
public void StopContinuousMeasurements()
{
continuousMeasurement = false;
continuousTimer.Stop();
}
/// <summary>
/// Represents the delegate used for the <see cref="MeasurementComplete"/> event.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="acceleration">The <see cref="Acceleration"/> object that contains the results of the reading.</param>
public delegate void MeasurementCompleteEventHandler(Accelerometer sender, Acceleration acceleration);
/// <summary>
/// Event raised when a measurement reading is completed.
/// </summary>
public event MeasurementCompleteEventHandler MeasurementComplete;
private MeasurementCompleteEventHandler _OnMeasurementComplete;
/// <summary>
/// Raises the <see cref="MeasurementComplete"/> event.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="acceleration">The <see cref="Acceleration"/> object that contains the results of the reading.</param>
protected virtual void OnMeasurementCompleteEvent(Accelerometer sender, Acceleration acceleration)
{
if (_OnMeasurementComplete == null) _OnMeasurementComplete = new MeasurementCompleteEventHandler(OnMeasurementCompleteEvent);
if (Program.CheckAndInvoke(MeasurementComplete, _OnMeasurementComplete, sender, acceleration))
{
MeasurementComplete(sender, acceleration);
}
}
/// <summary>
/// Represents the delegate used for the <see cref="ThresholdExceeded"/> event.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
public delegate void ThresholdExceededEventHandler(Accelerometer sender);
/// <summary>
/// Event raised when an acceleration threshold is exceeded.
/// </summary>
public event ThresholdExceededEventHandler ThresholdExceeded;
private ThresholdExceededEventHandler _OnThresholdExceeded;
/// <summary>
/// Raises the <see cref="MeasurementComplete"/> event.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
protected virtual void OnThresholdExceededEvent(Accelerometer sender)
{
if (_OnThresholdExceeded == null) _OnThresholdExceeded = new ThresholdExceededEventHandler(OnThresholdExceededEvent);
if (Program.CheckAndInvoke(ThresholdExceeded, _OnThresholdExceeded, sender))
{
ThresholdExceeded(sender);
}
}
void continuousTimer_Tick(Timer timer)
{
if (!continuousMeasurement)
{
timer.Stop();
return;
}
RequestMeasurement();
}
private enum Register : byte
{
// From MMA7455L Datasheet, pg. 21.
// Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
// ---------------------------------------------------------------------
XOUTL = 0x00, // 10 bits output value X LSB XOUT[7] XOUT[6] XOUT[5] XOUT[4] XOUT[3] XOUT[2] XOUT[1] XOUT[0]
XOUTH = 0x01, // 10 bits output value X MSB XOUT[9] XOUT[8]
YOUTL = 0x02, // 10 bits output value Y LSB YOUT[7] YOUT[6] YOUT[5] YOUT[4] YOUT[3] YOUT[2] YOUT[1] YOUT[0]
YOUTH = 0x03, // 10 bits output value Y MSB YOUT[9] YOUT[8]
ZOUTL = 0x04, // 10 bits output value Z LSB ZOUT[7] ZOUT[6] ZOUT[5] ZOUT[4] ZOUT[3] ZOUT[2] ZOUT[1] ZOUT[0]
ZOUTH = 0x05, // 10 bits output value Z MSB ZOUT[9] ZOUT[8]
XOUT8 = 0x06, // 8 bits output value X XOUT[7] XOUT[6] XOUT[5] XOUT[4] XOUT[3] XOUT[2] XOUT[1] XOUT[0]
YOUT8 = 0x07, // 8 bits output value Y YOUT[7] YOUT[6] YOUT[5] YOUT[4] YOUT[3] YOUT[2] YOUT[1] YOUT[0]
ZOUT8 = 0x08, // 8 bits output value Z ZOUT[7] ZOUT[6] ZOUT[5] ZOUT[4] ZOUT[3] ZOUT[2] ZOUT[1] ZOUT[0]
STATUS = 0x09, // Status registers PERR DOVR DRDY
DETSRC = 0x0A, // Detection source registers LDX LDY LDZ PDX PDY PDZ INT2 INT1
TOUT = 0x0B, // Temperature output value (Optional) TMP[7] TMP[6] TMP[5] TMP[4] TMP[3] TMP[2] TMP[1] TMP[0]
I2CAD = 0x0D, // I2C device address I2CDIS DAD[6] DAD[5] DAD[4] DAD[3] DAD[2] DAD[1] DAD[0]
USRINF = 0x0E, // User information (Optional) UI[7] UI[6] UI[5] UI[4] UI[3] UI[2] UI[1] UI[0]
WHOAMI = 0x0F, // "Who am I" value (Optional) ID[7] ID[6] ID[5] ID[4] ID[3] ID[2] ID[1] ID[0]
XOFFL = 0x10, // Offset drift X value (LSB) XOFF[7] XOFF[6] XOFF[5] XOFF[4] XOFF[3] XOFF[2] XOFF[1] XOFF[0]
XOFFH = 0x11, // Offset drift X value (MSB) XOFF[10] XOFF[9] XOFF[8]
YOFFL = 0x12, // Offset drift Y value (LSB) YOFF[7] YOFF[6] YOFF[5] YOFF[4] YOFF[3] YOFF[2] YOFF[1] YOFF[0]
YOFFH = 0x13, // Offset drift Y value (MSB) YOFF[10] YOFF[9] YOFF[8]
ZOFFL = 0x14, // Offset drift Z value (LSB) ZOFF[7] ZOFF[6] ZOFF[5] ZOFF[4] ZOFF[3] ZOFF[2] ZOFF[1] ZOFF[0]
ZOFFH = 0x15, // Offset drift Z value (MSB) ZOFF[10] ZOFF[9] ZOFF[8]
MCTL = 0x16, // Mode control DRPD SPI3W STON GLVL[1] GLVL[0] MOD[1] MOD[0]
INTRST = 0x17, // Interrupt latch reset CLRINT2 CLRINT1
CTL1 = 0x18, // Control 1 DFBW THOPT ZDA YDA XDA INTRG[1] INTRG[0] INTPIN
CTL2 = 0x19, // Control 2 DRVO PDPL LDPL
LDTH = 0x1A, // Level detection threshold limit value LDTH[7] LDTH[6] LDTH[5] LDTH[4] LDTH[3] LDTH[2] LDTH[1] LDTH[0]
PDTH = 0x1B, // Pulse detection threshold limit value PDTH[7] PDTH[6] PDTH[5] PDTH[4] PDTH[3] PDTH[2] PDTH[1] PDTH[0]
PW = 0x1C, // Pulse duration value PD[7] PD[6] PD[5] PD[4] PD[3] PD[2] PD[1] PD[0]
LT = 0x1D, // Latency time value LT[7] LT[6] LT[5] LT[4] LT[3] LT[2] LT[1] LT[0]
TW = 0x1E // Time window for 2nd pulse value TW[7] TW[6] TW[5] TW[4] TW[3] TW[2] TW[1] TW[0]
}
private byte[] _readBuffer8 = new byte[1];
private byte[] _writeBuffer8 = new byte[1];
private byte[] _writeBuffer16 = new byte[2];
private byte[] _readBuffer24 = new byte[3];
private byte[] _readBuffer48 = new byte[6];
private byte ReadByte(Register register)
{
_writeBuffer8[0] = (byte)register;
i2c.WriteRead(_writeBuffer8, _readBuffer8, 1000);
return _readBuffer8[0];
}
private void Read(Register register, byte[] readBuffer)
{
_writeBuffer8[0] = (byte)register;
i2c.WriteRead(_writeBuffer8, readBuffer, 1000);
}
private void Write(Register register, byte value)
{
_writeBuffer16[0] = (byte)register;
_writeBuffer16[1] = (byte)value;
i2c.Write(_writeBuffer16, 1000);
}
}
}