Integer PI control with integrator anti-windup

March 31, 2013 Coded in C
/**
 * @file
 * Proportional-integral (PI) control law.
 *
 * This module implements a simple position-type PI controller:
 * <pre>
 *   u = [ kp * e + ki * sum(e) ] >> shift
 * </pre>
 * <tt>shift</tt> is a right bit shift used to scale the output of the
 * controller down from the 32-bit intermediate result.
 *
 * An anti-windup provision is implemented on the PI integrator to prevent
 * deep saturation (aka integrator windup):
 * - The new control output with the latest integrator value is computed.
 * - If the control output exceeds either output limit, <i>and</i> the latest
 *   change in the integrator is in the same direction, then the new integrator
 *   value is not saved for the next call.
 * - Otherwise, the integrator is saved for the next call.
 */

#include <stdbool.h>
#include "pi_control.h"

/**
 * Proportional-integral (PI) control law.
 *
 * @param[in,out]  p    control parameter and state structure
 * @param[in]      e    error signal
 *
 * @return              control output <code>u</code>
 */
int pi_control (struct PIControl *p, int e)
{
  bool int_ok;      /* Whether or not the integrator should update */
  long new_i;       /* Proposed new integrator value */
  long u;           /* Control output */
  
  /* Compute new integrator and the final control output. */
  new_i = p->i + e;
  u = (p->kp * (long)e + p->ki * new_i) >> p->shift;

  /* Check for saturation.  In the event of saturation in any one direction,
     inhibit saving the integrator if doing so would deepen the saturation. */
  int_ok = true;
     
  /* Positive saturation? */
  if (u > p->max)
  {
    /* Clamp the output */
    u = p->max;

    /* Error is the same sign? Inhibit integration. */
    if (e > 0)
    {
      int_ok = false;
    }
  }
  /* Repeat for negative sign */
  else if (u < p->min)
  {
    u = p->min;
    
    if (e < 0)
    {
      int_ok = false;
    }
  }
  
  /* Update the integrator if allowed. */
  if (int_ok)
  {
    p->i = new_i;
  }

  return (int)u;
}

/**
 * Initializes the PI control.
 *
 * This function resets the PI integrator to zero.
 *
 * @param[in,out]  p  control parameter structure
 */
void pi_control_init (struct PIControl *p)
{
  p->i = 0L;
}

/* Header file */
#if !defined(_PI_CONTROL_H)
#define _PI_CONTROL_H

/**
 * @file
 * Proportional-integral (PI) control law header file.
 */

/** PI control data structure.  This structure contains configuration (the
    proportional and integral gain, plus a final divisor), output limits, and
    an integration accumulator (the PI controller's state variable). */
struct PIControl
{
  int kp;              /**< Proportional gain constant */
  int ki;              /**< Integral gain constant */
  unsigned char shift; /**< Right shift to divide */
  int max;             /**< Maximum value */
  int min;             /**< Minimum value */
  long i;              /**< Current integrator value */
};

/* Prototypes */
int pi_control (struct PIControl *p, int e);
void pi_control_init (struct PIControl *p);

#endif /* _PI_CONTROL_H */

1D and 2D table lookup

March 31, 2013 Coded in C
/**
 * @file
 * Table lookup with interpolation (1-D and 2-D).
 *
 * This is a 1/2-D table lookup facility.  Each routine looks up data in a table 
 * structure, interpolating as needed between data points.  The 2-D version
 * looks up along 2 axes and interpolates in two dimensions.
 *
 * <h2>Limitations</h2>
 * - The table axes (input values) must monotonically increase, or the lookup
 *   will fail.
 * - The index data type is nominally 8 bits, limiting the table length to
 *   256 elements.  Change <code>index_t</code> if larger tables are needed.
 */

#include <stdint.h>
#include <stdbool.h>
#include "lookup.h"

/** Index data type */
typedef uint8_t index_t;

/**
 * 1-D table lookup.
 *
 * This function performs a 1-D table lookup with interpolation.  The output
 * value is clamped to either of the table end values when the input value is
 * out of bounds.
 *
 * @param[in]   t      table data structure
 * @param[in]   ix     input (X-axis) value
 * @param[out]  o      output data
 *
 * @retval      true   if the lookup result is suspect due to clipping
 * @retval      false  on successful lookup
 */
bool lookup1d (Table1d *t, int ix, int *o)
{
  index_t i;
  
  /* ------------------------------------------------------------------------ */
  /* Off the end of the table */
  if (ix > t->columns[t->ncols - 1])
  {
    *o = t->table[t->ncols - 1];
    return true;
  }
  
  /* Off beginning of the table */
  else if (ix < t->columns[0])
  {
    *o = t->table[0];
    return true;
  }

  /* Within the bounds of the table */
  for (i = 0; i < t->ncols - 1; ++i)
  {
    if (   ix >= t->columns[i]
        && ix <= t->columns[i + 1])
    {
      /* Output (table) low value */
      int o_low   = t->table[i];
      /* Input (X-axis) low value */
      int i_low   = t->columns[i];
      /* Spead between the two adjacent input values */
      int i_delta = t->columns[i + 1] - t->columns[i];
      /* Spread between the two adjacent table output values */
      int o_delta = t->table[i + 1]   - t->table[i];
      
      /* Prevent division by zero.  We could get here if two consecutive
         input values in the table are the same. */
      if (o_delta == 0)
      {
        *o = o_low;
        return true;
      }
      
      *o = o_low + ((ix - i_low) * (long)o_delta) / i_delta;
      return false;
    }
  }

  /* Didn't find it (we shouldn't ever get here). */
  return true;
}

/**
 * 2-D table lookup.
 *
 * This function performs a 2-D table lookup with interpolation.  The output
 * value is clamped to either of the table end values when the input value is
 * out of bounds.
 *
 * @param[in]   t      table data structure
 * @param[in]   ix     input (X-axis) value
 * @param[in]   iy     input (Y-axis) value
 * @param[out]  o      output value
 *
 * @retval      true   if the lookup result is suspect due to clipping
 * @retval      false  on successful lookup
 */

bool lookup2d (Table2d *t, int ix, int iy, int *o)
{
  /* The lower X and Y coordinates of the interpolation box */
  index_t i, j;
  /* Set whenever one of the lookups goes off the end of the table */
  bool is_fault = false;
  
  /* ------------------------------------------------------------------------ */
  /* X axis coordinate lookup */

  /* Off the end of the table */
  if (ix > t->columns[t->ncols - 1])
  {
    /* Pretend the input value is right at the table edge so that interpolation
       works as expected */
    ix = t->columns[t->ncols - 1];
    i = t->ncols - 1;
    is_fault = true;
  }

  /* Off beginning of the table */
  else if (ix < t->columns[0])
  {
    ix = t->columns[0];
    i = 0;
    is_fault = true;
  }

  /* Within the bounds of the table */
  else
  {
    for (i = 0; i < t->ncols - 1; ++i)
    {
      if (   ix >= t->columns[i]
          && ix <= t->columns[i + 1])
      {
        break;
      }
    }
  }

  /* ------------------------------------------------------------------------ */
  /* Y axis coordinate lookup */

  /* Off the bottom of the table */
  if (iy > t->rows[t->nrows - 1])
  {
    iy = t->rows[t->nrows - 1];
    j = t->nrows - 1;
    is_fault = true;
  }

  /* Off the top of the table */
  else if (iy < t->rows[0])
  {
    iy = t->rows[0];
    j = 0;
    is_fault = true;
  }

  /* Within the bounds of the table */
  else
  {
    for (j = 0; j < t->nrows - 1; ++j)
    {
      if (   iy >= t->rows[j]
          && iy <= t->rows[j + 1])
      {
        break;
      }
    }
  }

  /* ------------------------------------------------------------------------ */
  /* 2-D interpolation */

  /* At this point we know that the input X value is between
     column[i] and column[i+1] and that the input Y value is between
     row[j] and row[j+1].  Therefore we have a rectangle in which we need
     to interpolate. 
     
     To do the interpolation, we first interpolate between column i and
     column i+1 on the upper row j.  Then, we interpolate between the same
     columns on row j+1.  Finally, we interpolate vertically between the two
     rows based on the input Y value.
     
     row0 is the upper row data and row1 is the lower (higher subscript) row
     data. */
  {
    const int *row0 = &t->table[j * t->ncols];
    const int *row1 = &row0[t->ncols];
    /* Difference between the two adjacent column values */
    int i_delta = t->columns[i + 1] - t->columns[i];
    /* Difference between the two adjacent row values */
    int j_delta = t->rows[j + 1] - t->rows[j];
    /* Low column value */
    int i_low = t->columns[i];
    /* Low row value */
    int j_low = t->rows[j];
    /* Interpolation results for the upper and lower rows */
    int o0, o1;
    
    /* Prevent division by zero if the input values aren't increasing.
       If no division by zero, interpolate between columns in the upper and
       lower row. */
    if (i_delta == 0)
    {
      o0 = row0[i];
      o1 = row1[i];
      is_fault = true;
    }
    else
    {    
      /* Interpolate the upper row */
      {
        int o_low   = row0[i];                 /* Row value at low column # */
        int o_delta = row0[i + 1] - row0[i];   /* Difference from next column */
  
        o0 = o_low + ((ix - i_low) * (long)o_delta) / i_delta;
      }

      /* Interpolate the lower (higher subscript) row */
      {
        int o_low   = row1[i];                 /* Row value at low column # */
        int o_delta = row1[i + 1] - row1[i];   /* Difference from next column */
  
        o1 = o_low + ((ix - i_low) * (long)o_delta) / i_delta;
      }
    }

    /* Guard against division by zero in the row axis.  If all is well,
       interpolate between the two row interpolation results from earlier. */
    if (j_delta == 0)
    {
      *o = o0;
      is_fault = true;
    }
    else
    {
      *o = o0 + ((iy - j_low) * (long)(o1 - o0)) / j_delta;
    }
  }
 
  return is_fault;
}

/* Header file */
#if !defined(_LOOKUP_H)
#define _LOOKUP_H

/**
 * @file
 * Table lookup with interpolation (1-D and 2-D) header file.
 */

#include <stdbool.h>

