Preventing delay() from blocking programs - Arduino.

Discussion in 'Embedded Systems and Microcontrollers' started by SalceyForest, May 13, 2016.

  1. SalceyForest

    Thread Starter New Member

    Nov 6, 2015
    11
    2
    I've got a confession, I don't have an Arduino and have never programmed one but http://www.allaboutcircuits.com/projects/build-a-desktop-industrial-automation-trainer/ has caught my eye, as have many examples in here. This post uses an Arduino to sequence through a hard-coded output list, with each transition delayed by a second. Unless interrupts are involved, the controller is just stuck there during that second, doing nothing and responding to less. All this is a general problem relating to the difference between electronics and the real world. In real life, things move sloooowly!

    What I've done here is replace the delay() block with a simple test. If the time isn't up yet, the processor can go and take can of other business. As part of a full solution, this can make the difference between a sulky, sluggish unit and a lively, responsive one. Imagine looking for a button press during the delayed part of the process.

    While I was at it, I used an array of timers, allowing a different time for each step. What I haven't done is actually try it, I wonder if someone could give it a go and point out any glaring errors?

    Code (Text):
    1. /*  3 INPUT LOGIC GATE SIMULATOR
    2. *  APRIL 8, 2016
    3. *  BY DON WILCHER
    4. * modified May 13th by Steve Root
    5. *
    6. * This code will provide digital inputs to the  Velocio ACE PLC (Programmable
    7. * Logic Controller) using the following Truth Table Inputs.
    8. * The output of the Logic Gate will be visible by the integrated
    9. * LED of the ACE PLC.
    10. *
    11. *           3 Input Logic Gate Simulator
    12. *                 INPUTS
    13. *                A |  B | C
    14. *               ___|____|____
    15. *                0 | 0 | 0
    16. *                0 | 0 | 1
    17. *                0 | 1 | 0
    18. *                0 | 1 | 1
    19. *                1 | 0 | 0
    20. *                1 | 0 | 1
    21. *                1 | 1 | 0
    22. *                1 | 1 | 1
    23. *
    24. */
    25.  
    26.  
    27. // Arduino Pin assignments
    28. int A = 13;
    29. int B = 12;
    30. int C = 11;
    31.  
    32. // Timer declaration
    33. bool SeqTimer(int, bool *);
    34.  
    35. // Timer definitions
    36. #define NUMTIMERS 8
    37. unsigned long TimeDelays[NUMTIMERS}={1000000, 500000, 200000, 100000, 100000, 200000, 500000, 1000000);
    38. int tIndex = 0;
    39. bool tReset = true;
    40.  
    41.  
    42. bool SeqTimer(int tIndex, bool *tRst)
    43. {
    44.     static unsigned long TargetList[NUMTIMERS];
    45.  
    46.     if(*tRst== true)
    47.     {
    48.         TargetList[tIndex] = micros() + TimeDelays[tIndex];
    49.         *tRst= false;
    50.     }
    51.     else
    52.     {
    53.         if(micros() > TargetList[tIndex])
    54.         {
    55.             return true;
    56.         }
    57.     return false;
    58.     }
    59.  
    60. void setup()
    61. {
    62.   // initialize digital pins 1, 2, and 3 as outputs
    63.   pinMode(A, OUTPUT);
    64.   pinMode(B, OUTPUT);
    65.   pinMode(C, OUTPUT);
    66. }
    67.  
    68. void loop()
    69. {
    70.     if (SeqTimer(tIndex, &tReset) == true)
    71.     {
    72.         tIndex++; // Next timer in list
    73.         if(tIndex >= NUMTIMERS)
    74.         {
    75.             tIndex = 0;
    76.         }
    77.         // write the outputs
    78.         if(tIndex & 0x1) DigitalWrite(C, HIGH);
    79.         else DigitalWrite(C, LOW);
    80.         if(tIndex & 0x2) DigitalWrite(B, HIGH);
    81.         else DigitalWrite(B, LOW);
    82.         if(tIndex & 0x4) DigitalWrite(A, HIGH);
    83.         else DigitalWrite(A, LOW);
    84.         // Timer will reset on next scan
    85.         tReset = true;
    86.     }
    87. // else do other stuff!
    88. }
    89.  
     
    Last edited: May 13, 2016
  2. Don Wilcher

    Member

    Jun 22, 2015
    33
    4
    Hi SalceyForest,

    Thank you for your input. The idea behind the project was to introduce an introductory lesson on Programmable Logic Controllers to the novice. As a Technical Educator, my goal is to teach basic concepts in electrical-electronics with application emphasis on robotics and industrial automation principles. As an Electrical Engineer, I am acutely aware of advanced software programming techniques used in embedded controllers. The overall goal of the project was to allow the reader to build a low cost and uncomplicated programmable Industrial Automation Trainer. Basic programming concepts and techniques were the secondary educational goals for the project.

    You have identified a potential problem (depending on the application) which warrants testing. Though you do not have the Arduino, you can use the Arduino compiler (website: Arduino.cc) to ensure that your programming instructions are compatible with the Arduino library functions. If there are problems, the compiler will flag the errors. As a recommendation, please provide solutions that have correct validations rather than offering only criticism of a fully functional and tested application. Suggestions have no value if you have not properly tested but only speculated. I've worked on multi-million dollar industrial, consumer, and automotive embedded systems. If I had ever presented such a solution without proper validation results, my engineering qualifications and knowledge would have been scrutinized after that. Validation is an essential habit for the professional or the novice practitioner.

    I appreciate your readership and the offer of a more advanced programming technique. Bear in mind; however, that the difference in time is not critical and removes visibility of the function for the novice programmer. I think your proposal is interesting, and I’d like to offer a challenge to other readers to test your code and provide additional feedback. I am accepting my own challenge and will report on your coding, soon.
     
  3. dannyf

    Well-Known Member

    Sep 13, 2015
    1,779
    360
    you could use the millie() function to do it.

    for example:

    Code (Text):
    1.  
    2.  
    3. uint8_t isTime0(unsigned time eTime) {
    4.   static unsigned long pTime=0; //previous time
    5.   unsigned long tmp=millis(); //take current time
    6.  
    7.   if (tmp >= pTime + eTime) {  //enough time has elapsed
    8.     pTime=tmp; //save the current time
    9.     return 1;  //time's up
    10.   } else return 0;
    11. }
    12.  
    You can copy the same routines over a few times for addition "timers".

    Alternatively, use a struct to hold the values and one timer routine will work.
     
  4. SalceyForest

    Thread Starter New Member

    Nov 6, 2015
    11
    2
    Hi Don, thanks for your reply and the slap on the wrist!

    Please appreciate that the post was not a criticism of your article per se, which was after all on a mostly unrelated topic, but actually of the very provision of a function in the library (almost all libraries) which is specifically designed to stop the hardware dead in its tracks. The work-round is small enough to be trivial and from my own experience (PICs, not Arduinos, and not at home) can vastly improve overall functionality. Sorry about the lack of validation, but I thought the principle was important. Thanks for offering the advice about Arduino.cc which I will take up tomorrow.

    As a ps, I'm aware of a small style error which has given a SeqTimer input parameter the same name as a global variable. Poor style but it will still work.
     
  5. SalceyForest

    Thread Starter New Member

    Nov 6, 2015
    11
    2
    I used micros because why not, basically! I don't see what advantage can be had in copying routines over simply #defining a different number?
     
  6. dannyf

    Well-Known Member

    Sep 13, 2015
    1,779
    360
    Because your implementation isn't terribly efficient.

    Adapting my routine to your application would be something like this:

    Code (Text):
    1.  
    2.   if isTime0(TimeDelays[index]) {//time is up
    3.     //do something
    4.     index=(index>=NUMTIMERS)?0:(index+1); //advance index
    5.   } else {  
    6.     //time is not yet up
    7.     //do someting else
    8.   }
    9.  
     
  7. Don Wilcher

    Member

    Jun 22, 2015
    33
    4
    SalceyForest:
    Thanks for your reply. I'm definitely interested in validating your code alternative. I do appreciate you posting a comment. When time permits, I will do the validation and let you know of the results. Please keep commenting!!!!
     
  8. Don Wilcher

    Member

    Jun 22, 2015
    33
    4
    SalceyForest:
    Thanks for your reply. I'm definitely interested in validating your code alternative. I do appreciate you posting a comment. When time permits, I will do the validation and let you know of the results. Please keep commenting!!!!
     
  9. Don Wilcher

    Member

    Jun 22, 2015
    33
    4
    Hi dannyf

    Thanks for providing an alternative code solution. Once the validated, I let you know the results. Thanks and keep commenting!!!
     
Loading...