C programming question for Arduino

This varies with manufacturer/implementation. Some implementations make the "output image" available to "subsequent rungs" *before* the hardware is updated. This allows implementations that have predictable rung scan orders to allow rungs to act like "sequential statements" in a procedural language.

E.g. (fixed width font):

Start Stop Run

+---[ ]--+---[/]--------( )---+ | | | | | | | Run | | +---[ ]--+ | | | | Run Motor | +---[ ]-----------------( )---+

causes "Motor" to be active "shortly after" Start is pressed (actuating "Run") *without* requiring another pass around the big_loop() to transfer the "output image table" to the physical outputs.

This sort of thing can lead to races as the order in which you arrange the rungs determines how the logic works.

A more intuitive form might be:

if ((conditionA || !conditionB) && ConditionC) { turn on output; } else { turn off output; }

And, for something this straightforward:

output = (conditionA || !conditionB) && ConditionC;

I would wrap this in a function invocation:

void rung28(void) { output = (conditionA || !conditionB) && ConditionC; }

so that big_loop just consists of a bunch of rungX()'s

The equivalent is:

void rung28(void) { if (!timer_expired(TIMER_ID)) return;

output = (conditionA || !conditionB) && ConditionC; }

So, timer_expired() just checks to see if there is any time remaining on timer #TIMER_ID. If so (timer NOT expired), then you just take an early exit from the function ("rung28()").

If you try to actually *watch* the current time, then you need to store an "expiration time" for each timer. Or, track it yourself, manually, and pass it as a parameter to timer_expired():

I.e., timer_expired(expiration) then becomes:

return (now > expiration);

Or, timer_expired(TIMER_ID) becomes:

return (now > timer[TIMER_ID]);

The problem with tracking it yourself is that you may want to set/specify an expiration time in one place and "wait on it" somewhere else. You have to propagate that *time* to the other place instead of just saying "wait for this TIMER"

Imagine setting up a rung that blinks a light at a certain rate. And, wanting to be able to blink the light at two

*different* rates to indicate two different "conditions". Using a TIMER_ID in the blink "rung()" lets that code ignore the details of the actual blink rate.

(this depends on how you implement your timers)

Reply to
Don Y
Loading thread data ...

It's very simple...

each rung has a destination results with no expected delay of information. All information required per rung is available. The logic with in each rung does not allow for any such process of loops that would other wise hold a program in place.

The whole idea of capturing external values and maybe some internal values to be fixed through the scan is the best solution, because there would never be any thing that can change with in the middle of a rung or multiple rungs or complete scan of all the page files.

The only items that change are those items that were captured at the start of a scan,which the OS of the PLC does that for you, you may change a value to one of these external events that were captured so that the remaining rungs that have not yet been scanned will see this change, But nothing is actually changed on the out side.

No loops there by waiting for an event that only takes place in some hardware timer or out side IO.

Talking about timers, All timers that have been started have their current values frozen at the start of the scan. No timers change while scanning down through the rungs. However, you can change a value of some timer that has been froze so that when you reach the end of all rungs, the timer will simply pick up and start from the change or from what ever it was before. These are ladder timers I refer to, not back ground real time timers, which you normally only have a couple of but with those you can make many software one's which is what the Ladder code uses for the most part. There are special timers/counters you can get to.

The only data that changes in real time while the rungs are being scanned are things like background communications, handling the hardware stuff. But any data you expect to read from this hardware is cached to be view only on the next scan cycle of the ladder program.

In other words, the Ladder never stops on a resource waiting for something specific to happen there by, holding up the rest of the system, that would be dangerous in many cases.

PLC controllers do not execute native code, that code you down load to the controller is like a form of P code.

There is very little a PCL does that could actually place a stall on your ladder code and that would be out of your hands. If things like that happens, there is something wrong and a watch dog timer kicks in and most likely will force a fault on the PLC and stop the ladder program. When this happens, all outputs on the PLC are switched off. SO you're suppose to tie in a interlock with one of the outputs.

You can have things like function blocks that contain FOR Loops to do a restricted amount of code. You can also have what looks like an INT service block and that still shares between the standard scan and INT's

When it comes to INT"s, what the system does is instead of doing a schedule ladder scan, it will call a INT block if a defined event like an external trigger took place on a input. The PCL will not wait for the schedule event. Doing that, the system still does the initial load of all the current inputs and outputs in cache before it goes to the ISR block.

