Synchronous state machine code implementation

Thread Starter

JMac3108

Joined Aug 16, 2010
348
I've designed a temperature controller, based on a TI MSP430 micro. I use a thermistor to sense temperature, and a thermoelectric unit to heat/cool my enclosure. My hardware is working and I've written some working code in C that is successfully implementing a simple on/off control scheme to set the temperature. To control temperature I use a state machine implemented with a case statement. Since the state machine is small and only has a few states, this works well. Currently I have a software delay that executes each time through the state machine.

I would like to improve the program by using a timer to set a time interval and execute the state machine once per interval. There are lots of ways to do this. I'm much more of a hardware designer than a programmer, so I 'm looking for some general advice on ways to handle this type of code.

Here are some options I see ...

(1) Just use the timer to count a fixed time and use that for a delay after each time through the state machine.

(2) Place the sate machine code into a timer overflow interrupt routine.

(3) Set a global flag inside a timer interrupt service routine that I use to tell me when to execute the state machine.

I'm looking for general advice on best practice to handle this kind of program. Perhaps a simple outline of common ways to program or arcihtect this would be greatly appreaciated. Thanks in advance.
 

THE_RB

Joined Feb 11, 2008
5,438
Probably 3 would be the most professional way to do it.

I generally use a short fast timer interrupt to generate real time periods (ie actual mS or 10mS units) which allows the same timer to be used for things like real time clocks and other timing processes in real seconds etc, useful in a heating controller.

Here is a page showing how to make a small fast interrupt routine generate actual seconds or 10mS periods, whatever you want, and it will work with any speed of xtal your micro uses;
http://www.romanblack.com/one_sec.htm

Like I said for a control application I would make the interrupt generate real 10mS period "events", then in the event increments a variable in the interrupt so it also counts real seconds every 100 events. So you have 2 easy variables, one incs every 10mS and one incs every second. Between those two you can do all the control things like determine how long things are turned on, etc.
 

ErnieM

Joined Apr 24, 2011
8,377
It really depends on what overall is being done.

As your app seems to literally have time to waste there is no problem in literally wasting time using a delay routine (option (1)).

While sometimes seemingly frowned upon, doing all your work inside the ISR can be efficient. I have one (albeit tiny) program where the main loop is simply:

Rich (BB code):
void main(void)
{
   init(); 
   while(1);
}
Everything gets done inside the ISR. which is similar to your app: it gets triggered by a timer match so my ISR runs at a very defined rate (as you would expect for a timer). So (2) is a working scheme.

Scheme (3) brings the time element into your state table. Guess what, that works fine too.

So you have 3 ways to skin your cat that all would work just fine. I might guess that over your lifetime you will find (2) more useful then (1) and (3) more useful then (2), but the difference between them is slight.

I will say the overall BEST way is the way your professor or boss prefers. One job I did had a ton of code to keep every path the same time length so the outputs were 100% stable on an oscilloscope no matter what it was reading. The only reason for that was if it was "jumpy" it would confuse my boss so I didn't let it do that.
 

Thread Starter

JMac3108

Joined Aug 16, 2010
348
Great info guys, thanks! I'm still thinking about which way to go.

Let me add a little more info and perhaps that will lead us to prefer one of the three choices over the other.

My temperature controller board communicates with the system's main controller board over a serial port. I don't have the protocol all worked out yet, but basically the main board sends the temperature controller simple commands such as the setpoint temperature and hysteresis. The temperature controller sends back status information such as actual temperature, and any hardware error conditions. Nothing needs to happen quickly in a temperature controller, so I am not using interrupts with the serial port. My state machine simply looks at the serial port RX buffer each time through the state machine, and if something is in there it goes to a state where it reads and interprets it.

In general I think I like idea (3). Let me summarize this idea as described by THE_RB and see if I'm understanding it fully.

- Setup timer for short period such as 10ms.

- ISR for timer has global variables that increment.

- These global timing variables are setup to count up to longer periods, such as 100ms or 1sec.

- Main program looks at the global timing variables and decides when to do things.

- Result is that I can execute some things quickly (perhaps every 100ms), such as checking for hardware errors and looking in the RX buffer for a command from the main board. And other things slowly (perhaps once per second), like reading the temperature and making a decision on what to do with my thermo-electric unit based on the temperature.
 

ErnieM

Joined Apr 24, 2011
8,377
OK, now you have added a second task (handling the serial data) and that is a time sensitive task, and here's why: say you have a user on the other end of the serial line who wants to do data logging so he sends you a continuous stream of "what's the temperature Jack?" requests. He sends them one following the other so as soon as you start replying with information the next request is already coming in.

Now you have a time crunch. If you simply accept the request and begin replaying the input buffer will overrun as you are no longer watching it, as the reply stream is probably longer then the request string. You might want to use the handshaking lines (the RTS and CTS lines) to act as a block to further inputs until you finish with the current event.
 

Thread Starter

JMac3108

