Strange global variable behavour

I'm adding a rev counter to the spindle motor on a cnc machine using an IR distance sensor.

Code:-

#include <U8x8lib.h>
#include <util/atomic.h> // this library includes the ATOMIC_BLOCK macro.   

U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);

//   Timer Counter and compare values

const uint16_t t1_load = 0;
const uint16_t t1_comp = 31250;

//   Pins

const byte led_pin = PB5;

volatile int Int_On_2 = false;

volatile byte Rev_Count = 0;
volatile float rpmfloat = 0;
volatile unsigned int rpm = 0;

void setup() {

  attachInterrupt(digitalPinToInterrupt(2), RPMCnt, LOW);

  Serial.begin(9600);

  PORTB ^= (1 << led_pin);

  TCCR1A = 0;

  //   Set CTC mode

  TCCR1B &= ~(1 << WGM13);
  TCCR1B |= (1 << WGM12);

  //  Set prescaler t0 256

  TCCR1B |= (1 << CS12);
  TCCR1B &= ~(1 << CS11);
  TCCR1B &= ~(1 << CS10);

  // Reset Timer1 and set compare value

  TCNT1 = t1_load;
  OCR1A = t1_comp;

  //   Eable Timer1 compare interupt

  TIMSK1 = (1 << OCIE1A);

  Rev_Count = 0;

  // Enable global interupts

  //sei();

  u8x8.begin();
  u8x8.setFont(u8x8_font_profont29_2x3_f);

}

void loop() {

  u8x8.setCursor(1, 0);
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
    // code with interrupts blocked (consecutive atomic operations will not get interrupted)
    Serial.print(Int_On_2);
    rpm = round(rpmfloat * 120);
  }
  u8x8.print(rpm);
  u8x8.print(Int_On_2);
  delay(500);
}

ISR(Timer1_COMPA_vect) {

  //  Triggers every 500 ms

  PORTB ^= (1 << led_pin);   //  flip the led

  // ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {

  // code with interrupts blocked (consecutive atomic operations will not get interrupted)

  rpmfloat = Rev_Count;
  Rev_Count = 0;

  // }
}

void RPMCnt () {

  //   Triggers every Infrared reflection detected

  // ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {

  // code with interrupts blocked (consecutive atomic operations will not get interrupted)

  Rev_Count += 1;
  Int_On_2 =  2;
  //}
}

RPM when displayed is always zero and when I trigger the sensor by hand Int_On_" displays 2 ONCE only and then goes back to zero. Int_On_2 = 2 is the ONLY instruction that changes this global. so once a trigger is detected it should stay at 2. I add Int_On_" to help me track down why rpm is always zero but to no avail. atomic block does not cure the problem.

Any suggestions much appreciated.

The LOW interrupt trigger will constantly retrigger the interrupt while the pin is LOW - you want FALLING I think. LOW is of very specialized use during sleep states I believe as it is the only interrupt trigger that works when clocking is turned off for the GPIO pads.

attachInterrupt(digitalPinToInterrupt(2), RPMCnt, LOW);

Triggering the interrupt when the sensor is LOW does not sound right. It's usual to trigger the interrupt on an edge: RISING, FALLING or CHANGE (which means either RISING or FALLING).

Hi Paul

Thanks for the reply. I just tried FALLING and with the same result. I'll maybe put a scope of the sensor to make sure I am getting a square wave. However this would not explain why Int_On_2 does not stay at 2 after the first trigger.

is it possible that at some point your program is crashing, reseting the processor and resetting Int_On_2 back to 0 - try putting a Serial print at the start of setup() so you know when the program starts executing

1 Like

Hi Horace

 Serial.begin(9600);
  Serial.println("Start");
  PORTB ^= (1 << led_pin);

You are right - it is resetting! Monitor shows Start 00 Start 00 ad nauseam. Why - Not a clue yet. I guess comment out lines until it starts behaving!

Re Paul - scope shows a nice square pulse when placed near the spining spindle motor although positioning seems to be critical.

I'll post when/if I find the culprit!

Thanks Guys

It is normally due to interference pick up. This is common when motors are involved.

Try and use a separate power supply for any motors and beef up your supply decoupling.
If the motors only turn one way, which seems likely as it is a CNC machine then make sure you have a fly back diode across the motor.

I have had similar problems when operating relays when then operate motors - ended up using shielded cabling between the relays and the motors

Guys


  //   Eable Timer1 compare interupt

  TIMSK1 = (1 << OCIE1A);       This  is the culprit!!!!!

Test done with motor not running but I take the point of motor noise. I didn't even have to manually trigger the sensor. Processor resets with this in line.

I copied the timer code from https://www.youtube.com/watch?v=2kr5A350H7E

More research I think!

Note: This is equivalent to:
PINB = 1 << led_pin;
This is a special feature of the PINx registers on the AVR processors. If you write a 1 into any bit(s) it will toggle the corresponding PORTx bit(s). This saves a read/modify/write cycle.

1 Like
ISR(Timer1_COMPA_vect) {

Compiler is complaining a bit, TIMER1_COMPA_vect is the correct capitalization.

  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
    // code with interrupts blocked (consecutive atomic operations will not get interrupted)
    Serial.print(Int_On_2);
    rpm = round(rpmfloat * 120);
  }

May want to take the Serial.print out of the section where interrupts are disabled.

1 Like

David

That made it burst into life. Thank you. Strange that my compiler (1.8.16) did not error this. I've just changed compiler warnings to ALL but it still did not complain when wrong case.

It's not an error.

I'm not really sure what the compiler does in the final code as a result of this.

warning: 'Timer1_COMPA_vect' appears to be a misspelled 'signal' handler, missing '__vector' prefix [-Wmisspelled-isr]
 ISR(Timer1_COMPA_vect) {
     ^

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.