Variable increment does not work

I made a program to detect an inductive loop. Timer 1 works as a PWM, which stores the value of the counter in the ICR1 register when the comparator is triggered. This happens when the voltage on the comparator drops below the reference value of 1.1V. In the interrupt routine, it writes the value from the ICR1 register to the variable t1on. I can see this variable on the serial monitor (serial.println) and it responds nicely to the change in loop inductance. Now we come to the problem: If I want to increment this variable, or any other variable, it only changes by one number from the defined value, or not at all. This applies to the ISR routine and to the main loop. So, I can overwrite a variable, but I can't increment it. Does not help if I change the type of variable(int, uint, byte) Can someone please help me, I've been scratching my head for 3 days?

I noticed that the arduino is running some code of its own in the background because the PWM period doesn't match the UNO frequency and prescaler settings. I also see period changes on the oscilloscope when I use the serial.println command.

Thak you in advance good people

volatile boolean PRINT=0;
  volatile boolean start=0;
  volatile unsigned int t1on=0;
  volatile byte cnt;
  volatile byte cnt1;

void setup () {
  cli();//disable interrupts
  Serial.begin(500000);//enalbel serial comunication
  DDRD |=  (1<<PD3)|   //set pin 3 on port D as autput (bit manipualtion is faster then use digitalwrite,read or bitset  )
          (1<<PD4);   //set pin 4 as output
  DDRB |=  (1<<PB1)|   //UNO set pin 9 on port D as autput (bit manipualtion is faster then use digitalwrite,read or bitset  )
          (1<<PB2);   //set pin D10 as output
  DIDR1 |= (1<<AIN0D); // Disable Digital Inputs at AIN0 and AIN1(1 shift left to pin AIN0D - set AIN0D)
  //ADCSRA &= ~(1<<ADEN);
  //ADCSRB |= (1<<ACME);  //Set ACME bit in ADCSRB to use external analog input at AIN1 -ve input
  ADMUX =         //referenc on AIN0 set to 2,5V
  (1<<REFS1)  |   (1<<REFS0);   //votage reference selection 00-Aref; 01-AVcc; 10-reserved; 11-1.1V (ARDUINO UNO-MEGA328p)
  ACSR =
  (0 << ACD)  |    // Analog Comparator: Enabled
  (1 << ACBG) |   // Clear ACBG to use external input to AIN0 +ve input
  (1 << ACO)  |    // Analog Comparator Output: OFF
  (1 << ACI)  |    // Analog Comparator Interrupt Flag: Clear Pending Interrupt by setting the bit
  (1 << ACIE) |   // Analog Comparator Interrupt: Disabled
  (1 << ACIC) |   // Analog Comparator Input Capture: 0-Disabled. Postavimo na 1 da omogočimo interrupt na timer 1, zajem stanja timerja v ICR1 
  (1 << ACIS1) | (0 << ACIS0);   // Analog Comparator Interrupt Mode: 00-toggle, 01-reserved, 10-falling, 11-rising

  TCCR1A =
  (0 << COM1A1)  |  (0 << COM1A0) |   // compare match mode COM1A 00-off, 01-toggle,10-clear on compare match, 11-set on compare match
  (1 << COM1B1)  |  (1 << COM1B0) |   // compare match mode COM1B 00-off, 01-toggle,10-clear on compare match, 11-set on compare match
  (1 << WGM11)   | (1 << WGM10);      // select wawe generation mode - look on table in instraction

  TCCR1B =
  (0 << ICNC1)  |  // Input capture noice canlcler 1-enable
  (1 << ICES1) |   // Input capture edge select: 1-positiv edge select
  (1<< WGM13)  |  (1 << WGM12) |   // select wawe generation mode - look on table in instraction WGM13 1-non pwm mode
  (0 << CS12)   | (0 << CS11)   |(1 << CS10);      // cloclk select, 0- stoped, 1-prescaler 1, 10-prescaler 8...

  OCR1A=50000; //top VALUE max 65535
  OCR1B=8000; //pwmB SETUP

  TIMSK1 =
  (1 << ICIE1)  |   // Input capture INTERRUPT ENABLE
  (0 << OCIE1B) |   //Output capture B interrupt enable
  (0 << OCIE1A)  |  //Output capture A interrupt enable
  (0 << TOIE1);     // cloclk select, 0- stoped, 1-prescaler 1, 10-prescaler 8...

  sei();//enable interrupts
}

