I am wondering if there is any method of outputting a PWM signal with a 50% duty cycle with a frequency that I can change without using the tone() command.
I cannot use the tone() function as it takes up too much processing time and I require the code to execute as fast as possible (in less than 90 micro seconds).
I have timed my code with the tone() command in it and it takes upwards of 200 micro seconds.
Thank you for your help, I can answer any further questions as best I can.
What frequency range do you need? For certain ranges and specific output pins you can change frequency by writing one register (less than a microsecond to change frequency). For wider frequency range you may need to change the clock prescale bits in addition to the register containing the TOP value.
Thanks blh64 I’ll have a read through that page and try use it in the code.
In terms of the frequency range John, I need frequencies in the range of around 20hz to 300hz.
Essentially my code will calculate the frequency of an incoming analog signal and then output a PWM signal with the same frequency. This frequency can fluctuate and thus the frequency of the PWM signal will need to fluctuate along with the incoming analog signal within the aforementioned frequency range. Is this possible using the method you mentioned?
I will send a copy of my code tomorrow to make this clearer, apologies for not doing this sooner.
I am having some difficulty with the timer1, I have set it up in the manner you mentioned earlier (I'm not sure if I have done this correctly).
This has increased the cycle time of my code from 8 microseconds to roughly 140 micro seconds which would make my code function improperly. When I first open the serial monitor to display the "duration" it starts at around 70-80 microseconds then jumps up to 140 microseconds.
Is this caused by timer1 making the micros(); functions erroneous and if so is there a way to reduce/solve this. Alternatively is there any method of generating the PWM using timer1 without increasing my cycle time so dramatically. Here is my code:
unsigned long totalLength;
unsigned long spaceLength;
unsigned long markLength;
int start1;
int i;
unsigned long endTime;
unsigned long lowTime;
unsigned long midTime;
unsigned short int x;
int val;
int frequency;
float period;
void setup() {
Serial.begin(2000000);
ADCSRA = 0; // clear ADCSRA register
ADCSRB = 0; // clear ADCSRB register
ADMUX |= (0 & 0x07); // set A0 analog input pin
ADMUX |= (1 << REFS0); // set reference voltage
ADMUX |= (1 << ADLAR); // left align ADC value to 8 bits from ADCH register
// sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles]
// for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles
ADCSRA |= (1 << ADPS2) | (1 << ADPS0); // 32 prescaler for 38.5 KHz
//ADCSRA |= (1 << ADPS2); // 16 prescaler for 76.9 KHz
//ADCSRA |= (1 << ADPS1) | (1 << ADPS0); // 8 prescaler for 153.8 KHz
ADCSRA |= (1 << ADATE); // enable auto trigger
ADCSRA |= (1 << ADIE); // enable interrupts when measurement complete
ADCSRA |= (1 << ADEN); // enable ADC
ADCSRA |= (1 << ADSC); // start ADC measurements
pinMode(3, OUTPUT);
TCNT1H = _BV(COM1A1) | _BV(CS11) | _BV(WGM13) | _BV(WGM11) | _BV(WGM10); // this is the section of code used to generate the PWM using timer1 & is based off this https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
OCR1A = val;
start1=0;
}
ISR(ADC_vect)
{
x = ADCH; // read 8 bit value from ADC
}
void loop() {
unsigned long start = micros();
if (x < 230 && start1==0) //detects first tooth and starts to read the output signal from the sensor
{
start1=1;
}
if (x > 235 && start1==1) //reads that the sensor has gone low and records the time
{
start1=2;
lowTime = micros();
}
if (x < 230 && start1==2) //reads that the sensor has gone high and records the time
{
start1=3;
midTime = micros();
}
if (x > 235 && start1==3) //reads that the sensor has gone high and records the time
{
start1=1;
endTime = micros();
spaceLength = endTime - midTime;
totalLength = endTime - lowTime;
markLength = totalLength - spaceLength;
}
period = totalLength/1000000.0; //to get to micro seconds
frequency = 1 / (period * 2); // multiply by two to sort rounding error
val = 500000/ (frequency * 4); //this calculation is to get val for the PWM generation using timer1
unsigned long finish = micros();
unsigned long duration = finish - start;
Serial.print(duration);
Serial.println();
}
I don't think you're using the timer correctly. This example compiles (I don't have a 2560 on hand to test it unfortunately)... It's supposed to generate a squarewave on pin 11 varying between 20Hz and 300Hz each second. If it works, maybe you can incorporate elements into your code: