Timer0 is an 8-bit timer (like Timer2) so you will need a prescale of 64 or higher.
12403 / 64 = 193.79 so you would set TOP to 194. That will get you a frequency of bount 1288.66 Hz.
Timer0 is an 8-bit timer (like Timer2) so you will need a prescale of 64 or higher.
12403 / 64 = 193.79 so you would set TOP to 194. That will get you a frequency of bount 1288.66 Hz.
I don't believe that you can use pin OC0A (pin 6) with fast PWM on timer0, when setting the frequency, which is what the OP originally wanted. The reason is here: avr - Can't set to Fast PWM OCRA mode - Electrical Engineering Stack Exchange
TL;DR you can use only OC0B (pin5) in this case.
I had thought of setting the frequency at 11 times the desired frequency and manually flipping the pin in the overflow ISR to get the desired duty cycle (9/11 is Approximately 81%) but you can't (re-)use the timer0 overflow vector even if you use your own main(). That would mean hacking the Arduino core to release the overflow vector.
In conclusion, I can't see a realistic way of controlling frequency and duty cycle on pin 6 using timer 0. However, I may have missed something.
Then the code should look something like this:
#include <PinChangeInterrupt.h>
const uint8_t buttonPin = 11;
const int pulsePin = 6;
volatile bool buttonPressed = false;
volatile int pulseCount = 0;
const unsigned long pulseDelay = 81;
unsigned long lastPulseTime = 0;
void buttonISR() {
buttonPressed = true;
}
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
pinMode(pulsePin, OUTPUT);
attachPCINT(digitalPinToPCINT(buttonPin), buttonISR, RISING);
Serial.begin(9600);
TCCR0A = 0;
TCCR0B = 0;
TCNT0 = 0;
OCR0A = 194-1;
OCR0B = (byte) (OCR0A * 0.81);
TCCR0A = 0x00;
//TCCR0A |= (1 << WGM01);
TIMSK0 |= (1 << OCIE0A);
//TCCR0B |= (1 << CS01) | (1 << CS00);
}
void loop() {
bool pinHigh = (digitalRead(buttonPin) == HIGH);
if(pinHigh && buttonPressed){
TCCR0B |= (1 << CS01) | (1 << CS00);
buttonPressed = false;
}else if(!pinHigh && !buttonPressed){
buttonPressed = true;
}
}
ISR(TIMER0_COMPA_vect){
//Serial.println(pulseCount);
if(pulseCount < 5500){
pulseCount++;
//digitalWrite(pulsePin, HIGH);
//digitalWrite(pulsePin, LOW);
PORTD ^= (1 << PD6);
}else{
TCCR0B &= ~(1 << CS00);
TCCR0B &= ~(1 << CS01);
pulseCount = 0;
}
}
Does your testing show that this solution works ?
If not, then are you able somehow to use pin 5 with timer 0 or are you prepared to use either timer 1 or timer 2 instead of timer 0 ?
It has already been pointed out that timer0 is a bad choice because it is used by the Arduino core and you are not free to use all its features.
You should solve the problem of getting the correct waveform (duty cycle/frequency) on the desired pin before looking at the simpler task of stopping the output after X pulses.
@GolamMostafa normally joins such threads with some interesting explanation and supporting diagrams.
What the generated pulses look like:

I can't judge the frequency but the duty cycle looks like 50%.
and how to make 81 %?
As I said, I don't believe you can do this using the Arduino core if you want all the following (a) to use timer0 (b) to use pin 6, 9 or 11 only (c) to be able to specify both frequency and duty cycle.
If this is a school exercise then consider the possibility that the combination of constraints was selected deliberately to make the task impossible as some sort of endurance test. If not, then make some compromise to the constraints. The least invasive being to use pin 5 instead of pin 6.
if I do something like this, I get such an impulse:
#include <PinChangeInterrupt.h>
const uint8_t buttonPin = 11;
const int pulsePin = 6;
volatile bool buttonPressed = false;
volatile int pulseCount = 0;
void buttonISR() {
buttonPressed = true;
}
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
pinMode(pulsePin, OUTPUT);
attachPCINT(digitalPinToPCINT(buttonPin), buttonISR, RISING);
Serial.begin(9600);
TCCR0A = 0;
TCCR0B = 0;
TCNT0 = 0;
OCR0A = 194-1;
OCR0B = (byte) (OCR0A * 0.81);
TCCR0A = 0x00;
//TCCR0A |= (1 << WGM01);
TIMSK0 |= (1 << OCIE0A);
//TCCR0B |= (1 << CS01) | (1 << CS00);
}
void loop() {
bool pinHigh = (digitalRead(buttonPin) == HIGH);
if(pinHigh && buttonPressed){
TCCR0B |= (1 << CS01) | (1 << CS00);
buttonPressed = false;
}else if(!pinHigh && !buttonPressed){
buttonPressed = true;
}
}
ISR(TIMER0_COMPA_vect){
//Serial.println(5);
if(pulseCount < 5500){
pulseCount++;
if(pulseCount % 4 == 0){
digitalWrite(pulsePin, LOW);
}else{
digitalWrite(pulsePin, HIGH);
}
}else{
TCCR0B &= ~(1 << CS00);
TCCR0B &= ~(1 << CS01);
pulseCount = 0;
}
}