/** One dimensional lookup table. */
typedef const struct
{
  /** Number of elements in the table.  This must be at least 2. */
  unsigned char ncols;
  /** List of input values. */
  int *columns;
  /** Table data (output values).  The output values list must have the same
      length as the input list. */
  int *table;
} Table1d;

/** Two dimensional lookup table. */
typedef const struct
{
  /** Number of columns (X values) in the table.  Must be at least 2. */
  unsigned char ncols;
  /** Number of rows (Y values) in the table.  Must be at least 2. */
  unsigned char nrows;
  /** X-axis input values list. */
  int *columns;
  /** Y-axis input values list. */
  int *rows;
  /** Table data.  This is an array of <code>columns</code>X<code>rows</code>,
      arranged in rows.  For example, <code>table[1]</code> is the second 
      column in the first row. */
  int *table;
} Table2d;

/* Prototypes */
bool lookup1d (Table1d *t, int ix, int *o);
bool lookup2d (Table2d *t, int ix, int iy, int *o);

#endif

Software UART receiver

March 31, 2013 Coded in C
/**
 * @file
 * Software serial (UART) receiver
 *
 * This module implements the receive engine for asynchronous serial
 * communications using polling ("bit banging").  Transmission capability
 * is not provided.
 *
 * The data format is <tt>8-N-1</tt>:
 * - Eight data bits
 * - No parity
 * - One stop bit
 *
 * <h2>Structural overview</h2>
 * The receiver is implemented as a polled finite state machine.  The state
 * of the I/O pin is passed as an argument to the state machine animation
 * function <code>soft_uart_rx()</code>.  The polling function must be called
 * on a stable timebase at a frequency at least three times
 * the bit rate.  The function returns a flag to indicate that a character has
 * been received and places the received character in a fixed buffer.
 *
 * <h2>Timing</h2>
 * The baud rate of the transmitter constrains the ossortment of possible
 * interrupt rates.  However, this receiver is designed to be configurable so
 * as to maximize those choices.
 *
 * Any frequency multiple of at least 3 is suitable.  Is this example, the
 * sample rate is four times the serial data bit rate:
 *
 * <pre>
 *  Given
 *  =====
 *  Baud rate specification: 1200 +/- 4%
 *  System interrupt rate:   5 kHz (200 us)
 *
 *  Selecting a sample rate
 *  =======================
 *  Chosen multiplier:       samples per bit
 *  Sample rate:             5 kHz / 4 == 1250 baud (4.16% high)
 * </pre>
 *
 * Since the baud rate is high in this example, We will have a tendency to
 * sample earlier and earlier on each successive bit.  Therefore it is desirable
 * to sample slightly later in the bit time if possible.
 * <pre>
 * \#define SOFT_SOFT_UART_RX_BIT_TIME  5
 * \#define SOFT_UART_RX_START_SAMPLES  2
 * </pre>
 * The diagram below shows the resultant timing.  The actual bit times are 4%
 * slower, owing to the fact that the system interrupy is not an exact multiple
 * of the bit time.
 *
 * The sample timing error at the stop bit is (4% X 9) = 36% too early.
 * <pre>
 *  _______                 _______________                     _______________
 *         \\_______________/               \\...________________/
 * +-------+---+---+---+---+---+---+---+---+...+---+---+---+---+---+---+---+---+
 * | Cycle | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |   | 8 | 9 | A | B | C | D | E | F |
 * +-------+---+---+---+---+---+---+---+---+...+---+---+---+---+---+---+---+---+
 * | Data  | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |   | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
 * |       |   Start bit   |  Data bit 0   |   |  Data bit N   |   Stop bit    |
 * | Samp. | X | X |   |   |   |   | X |   |   |   |   | X |   |   |   | X |   |
 * +-------+---+---+---+---+---+---+---+---+...+---+---+---+---+---+---+---+---+
 *           ^   ^                                       |<------------->|
 *           |   |                                               |
 *           |   |                  SOFT_UART_RX_BIT_TIME -------+
 *           |   |
 *           +---+---- SOFT_UART_RX_START_SAMPLES
 * </pre>
 * Here is an explanation of how a character is received:
 * -# We sample the line continuously until the START (logic zero) bit is seen.
 * -# Just to make sure it wasn't noise, we sample the line a second (or third
 *    or fourth, depending on the setting) time with the expectation that the
 *    state hasn't changed.
 * -# We continue to sample the start bit until we have reached the center of
 *    the bit time.  The line must stay in the low state.  This shifts us to
 *    safety away from edges.
 * -# We delay (frequency multiplier) cycles, ignoring the state of the line.
 *    This puts us in the middle of the first data bit.
 * -# We sample and save the data bit, then wait (frequency multiplier - 1)
 *    cycles.
 * -# We repeat until we have sampled all data (payload) bits.  The last bit
 *    is sampled and must be a logic one.
 *
 * <h2>Limitations</h2>
 * For speed, the receive buffer is implemented as a global variable that is
 * to be accessed directly by the calling code.  Also, the state variable
 * is private to this module.  Therefore, only one instance of the soft
 * UART receiver is supported in a given project. 
 *
 * @author Justin Dobbs
 */

#include <stdbool.h>

/** The number of times to sample the start bit.

    This defines the phase shift of subsequent samples.  If the interrupt rate is
    a bit high relative to the baud rate, we want to sample late to
    minimize cumulative timing error. */
#define SOFT_UART_RX_START_SAMPLES  3

/** The inter-bit delay time, a.k.a. the frequency multiplier */
#define SOFT_UART_RX_BIT_TIME       4

/* State definitions */
static bool st_idle (bool);
static bool st_start_bit (bool);
static bool st_delay_rx0 (bool);
static bool st_delay_rx1 (bool);
static bool st_delay_rx2 (bool);
static bool st_delay_rx3 (bool);
static bool st_delay_rx4 (bool);
static bool st_delay_rx5 (bool);
static bool st_delay_rx6 (bool);
static bool st_delay_rx7 (bool);
static bool st_delay_stop (bool);
static bool st_abort_wait_for_idle (bool);

/**
 * Soft UART receiver polling function.
 *
 * This function implements the receiver.  It should be called on a stable
 * timebase at a fixed multiple of the bit rate.
 *
 * @note This is implemented as a pointer to a function to handle the current
 *       state.  The caller need only invoke the function using the pointer.
 *
 * @param[in]   x      the state of the input line:
 *                     - <code>true</code>: the line is high
 *                     - <code>false</code>: the line is low
 *
 * @retval      true   if a character is ready in <code>soft_uart_rx_buf</code>
 * @retval      false  otherwise
 */
bool (*soft_uart_rx)(bool) = st_idle;

/** Serial recieve buffer.  This should be immediately read after
    <code>soft_uart_rx()</code> returns <code>true</code>. */
unsigned char soft_uart_rx_buf;

/** Cycle counter, for timing. */
static unsigned char i;

/**
 * Sampling continuously, waiting for the start bit.
 */
static bool st_idle (bool x)
{
  if (!x)
  {
    i = SOFT_UART_RX_START_SAMPLES - 1;
    soft_uart_rx = st_start_bit;
  }
  return false;
}

/* -------------------------------------------------------------------------- */

/**
 * Sampling the start bit a few more times to make sure it's solid.  This also
 * provides time offset for sampling future bits in the middle of the bit time.
 */
static bool st_start_bit (bool x)
{
  /* Reject if the start bit does not last long enough */
  if (x)
  {
    soft_uart_rx = st_idle;
  }
  else if (--i == 0)
  {
    i = SOFT_UART_RX_BIT_TIME;
    soft_uart_rx_buf = 0;
    soft_uart_rx = st_delay_rx0;
  }
  return false;
}

/* -------------------------------------------------------------------------- */

/**
 * Waiting one bit time, then sampling the LSb (bit 0).
 */
static bool st_delay_rx0 (bool x)
{
  /* When it's time, shift in the data to the RX buffer.  If we have
   received all the data, go wait for the STOP bit. */
  if (--i == 0)
  {
    if (x)
    {
      soft_uart_rx_buf |= 0x01;
    }
    i = SOFT_UART_RX_BIT_TIME;
    soft_uart_rx = st_delay_rx1;
  }
  return false;
}

/* -------------------------------------------------------------------------- */

/**
 * Waiting one bit time, then sampling bit 1.
 */
static bool st_delay_rx1 (bool x)
{
  if (--i == 0)
  {
    if (x)
    {
      soft_uart_rx_buf |= 0x02;
    }
    i = SOFT_UART_RX_BIT_TIME;
    soft_uart_rx = st_delay_rx2;
  }
  return false;
}

/* -------------------------------------------------------------------------- */

/**
 * Waiting one bit time, then sampling bit 2.
 */
static bool st_delay_rx2 (bool x)
{
  if (--i == 0)
  {
    if (x)
    {
      soft_uart_rx_buf |= 0x04;
    }
    i = SOFT_UART_RX_BIT_TIME;
    soft_uart_rx = st_delay_rx3;
  }
  return false;
}

/* -------------------------------------------------------------------------- */

/**
 * Waiting one bit time, then sampling bit 3.
 */
static bool st_delay_rx3 (bool x)
{
  if (--i == 0)
  {
    if (x)
    {
      soft_uart_rx_buf |= 0x08;
    }
    i = SOFT_UART_RX_BIT_TIME;
    soft_uart_rx = st_delay_rx4;
  }
  return false;
}

/* -------------------------------------------------------------------------- */

/**
 * Waiting one bit time, then sampling bit 4.
 */
static bool st_delay_rx4 (bool x)
{
  if (--i == 0)
  {
    if (x)
    {
      soft_uart_rx_buf |= 0x10;
    }
    i = SOFT_UART_RX_BIT_TIME;
    soft_uart_rx = st_delay_rx5;
  }
  return false;
}

/* -------------------------------------------------------------------------- */

/**
 * Waiting one bit time, then sampling bit 5.
 */
static bool st_delay_rx5 (bool x)
{
  if (--i == 0)
  {
    if (x)
    {
      soft_uart_rx_buf |= 0x20;
    }
    i = SOFT_UART_RX_BIT_TIME;
    soft_uart_rx = st_delay_rx6;
  }
  return false;
}

/* -------------------------------------------------------------------------- */

/**
 * Waiting one bit time, then sampling bit 6.
 */
