advanced c programming real time programming like the pros

Post on 01-Apr-2015

228 Views

Category:

Documents

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Advanced C Advanced C ProgrammingProgramming

Real Time Programming Real Time Programming Like the ProsLike the Pros

ContentsContents

typedef’stypedef’s Fixed-Point MathFixed-Point Math FilteringFiltering OversamplingOversampling Overflow ProtectionOverflow Protection Switch DebouncingSwitch Debouncing

Good Coding PracticesGood Coding Practices Signed (good) vs Unsigned (bad) Math Signed (good) vs Unsigned (bad) Math

– for physical calculationsfor physical calculations Use BracesUse Braces

{{ Always Always}}

Simple Readable CodeSimple Readable Code– Concept of “Self Documenting Code”Concept of “Self Documenting Code”– Code as if your grandmother is reading itCode as if your grandmother is reading it

Never use Recursion Never use Recursion – (watch your stack)(watch your stack)

*Disclaimer: Not all code in this presentation follows these practices due to space limitations

Typedef’sTypedef’s

Using Naturally Named Using Naturally Named Data TypesData Types

Why Typedef?Why Typedef?

You use variable with logical names, You use variable with logical names, why not use data types with logical why not use data types with logical names?names?

Is an “int” 8-bits or 16-bits? What’s a Is an “int” 8-bits or 16-bits? What’s a “long”? Better question: why “long”? Better question: why memorize it?memorize it?

Most integer data types are platform Most integer data types are platform dependent!!!dependent!!!

typedef’s make your code more typedef’s make your code more portable.portable.

How to use typedef’sHow to use typedef’s

1)1) Create a logical data type scheme. Create a logical data type scheme. For example, a signed 8-bit number For example, a signed 8-bit number could be “s8”.could be “s8”.

2)2) Create a “typedef.h” file for each Create a “typedef.h” file for each microcontroller platform you use.microcontroller platform you use.

3)3) #include “typedef.h” in each of #include “typedef.h” in each of your files.your files.

4)4) Use your new data type names.Use your new data type names.

typedef.h Exampletypedef.h Exampletypedef unsigned char u8;typedef unsigned char u8;typedef signed char s8;typedef signed char s8;typedef unsigned short u16;typedef unsigned short u16;typedef signed short s16;typedef signed short s16;typedef unsigned long u32;typedef unsigned long u32;typedef signed long s32;typedef signed long s32;

In your code:In your code:

unsigned char variable;unsigned char variable;

Is replaced with:Is replaced with:

u8 variable;u8 variable;

Fixed-Point MathFixed-Point Math

Fractional Numbers Using Fractional Numbers Using Integer Data TypesInteger Data Types

Creating FractionsCreating Fractions

Fractions are created by using extra bits Fractions are created by using extra bits below your whole numbers.below your whole numbers.

The programmer is responsible for The programmer is responsible for knowing where the “decimal place” is.knowing where the “decimal place” is.

Move the decimal place by using the shift Move the decimal place by using the shift operator (<< or >>).operator (<< or >>).

Shifting is multiplying by powers of 2. Ex.: Shifting is multiplying by powers of 2. Ex.: x<<5 = x*2^5; x>>5 = x*2^-5x<<5 = x*2^5; x>>5 = x*2^-5

Fixed Point Fraction ExampleFixed Point Fraction Example

A/D Sample (10-bit)

Fractional part

Shift left by 6 (i.e. A2D << 6;):

Whole part

Fractional Example, continuedFractional Example, continued

We know 5/2 = 2.5We know 5/2 = 2.5 If we used pure integers, 5/2 = 2 (i.e. If we used pure integers, 5/2 = 2 (i.e.

the number is rounded toward the number is rounded toward negative infinity)negative infinity)

Using a fixed-point fractional portion Using a fixed-point fractional portion can recover the lost decimal portion.can recover the lost decimal portion.

Fractional Example, continuedFractional Example, continued

0 0 0 0 0 0 0 0 0 0 00 0 1 0 1 = 5

A/D Sample (10-bit)

Fractional part

Shift left by 6 (i.e. A2D << 6;):

Whole part

0 0 0 0 0 1 0 10 0 0 0 0 0 00 = “5.0”

Fractional Example, continuedFractional Example, continued

Divide by 2 (i.e. A2D / 2;):

Fractional part

Whole part

0 0 0 0 0 0 1 00 0 0 0 0 0 01

The whole part: 0000000010(binary) = 2(decimal)

The fractional part: 100000(binary) = 32 (huh???)

