You are on page 1of 82

LẬP TRÌNH HỆ THỐNG

NHÚNG

BÙI QUỐC BẢO

BỘ MÔN KỸ THUẬT ĐIỆN TỬ-ĐH BK TP.HCM


Mục tiêu môn học
 Tự mình thiết kế phần mềm cho một hệ thống
nhúng dùng 1 hay nhiều CPU dựa trên vi điều
khiển ARM dựa trên một phần cứng có sẵn.
 Phần mềm được thiết kế có cấu trúc, dựa trên
ngôn ngữ cấp cao (C) hoặc sử dụng cả hợp
ngữ và C.
 Nắm được lý thuyết cơ bản về hệ điều hành
nhúng; sử dụng được các hệ điều hành nhúng
cơ bản (FreeRTOS).
 Nắm được cơ bản về cấu trúc và cách viết
ứng dụng cho hệ điều hành embedded linux
Tài liệu tham khảo

 Embedded C, Michael J Pont


 Lập Trình Hệ Thống Nhúng, Hoàng
Trang-Bùi Quốc Bảo.
Đánh giá kết quả

 Giữa kỳ: 20%


 Bài tập lớn: 30%
 Cuối kỳ: 50%
Khái niệm về hệ thống nhúng

 Hệ thống nhúng là sự kết hợp giữa phần


cứng máy tính và phần mềm, được thiết
kế để thực hiện một chức năng chuyên
biệt. Người sử dụng một hệ thống nhúng
không cần biết rằng hệ thống có một
máy tính bên trong
 VD: remote TV, lò vi sóng,…
Vi xử lý trong hệ thống nhúng
 Họ 8086
 PowerPC
 MIPS
 Họ 8051
 PIC
 …
 Tùy thuộc vào ứng dụng và giá thành, người
thiết kế quyết định loại vi xử lý dùng trong hệ
thống nhúng.
Vi xử lý dùng trong môn học này

 ARM Cortex M3
 ARM Cortex A8
Ngôn ngữ lập trình

Assembler
C
Phần cứng và phần mềm

 Kit TIVA lauchpad


 CCS software

 CodeBlock Software
 https://www.youtube.com/watch?v=3B4h
PHZNtNw&feature=youtu.be
Phần cứng và phần mềm
Kit Raspberry PI
Raspberry PI Simulator:
https://docs.microsoft.com/en-gb/azure/iot-hub/iot-hub-raspberry-pi-web-simulator-get-started
Phần cứng và phần mềm
Beagle Bone Black
Software: Qemu
Các phần cứng khác

https://www.st.com/en/evaluation-tools/32f746gdiscovery.html
Lý do sử dụng ngôn ngữ C

 C cho phép lập trình có cấu trúc.


 Ngôn ngữ C cho phép dễ dàng truy cập đến
cấu trúc phần cứng (ví dụ thông qua con trỏ)
 C được dùng rất phổ biến.
 Hầu hết các họ vi xử lý đều được hỗ trợ trình
biên dịch C.
 Rất nhiều taì nguyên tham khảo (sách, ví dụ,
website …) về lập trình C.
Lý do dùng hợp ngữ (Assembler)

 Cho phép viết những chương trình có


kích thước nhỏ nhất và chạy với tốc độ
nhanh nhất.
 Thích hợp cho những ứng dụng có yêu
cầu nghiêm ngặt về thời gian.
C operator
 = assignment statement
 @ address of
 ? selection
 < less than
 > greater than
 ! logical not (true to false, false to true)
 ~ 1's complement
 + addition
 - subtraction
 * multiply or pointer reference
 / divide
 % modulo, division remainder
 | logical or
 & logical and, or address of
 ^ logical exclusive or
 . used to access parts of a structure
C operator
 == equal to comparison
 <= less than or equal to
 >= greater than or equal to
 != not equal to
 << shift left
 >> shift right
 ++ increment
 -- decrement
 && boolean and
 || boolean or
 += add value to
 -= subtract value to
 *= multiply value to
 /= divide value to
 |= or value to
 &= and value to
 ^= exclusive or value to
 <<= shift value left
 >>= shift value right
 %= modulo divide value to
 -> pointer to a structure
