Option #2 is from this thread and it does indeed give 20K encoder counts with the ICR1 value = 199 and a prescaler of 8 such that each timer tick is .5us. The fundamental timer repeat is at 10KHz and there are two quadrature edges per cycle.
//Quadrature signal generator two outputs offset 90 degrees
//emulate rotary encoder
//Timer 1 CTC with ICR1 TOP
//Switch direction with Serial input F/R/S Enter Capital F S or R with not line ending
//Pin Change Interrupts on Timer Output Pins
const char encTable[16] = {0, 1, -1, 0, -1, 0, -0, 1, 1, 0, 0, -1, 0, -1, 1, 0}; //gives -1, 0 or 1 depending on encoder movement
volatile long encoderCount;
volatile long errorCount;
volatile byte encState;
unsigned long prevDisplay;
unsigned long interval = 1000;
char Command = 'F'; //default state is Forward
void setup() {
Serial.begin(115200);
pinMode(9, OUTPUT); //output A
pinMode(10, OUTPUT); //output B
//Enable pin change interrupts on pins 9 and 10 PB 2 and 3
PCICR |= (1 << PCIE0); //enable group interrupts on PORTB PCINT[7:0]
PCMSK0 |= (1 << PCINT2); //enable interrupt pin 10
PCMSK0 |= (1 << PCINT1); //enable interrupt pin 9
TCCR1A = 0; //clear timer registers
TCCR1B = 0;
TCNT1 = 0;
GTCCR |= 1 << PSRASY; //reset prescaler
//ICR1 and Prescaler sets frequency
//no prescaler .0625 us per count @ 16mhz
//prescaler 8 .5 us per count
TCCR1B |= _BV(CS11); // prescaler 8
//TCCR1B |= _BV(CS10); //no prescaler
//counts are zero indexed 2edges per ICR1 period
//numerical values for prescaler 8.
//e.g. 10k period give 20k encoder counts
ICR1 = 199;//10k ICR1 period 20k encoder counts
//ICR1 = 99; //20k ICR1 period 40k encoder counts
//ICR1 = 49; //40K ICR1 period 80k encoder counts
//ICR1 = 46; //42.5K ICR1 period 85k encoder counts
//ICR1 = 41; //47.5k ICR1 period 95K encoder counts
//ICR1 = 39; //50k ICR1 period 100k encoder counts
//ICR1 = 29; //66.6K ICR1 period 133k encoder counts
//ICR1 = 19; //100k ICR1 period 200k encoder counts
//ICR1 = 17;
//ICR1 = 14;
//ICR1 = 9;
OCR1A = ICR1 - 1; //two different pulse widths almost 100% duty cycle
OCR1B = OCR1A / 2; //offset by half period
TCCR1B |= _BV(WGM13) | _BV(WGM12); //CTC mode with ICR1
TCCR1A = _BV(COM1A0) | _BV(COM1B0); //Toggle OC1A/OC1B on compare match
}
void loop () {
readCommand();
if (Command == 'F')
{
OCR1A = ICR1 - 1; //two different pulse widths almost 100% duty cycle
OCR1B = OCR1A / 2; //offset by half period
TCCR1B |= _BV(CS11);//start timer
}
if (Command == 'R')
{
OCR1B = ICR1 - 1; //two different pulse widths almost 100% duty cycle
OCR1A = OCR1B / 2; //offset by half period
TCCR1B |= _BV(CS11);//start timer
}
if (Command == 'S')
{
TCCR1B &= ~(_BV(CS11));//stop timer
}
if (millis() - prevDisplay >= interval)
{
prevDisplay += interval;
noInterrupts();
long copyEncoderCount = encoderCount;
encoderCount = 0;
long copyErrorCount = errorCount;
errorCount = 0;
interrupts();
Serial.print(copyEncoderCount);
Serial.print('\t');
Serial.println(copyErrorCount);
}
}
ISR (PCINT0_vect)
{
encState = ((encState << 2) | ((PINB >> 1) & 3)) & 15; //use encoder bits and last state to form index
encoderCount += encTable[encState];//update actual position on encoder movement
if (encTable[encState] == 0)
errorCount++;
}
void readCommand() {
if (Serial.available() > 0)
{
Command = Serial.read();
Serial.println(Command);
}
}
However, it’s receiving 5K Hz on the multimeter and 100Khz on proteus. On the nano, I’m only getting 10k and not 20K. I’m not sure why. I’m not sure why all the differences.
This is strange. What do you see for Serial output?
Could your nano possible be running at 8MHz?