PID Control
// PID Control program by Bill Keenan, Melbourne
// Throttle PID loop stuff
#define Umin -1022
#define Umax 1022
#define Kp 0.5 //
#define Ki 0.005 //
#define Kd 1.25 //
float U0 = 0;
float integ; // integration part of PID-loop must be saved
float ep; // previous error used for differential error (e - ep)
/*****************************************************************************/
float prop, junk, der; //
// junk, U0, Umax, Umin, Kp, Ki, err.
int throttle_pidloop(int realpos) // PID-loop calc
// integ - integral part of controller
// ep - preceding control error
// realpos - throttle position feedback
// Besides this function uses global variables such as:
// Kp,Ki,Kd,U0 - constants of controller;
// accel_use - setpoint
// Umin,Umax - range of the output control signal
{
int output;
float error; // actual control error
error = (float)(accel_use - realpos); // calculation of actual error
der = ((error - ep) * Kd);
prop = error * Kp; // calculation of proportional part
if(prop > 1022)
{
prop = 1022;
}
if(prop < -1022)
{
prop = -1022;
}
junk = error * Ki; // calculation of integral part
integ = integ + junk;
if ((int)integ > Umax)
{
integ = (float)Umax;
}
else if ((int)integ < Umin)
{
integ = (float)Umin;
}
output = (int)(prop + integ + der);
if (output > Umax)
{
output = Umax;
}
else if (output < Umin)
{
output = Umin;
}
ep = error; // new error
return(output); // return the object controlling magnitude
}
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;
}
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
Delay for MSP430
void configureClocks();
void delay_ms(unsigned int ms);
void delay_us(unsigned int us);
void configureClocks()
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
}
void delay_us(unsigned int us)
{
while (us)
{
__delay_cycles(1); // 1 for 1 Mhz set 16 for 16 MHz
us--;
}
}
void delay_ms(unsigned int ms)
{
while (ms)
{
__delay_cycles(1000); 1000 for 1MHz and 16000 for 16MHz
ms--;
}
}
Binary numbers
// The following macros build values in binary. Nybbles are separated by
// commas for readability. If a non-binary digit is used, a compiler error
// will result. Here are some examples of the usage of the binary macros:
//
// B4 (0110) = 0x06
// B8 (0101,0101) = 0x55
// B16 (1010,1010, 0101,0101) = 0xAA55
// B32 (1000,0000, 1111,1111, 1010,1010, 0101,0101) = 0x80FFAA55
//
// For maximum readability, the bytes should be separated by spaces and there
// should be no spaces between nybbles, as shown above. Note that an enum
// isn't used because MISRA-C generates errors otherwise.
#define b0000 0u
#define b0001 1u
#define b0010 2u
#define b0011 3u
#define b0100 4u
#define b0101 5u
#define b0110 6u
#define b0111 7u
#define b1000 8u
#define b1001 9u
#define b1010 10u
#define b1011 11u
#define b1100 12u
#define b1101 13u
#define b1110 14u
#define b1111 15u
#pragma diag_suppress = Pm120
#define B4(n0) (b##n0) //!< Build a nybble in binary
#pragma diag_default = Pm120
#define B8(n1, n0) ((B4 (n1) << 4u) | B4 (n0))
//!< Build a byte in binary
#define B16(n3, n2, n1, n0) \
((B4 (n3) << 12) | (B4 (n2) << 8) | (B4 (n1) << 4) | B4 (n0))
//!< Build a halfword in binary
#define B32(n7, n6, n5, n4, n3, n2, n1, n0) \
((B4 (n7) << 28) | (B4 (n6) << 24) | (B4 (n5) << 20) | (B4 (n5) << 16) \
| (B4 (n3) << 12) | (B4 (n2) << 8) | (B4 (n1) << 4) | B4 (n0))
//!< Build a word in binary
#define B64(nF, nE, nD, nC, nB, nA, n9, n8, n7, n6, n5, n4, n3, n2, n1, n0) \
((B4 (nF) << 60) | (B4 (nE) << 56) | (B4 (nD) << 52) | (B4 (nC) << 48) \
| (B4 (nB) << 44) | (B4 (nA) << 40) | (B4 (n9) << 36) | (B4 (n8) << 32) \
| (B4 (n7) << 28) | (B4 (n6) << 24) | (B4 (n5) << 20) | (B4 (n5) << 16) \
| (B4 (n3) << 12) | (B4 (n2) << 8) | (B4 (n1) << 4) | B4 (n0))
//!< Build a long in binary
LED Blinker Using a Timer/Counter
/**@file timer_blinker.c
@brief A more advanced LED blinker using a timer
@author Stephen Friederichs
@date 3/28/13
@note This code assumes that the LED is active high (pin sources current)
*/
/**@def F_CPU
@brief Clock frequency = 8MHZ - this is set by fuses and registers, not by this define
@note Always define this before including delay.h!
*/
#define F_CPU 8000000
/**@include io.h
@brief Include for AVR I/O register definitions
*/
#include <avr/io.h>
/**@include stdint.h
@brief Include for standard integer definitions (ie, uint8_t, int32_t, etc)
*/
#include <stdint.h>
/**@include delay.h
@brief Include for delay functions such as _delay_ms() and _delay_us()
*/
#include <util/delay.h>
/* Basic bit manipulation macros - everyone should use these. Please, steal these! Don't not use them and
don't rewrite them yourself!
*/
#define SET(x,y) x |= (1 << y)
#define CLEAR(x,y) x &= ~(1<< y)
#define READ(x,y) ((0x00 == ((x & (1<<y))>> y))?0x00:0x01)
#define TOGGLE(x,y) (x ^= (1<<y))
int main(void)
{
/*Initialization Code*/
/* ATMega328 Datasheet Table 14-1 Pg 78
Configure PD7 for use as Heartbeat LED
Set as Output Low (initially)
*/
SET(DDRD,7); //Direction: output
CLEAR(PORTD,7); //State: Lo
/* TCCR1A - ATMega328 Datasheet Section 16.11.1 pg 132
No waveform generation is required on this timer, so set all
ports to normal operation
*/
TCCR1A = 0x00;
/* TCCR1C - ATMega328 Datasheet Section 16.11.3 pg 135
This register is only used for output compare.
There's no output compare in this application so this can be all 0's
*/
TCCR1C = 0x00;
/* TCCR1B
Note: I've disabled the CKDIV8 fuse so that the clock source is 8MHz
ATMega328 Datasheet Section 16.11.2 pg 134 - TCCR1A
No input capture used - bits 7:6 are 0
No waveform generation used - bits 4:3 are 0
Clock source select is bits 2:0 but are not yet set - wait until the
main loop is ready to start
As per ATMega328 Datasheet Section 16.9.1 page 123, setting the timer
to Normal mode causes the counter to count up until it reaches 0xFFFF
at which point it will overrun and start back at 0. To configure this
timer/counter to produce a period of 500ms we need to start counting
at a value that causes it to reach 65535 in 500ms.
What is that value?
With a clock prescaler of 256 each count of the timer is roughly
(1/8MHz)*256 = 32uS
500ms / 32us /tick = 15625 ticks /500ms
The counter counts up to 65535, so to determine what value we have to
start at we subtract 15635 from 65536:
65536-15625 = 49910
*/
#define TIMER1_PERIOD 49910
TCNT1 = TIMER1_PERIOD;
/* Flash the LED for a second to show that initialization has successfully
occurred
*/
SET(PORTD,7);
_delay_ms(1000);
CLEAR(PORTD,7);
/* Start the timer/counter
ATMega328 Datasheet Section 16.11.2 Pg 135 - TCCR1B
No Waveform generation: bits 4:3 = 0
No input capture: bits 7:6 = 0
Clock select: ClkIO/256 - bits 2:0 = 100b = 0x04
*/
TCCR1B = 0x04; //This starts the counter/timer
while(1)
{
/* Handle the Heartbeat LED
When the timer/counter reaches 65535 the 500ms period will have
elapsed and TIFR1 bit 1 will be '1'
*/
if(READ(TIFR1,0))
{
/* ATMega328 Datasheet Section 16.11.9 pg137
Setting TIFR1 bit 1 clears the overflow flag
*/
SET(TIFR1,0);
/* Toggle the LED to flash it at 1Hz*/
TOGGLE(PORTD,7);
/* Reload the timer/counter count value to the previous value
so that the period remains the same
*/
TCNT1 = TIMER1_PERIOD;
}
/* Now you can do useful work here - no delay loops!*/
}
}
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)))
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
Additive White Gaussian Noise Generator
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define PI 3.1415926536
double AWGN_generator()
{/* Generates additive white Gaussian Noise samples with zero mean and a standard deviation of 1. */
double temp1;
double temp2;
double result;
int p;
p = 1;
while( p > 0 )
{
temp2 = ( rand() / ( (double)RAND_MAX ) ); /* rand() function generates an
integer between 0 and RAND_MAX,
which is defined in stdlib.h.
*/
if ( temp2 == 0 )
{// temp2 is >= (RAND_MAX / 2)
p = 1;
}// end if
else
{// temp2 is < (RAND_MAX / 2)
p = -1;
}// end else
}// end while()
temp1 = cos( ( 2.0 * (double)PI ) * rand() / ( (double)RAND_MAX ) );
result = sqrt( -2.0 * log( temp2 ) ) * temp1;
return result; // return the generated random sample to the caller
}// end AWGN_generator()
PGA117 driver
#define READ 0x6A00
#define WRITE 0x2A00
#define NOP WRITE 0x0000
#define SDN_DIS 0xE100
#define SDN_EN 0xE1F1
#define GAIN_1 0
#define GAIN_2 1
#define GAIN_4 2
#define GAIN_8 3
#define GAIN_16 4
#define GAIN_32 5
#define GAIN_64 6
#define GAIN_128 7
#define CS BIT0
#define DI BIT1
#define DO BIT2
void write_pga(unsigned int value);
void set_ch_gain(unsigned int ch,unsigned int gain);
void config_spi();
void config_spi()
{
P1DIR |= 0x01; // P1.0 output
P3SEL |= 0x0C; // P3.2,3 USCI_B0 option select
P3DIR |= 0x01; // P3.0 output direction
UCB0CTL0 |= UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI mstr, MSB 1st
UCB0CTL1 |= UCSSEL_2; // SMCLK
UCB0BR0 = 0x02;
UCB0BR1 = 0;
UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
}
void write_spi(char data)
{
UCB0TXBUF = data; // Byte to SPI TXBUF
while (!(IFG2 & UCB0TXIFG)); // USCI_A0 TX buffer ready?
}
void write_pga(unsigned int value)
{
P3OUT &= ~CS;
write_spi(value>>8);
write_spi(value);
P3OUT |= CS;
}
void set_ch_gain(unsigned int ch,unsigned int gain)
{
unsigned int command;
command = gain<<4;
command += ch;
command +=WRITE;
write_pga(command);
}
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
}
Simple Bit Manipulation Macros
/* Basic bit manipulation macros
No one should ever have to rewrite these
*/
//Set bit y (0-indexed) of x to '1' by generating a a mask with a '1' in the proper bit location and ORing x with the mask.
#define SET(x,y) x |= (1 << y)
//Set bit y (0-indexed) of x to '0' by generating a mask with a '0' in the y position and 1's elsewhere then ANDing the mask with x.
#define CLEAR(x,y) x &= ~(1<< y)
//Return '1' if the bit value at position y within x is '1' and '0' if it's 0 by ANDing x with a bit mask where the bit in y's position is '1' and '0' elsewhere and comparing it to all 0's. Returns '1' in least significant bit position if the value of the bit is '1', '0' if it was '0'.
#define READ(x,y) ((0u == (x & (1<<y)))?0u:1u)
//Toggle bit y (0-index) of x to the inverse: '0' becomes '1', '1' becomes '0' by XORing x with a bitmask where the bit in position y is '1' and all others are '0'.
#define TOGGLE(x,y) (x ^= (1<<y))
Delay for MSP430
void configureClocks();
void delay_ms(unsigned int ms);
void delay_us(unsigned int us);
void configureClocks()
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
}
void delay_us(unsigned int us)
{
while (us)
{
__delay_cycles(1); // 1 for 1 Mhz set 16 for 16 MHz
us--;
}
}
void delay_ms(unsigned int ms)
{
while (ms)
{
__delay_cycles(1000); 1000 for 1MHz and 16000 for 16MHz
ms--;
}
}
PID (Floating Point)
/*! \details This structure holds the data to run a
* floating point PID loop.
*/
typedef struct{
float max /*! \brief Max manipulated value */;
float min /*! \brief Miniumum manipulated value */;
float e /*! \brief Error value */;
float i /*! \brief Integrator value */;
float kp /*! \brief Proportional constant */;
float ki /*! \brief Integrator constant */;
float kd /*! \brief Differential constant */;
} pid_f_t;
/*! \details This function initializes the data in a PID structure.
*
*/
void pid_init_f(pid_f_t * ptr /*! A pointer to the PID data structure */,
float min /*! The manipulated variable's minimum value */,
float max /*! The manipulated variable's maximum value */){
memset(ptr, 0, sizeof(pid_f_t));
ptr->min = min;
ptr->max = max;
}
/*! \details This function updates the value of the manipulated variable (MV)
* based on the current state of the PID loop.
*/
float pid_update_f(float sp /*! The set point */,
float pv /*! The process variable */,
pid_f_t * ptr /*! A pointer to the PID constants */){
float temp;
float e;
float p;
float manp;
float tmpi;
//get the error from the last call
e = ptr->e;
//calculate the new error (set point - present value)
ptr->e = sp - pv;
//use a temp variable for the integrator
tmpi = ptr->i + ptr->e;
//update the manipulated process variable
manp = ptr->kp * ptr->e + ptr->ki * tmpi + ptr->kd * (ptr->e - e);
//the integrator is only updated if the manipulated process is within range
//otherwise the system will likely become unstable
if ( (manp < ptr->max) && (manp > ptr->min) ){
ptr->i = tmpi;
} else if ( manp > ptr->max ){
manp = ptr->max;
} else if ( manp < ptr->min ){
manp = ptr->min;
}
return manp;
}
Additive White Gaussian Noise Generator
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define PI 3.1415926536
double AWGN_generator()
{/* Generates additive white Gaussian Noise samples with zero mean and a standard deviation of 1. */
double temp1;
double temp2;
double result;
int p;
p = 1;
while( p > 0 )
{
temp2 = ( rand() / ( (double)RAND_MAX ) ); /* rand() function generates an
integer between 0 and RAND_MAX,
which is defined in stdlib.h.
*/
if ( temp2 == 0 )
{// temp2 is >= (RAND_MAX / 2)
p = 1;
}// end if
else
{// temp2 is < (RAND_MAX / 2)
p = -1;
}// end else
}// end while()
temp1 = cos( ( 2.0 * (double)PI ) * rand() / ( (double)RAND_MAX ) );
result = sqrt( -2.0 * log( temp2 ) ) * temp1;
return result; // return the generated random sample to the caller
}// end AWGN_generator()
base64 Encoding
#include <string.h>
#include <stdint.h>
//This is a helper function to convert a six-bit value to base64
char base64_encode_six(uint8_t six_bit_value){
uint8_t x;
char c;
x = six_bit_value & ~0xC0; //remove top two bits (should be zero anyway)
if( x < 26 ){
c = 'A' + x;
} else if ( x < 52 ){
c = 'a' + (x - 26);
} else if( x < 62 ){
c = '0' + (x - 52);
} else if( x == 62 ){
c = '+';
} else if (x == 63 ){
c = '/';
} else {
printf("ERROR IN BASE 64\n");
c = 'A';
}
return c;
}
//This is the function for encoding in base64
void base64_encode(char * dest, const char * src){
int bits;
int i;
int j;
int k;
int len;
uint8_t six_bits[4];
len = strlen(src);
k = 0;
//We need to encode three bytes at a time in to four encoded bytes
for(i=0; i < len; i+=3){
//First the thress bytes are broken down into six-bit sections
six_bits[0] = (src[i] >> 2) & 0x3F;
six_bits[1] = ((src[i] << 4) & 0x30) + ((src[i+1]>>4) & 0x0F);
six_bits[2] = ((src[i+1] << 2) & 0x3C) + ((src[i+2]>>6) & 0x03);
six_bits[3] = src[i+2] & 0x3F;
//now we use the helper function to convert from six-bits to base64
for(j=0; j < 4; j++){
dest[k+j] = base64_encode_six(six_bits[j]);
}
k+=4;
}
//at the end, we add = if the input is not divisible by 3
if( (len % 3) == 1 ){
//two equals at end
dest[k-2] = '=';
dest[k-1] = '=';
} else if ( (len %3 ) == 2 ){
dest[k-1] = '=';
}
//finally, zero terminate the output string
dest[k] = 0;
}
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__,________,________),
};
Binary numbers
// The following macros build values in binary. Nybbles are separated by
// commas for readability. If a non-binary digit is used, a compiler error
// will result. Here are some examples of the usage of the binary macros:
//
// B4 (0110) = 0x06
// B8 (0101,0101) = 0x55
// B16 (1010,1010, 0101,0101) = 0xAA55
// B32 (1000,0000, 1111,1111, 1010,1010, 0101,0101) = 0x80FFAA55
//
// For maximum readability, the bytes should be separated by spaces and there
// should be no spaces between nybbles, as shown above. Note that an enum
// isn't used because MISRA-C generates errors otherwise.
#define b0000 0u
#define b0001 1u
#define b0010 2u
#define b0011 3u
#define b0100 4u
#define b0101 5u
#define b0110 6u
#define b0111 7u
#define b1000 8u
#define b1001 9u
#define b1010 10u
#define b1011 11u
#define b1100 12u
#define b1101 13u
#define b1110 14u
#define b1111 15u
#pragma diag_suppress = Pm120
#define B4(n0) (b##n0) //!< Build a nybble in binary
#pragma diag_default = Pm120
#define B8(n1, n0) ((B4 (n1) << 4u) | B4 (n0))
//!< Build a byte in binary
#define B16(n3, n2, n1, n0) \
((B4 (n3) << 12) | (B4 (n2) << 8) | (B4 (n1) << 4) | B4 (n0))
//!< Build a halfword in binary
#define B32(n7, n6, n5, n4, n3, n2, n1, n0) \
((B4 (n7) << 28) | (B4 (n6) << 24) | (B4 (n5) << 20) | (B4 (n5) << 16) \
| (B4 (n3) << 12) | (B4 (n2) << 8) | (B4 (n1) << 4) | B4 (n0))
//!< Build a word in binary
#define B64(nF, nE, nD, nC, nB, nA, n9, n8, n7, n6, n5, n4, n3, n2, n1, n0) \
((B4 (nF) << 60) | (B4 (nE) << 56) | (B4 (nD) << 52) | (B4 (nC) << 48) \
| (B4 (nB) << 44) | (B4 (nA) << 40) | (B4 (n9) << 36) | (B4 (n8) << 32) \
| (B4 (n7) << 28) | (B4 (n6) << 24) | (B4 (n5) << 20) | (B4 (n5) << 16) \
| (B4 (n3) << 12) | (B4 (n2) << 8) | (B4 (n1) << 4) | B4 (n0))
//!< Build a long in binary
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()
Exponential Moving Average
//This macros defines an alpha value between 0 and 1
#define DSP_EMA_I32_ALPHA(x) ( (uint16_t)(x * 65535) )
int32_t dsp_ema_i32(int32_t in, int32_t average, uint16_t alpha){
int64_t tmp0; //calcs must be done in 64-bit math to avoid overflow
tmp0 = (int64_t)in * (alpha) + (int64_t)average * (65536 - alpha);
return (int32_t)((tmp0 + 32768) / 65536); //scale back to 32-bit (with rounding)
}
//here is a function that uses the averaging code
int32_t my_avg_func(void){
static int32_t average = 0;
int32_t adc_value;
adc_value = read_the_adc_value();
average = dsp_ema_i32(adc_value, average, DSP_EMA_I32_ALPHA(0.1));
return average;
}