Many PLC's also have a command that can force a early scan at the end of the ISR so to get things moving sooner.

BUt, You'll never see something like

While !(I:100.01) do; // where I:100.01 would be an INPUT for example.

That could really screw things up if the input does not come on in short time, that is, even if that command was doing real time hardware reads.

You simply do test and set a results on the test, you never loop to wait for the value to change to what you want.

All this can be done in a uC with C language with no problem. You just need to code with no wait loops.

Jamie

Reply to
Jamie

You can get high speed high accuracy timer modules. They normally come with IO also attached to the module and what you can do is, you can program that module via talking to the address space of some specific indexes to set the timers count scale, alarm trigger value, have it stop/start on external events attached to its module and also activate an output on its module. This has been with operating servo's in many cases.

Mean while, the main CPU/processor can go and get cached information on the module while it remains operating..

Years ago, Seimens did this with their S5 line, They may still be doing this now? But you could have one of the modules be a hardware timer that can be read and controlled via the main CPU STL (step language) code, but it can run on its own. Some of them even have hardware trimmer knobs you can set on them to adjust values instead of changing the code in the processor.

Jamie

Reply to
Jamie

Way back when I was writing cooperative multitasking OS for 8-bit microcontrollers I had several IRQ run decrement towards but not below zero counters. This let me specify timeouts without regards to the overall control loop, as each 'process' had its own reference to the notion of passing 'real time'.

Of course the down side to writing cooperative multitasking was that each 'process' had to run a state machine in order to yield when there was nothing to do.

The main loop was simply a list of call statements.

Implemented as above, races could not occur. One reentrant task locked the 'gate' into accepting further calls; that's a far as I wanted to go while writing multitasking code in assembler.

Sorry, it is decades since I was warped into programming an industrial controller :) ... OT, very OT for this group :)

Grant.

Reply to
Grant

I inevitably have a "system time" that is updated by the jiffy. So, there are only two pieces of code looking at/modifying this variable: the IRQ and the *one* "task" that examines it and conveys that value to the timing subsystem. (This cuts down on the number of mutexes that have to be invoked to transact with this datum)

The timing subsystem periodically (e.g., if a "big_loop" implementation, then it is invoked "once per iteration") and updates the "armed" timers to reflect the time that has passed (present_system_time - previous_system_time). This can be done via delta queues or simple brute force (subtract elapsed_time from all timers and clamp result at 0).

[if a preemptive implementation, I make ready any tasks waiting on timers, etc.]

This allows tasks to examine timers (in a big_loop) without having to worry about the timer being updated *while* it is being examined (since the timer task has run "elsewhere" in the loop).

A timer then becomes just another entry in an array of timers (for example). Very low overhead. And, piggy backs on *one* ISR (only to update the "system_time" variable -- also an inexpensive operation)

The problem with this approach is that you can't measure *elapsed* time with these timers because they use saturated arithmetic.

OTOH, they are really easy to set, abort, test, etc.

Yes. Hence my analogy, here, to "a list of function invocations".

Ditto. For me, a 1771 (or maybe it was a 1772? The CPU had one number while the field modules had the other number) in the mid 80's. The cost was ridiculous and the capabilities so limited that it was (IMO) a silly way to do things!

Reply to
Don Y

a·nal·o·gy, noun: a similarity between like features of two things, ON WHICH A COMPARISON MAY BE BASED: e.g., the analogy between the heart and a pump.

I didn't find *your* ANALOGY in the above.

It would be like a cardiologist describing the role of calcium and potassium ions in how the sinoatrial node's action potential is conducted, first, to the atrioventricular node as the atria contract and, then, through the ventricular endocardium to the myocardium to bring about the contraction of the ventricles and the ultimate repolarization of the heart at the start of the next cycle (um, "beat").

Wanna bet "the heart is like a pump" conveys far more useful information than all of the above?

Reply to
Don Y

Hi Roger,

Yes, this is what I'm talking (err typing) about, the loop is scanned as fast as possible and the sequence is controlled by when conditions come true, not when the processor happens to get there. I figure the above would execute in a few microseconds.

