Tóm tắt về C cho vi điều khiển
1
Bài tập về nhà
2
Chương trình C đầu tiên
#include <reg51.h>
void main(void)
{
for (;;)
{
P1=0x55;
P1=0xAA;
}
}
3
#include <reg51.h>
void main(void)
{
while(1)
{
P1=0x55;
P1=0xAA;
}
}
Ví dụ lệnh sử dụng bit
#include <reg51.h>
void main(void)
{
unsigned char z;
z=P1;
z=z&0x3;
4
Chuyển đổi Hex - ASCII
#include <reg51.h>
void main(void)
{
unsigned char x,y,z;
unsigned char
mybyte=0x29;
x=mybyte&0x0F;
P1=x|0x30;
y=mybyte&0xF0;
y=y>>4;
P2=y|0x30;
}
5
#include <reg51.h>
void main(void)
{
unsigned char bcdbyte;
unsigned char w=‘4’;
unsigned char z=‘7’;
w=w&0x0F;
w=w<<4;
z=z&0x0F;
bcdbyte=w|z;
}
Ví dụ sử dụng với ngắt Timer
#include <reg51.h>
sbit SW =P1^7;
sbit IND =P1^0;
sbit WAVE =P2^5;
void timer0(void) interrupt 1 {
WAVE=~WAVE; //toggle pin
}
void main() {
SW=1; //make switch input
TMOD=0x02;
TH0=0xA4; //TH0=-92
IE=0x82; //enable interrupt for timer 0
while (1) {
IND=SW; //send switch to LED
}
}
6
Ví dụ tổng hợp về ngắt
#include <reg51.h>
sbit WAVE =P0^1;
void timer0() interrupt 1 {
WAVE=~WAVE; //toggle pin
}
void serial0() interrupt 4 {
if (TI==1) {
TI=0; //clear interrupt
}
else {
P0=SBUF; //put value on pins
RI=0; //clear interrupt
}
}
7
void main() {
unsigned char x;
P1=0xFF; //make P1 an input
TMOD=0x22;
TH1=0xF6; //4800 baud rate
SCON=0x50;
TH0=0xA4; //5 kHz has =200us
IE=0x92; //enable interrupts
TR1=1; //start timer 1
TR0=1; //start timer 0
while (1) {
x=P1; //read value from pins
SBUF=x; //put value in buffer
P2=x; //write value to pins
}
}
Kiểu dữ liệu
C có ba kiểu chính: characters, integers and
floating-point.
Mỗi kiểu khác nhau thi có giá trị sử dụng
khác nhau và thao tác có thể thực hiện trên
chúng
Mỗi kiểu có độ chính xác khác nhau và giới
hạn sử dụng min max
Kiểu mở rộng: long, double, void
Character Constants
Là các số nguyên biểu diễn kỹ tự theo bảng
ASCII.
Ví dụ ‘R’ có giá trị 52 hoặc 064 or 0x34
Các giá trị ASCII có thể định nghĩa cho các
ký tự không thể gõ được từ bàn phím
\n
new line
\t
tab
Lệnh
Cấu trúc for
for (init; test; action)
statement;
Tương tự như lệnh while
init;
while (test)
{
statement;
action;
}
Pointers
Định nghĩa: Con trỏ là một biết dùng để
chứa địa chỉ trong bộ nhớ của biến đấy
Khai báo * nghĩa là “trỏ tới”.
Khai báo & nghĩa là “địa chỉ của ”.
Lấy nội dung thông qua *.
Truyền tham chiếu
Thay vi đưa vào theo giá trị, người ta đưa vào theo con
trỏ. Giá trị đầu vào sẽ được copy những vẫn trỏ đến cùng
ô nhớ ban đầu
swap(&a, &b); /* Pass pointers to a and b */
void swap(int* px, int* py)
/*px and py are copies of the pointer arguments*/
{
int tmp = *px;
*px = *py;
*py = tmp;
}
Ví dụ: strcpy()
Thường dùng con trỏ như sau.
void strcpy (char *s, char *t)
{
while (*s++ = *t++)
;
}
Con trỏ và giá trị hàm
Hàm có thể trả về con trỏ.
int* func_returns_pointer(void);
Tuy nhiên sẽ là lỗi nếu trả về con trỏ của
biến cục bộ.
int* misguided(void)
{
int array[10], i;
for (i = 0; i < 10; ++i)
array[i] = i;
return array;
}
Mảng (array)
Mảng là tập hợp xác định các phần tử có cùng
kiểu
double empty[0]; /* Error: cannot be empty */
int an_array[10]; /* OK, allocate for 10 ints. */
a = an_array[0]; /* first element */
b = an_array[9]; /* last element */
c = an_array[10]; /* Error: but will compile */
Người lập trình phải tự quản lý giới hạn của
mảng.
Lệnh include
Xác định các khai báo của các hàm và các
biến.
#include <standard.h>
#include “myheader.h”
File #include sẽ chèn toàn bộ đoạn mã mà nó
được gọi đến vào phần mềm
Macros
Lệnh #define thường được sử dụng trong việc tạo ra các
macro
Khai báo sau
#define MAX(x,y) ((x)>(y) ? (x) : (y))
Macro giống như hàm, nhưng thực chất không phải hàm.
Thực tế chương trình dịch sẽ thay thế mọi khai báo MAX
bằng dòng lệnh tương ứng các đối số đưa vào (inline)
int a=4, b= -7, c;
c = MAX(a,b);
expands to:
c = ((a)>(b) ? (a) : (b));
Các Macros đơn giản
#define SQR(x)
((x)*(x))
#define SGN(x)
(((x)<0) ? -1 : 1)
#define ABS(x)
(((x)<0) ? -(x) : (x))
#define ISDIGIT(x)
((x) >= '0' && (x) <= '9')
#define NELEMS(array)
sizeof(array[0]))
(sizeof(array) /
#define CLAMP(val,low,high) \
((val)<(low) ? (low) : (val) > (high) ? (high) :
(val))
#define ROUND(val) \
((val)>0 ? (int)((val)+0.5) : -(int)(0.5-(val)))
Ví dụ
#define TIMELOOP(CODE) { \
t0 = clock(); \
for (i = 0; i
printf("%7d ", clock() - t0); \
}
Sử dụng như sau:
TIMELOOP(y = sin(x));
19
Dịch có điều kiện
Các lệnh dịch có điều kiện trong C:
#if, #elif, #else, #endif
#ifdef, #ifndef
Mục đích:
Thêm vào các đoạn gỡ lỗi chương trình
Thêm vào các đoạn không phãi mã chuẩn,
Bảo vệ các header-files sử dụng nhiều lần gọi.
Typedefs
A typedef cũng có cùng ý nghĩa như #define, tức là
thuần tùy thực hiện việc thay thế văn bản,
nhưng typedef là từ khóa của C, và được dịch bởi
chương trình dịch.
Từ khóa typedef cho phép tạo ra kiểu dữ liệu mới
với tên mới
typedef int Length;
Length len, maxlen;
Length lengths[50];
Toán tử làm việc với bit
C cung cấp 6 toán tử bit:
&|
^
~
<<
>>
Các toán tử này chỉ làm việc với các kiểu char,
short, int, long.
Không dùng cho dấu phẩy động.
Và 5 phép gán bit như sau
&=
|=
^=
<<= >>=
Phép gán này tương tự với phép gán số học
z &= x | y;
z = z & (x | y);
Mặt nạ bit
Bước 1. Tạo ra số nguyên để đại diện cho từng
trạng thái của bit (hoặt nhóm bit). Ví dụ
enum {
FIRST
SECND
THIRD
FORTH
ALL =
};
23
= 0x01,
= 0x02,
= 0x04,
= 0x08,
0x0f
/*
/*
/*
/*
/*
0001
0010
0100
1000
1111
binary
binary
binary
binary
binary
*/
*/
*/
*/
*/
Mặt nạ bit
Một cách khác
enum {
FIRST
SECND
THIRD
FORTH
ALL =
};
= 1 << 0,
= 1 << 1,
= 1 << 2,
= 1 << 3,
~(~0 << 4)
Dòng cuối cùng thường dùng để bật tắt một nhóm bit
1111 1111 /* ~0 */
1111 0000 /* ~0 << 4 */
0000 1111 /* ~(~0 << 4) */
24
Thao tác với mặt nạ bit
unsigned flags = 0;
flags |= SECND | THIRD | FORTH;
flags &= ~(FIRST | THIRD);
flags ^= (THIRD | FORTH);
/* (1110). */
/* (1010). */
/* (1100). */
if ((flags & (FIRST | FORTH)) == 0)
flags &= ~ALL;
/* (0000). */
Keys:
1. Toán tử| dùng để tổ hợp các mặt nạ, toán tử ~ dùng
25
2.
3.
4.
5.
để đảo dấu tất cả các bit (mọi bit là 1 trừ những bit được
che mặt nạ).
|= dùng để set bits.
&= dùng để reset bits.
^= dùng để đảo dấu bits.
& dùng để chọn bits (cho việc kiểm tra trạng thái).