static bool st_delay_rx6 (bool x)
{
  if (--i == 0)
  {
    if (x)
    {
      soft_uart_rx_buf |= 0x40;
    }
    i = SOFT_UART_RX_BIT_TIME;
    soft_uart_rx = st_delay_rx7;
  }
  return false;
}

/* -------------------------------------------------------------------------- */

/**
 * Waiting one bit time, then sampling bit 7.
 */
static bool st_delay_rx7 (bool x)
{
  if (--i == 0)
  {
    if (x)
    {
      soft_uart_rx_buf |= 0x80;
    }
    i = SOFT_UART_RX_BIT_TIME;
    soft_uart_rx = st_delay_stop;
  }
  return false;
}

/* -------------------------------------------------------------------------- */

/**
 * Waiting one bit time, then sampling the stop bit.
 * @note The reception is aborted if the stop bit does not arrive on schedule.
 */
static bool st_delay_stop (bool x)
{
  if (--i == 0)
  {
    /* STOP bit is always logic ONE by definition */
    if (x)
    {
      soft_uart_rx = st_idle;
      return true;  /* Got a character */
    }
    else
    {
      /* Stop bit didn't happen when we expected it.  Go sit and wait 
         indefinitely for the line to go high. */
      soft_uart_rx = st_abort_wait_for_idle;
      return false;
    }
  }
  /* Haven't sampled the stop bit yet! */
  return false;
}

/* -------------------------------------------------------------------------- */

/**
 * Reception aborted; waiting as long as required for the line to idle high
 * again.
 */
static bool st_abort_wait_for_idle (bool x)
{
  /* NOW the line is finally high/idle again.  Start the receive process over.
     We did not get a character. */
  if (x)
  {
    soft_uart_rx = st_idle;
  }
  return false;
}

/* Header file */
#if !defined(_SOFT_UART_RX_H)
#define _SOFT_UART_RX_H

/**
 * @file
 * Soft UART receiver header file
 *  
 * This file implements the interface to the software UART reciever module.
 * The full documentation is located in @ref soft_uart_rx.c.
 *
 * @author Justin Dobbs
 */

#include <stdbool.h>

/* Actually a function pointer, but this is supposed to be opaque.  This is
   called from a periodic interrupt. 

  @param[in]  x  the state of the serial line (true == high) */
extern bool (*soft_uart_rx) (bool x);

/* The receive buffer */
extern unsigned char soft_uart_rx_buf;

#endif

Olympic Averaging

Douglas Butler March 29, 20132 comments Coded in C
int16 adcval,sum,max,min;
int8 i;
#define samples 10

max=0;
min=0xFFFF;    //Set max and min to the limits of the range.

for (i=0;i<samples;i++){
    adcval=read_adc();
    if (adcval>max) max=adcval;    //Update max and min on the fly.
    if (adcval<min) min=adcval;
    sum+=adcval;    //Generate sum of all samples.
    }
sum-=max;    //Remove the maximum, and minimum values
sum-=min;    //as likely outliers.

return(sum/(samples-2)); //Average the remaining total.
     //If samples = 10 then the division becomes sum<<3

I2C driver

March 29, 2013 Coded in C for the Atmel AT89
/*
File: I2C_drive.h
*/

#ifndef __I2C_H
#define __I2C_H

#include <AT89X51.H>
#include <INTRINS.H>

typedef unsigned char ubyte;

/*
****************************************************
*       I2C Bus Configuration
*
****************************************************
*/

#define sda P1_0
#define scl P1_1
#define HOLD _nop_(); _nop_(); _nop_()

void send_stop();
void master(ubyte);
void send_byte(ubyte);
void send_data(ubyte, ubyte, ubyte, ubyte *);
ubyte recv_byte(ubyte);
void recv_data(ubyte, ubyte, ubyte, ubyte *);

#endif
----------------------------------------------------------

/*
File: I2C_drive.c
*/

#include "I2C_drive.h"

bit i2c_busy, no_ack, bus_fault;

ubyte bdata a;

sbit LSB=a ^ 0;
sbit MSB=a ^ 7;

/*
************************************
*       Sending Stop Condition
************************************
*/

void send_stop()
{
	sda = 0;
	scl = 1;
	HOLD;
	sda = 1;
	i2c_busy = 0;
}

/*
************************************
*      I2C Start Condition
*
*     NOTE: need to use it.
************************************
*/

void master(ubyte slave_addr)
{
	i2c_busy = 1;
	no_ack = 0;
	bus_fault = 0;
	if(!scl||!sda)
		bus_fault = 1;
	else
	{
		sda = 0;
		HOLD;
		scl = 0;
		HOLD;
		send_byte(slave_addr);
	}
}

/*
************************************
*     Sending a byte on I2C Bus
************************************
*/

void send_byte(ubyte i2c_data)
{
	ubyte i;
	a=i2c_data;
	for(i=0;i<8;i++)
	{
		scl=0;
		HOLD;
		sda=MSB;
		a<<=1;
		_nop_();
		scl=1;
		HOLD;
		scl=0;
	}
	sda = 1;
	scl = 1;
	HOLD;
	if(!sda)
	{
		scl = 0;
		HOLD;
	}
	else
	{
		no_ack = 1;
		scl = 0;
		HOLD;
	}
}

/*
****************************************************
*       Sending data on I2C bus
*
*   Usage:
*         send_data(0xD0,0x10, 0x20, send_buffer)
*
*         0XD0: Slave address, Must me with write bit
*         0x10: Starting address, or sub-address
*         0x20: number of bytes to send
*         send_buffer: adress of the buffer pointer
*
*****************************************************
*/

void send_data(ubyte slave_add, ubyte sub_add, ubyte bytes, ubyte *data_in)
{
	master(slave_add);
	send_byte(sub_add);
	if(no_ack)
		send_stop();
	else
	{
		for(bytes;bytes>0;bytes--)
		{
			send_byte(*data_in++);
			if(no_ack)
				break;
		}
		send_stop();
	}
}

/*
*********************************************
*      Recieve a single byte from I2C Bus
*
*    Note: if you are going to recieve
*          a single byte then the passing
*          argument should be 1.
*
*********************************************
*/

ubyte recv_byte(ubyte cnt)
{
	ubyte i,rcv_data;
	for(i=0;i<8;i++)
	{
		sda=1;
		scl=1;
		HOLD;
		LSB=sda;
		if(i<7)
			a<<=1;
		HOLD;
		scl=0;
		HOLD;
	}
	if(cnt==1)
		sda = 1;
	else
		sda = 0;
	scl =1;
	HOLD;
	scl = 0;
	sda = 1;
	HOLD;
	rcv_data = a;
	return rcv_data;
}

/*
****************************************************
*       Recieving bulk data on I2C bus
*
*   Usage:
*         recv_data(0xD0,0x10, 0x20, send_buffer)
*
*         0XD0: Slave address, Must me with write bit
*         0x10: Starting address, or sub-address
*         0x20: number of bytes to recieve
*         send_buffer: adress of the recieve buffer
*                      pointer
*
*****************************************************
*/

void recv_data(ubyte slave_add, ubyte sub_add, ubyte byte_cnt, ubyte *recv_buf)
{
	ubyte i;
	scl = sda = 1;
	master(slave_add);
	send_byte(sub_add);
	slave_add+=1;
	scl = sda = 1;
	master(slave_add);
	if(no_ack)
	{
		send_stop();
		goto exit;
	}
	for(i=0;i<byte_cnt;i++)
		recv_buf[i]=recv_byte(byte_cnt-i);
	send_stop();
exit:;
}

Complex serial port driver with feedback acceptance.

March 29, 20131 comment Coded in C for the TI MSP430
/*
Developed By: Dinesh SB
E-Mail: dinesh.badkas0809@gmail.com
*/

#include "msp430.h"

#define initialDelay 50000

unsigned int k,ADC12temp = 0,PotTemp = 0;;
unsigned char AdcDec[4],PotDec[4];;
volatile unsigned int i,j,m = 0,n = 0;
unsigned char IMUTemp = 0;
unsigned char IMURazorBuffer[35];

void IMU_Buffering(void);
void FSR_Read(void);
void Switch_Position_Read(void);
void Battery_Monitoring(void);
void Pot_Read(void);
void PC_UART_Transmit(unsigned char);
void Bluetooth_UART_Transmit(unsigned char);
void delayGen(unsigned int tcount);
void startTB(unsigned int,unsigned int,unsigned int);
void StartVibration(unsigned int);

unsigned char tmp;
static unsigned int module = 0;
unsigned int delay = 0, tone = 0;
static unsigned int cmdRcvd =0;
static unsigned int delayFinished =0;
static unsigned int multiDigitDelay = 0;
static unsigned int previousDelayDigit =0;
static unsigned int digitCnt = 0;
static unsigned int digit3Rcvd = 0;
static unsigned int pDetected = 0;
static unsigned int eDetected = 0;
static unsigned int time;

static unsigned int vModule = 0;
unsigned int vDelay = 0;
static unsigned int VCmdRcvd =0;
static unsigned int VDigitCnt =0;
static unsigned int VMultiDigitDelay = 0;
static unsigned int VPreviousDelayDigit =0;
static unsigned int iDetected = 0;
static unsigned int bDetected = 0;

static unsigned int UART_Select = 0;

/*******************************************************************************

 * Function :		Board_Init

 * Description: 	This function initializes GPIOs

 * Input parameters :   None

 * Output parameters :  None

*******************************************************************************/
void Board_Init(void)
{
  //P8DIR |= BIT0;                            //P8.0 LED 1
  //P8OUT &= ~BIT0;                           //LED 1 OFF

  P7DIR |= BIT3;                            //P7.3 LED 2
  P7OUT &= BIT3;                            //LED 2 off

  P1DIR = 0x3F;                             //P1.6,7 AS input 
  P1REN = 0xC0;                             //enable pullup/down reg.
  P1OUT = 0xC0;                             //select pull-up reg.

  P2DIR = 0x00;                             //P2.0-7 as input
  P2REN = 0xFF;                             //enable pullup/down reg.
  P2OUT = 0xFF;                             //select pull-up reg.

  P6DIR |= BIT6;                            //AMP_SD pin as O/P
  P6OUT &= ~BIT6;                           //SHUTDOWN disabled

  P4SEL |= BIT4;                            //select TB4
  P4DIR |= BIT4;                            //To take PWM @ pin configure that pin HIGH

  P3DIR |= BIT0;                            //LED_BATMON on P3.0
  P3OUT &= ~BIT0;                           //LED_BATMON OFF

  P7DIR |= BIT5;                            //P7.5 configued as output
  P7OUT &= ~BIT5;                           //P7.5 made 0 to sink current

  P4DIR |= BIT6;                            //vibration motor
  P4OUT &= ~BIT6;
  
  P6SEL |= BIT7;                            //select A7_____Vout_FSR pin 
  P7SEL |= BIT4;                            //select A12____VBat_Mon.
  P6SEL |= BIT5;                            //select A5_____POT

  P10DIR &= ~BIT1;                          //mechanical switch detection; P10.1
  P10REN |= BIT1;                           //enable register
  P10OUT |= BIT1;                           //select pull-up register
}

