Here is the latest version of the BoB code. I may have to split it in multiple postings. The only tricky part of this in my mind is the way I handle interrupts. I have them split into stubs which catch the interrupts and store them in a table, and routines which run periodically out of "Loop" which scan the table and handle the events. I do it this way so sloppy/slow coding doesn't make me miss interrupts without knowing. In principal I could take that stuff out once it's working but I never seem to.
//july 11 V8 cut out voltage display cuz it doesn't work!
//display speed in MPH for US trip
#include <LiquidCrystal.h>
LiquidCrystal lcd(10,13,9,12,15,11,16); //(rs,rw,enbl,d4,d5,d6,d7)
unsigned long lasttachint,lastwheelint; //time in millis of most recent tach and wheel interrupts
float insttachrpm=0, avgtachrpm=0, wheelrpm=0; //tach instantaneous and rolling average rpm, wheel rpms
float revratio; int currentgear=0; //updated by setgear routine
float roadspeed=0; //speed in kph
volatile int ilog=0;
int maxlog=31;
volatile boolean logoflo; //index to log table, max entry #, log overflow flag
volatile byte lflag[32];
volatile unsigned long lmillis[32]; //log of interrupts
int tachpin=2; //pedal sensor booster, drives interrupt 0;
int wheelpin=3; //wheel sensor, drives interrupt 1;
int neutralpin=5;
void setup() {
lcdbegin(); //initialize the lcd
clearlog(); //clear the interrupt table
attachInterrupt(0, tachmonitor, RISING); //interrupt from tachometer
digitalWrite(wheelpin,HIGH); //set pullup resistor for reed switch
attachInterrupt(1, wheelmonitor, RISING); //interrupt from reed switch wheel sensor
}
void loop(){
checklog(); //make sure log is ok before processing
processlog(); //process and dump the log file to the PC
chkneutral(); //test for neutral
chkstale(); //check to see if tach or speed readings are >3 seconds old (bike has stopped!)
updatedisplay();
delay(100); //wait a while
}
void chkstale(){
if ((millis()> (lastwheelint+3000)) && (wheelrpm>0)){
wheelrpm=0; roadspeed=0;
}
if ((millis()> (lasttachint+3000)) && (insttachrpm>0)){
insttachrpm=0; avgtachrpm=0;
}
}
void updatedisplay(){
lcd.clear();
pbc(currentgear); //display what gear we're in
lcd.setCursor(4,0); lcd.print(int((avgtachrpm+50)/100)*100); //tach
lcd.setCursor(4,1); lcd.print(int((roadspeed/1.6)+.5)); //speed in Mph
}
void chkneutral(){
if (inneutral()){
currentgear=10;
} //10 is code for neutral
else{ //need to see if we've come out of neutral with no other info
if (currentgear==10) {// if we used to be in neutral
currentgear=0; // 0 is "don't know"
}
}
}
boolean inneutral(){ //see is neutral light is on
int n=analogRead(neutralpin); //neutral light sensor is on analog pin 5 - usually <100 in neutral, >300 in gear.
if (n<150){
return(true);
}
else{
return(false);
}
}
void checklog(){ //make sure log hasn't overflowed
if (logoflo==true){
noInterrupts();
clearlog();
interrupts();
Serial.print("log overflowed at ");
Serial.println(millis());
}
}
void processlog(){
int dlog,i; //how many entries to copy and dump
unsigned long dmillis[32];
byte dflag[32]; //space for the log entries
noInterrupts(); //disable interrupts while we copy the log
dlog=ilog; //copy the count
if (dlog!=0) { //if there's anything to copy
for(int i=0; i<dlog;i++){
dmillis[i]=lmillis[i];
dflag[i]=lflag[i];
}
ilog=0; //reset the count
}
interrupts(); //reenable interrupts
if (dlog!=0){ //if there's anything to process
for (i=0;i<dlog;i++){
//Serial.print(i); Serial.print(dflag[i]); Serial.print(" "); Serial.print(dmillis[i]); Serial.print(" ");
if (dflag[i]=='W') {
processwheel(dmillis[i]);
}
else {
if (dflag[i]=='T') {
processtach(dmillis[i]);
}
}
//Serial.println(" ");
}
}
}
void processtach(unsigned long lmillis){ // input is interrupt time in millis
unsigned long tachtime; //elapsed time for 10 tach events
if (lasttachint!=0) { //skip calculation on first time in
tachtime=lmillis-lasttachint; //time for last 10 events
if (tachtime>0){ //just avoid divide by 0
insttachrpm=60000/(float)tachtime*10; //rpm based on time in ms for 10 tach pulses
avgtachrpm=(avgtachrpm*2+insttachrpm)/3; //rolling average rpm
//Serial.print(" tachtime="); Serial.print(tachtime); Serial.print(" inst tach rpm="); Serial.print(insttachrpm); Serial.print(" avg tach rpm="); Serial.print(avgtachrpm);
}
}
lasttachint=lmillis;
}
void tachmonitor(){
static int tachcount;
if (tachcount <9) { //bulking up tach interrupts by a factor of 10
tachcount++;
}
else { //every 10th tach pulse we spawn a log entry
if (ilog<=maxlog){
lflag[ilog]='T'; //pedal pass flag
lmillis[ilog]=millis();
ilog++;
}
else {
logoflo=true; //we've overrun the log table
}
tachcount=0;
}
}
void processwheel(unsigned long lmillis){ //input is time of interrupt from log
unsigned long wheeltime; //time for previous revolution
if (lastwheelint!=0){ //don't do calculations 1st time in
wheeltime=lmillis-lastwheelint; //track the exact rotation time
wheelrpm=60000/(float)wheeltime;
//Serial.print(" wheeltime="); Serial.print(wheeltime); Serial.print(" wheel rpm="); Serial.print(wheelrpm);
roadspeed=.123*wheelrpm; //condensed version of 2.05*60*wheelrpm/1000; where 205 is wheel circ. in metres
//Serial.print(" road speed kph="); Serial.print(roadspeed);
setgear(); //figure out what gear we're in
}
lastwheelint=lmillis;
}
void wheelmonitor(){
if (ilog<=maxlog){
lflag[ilog]='W'; //wheel pass flag
lmillis[ilog]=millis(); //record time
ilog++;
}
else {
logoflo=true;
}
}