Hello World Program
/*****************************************************
Function: main()
Description: Blink the green LED once a second.
Notes: This outer loop is hardware-independent.
However, it depends on two hardware-dependent functions.
Returns: This routine contains an infinite loop.
***********************************************************
***********/
#include "led.h"
#include "delay.h"
void main(void)
{ while (1) {
toggleLed(LED_GREEN);
/* Change the state of the LED. */
delay(500); /* Pause for 500 milliseconds. */
} }
Comments (chú thích)

 // This is a comment line


 /*
This is a comment block
*/
Preprocessor Directives (chỉ dẫn
tiền xử lý)
 Được xử lý đầu tiên trong quá trình biên
dịch
 Bắt đầu bằng từ khóa #
 VD:

 #include “LCD.h"
 #define LCD *(unsigned char volatile *)(0x1003)
Key word (Từ khóa)
 asm Insert assembly code
 auto Specifies a variable as automatic (created
on the stack)
 break Causes the program control structure to finish
 case One possibility within a switch statement
 char 8 bit integer
 const Defines parameter as constant in ROM
 continue Causes the program to go to beginning of loop
 default Used in switch statement for all other cases
 do Used for creating program loops
 double Specifies variable as double precision floating point
 else Alternative part of a conditional
 extern Defined in another module
 float Specifies variable as single precision floating point
Key word (Từ khóa)
 for Used for creating program loops
 goto Causes program to jump to specified
location
 if Conditional control structure
 int 16 bit integer
 long 32 bit integer
 register store the variable onto the CPU register if
space on the register is available
return Leave function
 short 16 bit integer
Key word (Từ khóa)
 signed Specifies variable as signed (default)
 sizeof Built-in function returns the size of an
object
 static Stored permanently in memory, accessed
locally
 struct Used for creating data structures
 switch Complex conditional control structure
 typedef Used to create new data types
 unsigned Always greater than or equal to zero
 void Used in parameter list to mean no parameter
 volatile Can change implicitly
 while Used for creating program loops
Dấu chấm phẩy (semicolons)

 Chấm dứt câu lệnh


 VD:
 For (i=0;i<1000;i++);
Dấu hai chấm (colons)
 Dùng để định nghĩa 1 nhãn (label)
 VD:
 char Debounce(void)
 {
short Cnt;
unsigned char LastData;

Start: Cnt=0; /* number of times Port C is the same */


LastData=PORTC;
Loop: if(++Cnt==100) goto Done;
/* same thing 100 times */
if(LastData!=PORTC) goto Start;/* changed */
goto Loop;
Done: return(LastData);
}
Dấu phẩy (Commas)

 Dùng để ngăn cách các phần tử.


 VD:
 unsigned short beginTime, endTime, elapsedTime;
 short add(short x, short y) ;
Dấu nháy (Apostrophes)

 Dùng để xác định ký tự


 VD:
 mych='a' ;
Dấu nháy kép (Quotation marks )

 Dùng để xác định chuỗi (string)


 VD:
unsigned char Name[] = “embedded";
Dấu ngoặc nhọn (braces)

 Dùng để bắt đầu và kết thúc một khối câu lệnh


 VD:
 For (i=0;i<100;i++)
{
delay(100);
PORTB = 0xff;
delay(100);
PORTB = 0x00;
}
Dấu ngoặc vuông (Brackets )

 Dùng để chỉ kích thước của mảng


(array) và chỉ số
 VD:
short fifo[100];
I = fifo[0];
Dấu ngoặc tròn (Parentheses )

 Bao quanh danh sách tham số


 VD:
add(x,y);
Xác định mức độ ưu tiên thực thi của
các biểu thức
VD:
X = (17+3)/2 ;
Biến tĩnh (Static)

 Biến tĩnh là biến mà giá trị của nó được


giữ trong suốt quá trình chương trình
chạy, nhưng chỉ truy cập được bên trong
chương trình mà nó được định nghĩa
Biến tĩnh
 char sumIt(void)
 {
 static char sum = 0;
 sum = sum + 1;
 return sum;
 }
 void main(void)
 {
 char i;
 char result;
 for(i=0;i<10;i++) result = sumIt();
 }
Từ khóa volatile

 Từ khóa volatile mô tả 1 biến mà giá trị


có thể thay đổi không đoán trước được.
 Biến volatile được dùng để mô tả:
 Các ngoại vi được thiết kế theo kiểu
