*/
/**
- * Reads the ADC pin connected to the LiPoly battery. The connection is made
- * via a resistor divider where the battery voltage is 3x that read by the ADC.
- * Therefore, BattV = ADC / 4096 * 1.5 * 3.
+ * Reads the ADC pin connected to the Davis Instruments anemometer. The
+ * connection is made via a resistor divider. The voltage seen by the ADC
+ * is related to VREF, the maximum voltage presented to the ADC.
+ * 0V or VREF means North
+ * VREF*1/4 means East
+ * VREF*2/4 means South
+ * VREF*3/4 means West
+ *
+ * We assume a 12-bit ADC, so VREF reads as 4095 and 0V reads as 0.
*
* @author R. Steve McKown <rsmckown@gmail.com>
*/
-generic configuration BatteryAdcC() {
+generic configuration WindVaneAdcC() {
provides interface Read<uint16_t>;
provides interface ReadStream<uint16_t>;
components new AdcReadStreamClientC();
ReadStream = AdcReadStreamClientC;
- components BatteryAdcP;
- AdcReadClientC.AdcConfigure -> BatteryAdcP;
- AdcReadStreamClientC.AdcConfigure -> BatteryAdcP;
+ components WindVaneAdcP;
+ AdcReadClientC.AdcConfigure -> WindVaneAdcP;
+ AdcReadStreamClientC.AdcConfigure -> WindVaneAdcP;
components new AdcReadNowClientC();
Resource = AdcReadNowClientC;
ReadNow = AdcReadNowClientC;
- AdcReadNowClientC.AdcConfigure -> BatteryAdcP;
+ AdcReadNowClientC.AdcConfigure -> WindVaneAdcP;
}
*/
/**
- * Battery ADC reading.
+ * Reads the ADC pin connected to the Davis Instruments anemometer. The
+ * connection is made via a resistor divider. The voltage seen by the ADC
+ * is related to VREF, the maximum voltage presented to the ADC.
+ * 0V or VREF means North
+ * VREF*1/4 means East
+ * VREF*2/4 means South
+ * VREF*3/4 means West
+ *
+ * We assume a 12-bit ADC, so VREF reads as 4095 and 0V reads as 0.
*
* @author R. Steve McKown <rsmckown@gmail.com>
*/
#include "Msp430Adc12.h"
-module BatteryAdcP {
+module WindVaneAdcP {
provides interface AdcConfigure<const msp430adc12_channel_config_t*>;
}
implementation {
* jumping around. The external reference of 2.50V seems stable.
*/
const msp430adc12_channel_config_t config = {
- inch: INPUT_CHANNEL_A0,
+ inch: INPUT_CHANNEL_A0, // A2
#if 0 /* internal references unstable */
sref: REFERENCE_VREFplus_AVss,
ref2_5v: REFVOLT_LEVEL_1_5, /* REFVOLT_LEVEL_2_5, */
components SoftwareRtcC as RtcC;
WindVaneP.Second -> RtcC;
- components HalWindVaneC;
- WindVaneP.Vane -> HalWindVaneC.AsyncGet;
+ components new WindVaneAdcC();
+ WindVaneP.Vane -> WindVaneAdcC.Read;
}
provides interface ReadRef<wind_vane_t>;
uses {
interface Tick as Second;
- interface AsyncGet<uint8_t> as Vane;
+ interface Read<uint16_t> as Vane;
}
}
implementation {
-#define COMPASS_COUNT 32
+ enum {
+ /* Compass count should ideally be a power of 2, or at least even */
+ COMPASS_COUNT = 36,
+ ADC_PER_HEADING = (4096 + COMPASS_COUNT - 1) / COMPASS_COUNT,
+ ADC_OFFSET = (ADC_PER_HEADING + 1) / 2,
+ ADC_BITMASK = 0x0fff,
+ };
wind_vane_t* m_data;
/* compass[0] = North, 0 degrees,
/*** Method implementations ***/
+ task void startRead()
+ {
+ call Vane.read();
+ }
async event void Second.fired()
{
- const static uint8_t lookup[] = {
- 0x01, 0x03, 0x02, 0x06, 0x04, 0x0c, 0x08, 0x18,
- 0x10, 0x30, 0x20, 0x60, 0x40, 0xc0, 0x80, 0x81
- };
- uint8_t wind;
- uint8_t i = 0;
-
- wind = call Vane.get();
- for (i = 0; i < sizeof(lookup); i++) {
- if (lookup[i] == wind) {
- compass[i]++;
- return;
- }
+ post startRead();
+ }
+
+ event void Vane.readDone(error_t error, uint16_t value)
+ {
+ if (error == SUCCESS) {
+ /* Convert the adc value (0...4095) to a compass heading
+ * (0...COMPASS_COUNT - 1).
+ */
+ value = (value + ADC_OFFSET) / ADC_PER_HEADING;
+ while (value >= COMPASS_COUNT)
+ value -= COMPASS_COUNT;
+ compass[value]++;
}
}
/* m_data's left, avg and right fields are currently represented in
* compass positions. We must now convert those fields into units of
- * angular degrees.
+ * angular degrees. The order of calculations is to maximize precision
+ * using integer arithmetic. Note that using a 16-bit unsigned field
+ * for calculations, the largest value of COMPASS_COUNT is 37.
*/
- m_data->left = 1800U / COMPASS_COUNT * m_data->left / 10;
- m_data->right = 1800U / COMPASS_COUNT * m_data->right / 10;
+ m_data->left = 1800U * m_data->left / COMPASS_COUNT / 10;
+ m_data->right = 1800U * m_data->right / COMPASS_COUNT / 10;
}
m_data = 0;