Maker Pro
Maker Pro

required delay before function execution!!

paddy

Sep 11, 2012
81
Joined
Sep 11, 2012
Messages
81
Hello,

Please refer below mentioned code.

Code:
void ringAlarm(int8* ai)
{  
   int i,j;
    static int16 time_delay=10000;
    time_delay=time_delay-1;
 
 for(i=0;i<8;i++)
 {    
     if(ai[i]==1 && time_delay==0)
     {   
            
          switch(i)
          {
            case 0:
               output_high(pin_A0);
               break;
            case 1:
               output_high(pin_A1);
               break;
            case 2:
               output_high(pin_A2);
               break;
            case 3:
               output_high(pin_A3);
               break;
            case 4:
               output_high(pin_A4);
               break;
            case 5:
               output_high(pin_A5);
               break;
            case 6:
               output_high(pin_E0);
               break;
            case 7:
               output_high(pin_E1);
               break;
           }//switch ends
        
    }// if ends
}//for ends
  
}

a gives alarm conditions.

My requirement is
1. Check a==1 i.e checking condition
2. Wait for some delay (i.e 1 or 2 minutes)
3. Again check for a
4. And if a==1 after delay then only execute the function

But i can not use delay function which halts execution of next code.

With the above mentioned code i am not getting expected result.

Please suggest what i need to do?

thanks,
paddy
 

CocaCola

Apr 7, 2012
3,635
Joined
Apr 7, 2012
Messages
3,635
Turn off the watchdog, or break the delay into smaller segments and put it in a for next loop while clearing the watchdog within that loop so it never overflows...
 

paddy

Sep 11, 2012
81
Joined
Sep 11, 2012
Messages
81
Turn off the watchdog, or break the delay into smaller segments and put it in a for next loop while clearing the watchdog within that loop so it never overflows...

I didn't understand.


As per my understanding If I turned off the watchdog function then it will not reset my controller .
So what is the need of clearing it?

Please correct me if I am wrong.
 

CocaCola

Apr 7, 2012
3,635
Joined
Apr 7, 2012
Messages
3,635
As per my understanding If I turned off the watchdog function then it will not reset my controller .

True...

So what is the need of clearing it?

So it doesn't overflow and reset the chip... A long delay will cause it to overflow and thus reset the chip, then it hits the delay again and overflows and resets again...
 

KrisBlueNZ

Sadly passed away in 2015
Nov 28, 2011
8,393
Joined
Nov 28, 2011
Messages
8,393
In a general sense, you need some kind of multi-tasking, or an approximation of it. You need to have some code running "in the foreground", but all the time, you also need to have your alarm handling code doing its thing as well.

There are a number of ways to handle this. The best way depends on factors like the microcontroller you're using, the other tasks it needs to perform, and your level of experience.

It would help me to know more about your project - its general function, the other functions it performs, the microcontroller you're using, and anything else you can think of.

This is a general answer to the problem of getting periodic execution for a background task.

There are four basic approaches, which come from two independent choices you need to make.

The first is whether the backgound code (your alarm logic) will be executed co-operatively or pre-emptively - that is, whether the main code co-operates with the background code, and explicitly calls it regularly while the main code is idle, or whether the background code is triggered by an interrupt, usually from a timer. Co-operative is generally simpler to implement, especially for the less experienced, because it avoids a number of issues relating to interrupt handlers.

The second decision is whether the background code is implemented as a state-driven function, or as a task.