Fractional part

Whole part

0 0 0 0 0 1 0 10 0 0 0 0 0 00

Fractional Example, continuedFractional Example, continuedDivide by 2 (i.e. A2D / 2;):

Fractional part

Whole part

0 0 0 0 0 0 1 00 0 0 0 0 0 01

The fractional part: 100000(binary) = 32 (huh???)

How many different values can the fractional part be?

Answer: we have 6 bits => 2^6 values = 64 values

(i.e.) 111111 + 1(binary) = 64(decimal)

Therefore:

Fractional part is actually 32/64 = 0.5

Fractional Example, conclusionFractional Example, conclusionDivide by 2 (i.e. A2D / 2;):

Fractional part

Whole part

0 0 0 0 0 0 1 00 0 0 0 0 0 01

-By using a fixed-point fractional part, we can have 5/2 = 2.5

-The more bits you use in your fractional part, the more accuracy you will have.

-Accuracy is 2^-(fraction bits).

-For example, if we have 6 bits in our fractional part (like the above example), our accuracy is 2^-6 = 0.015625. In other words, every bit is equal to 0.015625

Fractional Example, exampleFractional Example, example

Adding 2.5 + 2.5 0 0 0 0 0 0 1 00 0 0 0 0 0 01

Once our math operations are complete, we right shift our data to regain our original resolution and data position.

If we look diving and adding multiple values using this method we can see the benefit of fixed point math. This example assumes we are adding two “5/2” operations as shown.

0 0 0 0 0 0 1 00 0 0 0 0 0 01

0 0 0 0 0 1 0 10 0 0 0 0 0 00

+

0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 = 50

Without using the fixed point math the result of the addition would have been 4 due to the truncation of the integer division.

FilteringFiltering

Smoothing Your SignalsSmoothing Your Signals

Filter TypesFilter Types

Filters are classified by what they allow to Filters are classified by what they allow to pass through (NOT what they filter out).pass through (NOT what they filter out).

For example, a “low pass filter” (abv. LPF) For example, a “low pass filter” (abv. LPF) allows low frequencies to pass through – it allows low frequencies to pass through – it therefore removes high frequencies.therefore removes high frequencies.

The most common filters are: high pass The most common filters are: high pass filters, low pass filters, and band pass filters, low pass filters, and band pass filters.filters.

We will only cover low pass filters.We will only cover low pass filters.

Low Pass FiltersLow Pass Filters

Low Pass Filters (LPFs) are used to Low Pass Filters (LPFs) are used to smooth out the signal.smooth out the signal.

Common applications:Common applications:

– Removing sensor noiseRemoving sensor noise

– Removing unwanted signal frequenciesRemoving unwanted signal frequencies

– Signal averagingSignal averaging

Low Pass Filters, continuedLow Pass Filters, continued There are two basic types of filters:There are two basic types of filters:

– Infinite Impulse Response (IIR)Infinite Impulse Response (IIR)– Finite Impulse Response (FIR)Finite Impulse Response (FIR)

FIR filters are “moving averages”FIR filters are “moving averages”

IIR filters act just like electrical IIR filters act just like electrical resistor-capacitor filters. IIR filters resistor-capacitor filters. IIR filters allow the output of the filter to move allow the output of the filter to move a fixed fraction of the way toward the a fixed fraction of the way toward the input.input.

Moving Average (FIR) Filter ExampleMoving Average (FIR) Filter Example#define WINDOW_SIZE 16#define WINDOW_SIZE 16s16 inputArray[WINDOW_SIZE];s16 inputArray[WINDOW_SIZE];u8 windowPtr;u8 windowPtr;s32 filter;s32 filter;

s16 temp;s16 temp;s16 oldestValue = inputArray[windowPtr];s16 oldestValue = inputArray[windowPtr];

filter += input - oldestValue;filter += input - oldestValue;

inputArray[windowPtr] = input;inputArray[windowPtr] = input;

if (++windowPtr >= WINDOW_SIZE)if (++windowPtr >= WINDOW_SIZE){{ windowPtr = 0;windowPtr = 0;}}

Moving Average Filter ConsiderationsMoving Average Filter Considerations

For more filtering effect, use more For more filtering effect, use more data points in the average.data points in the average.

Since you are adding a lot of Since you are adding a lot of numbers, there is a high chance of numbers, there is a high chance of overflow – take precautionsoverflow – take precautions

IIR Filter Example (Floating Point)IIR Filter Example (Floating Point)

#define FILTER_CONST 0.8#define FILTER_CONST 0.8

