analogWrite in else clause executes only if I leave a debug line in

I am programming a small motor controller to drive a leadscrew. Mega2560 board, and have come across an odd bug.

This fragment of the code is from the Run-Stop switch, and is executed every pass - there is no delay in the loop only While statements for timing. It is programmed to behave as a novolt switch i.e. if the switch is at run when the code starts up, it needs to go to stop and back to run before the motor starts.

There are four boolean flags
LSnovolt true if the switch has been to Stop since startup
LSrunstate true if the motor is running
LSstarting true if the motor is starting up - I use it to control a ramp start
LSstartnxt true if the motor is stopped - used to trigger the starting sequence

The strcopy() line was inserted into the code for debugging purposes early on, and the code shown here works as designed. I no longer need the strcopy() line.

However if I remove it - or comment it out the analogWrite in the else clause is never executed. The other code in the else clause is executed. Leave the strcopy in and it all works fine.

strcopy only appears in two places in the sketch. Here and as a declaration
char runstop[5] = "stop"; //for debug
at the beginning.

Anyone with any clue as to what might be going on?

//read run stop switch every pass.

  if (digitalRead(LSrunpin) == HIGH) {  //if High switch is at run
    LSrunstate = LSnovolt;  //Lead screw runstate stays false unless LSnovolt is true
    if (LSstartnxt) LSstarting = LSrunstate;   //if running and LSStartnxt is set, then tell motor to execute startup routine
     LSnovolt = LSnovolt;
     strcpy(runstop, "run "); //for debugging
   
  }

  else {
    LSnovolt = true;   //Leadscrew switch at stop so novolt can be set true
    LSrunstate = false;  //Turn everything off
    strcpy(LSrunstring, "Stop");
    analogWrite (LSmotorpin, 0);  //and tell the motor to stop
    LSstarting = false;  //for Debugging?
    LSsetpoint = 0;
    LSpowervalue = 0;
    LSstartnxt = true; //set up to restart

  }

Not me without seeing your complete sketch

Did you mean:


    if (LSstartnxt) 
     {
     LSstarting = LSrunstate;   //if running and LSStartnxt is set, then tell motor to execute startup routine
     LSnovolt = LSnovolt;
     strcpy(runstop, "run "); //for debugging
     }

Larry - yes I did mean what I wrote. I want LSnovolt to remain unchanged regardless of the state of LSstartnxt

UK Helibob

Here you go

// ---
// Leadscrew Motor Startup Test on Mega2560 board
// 10 Aug 2021 fixed line 144 needs strcopy() God knows why
// Simple test of  Starting Leadscrew Motor.
// Run Motor at full power until Startpulses received then swap to demand power.
// Demand set with simple pot for now.
//
// Uses 4 * 20 LCD for communication
// LiquidCrystal_I2C.h: https://github.com/johnrickman/LiquidCrystal_I2C
#include <Wire.h> // Library for I2C communication
#include <LiquidCrystal_I2C.h> // Library for LCD

// Wiring: SDA pin is connected to SDA (20) and SCL pin to SCL(21).
// Connect to LCD via I2C, default address 0x27 (A0-A2 not jumpered)
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 20, 4); // Change to (0x27,16,2) for 16x2 LCD.

// Motor wiring. Red =12v, Black = Gnd connect to arduino ground
// White is change direction. Manual for now. Turn power off before grounding(?)
// Blue is PWC output to motor control connect to Arduino pin 5
volatile byte LSmotorpin = 5;
//yellow is FG pulse signal - use Timer 5 via pin 47
byte FGpulsepin = 47;
// No of pulses at full power to start up  motor ( 9 pulses/rev of motor)
int Startpulses = 175;

//Speed input via Pot slider connects to pin A0
const int LSSpeedInPin  = A0;      //Speed input potentiometer pin
int potvalue = 0;                //input value read

//variables for timing loop
unsigned long Loopmillisecond;  //milisecond store for last time loop ran
int Loopwait = 500; //length of wait between refreshes (every half second)

//Basic variables for Leadscrew speed measurement
volatile unsigned long LSlastmillisec = 0; //value of  millisec last time counter cleared
unsigned long LSthismillisec = 0; //new value of milisec
int t5count = 0; //number of pulses counted since LSlastmillisec
float lsrpm = 0; //Leadscrew rpm figure
float LSelapsed = 0; //for floating point calculation
char lsrpmstring[6] = "000.0";

//Control variables for Leadscrew Power
int LSsetpoint = 0; //Lead Screw Set point
int LStarget = 0;   //Lead screw operator target
volatile byte LSpowervalue = 0; //Lead Screw PWM Power out
volatile byte LSRunpower = 0;  //remember Powervalue for interrupt
volatile byte LSKickvalue = 180; //startup value for initial kick
bool LSstartnxt = true; //flag to initiate start sequence
volatile bool LSstarting = false; //flag set when motor is in start phase

// Includes Run/Stop/Novolt code
// Leadscrew Run Stop variables
byte LSrunpin = 2; //switch short to ground for RUN O/C for Stop
bool LSrunstate = false;
bool LSnovolt = false;  //stays false until switch goes to stop
char LSrunstring[5] = "Stop"; //string for Run/Stop status

//debugging
char runstop[5] = "stop"; //for debug
int temp=0; //for debug

//Output Array for Display
char line0[21];
char line1[21];
char line2[21];
char line3[21];

// Update display routine
void updatedisplay() {
  lcd.setCursor(0,0);
  lcd.print(line0);
  lcd.setCursor(0,1);
  lcd.print(line2);
  lcd.setCursor(0,2);
  lcd.print(line1);
  lcd.setCursor(0,3);
  lcd.print(line3);
}

