Arduino example for the FGM-3h magnetometer
Archive: The magnetometer is offline and we are no longer collecting data.
Getting started
This simple Arduino Mega example counts the pulses from the FGM-3h using an external counter and sends the result to the serial port. An interrupt counts timer overflows during the approximately five-second sample. First, the includes, constants and declarations:
#include "avr\io.h"
#define SAMPLE_DELAY 5 // number of seconds between samples
#define SAMPLE_DURATION 5 // number of seconds to sample for.
volatile int mult=0;
static uint32_t timer=0;
float GetData();
Setup
The setup function starts the serial port:
void setup()
{
Serial.begin(57600);
delay(1000);
Serial.println("Hello world");
}
Loop
The loop takes a reading roughly every five seconds and sends it to the serial port:
void loop()
{
if (millis() > timer) {
timer = millis() + (SAMPLE_DELAY*1000); //only run every 5 seconds or whatever
float FGMreading;
FGMreading = GetData();
Serial.print("FGM Reading. Period = ");
Serial.print(FGMreading,5);
Serial.println(" microseconds");
}
}
Timer overflow interrupt
The FGM square-wave output is connected to pin 47 on the Mega, which is connected to the counter for timer 5. The interrupt increments the overflow count:
ISR(TIMER5_COMPA_vect) {
//Interrrupt service routine for clock counter - each time it reaches 65k, reset and increase mult
//mult*65k is then added to the count at the end in GetData()
if (TIFR5 & 1) { // if Timer/Counter 1 overflow flag
mult++; // count number of Counter1 overflows
TIFR5 =(1<<TOV5); // clear Timer/Counter 1 overflow flag
}
}
Counting and calculating the period
GetData resets the counter, counts pulses during the sample and combines the timer count with the number of overflows. The calculation then converts the frequency to a period in microseconds. The original page presented this as an excerpt without the GetData function declaration:
unsigned long count;
unsigned long Frequency;
mult=0;
TCCR5A=0; // reset timer/counter control register A
TIMSK5 |=(1<<OCIE5A); //enable interrupt service routine
//start counting
bitSet(TCCR5B ,CS12); // Counter Clock source is external pin 47 of mega 2560
bitSet(TCCR5B ,CS11); // Clock on rising edge
delay(SAMPLE_DURATION*1000); //wait for sample duration and count the clicks
//stop counting
TCCR5B = 0;
count = TCNT5;
TCNT5 = 0;
count+=0x10000 * mult; // the counter is 16 bit, so total count is count + mult*65k
Frequency = count/SAMPLE_DURATION; //frequency in Hz
unsigned long long oneSecond = 1000;
oneSecond*=1000;
oneSecond*=1000;
oneSecond*=100;
unsigned long long Period;
Period = oneSecond / (unsigned long long) Frequency;
float usPeriod;
usPeriod = float (Period) / 100000;
return usPeriod;
}
Possible improvements
- Use a more stable timing source, such as the pulse-per-second output from a GPS.
- Use an Ethernet shield to send data to a website.
- Send the pulse count itself and convert it to a period elsewhere.
- Enable the watchdog timer to reset the Arduino if it gets stuck.