static float filtOut;static float filtOut;

static float filtOut_z;static float filtOut_z;

float input;float input;

// filter code// filter code

filtOut_z = filtOut;filtOut_z = filtOut;

filtOut = input + FILTER_CONST * (filtOut_z – input);filtOut = input + FILTER_CONST * (filtOut_z – input);

// optimized filter code (filtOut_z not needed)// optimized filter code (filtOut_z not needed)

filtOut = input + FILTER_CONST * (filtOut – input);filtOut = input + FILTER_CONST * (filtOut – input);

IIR Filter Example (Fixed Point)IIR Filter Example (Fixed Point)

// filter constant will be 0.75. Get this by// filter constant will be 0.75. Get this by

// (1 – 2^-2). Remember X * 2^-2 = X >> 2// (1 – 2^-2). Remember X * 2^-2 = X >> 2

#define FILT_SHIFT 2#define FILT_SHIFT 2

static s16 filtOut;static s16 filtOut;

s16 input;s16 input;

// filter code// filter code

filtOut += (input - filtOut) >> FILT_SHIFT;filtOut += (input - filtOut) >> FILT_SHIFT;

IIR Filter Example (Fixed Point)IIR Filter Example (Fixed Point)

Whoa! How did we get from Whoa! How did we get from

filtOut = input + FILTER_CONST * (filtOut – input);filtOut = input + FILTER_CONST * (filtOut – input);

ToTo

filtOut += (input - filtOut) >> FILT_SHIFT;filtOut += (input - filtOut) >> FILT_SHIFT;

Math:Math:

filtOut = input + (1 - 2^-2) * (filtOut – input)filtOut = input + (1 - 2^-2) * (filtOut – input)

= input + filtOut – input – 2^-2*filtOut + 2^-2*input= input + filtOut – input – 2^-2*filtOut + 2^-2*input

= filtOut + 2^-2 * (input – filtOut)= filtOut + 2^-2 * (input – filtOut)

filtOut += (input – filtOut) >> 2filtOut += (input – filtOut) >> 2

IIR Filter Considerations (Fixed Point)IIR Filter Considerations (Fixed Point)

For more filtering effect, make the For more filtering effect, make the shift factor bigger.shift factor bigger.

Take precautions for overflow.Take precautions for overflow.

You can get more resolution by using You can get more resolution by using more shift factors. For example, more shift factors. For example, have your filter constant be have your filter constant be

(1 – 2^-SHIFT1 – 2^-2SHIFT2)(1 – 2^-SHIFT1 – 2^-2SHIFT2)

(you’ll have to work out the math!)(you’ll have to work out the math!)

OversamplingOversampling

Gain resolution and make Gain resolution and make your data more reliable.your data more reliable.

Oversampling BasicsOversampling Basics

Simple oversampling: sample more Simple oversampling: sample more data (i.e. faster sample rate) than data (i.e. faster sample rate) than you need and average the samples.you need and average the samples.

Even if you don’t sample faster, Even if you don’t sample faster, averaging (or filtering the data) can averaging (or filtering the data) can be beneficial.be beneficial.

Oversampling EffectsOversampling Effects

Helps to “smooth” the data.Helps to “smooth” the data. Helps to “hide” a bad or unreliable Helps to “hide” a bad or unreliable

sample.sample. Increases A/D resolution if noise is Increases A/D resolution if noise is

present.present.

Oversampling EffectsOversampling Effects

Overflow ProtectionOverflow Protection

Making Sure Your Code Is Making Sure Your Code Is PredictablePredictable

What is Overflow? Why is it Bad?What is Overflow? Why is it Bad?

Overflow is when you try to store a Overflow is when you try to store a number that is too large for its data number that is too large for its data type.type.

For example, what happens to the For example, what happens to the following code?following code?

s8 test = 100;s8 test = 100;

test = test + 50;test = test + 50;

Overflow Protection MethodsOverflow Protection Methods

1.1. Create a new temporary variable using a Create a new temporary variable using a data type with a larger range to do the data type with a larger range to do the calculation.calculation.

2.2. Compare the sign of the variable before Compare the sign of the variable before and after the calculation. Did the sign and after the calculation. Did the sign change when it shouldn’t have? (for change when it shouldn’t have? (for signed variables)signed variables)

3.3. Compare the variable after the Compare the variable after the calculation to the value before. Did the calculation to the value before. Did the value decrease when it should have value decrease when it should have increased? increased?

Overflow Protection, Example 1Overflow Protection, Example 1

