EmbeddedRelated.com
Code Snippets

Very simple software timer framework

April 5, 2013 Coded in C
/*********************************************************************************/
/*                                sample usage                                   */
/*********************************************************************************/
#include <lt_timer.h>

LT_TIMER_DEC(slow_timer)		/* declaration */
LT_TIMER_IMP(slow_timer)		/* implementation */

LT_TIMER_DEC(fast_timer)		/* declaration */
LT_TIMER_IMP(fast_timer)		/* implementation */

int main(void)
{
    fast_timer_init();
    slow_timer_init();

    while(1)
    {
	if (slow_timer_expired(1000))
	{
	    //do something each 1000ms 
	}

	if (fast_timer_expired(10))
	{
	    //do something each 10ms 
        }		
	//...............
        //main program functionality
        //...............	
    }
}

/*********************************************************************************/
/*                           lt_timer definition                                 */
/*********************************************************************************/
#ifndef _LT_TIMER_H
#define _LT_TIMER_H

#include <stdint.h>

/* these definitions can vary on different platforms */
typedef unsigned int lt_ticks_t;
typedef int lt_tidiff_t;
typedef unsigned long lt_mstime_t;
typedef signed long lt_msdiff_t;

static lt_ticks_t last_ticks;
static lt_mstime_t actual_msec; 

/* it is expected increment "sys_timer_ticks" variable in some timer interrupt */
/* alternatively some function which return ticks can be provided */
#define lt_get_ticks()      (sys_timer_ticks)		
										
/* in ms (SYS_TIMER_HZ must be provided by user)*/									
#define lt_get_msbase()     (1000/SYS_TIMER_HZ)		

static inline void
lt_mstime_update()
{
  lt_ticks_t act_ticks;
  lt_mstime_t msec_diff;

  act_ticks=lt_get_ticks();
  msec_diff=((lt_tidiff_t)(act_ticks-last_ticks))*lt_get_msbase();
  last_ticks=act_ticks;

  actual_msec+=msec_diff;
}