Joined Aug 16, 2010
348
Ernie,
Thanks for hte comments. Very useful.

Its not a data-logger. We are simply holding the temperature constant in an enclosure, and the control is done by my board. The Main board will want to send commands to change the temperature, or sometimes to read the temperature.

However, your point is valid. Maybe I should use an ISR to respond immediately to data in the RX buffer. I can immediately go get it, then set a flag to say that I got a command. The flag will be used when I return to my state machine so that it knows that it received a command and should go to the command state to decide how to handle it.
 

THE_RB

Joined Feb 11, 2008
5,438
One of the benefits of the timing routines on that page I linked was that they can be used in any interrupt that occurs on a fixed time interval. So it's ideally suited for a timer interrupt like a 16bit timer overflow (occurs every 65536 instructions) so you can have a lot of other activity going on between the relatively sparse timer interrupts.

In that case I would use a 16bit timer overflow int as the main timer and the timing system on that page to generate 10mS "events", then a second int for detecting serial receive.

There's a bit benefit to having an interrupt driven system timer, to time the ADC sampling and output time etc even things like LED flashing or display or log heating time.

Here's a simple project that used a tiny PIC micro to do the temperature control, LCD display and a 1000 hour count up timer "000:00:00" for paint curing;
http://www.romanblack.com/shift1/sh1_p2.htm
There's C source code provided there too which may give you some ideas.
 

MMcLaren

Joined Feb 14, 2010
861
Hi JMac3108,

Just curious which MSP430 you're using. Is it one of the value-line devices on a Launchpad, or something else? If using a Launchpad, do you have the 32-kHz crystal installed?

Regards, Mike
 

takao21203

Joined Apr 28, 2012
3,702
option 3) is the way I usually code things like that, to keep the interrupt routine reasonably short.

And usually the execution is asynchronous.

If it is only a small program, and nothing else is implemented, then 1) is also OK.
 

Thread Starter

JMac3108

Joined Aug 16, 2010
348
MMc,

Nope, not using the Launchpad this time, but have played wiht it before.

Using MSP4302231, using the DCO set to 16MHz.

Jim
 

Thread Starter

JMac3108

Joined Aug 16, 2010
348
Another question ...

I'm using a terminal progrm on a desktop PC (TeraTerm) to debug my code. Its a pain because, for example, when I send an integer representing temperature the terminal program will interpret this as an ASCII character and display the ASCII equivalent. To get a readable display on TeraTerm I have to parse out each individual digit in my number, find the ASCII equivalent for that digit, then send this to TeraTerm. I have it working fine. But now I want to work out the detailed serial communication protocol between my temperature controller board and the main system board. I would like to work on this initially without the main board, using a desktop PC and a terminal program. But I would like to find something that will display RX values as integers, either in hex or decimal. And I would like to be able to TX integers the same way. Does anyone know a terminal program that will do this? I do not have any tools loaded to write my own desktop application, and I'm not really interested at this point in doing so. I'd rather find a terminal program that has this feature, if one exists. Thanks again for all the help.
 

Thread Starter

JMac3108

Joined Aug 16, 2010
348
Taka ...

The character disaply you suggest has exactly the same behavior as the terminal program I'm using. Integers sent to the character display are decoded and the ASCII equivalent is displayed. I want to directly display the integer that I send. Because in my real application another micro-controller will be getting this data and interpreting it as integers. I want to simulate that behavior.

If I can't find a terminal program that displays in decimal of hex, I will be forced to have to swite something to do this.

Thanks.
 

takao21203

Joined Apr 28, 2012
3,702
http://www.youtube.com/watch?v=YwFwE2yx6RY

more something like this. In the meanwhile, I have added points support, and ported most of it to C. Yes it is a complete transfer protocol. But complicate to use, difficult to share on the internet, or to sell.

It's OK for my own use, and it does save me developement time for many circuits. I use timeslot multiplexing, not the hardware serial port, by the way. And data on each high/low clock transition.

Never used hardware debugger! It's too slow.

5-digit decimal display would be highly unusual, somehow.

So let say instead of a terminal program, I hook up a 16f54 + carrier PCB, easy to program/to use, and send out the serial data I want, and add some keys etc. to control behaviour. Took me years but it works for me!

And all XC8 now, not assembly any more. Except the display itself, must use assembler for speed reason.
 

ErnieM

Joined Apr 24, 2011
8,377
Microsoft gives away a version of Visual Basic (VC++ too) that has a COMM object that can accept the serial stream. A simple program can convert the data from any format to any format.

My preference is for VB as it is easier to quickly toss something together you don't mind dumping later.
 

Thread Starter

JMac3108

Joined Aug 16, 2010
348
Thanks MMc!!!

RealTerm is doing exactly what I needed. Now I can just sent integers directly over the comm port to debug my program and RealTerm shows them directly. I can eliminate all the code I wrote to turn integers into ASCII equivalents that was necessary when I was using HyperTerm or TeraTerm.
 
Top