[solved]Changing pin assignment to be the output of a timer

solved edit:

accually it works as I wanted I just put Serial.available in the while loop so it wouldn't be empty at first run of the code I don't know why "while" cannot be empty but that was a problem, so the working fragments of the code are pretty much like this:

ISR (TIMER2_COMPA_vect) 
  {
   
    f=1;

}

void impulse(){
      
      
      timer2Settings();


      int l=0;      
      TIMSK2 = bit (OCIE2A);         //enable interupts   
      while(l<pwmValuesNumber) {

             
             if(f==1){
                       
             analogWrite(coilControlPin, values[l]); 
             
             f=0;
             l++;
             
             }
             else Serial.available();


       }
       
       TIMSK2 = 0;
       
}




void timer2Settings(){
      n=tu/16-1;
      TCCR2A = 0;                                                           //timer2 settings
      TCCR2B = 0;
      TCCR2A = bit (WGM21) ;   // CTC mode 
      
      TCCR2B =  bit (CS21) | bit (CS22);   
      OCR2A  = n;                    //count to n value                       //end of timer2 settings    
                 
}

/solved edit

Hello,

I m going to use code found on the forum but need to use pin 9 instead of pin 10 with this example code:

// Example of modulating a 38 KHz frequency duty cycle by reading a potentiometer
// Author: Nick Gammon
// Date: 24 September 2012

const byte POTENTIOMETER = A0;
const byte LED = 10;  // Timer 1 "B" output: OC1B

// 16 MHz clock divided by 38 KHz frequency desired
const long timer1_OCR1A_Setting = 16000000L / 38000L;

void setup() 
 {
  pinMode (LED, OUTPUT);

  // set up Timer 1 - gives us 38.005 KHz 
  // Fast PWM top at OCR1A
  TCCR1A = _BV (WGM10) | _BV (WGM11) | _BV (COM1B1); // fast PWM, clear OC1B on compare
  TCCR1B = _BV (WGM12) | _BV (WGM13) | _BV (CS10);   // fast PWM, no prescaler
  OCR1A =  timer1_OCR1A_Setting - 1;                 // zero relative  
  }  // end of setup

void loop()
  {
  // alter Timer 1 duty cycle in accordance with pot reading
  OCR1B = (((long) (analogRead (POTENTIOMETER) + 1) * timer1_OCR1A_Setting) / 1024L) - 1;
  
  // do other stuff here
  }

Sorry for probably such a trivial question but I don't entirely know how it works.

I didn't yet go further but I want to use it as waveform generator with array of PWM duty cycle values with another variable setting the time for updating duty cycle value so it would work like:

collecting array of value for dutycycle,
collecting variable for time between updates
putting first value to OCR1A,
generating signal with this duty cycle for time defined by variable
putting another value to OCR1A,

I already have a solution with analog write function but the accuracy of frequency of pulses of the waveform is quite low could it be improved by above solution?

I mean frequency as 1/time from one waveform pulse to another .

Do you have other ideas how to solve this?

To use Pin 9 you have to put the PWM value in OCR1A (that code uses OCR1B to control Pin 10). The code you are using uses OCR1A for TOP so it can't be used for the PWM value. To use OCR1A for PWM you have to move the TOP value somewhere else. If you look at the ATmega328P datasheet you will find that the only other choice is the ICR1 register. See section 15.9.3 regarding Fast PWM Mode.

Thank you for the reply but I'm afraid I still don't know what to do, I was hoping that I wouldn't have to read half of the datasheet to know how to do that since I'm a newbie but it doesn't seems to be the case ;(.

Could you maybe help me find maybe easy and better than now used solution for me concerning that fragment of the code:

TCCR1B = (TCCR1B & 0b11111000)  | 0x01 	// to set PWM frequency of 31250 Hz on pins 9,10




//function to just generate waveform with different pwm pulses values