Should impulses be like this?

Oops. That should be:
TCCR1B |= _BV(WGM13) | _BV(WGM12);
What can you say about the code above?
I did succeed in getting an approximation working on pin 6 with timer 0. I wrongly assumed that CTC mode used the overflow vector, which is not available if you use the Arduino core. In fact it uses the COMPA vector. It uses a trick in that the timer runs 11 times fast. See the comments.
There are surely better ways of doing it.
const int pulsePin = 6;
volatile uint32_t pulseCount = 0;
ISR(TIMER0_COMPA_vect){
// called 11 times during period of F=1290
// calls 0 to 8 puslePin HIGH else pulsePin LOW
// gives ~81% duty cycle
static uint8_t callCount = 0 ;
if ( callCount == 8 ) PORTD &= ~(1 << PORTD6); // digitalWrite(pulsePin, LOW);
if ( ++callCount == 11 ) {
PORTD |= (1 << PORTD6); // digitalWrite(pulsePin, HIGH);
callCount = 0 ;
}
pulseCount++;
}
void setup(){
pinMode(pulsePin, OUTPUT);
Serial.begin(9600);
cli() ;
TCCR0A = 0;
TCCR0B = 0;
TCNT0 = 0;
OCR0A = 140 ; // f = 14,190 (11 * 1,290) @16MHz clock
TCCR0A |= (1 << WGM01) ; // CTC
TCCR0B |= (1 << CS01); // PS 8
TIMSK0 = (1 << OCIE0A);
sei() ;
}
void loop() {
}
If you want 976.5625 Hz and 75% duty cycle instead of 1250 Hz and 81% duty cycle then it should work fine.
You would get closer just using: "analogWrite(pulsePin, 207);". You'd still get 976.5625 Hz but you'd get closer to 81% duty cycle.
const byte buttonPin = 11;
const byte pulsePin = 6;
void setup()
{
pinMode(buttonPin, INPUT_PULLUP);
}
void loop()
{
if (digitalRead(buttonPin) == LOW) // Button pressed
{
analogWrite(pulsePin, 206); // Start PWM with 81% duty cycle
// wait 5.632 seconds for 5500 cycles to elapse
delay(5600);
delayMicroseconds(32000ul); // Adjust to get desired pulse count
analogWrite(pulsePin, 0);
}
}
Is it possible to do without
PORTD |= (1 << PORTD6);
PORTD |= (1 << PORTD6);
Use OCR0A instead
I guess you mean, is it possible to select a timer mode where you don't have to explicitly flip the pin in an ISR and yet have your frequency and duty cycle respected?
Indeed it is, and here it is :
const int pulsePin = 5; // note OC0B Pin D5 ! ! !
volatile uint32_t pulseCount = 0;
void setup(){
pinMode(pulsePin, OUTPUT);
cli() ;
TCCR0A = 0;
TCCR0B = 0;
TCNT0 = 0;
OCR0A = 193 ; // f = 1,290 @16MHz clock
OCR0B = (float) OCR0A * 0.81 ;
TCCR0A |= (1 << WGM01) | (1 << WGM00) | (1 << COM0B1 ) ; // Mode 7 (fast PWM )
TCCR0B |= (1 << CS01) | (1 << CS00) | (1 << WGM02) ; // ps /64 mode 7
sei() ;
}
void loop() {
}
There is only one slight problem. The output is on pin D5 that is pin OC0B. See post #23 for an explanation.