memory-mapped
 Biến toàn cục mà bị thay đổi giá trị trong
trình phục vụ ngắt
 Biến toàn cục được truy cập bởi nhiều tác
vụ trong các ứng dụng đa tác vụ
Từ khóa volatile
 void main(void)
 {
 unsigned char xdata *p = (char xdata *) 0x8000;
 while (*p == 0);
 }

 void main(void)
 {
 volatile unsigned char xdata *p = (char xdata *) 0x8000;
 while (*p == 0);
 }
Từ khóa extern

 Dùng để chỉ biến được định nghĩa trong


1 module khác.
 VD:
 Trong module LCD.h, khai báo biến
 char LCD_value;
 Trong module main.h
 extern char LCD_value;
Biến được khởi tạo trước

 short Temperature = -55;


 const unsigned short Steps[4] = {10, 9,
6, 5};
 char Name[4] = "Jon";
 char Name[6] = "Jon";
 char Name[] = "Jon";
 char *NamePt = "Jon";
Con trỏ (pointer)

 Con trỏ là 1 biến chứa một địa chỉ


 Giá trị của con trỏ có thể thay đổi được
 Question:
 Khai báo biến a: int a;
 Địa chỉ của biến a: &a có phải là con trỏ hay
không?
Con trỏ

 int *p;
 p = 0x8000;
 int *p = (int *)0x8000;
 int k;
 p = &k;
 #define SW *(unsigned char volatile *)(0x2000)
Phép toán với con trỏ

 Phép cộng:
 Con trỏ luôn chỉ vào địa chỉ đầu của một đối
tượng (object). Cộng 1 vào con trỏ làm nó
chỉ đến đối tượng tiếp theo.
 Phép so sánh:
 Khi so sánh 2 con trỏ, giá trị chúng đang
mang được coi như số không dấu
int *p; p
0x01 0x2000

0x00 0x2001
int *k;
k 0x02 0x2002
p = 0x2000; 0x00 0x2003

*p = 1;
k = p+1;
*k = *p+1;
Mảng và chuỗi (array and string)

 Mảng là tập hợp các biến giống nhau có cùng


tên gọi.
 Các phần tử của mảng được xác định bằng
chỉ số (bắt đầu từ 0).
 Kích thước của mảng là cố định.
 VD:
 int a[4] = {1,2,3,4};
 int b = a[0];
Mảng và chuỗi (array and string)

 Chuỗi tương tự mảng, ngoại trừ:


 Chuỗi có thể có số lượng phần tử thay
đôỉ.
 Các phần tử của chuỗi là ký tự ASCII kết
thúc bằng giá trị 0.
 Chuỗi được khai báo như 1 con trỏ kiểu
char
 char * mystring = “embedded”;
Kiểu cấu trúc (structure)

 Một structure là tập hợp của nhiều biến. Các


biến trong struct có thể khác kiểu nhau.

 struct theport
 {
int mode; // 0 for I/O, 1 for in only -1 for out only
unsigned char volatile *addr; // pointer to its address
unsigned char volatile *ddr; // pointer to its direction reg
 };
 struct theport PortA, PortB, PortC;
Structure
 struct theport
 {
int mode ; // 0 for I/O, 1 for in only -1 for out only

 unsigned char volatile *addr ; // pointer to its address



 unsigned char volatile *ddr ; // pointer to its direction
//reg
 } PortA, PortB, PortC;
 struct theport
 {
int mode; // 0 for I/O, 1 for in only -1 for out only
unsigned char volatile *addr; // pointer to its address
unsigned char volatile *ddr; // pointer to its direction
reg
 };
 typedef struct theport port;
 port PortA, PortB, PortC;
Struct
 typedef struct
 {
int mode ; // 0 for I/O, 1 for in only -1 for out only
unsigned char volatile *addr ; // pointer to its address
unsigned char volatile *ddr ; // pointer to its direction
//reg
 } port;
 port PortA, PortB, PortC;
Truy cập phần tử con của struct

 PortC.mode=0;
 PortC.addr=(unsigned char volatile *)(0x1003);
PortC.ddr=(unsigned char volatile *)(0x1007);
(*PortC.ddr)=0;
 (*PortB.addr)=(*PortC.addr);