// Interrupt service routine for timer 5 overflow at leadscrew start goes here <----------
//Uses Timer 5 with OCR5A as TOP  //this needs work
//Initialised when Leadscrew Run/Stop goes to Run
//Reset leadscrew motor and speed counter to count mode (Clear bit 3 in TCCR5B)
ISR(TIMER5_COMPA_vect)
{
  LSstarting = false;  //reset the starting status
  LSpowervalue = LSRunpower; //reset power value to target
  OCR3A = LSpowervalue; //adjust motor power
  TCCR5B = TCCR5B & B11110111  ; //clears the bit that enables OCR5A CTC mode - goes to count mode.
  TCNT5 = 0; //reset pulse counter to zero
  LSlastmillisec = millis(); //set timing of reset
  TIMSK5 = TIMSK5 & B11111101; //disable interrupt
  
}

void setup() {

  
  // Initiate the LCD:
  lcd.init();
  lcd.backlight();

  //Enable runpin with pullup
  pinMode(LSrunpin, INPUT_PULLUP);
  LSnovolt = false; //don't start at init regardless of switch position

  //Set Up leadscrew motor and speed counter
  pinMode(LSmotorpin, OUTPUT); //set up motorpin as output
  TCCR3B = TCCR3B & B11111000 | B00000010;  // for PWM frequency of 32khzHz on D2,D3 & D5
  OCR3A = 0; //turn off power


  //set up to read speed pulses
  pinMode (FGpulsepin, INPUT_PULLUP); //input pin for timer
  TCCR5A = B00000000;  //Ensure normal mode
  TCCR5B = B00000000;

}

void loop()
{
  // Motor startup Code goes here to run once

  if (LSstartnxt && LSrunstate && LSstarting) {     //true if LSStartnxt has been set and LSrunstate has been called true
    //set up pin 47 to interrupt after Startpulses
    TCNT5 = 0; //reset the counter to zero
    OCR5A = Startpulses; //set up counter for number of pulses at full power
    TCCR5B = B10001110  ; //clock timer 5 on external rising edge for speed pulses CS10,11,12 see P 154 in manual high bit enables noise suppression bit 3 enables CTC mode
    TIMSK5 = B00000010; //enable interupt on match
    LSsetpoint = LStarget; //set setpoint to current target
    LSRunpower = map(LSsetpoint, 0, 100, 0, 255); //Map to LSRunpower for once started
    LSpowervalue = LSKickvalue; //set power for startup kick
    LSstartnxt = false; //clear flag so we only do this once
    analogWrite (LSmotorpin, LSpowervalue);  //and tell the motor to go

  }

  //read run stop switch every pass.

  if (digitalRead(LSrunpin) == HIGH) {  //if High switch is at run
    LSrunstate = LSnovolt;  //Lead screw runstate stays false unless LSnovolt is true
    if (LSstartnxt) LSstarting = LSrunstate;   //if running and LSStartnxt is set, then tell motor to execute startup routine
     LSnovolt = LSnovolt;
     strcpy(runstop, "run "); //for debugging  IF COMMENTED OUT analogWRITE FAILS TO EXECUTE
   
  }

  else {
    LSnovolt = true;   //Leadscrew switch at stop so novolt can be set true
    LSrunstate = false;  //Turn everything off
    strcpy(LSrunstring, "Stop");
    analogWrite (LSmotorpin, 0);  //and tell the motor to stop
    LSstarting = false;  //for Debugging?
    LSsetpoint = 0;
    LSpowervalue = 0;
    LSstartnxt = true; //set up to restart

  }


  while (millis() > Loopmillisecond + Loopwait) {  //every Loopwait miliseconds
    Loopmillisecond = millis(); //update the time

  
 
    //get the speed demand
    potvalue = analogRead(LSSpeedInPin);
    //map values between in and out
    LStarget = map(potvalue, 0, 1023, 0, 100);

    //if running normally (LSStarting is false) so reset variables
    if (LSrunstate && !LSstarting) {
      LSsetpoint = LStarget; //set setpoint to current target in case it's changed
      LSpowervalue = map(LSsetpoint, 0, 100, 0, 255); //Map to Powervalue
      strcpy(LSrunstring, "Run  ");

  

      //control the motor
      analogWrite (LSmotorpin, LSpowervalue);


  
  
      // and compute the leadscrew motor speed
      LSthismillisec = millis(); // time now - may overflow after 50 days running!!
      t5count = TCNT5; //grab the count
      TCNT5 = 0; //reset to zero
      LSelapsed = LSthismillisec - LSlastmillisec;
      lsrpm = (t5count * (111 / LSelapsed)); // calculate speed
      LSlastmillisec = LSthismillisec;  //remember the time
      dtostrf(lsrpm, 5, 1, lsrpmstring); //output shaft speed to one decimal place for display

    }
    
    // Print data values on LCD   //Needs Work  <-----------------

    sprintf(line0, "Switch= %-5d", t5count);
    sprintf(line1, "Power= %-5d " , LSpowervalue);
    sprintf(line2, "Leadscrew= %s", lsrpmstring);
    sprintf(line3, "LS target= %-4d %s", LSsetpoint, LSrunstring);

    updatedisplay();
  }


  //otherwise wait for the interrupt

  // The End
}

Hello,

strcpy(LSrunstring, "Run  ");

Size of LSrunstring is 5 and

"Run  "

is 6 characters including the null, so this line is possibly the cause of your issue

Thanks a million guix - that fixed it.

What is the purpose of:
LSnovolt = LSnovolt;