/* This should read a Neptune Ecoder register being * polled hourly by an R900 radio. * Uses approach from Bob Prust's 11 bit ascii decoder. * Expects inverters on clock and data lines. * This one ran on the target Arduino. * Dumb logic error had this read data line on wrong * clock edge, requiring 200usec data settling delay. * That error has been reversed in this code, and the * delay commented out. Not tested, but should work. :) * Cleaned up 2/3/20 */ //#include #define spl Serial.println #define sp Serial.print #define sps Serial.print(" ") #define DATAPIN A0 #define CLOCKPIN 10 #define MAXCHARS 35 // yeah, globals :( unsigned long starttime,laststart,firststart; char charBuf[MAXCHARS]; int charNum=0; // which char of the35 int bitpos=0,wip=0; //current bit pos (0-10); work in progress word void setup() { // put your setup code here, to run once: Serial.begin(115200); Serial.println("hello - waiting..."); digitalWrite(DATAPIN,HIGH); //pullups digitalWrite(CLOCKPIN,HIGH); }// end setup() //========== MAIN LOOP ========== // This code assumes inverters on clock and data lines // After inverters: clock and data idle low; data changes after clock lo->hi edge void loop() { byte bitnum,val; char outputStr[10]; int i=0,j; starttime=millis(); laststart=starttime; firststart=starttime; spl("in loop()"); //---------- STARTUP --------- // Whole read loop is bounded by existence of clocks. HaveClocks is managed by // count of recent valid clock edges EdgeCnt. LastClk is time (millis) of last clock edge. // Each time an edge is found, LastClk is reset and EdgeCnt is incremented up to MAXEDGECNT. // If millis()-LastClk is ever greater than MAXCLK, we decrement EdgeCnt and reset LastClk. // When EdgeCnt goes to 0, we're done. // #define MAXEDGECNT 10 #define MAXCLK 1 bool clockState,oldCS,haveClocks=0; unsigned long LastClk=0; int edgeCnt=0,hours,minutes,seconds; oldCS=digitalRead(CLOCKPIN); while(1){ // check for no clocks if(millis()-LastClk > 20){ //clock half-cycle is < 1ms if(haveClocks && --edgeCnt==0)goto CLOCKDONE; //end of clocks detected //if(edgeCnt<0)edgeCnt=0; // should never happen? LastClk=millis(); }// if slow clock else{ // normal reading continues here clockState=digitalRead(CLOCKPIN); // note this is still inverted if(clockState!=oldCS){ //we have an edge! if(++edgeCnt>MAXEDGECNT){ edgeCnt=MAXEDGECNT; haveClocks=1; }//end if edgeCnt oldCS=clockState; LastClk=millis(); //admin stuff //if(clockState==1) readBit(); // all the work is done here if(clockState==0) readBit(); // this is the edge we should read on }//end if clockstate change }// end else normal reading continue; // to top of while(1) // END OF READ CYCLE PROCESSING HERE CLOCKDONE: //spl("in clockdone"); spl(""); charBuf[charNum]='\0'; //terminating null so we can print it // create usage string for(int i=7;i<13;i++)outputStr[i-7]=charBuf[i]; outputStr[6]=charBuf[27]; outputStr[7]='.'; outputStr[8]=charBuf[28]; outputStr[9]='\0'; // time since last poll starttime=millis(); sp(starttime-laststart);spl(" ms since last poll"); hms(starttime-firststart,&hours,&minutes,&seconds); laststart=starttime; sp(hours);sp(':');sp(minutes);sp(':');sp(seconds); spl(" since first started"); spl(charBuf); sp("Water usage: "); sp(outputStr);spl(" gal"); // reset for next round charNum=0; bitpos=0; wip=0; haveClocks=0; spl("clockdone done"); } //end main while(1) }//end loop //============================================== // half a bit time so we read in the middle #define HALFBIT 200 //======= MAIN READ AND PROCESS ONE BIT ========== // Should set global error flag if bad stop or bad parity // (but not bad start bit, which we just ignore) void readBit(){ bool mybit,parity,badstart,stopErr=0,parityErr=0; //delayMicroseconds(HALFBIT); // don't need delay if we read on correct edge! mybit=!digitalRead(DATAPIN); // uninvert // check for start bit; only go if start bit hi badstart=((bitpos==0) && (mybit==1)); // 'cuz the original code was really ugly if(!badstart){ bitWrite(wip,bitpos,mybit); if(bitpos==9 && mybit==0)stopErr=1; // bad stop bit if(stopErr)sp('+'); // done with 11 bit word? if(++bitpos >10){ bitpos=0; //parity=(wip&0x80)?1:0; // compute, check parity here charBuf[charNum]=(byte)((wip&0xff)>>1); // mask off start, parity, stops; shift right //sp(charNum);sps;sp(wip>>1,HEX);sps;sp((wip>>1)&0x7f,HEX);sps;spl(charBuf[charNum]); charNum++; wip=0; }//end if have 11 bits }// end if not bad start bit //else sp('-'); // means bad start bit (skipped - nonfatal) }//end readBit() //============================================= void hms(unsigned long ms,int *hraddr,int *minaddr,int *secaddr){ // convert milliseconds to hrs, mins, secs long v; //sp(ms);spl(" ms"); *hraddr=ms/3600000L; v=ms%3600000L; // v is still in ms *minaddr=v/60000L; *secaddr=(v%60000L)/1000; }//end hms