Here's an example: I have a 24 bit A/D converter connected to my Arduino. My function to read the A/D consists of sending a conversion command, waiting on ready, reading the value into bytes, calculating long analogIn = byte3 * 65536 +byte2 * 256

  • byte1;

I want to change this to something like:

If(adtimer.dn) startConversion(); // after whatever timer is done, start the A/D conversion process.

if(conversionready) analogin=readAD();

This way I'm not wasting time waiting on the conversion to be ready.

I have it working OK as my inefficient example above, I'm wanting to add a display and buttons.

I think I'll use a structure for the timer memory type and have a done bit like we use in PLC's. This way I can set up the condition to enable the timer, example a fault timer that ignores faults less than 1 second.

if(faultCondition) OnDelayTimer(faultTimer);

If (faultTimer.done) //trigger appropriate alarm. Some faults would be immediate and wouldn't use a timer.

In your blink example I could use fastblink.done and slowblink.done as the bits for flashing. Or the blink rate could be adjusted by changing blink.preset

Another example

GripperOpenOutput = (auto_mode && open_auto)||(manual_mode && gripper_open_button);

RogerN

Reply to
RogerN

The problem comes when condition is actually an expression -- and possibly including function invocations. Then, it gets harder to control the time required (especially if the functions are opaque).

I suggested wrapping "rungs" in void functions so that you could conceptually package everything associated with a rung in that function. E.g., if you want to maintain some "state" that the function examines and updates (without it becoming a formal "output"), you could embed the manipulation of that state in the function instead of exposing it in big_loop().

This is a perfect example of how wrapping this ALL in rung_ReadADC() can group the details of this "task" together (so you can conceptualize it as a single "job") without exposing the innards needlessly to unrelated bits of code.

For example (untested pseudocode):

