0% found this document useful (0 votes)
33 views48 pages

Net3001 5 C

NET3001-5-C

Uploaded by

werqt01
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
33 views48 pages

Net3001 5 C

NET3001-5-C

Uploaded by

werqt01
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 48

NET3001

C Programming
Advantages
● programmers can work at a higher level than
assembly language
– can ignore the low level details
– work at a higher level of abstraction
● code is (mostly) portable
● language provides
– type checking
– control statements other than test-&-jump
– subroutine parameter/temp/return management
● still has low overhead
– can still access pointers
Data Types
void functions that return nothing
char single byte of data
short a small int, 16 bits
int/long a single word, 32 bit integer
unsigned char control the way math operates on larger
unsigned int numbers
boolean a byte
char[] an array of bytes

float 32 bit single-precision floating point


double 64 bit
we won't be using floating point

pointers to be discussed
C keywords
● these words are special
Data int long short char void
Data modifier const volatile static enum
signed unsigned
Control flow do while if else for
Switch switch case default
Disrupt the flow break continue
Extra sizeof
Not used in float double extern inline register
NET3001 auto restrict struct typedef union goto

● just about everything else goes into the


symbol table
C symbols

Subroutines ()
Math + - * / ++ -- %
Logicals & | && || == >= > < <= != ! ~ ^
Line end ;
Comments /* */ //
Preprocessor #
Arrays & pointers [] * &
Strings " '
Initializers {}
Fast assignment += -= *= /= %= &= |= ~= ^=
Either or ? :
Not used ... -> . ::
BEDMAS ()
Logical Operations
● any expression which is non-zero is
considered true
(i<10)
(i>0 && i<10)
(i) same as (i!=0)

● bit-wise operations
–only for char, short, int & long
PCOUT = PCOUT | 0x40; // set bit 6
PCOUT = PCOUT & 0xFFFE; // clear bit
0
PCOUT &= 0xFE; // the same
i = (PBIN >> 2); // shift right
if (!(PAIN & 0x80)) // check bit 7
Operators
● math
+ - * /
% (modulus) ++ --(inc dec)

● bit-wise operations
– returns char, short, int & long
& | ^ << >> (and or xor shift-l shift-r)
~ (invert each bit)

● logical operations
– return true or false/0
&& || == != (and or equal not-equal)
> < >= <= (math tests)
! (logical inversion)
Flow Control
● C has a powerful set of control structures
if (condition) {
doTrueActions();
} else {
doFalseActions();
}

while(condition) {
doActions();
}

do { // does at least once!


Actions();
} while (condition);
Flow Control
● C has a powerful set of control structures
for (i=0; i<100; i++) {
doLoopActions();
}
// is
for (init-expression; test-expression; incr-expr)
{
loopCode();
}
– init-expression is always executed
– test-expression is always executed
● if the return value is true, then we loop

– the incr-expression is executed after the loop code has been run
Flow Control
● multiple choice
switch(nChoice) {
case 0:
doFor0();
break;
case 2:
doFor2();
break;
case 7:
doFor7();
break;
default:
doOther();
break;
}
Flow Control
● keywords which affect flow
break
// escape out of the inner most for,while,do or switch

for (i=0; i<10; i++) {


r = sendPacket(i);
if (r==ERROR)
break;
}

continue
// finish the current for, while or do loop,
//but keep executing

for (i=0; i<100; i++) {


if (packetType[i] == PACKET_SKIP)
continue;
sendPacket(i);
}
Subroutines
● small chunk of code that does something
useful
– if you ever find yourself typing the same code
more than twice, you probably should use a
subroutine
– try to stay smaller than 2 screens worth
● if it's bigger than that, break it into sub-subroutines
● you can send it information
– you can send multiple things
– in C we usually send a copy of the information
● you can get one item of information back
Subroutine Examples
● general use
– max(), createSocket(), readFile()

● specialized
– getHttpObject()

● for this course


– setFontColor(char color)
– set7Segment(char n)
– setDCMotor(int direction)
– delayMsec(int nMsec)
Declare Subroutine
● C syntax
/** addArpTableEntry
ipAddr – to add to table
netMask – to indicate a range
tExpire – if -ve, don't add to table */
int addArpTableEntry(int ipAddr, int netMask, char tExpire)
{
int ipRange;
ipRange = ipAddr & netMask;
registerAddr(ipAddr, ipRange); 3 chunks of info
if (tExpire>0) sent into sub'rtn
addToTable(1, ipAddr, tExpire); one word, word
return 1; local variable char
} 4 bytes on stack

