Pages: [1] 2   Go Down
Author Topic: Help with Design: Using processor time efficiently when dealing with serial  (Read 1707 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 21
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi everyone,

I'm currently working on developing what is essentially a temperature controller with a few other bells and whistles attached. I have a few questions about how I should approach the code design in terms of using the microprocessor efficiently (I don't want to be blocking other things from happening while waiting around for a serial reponse). The basics of my system are as follows

                                                 TouchScreenDisplay
                                                          |
                                                        (Serial)
                                                           |
            USB Slave Device -----(USB)------Arduino Mega ADK-----------------RS485Bus
                                                          |
                                                         (Serial)
                                                          |
                                                        Temp monitor

There are a few other things attached but I think this is all I need to consider at this point in time. The arduino has a few tasks that need to be done often such as PID control for a heater (which is connected to a digital pin via a motor driver) and a rather large state machine function. It also needs to be able to receive commands/queries from the display and act accordingly for, example the display could ask the arduino for some propery of the USB slave device to display on screen.

The Arduino has a lot of things it needs to do so I want to minimise the time spent waiting for things e.g. a response over USB. How should I organise my code?

My thoughts so far are to have the PID function on a timer interrupt as it is a short method and needs to be regular (i guess this means I would need to query the temp monitor just as regularly and somehow ensure I don't read and write from the buffer at the same time). I think the state machine function can just be in the main loop. But, I am unsure how to handle the requests from the display. If I receive a query, should I use Serial.Event() and have code in there to send the USB device for the query and wait for a response? This seems a bit wasteful of resources. Ideally, once the query is received from the display, my code would send the query to the usb device and continue doing normal things until a response is received on which it would act (forward to the display or do some other necessay processing). How could i achieve this??

Any other comments and thoughts would be appreciated too,

Thanks a lot for your help
Logged

New Jersey
Offline Offline
Faraday Member
**
Karma: 72
Posts: 3763
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It's hard to tell what your timing need is from those details, but generally, the arduino is plenty fast enough to deal with serial data and other operations without the need for interrupts. Just steer clear of delay. What are you measuring the temperature of that you need such frequent updates?
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 162
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Separating the two communications accomplishes what you want.
Your main loop periodically sends a serial message to read the temperature and stores it in a variable.
The loop also checks for a touch screen request.  If it is a request for temperature it immediately sends the variable value.
(there is no additional transmission and wait).  It processes any other type of request.
Then it begins the loop again.  The only trick is to perhaps snap the time (millis()) when you last read the temperature, so that you can compare it to the current time and not read it too quickly.
This way, no delay is used.  You get instant response to your touch, except if it happens to be in the middle of a temperature measurement communication.
Logged

Anchorage, AK
Offline Offline
Edison Member
*
Karma: 42
Posts: 1176
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It might be worth breaking your project up into multiple chips.  For e.g., reading 1-wire digital thermometer ICs is a blocking event, so your code stops running while that's happening.  It's long enough to make the UI feel sluggish and unresponsive.

You could use an ATtiny or something to poll your sensor and send the temp back to your main controller.  The rest of what you want to do is all fairly cooperative.  For instance, serial I/O takes some time, but not that much.  You're not going to miss the (less than a) millisecond it takes to transfer some data over serial before a touch is registered.  Your PID routine probably won't miss the stolen ticks either.

Some code is forgiving of being interrupted, some isn't.  If you do schedule events on interrupts, make sure your ISR doesn't affect critical timing loops or change the contents of any variables or ports that might need to be consistent during some other unrelated operation that could be happening concurrently.
Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 639
Posts: 34726
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

What you want to do is simple if you go about it in the correct way. I would implement a finite state machine. It is a lot simpler than it sounds, google for more info.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 21
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey,

thanks for all the replies.

It sounds like I don't need to worry too much about time wasted for sending/receiving serial messages.

I should regularly check the state of the temp monitor and USB slave device, and store the values in variables so that they can be sent when requested (this will usually be once per loop anyway). eg
 
Code:
int temp;
unsigned long lastGotTemp; // time I last saved temp
int usbSlaveState;
boolean msgRcvd = false;

void getTemp(){
    char buf[bufLength];
    int temp;
    sendRequest("TEMP");
    lastGotTemp = millis();
    receiveRepy(buf);
    disablePIDInterupt();
    temp = atoi(buf);
    enablePIDInterrupt();
}

ISR pidControl(){
    // called when a timer over flows
    // using current temp etc values, calculate new output and applies it
    // restart timer
}

loop(){

    getTemp();
    getUSBSlaveState(); // similar to getTemp()

    if (msgRcvd ){
        // figure out what the display wants done
        // ...
    
        if(setSomethingOnUSBSlave)
            // set thing on USB slave
            
        if(someThingElse)
            // do other thing

       sendReplyToDisplay();
       msgRcvd = false;
    }

    automate(); // state machine function for opening closing valves etc

}

SerialEvent(){
    //Saves received characters to a circular buffer.
    // checks if full message received yet
    // if full msg received, sets a flag to true
}
If I used a finite state machine to process requests from the display, wouldn't I need to create a state for every single combination of requests i could receive from the display? as a received  message could contain a request for several things at once eg current temp, set some value, get some other value ...

Just steer clear of delay.
Why should I steer clear of delay(), what should i use instead?

Should I have my PID function in an interrupt? Or should I do this in the loop also? I initially thought to use interrupts as it is pretty critical that it happens regularly (I'm meant to be aiming for +/- 5 milli Kelvin stability), which is why I also thought I would need to check the temp just as often.

Thanks again for your help
« Last Edit: April 30, 2012, 07:37:49 am by alphabetSoup » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 654
Posts: 50931
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Should I have my PID function in an interrupt? Or should I do this in the loop also? I initially thought to use interrupts as it is pretty critical that it happens regularly (I'm meant to be aiming for +/- 5 milli Kelvin stability), which is why I also thought I would need to check the temp just as often.
With this statement, are you serious about asking this?
Quote
Why should I steer clear of delay(), what should i use instead?
Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 639
Posts: 34726
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
If I used a finite state machine to process requests from the display, wouldn't I need to create a state for every single combination of requests i could receive from the display?
No a state machine tells you only what you have to do now, when you have done it you move the machine on to the next task.
By using this with the millis timer you can sort out what to do when. There is no need for a delay.
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 162
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I agree with both veterans.  I had no idea you were aiming for a few milliKelvins.
In that case create two variables called Setpoint and LastMeasuredTemperature.

Use a timer interrupt and put your PID code in the interrupt routine.
At first the PID code can be simply:
LastMeasuredTemperature = ReadTemperature();  
OvenHeaterState = (LastMeasuredTemperature < Setpoint) ? true : false;
OutDigitalHeater (OvenHeaterState);

Your main loop() just deals with the user.  It gets a possible user message to change the setpoint and changes Setpoint.  In any case it then displays both variables to the touch screen display.

See how stable you get with that and then go PID math crazy if you need to!
See how fast your interrupt loop timer needs to be.

At first, for debug_mode only, you can have your pid loop print a running log of the temp messages it receives and the digital output actions it takes.  For debug mode of your main loop, you can print the message received from the touch screen and a message that you are changing the Setpoint.
« Last Edit: May 01, 2012, 04:28:34 pm by Techylah » Logged

New Jersey
Offline Offline
Faraday Member
**
Karma: 72
Posts: 3763
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I'm meant to be aiming for +/- 5 milli Kelvin stability
Just out of curiosity, what are you using to measure the temperature to this accuracy?
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13085
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I initially thought to use interrupts as it is pretty critical that it happens regularly (I'm meant to be aiming for +/- 5 milli Kelvin stability), which is why I also thought I would need to check the temp just as often.


The target accuracy and PID timing and not necessarily intertwined.  For example: If you're controlling the temperature of a 2 ton slab of iron in a well insulated room using the heating element from an electric kettle, sub-second updates are pointless.  Any output change is going to take days or weeks to have a measurable affect.  However, if you're controlling the temperature of the tip of a pushpin in a windtunnel using a 10KW heating element than sub-second updates are critical.

In other words, before adding the complexity of an interrupt service routine you need to first determine that PID timing really is that critical.
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 162
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

"In other words, before adding the complexity of an interrupt service routine you need to first determine that PID timing really is that critical."

Agreed and well said.   In this case, though, with an Arduino, it is so easy to set up a timer and interrupt loop, you can look at that as just a simpler and better way to organize the code.  It's probably harder to architect the code without such a loop.   Yes, it enables a faster control loop if need be, but even if it is not needed, it's an easy and proper place to put a separate loop to repeatedly read and control something.   I'd describe it as making a software thermostat.  You can modify an automatic adjusting algorithm on top of it, as you need it.
Logged

Anchorage, AK
Offline Offline
Edison Member
*
Karma: 42
Posts: 1176
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What temp sensor?  Again, if it's 1-wire, you'll be waiting for hundreds of ms for your results every probe.  Doing this, and waiting for the reply, more than once a minute or so means your UI will feel like it has locked up most of the time.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 21
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi thanks for the replies,

it seems to be split as to whether I should use an interrupt for my PID function. I like that having it in a seperate interrupt function seperates it out of the main loop (a finite state machine) and ensures that it will always happen. It wouldn't add too much more complexity, other than ensuring buffers etc aren't read/write at the same time, would it?

In other words, before adding the complexity of an interrupt service routine you need to first determine that PID timing really is that critical.
My environment can be extremely cold, down to 4K , and my heating element is only 5W.  Would you agree the timing is critical in the situation?

What temp sensor? 
I'm using The model 14C from here http://www.cryocon.com/TMSelectGuide.asp . I will be using RS232, and it supports only half duplex mode.

are you serious about asking this?
Quote
Why should I steer clear of delay(), what should i use instead?

I re read the delay() reference. Stupid question, agreed.

Thanks again



Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 639
Posts: 34726
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
My environment can be extremely cold, down to 4K , and my heating element is only 5W.  Would you agree the timing is critical in the situation?
No I would not. There is nothing remotely time critical about thermal management, it can always wait the odd half second or so.
Logged

Pages: [1] 2   Go Up
Jump to: