Hi, the question is simple: How can i generate a variable-FREQUENCY-square wave without any library ??
Before you answer i'll give you some details:
1) My goal is create a FUNCTION that can generate variable frequency square wave because i want to implement a personalized acceleration profile using Stepper Motors.
2) I know there is the AccelStepper library that works very well, but i have specific requirements so i would like to do my own code.
3) I have satrted using the Arduino Timers, the Timer1 (16 bits) works in CTC mode with a defined TOP value that i can change.
The Timer0 (8 bits) also in CTC mode has to change the TOP value of Timer1 everytime an interrupt occurs.
4) This system should generate a reliable signal since i'm using timmers directly (at least that's what I expect). But when I upload the code and see with the Oscilloscope there are some rebounds that affects the square wave while it's changing it's frequency.
This is a problem beacuse the stepper motor loses steps or even stops due to the rebounds.
I thought that could be some timing problem between both Timers while one afects the other.
This problem produces a stop or missing steps effect on the stepper motors.
5) I'm using direct register acces or modification instead of the arduino functions, because i want to make a very optimized and fast code that doesn't distorts or affect the resulting signal.
6) The maximum frequency that i would like to use (for timer1) is less than 10 kHz, so everything between 0 and 10 kHz would be nice. For the second timer i should use frequencies between 0 and 5 kHz if its possible.
7) Sorry if I forgot any other info that could be important. I'll post the code used and some picts (i hpe they appear) of the oscilloscope results, but it's difficult to me to post a video of the oscilloscope that would be more illustrative.
byte PULSE = 9; // pulse signal that motor driver needs
byte DIR = 8; // direction of motor rotation
void setup() {
pinMode(PULSE, OUTPUT); // pin 9 (OC1A) configured as an OUTPUT
pinMode(DIR, OUTPUT); //
digitalWrite(DIR, HIGH);
cli(); // disable global interrupts while seting up timers
//----------------------------------------------------------------------------- TIMER 0
// Set CTC Mode
TCCR0B &= ~(1 << WGM02); // WGM02 = 0
TCCR0A |= (1 << WGM01); // WGM01 = 1
TCCR0A &= ~(1 << WGM00); // WGM00 = 0
// Prescaler of 256
TCCR0B |= (1 << CS02); // CS02 = 1
TCCR0B &= ~(1 << CS01); // CS01 = 0
TCCR0B &= ~(1 << CS00); // CS00 = 0
// Enable CTC timer interrupts
TIMSK0 |= (1 << OCIE0A);
//----------------------------------------------------------------------------- TIMER 1
// Set CTC Mode
TCCR1B &= ~(1 << WGM13); // WGM13 = 0
TCCR1B |= (1 << WGM12); // WGM12 = 1
TCCR1A &= ~(1 << WGM11); // WGM11 = 0
TCCR1A &= ~(1 << WGM10); // WGM10 = 0
// set toggle mode for pin 9 (OC1A)
TCCR1A &= ~(1 << COM1A1); // COM1A1 = 0
TCCR1A |= (1 << COM1A0); // COM1A0 = 1
// Set Prescaler of 8
TCCR1B &= ~(1 << CS12); // CS12 = 0
TCCR1B |= (1 << CS11); // CS11 = 1
TCCR1B &= ~(1 << CS10); // CS10 0 0
// Maximum count values
OCR0A = 254; // For timer0
OCR1A = 999; // For timer1
TCNT1 = 0; //Initialize timer/counter 1 value to 0
TCNT0 = 0; //Initialize timer/counter 0 value to 0
sei(); // Enable global interrupts
}
// Timer 0 ISR that changes Top count value of Timer1, hence it's frequency
ISR(TIMER0_COMPA_vect) {
if (OCR1A >= 249) { // 249 set the max count value for Timer0
OCR1A--;
}
}
void loop() {
}