// Capacitive rotary encoder // v0.02 8 Jan 2012 C. Harrison // (c) 2012 C. Harrison // distributed under Creative Commons CC-BY-SA-compatible Open Source Ecology (OSE) License // resources required: // 1 16-bit timer/counter 1 // a full output port, of which we use 4 pins for output // (other pins of port may be used for input, but we are greedy in order to get fast interrupt service) // 1 analog comparator input pin #define Mega // using timer 1 for encoder #define TIMERe 1 #define TCCReA TCCR1A #define TCCReA_init 0 // CTC mode #define TCCReB TCCR1B #define TCCReB_init ( (1< 200 cts/cycle => 50 cts/quad step #define CarrierPeriodNominal 42 // prototype resonance ~ 11.6kHz // Working variables static volatile unsigned char drivePhase; const unsigned char PhaseData[4] = {0b1100<= carrierPeriod) { capturedPhase++; } if(capturedPhase&2) { capturedSubPhase += 2*carrierPeriod; } TIFRe = (1<C // where is a decimal number and C is a single-letter command code // check if data has been sent from the computer: if (Serial.available()) { // read the most recent byte (which will be a decimal digit or command letter): incomingByte = Serial.read(); Serial.write(incomingByte); //echo if (incomingByte >= '0' && incomingByte <= '9') { if (entryComplete) { value = 0; negValue = false; entryComplete = false; } value = value * 10 + (incomingByte - '0')*(negValue ? -1 : 1); } else entryComplete = true; if (incomingByte == '-') { value = 0; negValue = true; entryComplete = false; } if (incomingByte == 'P' || incomingByte == 'p') { // set new period carrierPeriod = value; //while(TCNTe > (value>>1)) { }; // avoid rogue long pulse (not tested) OCReA = 2*(unsigned int)carrierPeriod-1; OCReB = carrierPeriod-1; } if (incomingByte == 'R' || incomingByte == 'r') { // set reporting period reportInterval = value; } if (incomingByte == 'Q' || incomingByte == 'q') { // query status Serial.print(encoderCycles); Serial.print("+"); Serial.print(subPhase); Serial.print(" = "); Serial.println((float)subPhase/(4.0*carrierPeriod)+encoderCycles); } } // endif serial available // update encoder reading { int prevSubPhase = subPhase; // avoid possible race with latest capture unsigned char quad; do { quad = capturedPhase; subPhase = capturedSubPhase; } while (quad != capturedPhase); // accumulate cycle counter if subPhase rolled over int diff = subPhase - prevSubPhase; if (diff > 3*carrierPeriod) { encoderCycles--; } else if (diff < -3*carrierPeriod) { encoderCycles++; } } if(millis() > when && reportInterval > 100) { when = millis() + reportInterval; Serial.print(encoderCycles); Serial.print("+"); Serial.print(subPhase); Serial.print(" = "); Serial.println((float)subPhase/(4.0*carrierPeriod)+encoderCycles); } }