Embedded Systems

Multithreaded Temperature Control System

This is based on example code for the uC/OS-II embedded operating system implemented on a Tini2131 microcontroller package.

temperature.c (6255 bytes)  
/****************************************************************************
    Multithreaded Temperature Control System

    Steve Larsen and Zac Hester

    March 3rd, 2006

    For: Dr. Batchelder, CENG 447: Embedded Systems, Lab 4
****************************************************************************/

/*
 * Basic Includes
 */ 
#include "includes.h"
#include "consol.h"
#include "ad.h"


/*  Size of each task's stack (# of words) */
#define  TASK_STK_SIZE      64

/*  Number of concurrent tasks */
#define  NO_TASKS           3

/* Pin configuration: heater circuit assignment */
#define HTR_0 0x02000000
#define HTR_1 0x04000000
#define HTR_2 0x40000000

/*
 * Task variable data structure
 */
typedef struct {
    U32 sensor_num;
    U32 heater_bit;
    U8 temperature;
    U16 period;
    U8 label;
} controller_data;
controller_data system_data[3];

/*
 * Temperature conversion lookup table
 * The index is the 8-bit value of the AD converter.
 * The element value is the temperature in degrees celsius.
 *  (See temperature.pl for details.)
 */
const S16 temp_vector[256] = {
    176,164,147,138,131,126,122,118,115,112,109,107,105,103,101,100,98,
    97,95,94,93,91,90,89,88,87,86,85,84,83,83,82,81,80,79,79,78,77,76,76,
    75,75,74,73,73,72,71,71,70,70,69,69,68,68,67,67,66,66,65,65,64,64,63,
    63,63,62,62,61,61,60,60,60,59,59,58,58,58,57,57,57,56,56,55,55,55,54,
    54,54,53,53,53,52,52,52,51,51,51,50,50,50,49,49,49,48,48,48,48,47,47,
    47,46,46,46,45,45,45,45,44,44,44,43,43,43,43,42,42,42,42,41,41,41,40,
    40,40,40,39,39,39,39,38,38,38,38,37,37,37,37,36,36,36,35,35,35,35,34,
    34,34,34,33,33,33,33,32,32,32,32,32,31,31,31,31,30,30,30,30,29,29,29,
    29,28,28,28,28,27,27,27,27,26,26,26,26,25,25,25,25,24,24,24,24,24,23,
    23,23,23,22,22,22,22,21,21,21,21,20,20,20,20,19,19,19,19,18,18,18,18,
    17,17,17,17,16,16,16,16,15,15,15,15,14,14,14,14,13,13,13,13,12,12,12,
    12,11,11,11,11,10,10,10,9
};

/* Concurrent task stacks */
OS_STK TaskStk[NO_TASKS][TASK_STK_SIZE];

/* Startup task stack */
OS_STK TaskStartStk[TASK_STK_SIZE];

/* Task semaphore for reading the AD converter */
OS_EVENT *TempSem;


/*
 * Function prototypes
 */
void TempControl(void *data);
void TaskStart(void *data);
void APP_vMain(void);


/*=========================================================================*/



/**
 * TempControl
 * Operate a concurrent sense and control task.
 *
 * @param data A pointer to task-specific data
 */
void TempControl(void *data) {

    /* The task-specific data */
    controller_data* sys = (controller_data*) data;

    /* Error code from semaphore */
    U8 err;

    /* Converted AD value */
    U32 adval;

    /* An index variable to "protect" the temperature lookup table */
    U8 temp_index;

    /* The converted temperature */
    U32 temp;

    /* Sets this task's heater state (for output purposes) */
    U8 htr_on = 1;

    /* Enter control loop */
    while(1) {

        /* Acquire semaphore to read temperature sensor */
        OSSemPend(TempSem, 0, &err);

        /* Sense temperature. */
        adval = ConvertAD0(sys->sensor_num);

        /* Shift to 8-bit value */
        adval >>= 2;

        /* Mask and convert to a "safe" index value */
        temp_index = adval & 0x000000FF;

        /* Convert the AD value to degrees celsius */
        temp = temp_vector[temp_index];

        /* Test current temperature against desired temperature. */
        if(temp < sys->temperature) {

            /* Turn on heater. */
            rIOSET0 = sys->heater_bit;
            htr_on = 1;
        }
        else {

            /* Turn off heater. */
            rIOCLR0 = sys->heater_bit;
            htr_on = 0;
        }

        /* Send diagnostic output to the console. */
        CONSOL_SendCh('\n');
        /* Task label (number 0 to 2) */
        CONSOL_PrintNum(10, 2, False, ' ', sys->label);
        CONSOL_SendString(": ");
        /* Thermister temperature (degrees celsius) */
        CONSOL_PrintNum(10, 3, False, ' ', temp);
        CONSOL_SendString("/");
        /* Desired temperature (degrees celsius) */
        CONSOL_PrintNum(10, 3, False, ' ', sys->temperature);
        /* Heater control state */
        if(htr_on) {
            CONSOL_SendString(" Heater ON");
        }
        else {
            CONSOL_SendString(" Heater OFF");
        }

        /* Release semaphore */
        OSSemPost(TempSem);

        /* Wait one second plus the task period */
        OSTimeDlyHMSM(0, 0, 1, sys->period);
    }
}