void Pulse(){
   
    for (int l = 0 ; l < number ; l ++) {
          
     analogWrite(coilControlPin, values[l]); 
    
     delayMicroseconds(tu);      	//tu- declared value for time between //PWM values update
     
   }

My question is how to improve accuracy of the time that whole waveform lasts which should be approximately number*tu but it differs from it, I know that executing analogWrite function and also delayMicroseconds could also consume some time so when I substract some value lets say 12 microseconds from it as an correction, it works great for some cases practically eliminating error but for longer waveform it doesn't do the trick.

So do you maybe know some way how to improve it or do differently, I was thinking also to use for the frequency of PWM equal 31250 Hz(1/31250=32us) for example timer 2 with for example prescaler of 512 (if it is possible) (16mhz/512=32us) that would update PWM value (duty cycle value) with frequency which is total multiply of period of one PWM pulse, would that work and be possible?

I'm not quite sure what you are trying to do here. Can you please explain a little more.

How long do you want to dwell at each step of the cycle? What are the number of steps? What accuracy is required? Microseconds has a resolution of 4 us.

Rather than try and synchronize with another timer, it might be more simple to branch the output to an interrupt pin and count the number of pulses and switch values, at a given count.

Alternatively, I believe you could set up an overflow interrupt on the timer which is generating the pwm and count the number of cycles that way. This might take you deeper into the data sheet than you wish to go.

My question is how to improve accuracy of the time that whole waveform lasts which should be approximately number*tu but it differs from it, I know that executing analogWrite function and also delayMicroseconds could also consume some time so when I substract some value lets say 12 microseconds from it as an correction, it works great for some cases practically eliminating error but for longer waveform it doesn't do the trick.

Can you rewrite that in a way we can understand? What accuracy are you currently getting? What are you expecting/wanting?

... for longer waveform it doesn't do the trick ...

Please be specific. What frequency does it work for? What one does it not work for?

Hmm, how to rewrite it so lets say I sent 500 values for the waveform and (as time between PWM values update in above posted code)tu=200us (I also substrack 12 us from it right now because it helps with accuracy of lower frequencies) so the time that this waveform lasts is equal to 100000us=0,1s (and its frequancy 1/0,1=10Hz),

but when I check the output with osciloscope I got for example 10,5 Hz with lower frequencies lets say 1 Hz maybe up to 5 Hz there is no error but with higher lets say 100 Hz there is more than 10 Hz more so for example 110 Hz when I type 100 Hz.

Edit:

I'm hoping to get output frequency as accurate as possible limiting the value to multiples of 32 us would not be a problem.

Maybe read this: Gammon Forum : Electronics : Microprocessors : Timers and counters

I used some fragments of code from your article and wrote this:

ISR (TIMER2_COMPA_vect) 
  {
   
    f=1;

}

void impulse(){
      
      
      timer2Settings();


      int l=0;      
      TIMSK2 = bit (OCIE2A);         //enable interupts   
      while(l<pwmValuesNumber) {

             
             if(f==1){
                       
             analogWrite(coilControlPin, values[l]); 
             
             f=0;
             l++;
             
             }
       }
       
       TIMSK2 = 0;
       
}




void timer2Settings(){
      n=tu/16;
      TCCR2A = 0;                                                           //timer2 settings
      TCCR2B = 0;
      TCCR2A = bit (WGM21) ;   // CTC mode 
      
      TCCR2B =  bit (CS21) | bit (CS22);   
      OCR2A  = n;                    //count to n value                       //end of timer2 settings    
                 
}

but instead of reading values one by one and "analogWriting" them it generates PWM with just first duty cycle value, and gets stuck within impulse function... (I'm sending right amount of values equal to pwmValuesNumber variable)

Is it possible to use it this way? What am I doing incorrectly? Please help if possible just pointing the errors.

Here is a sketch I put together which has pwm pulses at 31,250hz from Timer 2 on pin 11.

I count the pulses with an interrupt on pin 2 (int0) and time the cycles with the counter on Timer 1. I run a jumper between pin 11 and pin 2

I have set the sketch to cycle through 50 different pulse widths (5 to 250) and the number of pulses at each level can be set. I have looked at it from 10 to 100 hz for the 50 step cycle.

There is a serial print out of the cycle times, and at lower frequencies you can also get a print of the individual level counts and times but it takes up too much time at higher frequencies. The values look as expected, although there is a slight timing anomaly on the first pulse.

I'm still not sure of what you want to achieve, but see if this gives you any ideas. I don't have a scope, so I would appreciate some feedback of if the program is actually doing what I think it is.

//variable pulseCount changed within ISR
volatile unsigned long  pulseCount = 0;
unsigned long copyCount = 0;//protected copy

//cycle time variables from Timer1
unsigned long tick = 0;
unsigned long sumTick = 0;

byte pwmValue = 5;//initial pwm value
byte lastPwmValue = 0;
int pwmCycles = 63; //number of pulses at a given level
// 63~10hz 32~20hz 21~30hz 13~50hz  9~70hz 7~90hz 6~100hz
byte pwmValueIncrement = 5;//50 pwm increments 5 to 250

volatile boolean flag = false; //pwmCycles counted

void setup()
{
  //set up Timer2 for equivalency to analogWrite(11,pwmValue)
  //with no prescaler pwm frequency 31250 hz  32us per pwm pulse

  TCCR2A = 0; //initialize register
  TCCR2A |= 1 << WGM20; //set mode 1 phase correct pwm to 255
  TCCR2A |= 1 << COM2A1; //output A clear up/set down
  pinMode(11, OUTPUT);//enable Timer2 pwm output A/Pin 11

  OCR2A = 5;//starting pwmValue;

  TCCR2B = 0;//initialize register
  TCCR2B |= 1 << CS20; //Timer2 no prescaler pwm 31250

  //Timer1 set up as pulseCounter
  // reset Timer1 registers
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;
  TCCR1B |= (1 << CS11);//start pulseCounter prescaler 8--.5us/tick

  //jumper pin 11 to pin 2
  attachInterrupt(0, isrCount, RISING); //interrupt 0 pin2

  Serial.begin(115200);
  Serial.println("start...");
}

void loop()
{

  if (flag)
  {
    flag = false;

    // disable interrupts,make copy of isr variables,reenable interrupts
    noInterrupts();
    copyCount = pulseCount;
    pulseCount = 0;
    interrupts();

    TCCR1B &= ~(1 << CS11); //stop timer
    tick = TCNT1 / 2; //microsseconds;
    sumTick += tick;
    TCNT1 = 0;
    TCCR1B |= (1 << CS11);//start timer

    lastPwmValue = pwmValue;//pwm associated with last pulseCount

    if (pwmValue < (255 - pwmValueIncrement ))
    {
      pwmValue += pwmValueIncrement;
      OCR2A = pwmValue;
      //display();//uncomment at 10hz

    }
    else
    {
      pwmValue = 5;
      OCR2A = pwmValue;
      //display();//uncomment at 10hz

      Serial.println(sumTick);//microseconds for cycle
      sumTick = 0;
      // Serial.println("  microseconds for cycle");
    }
  }
}

void isrCount()
{
  pulseCount++;
  if (pulseCount >= pwmCycles)
  {
    flag = true;
  }
}

void display()
{
  Serial.print(copyCount);
  Serial.print('\t');
  Serial.print(tick);
  Serial.print('\t');
  Serial.println(lastPwmValue);
}

NeverKnewMyself:
but when I check the output with osciloscope I got for example 10,5 Hz with lower frequencies lets say 1 Hz maybe up to 5 Hz there is no error but with higher lets say 100 Hz there is more than 10 Hz more so for example 110 Hz when I type 100 Hz.

I'm having a lot of trouble visualizing what you mean here. Perhaps explain with a diagram.

Sorry cattledog but I cannot check your program because I have permanently fixed circuit to arduino so pin 9 has to be my output,

I use this PWM with different duty cycle values to power the coil with different current shapes, so I include drawing to my post to explain what I mean by those sentences, but could you help me maybe fix the last code I posted,

To understand it more what kind of errors I made I wrote this:

byte n=200;
byte g=10;
bool f=0;
int fg;
int a=0;
void setup() {
 Serial.begin(9600);
 TCCR1B = TCCR1B & 0b11111000 | 0x01;
 sets();
 pinMode (9, OUTPUT);
 
}

void loop() {
  
  g=0;
  impulseOfSorts();
  analogWrite(9, 0);
  delay(1000);
}


ISR (TIMER2_COMPA_vect) 
  {    
            analogWrite(9, g);         
            g+=100;                           
  }

void sets(){
 Serial.println("sets");
 TCCR2A = 0;
 TCCR2B = 0;
 TCCR2A = bit (WGM21) ;   // CTC mode 
 OCR2A  = n; 
 TCCR2B =  bit (CS21) | bit (CS22); 


 
}

void impulseOfSorts(){
  Serial.println("impulse");
  
  TIMSK2 = bit (OCIE2A);
  while(g<200){
    Serial.println(g);
  }  
  TIMSK2 = 0;

  Serial.println("end");
  
}

but it isn't working properly (its seems like I would have to have right amount of commands in the while loop so it would occupy cpm for right amount of time or something, but it doesn't make sense) I added line Serial.println(g); in the while loop otherwise (with empty while loop) it doesn't stop at all and generate this few steps waveform on and on without delay (it isn't even getting out of while loop) , and also with n lesser than this 200 it cuts some steps sometimes even just sending one step value on a pin...