/*******************************************************************************

 * Function :		ADC12_Init

 * Description: 	This function initializes ADC12 peripheral

 * Input parameters :   None

 * Output parameters :  None

*******************************************************************************/
void ADC12_Init(void)
{
  ADC12CTL0 &= ~ADC12ENC;                                                                     //DISABLE ADC12 FOR CONFIGURATION
  P5SEL |= BIT0;                                                                              // select P5.0 for Veref+.
  ADC12CTL0 = ADC12SHT0_8 + ADC12ON + ADC12MSC;
  ADC12MCTL0 = ADC12SREF_2 | ADC12INCH_7;                                                     //FSR__A7
  ADC12MCTL1 = ADC12SREF_2 | ADC12INCH_12;                                                    //BAT-MON.__A12
  ADC12MCTL2 = ADC12EOS | ADC12SREF_2 | ADC12INCH_5;                                          //POT__A5
  ADC12CTL1 = ADC12CSTARTADD_0|ADC12SHS_0|ADC12SHP|ADC12DIV_0|ADC12SSEL_0|ADC12CONSEQ_1;      //ADC12CONSEQ_1 = SEQUENCE OF CHANNELS. .... 

  for (k = 0x4600; k; k--);                                                                   // Delay approx. = 368 ms for needed ref start-up.
  ADC12CTL0 |= ADC12ENC;                                                                      //ENABLE ADC12 for working
}

/*******************************************************************************

 * Function :		PC_UART_Init

 * Description: 	This function initializes USCI_A0; connected to PC

 * Input parameters :   None

 * Output parameters :  None

*******************************************************************************/
void PC_UART_Init(void)                       //USB-serial UART
{
  P3SEL |= BIT4 | BIT5;                       //USCI_A0 ... RXD TXD SELECT 
  UCA0CTL0 &= 0x00;                           //USCYNC = 0 ....... for UART mode.
  UCA0CTL1 |= UCSWRST;                     
  UCA0CTL1 |= UCSSEL_2;                       //select SMCLK = 1 MHz
  UCA0BR0 = 0x09;                             //115200 baud rate..
  UCA0BR1 = 0x00;
  UCA0MCTL = 0x00;
  UCA0CTL1 &= ~UCSWRST;                       //Initialize USCI state machine**
  //UCA0IE |= UCRXIE;                         //Enable USCI_A0 RX interrupt
}

/*******************************************************************************

 * Function :		IMU_UART_Init

 * Description: 	This function initializes USCI_A1; connected to IMU Razor
                        Sensor Board.

 * Input parameters :   None

 * Output parameters :  None

*******************************************************************************/
void IMU_UART_Init(void)                      //IMU UART
{
  P5SEL |= BIT6 | BIT7;
  UCA1CTL0 &= 0x00;
  UCA1CTL1 |= UCSWRST;                     
  UCA1CTL1 |= UCSSEL_2;
  UCA1BR0 = 0x12;                             //57600 baud rate..
  UCA1BR1 = 0x00;
  UCA1MCTL = 0x00;
  UCA1CTL1 &= ~UCSWRST;
}

/*******************************************************************************
 
 * Function :		Bluetooth_UART_Init
 
 * Description: 	This function initializes USCI_A2; connected to 
                        Bluetooth module.
 
 * Input parameters :   None
  					
 * Output parameters :  None
  					
*******************************************************************************/
void Bluetooth_UART_Init(void)                //bluethooth UART
{
  P9SEL |= BIT4 | BIT5;            
  UCA2CTL0 &= 0x00;
  UCA2CTL1 |= UCSWRST;                     
  UCA2CTL1 |= UCSSEL_2;                  
  UCA2BR0 = 0x09;                             //115200 baud rate..
  UCA2BR1 = 0x00;
  UCA2MCTL = 0x00;
  UCA2CTL1 &= ~UCSWRST;
  //UCA2IE |= UCRXIE;
}

void main(void)
{
  volatile unsigned int loop_var;

  WDTCTL = WDTPW + WDTHOLD;                                 //WDT made off

  for(loop_var = 0;loop_var < initialDelay;loop_var++);    //approx. 1 sec.
  for(loop_var = 0;loop_var < initialDelay;loop_var++);    //approx. 1 sec.
  for(loop_var = 0;loop_var < initialDelay;loop_var++);    //approx. 1 sec.
  
/*
  do                                                        //for to stabilize the oscillator
  {
    UCSCTL7 &= ~(XT1LFOFFG + DCOFFG);                       //clear XT1, DCO fault flags
    SFRIFG1 &= ~OFIFG;                                      //clear oscillator fault flag.
    for(loop_var = 0x47FF;loop_var > 0;loop_var--);         //delay approx. = 368 ms
  }while((SFRIFG1 & OFIFG));                                //loop till crystal oscillator stabilizes.
*/
  Board_Init();
  ADC12_Init();
  IMU_UART_Init();
  PC_UART_Init();
  Bluetooth_UART_Init();

  __bis_SR_register(GIE);                                   //set Global Interrupt Enable
  //for (k = 0x4600; k; k--);                               //delay to initialize IMU sensor board  

while(1)
{
  if(0x02 & P10IN)                        //P10.1 = 1 ---- for bluetooth
  {
    UART_Select = 1;
    UCA0IE &= ~UCRXIE;
    UCA2IE |= UCRXIE;
  }
  else                                    //P10.1 = 0 ---- for PC
  {
    UART_Select = 0;
    UCA0IE |= UCRXIE;
    UCA2IE &= ~UCRXIE;
  }

  switch(UART_Select)
  {
  case 0:                                       //PC UART selected

          IMU_Buffering();
          n = 0;
          while(IMURazorBuffer[n] != '\r')
          {
            PC_UART_Transmit(IMURazorBuffer[n]);
            n++;
          }

          PC_UART_Transmit(';');
          PC_UART_Transmit('F');
          PC_UART_Transmit('S');
          PC_UART_Transmit('R');
          PC_UART_Transmit(':');

          FSR_Read();
          for(i=0;i<4;i++)                            //FSR decimal transmit
          {
            PC_UART_Transmit(AdcDec[3-i]);
          }

          PC_UART_Transmit(';');
          PC_UART_Transmit('P');
          PC_UART_Transmit('O');
          PC_UART_Transmit('T');
          PC_UART_Transmit(':');
          Pot_Read();
          for(i=0;i<4;i++)                            //POT decimal transmit
          {
            PC_UART_Transmit(PotDec[3-i]);
          }

          PC_UART_Transmit(';');
          PC_UART_Transmit('S');
          PC_UART_Transmit('W');
          PC_UART_Transmit('I');
          PC_UART_Transmit('T');
          PC_UART_Transmit('C');
          PC_UART_Transmit('H');
          PC_UART_Transmit('E');
          PC_UART_Transmit('S');
          PC_UART_Transmit(':');

          Switch_Position_Read();
          PC_UART_Transmit(';');

          Battery_Monitoring();
          PC_UART_Transmit('\n');
          PC_UART_Transmit('\r');

   break;

  case 1:                                        //Bluetooth UART selected

          IMU_Buffering();
          n = 0;
          while(IMURazorBuffer[n] != '\r')
          {
            Bluetooth_UART_Transmit(IMURazorBuffer[n]);
            n++;
          }

          Bluetooth_UART_Transmit(';');
          Bluetooth_UART_Transmit('F');
          Bluetooth_UART_Transmit('S');
          Bluetooth_UART_Transmit('R');
          Bluetooth_UART_Transmit(':');

          FSR_Read();
          for(i=0;i<4;i++)                           //FSR decimal transmit
          {
            Bluetooth_UART_Transmit(AdcDec[3-i]);
          }

           Bluetooth_UART_Transmit(';');
           Bluetooth_UART_Transmit('P');
           Bluetooth_UART_Transmit('O');
           Bluetooth_UART_Transmit('T');
           Bluetooth_UART_Transmit(':');
           Pot_Read();
           for(i=0;i<4;i++)                          //POT decimal transmit
           {
              Bluetooth_UART_Transmit(PotDec[3-i]);
           }

           Bluetooth_UART_Transmit(';');
           Bluetooth_UART_Transmit('S');
           Bluetooth_UART_Transmit('W');
           Bluetooth_UART_Transmit('I');
           Bluetooth_UART_Transmit('T');
           Bluetooth_UART_Transmit('C');
           Bluetooth_UART_Transmit('H');
           Bluetooth_UART_Transmit('E');
           Bluetooth_UART_Transmit('S');
           Bluetooth_UART_Transmit(':');

           Switch_Position_Read();
           Bluetooth_UART_Transmit(';');

           Battery_Monitoring();
           Bluetooth_UART_Transmit('\n');
           Bluetooth_UART_Transmit('\r');
  break;

  default:
    break;
}//switch

}//while(1)

}//main

/*******************************************************************************
 
 * Function :		PC_UART_Transmit
 
 * Description: 	This function transmits data to USCI_A0.
 
 * Input parameters :   unsigned char PC_Transmit_char
  					
 * Output parameters :  None
  					
*******************************************************************************/
void PC_UART_Transmit(unsigned char PC_Transmit_char)
{
  while (!(UCA0IFG&UCTXIFG));                           //wait for TxBuf to become empty
  UCA0TXBUF = PC_Transmit_char;
}

/*******************************************************************************
 
 * Function :		Bluetooth_UART_Transmit
 
 * Description: 	This function transmits data to USCI_A2.
 
 * Input parameters :   unsigned char BL_Transmit_char
  					
 * Output parameters :  None
  					
*******************************************************************************/
void Bluetooth_UART_Transmit(unsigned char BL_Transmit_char)
{
  while (!(UCA2IFG&UCTXIFG));                          //wait for TxBuf to become empty
  UCA2TXBUF = BL_Transmit_char;
}