#define LT_TIMER_DEC(cust_prefix) \
\
extern lt_mstime_t cust_prefix##_last_expired; \
static inline void \
cust_prefix##_init() \
{\
  lt_mstime_update();\
  cust_prefix##_last_expired=actual_msec;\
}\
static inline int \
cust_prefix##_expired(lt_mstime_t expiration) \
{\
  lt_mstime_update();\
  \
  if ((lt_msdiff_t)(actual_msec-cust_prefix##_last_expired)>=expiration) {\
    cust_prefix##_last_expired=actual_msec;\
    return 1;\
  }\
  \
  return 0;\
}

#define LT_TIMER_IMP(cust_prefix) \
\
lt_mstime_t cust_prefix##_last_expired; \

#endif /* _LT_TIMER_H */

General library for debouncing (filtering) of digital inputs

April 3, 2013 Coded in C
/**************************************************************************************/
/*                            sample usage of the library                             */
/**************************************************************************************/

//Remark: sys_timer_ticks should be provided for timing by the user.

/* Simplest example with undefined CONFIG_DEBOUNCE_WITH_HANDLE and CONFIG_DEBOUNCE_SEPARATE_TIMES */

#include <debounce.h>

#define INPUTS_NUM		12
nl_debouce_time_t inp_times[ INPUTS_NUM ];
nl_debouce_time_t filt_time = 10;   //same value will be used for t_on and t_off

int main(void)
{
    nl_inp_t inp_state, filtered_inp_state;

    debounce_init( inp_times, INPUTS_NUM, &filt_time, &filt_time, 
            (nl_ticks_t*)&sys_timer_ticks );

    while(1)
    {
        //user defined function, which return actual state of all inputs as bit array
        inp_state = get_input_state();

        debounce_proc(&inp_state, &filtered_inp_state);
        //do something with filtered_inp_state 

        //...............
        //main program functionality 
        //...............
    }
}

/* More complex example with defined CONFIG_DEBOUNCE_WITH_HANDLE and CONFIG_DEBOUNCE_SEPARATE_TIMES */
#include <debounce.h>

#define INPUTS_NUM		5
struct debounce_state_s inp_dbnc_s;
nl_debouce_time_t inp_times[ INPUTS_NUM ];

nl_debouce_time_t t_on[ INPUTS_NUM ] = {10,10,20,20,50};   
nl_debouce_time_t t_off[ INPUTS_NUM ] = {5,5,10,10,50};   

int main(void)
{
    nl_inp_t inp_state, filtered_inp_state;

    debounce_init( &inp_dbnc_s, inp_times, INPUTS_NUM, 
        t_on, t_off, (nl_ticks_t*)&sys_timer_ticks );

    while(1)
    {
        //user defined function, which return actual state of all inputs as bit array
        inp_state = get_input_state();

        debounce_proc(&inp_dbnc_s, &inp_state, &filtered_inp_state);
        //do something with filtered_inp_state 

        //...............
        //main program functionality 
        //...............
    }
}

/**************************************************************************************/
/*                     debounce library header file "debounce.h"                      */
/**************************************************************************************/
#ifndef _DEBOUNCE_H_
#define _DEBOUNCE_H_
    
#include <stdint.h>

/* because library is multiplatform, following types are defined in separate file */
#include "nlib_types.h"
/* examaple of types definition in "nlib_types.h" */
//typedef   uint32_t    nl_ticks_t;
//typedef   int16_t nl_debouce_time_t;  //so maximum filter time is 32767ms (considering period of ticks 1ms)
//typedef   uint32_t nl_inp_t;  //up to 32 inputs can be handled

/* in general case following macros should be provided in this header file, or can be defined directly */
#include <debounce_config.h>
//#define CONFIG_DEBOUNCE_WITH_HANDLE
//#define CONFIG_DEBOUNCE_SEPARATE_TIMES
    
#ifdef CONFIG_DEBOUNCE_WITH_HANDLE
    #define DEBOUNCE_STRUCT_PAR  struct debounce_state_s * debounce_state,
#else
    #define DEBOUNCE_STRUCT_PAR
#endif

typedef struct debounce_state_s
{
    const nl_ticks_t* ticks; //pointer to timing variable (is incremented e.g. each 1ms)
    nl_ticks_t old_ticks;
    uint_fast8_t inp_num; //number of inputs
    const nl_debouce_time_t *debounce_on_time,*debounce_off_time; //tables with desired filter times
    nl_debouce_time_t* inp_times;   //actual time ON/OFF - non-negative values = ON, negative = OFF
}
debounce_state_t;

void debounce_init(DEBOUNCE_STRUCT_PAR nl_debouce_time_t* inp_tim, uint_fast8_t num, const nl_debouce_time_t *dton,const nl_debouce_time_t *dtoff, const nl_ticks_t* ticks);
uint_fast8_t debounce_proc(DEBOUNCE_STRUCT_PAR const nl_inp_t* act_inp_state, nl_inp_t* debounced_inp_state);

#endif /*_DEBOUNCE_H_*/

/**************************************************************************************/
/*                     debounce library source file "debounce.c"                      */
/**************************************************************************************/

#include "debounce.h"
#include <string.h>

//allow using multiple instances
#ifndef CONFIG_DEBOUNCE_WITH_HANDLE
    struct debounce_state_s _debounce_state_;
    struct debounce_state_s * debounce_state = &_debounce_state_;
#endif

/* allow different times for each input */
#ifndef CONFIG_DEBOUNCE_SEPARATE_TIMES
    #define _debounce_times_idx_ 0
#else
    #define _debounce_times_idx_ i
#endif

//maco trick to find maximum value of given signed integer type "http://www.fefe.de/intof.html"
#define __HALF_MAX_SIGNED(type) ((type)1 << (sizeof(type)*8-2))
#define __MAX_SIGNED(type) (__HALF_MAX_SIGNED(type) - 1 + __HALF_MAX_SIGNED(type))

/*
Init function of the library
	
  DEBOUNCE_STRUCT_PAR - depending on "CONFIG_DEBOUNCE_WITH_HANDLE": nothing, or pointer to handle
  inp_tim - array of variables for storing of state for each input (number of elements must be the same as number of inputs!)
  num - number of inputs
  dton - depending on "CONFIG_DEBOUNCE_SEPARATE_TIMES": pointer to sigle value (minimal ON time), or array of times
  dtoff - depending on "CONFIG_DEBOUNCE_SEPARATE_TIMES": pointer to sigle value (minimal OFF time), or array of times
  ticks - pointer to variable, which is periodicaly incremented
*/
void debounce_init(DEBOUNCE_STRUCT_PAR nl_debouce_time_t* inp_tim, uint_fast8_t num, const nl_debouce_time_t *dton, const nl_debouce_time_t *dtoff ,const nl_ticks_t* ticks)
{
    debounce_state-> inp_times=inp_tim;
    debounce_state-> inp_num=num;
    debounce_state-> debounce_on_time=dton;
    debounce_state-> debounce_off_time=dtoff;
    debounce_state-> ticks=ticks;
    debounce_state-> old_ticks=*ticks;
    memset(inp_tim,0,sizeof(*inp_tim)*num);
    inp_tim[0]=__MAX_SIGNED(nl_debouce_time_t);  //this is used later to evaluate first iteration after start
}

/*
This is core function of the library
	
  DEBOUNCE_STRUCT_PAR - depending on "CONFIG_DEBOUNCE_WITH_HANDLE": nothing, or pointer to handle
  act_inp_state - pointer to variable with actual state of all inputs (1 bit for each input)
  debounced_inp_state - resulting state after filtering
  return - 0=no change, 1=some input(s) are changed 
*/
uint_fast8_t debounce_proc(DEBOUNCE_STRUCT_PAR const nl_inp_t* act_inp_state, nl_inp_t* debounced_inp_state)
{
    uint_fast8_t i,change=0;
    nl_inp_t mask=1;
    nl_ticks_t tic_diff;

    tic_diff=(nl_ticks_t) (*(debounce_state-> ticks) - debounce_state-> old_ticks);
    debounce_state-> old_ticks = *(debounce_state-> ticks);

    if ((debounce_state-> inp_times)[0] == __MAX_SIGNED(nl_debouce_time_t)) //evaluate, if it is a first iteration
    {
        *debounced_inp_state=*act_inp_state;
        for(i=0; i<debounce_state-> inp_num ;i++)
            (debounce_state-> inp_times)[i]=0;
        return 0;
    }

    for(i=0; i<debounce_state-> inp_num ;i++)
    {
        if ( *act_inp_state & mask) //actual state is ON
        {
            if ((debounce_state-> inp_times)[i] >= 0) //and last state was ON
            {
                if (((debounce_state-> inp_times)[i] + (nl_debouce_time_t) tic_diff) < debounce_state-> debounce_on_time[_debounce_times_idx_])
                {
                    (debounce_state-> inp_times)[i] += (nl_debouce_time_t) tic_diff; //filter time not elapsed
                }
                else
                {   //filter time elapsed
                    if (!( *debounced_inp_state & mask))
                    {
                        *debounced_inp_state |= mask;
                        change=1;
                    }
                }
            }
            else (debounce_state-> inp_times)[i] = 0;
        }
        else    //actual state is OFF
        {
            if (debounce_state-> inp_times[i] < 0) //and last state was OFF
            {
                if ( (nl_debouce_time_t)(((debounce_state-> inp_times)[i] - (nl_debouce_time_t) tic_diff)) >= (-1*debounce_state-> debounce_off_time[_debounce_times_idx_]))
                {
                    (debounce_state-> inp_times)[i] -= (nl_debouce_time_t) tic_diff; //filter time not elapsed
                }
                else
                {   //filter time elapsed
                    if ( *debounced_inp_state & mask)
                    {
                        *debounced_inp_state &= ~mask;
                        change=1;
                    }
                }
            }
            else (debounce_state-> inp_times)[i] = -1;
        }
        mask=(nl_inp_t) mask<<1;

    }
    return change;
}

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
    //.....................      
}