I am writing the following program to cause a model to run backwards and forwards along a track. There are two sensors towards the end. The model needs to move over the sensors, slow down, stop, reverse and run back.
The program runs well, except that I cannot make Case 1 only run the SlowDown function run only once, no matter where I put the RunFlag flag. Presumably the subsequent cases also will have the same problem but I haven't got that far in testing it.
Can anyone tell me where I am going wrong, or suggest ways to make it happen.
Thank you in advance.
#define EXE_INTERVAL 20000
unsigned long lastExecutedMillis = 0; // variable to save the last executed time for code block 1
int MotorRun = 11;
int Direction1 = 8; //Not needed?
int Direction2 = 13;
int HallPin = 2;
int Speed = 60;
int MaxSpeed = 100;
int sensorVal = 0;
int HallPinCounter = 0; // counter for the number of button presses
int HallState = 0; // current state of the button
int lastHallState = 0; // previous state of the button
int Millis;
unsigned long currentMillis;
unsigned long previousMillis = 0;
const long Dwell = 3000;
int pass = 0;
int Value = 0;
bool RunFlag = false;
void setup() {
Serial.begin(9600);
pinMode(MotorRun, OUTPUT);
pinMode(Direction1, OUTPUT);
pinMode(Direction2, OUTPUT);
pinMode(HallPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(HallPin), Passes, RISING);
currentMillis = Millis;
}
void Passes() //counts number of passes
{
{
static unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > 500) {
HallPinCounter = HallPinCounter + 1;
Check();
}
last_interrupt_time = interrupt_time;
}
}
void Check() {
if (HallPinCounter > 4) {
HallPinCounter = 1;
}
}
void Pause() {
unsigned long currentMillis = millis();
if (currentMillis - lastExecutedMillis >= EXE_INTERVAL) {
lastExecutedMillis = currentMillis; // save the last executed time
Serial.println("Code Block executed");
}
}
void FWD() {
digitalWrite(Direction2, HIGH); //Establishes forward direction of Channel B
digitalWrite(Direction1, LOW); //Disengage the Brake for Channel B
{
}
}
void REV() {
digitalWrite(Direction2, LOW); //Establishes backward direction of Channel B
digitalWrite(Direction1, LOW); //Disengage the Brake for Channel B
{
}
}
void Accelerate() {
for (Speed = 60; Speed <= MaxSpeed; Speed++) {
analogWrite(MotorRun, Speed);
delay(100);
}
}
void Decelerate() {
for (Speed = MaxSpeed; Speed >= 0; Speed--) {
analogWrite(MotorRun, Speed);
delay(100);
}
}
void Run() {
analogWrite(MotorRun, MaxSpeed);
}
void Stop() {
analogWrite(MotorRun, 0);
delay(10000);
}
void SlowDown() {
Serial.println("Decelerating now");
Decelerate();
Serial.println("Stopped now");
Stop();
Serial.println("Reversing now");
REV();
Serial.println("Accelerating now");
Accelerate();
RunFlag = true;
}
void loop() {
switch (HallPinCounter) {
case 0:
if(RunFlag == false)
{
Serial.print(" No passes yet ");
FWD();
Accelerate();
}
RunFlag = true;
Run();
break;
case 1:
RunFlag = false;
{
if(RunFlag == false)
{
Serial.println(" The first pass");
SlowDown();
RunFlag = true;
}
}
Run();
break;
case 2:
RunFlag = false;
Serial.println(" The second pass");
FWD();
Run();
break;
case 3:
RunFlag = false;
Serial.println(" The third pass");
Decelerate();
REV();
Run();
break;
case 4:
RunFlag = false;
Serial.println(" The fourth pass");
FWD();
Run();
break;
}
}
So that each function, apart from Run, can be checked to run only once. RunFlag is set to true after each iteration.
Thank you for your attention.
Tony
This variable is used in your ISR and regular code so it needs to be declared volatile
You should also declare it of type byte vs. int so you can atomically access it without having to pause interrupts, make a copy, and restart interrupts
but it looks like you have all the sensors tied together. Doesn't that make it difficult to know exactly which sensor is being tripped?
why not at least use 2 inputs one for the slow down sensor and the other for the stop sensor .. at both ends?
knowing what direction the train is moving allows you to ignore the slow-down sensor after the train has reversed
Sorry, my poor wording. There is one sensor at each end. Yes, they are tied together, that is why I count the number of times the sensors are triggered. At each time a new case is created and I am trying to run the relevant functions for each. The model needs to slow down before stopping and will pass the sensors before coming to a halt, then reversing etc.
Thank you for your time.
if there's only one sensor, how do you know exactly where to stop?
if that doesn't really matter, then there's no need to monitor the sensor until after the train has reversed direction and then tripped the sensor again, possibly more than once and is past the sensor.
you could also just wait some appropriate # of seconds for the train to trip the sensor, reverse and safely move past the sensor
When you power up the system, do you guarantee that the train is somewhere in the middle? If you power up the system with the train at either end, you may not get any sensor readings or need two sensor readings before slowing, stopping, reversing, depending on which end the train starts and which direction it starts moving.
Stopping will be determined by the deceleration function. It doesn't have to be exact. By counting the number of passes over the sensor I am able to ignore the 2nd counts.
But you set it to false and then immediately test its value. What do you expect its value to be other than false ?
Declare it as a global variable with a value of true and only set it to false just before you enter the case. Only run the case code if its value is false and set it to true in the case code. That way the case will not run again
That is what I have been trying to do but it doesn't seem to work. I have tried the test in various places, and in various functions, but it doesn't seem to make much difference. Each function repeats.
For example. In case 1, the flag is tested for being false, the function (SlowDown) runs, the flag is set to true but the function (SlowDown) still repeats.
Thank you for taking the time to look at this problem. Would you like me to post the whole program again, reformatted but essentially the same. or just the case?
case 1:
RunFlag = false;
{
if (RunFlag == false) {
Serial.println(" The first pass");
SlowDown();
RunFlag = true;
}
}
Run();
break;
```The reason I am attempting to solve this problem is so that I can use the same technique on the other functions.