void rungReadADC(void) { static state = UNINITIALIZED:

switch (state) { case UNINITIALIZED: // do whatever you need to do to set up the hardware state = IDLE; break; case IDLE: // hardware is ready, start the conversion startConversion(); load_timer(ADC_TIMER, ADC_INTERVAL); state = CONVERTING; break; case CONVERTING: if (!expired(ADC_TIMER)) break; // stay in the same state! state = READY; break; case READY: ADCvalue = readADC(); state = IDLE; break; default: /* NOT REACHED */ }

return; }

I.e., you have built a little "program" (task) that knows how to deal with an ADC. It doesn't care how fast the scan time is. It ensures the ADC's output is not read until ADC_TIMER has expired (if the scan time starts to get sluggish, it might end up reading the ADC far less often than you had hoped!)

It never does anything costly in any invocation (look at how little is in each state's "case").

And, if you need to modify it to, for example, support a front-end multiplexor, you can add states to switch the mux to the desired input (perhaps it routinely examines all N inputs and makes them available AT THE SAME TIME to the rest of the application -- instead of "staggered"), delay for some amount of time while the mux settles, then, later, advance to the CONVERTING state when you know the inputs are nice and stable.

The switch statement gives you finer control over how much/little gets done in any given invocation (i.e., "scan instance"). You can also *cheat* and have big_loop() look like:

big_loop() { ... rungReadADC(); rung27(); rung35(); rung78(); ... rungReadADC(); // !!!!! rung19(); rung44(); ... }

I.e., rungReadADC now gets twice as much CPU time as it would otherwise have had if it only appeared *once* in big_loop(). Yet, the above code continues to work properly regardless!

Reply to
Don Y

I got a timer working, also used the same data structure to make a counter.

Instead of longs I used ints and a time base. The time base simply uses the milliseconds divided by the time base. In other words, if you want to time in milliseconds, you use a time base of 1 and maximum time is 65535 milliseconds. If you want to time in seconds, the time base would be 1000 and maximum time should be 65535 seconds. So I guess this should also work for minutes with a time base of 60,000. Need more than that you can trigger a counter for hours, days, or whatever you want. I made the switch from longs to ints to save memory and because I don't need timers that can time a month with millisecond resolution.

I'll paste my Arduino program at the bottom, it blinks a LED, prints millisecond time, and counts 20 blinks before resetting the counter. My weird timer and counter names come from Allen Bradley PLC addressing (T4, C5).

Most of the loop time comes from the Serial.print statements, at 9600 baud I get ~ 12 millisecond loop time, at 38,400 baud I get 40 lines of print in

0.1 seconds, at 57,600 baud I get 1-2 millisecond loop time.

In my example I use a preset of 50 and a base of 10 for 1/2 second ON, 1/2 second OFF.

My guess is that others here will have some ideas for improvement. I'm pretty green at C programming but I think this kind of idea, timing without waiting & wasting processor clocks, can help to get a processor to do more tasks at once. In PLC programming I use mostly instructions that are the equivalent of ANDs, ORs, NOTs, plus timers and the occasional counters, shift registers...

// Timers & Counters, Testing Not Complete

struct timerdata { unsigned int accum, starttime; boolean TT,DN,EN; } T4_0, T4_1,C5;

void setup() { Serial.begin(9600); pinMode(13,OUTPUT); }

void loop() { Serial.print(millis()); Serial.print(" "); TON(&T4_0,!T4_1.DN,50,10); TON(&T4_1,T4_0.DN,50,10); digitalWrite(13, T4_0.DN); CTU(&C5,T4_0.DN,1000); Serial.println(C5.accum); if(C5.accum>=20)RES(&C5); }

int TON(struct timerdata *sp, int EN, int preset, byte base) // Time On Timer { if(!base)base=1; // no divide by zero if base unspecified //sp->preset = preset; if(!sp->EN && EN)// Enable has transitioned from falset to true { sp->starttime = millis()/base; sp->EN = EN; sp->accum = 0; } if(EN && !sp->DN) { sp->accum = millis()/base-sp->starttime; sp->DN=sp->accum >= preset; sp->TT = 1; } if(sp->DN)sp->TT=0; if(!EN) { sp->EN=0; sp->DN=0; sp->TT=0; }

}

int CTU(struct timerdata *sp, int EN, int preset)// Count Up Counter { //sp->preset = preset; if(!sp->EN && EN)// Enable has transitioned from falset to true { sp->accum++; sp->EN = EN; if(sp->accum>=preset)sp->DN=1; } if(!EN)sp->EN=0; if(sp->DN)sp->TT=0; }

void RES(struct timerdata *sp) { sp->accum=0; sp->EN=0; sp->TT=0; sp->DN=0; }

RogerN

Reply to
RogerN

be

=20

condition=20

timer,=20

=20

=20

some.

your

have

the

I=20

I think you are looking for a timer manager, a common component of a microkernel. Your data structure is more than sufficient. Add a linked list of times and keep track of the next one to expire and keep flags to the semaphore for that tasklet to execute. As they expire, you can "reset" them with a new call to set_timeout(). Yes, you are pretty close to writing a microRTOS.

?-)

Reply to
josephkk

I don't see the savings. You've just moved the "data" to a different place (i.e., the function invocation) -- which may be an acceptable trade (if the data can be const, there!).

However, your "base" is declared as a byte. Awful hard to represent "1000" -- to use units of "seconds" -- in a byte! :-/ Even harder to represent "60000" for units of minutes!

Unless you are specifically intending the code to be read and maintained by folks with that background, I suggest you adopt "friendlier" names. Code gets read more often than written so the cost of typing a few extra characters is peanuts if it improves comprehension.

These, presumably, are present in the Arduino library?

Point of style: typedef struct { unsigned int accum; unsigned int starttime; boolean TT; boolean DN; boolean EN; } timer_t;

Then, you can use: timer_t T4_0, T4_1, C5; as a nice shorthand.

Another point of style: timer_t T4_0; // timer used for ... ? timer_t T4_1; // timer used for ... ? timer_t C5; // counts number of blinks

It's arguable whether you want to use a different type for counters -- even if just in terms of *name* (to draw the distinction between the two conceptual types)

These will effectively determine the speed at which your loop can operate. Change the baudrate and you'll see that the loop speed will change.

If you *want* the timestamp of each loop invocation (iteration), then you have to do this (or something equivalent).

OTOH, if you only want to emit data when it won't otherwise impact your loop speed, then you have to resort to other mechanisms.

Gack! Take advantage of the obvious improvements in capabilities that this sort of programming environment offers and:

- get rid of the hard constants

- add some commentary

E.g.,

#define NUMBER_OF_BLINKS (1000) ... count(&blink_counter, blink_timer.done, NUMBER_OF_BLINKS);

is arguably more obvious in it's intent.

why is TON declared to return an int? why *doesn't* it? why hasn't your compiler warned you about this?

typedef unsigned int time_t; // represents a time

(N.B. this conflicts with other "standard" uses of time_t!)

typedef enum {MS = 1, SEC, MIN, HR, DAY, WK, MON, YR, CEN, MIL...) base_t;

void time( timer_t *theTimer, // points to timer's representation boolean enable, // false->true transition starts timer time_t duration, // duration of timer after enabled base_t units // units of measure used for this time_t )

switch (units) { case MIN: prescaler = 60 * 1000; break; case SEC: prescaler = 1000; break; default: // warn user he forgot to specify units? case MS: prescaler = 1; break; }

Note that your implementation has the consequence of forcing all starttime's to be truncated to the start of the *preceding* "time unit" (base). I.e., if you count in seconds and the *first* time this is invoked the millis() value happens to be "999" (i.e., the current time is 0.999 seconds), then your timer will record an entire second as having passed EXACTLY ONE MS LATER! (when millis()/1000 is now "1" -- previously "0")

This has consequences when viewed with respect to other co-operating timers. E.g., if one is using seconds and another minutes, then the relative errors in each will vary depending on when each is started.

Also, two timers started in two different TON invocations may or may not be in sync. E.g., trying to flash a light in one and beep in another could (or could NOT!) result in a phase difference between them if their respective "starttime" notions are different.

I mentioned this previously -- you may want to capture millis() in a pseudo-global variable at the start of the loop and have all of your timing routines refer to that, instead. This ensures that everyone in a single loop iteration has the same sense of "what time is it?" regardless of where in the loop their code executed!

For personal preference, I would also rewrite the code to make the state machine within it more obvious: moving from IDLE to ENABLED to DONE, etc. (what's the role of TT?)

HTH...

Reply to
Don Y

Hi Roger,

Is it possible to enter a number as a function parameter and assign it to the structure? There are 3 possibilities that I know of, assign the data before the function is called, use data as a parameter then move to structure inside of function, or if not needed in both places then just use it as a parameter for the function.

Originally I was planning to use the "base" as time base similar to the way it's used in PLC's, much like your "switch ... case" example below. In the Allen Bradley PLC5 they use a time base of 0.01 Sec, 0.1 Sec or 1.0 Sec time base, they also use signed integer for a preset but since I can't time to a negative time I went with unsigned. I had a "base" in the struct with the other unsigned int's, removed from the struct but forgot to change it in the function parameter.

In use I would use meaningful names but just for testing I used short names similar to what I work with, actually in the PLC it's the first timer is T4:0, it's done bit is T4:0.DN or T4:0/DN. If T4:0 was to be used for a global flashing bit for pushbutton lights, tower lights, to blink stuff on the operator panel, I'd assign it a symbol like "Flash".

Yes, it goes up to 115,200 but it doesn't run as well as 57,600 on my PC with all the line feeds. I saw some C source that includes Arduino.h, I've always used the Arduino environment and haven't tried programming the AVR in C by including Arduino's library.

Would probably be more memory efficient if I created a different struct for counters since I don't need "starttime".

Right, I went from ~12 millisecond loops to ~1 millisecond loops going from

9600 baud to 57,600 baud. Normally I wouldn't write to a display that often.

Yes, I added another timer I called printtime that I only print when the timer is done, so I can update the display at the time I preset.

Once I got the functions to compile, I wrote a quick and dirty loop to test it out. The counter was a quick and dirty afterthought I tried out. It does need some commentary though to help explain how it (is supposed to) work.

In future I would like it to be able to be used in an if() function, returning a 1 when done so the block after if() will execute after the timer is done.

I haven't put it in there yet, plan to have something like: return(*sp.DN);

It might have, the Arduino environment uses the GCC AVR compiler AFAIK.

It would be better if I could do something like used in Siemens programming. Their timer values are like S5T#1h30m25s for 1 hour 30 minutes and 25 seconds. They automatically select the time base that is required for that time. If you enter a time of 500 milliseconds, the time base will be milliseconds, etc. I don't remember all their time bases but they are more limited to 9,990 seconds with a 10 second time base. Out of a 16 bit word they use 3 digits of BCD and 2 bits are used for time base, other 2 bits, I don't know if they are used.

Would be nice to automatically use the highest resolution that will do the job. For up to 65535 milliseconds, use milliseconds, up to 655.535 seconds, use 10 millisecond, up to 6553.5 seconds, use 0.1 sec, etc. If someone needs better than that they can modify the function for long data types.

I thought about having a "housekeeping" loop at the beginning or end of the loop to update timers, etc. I'm guessing Allen Bradley does something like that since their timer data has only PRESET, ACCUM, and the bits, no start time. Is there a way for the program to know of every instance of the timer data type and update every timer ACCUM every loop? Maybe a for() going from first timer to last timer and setting accumulated value properly for each timer according to it's time base?

TT indicates that the timer is actively timing. It's enabled but not done yet. In my example of flashing the LED, I could alternate 2 LED's having 1 come on when T4_0.DN and the other come on when T4_0.TT.

Yes, helps very much, what I pasted was quick, dirty, and barely functional. It needs some refining, fixing, ... One goal is to get handy functional timers for my own use but I also want to encourage others to learn to program without tying up the processor waiting for one thing to happen.

Like instead of: Flash = 1; delay(500); Flash = 0; delay(500);

use the timers that don't hold up the processor so it can do other things until it is time for flash to turn on or off.

thanks!

RogerN

Reply to
RogerN

Hi Roger,

[much elided]

You can create types that have a hierarchical relationship. E.g., if a timer is a *counter* that has the additional characteristic of having a "starttime", then you can:

typedef struct { unsigned int accum; // boolean timing; redundant? timing = enabled && !done? boolean done; boolean enabled; } counter_t;

typedef struct { counter_t offset; unsigned int starttime; } timer_t;

So, much of the same "counter" code can be used to update a "timer_t" by passing the "offset" counter_t contained within the timer_t to that counter_t code.

[There are many issues with this simplification... :< ]

Since you (probably) don't want the "display" to dictate performance yet *probably* want to emit some sort of periodic "status" to the user, you can, instead, have a "task" (sorry to keep falling back on this term) that checks to see if the PREVIOUS "status update" has been conveyed to the user. And, if so, it can create a *new* status update message using sprintf() in lieu of printf() to fabricate the message in a *buffer*. At this point, you mark the "status update" activity as "in progress" (i.e., "not yet conveyed to the user"). Hereafter, that causes the output device to be examined to determine if it can accept more data (characters). If so, the next character(s) from the buffer are passed to the output device NEVER WAITING FOR THEM TO BE TRANSMITTED so that the "OS"/interrupt system can push them out while your code is doing other things.

Each time around the loop, you check to see if you can move another character(s) from the buffer to the I/O device. Eventually, all of the characters will have been moved from the buffer to the physical I/O device and you will declare the status update as having been "conveyed to the user" -- so, you can now prepare a

*new* update.

This approach throttles the update frequency to match the capabilities of the I/O device -- instead of throttling the "loop()" to match the capabilities of the I/O device.

[Of course, sprintf() is still a bloated pig but at least it doesn't also carry the overhead of the physical I/O with it!]

OK.

#define INTERVAL(hr, min, sec) (1000*(60*hr + (60*min + sec)))

#define TIMEBASE(ms) ( ( ms < 65535) ? MS : \ ( (ms/1000) < 65535) ? SEC : \ ( ((ms/1000)/60) < 65535) ? MIN : \ ((((ms/1000)/60)/60) < 65535) ? HR : \ UNDEFINED );

[typos left as an exercise for the reader]

Not the most efficient way of doing this but fairly obvious, syntactically.

(Easier to have a genuine function that returns a (time, base) tuple)

You could also parse the character string at runtime (ick!) to adopt a syntax closer to the one you described above.

See above.

Pull the "loop()" out of the *real* loop so you have a "real loop" that contains the overhead that the "framework" provides (timers, printing, etc.) and have *it* invoke "yourloop()" that does the stuff that is "application specific":

realloop() { updatetimers(); scaninputs(); yourloop(); updateoutputs(); }

yourloop() { ... }

TT = EN && !DN?

The above, IMO, is more intuitive -- but, requires extra support so that "delay" can yield the processor to other tasks when it decides that the timer has not yet expired.

[since that is done so often, it is the sort of service I would move into an OS]

Good luck!

Reply to
Don Y

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.