void loop()
{
  if (PRINT==1)
  {
    //cli();
    ++cnt1;
    Serial.println(t1on);
    PRINT=0;
  }
}

ISR(TIMER1_CAPT_vect)//pozor, za različne procesorje so lahko različni nazivi!
{
  cli();
  t1on=ICR1;
  ++cnt;
  PRINT=1;
  //sei();
}

I didn't find in the code, where you try to increment t1on variable.

Addition - your using a cli() and sei() not looks correct for me

I have modified this code lots of time, but for instance variable cnt and cnt1 does not increment. Insted of t1on in serial.prinltn I tried with cnt and cnt1, an ther was no incremention.

Try this:

Thaks for hint, i will tray that and report

If I use cnt1=cnt and serial.println(cnt1), then print out on serial monitor continious number 1 printing. the same is for without cnt1=cnt. No mather what variable I put in serial.print line, alway is the answer 1. When i put in serial.println(t1on) it prints the inductiv fitback and is changing the value while aproaching with metal object. I do not understand, why is increment not working. I tried like cnt=cnt+1, ++cnt, cnt++, does not work. Like it would go thrue loop increment from zero and in next loop is set to zero, and again increment to one.

//14.08.2024 Test interrupt Analog Comparator
//preverjeno delovanje interrupt analog comparator

//#include <avr/interrupt.h>


  volatile boolean PRINT=0;
  volatile boolean start=0;
  volatile unsigned int t1on=0;
  volatile byte cnt=0;
  volatile byte cnt1=0;

void setup () {
  cli();//disable interrupts
  Serial.begin(500000);//enalbel serial comunication
  DDRD |=  (1<<PD3)|   //set pin 3 on port D as autput (bit manipualtion is faster then use digitalwrite,read or bitset  )
          (1<<PD4);   //set pin 4 as output
  DDRB |=  (1<<PB1)|   //UNO set pin 9 on port D as autput (bit manipualtion is faster then use digitalwrite,read or bitset  )
          (1<<PB2);   //set pin D10 as output
  DIDR1 |= (1<<AIN0D); // Disable Digital Inputs at AIN0 and AIN1(1 shift left to pin AIN0D - set AIN0D)
  //ADCSRA &= ~(1<<ADEN);
  //ADCSRB |= (1<<ACME);  //Set ACME bit in ADCSRB to use external analog input at AIN1 -ve input
  ADMUX =         //referenc on AIN0 set to 2,5V
  (1<<REFS1)  |   (1<<REFS0);   //votage reference selection 00-Aref; 01-AVcc; 10-reserved; 11-1.1V (ARDUINO UNO-MEGA328p)
  ACSR =
  (0 << ACD)  |    // Analog Comparator: Enabled
  (1 << ACBG) |   // Clear ACBG to use external input to AIN0 +ve input
  (1 << ACO)  |    // Analog Comparator Output: OFF
  (1 << ACI)  |    // Analog Comparator Interrupt Flag: Clear Pending Interrupt by setting the bit
  (1 << ACIE) |   // Analog Comparator Interrupt: Disabled
  (1 << ACIC) |   // Analog Comparator Input Capture: 0-Disabled. Postavimo na 1 da omogočimo interrupt na timer 1, zajem stanja timerja v ICR1 
  (1 << ACIS1) | (0 << ACIS0);   // Analog Comparator Interrupt Mode: 00-toggle, 01-reserved, 10-falling, 11-rising

  TCCR1A =
  (0 << COM1A1)  |  (0 << COM1A0) |   // compare match mode COM1A 00-off, 01-toggle,10-clear on compare match, 11-set on compare match
  (1 << COM1B1)  |  (0 << COM1B0) |   // compare match mode COM1B 00-off, 01-toggle,10-clear on compare match, 11-set on compare match
  (1 << WGM11)   | (1 << WGM10);      // select wawe generation mode - look on table in instraction

  TCCR1B =
  (0 << ICNC1)  |  // Input capture noice canlcler 1-enable
  (1 << ICES1) |   // Input capture edge select: 1-positiv edge select
  (1<< WGM13)  |  (1 << WGM12) |   // select wawe generation mode - look on table in instraction WGM13 1-non pwm mode
  (0 << CS12)   | (0 << CS11)   |(1 << CS10);      // cloclk select, 0- stoped, 1-prescaler 1, 10-prescaler 8...

  OCR1A=50000; //top VALUE max 65535 - PERIOD
  OCR1B=8000; //pwmB SETUP - PULS LENGHT

  TIMSK1 =
  (1 << ICIE1)  |   // Input capture INTERRUPT ENABLE
  (0 << OCIE1B) |   //Output capture B interrupt enable
  (0 << OCIE1A)  |  //Output capture A interrupt enable
  (0 << TOIE1);     // cloclk select, 0- stoped, 1-prescaler 1, 10-prescaler 8...

  sei();//enable interrupts
}