returns information of type int

name of subroutine....this goes into symbol table


Use Subroutine
● simply use the subroutine name, with round
brackets
r = addArpTableEntry(my_IP, my_mask, 1);
lcdSetFont(1);
lcdSetFont(LCD_BIG);
lcdPrintf(“hello %s”,”bob”);

setMotorPosition(calcPosition(4,-1));
// you can use a subroutine return value anywhere

PCOUT = calcLedPattern(0x0E,1,1,0,1);
// this does not call the subroutine!
// it just does a look up in the symbol table
a = lcdSetFont;
● when the code generator sees
valid = setFontColor(12);
● it does this
mov r0,#12
bl setFontColor // in the symbol table
ldr r1,=valid // in the symbol table
str r0,[r1]
● when the code generator sees this
valid = setFontColor;
it does this
ldr r0,=setFontColor // in symol table
ldr r1,=valid // in symbol table
str r0,[r1]
Quiz
● what's wrong with this?
unsigned int w;
// find the absolute value
if (w<0)
w = -w;

● and this?
void doubleMe(int r) {
r = 2*r;
}
int x = 14;
doubleMe(x);
Data Areas
int a; // Global in .bss
int b = 1; // Initialized global .data
static int c; // Static External in .bss
// (only for this file)
static int d = 2; // Init’d static in .data

void anyFunction () { // Including main()


int e; // Automatic or Local in stack
int f = 3; // Automatic or Local in stack
static int g; // Persistent Local in .bss but only
// visible in function
static int h=5; // Init’d persistent Local in .data
// but only visible in function
}

const char[] str = “this is a string”;


// stored in the .text section
C to Assembler
● real example
char release = 1; // .byte 1 [in .data]
int i; // .word 0 [in .bss]

while(release!=0) // ldr r0,=release


{} // ldrb r0,[r0]
// cmp r0, #0
// bne $-8 similar to sub r15,#8

PCOUT = 0x0700; // ldr r0,=0x4001100C


// mov r1,#0x0700
// strh r1,[r0]

while(1) {
PCOUT = (i & 7); // ldr r1,=i (somewhere in RAM)
// ldr r0,[r1]
// and r0,r0,#7
// ldr r2,=PCOUT (0x4001.100c)
// strh r0,[r2]
i++; // ldr r0,[r1]; add r0,r0,#1
// str r0,[r1]
delay(); // bl delay
} // b pc-22 similar to sub r15,#22
Memory Layout
char b = 4; // goes into .data 0x0800.0000 .vectors
.text
char s; // goes into .bss
const char f = 12; // goes in .text

int main() { // goes into .text flash


int a; // goes on the stack
0x0808.0000
doStuff();
}

0x2000.0000
.data
.bss
stack
0x2000.2000
0x4000.0000
i/o
Symbol Table
int aVariable;
void one_sec_delay(void) {
int i;
for (i=0; i<3000000; i++)
;
}
int main(void) {
int r;
PCDDR_HI = 0x11111111;
for (r=0; r<8; r++) {
PCOUT = (r<<8);
delay();
}
}
Symbol Table
Name Value Type Size Section Content
aVariable 0x2000.0000 int 4 .bss 0
one_sec_delay 0x0800.0040 function void(void) 0 .text
one_sec_delay.i stack 0(sp) int 4 stack
main 0x0800.0068 function int(void) 0 .text
main.r stack 0(sp) int 4 stack

notice the focus on the address of the variables


this is reflected in the fact that most assembly language instructions deal
with the address of the variable

in actual fact, the variables delay.i and main.r may be stored in on


