i was trying to make a frequency generator with arduino and a rotary encoder... was harder than i imagined...
but i´m using the encoder to count up or down the delay time the encoder got unresponsive at low frequencies so i had to take other way
i used a interrupt based library for the encoder so it connects to A2 and A3 analog inputs..
if it is going up it sums with the delay time according to a range determined by the encoder switch connected to D4 so if i press it it can sum or subtract 1 , 10 or 100 or for each encoder count.. the value of the delay range within is btw 1us and 16300 (thats the upper limit lowest freq)
because of the limited range the lowest freq that can be generated with delayMicrosecond function is 30Hz but using normal delay it can be much lower perhaps 0,03hz
the highest is 254khz
freq adjust
at 100hz the smallest increase step is 0,02hz // dutycycle49,9%
at 1khz the smallest increase step is 2<>2hz // dutycycle 49,8%
at 10khz the smallest increase step is 185<>200hz // dutycycle 48,6%
at 100khz the smallest increase step is 17kz<>26kz // dutycycle 36,5%
at 254khz the smallest decrease step is 86kz< // dutycycle 15,8%
the frequency is stable with cristal precision! <1%
there is a lower frequency noise on the voltage level of the output pulses but it can be reduced adding more capacitors to the arduino voltage line i guess it could increase the frequency stability even further
the code:
// -----
// InterruptRotator.ino - Example for the RotaryEncoder library.
// This class is implemented for use with the Arduino environment.
// -----because of the limited range the lowest freq that can be generated with delayMicrosecond function is 30Hz but using normal delay it can be much lower perhaps 0,03hz
//the highest is 254khz
//freq adjust
//at 100hz the smallest increase step is 0,02hz // dutycycle49,9%
//at 1khz the smallest increase step is 2<>2hz // dutycycle 49,8%
//at 10khz the smallest increase step is 185<>200hz // dutycycle 48,6%
//at 100khz the smallest increase step is 17kz<>26kz // dutycycle 36,5%
//at 254khz the smallest decrease step is 86kz< // dutycycle 15,8%
//the frequency is stable with cristal precision! <1%
//i used This example that checks the state of the rotary encoder in the loop() function.
// The current position is printed on output when changed.
// Hardware setup:
// Attach a rotary encoder with output pins to A2 and A3.and switch to pin 3 to trigger interrupt1 added a small debounce capacitor from this pin to ground
// The common contact should be attached to ground.
#include <RotaryEncoder.h>
unsigned int range=100;
int swt=3;
unsigned int pos = 0;
unsigned int microdelay;
RotaryEncoder encoder(A2, A3);// Setup a RoraryEncoder for pins A2 and A3:
void setup()
{
DDRB |= 0B00100000; // activate pin13
cli();
TIMSK0 &= ~(1 << TOIE0); // disable timer (no millis)
sei();
pinMode(swt, INPUT_PULLUP);
attachInterrupt(1,swtch,FALLING); // pin3
Serial.begin(57600);
Serial.println("Arduino Frequency Generator with RotaryEncoder library.");
// You may have to modify the next 2 lines if using other pins than A2 and A3
PCICR |= (1 << PCIE1); // This enables Pin Change Interrupt 1 that covers the Analog input pins or Port C.
PCMSK1 |= (1 << PCINT10) | (1 << PCINT11); // This enables the interrupt for pin 2 and 3 of Port C.
}
// The Interrupt Service Routine for Pin Change Interrupt 1
// This routine will only be called on any signal change on A2 and A3: exactly where we need to check.
ISR(PCINT1_vect) {
encoder.tick(); // just call tick() to check the state.
}
void loop()
{
unsigned int newPos = encoder.getPosition();
if (pos != newPos) {
// Serial.println(newPos);
Serial.println(microdelay);// Read the current position of the encoder and print out when changed.
if ((newPos > pos)&& ((microdelay+range) <= 16300)) {
microdelay= microdelay + range;
}else if ((newPos<pos) && ((microdelay-range) >= 1)&& (microdelay-range)<=16300){
microdelay= microdelay - range;
}
pos = newPos;
}
microdelay= constrain((microdelay),1,16300);
PORTB |= 0B00100000; //pin 13 on
delayMicroseconds(microdelay);
PORTB &= 0B11011111; //pin 13 off
delayMicroseconds(microdelay);
}
void swtch (){
if (digitalRead(swt)== LOW)range=range*10;
if (range > 100) range=1;
Serial.println (range);
}