Well, I was looking for advice on a project, not programming (hence this is in the project guidance section, not the programming section). Any chance someone can answer the questions about the interrupt behavior of SoftSerial vs. Serial and using the hardware counters instead of a software interrupt?
But...
#include <TimerOne.h>
#include <SoftwareSerial.h>
#include <string.h>
// Values that control display
#define BLUE_SPEED 8 // Minimum speed for blue display
#define RED_SPEED 21 // Minimum speed for red dispaly
/*
* Values that control recording. Note that DELAY_SECONDS and
* DELAY_SECONDS * TREND_BUCKETS must both go evenly into RECORD_TIME.
*/
#define RECORD_TIME 300 // Length of the recording
#define DELAY_SECONDS 1 // Sample time length. Max of 8.
#define TREND_BUCKETS 3 // # of buckets to use for trend checking.
// Physical constants
#define SENSOR_INT 1 // Meaning pin #3
#define SERIAL_OUT 2 // Serial line to the display
#define LINE_LENGTH 16 // Length of output line on LCD
// Display (TREND_* maps to first custom char for that trend).
#define TREND_UNKNOWN 0
#define TREND_DOWN 2
#define TREND_EVEN 4
#define TREND_UP 6
// 1 PULSE/SEC = 2.5 MPH
#define PULSES_TO_SPEED(count) (((count) * 5) / (DELAY_SECONDS * 2))
// The wind sensor interrupt data
volatile static uint16_t sensor_count = 0 ;
// And handler
static void
sensor_tick() {
sensor_count += 1 ;
}
// The recording instrument data
#define SPEED_LENGTH (RECORD_TIME / DELAY_SECONDS)
// Length of trend buckets in the record
#define BUCKET_LENGTH (SPEED_LENGTH / TREND_BUCKETS)
volatile static uint8_t current_speed ;
volatile static uint8_t speeds[SPEED_LENGTH] ;
volatile static uint16_t next_speed = 0 ;
volatile static uint8_t wrapped = 0 ;
void
recorder_tick() {
uint16_t raw ;
raw = sensor_count ; // Warning - could lose a tick here...
sensor_count = 0 ;
current_speed = PULSES_TO_SPEED(raw) ;
speeds[next_speed++] = current_speed ;
if (next_speed >= SPEED_LENGTH) {
wrapped = 1 ;
next_speed = 0 ;
}
}
// Select a color with a very clever plan
static uint8_t
color_of(uint8_t speed) {
if (speed >= RED_SPEED) return 0 ;
if (speed >= BLUE_SPEED) return 2 ;
return 1 ;
}
SoftwareSerial lcd = SoftwareSerial(0, SERIAL_OUT) ;
void
do_command(SoftwareSerial lcd, uint8_t len, const char *data) {
lcd.write(0xFE) ;
while (len--)
lcd.write(*data++) ;
delay(10) ;
}
void
setup() {
#ifdef MAKE_CHARS
char chars[][11] = {
{0xC1, 1, 0, B01001, B00101, B00011, B11111, B11111, B00011, B00101, B01001},
{0xC1, 1, 1, B10010, B10100, B11000, B11111, B11111, B11000, B10100, B10010},
{0xC1, 1, 2, 4, 2, 1, 0, 0, 0, 0, 0},
{0xC1, 1, 3, 0, 0, 0, B10001, B01001, B00101, B00011, B11111},
{0xC1, 1, 4, 0, 0, 0, B11111, B11111, 0, 0, 0},
{0xC1, 1, 5, B01000, B00100, B00010, B11111, B11111, B00010, B00100, B01000},
{0xC1, 1, 6, 0, 0, 0, 0, 0, 1, 2, 4},
{0xC1, 1, 7, B11111, B00011, B00101, B01001, B10001, 0, 0, 0},
} ;
#endif
pinMode(3, INPUT_PULLUP) ;
attachInterrupt(SENSOR_INT, sensor_tick, RISING) ;
Timer1.initialize(1000000 * DELAY_SECONDS) ;
Timer1.attachInterrupt(recorder_tick) ;
lcd.begin(57600) ;
delay(10) ;
#ifdef MAKE_CHARS
do_command(lcd, 33, "\x40 Meyer Heliport Wind Conditions ") ;
for (uint8_t i = 0; i < 8; i += 1)
do_command(lcd, 11, chars[i]) ;
#endif
do_command(lcd, 1, "\x4B") ; // Turn off underline cursor
do_command(lcd, 1, "\x54") ; // blinking cursor
do_command(lcd, 1, "\x52") ; // and autoscroll
do_command(lcd, 2, "\xC0\01") ; // Get arrows
}
void
loop() {
int8_t trend ;
int16_t end, start ;
uint16_t i, now, cur, avg, max, bucket_counter, bucket_count ;
uint32_t sum, bucket_sum ;
int32_t buckets[TREND_BUCKETS] ;
char bhold[LINE_LENGTH + 1], colors[4] = {0xD0} ;
end = next_speed ;
start = wrapped ? end : 0 ;
bucket_count = 0 ;
trend = TREND_UNKNOWN ;
if (!wrapped && end == 0) { // Haven't gotten a sample yet.
avg = max = cur = current_speed ;
} else { // Do some stats...
cur = current_speed ;
i = start ;
bucket_sum = bucket_counter = max = sum = 0 ;
do {
now = speeds[i] ;
sum += now ;
if (now > max)
max = now ;
bucket_sum += now ;
bucket_counter += 1 ;
if (bucket_counter == BUCKET_LENGTH) {
buckets[bucket_count++] = bucket_sum ;
bucket_counter = 0 ;
bucket_sum = 0 ;
}
i += 1 ;
if (i == SPEED_LENGTH)
i = 0 ;
} while (i != end) ;
avg = sum / (wrapped ? SPEED_LENGTH : end) ;
if (bucket_count == TREND_BUCKETS) {
for (i = 0; i < TREND_BUCKETS - 1; i += 1) {
if (buckets[i] == buckets[i + 1]) {
trend = TREND_EVEN ;
break ;
} else if (buckets[i] < buckets[i + 1]) {
if (trend == TREND_UNKNOWN)
trend = TREND_UP ;
else if (trend == TREND_DOWN) {
trend = TREND_UNKNOWN ;
break ;
}
} else if (buckets[i] > buckets[i + 1]) {
if (trend == TREND_UNKNOWN)
trend = TREND_DOWN ;
else if (trend == TREND_UP) {
trend = TREND_UNKNOWN ;
break ;
} else if (trend == TREND_UNKNOWN) {
trend = TREND_EVEN ;
}
}
}
}
}
// Now, display the data
do_command(lcd, 1, "\x58") ; // clear screen
do_command(lcd, 1, "\x48") ; // go home
// Pick a color...
memset(colors + 1, 0, 3) ;
colors[color_of(avg) + 1] = 255 ;
colors[color_of(max) + 1] = 255 ;
do_command(lcd, 4, colors) ;
lcd.println("Cur Avg Max Tnd") ;
snprintf(bhold, LINE_LENGTH + 1, "%3d %3d %3d ", cur, avg, max) ;
lcd.print(bhold) ;
lcd.write(trend) ;
lcd.write(trend + 1) ;
delay(1000) ;
}