The Digital Dowser took another step forward last night. Backstory here and then here. It seems that my Snootlab Memoire shield was somehow not friends with the old Arduino Diecimila I borrowed from Martin, so relying once more on the kindness of strangers it seems my duty to do as a wannabe hacker, I got in touch with Bruno Sinou, recently moved to Berlin from Paris who mentioned he had a few knocking about when we met each other at Martin’s last earthcode Berlin performance.
And so with a more modern Arduino on hand, I found that the shield performed as it should do with no hiccups or having to delve into alternative SDfat libraries (which are actually quite interesting, however, having many more examples than the SD library bundled with the current Arduino IDE).
What I’ve hacked together is the PS2 Mouse library and the AnalogLogger Example from the SdFat library. The wires from the PS/2 Mouse are connected to the Arduino pins thus:
Orange: 5V
Red: Gnd
Yellow (Clock): Digital 6
Black (Data): Digital 5
NB: The Snootlab Memoire shield has a handy LED-resistor combo hanging on digital pin 9 which I set to flash when data is being written to the card.
Here, for the curious, is the Arduino sketch (this will change when I get my head around this Arduino/C++ stuff)
// A hack of the following scripts:
// ps2_mouse in the examples folder of the ps2 library (https://www.arduino.cc/playground/ComponentLib/Ps2mouse)
// AnalogLogger in the SdFat library (https://code.google.com/p/beta-lib/downloads/detail?name=SdFatBeta20120825.zip&can=2&q=)
// The AnalogLogger uses RTClib from https://github.com/adafruit/RTClib
// Daniel Belasco Rogers Oct 2012
#include
#include // define FreeRam()
#include
#include
#include
#define CHIP_SELECT SS // SD chip select pin
#define LOG_INTERVAL 1000 // mills between entries
#define ECHO_TO_SERIAL 1 // echo data to serial port if nonzero
#define WAIT_TO_START 1 // Wait for serial input in setup()
// file system object
SdFat sd;
// text file for logging
ofstream logfile;
// Serial print stream
ArduinoOutStream cout(Serial);
// buffer to format data - makes it eaiser to echo to Serial
char buf[80];
// define the Real Time Clock object
RTC_DS1307 RTC;
// initialise the ps2 mouse
PS2Mouse mouse(6, 5);
int posx; // a variable to hold cumulative position for x
int posy; // a variable to hold cumulative position for y
// store error strings in flash to save RAM
#define error(s) sd.errorHalt_P(PSTR(s))
// call back for file timestamps
void dateTime(uint16_t* date, uint16_t* time) {
DateTime now = RTC.now();
// return date using FAT_DATE macro to format fields
*date = FAT_DATE(now.year(), now.month(), now.day());
// return time using FAT_TIME macro to format fields
*time = FAT_TIME(now.hour(), now.minute(), now.second());
}
//------------------------------------------------------------------------------
// format date/time
ostream& operator < < (ostream& os, DateTime& dt) {
os << dt.year() << '/' << int(dt.month()) << '/' << int(dt.day()) << ',';
os << int(dt.hour()) << ':' << setfill('0') << setw(2) << int(dt.minute());
os << ':' << setw(2) << int(dt.second()) << setfill(' ');
return os;
}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
// set up LED on logging shield
pinMode(9, OUTPUT);
// start mouse
mouse.init();
// pstr stores strings in flash to save RAM
cout << endl << pstr("FreeRam: ") << FreeRam() << endl;
#if WAIT_TO_START
cout << pstr("Type any character to start\n");
while (Serial.read() < 0) {}
#endif // WAIT_TO_START
// connect to RTC21
Wire.begin();
if (!RTC.begin()) error("RTC failed");
// set date time callback function
SdFile::dateTimeCallback(dateTime);
DateTime now = RTC.now();
cout << now << endl;
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
if (!sd.begin(CHIP_SELECT, SPI_HALF_SPEED)) sd.initErrorHalt();
// create a new file in root, the current working directory
char name[] = "LOGGER00.CSV";
for (uint8_t i = 0; i < 100; i++) {
name[6] = i/10 + '0';
name[7] = i%10 + '0';
if (sd.exists(name)) continue;
logfile.open(name);
break;
}
if (!logfile.is_open()) error("file.open");
cout << pstr("Logging to: ") << name << endl;
// format header in buffer
obufstream bout(buf, sizeof(buf));
bout << pstr("millis");
bout << pstr(",date,time");
bout << pstr(",mousex,mousey");
logfile << buf << endl;
#if ECHO_TO_SERIAL
cout << buf << endl;
#endif // ECHO_TO_SERIAL
}
//------------------------------------------------------------------------------
void loop() {
uint32_t m;
// wait for time to be a multiple of interval
do {
m = millis();
} while (m % LOG_INTERVAL);
// use buffer stream to format line
obufstream bout(buf, sizeof(buf));
// start with time in millis
bout << m;
DateTime now = RTC.now();
bout << ',' << now;
// get mouse data
MouseInfo mouseInfo;
mouse.getData(&mouseInfo);
// increment positions from x y
posx += int(mouseInfo.x);
posy += int(mouseInfo.y);
// push positions to buffer
bout << ',' << posx;
bout << ',' << posy;
bout << endl;
// log data and flush to SD - flash led
digitalWrite(9, HIGH);
logfile << buf << flush;
digitalWrite(9, LOW);
// check for error
if (!logfile) error("write data failed");
#if ECHO_TO_SERIAL
cout << buf;
#endif // ECHO_TO_SERIAL
// reset position if left mouse button clicked
if (mouseInfo.leftClick){
posx = posy = 0;
}
// don't log two points in the same millis
if (m == millis()) delay(1);
}
Now 'all' I have to do is design and build a way of attaching the black plastic encoder wheels to the dowsing rods - reliably, mind. No pressure.
I´m following this with interest. I´m very much looking forward to the first results.