I have been working on the code for the handle based on the hall sensor and capacitance sensor working as they have to date. I am not sure that I know how to control the sensitivity of the capacitance sensor but I will deal with that later.
Based on several different code samples this is what I have come up. I am putting the handle to sleep after a period of time. The handle wakes up when pin 2 is shorted to ground with a ball switch (or something similar). At that point the handle is activated. If a the handle is being touched, the green light blinks quickly. If not, there is no blinking,
If the handle goes over the magnetic strip with the handle touched, the red LED blinks slowly. If the handle goes over the magnetic strip with the hand off of the handle, the green light go on solid.
Then the cycle repeats.
A couple of questions
-
Is the choice I made for sleep mode ok? Using pin 2 as a trigger to wake the handle? Is there a better way to maximize battery life?
-
In the loop function, how big should the delay function be?
doe this look ok?
// Curling handle Code
// Version 1: Aug 27, 2014
#include <avr/sleep.h>
#include "elapsedMillis.h"
#include "multiBlinkOrig.h" // type definitions
elapsedMillis AwakeTime; //declare global if you don't want it reset every time loop runs
//define constants used
const int WakePin = 2; //pin for cap sensor input (ball switch)
const int CapPin = 3; //pin for cap sensor input
const int grnLEDpin = 5; //pin for green LED output
const int redLEDpin = 6; //pin for red LED output
const int HallPin = A0; //pin for Hall sensor input
const int magThrsh = 100; //magnitude of Hall reading needed to trip red LED
//define variables used
int magOffset = 0; //offset from Hall sensor
int magReading = 0; //magnitude of raw Hall reading with offset removed
float magSum = 0; //sum used in computing offset
boolean handincontact = false;
boolean activated = false;
boolean hoglineviolation = false;
boolean successfulthrow = false;
// Blink Table T - Modify this table to suit whatever the output requirements are
// Add or delete lines as required to achieve the desired effects.
//
ledTable T[] =
//Pin St State 0 State 1 LastTime
{
{ grnLEDpin, 0, 0, {{HIGH, 200}, {LOW, 200}}, 0 },
{ redLEDpin, 0, 1, {{HIGH, 300}, {LOW, 600}}, 0 },
};
// Self adjusting constants for loop indexes
#define MAX_STATE (sizeof(T[0].state)/sizeof(stateDef))
#define MAX_LED (sizeof(T)/sizeof(ledTable))
void setup()
{
for (int i=0; i < MAX_LED; i++)
{
pinMode(T[i].ledPin, OUTPUT);
digitalWrite(T[i].ledPin, LOW);
T[i].active = false;
}
Serial.begin(9600);
SetupSleepMode();
pinMode(CapPin, INPUT_PULLUP);
pinMode(HallPin, INPUT_PULLUP);
delay(3000);
CalculateHallSensorOffset();
AwakeTime = 0;
}
void loop()
{
if(not hoglineviolation) {
ReadSensors();
if(handincontact) {
T[0].active = false;
T[0].state[0].activeTime = 200; // Reset green blink rate
T[0].state[0].activeTime = 200;
if(magReading > magThrsh) {
T[1].active = true;
hoglineviolation = true;
}
AwakeTime = 0; // Reset AwakeTime
} else {
T[0].active = true;
if(AwakeTime > 10000) { // Slow down green blink rate
T[0].state[0].activeTime = 50;
T[0].state[0].activeTime = 350;
}
}
for (int i=0; i < MAX_LED; i++)
{
if(T[i].active) {
// check if the state active time has expired (ie, it is less than current time)
if (millis() >= T[i].lastTransTime + T[i].state[T[i].currentState].activeTime)
{
// switch to the next state with wrapround
T[i].currentState = (T[i].currentState + 1) % MAX_STATE;
// write out the next state value
T[i].lastTransTime = millis();
digitalWrite(T[i].ledPin, T[i].state[T[i].currentState].activeVal);
}
}
}
if((AwakeTime > 20000) || ((AwakeTime > 10000) && (hoglineviolation))) {
SleepNow();
AwakeTime = 0;
T[0].state[0].activeTime = 200;
T[0].state[1].activeTime = 200;
T[0].active = false;
T[1].active = false;
hoglineviolation = false;
}
}
delay(50);
}
void ReadSensors()
{
handincontact = digitalRead(CapPin);
magReading = analogRead(HallPin);
magReading = abs(magReading - magOffset);
// Serial.print(magReading);
// Serial.print(",");
// Serial.println(ishandletouched);
}
void SetupSleepMode()
{
pinMode(WakePin, INPUT);
Serial.begin(9600);
/* Now it is time to enable an interrupt. In the function call
* attachInterrupt(A, B, C)
* A can be either 0 or 1 for interrupts on pin 2 or 3.
*
* B Name of a function you want to execute while in interrupt A.
*
* C Trigger mode of the interrupt pin. can be:
* LOW a low level trigger
* CHANGE a change in level trigger
* RISING a rising edge of a level trigger
* FALLING a falling edge of a level trigger
*
* In all but the IDLE sleep modes only LOW can be used.
*/
attachInterrupt(0, wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
// wakeUpNow when pin 2 gets LOW
}
void wakeUpNow() // here the interrupt is handled after wakeup
{
// execute code here after wake-up before returning to the loop() function
// timers and code using timers (serial.print and more...) will not work here.
// we don't really need to execute any special functions here, since we
// just want the thing to wake up
}
void SleepNow() // here we put the arduino to sleep
{
/* Now is the time to set the sleep mode. In the Atmega8 datasheet
* http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf on page 35
* there is a list of sleep modes which explains which clocks and
* wake up sources are available in which sleep mode.
*
* In the avr/sleep.h file, the call names of these sleep modes are to be found:
*
* The 5 different modes are:
* SLEEP_MODE_IDLE -the least power savings
* SLEEP_MODE_ADC
* SLEEP_MODE_PWR_SAVE
* SLEEP_MODE_STANDBY
* SLEEP_MODE_PWR_DOWN -the most power savings
*
* For now, we want as much power savings as possible, so we
* choose the according
* sleep mode: SLEEP_MODE_PWR_DOWN
*
*/
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable(); // enables the sleep bit in the mcucr register
// so sleep is possible. just a safety pin
/* Now it is time to enable an interrupt. We do it here so an
* accidentally pushed interrupt button doesn't interrupt
* our running program. if you want to be able to run
* interrupt code besides the sleep function, place it in
* setup() for example.
*
* In the function call attachInterrupt(A, B, C)
* A can be either 0 or 1 for interrupts on pin 2 or 3.
*
* B Name of a function you want to execute at interrupt for A.
*
* C Trigger mode of the interrupt pin. can be:
* LOW a low level triggers
* CHANGE a change in level triggers
* RISING a rising edge of a level triggers
* FALLING a falling edge of a level triggers
*
* In all but the IDLE sleep modes only LOW can be used.
*/
attachInterrupt(0,wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
// wakeUpNow when pin 2 gets LOW
sleep_mode(); // here the device is actually put to sleep!!
// THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
sleep_disable(); // first thing after waking from sleep:
// disable sleep...
detachInterrupt(0); // disables interrupt 0 on pin 2 so the
// wakeUpNow code will not be executed
// during normal running time.
}
void CalculateHallSensorOffset()
{
int count = 50;
//send a recalibration message
//Serial.println("Place the sensor down flat, going to perform offset calibration");
// wait 3 secs
delay(3000);
//Serial.println("Performing offset calibration");
//take "count" A/D readings spaced 1 msec apart
for(int i = 0; i < count; i++){
magSum += analogRead(HallPin);
delay(1);
}
//now compute average
magOffset = int(magSum/count);
//Serial.print("Done. Offset is ");
//Serial.println(magOffset);
}