void loop()
{
  if (PRINT==1)
  {
    //cli();
    cnt1=cnt;
    Serial.println(cnt);
    PRINT=0;
  }
  sei();
}

ISR(TIMER1_CAPT_vect)//pozor, za različne procesorje so lahko različni nazivi!
{
  cli();
  t1on=ICR1;
  ++cnt;
  PRINT=1;
  //sei();
}

It looks like the variable is reset after each loop and mybe there is no time for background program to update the variable valu from last loop? any other idea?

Why did you change the usage of cli() and sei() again?
Didn't I wrote you how to do it???

Remove cli() and sei() from interrupt completely. Add cli() and sei() around copying your variable in the loop().
Or better yet - just copy my code from post #4 AS IS, without changing anything - and see the result

Copied, no change, stil prints out number 1 in column.

Post the complete code you have found to not work.

It still may be something dumb you just aren't doing what you are asked.

It happens.

a7

1 Like
//14.08.2024 Test interrupt Analog Comparator
//preverjeno delovanje interrupt analog comparator

//#include <avr/interrupt.h>


  volatile boolean PRINT=0;
  volatile boolean start=0;
  volatile unsigned int t1on=0;
  volatile byte cnt=0;
  volatile byte cnt1=0;

void setup () {
  cli();//disable interrupts
  Serial.begin(500000);//enalbel serial comunication
  DDRD |=  (1<<PD3)|   //set pin 3 on port D as autput (bit manipualtion is faster then use digitalwrite,read or bitset  )
          (1<<PD4);   //set pin 4 as output
  DDRB |=  (1<<PB1)|   //UNO set pin 9 on port D as autput (bit manipualtion is faster then use digitalwrite,read or bitset  )
          (1<<PB2);   //set pin D10 as output
  DIDR1 |= (1<<AIN0D); // Disable Digital Inputs at AIN0 and AIN1(1 shift left to pin AIN0D - set AIN0D)
  //ADCSRA &= ~(1<<ADEN);
  //ADCSRB |= (1<<ACME);  //Set ACME bit in ADCSRB to use external analog input at AIN1 -ve input
  ADMUX =         //referenc on AIN0 set to 2,5V
  (1<<REFS1)  |   (1<<REFS0);   //votage reference selection 00-Aref; 01-AVcc; 10-reserved; 11-1.1V (ARDUINO UNO-MEGA328p)
  ACSR =
  (0 << ACD)  |    // Analog Comparator: Enabled
  (1 << ACBG) |   // Clear ACBG to use external input to AIN0 +ve input
  (1 << ACO)  |    // Analog Comparator Output: OFF
  (1 << ACI)  |    // Analog Comparator Interrupt Flag: Clear Pending Interrupt by setting the bit
  (1 << ACIE) |   // Analog Comparator Interrupt: Disabled
  (1 << ACIC) |   // Analog Comparator Input Capture: 0-Disabled. Postavimo na 1 da omogočimo interrupt na timer 1, zajem stanja timerja v ICR1 
  (1 << ACIS1) | (0 << ACIS0);   // Analog Comparator Interrupt Mode: 00-toggle, 01-reserved, 10-falling, 11-rising

  TCCR1A =
  (0 << COM1A1)  |  (0 << COM1A0) |   // compare match mode COM1A 00-off, 01-toggle,10-clear on compare match, 11-set on compare match
  (1 << COM1B1)  |  (0 << COM1B0) |   // compare match mode COM1B 00-off, 01-toggle,10-clear on compare match, 11-set on compare match
  (1 << WGM11)   | (1 << WGM10);      // select wawe generation mode - look on table in instraction

  TCCR1B =
  (0 << ICNC1)  |  // Input capture noice canlcler 1-enable
  (1 << ICES1) |   // Input capture edge select: 1-positiv edge select
  (1<< WGM13)  |  (1 << WGM12) |   // select wawe generation mode - look on table in instraction WGM13 1-non pwm mode
  (0 << CS12)   | (0 << CS11)   |(1 << CS10);      // cloclk select, 0- stoped, 1-prescaler 1, 10-prescaler 8...

  OCR1A=50000; //top VALUE max 65535 - PERIOD
  OCR1B=8000; //pwmB SETUP - PULS LENGHT

  TIMSK1 =
  (1 << ICIE1)  |   // Input capture INTERRUPT ENABLE
  (0 << OCIE1B) |   //Output capture B interrupt enable
  (0 << OCIE1A)  |  //Output capture A interrupt enable
  (0 << TOIE1);     // cloclk select, 0- stoped, 1-prescaler 1, 10-prescaler 8...

  sei();//enable interrupts
}