edit xx

Is there a condition statement maybe more reliable in this case (than while) that would keep code from running until the g would not exceed certain value because this while loop without anything inside doesn't work as planned...

I replaced while with
do {
}

while (g<100) ;
but it didn't change anything

I have modified my sketch to put the pwm output on pin 9 and pin 10, using Timer 1. Jumper the pin 10 output to pin 2 for the interrupt counting of the pulses. Cycle frequency is changed by the number of pulses to count before a pwm waveform change. I have changed the cycle time counting to Timer 2.

It is still very unclear to me what you are trying to do, but maybe we are getting closer. :slight_smile:

//variable pulseCount changed within ISR
volatile unsigned long  pulseCount = 0;
unsigned long copyCount = 0;//protected copy

//cycle time variables from Timer2
volatile unsigned long tick = 0;//timer overflow count
unsigned long copyTick = 0;//protected copy
unsigned long cycleTime =0;//tick plus TCNT2
unsigned long sumCycleTime = 0;

byte pwmValue = 5;//initial pwm value
byte lastPwmValue = 0;
int pwmCycles = 63; //number of pulses at a given level
// 63~10hz 32~20hz 21~30hz 16~40hz 13~50hz  9~70hz 7~90hz 6~100hz
byte pwmValueIncrement = 5;//50 pwm increments 5 to 250

