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
Graphics in source code
// This enum defines the value of each of the 256 possible combinations of
// underlines and Os in 8 bits.
enum
{
________,_______O,______O_,______OO,_____O__,_____O_O,_____OO_,_____OOO,
____O___,____O__O,____O_O_,____O_OO,____OO__,____OO_O,____OOO_,____OOOO,
___O____,___O___O,___O__O_,___O__OO,___O_O__,___O_O_O,___O_OO_,___O_OOO,
___OO___,___OO__O,___OO_O_,___OO_OO,___OOO__,___OOO_O,___OOOO_,___OOOOO,
__O_____,__O____O,__O___O_,__O___OO,__O__O__,__O__O_O,__O__OO_,__O__OOO,
__O_O___,__O_O__O,__O_O_O_,__O_O_OO,__O_OO__,__O_OO_O,__O_OOO_,__O_OOOO,
__OO____,__OO___O,__OO__O_,__OO__OO,__OO_O__,__OO_O_O,__OO_OO_,__OO_OOO,
__OOO___,__OOO__O,__OOO_O_,__OOO_OO,__OOOO__,__OOOO_O,__OOOOO_,__OOOOOO,
_O______,_O_____O,_O____O_,_O____OO,_O___O__,_O___O_O,_O___OO_,_O___OOO,
_O__O___,_O__O__O,_O__O_O_,_O__O_OO,_O__OO__,_O__OO_O,_O__OOO_,_O__OOOO,
_O_O____,_O_O___O,_O_O__O_,_O_O__OO,_O_O_O__,_O_O_O_O,_O_O_OO_,_O_O_OOO,
_O_OO___,_O_OO__O,_O_OO_O_,_O_OO_OO,_O_OOO__,_O_OOO_O,_O_OOOO_,_O_OOOOO,
_OO_____,_OO____O,_OO___O_,_OO___OO,_OO__O__,_OO__O_O,_OO__OO_,_OO__OOO,
_OO_O___,_OO_O__O,_OO_O_O_,_OO_O_OO,_OO_OO__,_OO_OO_O,_OO_OOO_,_OO_OOOO,
_OOO____,_OOO___O,_OOO__O_,_OOO__OO,_OOO_O__,_OOO_O_O,_OOO_OO_,_OOO_OOO,
_OOOO___,_OOOO__O,_OOOO_O_,_OOOO_OO,_OOOOO__,_OOOOO_O,_OOOOOO_,_OOOOOOO,
O_______,O______O,O_____O_,O_____OO,O____O__,O____O_O,O____OO_,O____OOO,
O___O___,O___O__O,O___O_O_,O___O_OO,O___OO__,O___OO_O,O___OOO_,O___OOOO,
O__O____,O__O___O,O__O__O_,O__O__OO,O__O_O__,O__O_O_O,O__O_OO_,O__O_OOO,
O__OO___,O__OO__O,O__OO_O_,O__OO_OO,O__OOO__,O__OOO_O,O__OOOO_,O__OOOOO,
O_O_____,O_O____O,O_O___O_,O_O___OO,O_O__O__,O_O__O_O,O_O__OO_,O_O__OOO,
O_O_O___,O_O_O__O,O_O_O_O_,O_O_O_OO,O_O_OO__,O_O_OO_O,O_O_OOO_,O_O_OOOO,
O_OO____,O_OO___O,O_OO__O_,O_OO__OO,O_OO_O__,O_OO_O_O,O_OO_OO_,O_OO_OOO,
O_OOO___,O_OOO__O,O_OOO_O_,O_OOO_OO,O_OOOO__,O_OOOO_O,O_OOOOO_,O_OOOOOO,
OO______,OO_____O,OO____O_,OO____OO,OO___O__,OO___O_O,OO___OO_,OO___OOO,
OO__O___,OO__O__O,OO__O_O_,OO__O_OO,OO__OO__,OO__OO_O,OO__OOO_,OO__OOOO,
OO_O____,OO_O___O,OO_O__O_,OO_O__OO,OO_O_O__,OO_O_O_O,OO_O_OO_,OO_O_OOO,
OO_OO___,OO_OO__O,OO_OO_O_,OO_OO_OO,OO_OOO__,OO_OOO_O,OO_OOOO_,OO_OOOOO,
OOO_____,OOO____O,OOO___O_,OOO___OO,OOO__O__,OOO__O_O,OOO__OO_,OOO__OOO,
OOO_O___,OOO_O__O,OOO_O_O_,OOO_O_OO,OOO_OO__,OOO_OO_O,OOO_OOO_,OOO_OOOO,
OOOO____,OOOO___O,OOOO__O_,OOOO__OO,OOOO_O__,OOOO_O_O,OOOO_OO_,OOOO_OOO,
OOOOO___,OOOOO__O,OOOOO_O_,OOOOO_OO,OOOOOO__,OOOOOO_O,OOOOOOO_,OOOOOOOO,
};
// These macros use the above enum to build the image in a source file.
#define G8(n0) (n0) //!< Build a byte image line
#define G16(n1, n0) (((n1) << 8) | (n0))
//!< Build a halfword image line
#define G32(n3, n2, n1, n0) \
((G16 ((n3), (n2)) << 16) | G16 ((n1), (n0)))
//!< Build a word image line
#define G64(n7, n6, n5, n4, n3, n2, n1, n0) \
((G32 ((n7), (n6), (n5), (n4)) << 32) | G32 ((n3), (n2), (n1), (n0)))
//!< Build a long image line
=====
Example using the letter A in Arial Black 21 font:
Old code:
{
19, // A
0x00040000, 0x00078000, 0x0007F000, 0x0007FC00,
0x0007FF80, 0x0003FFF0, 0x0000FFFC, 0x0000FFFE,
0x0000F1FE, 0x0000F03E, 0x0000F1FE, 0x0000FFFE,
0x0000FFFC, 0x0003FFF0, 0x0007FF80, 0x0007FC00,
0x0007F000, 0x00078000, 0x00040000
};
New code:
{
19, // A
G32 (________,_____O__,________,________),
G32 (________,_____OOO,O_______,________),
G32 (________,_____OOO,OOOO____,________),
G32 (________,_____OOO,OOOOOO__,________),
G32 (________,_____OOO,OOOOOOOO,O_______),
G32 (________,______OO,OOOOOOOO,OOOO____),
G32 (________,________,OOOOOOOO,OOOOOO__),
G32 (________,________,OOOOOOOO,OOOOOOO_),
G32 (________,________,OOOO___O,OOOOOOO_),
G32 (________,________,OOOO____,__OOOOO_),
G32 (________,________,OOOO___O,OOOOOOO_),
G32 (________,________,OOOOOOOO,OOOOOOO_),
G32 (________,________,OOOOOOOO,OOOOOO__),
G32 (________,______OO,OOOOOOOO,OOOO____),
G32 (________,_____OOO,OOOOOOOO,O_______),
G32 (________,_____OOO,OOOOOO__,________),
G32 (________,_____OOO,OOOO____,________),
G32 (________,_____OOO,O_______,________),
G32 (________,_____O__,________,________),
};
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;
}
Integer to ASCII
/***** integerToAscii.h *****/
#define BASE_OCTAL 8
#define BASE_DECIMAL 10
#define BASE_HEXADECIMAL 16
#define BUFFER_SIZE 32
char* integerToASCII(long int value, int base);
/***** integerToAscii.c *****/
char* integerToASCII(long int value, int base){
int aux;
static char buf[BUFFER_SIZE] = {0};
int isNeg=0;
if (value == 0) {
buf[0]='0';
return &buf[0];
}
if (value<0) {
isNeg = 1;
value *= -1;
}
for(aux=BUFFER_SIZE; value && aux ; --aux, value /= base){
buf[aux] = "0123456789abcdef"[value % base];
}
if (isNeg) {
buf[aux] = '-';
return &buf[aux];
}
return &buf[aux+1];
}
Little Endian Converter Functions
unsigned short u16ToLittleEndian( unsigned short u16input )
{/* Use this function to convert a 16-bit number into little endian. */
return( (u16input >> 8) ^ (u16input << 8) );
}// end u16ToLittleEndian()
unsigned long u32ToLittleEndian( unsigned long u32input )
{/* Use this function to convert a 32-bit number into little endian. */
return( (u32input >> 24)
^ ( (u32input >> 8) & 0x000FF00 )
^ ( (u32input << 8) & 0x00FF0000 )
^ ( (u32input << 24) & 0xFF000000 )
);
}// end u32ToLittleEndian()
Universal InfraRed remote pass-thru
#define MAX_IR_INDEX 64
#define ESCAPE_COUNT 0x2200ul /* Could be reduced?*/
#pragma udata ircounts
unsigned int lcounts[MAX_IR_INDEX];
unsigned int hcounts[MAX_IR_INDEX];
#pragma interrupt high_isr /*=section(".tmpdata")*/
void high_isr(void) {
unsigned int l;
unsigned int c;
unsigned char th, tl;
l = 0;
TMR1H = 0; // Always write H before L
TMR1L = 0;
// Check that this is the INT0 interrupt
// IRRX is int0
if(INTCONbits.INT0IF)
{
// Disable the interrupt source
INTCONbits.INT0IE = 0;
// the code in the while needs to be balanced so that the ==0 and ==1 bits are the size number of cycles.
while(lindex < MAX_IR_INDEX)
{
while(PORTBbits.RB0 == 0)
{
l++;
if(l == ESCAPE_COUNT)
{
lcounts[lindex] = 0xffff;
goto done;
}
}
tl = TMR1L;
th = TMR1H; // << 8 ;// Always read L before H
lcounts[lindex++] = th * 256 + tl;
l = 0;
TMR1H = 0; // Always right H before L
TMR1L = 0;
while(PORTBbits.RB0 == 1)
{
l++;
if(l == ESCAPE_COUNT)
{
hcounts[hindex] = 0xffff;
goto done;
}
}
tl = TMR1L;
th = TMR1H; //<< 8 ;// Always read L before H
hcounts[hindex++] = th * 256 + tl;
l = 0;
TMR1H = 0; // Always write H before L
TMR1L = 0;
}
}
done:
codeReady = 1;
// reset interrupt status bit
//INTCONbits.INT0IE = 1;
//INTCONbits.INT0IF = 0;
return;
}
void zeroIR() {
unsigned char c;
// Initialize the IR Count holders
lindex = 0;
hindex = 0;
for(c = 0; c < MAX_IR_INDEX; c++)
{
lcounts[c] = 0xdead;
}
codeReady = 0;
// reset interrupt status bit
INTCONbits.INT0IE = 1;
INTCONbits.INT0IF = 0;
}
void transmitIR(void) {
unsigned char c;
// First check that the code is valid by examining the first LCOUNT
// if it is less than our defined threshold we will not transmit it.
// The first lcount holds the low-going preamble, it must be a minimum length or it does not
// represent a valid IR Transmission preamble.
if(lcounts[0] < PREAMBLE_MINIMUM)
{
return;
}
sprintf(serTX, (CAST) "$%c%cIC%d,", id1, id2, lindex);
rs485_puts(serTX);
for(c = 0; c < lindex; c++)
{
sprintf(serTX, (CAST) "%04x,%04x, ", lcounts[c], hcounts[c]);
rs485_puts(serTX);
}
sprintf(serTX, (CAST) "\n");
rs485_puts(serTX);
}
GPIO library
//---------------------------------------------------------
// start of header file (gpio.h)
//---------------------------------------------------------
#if !defined(_GPIO_H_)
#define _GPIO_H_
typedef unsigned long dword;
typedef struct tGPIOpinTag
{
dword dwReg;
dword dwClr;
dword dwSet;
int iBit;
dword dwFunction;
} tGPIOpin;
#define REG32 volatile dword *
//
// bit patterns for alternate pin functions.
//
#define PINFUNC_GPIO ( 0x00000000 )
#define PINFUNC_ALT1 ( 0x55555555 )
#define PINFUNC_ALT2 ( 0xAAAAAAAA )
#define PINFUNC_ALT3 ( 0xFFFFFFFF )
//
// Active high and low works by swapping the SET and CLR register offsets round
//
#define GPIO_ACTIVE_L FIO_SET_OFS, FIO_CLR_OFS
#define GPIO_ACTIVE_H FIO_CLR_OFS, FIO_SET_OFS
//
// Start addresses of GPIO blocks of registers
//
#define LPC_GPIO_BASE ( 0x2009C000UL )
#define LPC_GPIO0_BASE ( LPC_GPIO_BASE + 0x00000 )
#define LPC_GPIO1_BASE ( LPC_GPIO_BASE + 0x00020 )
#define LPC_GPIO2_BASE ( LPC_GPIO_BASE + 0x00040 )
#define LPC_GPIO3_BASE ( LPC_GPIO_BASE + 0x00060 )
#define LPC_GPIO4_BASE ( LPC_GPIO_BASE + 0x00080 )
//
// Offsets to the direction register and PIN register
//
#define FIO_SET_OFS ( 0x00000018 )
#define FIO_CLR_OFS ( 0x0000001C )
#define FIO_DIR_OFS ( 0x00000000 )
#define FIO_PIN_OFS ( 0x00000014 )
#define FIO_MASK_OFS ( 0x00000010 )
// Parameters for vGPIODDsetDirection
#define PIN_IN ( FALSE )
#define PIN_OUT ( TRUE )
//
// Macro for pin definition structure
//
#ifdef _INSIDE_GPIODD_
//
// this version is for use inside the gpio module
//
#define PINFUNC_DEF( name, port, bit, act, func ) \
const tGPIOpin t##name = { \
LPC_GPIO##port##_BASE, \
GPIO_ACTIVE_##act, \
bit, \
PINFUNC_##func \
}; \
const tGPIOpin * const name = &t##name;
#else
//
// and this is how external modules see the pin definition
//
#define PINFUNC_DEF( name, port, bit, act, func ) \
extern const tGPIOpin * const name;
#endif
//
// include the hardware pin allocations from another file
// (see example below)
//
#include "gpio_pindefs.h"
extern void vGPIODDsetPinFunction( const tGPIOpin * const psPin );
extern void vGPIODDsetPinDirection( const tGPIOpin * const psPin,
const bool boOutput );
extern void vGPIODDconfigurePin( const tGPIOpin * const psPin,
const bool boOutput );
extern void vGPIODDsetActive( const tGPIOpin * const psPin );
extern void vGPIODDsetInactive( const tGPIOpin * const psPin );
extern bool boGPIODDgetPin( const tGPIOpin * const psPin );
#endif // _GPIO_H_
//---------------------------------------------------------
// end of header file (gpio.h)
//---------------------------------------------------------
//---------------------------------------------------------
// start of example gpio_pindefs.h
//---------------------------------------------------------
#if !defined(_GPIO_PINDEFS_H_)
#define _GPIO_PINDEFS_H_
// LEDs
PINFUNC_DEF( GPIO_LED_GREEN, 1, 25, L, GPIO )
// USB interface
PINFUNC_DEF( GPIO_USB_VBUS, 1, 30, H, ALT1 )
PINFUNC_DEF( GPIO_USB_CONNECT, 2, 9, L, ALT1 )
// Serial Ports
PINFUNC_DEF( UART0_RX, 0, 3, H, ALT1 )
PINFUNC_DEF( UART0_TX, 0, 2, H, ALT1 )
PINFUNC_DEF( UART1_RX, 0, 16, H, ALT1 )
PINFUNC_DEF( UART1_TX, 0, 15, H, ALT1 )
// SPI port
PINFUNC_DEF( SPI_MOSI, 0, 9, H, ALT2 )
PINFUNC_DEF( SPI_MISO, 0, 8, H, ALT2 )
PINFUNC_DEF( SPI_SCK, 0, 7, H, ALT2 )
PINFUNC_DEF( SPI_SSEL, 0, 6, L, ALT2 )
#endif // _GPIO_PINDEFS_H_
//---------------------------------------------------------
// end of example gpio_pindefs.h
//---------------------------------------------------------
//---------------------------------------------------------
// start of gpio.c
//---------------------------------------------------------
#define _INSIDE_GPIODD_ ( 1 )
#include "gpio.h"
/* --------------------------------------------------------
vGPIODDsetPinFunction
........................................................
Description : Set the pin connect block from a pin
definition
Params : psPin - pin definition
Returns : Nothing
----------------------------------------------------- */
void vGPIODDsetPinFunction( const tGPIOpin * const psPin )
{
if ( psPin )
{
// Each PINSELXX register contains the settings
// for 16 port pins. Each PINSEL register is 4 bytes
// above the previous one. Base addresses for ports
// are 32 bytes apart.
dword dwPinSel = LPC_PINCON_BASE +
((psPin->dwReg - LPC_GPIO0_BASE) / 4) +
((psPin->iBit / 16) * 4);
dword dwMask = ( 0x00000003 << ( 2 * ( psPin->iBit % 16 ) ) );
REG32 pdwPinSel = (REG32)dwPinSel;
*pdwPinSel = ( *pdwPinSel & ~dwMask ) |
( psPin->dwFunction & dwMask );
}
}
/* --------------------------------------------------------
vGPIODDsetPinDirection
........................................................
Description : Sets the pin direction from a pin
definition
Params : psPin - pin definition
boOutput - set to TRUE to turn the pin into an
output
Returns : Nothing
----------------------------------------------------- */
void vGPIODDsetPinDirection( const tGPIOpin * const psPin,
const bool boOutput )
{
if ( psPin )
{
if( boOutput )
{
(*((REG32) (psPin->dwReg + FIO_DIR_OFS))) |= ( 1 << psPin->iBit );
}
else
{
(*((REG32) (psPin->dwReg + FIO_DIR_OFS))) &= ~( 1 << psPin->iBit );
}
}
}
/* --------------------------------------------------------
vGPIODDconfigurePin
........................................................
Description : Combination function to configure and set
direction of GPIO pin
Params : psPin - pin definition
boOutput - set to TRUE to turn the pin into an
output
Returns : Nothing
----------------------------------------------------- */
void vGPIODDconfigurePin( const tGPIOpin * const psPin,
const bool boOutput )
{
if ( psPin )
{
vGPIODDsetInactive( psPin );
vGPIODDsetPinFunction( psPin );
vGPIODDsetPinDirection( psPin, boOutput );
}
}
/* --------------------------------------------------------
vGPIODDsetActive
........................................................
Description : Sets a pin to its active state
Params : psPin - pin definition
Returns : Nothing
----------------------------------------------------- */
void vGPIODDsetActive( const tGPIOpin * const psPin )
{
if ( psPin )
{
// use the Set register to set a single bit
(*((REG32) (psPin->dwReg + psPin->dwSet))) = ( 1 << psPin->iBit );
}
}
/* --------------------------------------------------------
vGPIODDsetInactive
........................................................
Description : Sets a pin to its inactive state
Params : psPin - pin definition
Returns : Nothing
----------------------------------------------------- */
void vGPIODDsetInactive( const tGPIOpin * const psPin )
{
if ( psPin )
{
// use the Clr register to clear a single bit
(*((REG32) (psPin->dwReg + psPin->dwClr))) = ( 1 << psPin->iBit );
}
}
/* --------------------------------------------------------
boGPIODDgetPin
........................................................
Description : Gets the current state of a pin
Params : psPin - pin definition
Returns : TRUE if the pin is in its active state,
FALSE otherwise.
----------------------------------------------------- */
bool boGPIODDgetPin( const tGPIOpin * const psPin )
{
if ( psPin )
{
dword dwPins = *((REG32) (psPin->dwReg + FIO_PIN_OFS));
if ( psPin->dwSet > psPin->dwClr )
{
dwPins = ~dwPins;
}
return ((dwPins & ( 1 << psPin->iBit )) != 0 );
}
else
{
return FALSE;
}
}
//---------------------------------------------------------
// end of gpio.c
//---------------------------------------------------------
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:;
}
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 */
I2C driver using bit bang
typedef struct
{
unsigned int PIN0:1;
unsigned int PIN1:1;
unsigned int PIN2:1;
unsigned int PIN3:1;
unsigned int PIN4:1;
unsigned int PIN5:1;
unsigned int PIN6:1;
unsigned int PIN7:1;
} PORT;
/* TODO: Example address shown, but the proper address */
#define PORT0 *(volatile PORT *)0x1234
/* Define the port used for I2C data and clk as shown above to access them pin wise */
#define I2C_DATA PORT0.PIN0
#define I2C_CLK PORT0.PIN1
#define HIGH 1
#define LOW 0
/* I2C Start - bit bang */
void I2C_START(void)
{
/* I2C Start condition, data line goes low when clock is high */
I2C_DATA = HIGH;
I2C_CLK = HIGH;
I2C_DATA = LOW;
I2C_CLK = LOW;
}
/* I2C Stop - bit bang */
void I2C_STOP (void)
{
/* I2C Stop condition, clock goes high when data is low */
I2C_CLK = LOW;
I2C_DATA = LOW;
I2C_CLK = HIGH;
I2C_DATA = HIGH;
}
/* I2C Write - bit bang */
void I2C_WRITE(unsigned char data)
{
unsigned char outBits;
unsigned char inBit;
/* 8 bits */
for(outBits = 0; outBits < 8; outBits++)
{
if(data & 0x80)
I2C_DATA = 1;
else
I2C_DATA = 0;
data <<= 1;
/* Generate clock for 8 data bits */
SCLK = HIGH;
SCLK = LOW;
}
/* Generate clock for ACK */
I2C_CLK = HIGH;
/* Wait for clock to go high, clock stretching */
while(I2C_CLK);
/* Clock high, valid ACK */
inBit = I2C_DATA;
I2C_CLK = LOW;
}
unsigned char I2C_READ (void)
{
unsigned char inData, inBits;
inData = 0x00;
/* 8 bits */
for(inBits = 0; inBits < 8; inBits++)
{
inData <<= 1;
I2C_CLK = HIGH;
inData |= I2C_DATA;
I2C_CLK = LOW;
}
return inData;
}
/* Examble for writing to I2C Slave */
void writeI2CSlave (unsigned char data)
{
/* Start */
I2C_START();
/* Slave address */
I2C_WRITE(0xAA)
/* Slave control byte */
I2C_WRITE(0xBB);
/* Slave data */
I2C_WRITE(data);
/* Stop */
I2C_STOP();
}
/* Examble for reading from I2C Slave */
unsigned char readI2CSlave(unsigned char data)
{
unsigned char inData;
/* Start */
I2C_START();
/* Slave address */
I2C_WRITE(0xAA);
/* Slave control byte */
I2C_WRITE(data);
/* Stop */
I2C_STOP();
/* Start */
I2C_START();
/* Slave address + read */
I2C_WRITE(0xAA | 1);
/* Read */
inData = I2C_READ();
return inData;
}
GPIO library
//---------------------------------------------------------
// start of header file (gpio.h)
//---------------------------------------------------------
#if !defined(_GPIO_H_)
#define _GPIO_H_
typedef unsigned long dword;
typedef struct tGPIOpinTag
{
dword dwReg;
dword dwClr;
dword dwSet;
int iBit;
dword dwFunction;
} tGPIOpin;
#define REG32 volatile dword *
//
// bit patterns for alternate pin functions.
//
#define PINFUNC_GPIO ( 0x00000000 )
#define PINFUNC_ALT1 ( 0x55555555 )
#define PINFUNC_ALT2 ( 0xAAAAAAAA )
#define PINFUNC_ALT3 ( 0xFFFFFFFF )
//
// Active high and low works by swapping the SET and CLR register offsets round
//
#define GPIO_ACTIVE_L FIO_SET_OFS, FIO_CLR_OFS
#define GPIO_ACTIVE_H FIO_CLR_OFS, FIO_SET_OFS
//
// Start addresses of GPIO blocks of registers
//
#define LPC_GPIO_BASE ( 0x2009C000UL )
#define LPC_GPIO0_BASE ( LPC_GPIO_BASE + 0x00000 )
#define LPC_GPIO1_BASE ( LPC_GPIO_BASE + 0x00020 )
#define LPC_GPIO2_BASE ( LPC_GPIO_BASE + 0x00040 )
#define LPC_GPIO3_BASE ( LPC_GPIO_BASE + 0x00060 )
#define LPC_GPIO4_BASE ( LPC_GPIO_BASE + 0x00080 )
//
// Offsets to the direction register and PIN register
//
#define FIO_SET_OFS ( 0x00000018 )
#define FIO_CLR_OFS ( 0x0000001C )
#define FIO_DIR_OFS ( 0x00000000 )
#define FIO_PIN_OFS ( 0x00000014 )
#define FIO_MASK_OFS ( 0x00000010 )
// Parameters for vGPIODDsetDirection
#define PIN_IN ( FALSE )
#define PIN_OUT ( TRUE )
//
// Macro for pin definition structure
//
#ifdef _INSIDE_GPIODD_
//
// this version is for use inside the gpio module
//
#define PINFUNC_DEF( name, port, bit, act, func ) \
const tGPIOpin t##name = { \
LPC_GPIO##port##_BASE, \
GPIO_ACTIVE_##act, \
bit, \
PINFUNC_##func \
}; \
const tGPIOpin * const name = &t##name;
#else
//
// and this is how external modules see the pin definition
//
#define PINFUNC_DEF( name, port, bit, act, func ) \
extern const tGPIOpin * const name;
#endif
//
// include the hardware pin allocations from another file
// (see example below)
//
#include "gpio_pindefs.h"
extern void vGPIODDsetPinFunction( const tGPIOpin * const psPin );
extern void vGPIODDsetPinDirection( const tGPIOpin * const psPin,
const bool boOutput );
extern void vGPIODDconfigurePin( const tGPIOpin * const psPin,
const bool boOutput );
extern void vGPIODDsetActive( const tGPIOpin * const psPin );
extern void vGPIODDsetInactive( const tGPIOpin * const psPin );
extern bool boGPIODDgetPin( const tGPIOpin * const psPin );
#endif // _GPIO_H_
//---------------------------------------------------------
// end of header file (gpio.h)
//---------------------------------------------------------
//---------------------------------------------------------
// start of example gpio_pindefs.h
//---------------------------------------------------------
#if !defined(_GPIO_PINDEFS_H_)
#define _GPIO_PINDEFS_H_
// LEDs
PINFUNC_DEF( GPIO_LED_GREEN, 1, 25, L, GPIO )
// USB interface
PINFUNC_DEF( GPIO_USB_VBUS, 1, 30, H, ALT1 )
PINFUNC_DEF( GPIO_USB_CONNECT, 2, 9, L, ALT1 )
// Serial Ports
PINFUNC_DEF( UART0_RX, 0, 3, H, ALT1 )
PINFUNC_DEF( UART0_TX, 0, 2, H, ALT1 )
PINFUNC_DEF( UART1_RX, 0, 16, H, ALT1 )
PINFUNC_DEF( UART1_TX, 0, 15, H, ALT1 )
// SPI port
PINFUNC_DEF( SPI_MOSI, 0, 9, H, ALT2 )
PINFUNC_DEF( SPI_MISO, 0, 8, H, ALT2 )
PINFUNC_DEF( SPI_SCK, 0, 7, H, ALT2 )
PINFUNC_DEF( SPI_SSEL, 0, 6, L, ALT2 )
#endif // _GPIO_PINDEFS_H_
//---------------------------------------------------------
// end of example gpio_pindefs.h
//---------------------------------------------------------
//---------------------------------------------------------
// start of gpio.c
//---------------------------------------------------------
#define _INSIDE_GPIODD_ ( 1 )
#include "gpio.h"
/* --------------------------------------------------------
vGPIODDsetPinFunction
........................................................
Description : Set the pin connect block from a pin
definition
Params : psPin - pin definition
Returns : Nothing
----------------------------------------------------- */
void vGPIODDsetPinFunction( const tGPIOpin * const psPin )
{
if ( psPin )
{
// Each PINSELXX register contains the settings
// for 16 port pins. Each PINSEL register is 4 bytes
// above the previous one. Base addresses for ports
// are 32 bytes apart.
dword dwPinSel = LPC_PINCON_BASE +
((psPin->dwReg - LPC_GPIO0_BASE) / 4) +
((psPin->iBit / 16) * 4);
dword dwMask = ( 0x00000003 << ( 2 * ( psPin->iBit % 16 ) ) );
REG32 pdwPinSel = (REG32)dwPinSel;
*pdwPinSel = ( *pdwPinSel & ~dwMask ) |
( psPin->dwFunction & dwMask );
}
}
/* --------------------------------------------------------
vGPIODDsetPinDirection
........................................................
Description : Sets the pin direction from a pin
definition
Params : psPin - pin definition
boOutput - set to TRUE to turn the pin into an
output
Returns : Nothing
----------------------------------------------------- */
void vGPIODDsetPinDirection( const tGPIOpin * const psPin,
const bool boOutput )
{
if ( psPin )
{
if( boOutput )
{
(*((REG32) (psPin->dwReg + FIO_DIR_OFS))) |= ( 1 << psPin->iBit );
}
else
{
(*((REG32) (psPin->dwReg + FIO_DIR_OFS))) &= ~( 1 << psPin->iBit );
}
}
}
/* --------------------------------------------------------
vGPIODDconfigurePin
........................................................
Description : Combination function to configure and set
direction of GPIO pin
Params : psPin - pin definition
boOutput - set to TRUE to turn the pin into an
output
Returns : Nothing
----------------------------------------------------- */
void vGPIODDconfigurePin( const tGPIOpin * const psPin,
const bool boOutput )
{
if ( psPin )
{
vGPIODDsetInactive( psPin );
vGPIODDsetPinFunction( psPin );
vGPIODDsetPinDirection( psPin, boOutput );
}
}
/* --------------------------------------------------------
vGPIODDsetActive
........................................................
Description : Sets a pin to its active state
Params : psPin - pin definition
Returns : Nothing
----------------------------------------------------- */
void vGPIODDsetActive( const tGPIOpin * const psPin )
{
if ( psPin )
{
// use the Set register to set a single bit
(*((REG32) (psPin->dwReg + psPin->dwSet))) = ( 1 << psPin->iBit );
}
}
/* --------------------------------------------------------
vGPIODDsetInactive
........................................................
Description : Sets a pin to its inactive state
Params : psPin - pin definition
Returns : Nothing
----------------------------------------------------- */
void vGPIODDsetInactive( const tGPIOpin * const psPin )
{
if ( psPin )
{
// use the Clr register to clear a single bit
(*((REG32) (psPin->dwReg + psPin->dwClr))) = ( 1 << psPin->iBit );
}
}
/* --------------------------------------------------------
boGPIODDgetPin
........................................................
Description : Gets the current state of a pin
Params : psPin - pin definition
Returns : TRUE if the pin is in its active state,
FALSE otherwise.
----------------------------------------------------- */
bool boGPIODDgetPin( const tGPIOpin * const psPin )
{
if ( psPin )
{
dword dwPins = *((REG32) (psPin->dwReg + FIO_PIN_OFS));
if ( psPin->dwSet > psPin->dwClr )
{
dwPins = ~dwPins;
}
return ((dwPins & ( 1 << psPin->iBit )) != 0 );
}
else
{
return FALSE;
}
}
//---------------------------------------------------------
// end of gpio.c
//---------------------------------------------------------
high resolution frequency counter implementation
/* high resolution frequency counter implementation
*/
/* timer2 interrupt handler. timer1 is an extended
32 bits register (16 bits hard + 16 softs)
incremented once per:
1 / (fcpu / prescal) <=> prescal / fcpu
thus, it will overflow at:
2^16 * prescal / fcpu
on tim2 overflow, the interrupt handler is called
and stores the tim1 current value in tim1_cur_counter.
thus, the tim1 value integrated over the whole
tim1 period is:
(tim1_ovf_counter * 2^16) + tim1_cur_counter.
tim2_is_ovf is set to notify the application.
*/
static volatile uint8_t tim2_ovf_counter;
static volatile uint8_t tim2_is_ovf;
static volatile uint16_t tim1_cur_counter;
ISR(TIMER2_OVF_vect)
{
if ((tim2_ovf_counter--) == 0)
{
/* disable tim1 before reading */
TCCR1B = 0;
tim1_cur_counter = TCNT1;
/* disable tim2 */
TCCR2B = 0;
tim2_is_ovf = 1;
}
}
/* timer2 interrupt handler. timer2 is a 8 bits counter
incremented by the input signal rising edges. since
8 bits are not enough to integrate, an auxiliary
register (tim2_ovf_counter) is updated on overflow.
tim2_ovf_counter is an 8 bits register, and will
overflow without any notice past 0xff.
*/
static volatile uint8_t tim1_ovf_counter;
ISR(TIMER1_OVF_vect)
{
++tim1_ovf_counter;
}
static void hfc_start(void)
{
/* resolution: 1.907349 hz per tick */
/* fmax: 500 khz */
/* acquisition time: 0.524288 seconds */
/* disable interrupts */
TIMSK1 = 0;
TIMSK2 = 0;
/* reset stuff */
tim1_ovf_counter = 0;
tim1_cur_counter = 0;
tim2_is_ovf = 0;
/* 0x100 overflows make 16 bits */
tim2_ovf_counter = 0xff;
/* configure tim2
normal operation
prescaler 128
enable interrupt on overflow
*/
TCNT2 = 0;
TIMSK2 = 1 << 0;
TCCR2A = 0;
TCCR2B = 0;
/* configure tim1
t1 pin (pd5) rising edge as external clock
*/
DDRD &= ~(1 << 5);
TCNT1 = 0;
TIMSK1 = 1 << 0;
TCCR1A = 0;
TCCR1B = 0;
/* start tim1, tim2 */
TCCR1B = 7 << 0;
TCCR2B = 5 << 0;
}
static uint8_t hfc_poll(void)
{
return tim2_is_ovf;
}
static uint32_t hfc_wait(void)
{
/* busy wait for tim1 to overflow. returns the resulting
16 bits counter, to be multiplied by the frequency
resolution (refer to hfc_start) to get the actual
frequency.
*/
/* force inline, do not use hfc_poll */
while (tim2_is_ovf == 0) ;
return ((uint32_t)tim1_ovf_counter << 16) | (uint32_t)tim1_cur_counter;
}
static inline uint32_t hfc_start_wait(void)
{
hfc_start();
return hfc_wait();
}
static inline double hfc_to_hz(uint32_t counter)
{
return 1.907349 * (double)counter;
}
Playing sound in DAC using simple 8051 MCU
/*System reads wav files by SPI from external memory . Samples read are sent to external DAC by other SPI to be played. It's nedeed ISR reception (not included) of SPI to manage info of this file. At the beginnig, this timing is not important, but after all info of wav file is read, timming is fitted to sampling time of wav to play.
This Timer ISR manages read samples by SPI_Memory and write in SPI_DAC in 8051 MCU. Because this MCU has only one SPI,the info transmited to DAC is managed by simple GPIOs */
void Timer2_ISR (void) interrupt 5
{
char desp=0;
char temp=0;
SFRPAGE_save = SFRPAGE;
//! buffer to store 1 or 0 in bit content audio to convert
if(TF2H == 1)
{
/*When system starts, only reads from memory, to get wav header (sampletime, length, and because
there are more than one wav file in memory, the starting address of wav, In "configurating" the
timer period is not sampleTime*/
if (configurating==TRUE)
{
SPI_Read_Memory(); /*it's nedeed ISR to manage recepcion*/
}
else
{
/*pread counts samples of wav file reading*/
if (pread<(audioLength+1))
{
/*wavSampleRead is the last sample stored by SPI, taken in SPI ISR*/
PCA0CPH0=wavSampleRead;
desp=4;
MOSI_SPI_SW=0;
index++;
if (index==256)
{
index=0;
}
CS_DAC=0; /*Chip Select of DAC. This SPI is controlled by GPIOs*/
while (desp!=0)
{
CLK_SPI_SW=0;
CLK_SPI_SW=1;
desp--;
}
desp=0;
while (desp!=8)
{
CLK_SPI_SW=0;
if ((wavSampleRead&0x80)!=0)
{
MOSI_SPI_SW=1;
}
else
{
MOSI_SPI_SW=0;
}
CLK_SPI_SW=1;
desp++;
wavSampleRead=wavSampleRead<<1;
}
CLK_SPI_SW=0;
MOSI_SPI_SW=0;
CLK_SPI_SW=1;
CLK_SPI_SW=0;
CLK_SPI_SW=1;
CLK_SPI_SW=0;
CLK_SPI_SW=1;
CLK_SPI_SW=0;
CLK_SPI_SW=1;
CLK_SPI_SW=0;
CS_DAC=1;
MOSI_SPI_SW=0;
/* starts new transmision on SPI to read new sample from memory*/
SFRPAGE = ACTIVE_PAGE;
SPI_transferData = NO_OK;
SPI0DAT = TRANSFER_MEMORY_COMMAND;
SFRPAGE = SFRPAGE_save;
buffer_Index=0;
pread++;
}
else
{
/*in configurating mode is stored a buffer with some samples. This buffer
it's used to allow "clac" noises to reproduce the audioagain (becuase the audio is
playing periodically. The audios are siren sounds, and the last sample must linked whit
the first sample, having a compled wave form)*/
PCA0CPH0=buffer[buffer_Index];
temp=buffer[buffer_Index];
buffer_Index++;
if (buffer_Index==1)
{
looping=1;
}
else if (buffer_Index==BUFFER_SIZE)
{
pread=BUFFER_SIZE+1;
}
desp=4;
MOSI_SPI_SW=0;
CS_DAC=0;
while (desp!=0)
{
CLK_SPI_SW=0;
CLK_SPI_SW=1;
desp--;
}
desp=0;
while (desp!=8)
{
CLK_SPI_SW=0;
if ((temp&0x80)!=0)
{
MOSI_SPI_SW=1;
}
else
{
MOSI_SPI_SW=0;
}
//CLK_SPI_SW=0;
CLK_SPI_SW=1;
desp++;
temp=temp<<1;
}
desp=4;
while (desp!=0)
{
CLK_SPI_SW=0;
MOSI_SPI_SW=0;
//CLK_SPI_SW=0;
CLK_SPI_SW=1;
desp--;
}
CLK_SPI_SW=0;
CS_DAC=1;
MOSI_SPI_SW=0;
CS_DAC=1;
}
if (pread==BUFFER_SIZE+1)
{
/*First sample to begin the cicle*/
SFRPAGE = ACTIVE_PAGE;
SPI_transferData = NO_OK;
SPI0DAT = TRANSFER_MEMORY_COMMAND;
SFRPAGE = SFRPAGE_save;
}
}
}
TF2H = 0;
}
}
Fast lookup plus interpolation computation of non-linear functions
// Fast integer arithmetic lookup+interpolation method for converting
// barometric pressure readings to altitude readings.
// Each Lookup Table (LUT) entry is the altitude in centimeters above
// sea level, corresponding to an implicit pressure value,
// calculated as [PA_INIT - 1024*LUTindex] in Pascals.
// The region of interest is approximately 460metres below sea level,
// to 10000 metres above sea level.
typedef signed long s32;
#define PZLUT_ENTRIES 80
#define PA_INIT 106956L
#define PA_DELTA 1024L
#define Z_LIMIT_LO -99999L
#define Z_LIMIT_HI 99999L
const s32 gPZTbl[PZLUT_ENTRIES] = {
-45853,
-37662,
-29407,
-21087,
-12700,
-4245,
4279,
12874,
21540,
30279,
... // values removed for brevity
959708,
984147,
1009345
};
// Calculates the altitude in centimeters above sea level, given the barometric
// sensor pressure reading in pascals. The nearest lower LUT index is computed.
// The altitude is then linearly interpolated from the corresponding altitude
// values at the lower and next higher LUT index. Computation is optimized by
// ensuring the difference between LUT entries are spaced by a power of 2, in
// this case 2^10 (1024), so no integer division is required.
// Returns the error values Z_LIMIT_LO or Z_LIMIT_HI if
// the pressure data exceeds the LUT index limits.
s32 sns_Pa2Cm(s32 pa) {
s32 inx,pa1,z1,z2,z;
if (pa > PA_INIT) {
z = Z_LIMIT_LO;
}
else {
inx = (PA_INIT - pa)>>10;
if (inx >= PZLUT_ENTRIES-1) {
z = Z_LIMIT_HI;
}
else {
pa1 = PA_INIT - (inx<<10);
z1 = gPZTbl[inx];
z2 = gPZTbl[inx+1];
z = z1 + (((pa1-pa)*(z2-z1))>>10);
}
}
return z;
}
Linear regression of samples in a circular buffer
// Linear regression of samples in a circular sample
// buffer. Uses only integer arithmetic, optimized for
// computation on 16bit microcontroller with hardware
// multiplier. The linear regression computation is
// simplified considerably by subtracting out the rolling
// average of the buffer samples.
// This computation assumes the samples arrive at
// regular intervals, and this sampling rate is known.
// Usage :
// 1. call lr_Init() to initialize gnLRDenominator,
// gnNumSamples and gnSampleIndex
// 2. get first sample value and initialize gZBuffer
// with this value
// 3. for each subsequent incoming sample
// gZBuffer[gnSampleIndex] = lr_GetNewZSample();
// gZAverage = lr_CalculateAverage(gZBuffer,gnNumSamples);
// gSlope = lr_CalculateSlope(gZBuffer, gnNumSamples, gnSampleIndex, gZAverage);
// gnSampleIndex++;
// if (gnSampleIndex >= gnNumSamples) gnSampleIndex = 0;
//
typedef signed long s32;
#define MAX_Z_SAMPLES 80
#define SENSOR_SAMPLES_PER_SEC 26L
#define MAX_SLOPE 2000L
#define CLAMP(x,min,max) {if ((x) <= (min)) (x) = (min); else if ((x) >= (max)) (x) = (max);}
s32 gnLRDenominator;
int gnSampleIndex, gnNumSamples;
s32 gZBuffer[MAX_Z_SAMPLES];
s32 gZAverage;
s32 gSlope;
void lr_Init(int numSamples) {
s32 zSample, sumT, sumT2;
int inx;
sumT = -(numSamples * (numSamples-1L))/2L;
sumT2 = (numSamples * (numSamples-1L)*(2L*numSamples-1L))/6L;
gnLRDenominator = (numSamples*sumT2) - (sumT*sumT);
gnSampleIndex = 0;
gnNumSamples = numSamples;
zSample = lr_GetNewZSample(); // get a sample from the sensor
inx = gnNumSamples;
while (inx--) gZBuffer[inx] = zSample; // fill the ZBuffer with first sample value
}
s32 lr_CalculateAverage(s32* pZBuffer, int numSamples ) {
int inx;
s32 accumulator, average;
inx = numSamples;
accumulator = 0;
while (inx--) {
accumulator += pZBuffer[inx];
}
accumulator = (accumulator >= 0 ? accumulator +numSamples/2 : accumulator - numSamples/2);
average = accumulator/numSamples; // rounded up average
return average;
}
/// Linear regression of samples in buffer to calculate slope.
s32 lr_CalculateSlope(s32* pZBuffer, int numSamples, int currentSampleIndex, int zAverage) {
int inx,tRelative;
s32 z, sumZT,slope;
sumZT = 0;
inx = numSamples;
while (inx--) {
z = pZBuffer[inx] - zAverage; // subtract out the average value to simplify the arithmetic
tRelative = inx - currentSampleIndex; // time origin is the current sample in window
if (tRelative > 0) {
tRelative -= numSamples;
}
sumZT += ((s32)tRelative*z);
}
slope = (sumZT*(s32)(SENSOR_SAMPLES_PER_SEC*numSamples))/gnLRDenominator;
CLAMP(slope,-MAX_SLOPE,MAX_SLOPE);
return slope;
}
High speed serial and port control for logic analysis
#ifndef TESTPOINTS_H
#define TESTPOINTS_H
#include "gpio.h"
class TpHw
{
public:
//===================================================================================
// TOG, CLR, SET macros provide a means to quickly clear, set or toggle a pin.
// Each macro compiles into a single machine instruction when optimized.
// usage is:
// TOG(AVR32_PIN10);
//===================================================================================
#define TOG(pin) { \
volatile avr32_gpio_port_t *gpio_pin = &AVR32_GPIO.port[pin >> 5]; \
gpio_pin->ovrt = 1 << (pin & 0x1F); }
#define CLR(pin) { \
volatile avr32_gpio_port_t *gpio_pin = &AVR32_GPIO.port[pin >> 5]; \
gpio_pin->ovrc = 1 << (pin & 0x1F); }
#define SET(pin) { \
volatile avr32_gpio_port_t *gpio_pin = &AVR32_GPIO.port[pin >> 5]; \
gpio_pin->ovrs = 1 << (pin & 0x1F); }
//===================================================================================
// TAG provides a means to insert static real time serial data to be displayed on a
// logic analyzer. The TAG macro should be optimized for a baud rate that matches
// the instruction cycle time of the compiler. Each letter compiles into 10
// machine instructions when optimized. Use 8 data bits, no parity and one stop bit.
// usage is:
// TAG(AVR32_PIN10, 'H', 'E', 'L', 'L', 'O');
//===================================================================================
// this macro builds the bit
#define BT(pin, letter, bit) { \
volatile avr32_gpio_port_t *gpio_pin = &AVR32_GPIO.port[pin >> 5]; \
if (letter & bit) \
gpio_pin->ovrs = 1 << (pin & 0x1F); \
else \
gpio_pin->ovrc = 1 << (pin & 0x1F); }
// this macro builds the letter
#define LETTER(pin, letter) { \
BT(pin, letter, 0x00); \
BT(pin, letter, 0x01); \
BT(pin, letter, 0x02); \
BT(pin, letter, 0x04); \
BT(pin, letter, 0x08); \
BT(pin, letter, 0x10); \
BT(pin, letter, 0x20); \
BT(pin, letter, 0x40); \
BT(pin, letter, 0x80); \
BT(pin, 0xff, 0xff); }
// these build the tag
#define LETTER1(pin, letter) LETTER(pin, letter)
#define LETTER2(pin, letter, ...) LETTER1(pin, letter) LETTER1(pin, __VA_ARGS__)
#define LETTER3(pin, letter, ...) LETTER1(pin, letter) LETTER2(pin, __VA_ARGS__)
#define LETTER4(pin, letter, ...) LETTER1(pin, letter) LETTER3(pin, __VA_ARGS__)
#define LETTER5(pin, letter, ...) LETTER1(pin, letter) LETTER4(pin, __VA_ARGS__)
#define LETTER6(pin, letter, ...) LETTER1(pin, letter) LETTER5(pin, __VA_ARGS__)
#define LETTER7(pin, letter, ...) LETTER1(pin, letter) LETTER6(pin, __VA_ARGS__)
#define LETTER8(pin, letter, ...) LETTER1(pin, letter) LETTER7(pin, __VA_ARGS__)
// these calculate the number of arguments passed
#define ARGS_N(x1, x2, x3, x4, x5, x6, x7, x8, N, ...) N
#define RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
#define NARG_N(...) ARGS_N(__VA_ARGS__)
#define NARG(...) NARG_N(__VA_ARGS__, RSEQ_N())
// these build the macro to start with (T1 - T8) base on number of arguments
#define PASTE(a, b) a ## b
#define XPASTE(a, b) PASTE(a, b)
#define T_(pin, M_, ...) M_(pin, __VA_ARGS__)
#define TAG(pin, ...) T_(pin, XPASTE(LETTER, NARG(__VA_ARGS__)), __VA_ARGS__)
//=====================================================================================
// textOut provides a means to insert dynamic real time serial data to be displayed
// on a logic analyzer. The code below should be optimized for a baud rate that matches
// the instruction cycle time of the compiler by stuffing no ops where appropriate
// to balance the bit output. Use 8 data bits, no parity and one stop bit. This
// gives a character that should take 55 cycles and doesn't take any time to set up.
// usage is:
// TpHw::textOut(AVR32_PIN_PA22, "HELLO");
//=====================================================================================
static void serialOut(uint32_t pin, uint8_t value)
{
volatile avr32_gpio_port_t *gpio_pin = &AVR32_GPIO.port[pin >> 5];
volatile uint32_t out = 1 << (pin & 0x1F);
// start bit
gpio_pin->ovrc = out;
asm("nop");
// bit 0
if (value & (1 << 0))
{
gpio_pin->ovrs = out;
}
else
{
gpio_pin->ovrc = out;
asm("nop");
}
// bit 1
if (value & (1 << 1))
{
gpio_pin->ovrs = out;
}
else
{
gpio_pin->ovrc = out;
asm("nop");
}
// bit 2
if (value & (1 << 2))
{
gpio_pin->ovrs = out;
}
else
{
gpio_pin->ovrc = out;
asm("nop");
}
// bit 3
if (value & (1 << 3))
{
gpio_pin->ovrs = out;
}
else
{
gpio_pin->ovrc = out;
asm("nop");
}
// bit 4
if (value & (1 << 4))
{
gpio_pin->ovrs = out;
}
else
{
gpio_pin->ovrc = out;
asm("nop");
}
// bit 5
if (value & (1 << 5))
{
gpio_pin->ovrs = out;
}
else
{
gpio_pin->ovrc = out;
asm("nop");
}
// bit 6
if (value & (1 << 6))
{
gpio_pin->ovrs = out;
}
else
{
gpio_pin->ovrc = out;
asm("nop");
}
// bit 7
if (value & (1 << 7))
{
gpio_pin->ovrs = out;
}
else
{
gpio_pin->ovrc = out;
asm("nop");
}
// stop bit
asm("nop");
asm("nop");
asm("nop");
gpio_pin->ovrs = out;
}
static void textOut(uint32_t pin, char *text)
{
while (*text != 0)
{
serialOut(pin, *text++);
}
}
};
#endif
ARM Cortex-M Bit Banding
#include <stdint.h>
//! @brief Convert word address + bit position to bitband address.
//!
//! @param address Word address containing of bit
//! @param bit Bit offset (0 = LSB, 31 = MSB)
//! @return Address of bit in bitband region.
volatile uint32_t* getBitBandAddress( volatile void* address, int bit )
{
uint32_t addr = (uint32_t)address ;
uint32_t word_band_base = addr & 0xf0000000 ;
uint32_t bit_band_base = word_band_base | 0x02000000 ;
uint32_t offset = addr - word_band_base ;
return (volatile uint32_t*)(bit_band_base + (offset * 32) + (bit * 4)) ;
}
--- EXAMPLES ---
// Example usage 1: 160 bit array
uint32_t physical_memory[5] = {0} ;
uint32_t* bit_array = getBitBandAddress( physical_memory, 0 ) ;
int bit_array_length = sizeof(physical_memory) * CHAR_BIT ;
for( i = 0; i < bit_array_len; i++ )
{
bit_array[i] = rand() % 2;
}
// Example usage 2: STM32 USART1 Tx Int Enable/Disable
uint32_t* tx_intr_enable_bit_addr = getBitBandAddress( (&(USART1->CR1)), 7 ) ;
*tx_intr_enable_bit_addr = 0 ; // Disable Tx
*tx_intr_enable_bit_addr = 1 ; // Enable Tx
// Example usage 3: C++ reference version of example 2
uint32_t& tx_intr_enable_bit = *getBitBandAddress( (&(USART1->CR1)), 7 ) ;
tx_intr_enable_bit = 0 ; // Disable Tx
tx_intr_enable_bit = 1 ; // Enable Tx
Debug print trace macro
#if defined NDEBUG
#define TRACE( format, ... )
#else
#define TRACE( format, ... ) printf( "%s::%s(%d) " format, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__ )
#endif
// Example usage
void example()
{
unsigned var = 0xdeadbeef ;
TRACE( "var=0x%x", var ) ;
}
// Resultant output example:
// example.c::example(5) var=0xdeadbeef
//
Macros to get and set a bit field within a value
// Get a bit field from a value
#define GetField(Var, Mask, Shift) \
(((Var) >> (Shift)) & (Mask))
// Set a bit field in a value
#define SetField(Var, Mask, Shift, Val) \
(Var) = (((Var) & ~((Mask) << (Shift))) | (((Val) & (Mask)) << (Shift)))
Universal InfraRed remote pass-thru
#define MAX_IR_INDEX 64
#define ESCAPE_COUNT 0x2200ul /* Could be reduced?*/
#pragma udata ircounts
unsigned int lcounts[MAX_IR_INDEX];
unsigned int hcounts[MAX_IR_INDEX];
#pragma interrupt high_isr /*=section(".tmpdata")*/
void high_isr(void) {
unsigned int l;
unsigned int c;
unsigned char th, tl;
l = 0;
TMR1H = 0; // Always write H before L
TMR1L = 0;
// Check that this is the INT0 interrupt
// IRRX is int0
if(INTCONbits.INT0IF)
{
// Disable the interrupt source
INTCONbits.INT0IE = 0;
// the code in the while needs to be balanced so that the ==0 and ==1 bits are the size number of cycles.
while(lindex < MAX_IR_INDEX)
{
while(PORTBbits.RB0 == 0)
{
l++;
if(l == ESCAPE_COUNT)
{
lcounts[lindex] = 0xffff;
goto done;
}
}
tl = TMR1L;
th = TMR1H; // << 8 ;// Always read L before H
lcounts[lindex++] = th * 256 + tl;
l = 0;
TMR1H = 0; // Always right H before L
TMR1L = 0;
while(PORTBbits.RB0 == 1)
{
l++;
if(l == ESCAPE_COUNT)
{
hcounts[hindex] = 0xffff;
goto done;
}
}
tl = TMR1L;
th = TMR1H; //<< 8 ;// Always read L before H
hcounts[hindex++] = th * 256 + tl;
l = 0;
TMR1H = 0; // Always write H before L
TMR1L = 0;
}
}
done:
codeReady = 1;
// reset interrupt status bit
//INTCONbits.INT0IE = 1;
//INTCONbits.INT0IF = 0;
return;
}
void zeroIR() {
unsigned char c;
// Initialize the IR Count holders
lindex = 0;
hindex = 0;
for(c = 0; c < MAX_IR_INDEX; c++)
{
lcounts[c] = 0xdead;
}
codeReady = 0;
// reset interrupt status bit
INTCONbits.INT0IE = 1;
INTCONbits.INT0IF = 0;
}
void transmitIR(void) {
unsigned char c;
// First check that the code is valid by examining the first LCOUNT
// if it is less than our defined threshold we will not transmit it.
// The first lcount holds the low-going preamble, it must be a minimum length or it does not
// represent a valid IR Transmission preamble.
if(lcounts[0] < PREAMBLE_MINIMUM)
{
return;
}
sprintf(serTX, (CAST) "$%c%cIC%d,", id1, id2, lindex);
rs485_puts(serTX);
for(c = 0; c < lindex; c++)
{
sprintf(serTX, (CAST) "%04x,%04x, ", lcounts[c], hcounts[c]);
rs485_puts(serTX);
}
sprintf(serTX, (CAST) "\n");
rs485_puts(serTX);
}