void loop()
{
  if (PRINT==1)
  {
    cli();
    cnt1 = cnt;
    PRINT=0;
    sei();
    Serial.println(cnt1);
  }
  //sei();
}

ISR(TIMER1_CAPT_vect)//pozor, za različne procesorje so lahko različni nazivi!
{
  //cli();
  t1on=ICR1;
  ++cnt;
  PRINT=1;
  //sei();
}

I'm in transit so just reading the code you posted, thanks.

I don't use all that low level stuff enough to be able to spot your error; have you done anything simpler that could confirm you are setting things up correctly?

Speaking of which, this comment

bit manipualtion is faster then use digitalwrite,read or bitset

is amusing. You do things in a cool but needlessly obscure manner in the setup() function. Which runs once. If ever there were a place to go for clarity over speed, it would be in things done in the setup.

Replace as much as you can of the bit twiddling you do with regular functions. It will increase the ability of ppl to see and focus on what may be the real issues.

If you wrote all that low level stuff, I suggest you be sure you have interpreted the data sheet correctly. If you did not write it, please post the code that you used to create your sketch.

a7

Thak you for your time and help. I have studied atmega data sheets to set registers. Only timer1 works in combination with comparator. I dont think there is a problem in register settings, it works exactley as i want. But i have very litle experience how arduino works in backgraund. I Guess it works on timer 1, so that May be a cause of the problem.

V pet., 20. sep. 2024, 15:50 je oseba alto777 via Arduino Forum <notifications@arduino.discoursemail.com> napisala:

Post a sketch where your register settings "works exactley as [you] want".

Say what it does, and how that is supposed to function in your later sketch. How you needed to change or modify wht worked to fit into the new framework.


It works the same as any microprocessor; do you have experience with any writing ISRs that do stuff in the background and so forth?


Say more about exactly what your end goal is. I am always skeptical of code that uses interrupts, furthermore if it does low level stuff. Interrupts have their place, this may not need to be one of them.

a7

I don't think you timer mode setting of FastPWM to OCR1A is correct.

From the data sheet

The ICR1 Register can only be written when using a Waveform Generation mode that utilizes the ICR1
Register for defining the counter’s TOP value. In these cases the Waveform Generation mode bits
(WGM1[3:0]) must be set before the TOP value can be written to the ICR1 Register.

Based on this, you should be using WGM mode 12 (1100) or 14(1110).

OP's using WGM mode 15 -- Fast PWM with TOP=OCR1A=50000

12 or 14 would use ICR1 as top, and then ICR1 wouldn't be useful for input capture.

I want fast PWM(pdf line15). I want to set the needed lenght of period(OCR1A) to fit the inductiv response. ICR1 must not be used in PWM settings. It has to be free, that can be used on interrupt event on comparator, whitch trrigers timer1 and then captures current counter value of timer1 in OCR1 register. It is tricky mechanisem that only timer1 in connection with comparator interrupt enables. Comparator is using one input for internal reference 1.1V and on the other input is coil respons which triggers event, when signal falls below 1.1V.

You are correct. I was confused. I think it is more common to use Normal mode with top value 0xFFFF instead of a pwm mode with a different top.

1 Like

OCR1B is used to set the lenght of pulse to excite the coil. It depends on current on the coil I want to reach.