/**
 * TaskStart
 * Initialize and run the application-specific control tasks.
 *
 * @param data A pointer to task-specific data
 */
void TaskStart(void *data) {
    U8 i = 0;
    char key;

    /* Prevent compiler warning. */
    data = data;

    /* OSStatInit(); /* Initialize uC/OS-II's statistics. */

    CONSOL_SendString("Temperature Lab\n");

    /* Set I/O direction for heater driver circuits */
    rIODIR0 |= HTR_0 | HTR_1 | HTR_2;

    /* Assign task-specific information. */
    /*  (Heater assignment based on changes in physical cicuit.) */                 
    system_data[0].sensor_num = 1;
    system_data[0].heater_bit = HTR_1;
    system_data[0].temperature = 20;
    system_data[0].period = 159;
    system_data[0].label = 0;
    
    system_data[1].sensor_num = 2;
    system_data[1].heater_bit = HTR_2;
    system_data[1].temperature = 25;
    system_data[1].period = 373;
    system_data[1].label = 1;
    
    system_data[2].sensor_num = 4;
    system_data[2].heater_bit = HTR_0;
    system_data[2].temperature = 40;
    system_data[2].period = 257;
    system_data[2].label = 2;

    /* Initialize A/D converter. */
    InitAD0();

    /* Concurrent task startup loop */
    for (i = 0; i < NO_TASKS; i++) {

        /* Start a control task using its own data structure. */
        OSTaskCreate(
            /* Task to run */
            TempControl,
            /* Data for Task */
            (void *)&system_data[i],
            /* Task stack */
            (void *)&TaskStk[i][TASK_STK_SIZE-1],
            /* Task priority */
            i+1
        );
    }

    /* Console polling loop */
    while(1) {

        OSCtxSwCtr = 0;

        /* See if key has been pressed */
        if(CONSOL_GetChar(&key) == True) {

            /* Yes, see if it's the ESCAPE key */
            if(key == 0x1B) {

                /* Stay here for ever */
                while(1);
            }
        }

        /* Wait one minute */
        OSTimeDlyHMSM(0, 1, 0, 0);
    }
}



/**
 * APP_vMain
 * Primary startup code for the OS
 */
void APP_vMain(void) {

    /* Initialize uC/OS-II */
    OSInit();

    /* Create process synchronization semaphore. */
    TempSem = OSSemCreate(1);

    /* Run the startup task */
    OSTaskCreate(
        TaskStart,
        (void *)0,
        (void *)&TaskStartStk[TASK_STK_SIZE-1],
        0
    );

    /* os_cfg.h */
    FRMWRK_vStartTicker(OS_TICKS_PER_SEC);

    /* Start multitasking */
    OSStart();
}

Temperature Lookup Table Construction

temperature.pl (1345 bytes)  
#!/usr/bin/perl
#############################################################################
#
# Temperature Lookup Table Construction
#
# Steve Larsen and Zac Hester
#
# March 3rd, 2006
#
# For: Dr. Batchelder, CENG 447: Embedded Systems, Lab 4
#
# Construct a table of temparature values corresponding to AD-converted
# integer values for a particular thermister sensing circuit.
#
#############################################################################

# Open output file.
open FH, "> temp_list.txt";

# Run through every possible index value.
#  (Index 0 is not a valid log argument.)
for($i = 1; $i < 255; $i++) {

    # Calculate the real temperature for this index.
    print FH &calc($i).",";
}

# Close output file.
close FH;

##
# Calculate a temperature based on an index.
##
sub calc {

    # Argument 0 is the index for which to calculate.
    my $index = shift;

    # The raw voltage at this index value.
    my $volts = ($index * 0.012890625); # 0.129 = 3.3 / 256

    # The thermister resistance is based on the voltage divider formula.
    #  (10k*Vt) / (5-Vt)
    my $rt = (10000 * $volts) / (5 - $volts);

    # The temperature is calculated from the characteristic equation of
    #  the thermister.  (Perl's log() is the natural log.)
    my $temp = (log($rt) - log(28899)) / -0.0429;

    # Return rounded temperature value.
    return int($temp + 0.5);
}

Page last updated 2006-04-03