Very simple software timer framework
/*********************************************************************************/
/* 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 */
Incremental Encoder Decode Trick
// Incremental encoder decoding.
uint new;
uint old;
bool direction;
int count=0;
/* Get the latest 2bit sample. */
new = get_new_bits(); // Your function to get new samples.
/* XOR the lower bit from the new sample with the upper bit from the old.*/
direction = (new&1) ^ (old>>1)
/* The "direction" var holds the direction of rotation. */
/* Transfer the new sample to the old sample. */
old = new;
/* We can use this to inc or dec a counter to maintain position of rotation. */
if(direction) counter--; else counter++;
Sine Wave Generator
/*************************************************************************************************************
sineWaveGeneration
*************************************************************************************************************/
void sineWaveGeneration(unsigned long amplitude, unsigned long frequency, unsigned long time)
{
const double angularfrequency = (2.0 * pi) * (double)frequency;
const double pi = 3.141592654;
double timeperiod;
const double samplingrate = 48000;
double displacement;
//declare values
//obtain omega(the angular frequency)
// creates a 'for' loop that continues until 'endtime'
for (timeperiod = 0; timeperiod <= (double)time; timeperiod = timeperiod+(1/samplingrate))
{
//creates the sine wave A*sin(wt) by plotting every sample.
displacement = sin(angularfrequency * timeperiod) * amplitude;
}
return;
}
Embedded Linux Frequency Meter
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/arch/gpio.h>
#include <asm/arch/dmtimer.h>
/*
The prescaler is enabled when TCLR bit 5 is set (PRE). The 2n division ratio value
(PTV) can be configured in the TCLR register.
Each internal interrupt source can be independently enabled/disabled in the interrupt
enable register TIER.
When the interrupt event has been issued, the associated interrupt status bit is set
in the timer status register (TISR). The pending interrupt event is reset when the
set status bit is overwritten by a 1.
The timer rate is defined by:
-Value of the prescaler fields (PRE and PTV of TCLR register)
-Value loaded into the timer load register (TLDR)
timer rate = (0xFFFF FFFF – TLDR + 1) x timer clock period x clock divider (PS)
PTV + 1)
PS = 2
*/
static unsigned long freq , ct, round;
extern struct omap_dm_timer * frequencimeter; // timer reserved to measure frequency
static irqreturn_t gpio4_freqmeter_irq_handler(int irq, void *arg);
static int __init freqmeter_init(void)
{
int r;
round = 0; freq = 0 ; ct = 0;
printk(KERN_DEBUG "Init driver Freqmeter.\n");
/* request gpios*/
/* GPIO - P20_1610_GPIO4 */
if ( omap_request_gpio(4) < 0 ) printk(KERN_ERR "Error init GPIO4 (freqmeter).\n");
/* entrada */
omap_set_gpio_direction(4,1); /* in */
r = request_irq(OMAP_GPIO_IRQ(4), gpio4_freqmeter_irq_handler, IRQF_TRIGGER_RISING, "freqmeter", gpio4_freqmeter_irq_handler);
if ( r < 0 ) {
printk(KERN_ERR "freqmeter: request_irq() failed.\n");
return r;
}
printk(KERN_DEBUG "freqmeter initialized.\n");
return 0;
}
static irqreturn_t gpio4_freqmeter_irq_handler(int irq, void *arg)
{
// dummy: no interrupt? freq = 0Hz
// only one int? freq = 0Hz
/** there is interference?: lread INT again
should be in same logic level */
if ( omap_get_gpio_datain(4) )
{
if(round > 0)
{
if(round == 50)
{
ct = omap_dm_timer_read_counter(frequencimeter);
omap_dm_timer_stop(frequencimeter);
ct /= 50;
freq = 1200000000/(ct +1);
printk("freq = %d\n",(freq/*-8*/));
round = 0xFFFFFFFF;
ct = 0;
freq = 0;
}
}
else // first read
{
freq = 0;
printk(KERN_DEBUG "Iniciou o freqmeter");
omap_dm_timer_write_counter(frequencimeter,0x0);
omap_dm_timer_start(frequencimeter);
}
round++;
}
return IRQ_HANDLED;
}
asmlinkage long sys_freq_read(void)
{
return freq;
}
static void __exit freqmeter_cleanup(void)
{
free_irq(OMAP_GPIO_IRQ(4), NULL);
omap_free_gpio(4);
}
module_init(freqmeter_init);
module_exit(freqmeter_cleanup);
MODULE_LICENSE("GPL");
Arithmetic Operations
UDATA
HIBYTE RES 1
LOBYTE RES 1
COUNTX RES 1
MULCND RES 1
MULPLR RES 1
BCD RES 2
ACCaLO res 1
ACCaHI res 1
ACCbLO res 1
ACCbHI res 1
ACCcLO res 1
ACCcHI res 1
ACCdLO res 1
ACCdHI res 1
R2 res 1
R1 res 1
R0 res 1
TEMPX res 1
L_temp res 1
H_temp res 1
w_save res 1
RandHi res 1
RandLo res 1
parity res 1
;*************************************************************************
; Multiplication MULPLR(8 bit) x MULCND(8 bit) -->HIBYTE(msb),LOBYTE(lsb)*
; a) Load the multiplier in the location MULPLR *
; b) Load the multiplicant in the location MULCND *
; c) Call Mpy8x8 *
; d) Msb is in the location HIBYTE *
; e) Lsb is in the location LOBYTE *
;*************************************************************************
Mpy8x8
clrf HIBYTE
clrf LOBYTE
clrf COUNTX
bsf COUNTX, 3
movf MULCND, W
LoopX
bcf STATUS, C
btfsc MULPLR, 0
addwf HIBYTE, f
rrf HIBYTE, f
rrf LOBYTE, f
bcf STATUS, C
rrf MULPLR, f
decfsz COUNTX, f
goto LoopX
return
;*******************************************************************
;Multiplication: ACCb(16 bits)*ACCa(16 bits) -> ACCb,ACCc (32 bits)*
;(a) Load the 1st operand in location ACCaLO & ACCaHI (16 bits) *
;(b) Load the 2nd operand in location ACCbLO & ACCbHI (16 bits) *
;(c) CALL Mpy_16bit *
;(d) The 32 bit result is in location (ACCbHI,ACCbLO,ACCcHI,ACCcLO)*
;*******************************************************************
Mpy_16bit
movlw .16 ; for 16 shifts
movwf temp
movf ACCbHI,W ; move ACCb to ACCd
movwf ACCdHI
movf ACCbLO,W
movwf ACCdLO
clrf ACCbHI
clrf ACCbLO
Mloop
rrf ACCdHI, F ;rotate d right
rrf ACCdLO, F
btfsc STATUS,C ;need to add?
call Add_16bit
rrf ACCbHI, F
rrf ACCbLO, F
rrf ACCcHI, F
rrf ACCcLO, F
decfsz temp, F ;loop until all bits checked
goto Mloop
return
;******************************************************************
;This routine convert the hex value present in the WREG to decimal*
;and store the results in the reg: BCD and BCD+1 *
;******************************************************************
BinBCD
clrf BCD
clrf BCD+1
Again1
addlw 0x9C ;subtract 100 and check for borrow
btfss STATUS, C
goto add100
incf BCD+1, f
goto Again1
add100
addlw 0x64
Again
addlw 0xF6 ;subtract 10 and check for borrow
btfss STATUS, C
goto SwapBCD
incf BCD, f
goto Again
SwapBCD
addlw 0x0A
swapf BCD, f
iorwf BCD, f
return
;***************************************************************
;This routine find the square of the number present in the WREG*
;The hex result is stored in WREG and the decimal result is *
;stored in GPRs BCD and BCD+1 *
;***************************************************************
square
movwf COUNTX
movlw 0x01
movwf TEMPX
clrw
r_square
addwf TEMPX,W
incf TEMPX,F
incf TEMPX,F
decfsz COUNTX,F
goto r_square
movwf w_save
call BinBCD
movf w_save,W
return
;*******************************************************************
;This routine find the square root of a number which is stored in *
;WREG.The result is stored in WREG.If the number hasn't a finite *
;square root this function returns an error value EE in WREG *
;*******************************************************************
square_root
movwf w_save
movlw 0x01
movwf TEMPX
movwf COUNTX
loop
movf TEMPX,W
subwf w_save,f
btfsc STATUS,Z
goto zero
btfss STATUS,C
goto no_root
incf COUNTX,F
incf TEMPX,F
incf TEMPX,F
goto loop
zero
movf COUNTX,W
return
no_root
movlw 0XEE
return
;********************************************************************
; Binary To BCD Conversion Routine *
; This routine converts a 16 Bit binary Number to a 5 Digit *
; BCD Number. *
; The 16 bit binary number is input in locations ACCaHI and *
; ACCaLO with the high byte in ACCaHI. *
; The 5 digit BCD number is returned in R0, R1 and R2 with R0 *
; containing the MSD in its right most nibble. *
;********************************************************************
Hex_to_Dec
bcf STATUS, C
clrf COUNTX
bsf COUNTX, 4 ;set count to 16
clrf R0
clrf R1
clrf R2
Loop16a
rlf ACCaLO, f
rlf ACCaHI, f
rlf R2, f
rlf R1, f
rlf R0, f
decfsz COUNTX, f
goto Adjdec
return
Adjdec
movlw R2 ;load as indirect address pointer
movwf FSR
call AdjBCD
incf FSR, f
call AdjBCD
incf FSR, f
call AdjBCD
goto Loop16a
AdjBCD
movf INDF, w
addlw 0x03
movwf TEMPX
btfsc TEMPX,3;test if result > 7
movwf INDF
movf INDF, w
addlw 0x30
movwf TEMPX
btfsc TEMPX, 7 ;test if result > 7
movwf INDF ;save as MSD
return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Division : ACCb(16 bits) / ACCa(16 bits) -> ACCd(16 bits) with ;
; Remainder in ACCc (16 bits) ;
; (a) Load the Denominator in location ACCaHI & ACCaLO ( 16 bits );
; (b) Load the Numerator in location ACCbHI & ACCbLO ( 16 bits ) ;
; (c) CALL Division ;
; (d) The 16 bit result is in location ACCdHI & ACCdLO ;
; (e) The 16 bit Remainder is in locations ACCcHI & ACCcLO ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Division
clrf COUNTX
bsf COUNTX,4 ; set count = 16
clrf ACCcHI
clrf ACCcLO
clrf ACCdLO
clrf ACCdHI
divLoop
bcf STATUS,C
rlf ACCbLO,F
rlf ACCbHI,F
rlf ACCcLO,F
rlf ACCcHI,F
movf ACCaHI,W
subwf ACCcHI,W ; check if a>c
btfss STATUS,Z
goto notz
movf ACCaLO,W
subwf ACCcLO,W ; if msb equal then check lsb
notz
btfss STATUS,C ; carry set if c>a
goto nosub ; if c < a
subca
movf ACCaLO,W ; c-a into c
subwf ACCcLO, F
movf ACCaHI,W
subwf ACCcHI, F
bsf STATUS,C ; shift a 1 into d (result)
nosub
rlf ACCdLO,F
rlf ACCdHI,F
decfsz COUNTX,F
goto divLoop
return
;*******************************************************************
; Random Number Generator *
; This routine generates a 16 Bit Pseudo Sequence Random Generator *
; It is based on Linear shift register feedback. The sequence *
; is generated by (Q15 xorwf Q14 xorwf Q12 xorwf Q3 ) *
; The 16 bit random number is in location RandHi(high byte) *
; & RandLo (low byte) *
; Before calling this routine, make sure the initial values *
; of RandHi & RandLo are NOT ZERO *
; A good chiose of initial random number is 0x3045 *
;*******************************************************************
Random16
rlf RandHi,W
xorwf RandHi,W
movwf w_save
rlf w_save, F ; carry bit = xorwf(Q15,14)
swapf RandHi, F
swapf RandLo,W
movwf w_save
rlf w_save, F
xorwf RandHi,W ; LSB = xorwf(Q12,Q3)
swapf RandHi, F
andlw 0x01
rlf RandLo, F
xorwf RandLo, F
rlf RandHi, F
return
;**********************************************************************
; BCD To Binary Conversion *
; This routine converts a 5 digit BCD number to a 16 bit binary *
; number. *
; The input 5 digit BCD numbers are asumed to be in locations *
; R0, R1 & R2 with R0 containing the MSD in its right most nibble. *
; The 16 bit binary number is output in registers ACCaHI & ACCaLO *
; ( high byte & low byte repectively ). *
; The method used for conversion is : *
; input number X = abcde ( the 5 digit BCD number ) *
; X = abcde = 10[10[10[10a+b]+c]+d]+e *
;**********************************************************************
Dec_to_Hex
clrf ACCaHI
movf R0,W
andlw 0x0F
movwf ACCaLO
call mpy10a ; result = 10a+b
swapf R1,W
call mpy10b ; result = 10[10a+b]
movf R1,W
call mpy10b ; result = 10[10[10a+b]+c]
swapf R2,W
call mpy10b ; result = 10[10[10[10a+b]+c]+d]
movf R2,W
andlw 0x0F
addwf ACCaLO, F
btfsc STATUS,C
incf ACCaHI, F ; result = 10[10[10[10a+b]+c]+d]+e
return ; BCD to binary conversion done
mpy10b
andlw 0x0F
addwf ACCaLO, F
btfsc STATUS,C
incf ACCaHI, F
mpy10a
bcf STATUS,C ; multiply by 2
rlf ACCaLO,W
movwf L_temp
rlf ACCaHI,W ; (H_temp,L_temp) = 2*N
movwf H_temp
bcf STATUS,C ; multiply by 2
rlf ACCaLO, F
rlf ACCaHI, F
bcf STATUS,C ; multiply by 2
rlf ACCaLO, F
rlf ACCaHI, F
bcf STATUS,C ; multiply by 2
rlf ACCaLO, F
rlf ACCaHI, F ; (H_byte,L_byte) = 8*N
movf L_temp,W
addwf ACCaLO, F
btfsc STATUS,C
incf ACCaHI, F
movf H_temp,W
addwf ACCaHI, F
return ; (H_byte,L_byte) = 10*N
;*********************************************************************************************
;This routine is used to find the parity bit(ODD or EVEN)an 8 bit no:stored in the WREG. *
;The parity bit is stored in the LSB of parity reg.To find EVEN parity make the EVEN_PARITY *
;definition TRUE.To find ODD parity make the EVEN_PARITY definition FALSE. *
;*********************************************************************************************
find_parity
movwf TEMPX
swapf TEMPX,W
xorwf TEMPX,W
movwf parity
rrf parity, F
rrf parity, F
xorwf parity,W
andlw 0x03
addlw 0x01
movwf TEMPX
rrf TEMPX,F
rrf TEMPX,W
movwf parity
#if EVEN_PARITY
xorlw 0x01
movwf parity
#endif
return
;************************************************************************
; Subtraction : ACCb(16 bits) - ACCa(16 bits) -> ACCb(16 bits) *
; (a) Load the 1st operand in location ACCaLO & ACCaHI ( 16 bits ) *
; (b) Load the 2nd operand in location ACCbLO & ACCbHI ( 16 bits ) *
; (c) CALL Sub_16bit *
; (d) The result is in location ACCbLO & ACCbHI ( 16 bits ) *
;************************************************************************
Sub_16bit
call Neg_16bit
call Add_16bit
return
;************************************************************************
; Addition : ACCb(16 bits) + ACCa(16 bits) -> ACCb(16 bits) *
; (a) Load the 1st operand in location ACCaLO & ACCaHI ( 16 bits ) *
; (b) Load the 2nd operand in location ACCbLO & ACCbHI ( 16 bits ) *
; (c) CALL Add_16bit *
; (d) The result is in location ACCbLO & ACCbHI ( 16 bits ) *
;************************************************************************
Add_16bit
movf ACCaLO,W
addwf ACCbLO, F ; add lsb
btfsc STATUS,C ; add in carry
incf ACCbHI, F
movf ACCaHI,W
addwf ACCbHI, F ; add msb
return
;************************************************************************
; 2's Compliment: negate ACCa ( -ACCa -> ACCa ) *
; (a) Load the operand in location ACCaLO & ACCaHI ( 16 bits ) *
; (b) CALL Neg_16bit *
; (c) The result is in location ACCaLO & ACCaHI ( 16 bits ) *
;************************************************************************
Neg_16bit
comf ACCaLO, F ;
incf ACCaLO, F
btfsc STATUS,Z
decf ACCaHI, F
comf ACCaHI, F
return
SHT11 humidity sensor library (sensirion manufacture)
/*********** 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
//.....................
}
Stack Implementation with data hiding
/**@file stack.h
@brief This header file contains the public types, variables and methods associated with the stack implementation in stack.c. None of the internal implementation details are exposed. This allows the implementation to vary while the public interface remains the same.
@author Stephen Friederichs
@date 4/28/13
@note This compiles in Cygwin using GCC 4.5.3
*/
#ifndef __STACK_H__
#define __STACK_H__
/**@include stdint.h
@brief Include for standard integer definitions (ie, uint8_t, int32_t, etc)
*/
#include <stdint.h>
/**@include stdlib.h
@brief Include stdlib for malloc and free definition
*/
#include <stdlib.h>
/**@include stddef.h
@brief Include stddef.h for definition of size_t
*/
#include <stddef.h>
/**@typedef stack
@brief Define the type for a stack handle
There are two fundamental aspects of data hiding in C used here.
The first is that you can define a type as a pointer to a struct WITHOUT
having defined the struct. The struct is defined in the source file alone
and no implementation details are exposed in the header file.
The second aspect of this typedef is that stack_t is defined as a
pointer to a const st_stack struct. Const correctness is tricky in C but
for this usage the stack_t type points to a constant struct - changes to the
struct are NOT ALLOWED when the stack_t type is used.
Is this tough security? No. This only ensures the compiler complains if
someone tries to dereference a stack_t type and mess with the data inside
(of course, they don't know what any of the data inside the struct IS due
to the fact it's hidden in the source file). An unscrupulous person could
cast to a void pointer and do whatever they want with it. Or edit the
header file to remove the const. And of course, if they have the source they
know exactly what's inside the struct and can do whatever they want.
Definitely read the Wikipedia article on const correctness to get this all
straight in your head: http://en.wikipedia.org/wiki/Const-correctness
*/
typedef const struct st_stack * stack_t;
/**@typedef stack_element_t
@brief Define the type of the stack elements - bytes in this case
*/
typedef uint8_t stack_element_t;
/**@fn stack_init
@brief Initializes the stack and returns a pointer to the stack struct
@param[in] size The number of elements that can be stored on the stack
@return A pointer to the stack or NULL if the initialization failed.
*/
stack_t stack_init(size_t size);
/**@fn stack_push
@brief Push an element on to the stack
@param[in] stack A pointer to the stack to which we are pushing data
@param[in] element The data to push to the stack
@return Status of the call
@retval -1 The supplied pointer doesn't point to a stack
@retval -2 The stack is full
@retval 0 The call succeeded
*/
int stack_push(stack_t stack, stack_element_t element);
/**@fn stack_pop
@brief Remove an element from the stack
@param[in] element Pointer to an element variable to hold the received data
@note The element argument is a const pointer to an element. This means that the function will not change the address of the pointer, but the value of the element can change (this is the entire point of the function call).
@return Status of the call
@retval -1 Call failed - not a valid stack
@retval -2 Call failed - stack empty
@retval 0 Call succeeded
*/
int stack_pop(stack_element_t const * element);
/**@fn stack_destroy
@brief This stack no longer pleases me and I wish it gone. Or the program is exiting. Either way, free the memory associated with the stack.
@param[in] stack The stack which should no longer exist.
@return Status of the call
@retval -1 Call failed - not a valid stack
@retval 0 Call succeeded
*/
int stack_destroy(stack_t stack);
#endif
/*---------------------------------------------------------------------------*/
#ifdef STACK_IMPLEMENTATION_1
/**@file stack.c
@brief This file implements a basic stack in C but uses C's scope system and typing to hide the internal implementation of the stack and only allow to publicly-advertised functions and variables. This stack implementation uses an array to hold the data and grows up.
@note Implementation 1
@author Stephen Friederichs
@date 4/20/13
*/
/**@include stack.h
@brief stack.h contains all of the types and includeds that allow this stack implementation uses.
*/
/* This file doesn't actually exist - it's all of the above definitions
To avoid errors, comment it out
*/
//#include <stack.h>
/**@def STACK_CANARY_VALUE
@brief Value that the canary in the stack struct must be set to for the stack to be considered a value stack object
*/
#define STACK_CANARY_VALUE 0x31
/**@struct st_stack
@brief Struct containing the internal variables for the stack implementation
*/
struct st_stack
{
uint8_t canary; /**< A value that will be initialized to a specific value to show signify that the pointer points to a stack and that the stack is a valid stack object. This can't protect against any malicious intent but should at least serve as an indication that someone might have tried to modify the internals of the stack object itself*/
stack_element_t * array;/**< Pointer to the array where the stack data is stored*/
size_t head; /**< Index of the most recently added element in the stack*/
size_t size; /**< The maximum size of the stack*/
};
/**@fn _stack_valid
@brief Returns 1 if the stack object is valid
@param[in] stack Pointer to the stack
@return Validity of the object
@retval 1 Valid object
@retval 0 Invalid object
@note This function can only be called from within this file.
*/
static int _stack_valid( stack_t stack)
{
return (STACK_CANARY_VALUE == stack->canary)?1:0;
}
/**@fn stack_init
See above
*/
stack_t stack_init(size_t size)
{
struct st_stack * new_stack = malloc(sizeof(st_stack));
if(NULL == new_stack)
{
return NULL;
}
new_stack->array = malloc(sizeof(st_element)*size));
if(NULL == new_stack->array)
{
/* Allocation of the array failed, so free the memory associated with the stack
object before returning
*/
free(new_stack);
return NULL;
}
new_stack->head = 0; /* This stack grows up so it starts at element 0*/
new_stack->size = size
new_stack->canary = STACK_CANARY_VALUE; /* Initialize the stack's canary
to the appropriate value*/
/* Return a pointer to the new stack object - appropriately cast
to the const type to avoid warnings
*/
return (stack_t)new_stack;
}
/**@fn stack_push
See above
*/
int stack_push(stack_t stack, stack_element_t element)
{
/* The passed pointer is a pointer to a const stack,
so generate a non-const pointer
*/
st_stack * stack_pointer = (st_stack *)stack;
if(!_stack_valid(stack))
{
return -1; /* Object is not a stack*/
}
if(stack->head == (stack->size-1))
{
return -2; /* Stack is full*/
}
/* All checks passed, add element*/
stack_pointer->array[++head] = element;
return 0;
}
/**@fn stack_pop
See above
*/
int stack_pop(stack_t stack, stack_element const * element)
{
stack_element popped_element;
/* The passed pointer is a pointer to a const stack,
so generate a non-const pointer
*/
st_stack * stack_pointer = (st_stack*)stack;
if(!_stack_valid(stack))
{
return -1; /* Pointer doesn't point to a stack*/
}
/* Check to see if the stack is empty*/
if(0 == stack->head)
{
return -2; /* Stack is empty, cannot pop*/
}
*popped_element = stack->array[stack_pointer->head--];
return 0;
}
/**@fn stack_destroy
See above
*/
int stack_destroy(stack_t stack)
{
/* The passed pointer is a pointer to a const stack,
so generate a non-const pointer
*/
st_stack stack_pointer = (st_stack*)stack;
if(!_stack_valid(stack))
{
return -1; /* Signal failure - not a stack object*/
}
/* Clear the canary - if the pointer to this struct is reused after the
stack is destroyed, the canary will be invalid and the call wil fail
*/
stack_pointer->canary = 0x00;
free(stack->array);
free(stack);
return 0;
}
/* Don't allow the use of the STACK_CANARY_VALUE outside of this vile*/
#undef STACK_CANARY_VALUE
#else //STACK_IMPLEMENTATION_2
/**@file stack.c
@brief This file implements a basic stack in C but uses C's scope system and typing to hide the internal implementation of the stack and only allow to publicly-advertised functions and variables. This stack implementation uses an array to hold the data and grows down.
@note Implementation 2
@author Stephen Friederichs
@date 4/20/13
*/
/**@include stack.h
@brief stack.h contains all of the types and includes that allow this stack implementation uses.
*/
/* This file doesn't actually exist - it would if this weren't one huge file
So comment this out to ensure no compilation errors
*/
//#include <stack.h>
/**@def STACK_CANARY_VALUE
@brief Value that the canary in the stack struct must be set to for the stack to be considered a value stack object
*/
#define STACK_CANARY_VALUE 0x32
/**@struct st_stack
@brief Struct containing the internal variables for the stack implementation
*/
struct st_stack
{
uint8_t canary; /**< A value that will be initialized to a specific value to show signify that the pointer points to a stack and that the stack is a valid stack object. This won't protect against any truly malicious intent but might indicate that someone tried to modify the internals of the object themselves.*/
stack_element_t * array; /**< Pointer to the array where the stack data is stored*/
size_t head; /**< Index of the most recently added element in the stack*/
size_t size; /**< The maximum size of the stack*/
};
/**@fn _stack_valid
@brief Returns 1 if the stack object is valid
@param[in] stack Pointer to the stack
@return Validity of the object
@retval 1 Valid object
@retval 0 Invalid object
@note This function can only be called from within this file.
*/
static int _stack_valid( stack_t stack)
{
/* Ensure we don't try to dereference a NULL pointer
Obviously if the pointer is NULL it's not a valid stack
*/
if(NULL == stack)
{
return 0;
}
return (STACK_CANARY_VALUE == stack->canary)?1:0;
}
/**@fn stack_init
See above
*/
stack_t stack_init(size_t size)
{
struct st_stack * new_stack = malloc(sizeof(st_stack));
if(NULL == new_stack)
{
return NULL;
}
new_stack->array = malloc(sizeof(st_element)*size));
if(NULL == new_stack->array)
{
/* Allocation failed, so free the memory associated with the stack
object before returning
*/
free(new_stack);
return NULL;
}
new_stack->head = size; /* This stack grows down so it starts at the
highest element*/
new_stack->size = size
new_stack->canary = STACK_CANARY_VALUE;
return (stack_t)new_stack;
}
/**@fn stack_push
See above
*/
int stack_push(stack_t stack, stack_element_t element)
{
/* The passed pointer is a pointer to a const stack,
so generate a non-const pointer
*/
st_stack * stack_pointer = (st_stack *)stack;
if(!_stack_valid(stack))
{
return -1; /* Object is not a stack*/
}
if(0 == stack->head)
{
return -2; /* Stack is full*/
}
/* All checks passed, add element*/
stack_pointer->array[--head] = element;
/* Return success*/
return 0;
}
/**@fn stack_pop
See above
*/
int stack_pop(stack_t stack, stack_element const * element)
{
stack_element popped_element;
/* The passed pointer is a pointer to a const stack,
so generate a non-const pointer so we can modify
the head variable.
*/
st_stack * stack_pointer = (st_stack *)stack;
if(!_stack_valid(stack))
{
return -1; /* Pointer doesn't point to a stack*/
}
/* Check to see if the stack is empty*/
if(stack->size == stack->head)
{
return -2; /* Stack is empty, cannot pop*/
}
*popped_element = stack->array[stack_pointer->head--];
/* Signal success*/
return 0;
}
/**@fn stack_destroy
See above
*/
int stack_destroy(stack_t stack)
{
/* The passed pointer is a pointer to a const stack,
so generate a non-const pointer so the canary can
be cleared later
*/
st_stack * stack_pointer = (st_stack *)stack;
if(!_stack_valid(stack))
{
return -1; /* Signal failure - not a stack object*/
}
/* Clear the canary - if the pointer to this struct is reused after the
stack is destroyed, the canary will be invalid and the call wil fail
*/
stack_pointer->canary = 0x00;
free(stack->array);
free(stack);
/* Return success*/
return 0;
}
/* Don't allow the use of the STACK_CANARY_VALUE outside of this vile*/
#undef STACK_CANARY_VALUE
#endif
Circular FIFO Buffer
/***** circularBuffer.h *****/
#ifndef CIRCULAR_BUFFER_H_
#define CIRCULAR_BUFFER_H_
#define BUFFER_SIZE 128
#define TYPE char
// Check if the buffer it is full
bool isFull();
// Check if the buffer it is empty
bool isEmpty();
// Get the first element from the FIFO queue
TYPE getElement();
// Add an element to the FIFO queue
bool addElement(TYPE data);
// Return the number of Elements that are in the FIFO queue
unsigned char getNumberOfElements();
#endif /*CIRCULAR_BUFFER_H_*/
/***** circularBuffer.cpp *****/
#include "circularBuffer.h"
TYPE Buffer[BUFFER_SIZE + 1]; // It needs 1 extra byte to difference full and empty
unsigned char next = 0;
unsigned char first = 0;
bool isFull(){
if (getNumberOfElements() == BUFFER_SIZE){
return true;
}else{
return false;
}
}
bool isEmpty(){
if ( next == first ){
return true;
}else{
return false;
}
}
TYPE getElement(){
TYPE theElement = 0;
if (! isEmpty()){
theElement = Buffer[first];
if ( first != BUFFER_SIZE ){
first++;
}else{
first = 0;
}
}
return theElement;// Return 0 always if it is empty, must be checked before
}
bool addElement(TYPE data){
if (!isFull()){
Buffer[next] = data;
if ( next != BUFFER_SIZE ){
next++;
}else{
next = 0;
}
return true;
}else{
return false;
}
}
unsigned char getNumberOfElements(){
if (next >= first){
return (next - first);
}else{
return (BUFFER_SIZE - next + first);
}
}
DS18B20 Interfacing
float get_temp(void);
void reset_18B20(void);
void send_18B20(char data);
unsigned int read_18B20(void);
#define ONE_WIRE_PIN BIT4
#define ONE_WIRE_IN P1IN
#define ONE_WIRE_OUT P1OUT
#define ONE_WIRE_DIR P1DIR
float get_temp(void)
{
unsigned int temp;
reset_18B20();
send_18B20(0xcc); //send CCH,Skip ROM command
send_18B20(0x44);
delay_us(100);
reset_18B20();
send_18B20(0xcc); //send CCH,Skip ROM command
send_18B20(0xbe);
temp = read_18B20();
return((float)temp/8.0);
}
void reset_18B20(void)
{
ONE_WIRE_DIR |=ONE_WIRE_PIN;
ONE_WIRE_OUT &= ~ONE_WIRE_PIN;
__delay_cycles(500);
ONE_WIRE_OUT |=ONE_WIRE_PIN;
ONE_WIRE_DIR &= ~ONE_WIRE_PIN;
__delay_cycles(500);
}
void send_18B20(char data)
{
char i;
for(i=8;i>0;i--)
{
ONE_WIRE_DIR |=ONE_WIRE_PIN;
ONE_WIRE_OUT &= ~ONE_WIRE_PIN;
__delay_cycles(2);
if(data & 0x01)
{
ONE_WIRE_OUT |= ONE_WIRE_PIN;
}
__delay_cycles(60);
ONE_WIRE_OUT |= ONE_WIRE_PIN;
ONE_WIRE_DIR &= ~ONE_WIRE_PIN;
data >>=1;
}
}
unsigned int read_18B20()
{
char i;
unsigned int data=0;
for(i=16;i>0;i--)
{
ONE_WIRE_DIR |= ONE_WIRE_PIN;
ONE_WIRE_OUT &= ~ONE_WIRE_PIN;
__delay_cycles(2);
ONE_WIRE_OUT |=ONE_WIRE_PIN;
ONE_WIRE_DIR &= ~ONE_WIRE_PIN;
__delay_cycles(8);
if(ONE_WIRE_IN & ONE_WIRE_PIN)
{
data |=0x8000;
}
data>>=1;
__delay_cycles(120);
}
return(data);
}
Primitive exception processing using macros
#define Try \
jmp_buf ExceptionBuffer; \
int ExceptionStatus = setjmp (ExceptionBuffer); \
if (ExceptionStatus == 0)
#define Catch(Value) else if (ExceptionStatus == (int) (Value))
#define Finally else
#define Throw(Value) \
{ \
int Result = (int) (Value); \
if (Result != 0) { \
longjmp (ExceptionBuffer, Result); \
} \
}
An example using a function to read the OCR register on an SD card:
uint32_t SDCard_OCR (void) {
SDCard_ConfigSSP ( );
Try {
// The card is asked to send its OCR. The OCR is
// placed in module variable mOCRValue by the
// function.
Throw (SDCard_SendCommand (CMD58_READ_OCR));
}
// Error processing.
Catch (SD_TIMEOUT) {
GUI_SendMessage (SDCARD_TIMEOUT);
}
Catch (SD_NO_CARD) {
GUI_SendMessage (SDCARD_NOT_FOUND);
}
Finally { // Unknown SD card error
Throw (SD_NO_CARD); // Rethrow the exception
}
// Executed even if an exception thrown:
SDCard_DeconfigSSP ( );
return mOCRValue; // 0xFFFFFFFF if error
}
Integer PI control with integrator anti-windup
/**
* @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
/**
* @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
/**
* @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
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
/*
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.
/*
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
#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
/*********************************************************************
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)
/*********** 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
/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;
}