/*******************************************************************************
 
 * Function :		Pot_Read
 
 * Description: 	This function converts pot`s digitalized value 
                        to decimal.
 
 * Input parameters :   None
  					
 * Output parameters :  None
  					
*******************************************************************************/
void Pot_Read(void)
{
  PotTemp = ADC12MEM2;                      //collect digitalized O/P of POT

  for(i=0;i<4;i++)                          //convert to Decimal
  {
    PotDec[i]=(PotTemp%10) + 0x30;          //for HEX->ASCII conversion
    PotTemp = PotTemp/10;                   //for HEX->Decimal conversion
  }
}

/*******************************************************************************
 
 * Function :		IMU_Buffering
 
 * Description: 	This function does the buffering of packets coming from 
                        IMU Razor Sensor Board.
 
 * Input parameters :   None
  					
 * Output parameters :  None
  					
*******************************************************************************/
void IMU_Buffering(void)
{
  //P8OUT |= BIT0;              //LED on
  m = 0;
  IMUTemp = 'd';               //for safety purpose
  while(1)
	{
          
            while(IMUTemp != '!')                           //wait till '!' to be received
            {
              if(UCA1IFG&UCRXIFG)
	      {IMUTemp = UCA1RXBUF;}
            }
            
			do                                  //collect a complete packet of IMU Razor. 
			{   
		          IMURazorBuffer[m] = IMUTemp;
                          while(!(UCA1IFG&UCRXIFG));
		          IMUTemp = UCA1RXBUF;
                          m++;
			}while((IMUTemp != '!'));
                        IMURazorBuffer[m] = '\0';
          
			break;
	}
  
  //P8OUT &= ~BIT0;       //LED off
}

/*******************************************************************************
 
 * Function :		FSR_Read
 
 * Description: 	This function converts FSR`s digitalized value 
                        to decimal.
 
 * Input parameters :   None
  					
 * Output parameters :  None
  					
*******************************************************************************/
void FSR_Read(void)
{
  ADC12CTL0 |= ADC12SC;                     //start conversion for 3 channels - A7 & A12 & A5
  ADC12temp = 0;         
  while(ADC12CTL1 & ADC12BUSY);             //wait till conversion ends

  ADC12temp = ADC12MEM0;                    //collect converted O/P of FSR

  for(i=0;i<4;i++)                          //convert to Decimal
  {
  AdcDec[i]=(ADC12temp%10) + 0x30;          //for HEX->ASCII conversion
  ADC12temp = ADC12temp/10;                 //for HEX->Decimal conversion
  }
}

/*******************************************************************************
 
 * Function :		Battery_Monitoring
 
 * Description: 	This function checks the battery voltage.
                        Assume Battery deferres @ 2.75V
 
 * Input parameters :   None
  					
 * Output parameters :  None
  					
*******************************************************************************/
void Battery_Monitoring(void)
{
  if(ADC12MEM1 <= 0x11D)                    //considering Vbat_min.= 2.75V
  {
     P3OUT |= BIT0;                         //LED_BATMON ON
     if(UART_Select == 0)
     PC_UART_Transmit('1');
     else
     Bluetooth_UART_Transmit('1');
  }
  else
  {
    P3OUT &= ~BIT0;                        //LED_BATMON OFF
    if(UART_Select == 0)
    PC_UART_Transmit('0');
    else
    Bluetooth_UART_Transmit('0');
  }
}

/*******************************************************************************
 
 * Function :		Switch_Position_Read
 
 * Description: 	This function sends the status of all switches of 
                        the switch board.
 
 * Input parameters :   None
  					
 * Output parameters :  None
  					
*******************************************************************************/
void Switch_Position_Read(void)
{
    if(!(0x40 & P1IN))                        //SW2-P1.6
    {
      if(UART_Select == 0)
      PC_UART_Transmit('1');
      else
      Bluetooth_UART_Transmit('1');
    }
      else
      {
        if(UART_Select == 0)
        PC_UART_Transmit('0');
        else
        Bluetooth_UART_Transmit('0');
      }

    if(!(0x80 & P1IN))                      //SW3-P1.7
    {
      if(UART_Select == 0)
      PC_UART_Transmit('1');
      else
      Bluetooth_UART_Transmit('1');
    }
      else
      {
        if(UART_Select == 0)
        PC_UART_Transmit('0');
        else
        Bluetooth_UART_Transmit('0');
      }

    if(!(0x01 & P2IN))                      //SW4-P2.0
    {
      if(UART_Select == 0)
      PC_UART_Transmit('1');
      else
      Bluetooth_UART_Transmit('1');
    }
      else
      {
        if(UART_Select == 0)
        PC_UART_Transmit('0');
        else
        Bluetooth_UART_Transmit('0');
      }

    if(!(0x02 & P2IN))                      //LEFT-P2.1
    {
      if(UART_Select == 0)
      PC_UART_Transmit('1');
      else
      Bluetooth_UART_Transmit('1');
    }
      else
      {
        if(UART_Select == 0)
        PC_UART_Transmit('0');
        else
        Bluetooth_UART_Transmit('0');
      }

    if(!(0x04 & P2IN))                      //RIGHT-P2.2
    {
      if(UART_Select == 0)
      PC_UART_Transmit('1');
      else
      Bluetooth_UART_Transmit('1');                  
    }
      else
      {
        if(UART_Select == 0)
        PC_UART_Transmit('0');
        else
        Bluetooth_UART_Transmit('0');
      }

    if(!(0x08 & P2IN))                      //SELECT-P2.3
    {
      if(UART_Select == 0)
      PC_UART_Transmit('1');
      else
      Bluetooth_UART_Transmit('1');
    }
      else
      {
        if(UART_Select == 0)
        PC_UART_Transmit('0');
        else
        Bluetooth_UART_Transmit('0');
      }

    if(!(0x10 & P2IN))                      //UP-P2.4
    {
      if(UART_Select == 0)
      PC_UART_Transmit('1');
      else
      Bluetooth_UART_Transmit('1');
    }
      else
      {
        if(UART_Select == 0)
        PC_UART_Transmit('0');
        else
        Bluetooth_UART_Transmit('0');
      }

    if(!(0x20 & P2IN))                      //DOWN-P2.5
    {
      if(UART_Select == 0)
      PC_UART_Transmit('1');
      else
      Bluetooth_UART_Transmit('1');
    }
      else
     {
       if(UART_Select == 0)
        PC_UART_Transmit('0');
        else
        Bluetooth_UART_Transmit('0');
      }

    if(!(0x80 & P2IN))                      //SW6-P2.7
    {
      if(UART_Select == 0)
      PC_UART_Transmit('1');
      else
      Bluetooth_UART_Transmit('1');
    }
      else
      {
        if(UART_Select == 0)
        PC_UART_Transmit('0');
        else
        Bluetooth_UART_Transmit('0');
      }
}

/*******************************************************************************
 
 * Function :		startTB
 
 * Description: 	This function starts the TIMER_B & speaker 
                        on speaker sound request.
 
 * Input parameters :   unsigned int count0,unsigned int count1,unsigned int delayTime
  					
 * Output parameters :  None
  					
*******************************************************************************/
void startTB(unsigned int count0,unsigned int count1,unsigned int delayTime)
{
  TBCCR0 = count0;                            // PWM Period
  TBCCTL4 = OUTMOD_7;                         // CCR4 reset/set
  TBCCR4 = count1;                            // CCR4 PWM duty cycle	
  TBCTL = TBSSEL_2 + MC_1;                    // SMCLK, upmode
  delayGen(delayTime);
}

/*******************************************************************************
 
 * Function :		delayGen
 
 * Description: 	This function starts the TIMER_A1 on speaker sound request.
 
 * Input parameters :   unsigned int tcount
  					
 * Output parameters :  None
  					
*******************************************************************************/
void delayGen(unsigned int tcount)
{
  //P8OUT ^= BIT0;
  TA1CCR0 = tcount;                         //Timer_A1 compare count
  TA1CCTL0 |= CCIE;                         //enable Timer_A1 Interrupt
  TA1CTL = TASSEL_1 + ID_3 + MC_2;          //Select ACLK, divider 8, Continuous mode
}

/*******************************************************************************
 
 * Function :		TIMER1_A0_ISR
 
 * Description: 	This ISR function stops the TIMER_A1.
 
 * Input parameters :   None
  					
 * Output parameters :  None
  					
*******************************************************************************/
#pragma vector=TIMER1_A0_VECTOR
__interrupt void TIMER1_A0_ISR(void)
{
  //P7OUT ^= BIT3;
  TA1CCTL0 &= ~CCIE;                          //clear Timer_A1 interrupt flag
  TA1CTL |= TACLR;                            //clears all counts of Timer_A1
  TA1CTL &= MC_0;                             //Stop Timer_A1
  TBCTL |= TBCLR;                             //clears all counts of Timer_B
  TBCTL &= MC_0;                              //Stop Timer_B
  module = 0;                                 
  digitCnt = 0;
  digit3Rcvd = 0;
  pDetected = 0;
  eDetected = 0;                              //clear all static global flags for safety purpose
}

/*******************************************************************************
 
 * Function :		StartVibration
 
 * Description: 	This function starts the Vibration motor & TIMER_A0
                        on vibration motor request.
 
 * Input parameters :   unsigned int tcount
  					
 * Output parameters :  None
  					
*******************************************************************************/
void StartVibration(unsigned int vtime)
{
  volatile unsigned int x,y;
  
  P4OUT |= BIT6;                                //start vibration motor
  //P7OUT &= ~BIT3;

  TA0CCR0 = (vtime*4);                          //Initialize Timer_A0 compare count 
  TA0CCTL0 |= CCIE;                             //Enable Timer_A0 interrupt flag 
  TA0CTL = TASSEL_1 + ID_3 + MC_2;              //Select ACLK, divider 8, Continuous mode
}