Using a task-based design is a good idea if there are many independent tasks that need to (appear to) run simultaneously. It requires a microcontroller that can switch between multiple stacks (small PICs can't), and it requires some overhead in firmware and stack space. It allows each task to be written as if it was the only program running on the microcontroller. The only requirement is that each task must co-operate with the other tasks, by "deferring" execution periodically to the other tasks, typically while it has nothing to do, at the start of its activity loop, and when it's doing something that might take a significant amount of time.

That is called co-operative multi-tasking. Alternatively, the deferring between tasks can be done through an interrupt; this is called pre-emptive multi-tasking and it brings in the complexities that are related to interrupt handlers.

Maintaining the watchdog can become a bit tricky with a task-based architecture. Usually you want the watchdog to time out when ANY task gets stuck, but there is usually only one hardware watchdog. Multiple watchdogs can be implemented in software, and the defer logic may be a good place to implement them, and to toggle the hardware watchdog if all the software watchdogs are being fed.

The alternative to a task-based architecture is a state-driven function. This is a function that is called periodically by the main code, in the same way that the defer() function is called in the task-switching architecture, but instead of deferring to other tasks, this function only performs the requirements of the alarm detection. This is what I recommend for your application.

The function needs to return quickly, so it can't implement any delays, but it knows that it's going to get executed regularly, so it doesn't need to tie up the microcontroller in a delay loop - it just needs to be able to remember what it needs to do until the next time it is called, and it needs some kind of independent time reference, such as a free-running counter, which nearly all microcontrollers have.

The function remembers its state through one or more variables, depending on what it needs to do. The traditional state-driven function has a single main state variable, and on entry, it uses a switch() to execute the section of code that is appropriate for its current state. That code will usually contain logic to switch to a different state in the right circumstances. After the case is executed, the function exits, and the next time it is called, a different state handler may execute.

A state-driven function usually has other variables that help it keep track of what it's doing. These variables may include sub-states for a particular state, counters, pointers, timestamps, and so on. Since a state-driven function is not allowed to do anything that waits for an event, or takes a significant amount of time, it should be impossible for the micro to get stuck in an endless loop inside the function. The function can still get stuck in a particular state though, due to a coding error or unexpected hardware behaviour; the function can include watchdog logic to watch for this situation (e.g. state != IDLE_STATE continuously for 1 second) and signal a failure.

Here's a summary of the four combinations of co-operative vs. pre-emptive and task-based vs. state-driven-function-based.

1. Co-operative task-based: All tasks, including the mainline, are written as if they are the only program running on the micro, but they must include regular calls to defer(), which transfers execution to the next due task; eventually, execution returns to the first task again. Tasks should not tie up the micro with long runs of code; typically, significant loops will include calls to defer(). There is overhead in the task-switching system, but each task can be written fairly easily without the need for state variables. There is no problem with interrupts because task switching is done co-operatively.

2. Pre-emptive task-based: All tasks, including the mainline, are written as if they are the only program running on the micro. No calls to defer() are needed, because deferring is forced through an interrupt. Special handshaking between tasks, using semaphores and queues, is usually needed to deal with the unpredictable timing of these interrupts, and code must be more carefully written.

3. Pre-emptive state-driven: This is another name for the traditional interrupt handler approach. The mainline doesn't defer. Periodically, an interrupt comes along, and the interrupt handler figures out "where it was up to", and what it needs to do, using one or more variables that identify the interrupt handler's current state, either directly or indirectly. The interrupt handler then takes the appropriate action, and may change its control variables, before exiting back to the mainline. If the interrupt handler is called at regular intervals from a timer interrupt, it can maintain a "tick counter" which it can use as a coarse time reference. Apart from in very simple cases, communication with the interrupt handler must be clearly defined and properly controlled to avoid race conditions and hard-to-debug failures.

4. Co-operative state-driven: This is what I recommend for this case. You have a function that handles the alarm logic, which must be called periodically by all mainline code - that is, at the top of the mainline (typically), inside any loop where the mainline is waiting for something to happen, and inside any loop where the mainline is doing something that may take a significant amount of time. This includes any functions called by the mainline - in fact, all the "foreground" code. The function is designed to be quick. It uses one or more variables to keep track of what it's doing, and an external timebase such as a free-running counter to keep track of the time, and on each call, it does the processing required to make decisions on what it needs to do, it updates hardware outputs if appropriate, it updates its own variables, then it returns to the mainline.

That's my attempt at "Multi-tasking 101". Get back to us with your response to my suggestions, and other information about the project, and I'll be able to help some more.
 
Last edited:

paddy

Sep 11, 2012
81
Joined
Sep 11, 2012
Messages
81
Thank you vary much KrisBlueNZ for your suggestions.

I am newbie and I don't have much experience of coding.

I am using PIC18F4520 micro controller

Let me explain you for what I am looking for,

I have a device which takes 4-20 mA input and display it over the range of 0-100.

It gives alarm for 2 limit values.

But what happening is due to some false triggering the device is generating alarm even if the signal is absent.

So my thought is as soon as condition occurs ,it will assign some value to one variable and decrements it and when it becomes zero it will execute that function and mean time it will execute other code.

So it will generate some delay and avoid false triggering.

I appreciate your kind support!!!
 
Last edited:

KrisBlueNZ

Sadly passed away in 2015
Nov 28, 2011
8,393
Joined
Nov 28, 2011
Messages
8,393
Hi Paddy,

I have a device which takes 4-20 mA input and display it over the range of 0-100. It gives alarm for 2 limit values. But what happening is due to some false triggering the device is generating alarm even if the signal is absent.

This should be able to be solved fairly simply, without any multi-tasking or timer interrupt logic.

Are you measuring your 4~20 mA signal using the microcontroller's 10-bit ADC?

How do you decide when to read the ADC? Are you using a timer, and sampling the ADC at regular intervals? Or are you sampling as quickly as you can?

Are you using any kind of smoothing or filtering on the values you get from the ADC?

What do you mean by the device is generating alarms "even if the signal is absent"?

Are the alarm trigger points a low limit and a high limit? So if the input goes below the low limit, the low alarm is triggered, and if it goes above the high limit, the high alarm is triggered?
 

paddy

Sep 11, 2012
81
Joined
Sep 11, 2012
Messages
81
I have used external ADC (MCP 3208) .

8 devices whose output is 4~20 mA is fed to MCP 3208 through differential amplifier and MCP3208 is interfaced with micro controller using SPI.

So i am scanning 8 channels continuously in while loop.

I have set alarm conditions on two different points say ALM1 on 20 and ALM2 on 40.

And there are different LED's for indication for every channel.

So in this case I have 16 LED's for ALM1 and ALM2.

And as the process value goes above 20 or 40 the LED of particular channel should turn on in both the cases(ALM1 and ALM2).

But some times i am getting false indication due to noise. (In this case my process values are less than limit points)
 

KrisBlueNZ

Sadly passed away in 2015
Nov 28, 2011
8,393
Joined
Nov 28, 2011
Messages
8,393
If your converted values are noisy, I would first try to find out why they're noisy and fix that problem, and if I couldn't fix the cause of the problem, apply some filtering or smoothing to the digital value so that brief wrong values can be filtered out.

First I would try to characterise the errors. Is it possible that you're losing bit-sync with the ADC sometimes? Set your analogue measurement to say 15% and run some temporary code that fills an area of RAM with consecutive readings from the ADC, then go back and look at that data to see whether there's a pattern to what's happening. Do the reported values go up and down steadily, or is there an occasional one that's way out of range? Can you find out why?
 

paddy

Sep 11, 2012
81
Joined
Sep 11, 2012
Messages
81
Hi KrisBlueNZ,

In normal conditions, the system works fine.

But it is going to be installed on offshore and in that case it gives false alarms.
 

KrisBlueNZ

Sadly passed away in 2015
Nov 28, 2011
8,393
Joined
Nov 28, 2011
Messages
8,393
OK. So there's something about the environment that it's installed in that is causing incorrect measurements. This sounds like a hardware issue to me. The screening may need to be improved, or the cable to the transducer may need to be moved away from sources of interference.

You might think that you can compensate for the interference in software, by adding filtering. But that's not true. The ADC has a defined input range (the equivalent of 0~4095 raw value) and whenever the input current goes outside that limit, it will effectively be clipped by the ADC. So for example an input at 50% with +/- 10% noise on it due to interference will seem to vary between 40% and 60%, and if you smooth it, you can get the true value of 50%, but if that input is at 5% with +/- 10% noise on it, the input ranges between -5% and 15% but -5% can't be represented by the ADC so the smoothed value will be wrong. The same problem happens at the top end of the scale.

Actually with a 4~20 mA transducer that problem won't happen at the bottom of scale unless the interference is very large.

In any case, if there is significant interference getting into the input, the problem should be fixed at its source, or the 4~20 mA transducer (whatever it is) should be replaced with one that has a digital output so interference will not affect the measurement.

It might be useful for you to add a diagnostic mode to your software so the interference can be characterised. It may be a continuous waveform at a certain frequency, in which case the frequency might give a clue as to where it's coming from, or it might be a pulse or a burst of noise that happens when some large piece of equipment turns on and off. By looking at the timing of the interference you may be able to figure out what is causing it. Or, use your eyes and see what sources of interference are near the wiring to the transducer.
 

paddy

Sep 11, 2012
81
Joined
Sep 11, 2012
Messages
81
You might think that you can compensate for the interference in software, by adding filtering.


Yeah... i am trying to do something like that.

thank you very much for your kind support
 
Top