0

I am trying output a clock and change its frequency dynamically with a rotary encoder.

When the code for the rotary encoder is included the clock doesn't reach its max freq(31Khz). But without the rotary encoder code, it does. What is happening that it can't reach its max freq?

const byte CLOCKOUT = 9;
int val;
int encoder0PinA = 3;
int encoder0PinB = 4;
int encoder0Pos = 0;
int encoder0PinALast = LOW;
int n = LOW;

void setup() {
  pinMode (CLOCKOUT, OUTPUT); 
  // set up Timer 1
  TCCR1A = bit (COM1A0);  // toggle OC1A on Compare Match
  TCCR1B = bit (WGM12) | bit (CS12);   // CTC, no prescaling
  OCR1A =  0;

  pinMode (encoder0PinA, INPUT);
  pinMode (encoder0PinB, INPUT);
  Serial.begin (9600);
}

void loop() {
  n = digitalRead(encoder0PinA);
  if ((encoder0PinALast == LOW) && (n == HIGH)) {
    if (digitalRead(encoder0PinB) == LOW) {
      OCR1A-=100;
    } else {
      OCR1A+=100;
    }
    Serial.print (OCR1A);
    Serial.print ("/");
  }
  encoder0PinALast = n;
}

The Code that reaches the Max freq properly is below

void setup ()
  {
  pinMode (CLOCKOUT, OUTPUT); 
  // set up Timer 1
  TCCR1A = bit (COM1A0);  // toggle OC1A on Compare Match
  TCCR1B = bit (WGM12) | bit (CS12);   // CTC, no prescaling
  OCR1A =  0;
  }

void loop (){
  }
3
  • 2
    you exclude a lot of values if you increment by 100 .... please post the code that reaches max freq – jsotola May 27 '19 at 2:19
  • Note that when OCR1A-=100; makes TCNT1 lower than OCR1A you miss the compare match and have to wait a full second for the timer to overflow. Use waveform generation mode 15 instead of 4 (CTC) to avoid this. – Edgar Bonet May 27 '19 at 8:44
  • Okay, I updated with the code that reaches the full freq. I intend to skip a lot of values in the increment as I am not trying to get every single value. What does the changing to wave generation mode 15 do? – user2242960 May 27 '19 at 12:36
1

I'm not sure whether this is the real issue you have, but I spot an issue which can be the issue you have.

You wrote something like this:

if (pulseFromEncoder)
  if (direction1)
    OCR1A -= 100;
  else
    OCR1A += 100;

Now, the OCR1A is a unsigned 16 bit integer. A value of 100 corresponds to 1.6ms of delay on the timer (see comment from Edgar Bonet below). This is what happens when you rotate in direction 2:

        OCR1A  Time delay
Rotate:   300      4.8ms
Rotate:   200      3.2ms
Rotate:   100      1.6ms
Rotate:     0      0ms
Rotate: 65436   1047ms

See? The value rolls over and the time completely changes.

Now, maybe the issues are other (for instance changing the mode to 15 instead of 4 like EdgarBonet said (no idea on what this means, you should double check the differences on the atmega datasheet), but I strongly suggest you to fix this issue, for instance this way:

const uint16_t OCR1A_Min = 0
const uint16_t OCR1A_Max = 20000
const uint16_t OCR1A_Step = 100

...

if (pulseFromEncoder)
  if (direction1)
  {
    if (OCR1A > OCR1A_Min + OCR1A_Step)
      OCR1A -= OCR1A_Step;
    else
      OCR1A = OCR1A_Min;
  }
  else
  {
    if (OCR1A < OCR1A_Max - OCR1A_Step)
      OCR1A += OCR1A_Step;
    else
      OCR1A = OCR1A_Max;
  }

Sidenote: doesn't your encoder need debounce?

2
  • Re “let's assume the OCR1A is a unsigned 16 bit integer”: This is indeed the case. Re “Let's assume also that 100 corresponds to 1ms of delay”: It's actually 100 × 256 ÷ F_CPU = 1.6 ms. – Edgar Bonet May 27 '19 at 19:43
  • @EdgarBonet Thank you, I updated the answer with your confirmations and fixed the data. As a side note, I was pretty close even if I gave a totally random value ;) – frarugi87 May 28 '19 at 7:30
0

PWM doesn't vary frequency. It holds the frequency steady and varies the duty cycle of the output. (Percent of on-time to total time.) So unless fast Arduino PWM does something very unconventional, the answer to the question you asked is no.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.