/*******************************************************************************
 
 * Function :		TIMER0_A0_ISR
 
 * Description: 	This ISR function stops the TIMER_A0.
 
 * Input parameters :   None
  					
 * Output parameters :  None
  					
*******************************************************************************/
#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR(void)
{
  //P7OUT ^= BIT3;
  P4OUT &= ~BIT6;                           //turn off vibration motor.
  TA0CCTL0 &= ~CCIE;                        //clear Timer_A0 interrupt flag
  TA0CTL |= TACLR;                          //clear Timer_A0
  TA0CTL &= MC_0;                           //stop Timer_A0
  vModule = 0;                            
  iDetected = 0;
  bDetected = 0;                            //clear all static global flags for safety purpose
}

/*******************************************************************************
 
 * Function :		USCI_A0_ISR
 
 * Description: 	ISR function of USCI_A0.
 
 * Input parameters :   None
  					
 * Output parameters :  None
  					
*******************************************************************************/
#pragma vector = USCI_A0_VECTOR
__interrupt void USCI_A0_ISR (void)
{
  switch(__even_in_range(UCA0IV,4))
  {
  case 0:break;                             // Vector 0 - no interrupt
  case 2:                                   // Vector 2 - RXIFG
    
    tmp = UCA0RXBUF;
    while (!(UCA0IFG&UCTXIFG));
    UCA0TXBUF = tmp;

    if((tmp == 's')/* | (tmp == 'S')*/)
    {
      module = 1;
      cmdRcvd = 0;
      delay = 0;
      previousDelayDigit = 0;
      delayFinished = 0;
      multiDigitDelay = 0;
      tone = 0;
      digitCnt = 0;
      digit3Rcvd = 0;
      pDetected = 0;
      eDetected = 0;
      break;
    }
    if((tmp == 'v') /*|(tmp == 'V')*/)
    {
      vModule = 1;
      VCmdRcvd = 0;
      vDelay = 0;
      VPreviousDelayDigit = 0;
      VMultiDigitDelay = 0;
      VDigitCnt = 0;
      iDetected = 0;
      bDetected = 0;
      break;
    }
       if(module == 1 )                             
       {
	  if((cmdRcvd != 1) &  (tmp == 'p') & (pDetected != 1) & (tmp != ','))
          {
            pDetected = 1;
	  //break;
	  }
	  if((cmdRcvd != 1) &  (tmp == 'e') & (pDetected == 1) & (eDetected != 1) & (tmp != ','))
          {
            eDetected = 1;
	  //break;
	  }
	  
          if((cmdRcvd != 1) & (tmp == ',') & (digit3Rcvd != 1) & (pDetected == 1) & (eDetected == 1))
          {
	    cmdRcvd = 1;
	    //break;
	  }
           	  
          if((cmdRcvd == 1) & (digitCnt <= 3) & (tmp >= '0') & (tmp <= '9') & (digit3Rcvd != 1) & (pDetected == 1) & (eDetected == 1))
          {
          digitCnt++;
	  delay = tmp - '0'; 
          if(digitCnt == 1)
          {
            multiDigitDelay = delay * 100;
            previousDelayDigit = multiDigitDelay;
          }
          if(digitCnt == 2)
          {
            multiDigitDelay = previousDelayDigit + (delay * 10);
            previousDelayDigit = multiDigitDelay;
          }
          if(digitCnt == 3)
          {
            multiDigitDelay = previousDelayDigit + delay;
            digit3Rcvd = 1;
          }
	  //break;
	  }
          
	  if((cmdRcvd == 1) & (digit3Rcvd == 1) & (tmp== ',') & (delayFinished != 1) & (pDetected == 1) & (eDetected == 1))
          {
            delayFinished = 1;
	    //break;		  		
	  }
            	  
	  if((delayFinished == 1) & (tmp >= '1') & (tmp <= '3') & (pDetected == 1) & (eDetected == 1))
          {
	    tone = tmp;
          
            time = multiDigitDelay * 4;              //delay is in msec. if you want delay in sec. make "time = delay * 4000;"
            TA1CTL |= TACLR;
            TBCTL |= TBCLR;
            if(tone == '1')
            {
              startTB(1023,256,time);
              //break;
            }
            if(tone == '2')
            {
              startTB(332,167,time);
              //break;
            }
            if(tone == '3')
            {
              startTB(255,64,time);
              //break;
            }
          }
      }

      if( vModule == 1)
      {
	if( (VCmdRcvd != 1) &  (tmp =='i') & (iDetected != 1)  & (tmp != ','))
        {
          iDetected = 1;
	  break;
	}
	if( (VCmdRcvd != 1) &  (tmp =='b') & (iDetected == 1)  & (bDetected != 1) & (tmp != ','))
        {
          bDetected = 1;
	  break;
	}
        
	if( (VCmdRcvd != 1) & (tmp == ',') & (iDetected == 1)  & (bDetected == 1))
        {
	  VCmdRcvd = 1;
	  break;
	}
	if((VCmdRcvd == 1) & (VDigitCnt <= 3 ) & (iDetected == 1)  & (bDetected == 1))
          {
          VDigitCnt++;
	  vDelay = tmp - '0'; 
          if(VDigitCnt == 1)
          {
            VMultiDigitDelay = vDelay * 100;
            VPreviousDelayDigit = VMultiDigitDelay;
          }
          if(VDigitCnt == 2)
          {
            VMultiDigitDelay = VPreviousDelayDigit + (vDelay * 10);
            VPreviousDelayDigit = VMultiDigitDelay;
          }
          if(VDigitCnt == 3)
          {
            VMultiDigitDelay = VPreviousDelayDigit + vDelay;
            {StartVibration(VMultiDigitDelay);}
          }
	  break;
	  }

      }
    break;
  case 4:

    break;                             // Vector 4 - TXIFG
  default: break;  
  }

}

/*******************************************************************************
 
 * Function :		USCI_A2_ISR
 
 * Description: 	ISR function of USCI_A2.
 
 * Input parameters :   None
  					
 * Output parameters :  None
  					
*******************************************************************************/
#pragma vector = USCI_A2_VECTOR
__interrupt void USCI_A2_ISR (void)
{
  switch(__even_in_range(UCA2IV,4))
  {
  case 0:break;                             // Vector 0 - no interrupt
  case 2:                                   // Vector 2 - RXIFG
    
    tmp = UCA2RXBUF;
    while (!(UCA2IFG&UCTXIFG));
    UCA2TXBUF = tmp;

    if((tmp == 's') /*| (tmp == 'S')*/)
    {
      module = 1;
      cmdRcvd = 0;
      delay = 0;
      previousDelayDigit = 0;
      delayFinished = 0;
      multiDigitDelay = 0;
      tone = 0;
      digitCnt = 0;
      digit3Rcvd = 0;
      pDetected = 0;
      eDetected = 0;
      break;
    }
    if((tmp == 'v') /*|(tmp == 'V')*/)
    {
      vModule = 1;
      VCmdRcvd = 0;
      vDelay = 0;
      VPreviousDelayDigit = 0;
      VMultiDigitDelay = 0;
      VDigitCnt = 0;
      iDetected = 0;
      bDetected = 0;
      break;
    }
       if(module == 1 )
       {
	  if((cmdRcvd != 1) &  (tmp == 'p') & (pDetected != 1) & (tmp != ','))
          {
            pDetected = 1;
	  //break;
	  }
	  if((cmdRcvd != 1) &  (tmp == 'e') & (pDetected == 1) & (eDetected != 1) & (tmp != ','))
          {
            eDetected = 1;
	  //break;
	  }
	  
          if((cmdRcvd != 1) & (tmp == ',') & (digit3Rcvd != 1) & (pDetected == 1) & (eDetected == 1))
          {
	    cmdRcvd = 1;
	    //break;
	  }
           	  
          if((cmdRcvd == 1) & (digitCnt <= 3) & (tmp >= '0') & (tmp <= '9') & (digit3Rcvd != 1) & (pDetected == 1) & (eDetected == 1))
          {
          digitCnt++;
	  delay = tmp - '0'; 
          if(digitCnt == 1)
          {
            multiDigitDelay = delay * 100;
            previousDelayDigit = multiDigitDelay;
          }
          if(digitCnt == 2)
          {
            multiDigitDelay = previousDelayDigit + (delay * 10);
            previousDelayDigit = multiDigitDelay;
          }
          if(digitCnt == 3)
          {
            multiDigitDelay = previousDelayDigit + delay;
            digit3Rcvd = 1;
          }
	  //break;
	  }
          
	  if((cmdRcvd == 1) & (digit3Rcvd == 1) & (tmp== ',') & (delayFinished != 1) & (pDetected == 1) & (eDetected == 1))
          {
            delayFinished = 1;
	    //break;		  		
	  }
            	  
	  if((delayFinished == 1) & (tmp >= '1') & (tmp <= '3') & (pDetected == 1) & (eDetected == 1))
          {
	    tone = tmp;
          
            time = multiDigitDelay * 4;              //delay is in msec. if you want delay in sec. make "time = delay * 4000;"
            TA1CTL |= TACLR;
            TBCTL |= TBCLR;
            if(tone == '1')
            {
              startTB(1023,256,time);
              //break;
            }
            if(tone == '2')
            {
              startTB(332,167,time);
              //break;
            }
            if(tone == '3')
            {
              startTB(255,64,time);
              //break;
            }
          }
      }

      if( vModule == 1)
      {
	if( (VCmdRcvd != 1) &  (tmp =='i') & (iDetected != 1)  & (tmp != ','))
        {
          iDetected = 1;
	  break;
	}
	if( (VCmdRcvd != 1) &  (tmp =='b') & (iDetected == 1)  & (bDetected != 1) & (tmp != ','))
        {
          bDetected = 1;
	  break;
	}
        
	if( (VCmdRcvd != 1) & (tmp == ',') & (iDetected == 1)  & (bDetected == 1))
        {
	  VCmdRcvd = 1;
	  break;
	}
	if((VCmdRcvd == 1) & (VDigitCnt <= 3 ) & (iDetected == 1)  & (bDetected == 1))
          {
          VDigitCnt++;
	  vDelay = tmp - '0'; 
          if(VDigitCnt == 1)
          {
            VMultiDigitDelay = vDelay * 100;
            VPreviousDelayDigit = VMultiDigitDelay;
          }
          if(VDigitCnt == 2)
          {
            VMultiDigitDelay = VPreviousDelayDigit + (vDelay * 10);
            VPreviousDelayDigit = VMultiDigitDelay;
          }
          if(VDigitCnt == 3)
          {
            VMultiDigitDelay = VPreviousDelayDigit + vDelay;
            {StartVibration(VMultiDigitDelay);}
          }
	  break;
	  }

      }
    break;
  case 4:

    break;                             // Vector 4 - TXIFG
  default: break;  
  }

}

