I have been playing around with Timer Interrupts to generate a square wave on a pin. I have got that working, but now I want to be able to vary the length of the pulse but keep the frequency the same. For example, I want to create a pulse of 100-200us, and have a frequency of 1000Hz. Here is my code:
int channels = 0;
#define REFRESH 16000 //1000us/0.0625us = 16,000
void setup() {
// Reset Timer 3 Control Register to 0
TCCR3A = 0;
// Set prescaler to 1
TCCR3B &= ~(1 << CS32); //0
TCCR3B &= ~(1 << CS31); //0
TCCR3B |= (1 << CS30); //1
//Reset Timer 3 and set compare value
TCNT3 = 0;
// Enable Timer 3 compare interrupt
TIMSK3 = (1 << OCIE3A);
//Enable global interrupts
sei();
pinMode(4, OUTPUT);
}
void loop() {
delay(100);
}
ISR(TIMER3_COMPA_vect) {
if (channels == 1) {
digitalWrite(4, HIGH);
OCR3A = 100 / 0.0625;
channels = 0;
}
if (channels == 0) {
digitalWrite(4, LOW);
OCR3A = REFRESH;
channels = 1;
TCNT3 = 0;
}
}
The servo library does something similar, and I found this is the code for the library:
static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t *TCNTn, volatile uint16_t* OCRnA)
{
if( Channel[timer] < 0 )
*TCNTn = 0; // channel set to -1 indicated that refresh interval completed so reset the timer
else{
if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && SERVO(timer,Channel[timer]).Pin.isActive == true )
digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,LOW); // pulse this channel low if activated
}
Channel[timer]++; // increment to the next channel
if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) {
*OCRnA = *TCNTn + SERVO(timer,Channel[timer]).ticks;
if(SERVO(timer,Channel[timer]).Pin.isActive == true) // check if activated
digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,HIGH); // its an active channel so pulse it high
}
else {
// finished all channels so wait for the refresh period to expire before starting over
if( ((unsigned)*TCNTn) + 4 < usToTicks(REFRESH_INTERVAL) ) // allow a few ticks to ensure the next OCR1A not missed
*OCRnA = (unsigned int)usToTicks(REFRESH_INTERVAL);
else
*OCRnA = *TCNTn + 4; // at least REFRESH_INTERVAL has elapsed
Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
}
}
It seems like they are only using OCRnA, and just redefining it for the next servo pulse. Once all the servo pulses are sent it then resets the timer to 0, and starts the process again.
When I look at pin 4 on the oscilloscope it does a frequency of 1000Hz, but the pulse is only about 4us. I am obviously doing something wrong in my code and could use a little guidance.