Embedded C Programming - Neff Siteneff.site/courses/other/legacy/embedded_c/script.pdf ·...
Transcript of Embedded C Programming - Neff Siteneff.site/courses/other/legacy/embedded_c/script.pdf ·...
Embedded C Programming
Networks and Embedded Software
Embedded Systems
by Wolfgang Neff
Programming C (1)
• Code file organization
Header File(Declarations)
Source Code(Implementation)
Program(Executable)
11.02.2016 Embedded C Programming, © W. Neff 2
Programming C (2)
• Header file
#ifndef ADD_H_#define ADD_H_
#define FIVE 5#define ADD(x,y) x+y
extern int result;void add5(int x);
#endif /* ADD_H_ */
Preprocessor directives
Definition of a constant value
Definition of a macro
Declaration of a global variable
Declaration of a function
11.02.2016 Embedded C Programming, © W. Neff 3
Programming C (3)
• Source file
#include "add.h"
int result;
void add5(int x) {result = ADD(x,FIVE);
}
Include header file
Definition of the global variable
Implementation of the function
11.02.2016 Embedded C Programming, © W. Neff 4
Programming C (4)
• Main file
#include <avr/io.h>#include "add.h"
int main(void) {
add5(4);
while (1) {/* do something */
}
}
Include a user header file
Main program
Call function declared in add.h
Infinite main loop(embedded systems, only)
(result now in global variable)
Include a system header file
No good idea!
11.02.2016 Embedded C Programming, © W. Neff 5
Programming C (5)
• Data types
Standard C Alias Embedded Systems* Size
signed char int8_t 8 Bits
unsigend char char uint8_t 8 Bits
signed short int int16_t 16 Bits
unsigend short uint16_t 16 Bits
signed long int32_t 32 Bits
unsigned long uint32_t 32 Bits
float 32 Bits
double (* Defined in <stdint.h>) 64 Bits
11.02.2016 Embedded C Programming, © W. Neff 6
Programming C (6)
• Indirect addressing with pointers
*p = 5;int x = 4;int y = 4;int *p = &y;
SRAM0108hex…0107hex4y:0106hex?0105hex?0104hex?0103hex107hexp:0102hex4x:0101hex…
SRAM0108hex…0107hex5y:0106hex?0105hex?0104hex?0103hex107hexp:0102hex4x:0101hex…
p points to y
11.02.2016 Embedded C Programming, © W. Neff 7
Programming C (7)
• Input / Output
– Special drivers
• E. g. uart_put, uart_get
– Standard input / output
• #include <stdio.h>
• Simple input / output– Characters: getchar, putchar
– Strings: gets, puts
• Complex input / output– scanf / printf
11.02.2016 Embedded C Programming, © W. Neff 8
Programming C (8)
• Formatted output
– int printf(const char *format, ...);
– Format Specifiers
• %d decimal signed integer
• %x hex integer
• %u unsigned integer
• %c character
• %s string
• %p pointer
11.02.2016 Embedded C Programming, © W. Neff 9
Programming C (9)
• Example
– char s = 'A'; // define sensorint d = adc_read(s); // read sensorint v = d / 15; // convert adc to voltageprintf("Sensor %c read '%x'. This are %d V.",s,d,v);
– Result:
• Sensor A read 'A1'. This are 10 V.
• Drawback
– Very expensive – storage and performance
11.02.2016 Embedded C Programming, © W. Neff 10
Programming C (10)
• Logical versus bitwise operators
– Logical operators: !, &&, ||
• No Boolean data type – false = 0, true ≠ 0
• Example: !(a<0 || a>9) = 0 if a ∊ {0 … 9}
– Bitwise operators: ~, &, |, ^, <<, >>
• Same name but different functionality
• Manipulate individual bits
• Do not mix
• Do not confuse
11.02.2016 Embedded C Programming, © W. Neff 11
Programming C (11)
• Operator ~ - bitwise NOT
• Bitwise & - bitwise AND
a 0 0 1 1 0 1 1 0
~a 1 1 0 0 1 0 0 1
a 0 0 1 1 0 1 1 0
b 0 0 0 0 1 1 1 1
a&b 0 0 0 0 0 1 1 0
11.02.2016 Embedded C Programming, © W. Neff 12
Programming C (12)
• Operator | - bitwise OR
• Bitwise ^ - bitwise XOR
a 0 0 1 1 0 1 1 0
b 0 0 0 0 1 1 1 1
a|b 0 0 1 1 1 1 1 1
a 0 0 1 1 0 1 1 0
b 0 0 0 0 1 1 1 1
a^b 0 0 1 1 1 0 0 1
11.02.2016 Embedded C Programming, © W. Neff 13
Programming C (13)
• Operator << - bitwise left shift
• Bitwise >> - bitwise right shift
– Attention: implementation dependent
a 0 0 1 1 0 1 1 0
a<<2 1 1 0 1 1 0 0 0
a 0 0 1 1 0 1 1 0
a>>2 0 0 0 0 1 1 0 1
11.02.2016 Embedded C Programming, © W. Neff 14
Programming C (14)
• Volatile values
– Not under the control of the C compiler
– Change asynchronously
– Optimization would be harmful
– Example
• volatile uint8_t i = USART.DATA;volatile uint8_t j = USART.DATA;if (i != j) { … } // Has DATA changed?// dead code is optimized away if volatile is omitted
11.02.2016 Embedded C Programming, © W. Neff 15
Bit Manipulation (1)
• Individual bits
– Bit position (_bp)
• Example: USART. CTRLC
– USART_SBMODE_bp = 3
– Bit mask (_bm)
• Byte with one bit set at bit position
• Example: USART_SBMODE_bm = 00001000
11.02.2016 Embedded C Programming, © W. Neff 16
Bit 7 6 5 4 3 2 1 0
Name CMODE PMODE SBMODE CHSIZE
Bit Manipulation (2)
• Bits groups
– Group position (_gp)
• Start position of a bit group
• Example: USART_PMODE_gp = 4
– Group mask (_gm)
• Byte with all bits of a bit group set
• Example: USART_PMODE_gm = 0011 0000
11.02.2016 Embedded C Programming, © W. Neff 17
Bit Manipulation (3)
• Bits groups (continued)
– Group configuration (_gc)
• A meaningful configuration of group bits
• Example: PMODE configuration– USART_PMODE_DISABLED_gc = 00000000
– USART_PMODE_EVEN_gc = 00100000
– USART_PMODE_ODD_gc = 00110000
• Header file with definitions
– #include <avr/io.h>
11.02.2016 Embedded C Programming, © W. Neff 18
Bit Manipulation (4)
• Testing bits
– Test if a specific bit is set
• if (REG & BIT_bm) { … }
– Test if a specific bit is cleared
• if (!(REG & BIT_bm)) { … }
– Test if a bit group has a specific configurationif ((REG & GROUP_gm) == GROUP_gc) { … }
logical bitwise
11.02.2016 Embedded C Programming, © W. Neff 19
parenthesis
Bit Manipulation (5)
• Manipulation of individual bits
– Setting one or more bits
• REG |= BIT_bm; (REG = REG | BIT_bm)
• REG |= (BIT1_bm | BIT2_bm | …);
– Clearing one or more bits
• REG &= ~BIT_bm; (REG = REG & ~BIT_bm)
• REG &= ~(BIT1_bm | BIT2_bm | …);
– Toggling one or more bits
• REG ^= BIT_bm; (REG = REG ^ BIT_bm)
11.02.2016 Embedded C Programming, © W. Neff 20
Bit Manipulation (6)
• Manipulation of bit groups
– Clearing a bit group
• REG = REG & ~GROUP_gm;
– Configuring a bit group
• REG = (REG & ~GROUP_gm) | GROUP_gc;
• First clear bit group then set configuration bits
– Assigning a specific value to a bit group
• REG = (REG & ~GROUP_gm) | (value << GROUP_gp);
11.02.2016 Embedded C Programming, © W. Neff 21
Finite State Machines (1)
• They have
– States
– Transitions
– Conditions
– An initial state
• They …
– Do something subject to state
– Switch state if a transition condition is met
Finite State Machines (2)
• State diagram
start statestates
transition
condition
start state
Finite State Machines (3)
• Example
– A LED is controlled by three buttons
• If button 0 is pressed the LED is turned on.
• If button 1 is pressed the LED is turned off.
• While button 2 is pressed the LED is turned on.
– States
• Q0: LED is off
• Q1: LED is on, waiting for a press on button 1
• Q2: LED is on, waiting for the release of button 2
11.02.2016 Embedded C Programming, © W. Neff 24
Finite State Machines (4)
• Example (continued)
– Transitions
• t0: State Q0, button 0 pressed → state Q1
• t1: State Q1, button 1 pressed → state Q0
• t2: State Q0, button 2 pressed → state Q2
• t3: State Q2, button 2 released → state Q0
11.02.2016 Embedded C Programming, © W. Neff 25
Finite State Machines (5)
• Example (continued)
– State diagram
11.02.2016 Embedded C Programming, © W. Neff 26
Finite State Machines (6)
• Example (continued)
– Program• int state=0;
• while(1) {
• switch (state) {
• case 0:
• // Handle state
• led = off;
• // Handle transitions
• if (button0) state=1;
• if (button2) state=2;
• break;
11.02.2016 Embedded C Programming, © W. Neff 27
Finite State Machines (7)
• Example (continued)
– Program (continued)
• case 1:
• led = on;
• if (button1) state=0;
• break;
• case 2:
• led = on;
• if (!button2) state=0;
• break;
• } /* switch */
• } /* while */
11.02.2016 Embedded C Programming, © W. Neff 28
Finite State Machines (8)
• Splitting states into more states
11.02.2016 Embedded C Programming, © W. Neff 29
Finite State Machines (9)
• Example
– Program• int state=0;
• while(1) {
• switch (state) {
• case 0:
• doSomething(0);
• if (button) { state = STOP; break; }
• state = 1;
• break;
• case 1:
• doSomething(1);
• …
11.02.2016 Embedded C Programming, © W. Neff 30
Finite State Machines (10)
• Example (continued)
– Program (continued)
• void doSomething(int action)
• {
• switch (action) {
• case 0:
• action0();
• return;
• case 1:
• action1();
• …
• } /* switch */
• } /* function */
11.02.2016 Embedded C Programming, © W. Neff 31
Finite State Machines (11)
• Timer controlled transitions
11.02.2016 Embedded C Programming, © W. Neff 32
Common Mistakes (1)
• Inconsistent indention
– Incorrect code
• while (!ready) {for (int i=0; i<10; i++) {if (i == 5) {}break;}
11.02.2016 Embedded C Programming, © W. Neff 33
Common Mistakes (2)
• Inconsistent indention (continued)
– Correct code
• while (!ready) {for (int i=0; i<10; i++) {
if (i == 5) {} // Empty statement?break; // Unconditional break?
}// Missing }
11.02.2016 Embedded C Programming, © W. Neff 34
Common Mistakes (3)
• Inconsistent indention (finished)
– Explanation
• Code blocks embraced witch braces ({, }) are very important in C. Such blocks must be seen at first sight. Correct indention is the best way to ensure this.
• Incorrect indention is error prone. Orientation in the code is lost. Missing braces are hard to find and the meaning of the code is hard to understand.
• Inconsistent indention is bad programming style and a typical beginner's mistake.
11.02.2016 Embedded C Programming, © W. Neff 35
Common Mistakes (4)
• Ignoring warnings
– Incorrect code
• short i = 1000000;Warning: overflow in implicit constant conversion
– Correct code
• long i = 1000000; // Fix code
• short i = (short)1000000; // Make intention explicit
11.02.2016 Embedded C Programming, © W. Neff 36
Common Mistakes (5)
• Ignoring warnings (continued)
– Explanation
• C has a the programmer knows what he doesphilosophy. Therefore many potentially dangerous things are possible in C. The compiler, however, often emits a warning. Warnings are important. Do not ignore them.
11.02.2016 Embedded C Programming, © W. Neff 37
Common Mistakes (6)
• Ignoring warnings (finished)
– Explanation (continued)
• The compiler produces correct code even if warnings were emitted. They disappear if you simply build you again as nothing has to bee done. You have to rebuildyour code to see them again. This is how a build system works.
• Avoid warnings at all. Either correct your code or make your intentions explicit.
11.02.2016 Embedded C Programming, © W. Neff 38
Common Mistakes (7)
• Missing prototypes
– Incorrect code
• _delay_ms(100);Warning: implicit declaration of function '_delay_ms'
• int main (void) { …; f(); … }void f(void) { … }Warning: implicit declaration of function 'f'
11.02.2016 Embedded C Programming, © W. Neff 39
Common Mistakes (8)
• Missing prototypes (continued)
– Correct code
• #include <util/delay.h>…_delay_ms(100);
• void f(void);int main (void) { …; f(); … }void f(void) { … }
• void f(void) { … }int main (void) { …; f(); … }
11.02.2016 Embedded C Programming, © W. Neff 40
Common Mistakes (9)
• Missing prototypes (finished)
– Explanation
• C has to know the prototype (signature) of a function. Otherwise it assumes one (implicit declaration). This assumption is in the majority of cases not correct.
• Always include the appropriate header files.
• Provide prototypes for your own functions or define them before they are used. This is often better as you do not need to provide a prototype.
11.02.2016 Embedded C Programming, © W. Neff 41
Common Mistakes (10)
• Missing void in prototype
– Incorrect code
• void f() { … };f(7);
– Correct code
• void f(void) { … };f(7);Error: too many arguments to function 'f'
11.02.2016 Embedded C Programming, © W. Neff 42
Common Mistakes (11)
• Missing void in prototype (continued)
– Explanation
• In C you must explicitly declare that a function has no arguments. This is done by void.
• If you declare a function with empty parentheses it accepts any number of arguments.
• Here C++ differs from C. In C++ you need not and must not put a void between the parentheses
11.02.2016 Embedded C Programming, © W. Neff 43
Common Mistakes (12)
• Misplaced semicolons
– Incorrect code
• if (i > 10); i = 10;
– Correct code
• if (i > 10) i = 10;
• if (i > 10) {i = 10;
}
11.02.2016 Embedded C Programming, © W. Neff 44
Common Mistakes (13)
• Misplaced semicolons (continued)
– Explanation
• In C statements must be closed by a semicolon. A if statement i. g. has the following form: if (condition) statement;. for, while etc. are similar.
• Unfortunately there is a null (empty) statement which is simply a colon. So if (condition); is valid but means: if condition do nothing. This is usually not intended.
• If there is only one statement you may omit the braces but this is considered bad programming style.
11.02.2016 Embedded C Programming, © W. Neff 45
Common Mistakes (14)
• Missing break in switch statement
– Incorrect code
• switch(i) {case 1:n = n + 1;
case 2:n = n - 1;break;
}
11.02.2016 Embedded C Programming, © W. Neff 46
Common Mistakes (15)
• Missing break in switch statement (continued)
– Correct code
• switch(i) {case 1:n = n + 1;break;
case 2:n = n + 1;break;
}
11.02.2016 Embedded C Programming, © W. Neff 47
Common Mistakes (16)
• Missing break in switch statement (continued)
– Correct code
• switch(i) {case 1:case 2: // Possible but meaning is differentn = n + 1;break;
}
11.02.2016 Embedded C Programming, © W. Neff 48
Common Mistakes (17)
• Missing break in switch statement (finished)
– Explanation
• In C the cases of a switch statement fall through. This enables case 1: case 2: … sequences but apart from that is usually not what you want. So don’t forget to place a break before each case.
• In functions return might be in some cases an appropriate alternative.
11.02.2016 Embedded C Programming, © W. Neff 49
Common Mistakes (18)
• Confusing characters and strings
– Incorrect code
• char c = "H";Warning: initialization makes integer from pointer without a cast
– Correct code
• char c = 'H';
11.02.2016 Embedded C Programming, © W. Neff 50
Common Mistakes (19)
• Confusing characters and strings (continued)
– Explanation
• There is no string data type in C. Strings are arrays of char. 'H' is one character whereas "H" are two.
• Characters are like numbers. char c = 'H' actually assigns 72 which is the ASCII code of 'H'. Since characters are numbers c = c+1 is quite okay in C.
• "H" is the shorthand for { 'H', '\0' } as strings are zero terminated in C. { 'H', '\0' } is an array and char c = "H" assigns a pointer to the first element of this array.
11.02.2016 Embedded C Programming, © W. Neff 51
Common Mistakes (20)
• Confusing characters and strings (finished)
– Explanation (continued)
11.02.2016 Embedded C Programming, © W. Neff 52
* Overflow not considered
char c = 'H';
RAM
0101h72c:0102h.
0103h.
0104h.0105h.0106h.
char c = "H";
RAM
0101h0x102*c:0102h72.
0103h0.
0104h.0105h.0106h.
Terminating Zero
Common Mistakes (21)
• Wrong array bounds
– Incorrect code
• int a[5];for (int i<0; i<=5; i++) a[i]=i;
• char s[5] = "Hello";for (int i<0; strlen(s); i++) s[i]='a';
11.02.2016 Embedded C Programming, © W. Neff 53
Common Mistakes (22)
• Wrong array bounds (continued)
– Incorrect code
• int a[5];for (int i<0; i<5; i++) a[i]=i;
• char s[] = "Hello";for (int i<0; strlen(s); i++) s[i]='a';
11.02.2016 Embedded C Programming, © W. Neff 54
Common Mistakes (23)
• Wrong array bounds (continued)
– Explanation
• In an array declaration the number of elements is specified not the upper bound. So an array[5] ranges from 0 to 4. Unfortunately indices are not checked. Therefore values outside may be overwritten.
• Declare strings with implicit size. C does not add a trailing zero if no space is left. So strlen does not work with strings declared such as char s[5] = "Hello"; as they are not zero terminated.
11.02.2016 Embedded C Programming, © W. Neff 55
Common Mistakes (24)
• Wrong array bounds (finished)
– Explanation (continued)
11.02.2016 Embedded C Programming, © W. Neff 56
char s[3] = "abc";int i = 7;
RAM
0101h0x102s:0102h'a'.
0103h'b'.
0104h'c'.0105h7i:0106h.
int a[4] = {0,1,2,3};int i = 7;a[4] = 4; // Wrong!
RAM
0101h0x102a:0102h0.
0103h1.
0104h2.0105h3.0106h4i:
Common Mistakes (25)
• Assignment in conditions (continued)
– Explanation
• = is the assignment operator. x = 3 means that from now on x has a value of 3. The result of this operation is the value assigned. Therefore if (x = 3) is always true since 3 is not zero. In C only zero is regarded to be false.
• == checks for equality. x == 3 is true only if x has a value of 3.
11.02.2016 Embedded C Programming, © W. Neff 57
Common Mistakes (26)
• Assignment in conditions
– Incorrect code
• if (x = 3) { … }Warning: suggest parentheses around assignment used as truth value
– Correct code
• if (x == 3) { … }
11.02.2016 Embedded C Programming, © W. Neff 58
Common Mistakes (27)
• Assignment in conditions (continued)
– Explanation
• = is the assignment operator. x = 3 means that from now on x has a value of 3. The result of this operation is the value assigned. Therefore if (x = 3) is always true since 3 is not zero. In C only zero is regarded to be false.
• == checks for equality. x == 3 is true only if x has a value of 3.
11.02.2016 Embedded C Programming, © W. Neff 59
Common Mistakes (28)
• String processing without loops
– Incorrect code
• putchar("Hallo");Warning: passing argument 1 makes integer from pointer without a cast
– Correct code
• char s = "Hallo";for (int i=0; i<strlen(s); i++) putchar(s[i]);
11.02.2016 Embedded C Programming, © W. Neff 60
Common Mistakes (29)
• String processing without loops (continued)
– Explanation
• You must not pass an array of characters to a function which expects a single character. You have to pass the characters one after another in a for loop.
11.02.2016 Embedded C Programming, © W. Neff 61
Common Mistakes (30)
• Calling functions without parentheses
– Incorrect Codeint f(void) { return 3; }int x = f;Warning: assignment makes integer from pointer without a cast
– Correct Codeint f(void) { return 3; }int x = f();
11.02.2016 Embedded C Programming, © W. Neff 62
Common Mistakes (31)
• Calling functions without parentheses (continued)
– Explanation
• () is the function call operator. So it parentheses are needed also if a function has no arguments. If they are missing the name is considered to be a function pointer. Function pointers are an advanced feature.
11.02.2016 Embedded C Programming, © W. Neff 63