volatile boolean flag = false; //pwmCycles counted

void setup()
{
  //set up Timer1 for equivalency to analogWrite(9,pwmValue)
  //with no prescaler pwm frequency 31250 hz  32us per pwm pulse
  //echo pin 9 on pin 10 for use as interrupt on pin 2
  TCCR1A = 0; //initialize register
  TCCR1A |= 1 << WGM10; //set mode 1 phase correct pwm to 255
  TCCR1A |= 1 << COM1B1; //output B clear up/set down
  TCCR1A |= 1 << COM1A1; //output A clear up/set down
  pinMode(9, OUTPUT);//enable Timer1 pwm output A/Pin 9
  pinMode(10, OUTPUT);//enable Timer1 pwm output B/Pin 10

  OCR1A = 5;//starting pwmValue;
  OCR1B = 5;//starting pwmValue;

  TCCR1B = 0;//initialize register
  TCCR1B |= 1 << CS20; //Timer1 no prescaler pwm 31250

  //Timer2 set up as Counter OVF + TCNT2
  // reset Timer2 registers and the Counter
  TCCR2A = 0;
  TCCR2B = 0;
  TCNT2 = 0;
  TCCR2B |= (1 << CS21);//start pulseCounter prescaler 8--.5us count 128us per overflow
  TIMSK2 |= 1<< TOIE2; //enable Timer 2 overflow vector interrupt
 
 
  //jumper pin 10 to pin 2
  attachInterrupt(0, isrCount, RISING); //interrupt pin2

  Serial.begin(115200);
  Serial.println("start...");
}

void loop()
{

  if (flag)
  {
    flag = false;

    // disable interrupts,make copy of isr variables,reenable interrupts
    noInterrupts();
    copyCount = pulseCount;
    pulseCount = 0;
    copyTick= tick;
    tick= 0;
    interrupts();

    TCCR2B &= ~(1 << CS21); //stop timer2
    cycleTime= copyTick*128 + TCNT2 / 2; //microsseconds;
    sumCycleTime += cycleTime;;
    TCNT2 = 0;
    TCCR2B |= (1 << CS21);//start timer

    lastPwmValue = pwmValue;//pwm associated with last pulseCount

    if (pwmValue < (255 - pwmValueIncrement ))
    {
      pwmValue += pwmValueIncrement;
      OCR1B = pwmValue;
      OCR1A = pwmValue;
      //display(); //uncomment at 10hz

    }
    else
    {
      pwmValue = 5;
      OCR1B = pwmValue;
      OCR1A = pwmValue;
      //display();//uncomment at 10hz

      Serial.println(sumCycleTime);
      sumCycleTime = 0;
      // Serial.println("  microseconds for cycle");

    }
  }
}

void isrCount()
{
  pulseCount++;
  if (pulseCount >= pwmCycles)
  {
    flag = true;
  }
}

void display()
{
  Serial.print(copyCount);
  Serial.print('\t');
  Serial.print(cycleTime);
  Serial.print('\t');
  Serial.println(lastPwmValue);
}

//Timer 2 Overflow Interrupt Vector called every 128 us
ISR(TIMER2_OVF_vect) {
  tick++; //Increments the tick counter
  }