Truy cập struct thông qua pointer

 port PORTA;
 port *p;
 p = &PORTA;
 p->mode=0; (dùng dấu -> để truy cập phần
tử con của 1 con trỏ kiểu struct)
Khởi tạo struct

 port PortE={1,
(unsigned char volatile *)(0x100A),
(unsigned char volatile *)(0)};
Kiểu Union

 Kiểu Union là kiểu trong C cho phép


chứa nhiều kiểu biến tại cùng một địa chỉ
 union [union tag]
{ member definition;
member definition;
... member definition;
} [one or more union variables];

union Data
{ int i; float f; char str[20]; } data;
Union Example
#include <stdio.h>
#include <string.h>
union Data { int i; float f; char str[20]; };
int main( )
{ union Data data;
printf( "Memory size occupied by data :
%d\n", sizeof(data));
return 0;
}
Union Example
#include <stdio.h>
#include <string.h>
union Data { int i; float f; char str[20]; };
int main( )
{ union Data data;
data.i = 10;
data.f = 220.5;
strcpy( data.str, "C Programming");
printf( "data.i : %d\n", data.i);
printf( "data.f : %f\n", data.f);
printf( "data.str : %s\n", data.str);
return 0;
}
Write a C program to extract
individual bytes from a float
variable and write them to address
2000H to 2003H
Function (Hàm, chương trình con)

 Một chương trình lớn thường được chia


thành nhiều khối (module)
 Module là 1 tác vụ nhận dữ liệu vào
(input), xử lý và xuất ra kết quả (output).
 Các module được tạo ra như là các hàm
(function).
Function

Một module (Nguồn: EmbeddedProg/Developing Embedded Software in C)


int FtoC(int TempF){
int TempC;
TempC=(5*(TempF-32))/9; // conversion
return TempC;}

Note:
Hạn chế truy cập đến biến toàn cục và I/O trong 1 function
Mô tả hàm (function declaration)
 Mô tả hàm cho ta biết tên hàm, kiểu của các
tham số và kiểu kết quả trả về.
 // declaration input output
void Ritual(void); // none none
char InChar(void); // none 8-bit
void OutChar(char letter); // 8-bit none
short InSDec(void); // none 16-bit
void OutSDec(short i); // 16-bit none
char Max(char in1,char in2); // two 8-bit 8-bit
int EMax(int in1,int in2); // two 16-bit 16-bit
void OutString(char* mystring); // pointer to 8-bit none
char *alloc(int size); // 16-bit pointer to
8-bit
int Exec(void(*fnctPt)(void)); // function pointer 16-bit
Định nghĩa hàm (function definition)

 Một định nghĩa của hàm là cách mà hàm


đó thực thi.
 type Name(parameter list){
CompoundStatement
};

int FtoC(int TempF)


{
int TempC;
TempC=(5*(TempF-32))/9; // conversion
return TempC;
}
Mô tả hàm

 Một module thường bao gồm 2 file:


 Header file (dùng chứa các mô tả hàm).
 Source file (dùng chứa các định nghĩa
hàm)
Extern function

 Khi ta cần khai báo một hàm được định


nghĩa ở một module khác, ta dùng từ
khóa extern
extern void InitSCI(void);
extern char InChar(void);
extern void OutChar(char character);
Truyền tham số (Arguments
passing)
 Có hai phương pháp truyền tham số cho
chương trình con:
 Truyền tham chiếu (call by reference)
 Truyền giá trị (call by value)
Truyền tham chiếu (call by
reference)
 Tham chiếu (con trỏ) đến tham số được đưa
vào chương trình con.
 Các tính toán trong chương trình con sẽ ảnh
hưởng đến biến được được truyền vào.
 int increment(int *num)
 {
 *num=*num+1;

 return *num;

 }
 Void main(void)
 {
 int number = 1;
 int temp;
 temp = increment(& number );
 }
Truyền giá trị (call by value)
 Giá trị của biến sẽ được sao chép và truyền
vào chương trình con.
 Các phép tính trên tham số trong chương trình
con không ảnh hưởng biến ban đầu.
 int increment(int num)
 {
 num++;
 return num;
 }
 Void main(void)
 {
 int number = 1;
 int temp;
 temp = increment(number );
 }
Struct làm tham số của chương
trình con
 struct theport
 {
int mode; // 0 for I/O, 1 for in only -1 for out only
unsigned char volatile *addr; // pointer to its address
unsigned char volatile *ddr; // pointer to its direction reg
 };
 typedef struct theport port;

 unsigned char Input(port thePort)


 {
return (thePort.addr);
 }

 unsigned char InputP(port *thePort)


 {
return (thePort->addr);
 }
 Function nào là tốt hơn?
Bài tập

 Viết hàm int strLen(char *str) tính số


phần tử của chuỗi
 Viết hàm int strcopy(char *dest, char
*src) chép nội dung của chuỗi src vào
chuỗi dest
 Viết hàm int findPos(char *child, char
*parent) trả về vị trí đầu tiên xuất hiện
chuỗi child trong chuỗi parent. Nếu
không có trả về -1.
Con trỏ hàm (function pointer)
 Con trỏ hàm là con trỏ chỉ đến 1 hàm.

 int (*fp)(int); // pointer to a function with input and output



int fun1(int input)
 {
return(input+1); // this adds 1
};
int fun2(int input)
 {
return(input+2); // this adds 2
};
void Setp(void)
 {
 int data;
fp=&fun1; // fp points to fun1
data=(*fp)(5); // data=fun1(5);
fp=&fun2; // fp points to fun2
data=(*fp)(5); // data=fun2(5);
};
 Question:
 Giải thích sự khác nhau giữa:
 int (*fp)(int);
 int *fp(int);
Con trỏ hàm là tham số của 1 hàm
khác
 int fun1(int input){
return(input+1); // this adds 1
};

 int fun2(int input){


return(input+2); // this adds 2
};

 int execute(int (*fp)(int))


 {
 int data;
data=(*fp)(5); // data=fun1(5);
return (data);
};

 void main(void)
 { int result;
result=execute(&fun1); // result=fun1(5);
result=execute(&fun2); // result=fun2(5);
};
Hàm callback

 Hàm callback là hàm được gọi khi có 1


sự kiện xảy ra.

MyButton

void create_button( int x, int y, const char *text, function callback_func );

ButtonClickedEvent callback_func
MyButton

click
Ví dụ về hàm callback
void cbfunc()
{
printf("called");
}
int main () {
/* function pointer */
void (*callback)(void);
/* point to your callback function */
callback=(void *)cbfunc;
/* perform callback */
callback();
return 0;
}
Truyền tham số cho hàm callback
 typedef struct _myst
 {
 int a; char b[10];
 }myst;
 void cbfunc(myst *mt)
 {
 fprintf(stdout,"called %d %s.",mt->a,mt->b);
 }
 int main()
 { /* func pointer */
 void (*callback)(void *);
 //param
 myst m; m.a=10; strcpy(m.b,"123");
 /* point to callback function */
 callback = (void*)cbfunc;
 /* perform callback and pass in the param */
 callback(&m);
 return 0;
 }
Chỉ dẫn tiền biên dịch
(Preprocessor Directives )
 #define size 100
 int data[size];
 #define LCD *(unsigned char *)0x2000
Chỉ dẫn tiền biên dịch
(Preprocessor Directives )
 #ifdef A
…
 #endif
 #ifndef B
…
 #endif
Chỉ dẫn tiền biên dịch
(Preprocessor Directives )
 #define Debug 1
#define LCD *(unsigned char *)0x2000
 void LCD_write(char data)
 {
#ifdef Debug
printf(“entering LCD_write”);
#endif

 LCD = data;

 #ifdef Debug
printf(“exitting LCD_write”);
#endif
 return;
 }
Debug macro

 #ifdef PRGDEBUG
 #define DBG(x) printf(x)
 #else
 #define DBG(x) /* nothing */
 #endif
Chỉ dẫn tiền biên dịch
(Preprocessor Directives )
 #include "Filename"
 #include <Filename>
Recursion (Đệ qui)
Be careful to define an
exit condition
Circular buffer
Head is equal to tail -> the buffer is empty
(Head + 1) is equal to tail -> the buffer is full

Write in: is_buffer_full?


Readout: is_buffer_empty?
Circular buffer
int circBufPush(circBuf_t *c, uint8_t data)

int circBufPop(circBuf_t *c, uint8_t *data)


Circular buffer
Circular buffer

You might also like