s16 add16(s16 adder1, s16 adder2); // prototypes16 add16(s16 adder1, s16 adder2); // prototype

S16 add16(s16 adder1, s16 adder2)S16 add16(s16 adder1, s16 adder2){{ s32 temp = (s32)adder1 + (s32)adder2;s32 temp = (s32)adder1 + (s32)adder2; if (temp > 32767) // overflow will occurif (temp > 32767) // overflow will occur return 32767;return 32767; else if (temp < -32768) // underflowelse if (temp < -32768) // underflow return -32768;return -32768; elseelse return (s16)temp;return (s16)temp;

}}*This example uses a s32 (larger) data value for overflow checking

Overflow Protection, Example 2Overflow Protection, Example 2// prototype// prototypes16 addTo16bit(s16 start, s16 adder);s16 addTo16bit(s16 start, s16 adder);

S16 addTo16bit(s16 start, s16 adder)S16 addTo16bit(s16 start, s16 adder){{ s16 temp = start;s16 temp = start; start += adder;start += adder; if ((start > 0) && (adder > 0) && (temp <= 0))if ((start > 0) && (adder > 0) && (temp <= 0)) return 32767; // Overflow occurredreturn 32767; // Overflow occurred else if ((start < 0) && (adder < 0) && (temp >= 0))else if ((start < 0) && (adder < 0) && (temp >= 0)) return -32768; // Underflow occurredreturn -32768; // Underflow occurred elseelse return start;return start;

}}

*This example uses 16 bit values only to check for overflow on signed values this provides improved efficiency on 16 bit platforms.

Overflow Protection, Example 3Overflow Protection, Example 3// prototype// prototypeu16 addToUnsigned16bit(u16 start, s16 adder);u16 addToUnsigned16bit(u16 start, s16 adder);

S16 addToUnsigned16bit(u16 start, s16 adder)S16 addToUnsigned16bit(u16 start, s16 adder){{ u16 temp = start;u16 temp = start; start += adder;start += adder; if ((adder > 0) && (start < temp))if ((adder > 0) && (start < temp)) return 65536; // Overflow occurredreturn 65536; // Overflow occurred else if ((adder < 0) && (start > temp))else if ((adder < 0) && (start > temp)) return 0; // underflow occurredreturn 0; // underflow occurred elseelse return start;return start;

}}

*This example checks for overflow on unsigned values

Switch DebouncingSwitch Debouncing

Having Confidence in Having Confidence in Switch InputsSwitch Inputs

Why Debounce? When to Use It?Why Debounce? When to Use It?

Debouncing a switch input reduces Debouncing a switch input reduces erroneous inputs.erroneous inputs.

Use debouncing when pressing a Use debouncing when pressing a switch starts a sequence or changes switch starts a sequence or changes the state of something.the state of something.

When to Debounce ExamplesWhen to Debounce Examples

Debounce when a single push of the Debounce when a single push of the switch changes a state. Examples:switch changes a state. Examples:

- pneumatic gripper- pneumatic gripper

- motorized gripper where a single - motorized gripper where a single push causes the motor to go until a push causes the motor to go until a limit switch is reachedlimit switch is reached

Do not debounce if constant driver Do not debounce if constant driver input is needed.input is needed.

What is Debouncing?What is Debouncing?

Basically, debouncing means to require a Basically, debouncing means to require a certain number of samples before you certain number of samples before you confirm the switch input.confirm the switch input.

Various debounce schemes can be used:Various debounce schemes can be used:

- require N - require N consecutive samplesconsecutive samples (i.e. reset (i.e. reset the counter if one sample fails)the counter if one sample fails)

- count up / count down (i.e., if one sample - count up / count down (i.e., if one sample fails, decrement the counter by 1 rather fails, decrement the counter by 1 rather than resetting to zero.than resetting to zero.

Debounce ExampleDebounce Example // debounce opening gripper// debounce opening gripper if (!pneumaticGripperOpenState)if (!pneumaticGripperOpenState) {{ if (gripperOpenSwitch == ON)if (gripperOpenSwitch == ON)

gripperOpenDebCount++;gripperOpenDebCount++; elseelse gripperOpenDebCount = 0;gripperOpenDebCount = 0; if (gripperOpenDebCount >= DEBOUNCE_LIMIT)if (gripperOpenDebCount >= DEBOUNCE_LIMIT) {{ gripperOpenDebCount = 0;gripperOpenDebCount = 0; pneumaticGripperOpenState = TRUE;pneumaticGripperOpenState = TRUE; }} }}

top related