bitbang (software) SPI implementation

Fabien Le Mentec March 28, 2013 Coded in C for the atmega328p
#include <stdint.h>
#include <avr/io.h>

/* default pins */
#define SOFTSPI_CLK_DDR DDRD
#define SOFTSPI_CLK_PORT PORTD
#define SOFTSPI_CLK_MASK (1 << 3)
#define SOFTSPI_MOSI_DDR DDRD
#define SOFTSPI_MOSI_PORT PORTD
#define SOFTSPI_MOSI_MASK (1 << 4)

#ifndef SOFTSPI_DONT_USE_MISO
#define SOFTSPI_DONT_USE_MISO 0
#endif

#if (SOFTSPI_DONT_USE_MISO == 0)
#define SOFTSPI_MISO_DDR DDRD
#define SOFTSPI_MISO_PIN PIND
#define SOFTSPI_MISO_MASK (1 << 5)
#endif

static void softspi_setup_master(void)
{
  SOFTSPI_CLK_DDR |= SOFTSPI_CLK_MASK;
  SOFTSPI_MOSI_DDR |= SOFTSPI_MOSI_MASK;

#if (SOFTSPI_DONT_USE_MISO == 0)
  SOFTSPI_MISO_DDR |= SOFTSPI_MISO_MASK;
#endif
}

static inline void softspi_clk_low(void)
{
  SOFTSPI_CLK_PORT &= ~SOFTSPI_CLK_MASK;
}

static inline void softspi_clk_high(void)
{
  SOFTSPI_CLK_PORT |= SOFTSPI_CLK_MASK;
}

static inline void softspi_mosi_low(void)
{
  SOFTSPI_MOSI_PORT &= ~SOFTSPI_MOSI_MASK;
}

static inline void softspi_mosi_high(void)
{
  SOFTSPI_MOSI_PORT |= SOFTSPI_MOSI_MASK;
}

static inline void softspi_write_bit(uint8_t x, uint8_t m)
{
  /* dac7554 samples at clock falling edge */

  /* 5 insns per bit */

  softspi_clk_high();
  if (x & m) softspi_mosi_high(); else softspi_mosi_low();
  softspi_clk_low();
}

static void softspi_write_uint8(uint8_t x)
{
  /* transmit msb first, sample at clock falling edge */

  softspi_write_bit(x, (1 << 7));
  softspi_write_bit(x, (1 << 6));
  softspi_write_bit(x, (1 << 5));
  softspi_write_bit(x, (1 << 4));
  softspi_write_bit(x, (1 << 3));
  softspi_write_bit(x, (1 << 2));
  softspi_write_bit(x, (1 << 1));
  softspi_write_bit(x, (1 << 0));
}

static inline void softspi_write_uint16(uint16_t x)
{
  softspi_write_uint8((uint8_t)(x >> 8));
  softspi_write_uint8((uint8_t)(x & 0xff));
}

#if (SOFTSPI_DONT_USE_MISO == 0)

static inline void softspi_read_bit(uint8_t* x, uint8_t i)
{
  /* read at falling edge */

  softspi_clk_high();
#if 0
/* no need, atmega328p clock below 50mhz */
/* softspi_wait_clk(); */
#endif
  softspi_clk_low();

  if (SOFTSPI_MISO_PIN & SOFTSPI_MISO_MASK) *x |= 1 << i;
}

static uint8_t softspi_read_uint8(void)
{
  /* receive msb first, sample at clock falling edge */

  /* must be initialized to 0 */
  uint8_t x = 0;

  softspi_read_bit(&x, 7);
  softspi_read_bit(&x, 6);
  softspi_read_bit(&x, 5);
  softspi_read_bit(&x, 4);
  softspi_read_bit(&x, 3);
  softspi_read_bit(&x, 2);
  softspi_read_bit(&x, 1);
  softspi_read_bit(&x, 0);

  return x;
}

static inline uint16_t softspi_read_uint16(void)
{
  /* msB ordering */
  const uint8_t x = softspi_read_uint8();
  return ((uint16_t)x << 8) | (uint16_t)softspi_read_uint8();
}

#endif /* SOFTSPI_DONT_USE_MISO == 0 */

Finite State Machine Template

Gabriel Rivas March 28, 20131 comment Coded in C
/*********************************************************************
Finiste State Machine design example

FSM based embedded software design has several advantages:
1. You can translate the systems' requirements into FSM diagramas or
state transition tables.
2. From the FSM diagram or state transition table you can validate if the design
is right or wrong before actually start coding.
3. It makes the code easier to understand
4. You can have traceability from the requirements document to the
code
5. Determinism; you can now exactly what the system is doing at any time
6. Hmmm I don't know, they just look good in C! 

In this code Example it is shown how to implement the following FSM
state transition table into C code. You can use this as a template by 
replacing inputs and outputs sets, set of states by your actual application 
values.

I hope this helps.

Current State	INPUT_0	INPUT_1	INPUT_2	INPUT_3	Next State	OUTPUT_0
DETECT_IN0	    0	    X	    X	    X	    DETECT_IN1	0
	            1	    X	    X	    X	    DETECT_IN0	0
DETECT_IN1	    X	    0	    X	    X	    DETECT_IN2	0
	            X	    1	    X	    X	    DETECT_IN1	0
DETECT_IN2	    X	    X	    0	    X	    DETECT_IN3	0
	            X	    X	    1	    X	    DETECT_IN2	0
DETECT_IN3	    X	    X	    X	    0	    SET_OUTPUT	0
	            X       X	    X	    1	    DETECT_IN3	0
SET_OUTPUT	    X	    X	    X	    X	    DETECT_IN0	1
	            X	    X	    X	    X	    DETECT_IN0	1
 *
 ********************************************************************/
 
#include <stdio.h>

/*Inputs and outputs sets
You can give meaningful names to the IO ports of your microcontroller,
and that will make the code easier to understand and make it consistent
with a FSM diagram or state transition table
*/
#define INPUT_0  PTA0
#define INPUT_1  PTA1
#define INPUT_2  PTA2
#define INPUT_3  PTA3
#define OUTPUT_0 PTB0

/*
The inputs have pull-ups resistors so we can define a condition
to identify when an input has been selected, in this case an
input is selected when its value is 0
*/
#define SELECTED 0x00

/*Set of states
It is more convenient to give meaningful names to the states
and it's better when you can map them to a finite state machine
diagram or state transition table.
*/
typedef enum { DETECT_IN0 = 0x00, 
               DETECT_IN1, 
               DETECT_IN2, 
               DETECT_IN3, 
	       SET_OUTPUT} SM_STATES;

/*We need a state variable to store the next state value as well
and we have to assign an initial state to it
*/
unsigned char state = DETECT_IN0;

int ctr_ms = 500;  /*This finite state machine executes every 500 ms*/

/*wait function*/
static unsigned char wait_ms(void);

void main(void) {
    for(;;) {
        if(wait_ms()) {  /*The state machine is synch to a timer*/
            switch(state) {
                case DETECT_IN0:
                    OUTPUT_0 = 0;
                    if(INPUT_0 == SELECTED) {   
                        state = DETECT_IN1;					
                    }
                    break;
                case DETECT_IN1:
                    if(INPUT_1 == SELECTED) {   
                        state = DETECT_IN2;					
                    }
                    break;		
                case DETECT_IN2:
                    if(INPUT_2 == SELECTED) {   
                        state = DETECT_IN3;					
                    }
                    break;	
                case DETECT_IN3:
                    if(INPUT_3 == SELECTED) {   
                        state = SET_OUTPUT;					
                    }
                    break;	
                case SET_OUTPUT:
                    OUTPUT_0 = 1;
		    state = DETECT_IN0;	
                    break;					
                default:
                /*None of the above*/
                break;                
            }
	}
    } /* loop forever */
  /* please make sure that you never leave main */
}

unsigned char wait_ms(void) {
    unsigned char ctr_flag;
    
    ctr_flag = 0;

	/*Test for timer overflow flag*/
    if(TPM_Get_OVFlag() == 1) {     
        if (ctr_ms == 0) {
            ctr_flag = 1;
         } else {
            ctr_ms--;  
         }
         TPM_Clr_OVFlag();          
     }
     return ctr_flag; 
}

SHT11 humidity sensor library (sensirion manufacture)

March 25, 20131 comment Coded in C
/*********** begin of library header file sht11.h ***************/

#ifndef _SHTXX_H
#define _SHTXX_H

#include <inttypes.h>

#define HUMIDITY_BYTE    0x05
#define TEMPERATURE_BYTE 0x03

//State machine states

#define SHT_DATA_WAIT_INITIAL_STATE     0
#define SHT_DATA_WAIT_TIMEOUT_STATE     1

#define SHT_PROC_RESET_COND_STATE       0   
#define SHT_PROC_START_COND_STATE       1
#define SHT_PROC_SEND_STATE             2
#define SHT_PROC_WAIT_STATE             3
#define SHT_PROC_RETURN_STATE           4

#define SHT_RH_READ_TEMPERATURE_STATE   0
#define SHT_RH_READ_HUMIDITY_STATE      1
#define SHT_RH_CONVERT_RH_STATE         2

#include <sht_low_level_drv.h>

void shtxx_init(void);

int shtxx_proc(uint8_t sht_param,uint16_t *ret_value);

int shtxx_get_temp(uint16_t *ret_temperature);
int shtxx_get_temp_RH( int16_t *ret_temperature, int16_t *ret_humidity );

#endif /* _SHTXX_H */

/*********** begin of library source file sht11.c ***************/
#include "sht11.h"

void shtxx_init( void )
{
    shtxx_set_db();
    shtxx_set_cb();
}

void shtxx_wait( void ) //SHT_WAIT should be tuned acording to MCU clock
{
    volatile int wait_cnt;
    for ( wait_cnt = 0; wait_cnt < SHT_WAIT;wait_cnt )
    {
        wait_cnt++;
    }
}