the stack frame or they may be stored in registers; the compiler decides
Real Code (for debugging)
int main(void) {
2f8: b580 push {r7, lr}
2fa: b082 sub sp, #8
2fc: af00 add r7, sp, #0
int r;
PCDDR_HIGH = 0x11111111;
2fe: 4b0d ldr r3, [pc, #52] ; (334 <test+0x3c>)
300: f04f 3211 mov.w r2, #286331153 ; 0x11111111
304: 605a str r2, [r3, #4]
for (r=0; r<8; r++) {
306: f04f 0300 mov.w r3, #0
30a: 607b str r3, [r7, #4] ; r
30c: e00a b.n 324 <test+0x2c>
PCOUT = (r<<8);
30e: 4b09 ldr r3, [pc, #36] ; (334 <test+0x3c>)
310: 687a ldr r2, [r7, #4] ; r
312: ea4f 2202 mov.w r2, r2, lsl #8
316: 60da str r2, [r3, #12]
delay();
318: f7ff fffe bl 0 <delay>
318: R_ARM_THM_CALL delay
31c: 687b ldr r3, [r7, #4] ; r
31e: f103 0301 add.w r3, r3, #1
322: 607b str r3, [r7, #4] ; r
324: 687b ldr r3, [r7, #4] ; r
326: 2b07 cmp r3, #7
328: ddf1 ble.n 30e <test+0x16>
32a: 4618 mov r0, r3
32c: f107 0708 add.w r7, r7, #8
330: 46bd mov sp, r7
332: bd80 pop {r7, pc}
334: 40011000 .word 0x40011000
Real Code (for production)

int main(void) {
PCDDR_HIGH = 0x11111111;
188: 4b07 ldr r3, [pc, #28] ; (1a8 <test+0x20>)
18a: f04f 3211 mov.w r2, #286331153 ; 0x11111111
18e: b510 push {r4, lr}
190: 605a str r2, [r3, #4]
for (r=0; r<8; r++) {
192: 2400 movs r4, #0 ; use r4 to hold r
PCOUT = (r<<8);
194: 4b04 ldr r3, [pc, #16] ; (1a8 <test+0x20>)
196: 0222 lsls r2, r4, #8
198: 60da str r2, [r3, #12]
19a: 3401 adds r4, #1 ; r++
19c: f7ff fffe bl 0 <delay>
19c: R_ARM_THM_CALL delay
1a0: 2c08 cmp r4, #8 ; if (r<8)
1a2: d1f7 bne.n 194 <test+0xc>
1a4: bd10 pop {r4, pc}
1a6: bf00 nop
1a8: 40011000 .word 0x40011000
Pointers
● a pointer is another type of variable
● can address any type of variable
– byte, int, array, function....anything
● a pointer is always 4 bytes long
char b; // is 1 byte
&b; // the address of 'b'
char* pb; // is four bytes
pb = &b; // write 4 bytes to pb
b = 4; // write to the byte 'b'
*pb = 12; // write to the SAME byte

int c; // is 4 bytes
int* pc = &c; // is 4 bytes, just a coincidence

char string1[14]; // is 14 bytes


char * string2; // is 4 bytes
Pointer Syntax
● '&' means “take the address of...”
– will always be 4 bytes
● '*' means “use this as an address, and go
through it to access the data
– dereferencing
– may be different sizes or properties, depending
on the type of the pointer
unsigned char* puc;

a = 14 + *puc ; // *puc is an unsigned char

if (*puc < 150) // the compiler will do


// unsigned math on this
Pointers
● on this CPU, pointers are 4 bytes
● pointers to writable data will be
– around 0x2000.0000 for globals and statics
– around 0x2000.1FE0 for variables on the stack
● pointers to const data will be
– around 0x0800.0000 (flash)
int a = 12; // global, in .data
int b; // global, in .bss
const int c = 0xDEADFACE; // in .rodata (flash)
void delay(int d) { // d is on the stack
int e; // automatic, it's on the stack, too
}

const char sMyName[] = “Pat Beirne”; // in .rodata


char sChangeName[] = “Pat Beirne”; // in .data
Arrays and Pointers
● arrays are of size n*type_size DIFFERENT!
● pointers are always 4 bytes
● you can dereference them in two ways!
char aData[12] = {4,5,7,3,4, 6,5,4,3,2, 0,1};
char* pData; // is 4 bytes

// dereferencing
aData[2]; // is one byte long ==7
*(aData + 2); // is the same ==7

// assigning a pointer
pData = aData; // 4 bytes are written
*(pData + 5); // is a byte == 6
pData[5]; // is the same == 6
Pointers and Arrays
● arrays names go into the symbol table and take
up n bytes in memory
● pointers go into the symbol table and take up 4
bytes in memory
char aData[12] = {4,5,7,3,4, 6,5,4,3,2, 0,1};
char* pData; // is 4 bytes

pData = aData; // assign the 4 byte address


pData++; // modify the 4 bytes to point to next

aData++; // !! not allowed!! illegal


// aData is the address of the 12 bytes
// you cannot change aData; only *aData
symbol value type size contents
aData 0x2000.0000 char[] 12 4,5,7,3,4.....
pData 0x2000.000C char* 4 0x2000.0000
Pointers and Array
– a common idiom
● create a pointer which points to the start of an array
● use the pointer to fetch the contents of the array
● then increment it to go to the next
const char szHelloWorld[] = “Hello there!”; // at 0x0800.0144
char *pString; // at 0x2000.0000

for (i=0; i<12; i++)


doSomething(szHelloWorld[i]); //fetch from flash

// or
pString = szHelloWorld; // put 0x0800.0144 into pString
while (*pString) // use it as a pointer
doSomething(*pString++); // fetch through pString then
// increment it to 0x0800.0144/5/6...
Static
● the static keyword has several meanings
– static on a function
● visible only to this file
– static on a variable outside a function
● visible only to this file
– static on a variable inside a function
● variable exists even when the function exits
● it lives in .bss or .data, has permanent address

int countDogs(int newDogs) {


static int nDogs;
nDogs = nDogs + newDogs;
return nDogs;
}
C Defines

#define lets you make your code easier to read


PAOUT |= 0x0800; // beep-click
delay_ms(2);
PAOUT &= ~0x0800;
//------------------or-----------------
#define BEEPER_ON_BIT 0x0800
#define BEEPER_OFF_BIT ~0x0800 // 0xF7FF
#define MAIN_OUT PAOUT

MAIN_OUT |= BEEPER_ON_BIT;
delay_ms(2);
MAIN_OUT &= BEEPER_OFF_BIT;
//------------------or------------- I like this one best
#define BEEPER_ON PAOUT |= 0x0800
#define BEEPER_OFF PAOUT &= ~0x0800

BEEPER_ON;
delay_ms(2);
BEEPER_OFF;
Startup Code
● contained in crt1.c
● copy .data from flash to ram
– ram contents are unknown/random at power-up
time
● clear .bss
– immediately after the .data section
● C++ constructors; initialize the library
● jump to main()

● stack pointer was set up by hardware


● interrupts are off be default
AND / OR
examine, extract, access,
observe, evaluate AND
● inputs
if ((PAIN & 2) == 0) ...
while ((PBIN & 4) != 0) ...
● the pattern has 1's where we want to extract information
● so it's mostly 0's
● outputs
PCOUT = PCOUT | 0x0100; // set a 1 (pattern mostly 0's)
PCOUT |= 0x0100; // same as above

PCOUT = PCOUT & 0xFEFF; // force a 0 (pattern mostly 1's)


PCOUT = PCOUT & ~0x0100; // same as above
PCOUT = PCOUT & ~LED_BLUE; // same as above
PCOUT &= ~LED_BLUE; // same as above
● these |= &= contractions only work with single bit sets

● for multiple bits, you have to do the operation in steps


PCOUT = (PCOUT & 0xFF00) | 0x0036;
outputs
left hand of = sign
AND / OR example

● how would you decrement the TTL?


int packet[];
int ttl = packet[2] & 0x000000ff; // extract the 8 bits
if (ttl > 0) {
packet[2] = packet[2] & 0xFFFFFF00; // force 0's in the TTL
packet[2] = packet[2] | (ttl-1); // add back the new TTL
}
AND / OR example

● how would you check the DF flag?


int packet[];
int flags = packet[1] & 0x00070000; // extract the 3 bits
if (flags & 0x00020000) {
. . . do something
}
OR
flags = flags >> 16;
if (flags & 2) {….do something }
Common Idioms in C
● to do something n times
for (i=0; i<n; i++) {...}
● to wait for a bit to change
while ((P2IN & 1) == 0) // keyboard
{}
while (TIM1->CNT < 10000) // timer
{}
● to count and loop back
while(1) // forever-loop
for(i=0; i<100; i++)
{}
● or
while(1) {
i++;
if (i==100)
i=0;
}
Program Examples
● write the code for an electric toothbrush
● I/O
– single push button (P1.0)
– the reciprocating motor (P1.2)
– a timer (on chip), counting at 0.5 sec (TAR)
● functions
– push button to turn on
– push button to turn off
– after 2 minutes of being on, turn the motor
off/on/off/on/off/on at 0.5 second intervals
Program Examples
● write the code for a model railroad crossing
● I/O
– single train sensor (P1.0)
– the motor to raise the gate (P1.2)
– motor to lower the gate (P1.3)
– two red LED's (P1.4 & P1.5)
– noise maker (P1.7)
– a timer (on chip), counting at 0.1 sec (TAR)
● functions
– when a train is present
● lower the gate (motor on for 1 sec)

● flash the two LED's alternately, at 0.5 seconds

● operate the dinger, at 8 dings/sec

– when the train leaves


● stop LED's and dinger

● raise the gate (motor on the other way for 1 sec)


Idioms in C
● idioms are common techniques

● if you have to do something n times...


for (i=0; i<n; i++) {
do stuff
}

● if you don't need the variable n anymore, try


while(n--) {
do stuff
}
Idioms (cont'd)
● if you need to do something forever, try

while(1) {
do stuff
}
Idioms (cont'd)
● you are allowed to add extra statements to
the 1st and 3rd sections of an if statement
for (count=0, i=0; i<100; i++) {
do stuff;
count += 2;
}
● or even
for (count=0, i=0; i<100; i++, count+=2) {
do stuff;
}
Idioms (cont'd)
● you can use the "break" statement to get out
of one loop, but you need to use a variable to
break out of a deep loop
int done = 0;

for (j=0; j<100 && !done; j++) {


for (i=0; i<4 && !done; i++) {
r = sendPacket(i*j);
if (r==ERROR)
// want to exit all
{
done = 1;
}
}
}
.h Files
● declare all the public variables and functions that
a .c file provides to the project
– data is prefixed with the word “extern”
extern unsigned char fColor;
– functions are simply prototypes, without body
void lcdSetFontColor(unsigned char);
● .h files add entries to the symbol table
– as a rule, .h files do not create either RAM or FLASH entries
● that's what .c files are for
– .h files often have lots of #defines
● #defines engage a search-&-replace mechanism and do not

use the symbol table


– once you have #include'd a .h file, you can use any of the
symbols with confidence
● recent guidelines suggest that usage documentation should
be in the .H file
.h File
motors.h lcd.h assign31.h

void setDcMotor(int); void lcdSetTextColor(int); may not be needed


void step(int); void lcdPutStr(char*,int,
int);

extern unsigned char fColor;

motors.c lcd.c assign31.c

#include “motors.h”
#include “motors.h” #include “lcd.h”
#include “lcd.h”
void setDcMotor(int) { void lcdSetTextColor(int) {
main(void) {
…...... //body ….... //body
…...//body
} }
lcdSetTextColor(LCD_WHITE);
a = fColor;
void lcdPutStr(char*, int, int) {
void step(int d) { setDCMotor(-1);
….......//body
…..... // body }
}
}
unsigned char fColor;
add entry
generate
code
to symbol
table .h File
motors.h lcd.h assign31.h

void setDcMotor(int); void lcdSetTextColor(int); may not be needed


void step(int); void lcdPutStr(char*,int,
int);

extern unsigned char fColor;

motors.c lcd.c assign31.c

#include “motors.h”
#include “motors.h” #include “lcd.h”
#include “lcd.h”
void setDcMotor(int) { void lcdSetTextColor(int) {
main(void) {
…...... //body ….... //body
…...//body
} }
lcdSetTextColor(LCD_WHITE);
a = fColor;
void lcdPutStr(char*, int, int) {
void step(int d) { setDCMotor(-1);
….......//body
…..... // body }
}
}
unsigned char fColor;
.h File
motors.h lcd.h assign31.h

void setDcMotor(int); void lcdSetTextColor(int); may not be needed


void step(int); void lcdPutStr(char*,int,
int);

extern unsigned char fColor;

motors.c lcd.c assign31.c

#include “motors.h”
#include “motors.h” #include “lcd.h”
#include “lcd.h”
void setDcMotor(int) { void lcdSetTextColor(int) {
main(void) {
…...... //body ….... //body
…...//body
} }
lcdSetTextColor(LCD_WHITE);
a = fColor;
void lcdPutStr(char*, int, int) {
void step(int d) { setDCMotor(-1);
….......//body
…..... // body }
}
}
unsigned char fColor;
.h File
motors.h lcd.h assign31.h

void setDcMotor(int); void lcdSetTextColor(int); may not be needed


void step(int); void lcdPutStr(char*,int,
int);

extern unsigned char fColor;

motors.c lcd.c assign31.c

#include “motors.h”
#include “motors.h” #include “lcd.h”
#include “lcd.h”
void setDcMotor(int) { void lcdSetTextColor(int) {
main(void) {
…...... //body ….... //body
…...//body
} }
lcdSetTextColor(LCD_WHITE);
a = fColor;
void lcdPutStr(char*, int, int) {
void step(int d) { setDCMotor(-1);
….......//body
…..... // body }
}
}
unsigned char fColor;

You might also like