void shtxx_reset_condition( void )
{
    uint8_t i;
    shtxx_set_db();
    shtxx_set_out_data_dir();
    for ( i = 0;i < 12;i++ )
    {
        if ( i % 2 == 0 )
            shtxx_set_cb();
        else
            shtxx_clr_cb();
        shtxx_wait();
    }
}

void shtxx_start_condition( void )
{
    shtxx_set_db();
    shtxx_set_out_data_dir();
    shtxx_wait();
    shtxx_set_cb();
    shtxx_wait();
    shtxx_clr_db();
    shtxx_wait();
    shtxx_clr_cb();
    shtxx_wait();
    shtxx_wait();
    shtxx_set_cb();
    shtxx_wait();
    shtxx_set_db();
    shtxx_wait();
    shtxx_clr_cb();
    shtxx_wait();

}

int shtxx_send_byte( uint8_t sht_data2send )
{
    uint8_t i = 0;
    while ( i <= 7 )
    {
        if ( ( ( sht_data2send << i++ ) & 0x80 ) == 0x80 )
            shtxx_set_db();
        else
            shtxx_clr_db();
        shtxx_set_out_data_dir();
        shtxx_wait();
        shtxx_set_cb();
        shtxx_wait();
        shtxx_clr_cb();

    }
    shtxx_set_in_data_dir();
    shtxx_wait();
    shtxx_set_cb();
    shtxx_wait();
    if ( shtxx_get_db() == 0 )
        return 1;

    else
        return -1;
}

int shtxx_data_wait( sht_ticks_t sht_timeout )
{
    static uint8_t sht_wait_state;
    static sht_ticks_t sht_previous_ticks;

    switch ( sht_wait_state )
    {
    case SHT_DATA_WAIT_INITIAL_STATE:
        sht_previous_ticks = sht_msec_ticks;
        sht_wait_state = SHT_DATA_WAIT_TIMEOUT_STATE;
        shtxx_set_in_data_dir();
        shtxx_clr_cb();

    case SHT_DATA_WAIT_TIMEOUT_STATE:
        if ( shtxx_get_db() == 0 )
        {
            sht_wait_state = SHT_DATA_WAIT_INITIAL_STATE;
            return 1;
        }
        else
        {
            if ( ( sht_msec_ticks - sht_previous_ticks ) > sht_timeout )
            {
                sht_wait_state = SHT_DATA_WAIT_INITIAL_STATE;
                return -1;
            }
            else
                return 0;
        }
    }
}

uint8_t sht_read_byte( uint8_t sht_ack )
{
    shtxx_set_in_data_dir();
    uint8_t temp_rx_buff = 0;
    int8_t i = 7;
    while ( i >= 0 )
    {
        shtxx_wait();
        shtxx_set_cb();
        temp_rx_buff |= ( ( shtxx_get_db() & 0x01 ) << i );
        i--;
        shtxx_wait();
        shtxx_clr_cb();

    }

    if ( sht_ack == 1 )
    {
        shtxx_clr_db();
        shtxx_set_out_data_dir();
        shtxx_wait();
        shtxx_set_cb();
        shtxx_wait();
        shtxx_clr_cb();
        shtxx_set_in_data_dir();

    }
    return temp_rx_buff;
}

int shtxx_proc( uint8_t sht_param, uint16_t *ret_value )
{

    static uint8_t sht_proc_state = 0;
    int8_t	wait_status;

    switch ( sht_proc_state )
    {
    case SHT_PROC_RESET_COND_STATE:
        shtxx_reset_condition();
    case SHT_PROC_START_COND_STATE:
        shtxx_start_condition();
    case SHT_PROC_SEND_STATE:
        shtxx_send_byte( sht_param );
    case SHT_PROC_WAIT_STATE:
        wait_status = shtxx_data_wait( 300 );
        if ( wait_status == -1 )
        {
            sht_proc_state = SHT_PROC_RESET_COND_STATE;
            return -1;

        }
        if ( wait_status == 0 )
        {
            sht_proc_state = SHT_PROC_WAIT_STATE;
            return 0;
        }
        else
            sht_proc_state = SHT_PROC_RETURN_STATE;
    case SHT_PROC_RETURN_STATE:
        *ret_value = ( ( uint16_t ) sht_read_byte( 1 ) << 8 );
        shtxx_wait();
        *ret_value += sht_read_byte( 0 );
        sht_proc_state = SHT_PROC_START_COND_STATE;
        return 1;

    }
}

int shtxx_get_temp( uint16_t *ret_temperature )
{
    static uint16_t tmp_temp;
    if ( shtxx_proc( TEMPERATURE_BYTE, &tmp_temp ) == 1 )
    {
        *ret_temperature = tmp_temp - 3965;
        return 1;
    }
    else
        return 0;
}

int shtxx_get_temp_RH( int16_t *ret_temperature, int16_t *ret_humidity )
{

    static uint8_t sht_humidity_state;
    static uint16_t sht_humidity_raw;
    static uint16_t sht_temp_C;

    static float RH_linear;
    static float RH_compensated;

    switch ( sht_humidity_state )
    {
    case SHT_RH_READ_TEMPERATURE_STATE:
        if ( shtxx_get_temp( &sht_temp_C ) )
            sht_humidity_state = SHT_RH_READ_HUMIDITY_STATE;
        break;
    case SHT_RH_READ_HUMIDITY_STATE:
        if ( shtxx_proc( HUMIDITY_BYTE, &sht_humidity_raw ) )
            sht_humidity_state = SHT_RH_CONVERT_RH_STATE;
        break;
    case SHT_RH_CONVERT_RH_STATE:
        RH_linear = ( float ) ( ( 0.0405 * ( float ) sht_humidity_raw ) - ( 0.0000028 * ( float ) sht_humidity_raw * ( float ) sht_humidity_raw ) - 4 );
        RH_compensated = ( float ) ( ( ( ( ( ( float ) sht_temp_C ) / 100 ) - 25 ) * ( 0.01 + ( 0.00008 * ( float ) sht_humidity_raw ) ) ) + RH_linear );
        sht_humidity_state = SHT_RH_READ_TEMPERATURE_STATE;
        *ret_temperature = sht_temp_C;
        *ret_humidity = ( ( int16_t ) ( RH_compensated * 100 ) );
        return 1;
    default:
        sht_humidity_state = SHT_RH_READ_TEMPERATURE_STATE;
    }
	return 0;
}

/*** sample low-level functions (platform dependent) sht_low_level_drv.h ***/

#ifndef _SHT_LOW_LEVEL_DRV_H
#define _SHT_LOW_LEVEL_DRV_H

#include <types.h>
#include <system_def.h> /* for concrete HW,  SHT_PORT, SHT_DATA_BIT must be defined*/

#define SHT_MAX_CLK		100000
#define SHT_WAIT		(CCLK/SHT_MAX_CLK) /* CCLK is MCU clock */
#define sht_ticks_t		uint32_t
#define sht_msec_ticks		sys_timer_ticks /* this variable should be defined in BSP and incremented each ms (usually in some timer interrupt routine) */

static inline void shtxx_set_db(void)
{
	
	SET_OUT_PIN(SHT_PORT,SHT_DATA_BIT);
}

static inline void shtxx_clr_db(void)
{
	CLR_OUT_PIN(SHT_PORT,SHT_DATA_BIT);
}

static inline void shtxx_set_cb(void)
{
	SET_OUT_PIN(SHT_PORT,SHT_CLK_BIT);
}

static inline void shtxx_clr_cb(void)
{
	CLR_OUT_PIN(SHT_PORT,SHT_CLK_BIT);
}

static inline uint8_t shtxx_get_db(void)
{
	return(	GET_IN_PIN(SHT_PORT,SHT_DATA_BIT) );	
}

static inline void shtxx_set_in_data_dir(void)
{
	IO0DIR &=~(SHT_DATA_BIT);
}

static inline void shtxx_set_out_data_dir(void)
{
	IO0DIR |= SHT_DATA_BIT ;
}

#endif /* _SHT_LOW_LEVEL_DRV_H */

/********************* sample usage in main program ************************/

//..............
int16_t temperature, humidity;

while(1) //main loop of the user program
{
    if (shtxx_get_temp_RH( &temperature, &humidity )
    {
        //do something
    }
    //do other operations
    //.....................      
}

Interface matrix Keypad

March 25, 2013 Coded in C for the Microchip PIC16
/Keypad connection: 

#define col0 PIN_B3
#define col1 PIN_B2
#define col2 PIN_B1
#define col3 PIN_B0
#define row0 PIN_B7
#define row1 PIN_B6
#define row2 PIN_B5
#define row3 PIN_B4

#define num_col 4

// Keypad layout:
char const KEYS[4][4] = {{1,2,3,13},
                         {4,5,6,14},
                         {7,8,9,15},
                         {11,10,12,16}};

void init_keypad()
{
	output_high(row0);
	output_high(row1);
	output_high(row2);
	output_high(row3);
	output_low(col0);
	output_low(col1);
	output_low(col2);
	output_low(col3);	
}

short int ALL_ROWS (void)
{
   if (input (row0) & input (row1) & input (row2) & input (row3))
      return (0);
   else
      return (1);
}

//Will return a key value if pressed or 0 if not 

int8 get_key()
{
int8 row,col=0;
	do	
	{
		switch (col)
		{
			case 0   :
				output_low(col0);
				output_high(col1);
				output_high(col2);
				output_high(col3);
				break;
			case 1   :
				output_high(col0);
				output_low(col1);
				output_high(col2);
				output_high(col3);
				break;
			case 2   : 
				output_high(col0);
				output_high(col1);
				output_low(col2);
				output_high(col3);
				break;
			case 3   : 
				output_high(col0);
				output_high(col1);
				output_high(col2);
				output_low(col3);
				break;                    
		}
		
		if(!input (row0))
			row=1;
		else if(!input (row1))
			row=2;
		else if(!input (row2))
			row=3;
		else if(!input (row3))
			row=4;
		else
			row=0;
		col++;
	}while(!row && col<num_col);	
	if(row)
        return KEYS[row-1][col-1];
    else
        return 0;		
}
//function waits until any key is pressed and released.
int8 get_key_released()
{
int8 _key_temp ;
    do
    {
        _key_temp=get_key();
    }while(!_key_temp);
    init_keypad();
    do
    {
        while(ALL_ROWS());
        delay_ms(50);
    }
    while(ALL_ROWS());
return _key_temp;
}