Professional Documents
Culture Documents
Vi Điều Khiển AVR Full
Vi Điều Khiển AVR Full
BÀI 1
VI ĐIỀU KHIỂN ATMEGA16
1.GIỚI THIỆU SƠ QUA
-Bộ nhớ Flash: 16 Kbtye
-Bộ nhớ RAM: 2 Kbyte
-Bộ nhớ EEPROM: 512 Byte
-Tốc độ dao động: 0 → 16Mhz
-Điện áp nguồn nuôi: 4.5V → 5.5V
2.SƠ ĐỒ CHÂN
*Sơ đồ chân như hình vẽ
-Để ATmega16 hoạt động được thì ta cần nối một số chân đặc biệt sau
+GND (chân 11 và chân 31): Nối GND của nguồn cấp
+VCC (chân 10): Nối với VCC của nguồn cấp
+AVCC (chân 30): Nối VCC của nguồn cấp.Đây là chân cấp nguồn cho
Modul ADC nội tích hợp trong vi điều khiển
+AREF (chân 32): Nối tụ gốm 100pF để lọc nhiễu,trong trường hợp
dùng
chân này để cấp điện áp tham chiếu cho Modul ADC
nội
thì sẽ nối chân này với nguồn điện áp tham chiếu.
1
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
+RESET (chân 9): Nối với mạch reset
+XTAL1,XTAL2 (chân 12 và chân 13): Nối với bộ dao động thạch anh
ngoài.Trong trường hợp dùng thạch anh nội thì có thể để trống 2 chân
này.
2
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
3
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
3.CÁC CHÂN IO
-ATmega16 có tổng cộng 40 chân trong đó có 32 chân IO.Các chân IO đó
nằm trên 4 cổng A,B,C,D.Mỗi cổng có 8 chân.
-Các cổng IO có các thanh ghi điều hướng tương ứng là:
DDRA,DDRB,DDRC,DDRD.
-Để thiết lập cổng là đầu ra Output thì các bit tương ứng trong thanh ghi
DDR của cổng đó phải được thiết lập ở mức logic 1.Khi cổng là Output
thì chúng ta truy cập cổng bằng thanh ghi PORT.
-Để thiết lập cổng là đầu ra Input thì các bit tương ứng trong thanh ghi
DDR của cổng đó phải được thiết lập ở mức logic 0.Khi cổng là Input thì
chúng ta truy cập cổng bằng thanh ghi PIN.
-Khi lập trình trên phần mềm CodeVisionAVR thì chúng ta có thể truy
cập các cổng này ở cả chế độ byte và cả ở chế độ bit.
-Từ đó chúng ta có thể thiết lập chế độ IO cho các cổng như sau
DDRX.i=0 => Chân có trọng số bit thứ i của cổng X là đầu vào Input
Lúc này ta xử lý cổng bằng PINX.i
DDRX.i=1 => Chân có trọng số bit thứ i của cổng X là đầu ra Output
Lúc này ta xử lý cổng bằng PORTX.i
+Trong đó i là 1 trong các giá trị từ 0 đến 7
+X là các ký tự A,B,C hoặc D
*Ví dụ
-Thiết lập cổng A là đầu ra,chân thứ 4 của cổng B là đầu vào chúng ta
làm như sau.
DDRA=0xff; (Tất cả các chân cổng A là đầu ra)
DDRB.3=0; (chân số 4 của cổng B là đầu vào)
-Bên trong các cổng của ATmega16 có tích hợp điện trở băng nội.các
điện trở băng nội này hay dùng khi cổng ở chế độ Input.Khi cổng là Input
chúng ta có thể kích hoạt điện trở băng nội của cổng đó bằng cách cho
các chân PORTX.i của cổng đó tương ứng lên mức logic 1.
-Ví dụ
DDRB.0=0;PORTB.0=1; (chân B0 là Input và được kích hoạt điện trở
băng nội).
*Cách thức truy cập IO
-Truy cập dạng byte (truy cập trên toàn bộ thanh ghi)
DDRA=0xff;//truy cập trên tất cả 8 bit trên thanh ghi DDRA
PORTA=0x80;//truy cập trên toàn bộ PORTA
if(PINA==0xff) //thanh ghi đầu vào của cổng A
-Truy cập trên từng bit,từng chân IO
DDRA.0=1;//chỉ khởi tạo 1 mình bit DDRA.0=1
PORTA.0=1;//chỉ truy cập đến chân A0
PORTA.1=1;//chỉ truy cập đến chân A1
PORTA.2=0;//chỉ truy cập đến chân A2
PORTB.0=0;//chỉ truy cập đến chân B0
4
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
BÀI 2
CHUYỂN ĐỔI CƠ SỐ
-Có 3 hệ cơ số sử dụng phổ biến nhất trong lập trình là cơ số 2,cơ số 10
và cơ số 16.
-Trong C thường dùng các ký hiệu sau để đặc trưng cho hệ cơ số
0x là ký hiệu của hệ hexa (Cơ số 16)
0b là ký hiệu của hệ nhị phân (Cơ số 2)
hệ thập phân thì không có ký hiệu chỉ viết số (Cơ số 10)
-Các hệ cơ số khác ít dùng nên không cần quan tâm
1.CHUYỂN ĐỔI GIỮA HỆ THẬP PHÂN VÀ NHỊ PHÂN
*Chuyển từ thập phân sang nhị phân
-Ta lấy số thập phân chia liên tiếp cho 2 sau đó kết quả sẽ là các phần
dư,vị trí đầu tiên lấy từ phần cuối cùng của phép chia đảo ngược về.
-Ví dụ 1: Chuyển đổi số thập phân 112 sang hệ nhị phân
unsigned char x=112;
=> x=112= 0b01110000
5
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
6
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
-Ta lấy số thập phân chia cho 16,sau đó lấy các phần nguyên của phép
chia tiếp tục chia cho 16,kết quả sẽ là các phần dư của phép chia.Vị trí bắt
đầu lấy là phần dư cuối cùng của phép chia ngược về.
-Ví dụ 1: Chuyển đổi số thập phân x sang hệ hexa
unsigned int x=4589;
=> x= 4589 = 0x11ed (A=10,B=11,C=12,D=13,E=14,F=15)
7
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
-Trong trường hợp số nhị phân không đủ 4 bit thì ta bù vào các bit 0 vào
phía trước để đủ 4 bit rồi nhóm lại.
-Bảng chuyển đổi qua lại giữa nhị phân và hexa như sau.
-Ví dụ 1: Chuyển đổi số hexa 0xf4 sang hệ nhị phân tương ứng
=> y=0xf4=0b11110100
Vì dựa vào bảng ta thấy f=0b1111 và 4=0b0100
-Ví dụ 2: Chuyển đổi số nhị phân 0b11011100 sang hệ hexa tương ứng
=> y=0b11011100=0xdc
Vì 0b1101=d và 0b1100=c
BÀI 3
LED ĐƠN
1.CÁC LOẠI LED ĐƠN THƯỜNG DÙNG
*Có nhiều cách để phân loại và gọi tên led đơn,sau đây là một số led
đơn sử dụng phổ biến trong cuộc sống.
-Led đơn 3mm có đường kính 3mm
8
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
-Led đơn 5mm có đường kính 5mm
-Led đơn 3mm,led đơn 5mm,…
-Led đơn màu đỏ,màu xanh,màu vàng,màu trắng,…
-Led đơn sáng đục,led đơn siêu sang,led đơn sáng trong
*Ý nghĩa và ứng dụng của led đơn
-Dùng để hiển thị
-Làm đèn báo sự cố
-Dùng để thắp sáng
-Dùng nhiều trong ngành quảng cáo led
2.CÁCH PHÂN CỰC CHO LED ĐƠN
*Có 2 cách phân cực phổ biến hay dùng với led đơn
-Cách 1: Các led nối chung chân âm.
+Ở trường hợp này các led tích cực ở mức cao
Khi chân điều khiển ở mức cao thì led sáng
Khi chân điều khiển ở mức thấp thì led tắt
Vì thế mà người ta gọi là đấu led tích cực ở mức cao
9
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
10
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
4.VÍ DỤ
*Ví dụ 1: Điều khiển 8 led đơn nối PORTC
-Sáng chạy
-Sáng dần
-Sáng dồn
-Sáng giữa ra 2 bên
-Sáng từ 2 bên vào giữa
#include <mega16.h>
#include <delay.h>
void sangchay(signed char n)
{
signed char i;
PORTC=0x00;
delay_ms(400);
for(i=0;i<n;i++)
{
PORTC=(1<<i);
delay_ms(400);
}
}
void sangdan(signed char n)
{
signed char i;
PORTC=0x00;
delay_ms(400);
11
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
for(i=0;i<n;i++)
{
PORTC=PORTC|(1<<i);
delay_ms(400);
}
}
void sangdon(signed char n)
{
signed char i,j;
unsigned char p,q;
PORTC=0x00;
delay_ms(400);
p=0;q=0;
for(i=n-1;i>=0;i--)
{
for(j=0;j<=i;j++)
{
p=q|(1<<j);
PORTC=p;
delay_ms(400);
}
q=q|(1<<i);
}
}
void sanggiuara(signed char n)
{
signed char i;
PORTC=0x00;
delay_ms(400);
for(i=0;i<=n/2;i++)
{
PORTC=(0x10<<i)|(0x08>>i);
delay_ms(400);
}
}
void sangngoaivao(signed char n)
{
signed char i;
PORTC=0x00;
delay_ms(400);
for(i=0;i<=n/2;i++)
{
PORTC=(0x80>>i)|(0x01<<i);
12
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
delay_ms(400);
}
}
void main(void)
{
DDRC=0xff;
while(1)
{
sangchay(8);
sangdan(8);
sangdon(8);
sanggiuara(8);
sangngoaivao(8);
}
}
BÀI 4
IC GHI DỊCH 74HC595
1.SƠ ĐỒ CHÂN
13
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
14
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
15
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
-Chân Q7’: Nếu dùng nhiều IC74HC595 thì chân Q7’ này dùng để nối
vào
chân DS của con 74HC595 tiếp theo nó.
3.VÍ DỤ
*Ví dụ 1: Điều khiển 8 led đơn nối IC74HC595
-Sáng chạy
-Sáng dần
-Sáng dồn
-Sáng giữa ra 2 bên
-Sáng từ 2 bên vào giữa
#include <mega16.h>
#include <delay.h>
#define ck PORTC.0
#define da PORTC.1
#define cp PORTC.2
void dich8bit(unsigned char n)
{
signed char i;
unsigned char x;
for(i=0;i<8;i++)
{
x=(n<<i)&0x80;
if(x==0) da=0;
else da=1;
ck=0;ck=1;//dua data tu chan da vao bo dem
}
cp=0;cp=1;//xuat data tu bo dem ra cac dau ra Q
}
void sangchay(signed char n)
{
signed char i;
unsigned char p;
dich8bit(0x00);
delay_ms(400);
for(i=0;i<n;i++)
{
p=(1<<i);
dich8bit(p);
delay_ms(400);
}
}
void sangdan(signed char n)
{
16
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
signed char i;
unsigned char p;
dich8bit(0x00);
delay_ms(400);
p=0;
for(i=0;i<n;i++)
{
p=p|(1<<i);
dich8bit(p);
delay_ms(400);
}
}
void sangdon(signed char n)
{
signed char i,j;
unsigned char p,q;
dich8bit(0x00);
delay_ms(400);
p=0;q=0;
for(i=n-1;i>=0;i--)
{
for(j=0;j<=i;j++)
{
p=q|(1<<j);
dich8bit(p);
delay_ms(400);
}
q=q|(1<<i);
}
}
void sanggiuara(signed char n)
{
signed char i;
unsigned char p;
dich8bit(0x00);
delay_ms(400);
for(i=0;i<=n/2;i++)
{
p=(0x10<<i)|(0x08>>i);
dich8bit(p);
delay_ms(400);
}
}
17
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
void sangngoaivao(signed char n)
{
signed char i;
unsigned char p;
dich8bit(0x00);
delay_ms(400);
for(i=0;i<=n/2;i++)
{
p=(0x80>>i)|(0x01<<i);
dich8bit(p);
delay_ms(400);
}
}
void main(void)
{
DDRC=0xff;
while(1)
{
sangchay(8);
sangdan(8);
sangdon(8);
sanggiuara(8);
sangngoaivao(8);
}
}
18
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
BÀI 5
LED 7 ĐOẠN,LED 7 THANH
1.CẤU TẠO CỦA LED 7 ĐOẠN
-Led 7 đoạn có nhiều loại,nhưng loại mà chúng ta thường dùng là loại
được tạo thành bởi 7 thanh led đơn và 1 dấu chấm dp ở góc phải phí
dưới.Nên người ta gọi là led 7 đoạn hay còn gọi là led 7 thanh tùy từng
người.
-Led 7 đoạn thường có 2 loại nếu phân theo cách đấu led
+Loại A chung: Tất cả các thanh được nối chung chân dương
+Loại K chung: Tất cả các thanh được nối chung chân âm
2.CÁC TẠO MÃ LED 7 ĐOẠN
-Cách tạo bảng mã cho led 7 đoạn phụ thuộc vào đấu nối phần cứng (phụ
thuộc vào cách nối các thanh a,b,c,d,e,f,g,dp với các chân của vi điều
khiển).Sơ đồ đấu nối như thế nào thì ta phải tra mã led tương ứng với sơ
đồ đó.
19
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
-Chú ý: Dùng led A chung thì thanh nào sáng sẽ ở mức 0,thanh nào tắt sẽ
ở mức 1.Còn led K chung thì ngược lại.
-Nếu như sơ đồ kết nối như trên và led 7 đoạn đang dùng là loại A chung
(Chung dương) thì ta sẽ tạo được bảng mã led tương ứng với các số cần
hiển thị như sau.
-Ví dụ: Để hiển thị số 0 thì tất cả các thanh đều sáng chỉ mỗi thanh g và
thanh dp tắt.Vì thế mà a=0,b=0,c=0,d=0,e=0,f=0,g=1,dp=1.
20
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
7 1 1 1 1 1 0 0 0 0xf8
8 1 0 0 0 0 0 0 0 0x80
9 1 0 0 1 0 0 0 0 0x90
=> Muốn hiển thị số 5 trên led 7 đoạn ta chỉ cần đặt PORTC=0x92
-Tương tự ta có thể tự tạo các mã cho các ký tự A,B,C,…
-Đối với led K chung cách thức tạo mã cũng tương tự nhưng mức tích cực
sẽ thay đổi.
3.CÁCH TÍNH ĐIỆN TRỞ HẠN DÒNG CHO LED 7 ĐOẠN
-Led 7 đoạn có nhiều loại,loại 5V,loại 12V,…,tùy theo từng loại mà ta
đấu nối cho phù hợp.
-Giả sử ta dùng loại led 7 đoạn 5V và nguồn nuôi cho vi điều khiển AVR
cũng là 5V.Nếu ta xem mỗi thanh của led 7 đoạn giống như 1 led đơn thì
ta cũng áp dụng cách tính điện trở hạn dòng cho mỗi thanh tương tự như
tính toán trên led đơn.
-Từ đó ta có mỗi thanh sẽ nối trở R=220 ôm
4.VÍ DỤ
*Ví dụ 1: Viết chương trình đếm số từ 00 → 99 sử dụng led 7 đoạn A
chung (Chung dương) không quét led.
#include <mega16.h>
#include <delay.h>
21
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
unsigned char
maled[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
void num2s(unsigned char n)
{
PORTC=maled[n/10];//xuat ma led hang chuc ra PORTC
PORTD=maled[n%10];//xuat ma led hang don vi ra PORTD
}
void main(void)
{
unsigned char i;
DDRC=0xff;
DDRD=0xff;
PORTC=0xff;//tat led chuc
PORTD=0xff;//tat led don vi
while(1)
{
for(i=0;i<100;i++)
{
num2s(i);
delay_ms(400);
}
}
}
22
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
23
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
BÀI 6
TEXT LCD
1.SƠ ĐỒ CHÂN
24
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
25
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
-Tăng AC,dịch hiển thị sang trái: DB=0x07
*Các lệnh điều khiển hiển thị
-Bật hiển thị,bật con trỏ,nhấp nháy ký tự hiện tại: DB=0x0f
-Bật hiển thị,bật con trỏ,không nhấp nháy ký tự hiện tại: DB=0x0e
-Bật hiển thị,tắt con trỏ,nhấp nháy ký tự: DB=0x0d
-Bật hiển thị,tắt con trỏ,không nháy ký tự: DB=0x0c
*Các lệnh chức năng
-Mode 4 bit,2 dòng,ký tự=5x8 điểm ảnh: 0x28
-Mode 4 bit,2 dòng,ký tự=5x10 điểm ảnh: 0x2C
-Mode 8 bit,2 dòng,ký tự=5x8 điểm ảnh: 0x38
-Mode 8 bit,2 dòng,ký tự=5x10 điểm ảnh: 0x3C
*Địa chỉ dòng 3 và dòng 4 của LCD 16x4 và 20x4
Với LCD 16x4:
- Địa chỉ đầu dòng thứ 3 là 0x80 + 16 = 0x90
- Địa chỉ đầu dòng thứ 4 là 0xC0 + 16 = 0xD0
Với LCD 20x4:
- Địa chỉ đầu dòng thứ 3 là 0x80 + 20 = 0x94
- Địa chỉ đầu dòng thứ 4 là 0xC0 + 20 = 0xD4
3.VÍ DỤ
-Viết chương trình hiển thị dòng chữ VI DDIEU KHIEN ATmega16 trên
LCD 16x2.
#include <mega16.h>
#include <delay.h>
#define RS PORTC.5
#define RW PORTC.6
#define EN PORTC.7
#define LCD PORTD
void lenhlcd(unsigned char n)
{
RS=0;RW=0;
LCD=n;
EN=1;
EN=0;
delay_ms(10);
}
void datalcd(unsigned char n)
{
RS=1;RW=0;
LCD=n;
EN=1;
EN=0;
delay_ms(10);
}
26
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
void gotoxy(unsigned char x,unsigned char y)
{
unsigned char address;
address=0x80+64*(x-1)+(y-1);
lenhlcd(address);
}
void textlcd(unsigned char x,unsigned char y,unsigned char *s)
{
signed char i;
for(i=0;s[i]!=0;i++)
{
gotoxy(x,y+i);
datalcd(s[i]);
}
}
void lcd_init(void)
{
lenhlcd(0x38);
lenhlcd(0x06);
lenhlcd(0x0c);
delay_ms(400);
}
void main(void)
{
DDRC=0xff;
DDRD=0xff;
lcd_init();
lenhlcd(0x01);
textlcd(1,3,"VI DIEU KHIEN");
textlcd(2,5,"ATmega16");
while(1);
}
27
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
BÀI 7
LED MA TRẬN
1.CẤU TẠO LED MA TRẬN
*Ví dụ led matix 8x8
28
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
29
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
-Các hàng là chung dương hoặc chung âm,tương tự đối với cột cũng vậy
2.QUÉT LED MA TRẬN
Có 2 loại quét led ma trận phổ biến là quét theo hàng và quét theo cột
*Nguyên lý quét
-Quét theo cột tại 1 thời điểm chỉ có 1 cột được bật
-Quét theo hang tại 1 thời điểm chỉ có 1 hàng bật
-Để quét theo cột ta có thể làm như sau
+Tắt tất cả các cột (1)
+Xuất mã tương ứng của cột i ra các hàng (2)
+Bật cột i,tắt các cột còn lại (3)
+Tạo trễ vài trăm us → vài nghìn ms (4)
+Tắt cột i (5)
+Quay lại bước (1),tăng i và lặp lại
-Để quét theo hàng ta có thể làm như sau
+Tắt tất cả các hàng (1)
+Xuất mã tương ứng của hàng i ra các cột (2)
+Bật hàng i,tắt các hàng còn lại (3)
+Tạo trễ vài trăm us → vài nghìn ms (4)
+Tắt hàng i (5)
+Quay lại bước (1),tăng i và lặp lại
3.VÍ DỤ
30
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
*Ví dụ 1: Viết chương trình hiển thị chữ U trên led ma trận 8x8 green
#include <mega16.h>
#include <delay.h>
unsigned char text[8]={255,128,0,63,63,0,128,255};
void quetled(void)
{
signed char i;
for(i=0;i<8;i++)
{
PORTD=text[i];
PORTC=(0x80>>i);
delay_ms(4);
PORTC=0x00;
}
}
void main(void)
{
DDRC=0xff;PORTC=0xff;
DDRD=0xff;
while(1) quetled();
}
31
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
*Ví dụ 2: Viết chương trình đếm các số từ 0 → 4 dùng led ma trận 8x8
#include <mega16.h>
#include <delay.h>
unsigned char text[5][8]={
{255,129,0,60,60,0,129,255},//0
{255,63,61,0,0,63,63,255},//1
{255,124,60,28,12,32,49,255},//2
{255,36,36,36,36,0,129,255},//3
{255,195,193,204,207,0,0,255}//4
};
void quetled(unsigned char n)
{
signed char i;
for(i=0;i<8;i++)
{
PORTD=text[n][i];
PORTC=(0x80>>i);
delay_ms(4);
PORTC=0x00;
}
}
void main(void)
32
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
{
unsigned char i,j;
DDRC=0xff;PORTC=0xff;
DDRD=0xff;
while(1)
{
for(i=0;i<5;i++)
{
for(j=0;j<30;j++) quetled(i);
}
}
}
BÀI 8
NÚT NHẤN,PHÍM BẤM
*Nút bấm thường được dùng để chọn chế độ hoạt động,thiết lập các
thông số điều khiển khiển.Nút bấm được sử dụng khá rộng dãi trong các
sản phẩm điện tử.
*Ví dụ: Đồng hồ có nút bấm chỉnh thời gian,điện thoại có nút bấm số,…
1.PHÍM NHẤN,NÚT BẤM ĐƠN
33
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
34
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
*Cách kiểm kiểm tra nút bấm trong vi điều khiển AVR
-Để kiểm tra nút bấm ta phải thiết lập chân nối nút bấm là input,đối với
avr có điện trở băng nội tại chân đó thì ta không cần phải nối thêm điện
trở băng 10k bên ngoài.Trong trường hợp không có điện trở băng nội thì
ta phải nối thêm điện trở băng ngoại khoảng 10k.
-Khi kiểm tra nút ta dùng thanh ghi PIN để kiểm tra
-Ví dụ
DDRD.2=0;PORTD.2=1;//thiết lập chân D2 là input và kéo điện
trở băng nội
if(PIND.2==0) //kiểm tra nếu nhấn phím
{
d++;
if(d>10) d=0;
while(PIND.2==0);//chống nảy phím,rung phím,chờ nhả phím
}
2.MA TRẬN PHÍM BẤM
-Ma trận phím bấm là 1 bảng phím được tạo thành bởi nhiều nút bấm.
35
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
-Dùng ma trận phím bấm sẽ tiết kiệm được chân cho vi điều khiển
-Dưới đây là ma trận phím 8x8
36
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
{
DDRB=0x00;PORTB=0xff;
DDRD=0xff;PORTD=0x00;
while(1)
{
if(PINB.0==0)
{
PORTD.0=~PORTD.0;
while(PINB.0==0);
}
if(PINB.1==0)
{
PORTD.1=~PORTD.1;
while(PINB.1==0);
}
if(PINB.2==0)
{
PORTD.2=~PORTD.2;
while(PINB.2==0);
}
if(PINB.3==0)
{
PORTD.3=~PORTD.3;
while(PINB.3==0);
}
if(PINB.4==0)
{
PORTD.4=~PORTD.4;
while(PINB.4==0);
}
if(PINB.5==0)
{
PORTD.5=~PORTD.5;
while(PINB.5==0);
}
if(PINB.6==0)
{
PORTD.6=~PORTD.6;
while(PINB.6==0);
}
if(PINB.7==0)
{
PORTD.7=~PORTD.7;
37
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
while(PINB.7==0);
}
}
}
*Ví dụ 2
#include <mega16.h>
#include <delay.h>
unsigned char kt=0;
unsigned char
maled[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned char maphim[4]={247,251,253,254};
unsigned char quetphim(unsigned char n)
{
unsigned char i,j;
unsigned char phim=16;
for(i=0;i<4;i++)
{
PORTB=maphim[i];
for(j=0;j<n;j++)
{
if(PINB.4==0)
{
phim=4*i;
while(PINB.4==0);
38
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
}
if(PINB.5==0)
{
phim=4*i+1;
while(PINB.5==0);
}
if(PINB.6==0)
{
phim=4*i+2;
while(PINB.6==0);
}
if(PINB.7==0)
{
phim=4*i+3;
while(PINB.7==0);
}
}
}
return(phim);
}
void hienthi(unsigned char n)
{
unsigned char x,m[2];
signed char i,k;
x=n;
k=0;
do
{
m[k]=x%10;
x=x/10;
k++;
}
while(x);
for(i=0;i<k;i++)
{
PORTC=maled[m[i]];
PORTD=(0x02>>i);
delay_ms(4);
PORTD=0x00;
}
}
void main(void)
{
39
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
unsigned char p,q=16;
DDRB=0x0f;PORTB=0xff;
DDRC=0xff;
DDRD=0xff;
PORTD=0x00;
while(1)
{
p=quetphim(100);
if(p!=16)
{
q=p;
kt=1;
}
if(kt==1) hienthi(q);
}
}
BÀI 9
NGẮT
40
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
I.NGẮT
1.KHÁI NIỆM VỀ NGẮT
-Một sự kiện nào đó xảy ra gây ra sự gián đoạn một quá trình đang tiếp
diễn thì gọi là ngắt.
2.BẢNG VECTO NGẮT CỦA ATMEGA16
-Ví dụ: Xem trong bảng ta thấy chỉ số vectơ ngắt ngoài 1 là 3,chỉ số vectơ
ngắt của ngắt tràn timer1 là 9.
3.CẤU TRÚC CHƯƠNG TRÌNH NGẮT
*Chương trình ngắt là chương trình con phục vụ ngắt,trong
CodevisionAVR cấu trúc của chương trình ngắt được tổ chức như sau
interrupt[chỉ số vectơ ngắt] void tenctn(void)
{
//xử lý ngắt
}
41
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
-Ví dụ ngắt ngoài 1 có chỉ số vectơ ngắt là 3 do đó chương trình con xử lý
ngắt ngoài 1 có cấu trúc như sau:
interrupt[3] void ngoai1(void)
{
//xử lý ngắt ngoài 1
}
4.NGẮT TOÀN CỤC,NGẮT THÀNH PHẦN
-Các ngắt riêng biệt thì gọi là ngắt thành phần
-Ngắt toàn cục ngắt kiểm soát tất cả các ngắt thành phần
+Khi cấm ngắt toàn cục có nghĩa là cấm tất cả các ngắt thành phần
+Khi cho phép ngắt toàn cục thì ta được phép cho phép những ngắt thành
phần hoạt động nếu ta muốn.
-Ví dụ nếu ta xem mỗi lớp học của 1 trường học là ngắt thành phần và
trường học là ngắt toàn cục.Thì cánh cửa của mỗi lớp học sẽ là bit điều
khiển ngắt thành phần và cánh cửa trường học sẽ là bit điều khiển ngắt
toàn cục.Mọi người ở phòng 1 muốn ra khỏi trường thì cửa lớp của phòng
đó phải mở và cửa trường cũng phải mở.
-Trong CodevisionAVR cho nhúng 2 lệnh assembly để điều khiển ngắt
toàn cục.
#asm(“sei”); //Cho phép ngắt toàn cục (hình dung như mở cổng trường
học)
#asm(“cli”); //Cấm ngắt toàn cục (đóng cổng trường học)
5.CÁCH THIẾT LẬP NGẮT
-Thiết lập các bit chọn tác nhân gây ra ngắt
-Thiết lập các bit cho phép ngắt thành phần tương ứng
-Xóa các cờ ngắt
-Cho phép ngắt toàn cục
*Chú ý:
-Trong CodevisionAVR mỗi khi thực hiện chương trình ngắt trình biên
dịch CodevisionAVR sẽ tự xóa cờ ngắt tương ứng với ngắt đó.Vì vậy ta
không cần phải xóa cờ ngắt sau mỗi lần xảy ra ngắt.
-Đối với trình biên dịch không tự xóa cờ ngắt khi thực hiện chương trình
ngắt thì khi vào chương trình ngắt ta phải xóa ngay cờ ngắt để cờ ngắt có
thể nhận biết các lần ngắt tiếp theo.
II.NGẮT NGOÀI
1.CÁC CHÂN LIÊN QUAN
+ATmega16 có 3 chân ngắt ngoài
-Ngắt ngoài 0 nằm ở chân PD2 (INT0)
-Ngắt ngoài 1 nằm ở chân PD3 (INT1)
-Ngắt ngoài 2 nằm ở chân PB2 (INT2)
42
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
43
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
44
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
*Thanh ghi GICR
45
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
void ext_init(void)
{
DDRB.2=0;PORTB.2=1;//int2 la input
DDRD.2=0;PORTD.2=1;//int0 la input
DDRD.3=0;PORTD.3=1;//int1 la input
MCUCR=(MCUCR&0xf0)|0x0a;//ngat o canh xuong tai int1,int0
MCUCSR=(MCUCSR&0xbf);//ngat canh xuong tai int2
GICR=(GICR&0x1f)|0xe0;//cho phep ca 3 ngat ngoai hoat dong
GIFR=0x00;//xoa co ngat
#asm("sei");//cho phep ngat toan cuc
delay_ms(400);//cho phan cung on dinh
d=0;
}
void hienthi(unsigned int n)
{
unsigned int x,y;
unsigned char m[5];
signed char i,k;
k=0;
x=n;
do
{
y=x%10;
x=x/10;
m[k]=y;
k++;
}
while(x);
for(i=0;i<k;i++)
{
PORTC=maled[m[i]];
PORTA=(1<<i);
delay_ms(4);
PORTA=0x00;
}
}
interrupt[2] void ngoai0(void)
{
d++;
if(d>99) d=0;
}
interrupt[3] void ngoai1(void)
{
46
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
d=d+2;
if(d>99) d=0;
}
interrupt[19] void ngoai2(void)
{
d=d+3;
if(d>99) d=0;
}
void main(void)
{
DDRC=0xff;
DDRA=0xff;PORTA=0x00;//tat het le 7 doan
ext_init();
while(1) hienthi(d);
}
47
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
BÀI 10
EEPROM NỘI
1.ỨNG DỤNG BỘ EEPROM NỘI
-Các giá trị lưu vào bộ nhớ eeprom nội sẽ không bị mất đi khi bị mất điện
vì vậy chúng ta có thể dùng bộ nhớ eeprom để lưu những giá trị quan
trọng đề phòng bị mất điện.
-Trong ATmega16 có hỗ trợ 512 byte bộ nhớ eeprom nội có địa chỉ từ 0
→ 511
2.CÁC THANH GHI LIÊN QUAN
EECR → Điều khiển eeprom
EEDR → Chứa dữ liệu cần ghi hoặc đọc
EEAR(H,L) → Xác định địa chỉ ô nhớ eeprom cần làm việc
3.CHI TIẾT CÁC THANH GHI
*Thanh ghi EECR
48
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
EEAR8 EEARH
EEAR7 EEAR6 EEAR5 EEAR4 EEAR3 EEAR2 EEAR1 EEAR0 EEARL
MSB LSB
4.VÍ DỤ
*Viết chương trình tăng giá trị biến đếm d,giá trị của biến đếm d sẽ được
lưu vào ô nhớ có địa chỉ là 1 trong eeprom nội.Nếu bị mất điện khi có
điện trở lại giá trị của biến đếm d vẫn còn như trước lúc mất điện.
-Nếu ấn nút nhấn nối chân INT0 (PD2) biến d tăng 1 đơn vị
-Nếu ấn nút nhấn nối chân INT1 (PD3) biến d tăng 2 đơn vị
-Nếu ấn nút nhấn nối chân INT2 (PB2) biến d tăng 3 đơn vị
#include <mega16.h>
#include <delay.h>
unsigned int d=0;
unsigned char crom;
unsigned char
maled[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
void send_eeprom(unsigned int address,unsigned char n)
{
while((EECR&0x02)==0x02);//cho EEWE=0 thi da ghi xong
EEAR=address;//xac dinh o nho can ghi
EEDR=n;//du lieu can ghi
EECR=0x04;//EEMWE=1,cho phep ghi
EECR=0x06;//bat dau ghi
}
unsigned char read_eeprom(unsigned int address)
{
while((EECR&0x02)==0x02);//cho EEWE=0
EEAR=address;
EECR=0x01;//cho phep doc
return(EEDR);
}
void ext_init(void)
{
DDRB.2=0;PORTB.2=1;//int2 la input
DDRD.2=0;PORTD.2=1;//int0 la input
DDRD.3=0;PORTD.3=1;//int1 la input
49
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
MCUCR=(MCUCR&0xf0)|0x0a;//ngat o canh xuong tai int1,int0
MCUCSR=(MCUCSR&0xbf);//ngat canh xuong tai int2
GICR=(GICR&0x1f)|0xe0;//cho phep ca 3 ngat ngoai hoat dong
GIFR=0x00;//xoa co ngat
#asm("sei");//cho phep ngat toan cuc
delay_ms(400);//cho phan cung on dinh
}
void hienthi(unsigned int n)
{
unsigned int x,y;
unsigned char m[5];
signed char i,k;
k=0;
x=n;
do
{
y=x%10;
x=x/10;
m[k]=y;
k++;
}
while(x);
for(i=0;i<k;i++)
{
PORTC=maled[m[i]];
PORTA=(1<<i);
delay_ms(4);
PORTA=0x00;
}
}
interrupt[2] void ngoai0(void)
{
d=read_eeprom(1);
d++;
if(d>99) d=0;
send_eeprom(1,d);
}
interrupt[3] void ngoai1(void)
{
d=read_eeprom(1);
d=d+2;
if(d>99) d=0;
send_eeprom(1,d);
50
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
}
interrupt[19] void ngoai2(void)
{
d=read_eeprom(1);
d=d+3;
if(d>99) d=0;
send_eeprom(1,d);
}
void main(void)
{
DDRC=0xff;
DDRA=0xff;PORTA=0x00;//tat het le 7 doan
ext_init();
crom=read_eeprom(0);
if(crom!=0x0f)
{
send_eeprom(0,0x0f);//bien crom de tranh khoi tao khi co dien tro lai
send_eeprom(1,0);//khoi tao gia tri ban dau vao o nho 1
}
d=read_eeprom(1);
while(1) hienthi(d);
}
51
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
BÀI 11
ADC
1.CÁC CHÂN LIÊN QUAN
-Chân AVCC (Chân cấp nguồn cho ADC)
-Chân AVREF (Chân cấp điện áp tham chiếu)
-Các chân ADC của ATmega16 nằm ở PORTA
ADC0 (PA0)
ADC1 (PA1)
ADC2 (PA2)
ADC3 (PA3)
ADC4 (PA4)
ADC5 (PA5)
ADC6 (PA6)
ADC7 (PA7)
52
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
53
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
3.CHI TIẾT CÁC THANH GHI
*Thanh ghi ADMUX
-Các bit REFS1,REFS0: Chọn điện áp tham chiếu cấp cho ADC
D D D D D D D D D D
9 8 7 6 5 4 3 2 1 0
=1: Căn trái,toàn bộ 10 bit kết quả ADC nằm ở 10 bit cao của
thanh ghi ADCW,tức là ADCH chứa 8 bit cao,ADCL chứa
2
bit thấp.6 bit thấp trong ADCL không chứa kết quả ADC.
D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
54
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
55
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
=1: Cho phép chế độ kích hoạt ADC tự động,nguồn kích mở ADC
tự
động sẽ được thiết lập bởi thanh ghi SFIOR
-Bit ADIF: Cờ báo ngắt ADC
Khi chuyển đổi ADC hoàn thành bit này sẽ tự động bật lên 1,nếu ta cho
phép ngắt ADC hoạt động thì chương trình ngắt ADC sẽ được thực hiện.
-Bit ADIE: Cho phép ngắt ADC
=0: Cấm ngắt ADC
=1: Cho phép ngắt ADC
-Các bit ADPS2,ADPS1,ADPS0: Chọn nguồn xung cấp cho ADC
ADCH ADCL
ADCW
56
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
0 1 0 Khi có tác nhân gây ra ngắt ngoài 0
0 1 1 Khi TCNT0 = OCR0
1 0 0 Khi timer0 bị tràn
1 0 1 Khi TCNT1 = OCR1B
1 1 0 Khi timer1 bị tràn
Khi xảy ra sự kiện input capture tại chân
1 1 1
ICP1
4.VÍ DỤ
*Ví dụ 1: Đọc điện áp ADC tại chân ADC2 (PA2)
#include <mega16.h>
#include <delay.h>
unsigned int adc=0;
unsigned char
maled[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
void adc_init(void)
{
DDRA=0x00;//input ADC in PORTA
ADMUX=0x40;//VREF=AVCC
ADCSRA=0x80;//ADCEN=1
#asm("cli");//disable all interrupt
delay_ms(400);//cho mot khoang time de on dinh
}
void hienthi(unsigned int n)
{
unsigned int x,y;
unsigned char m[5];
signed char i,k;
k=0;
x=n;
do
{
y=x%10;
x=x/10;
m[k]=y;
k++;
}
while(x);
for(i=0;i<k;i++)
{
PORTC=maled[m[i]];
57
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
PORTD=(0x08>>i);
delay_ms(4);
PORTD=0x00;
}
}
unsigned int read_adc(unsigned char kenh)
{
ADMUX=0x40|kenh;
hienthi(adc);//doi vai ms de kenh duoc thiet lap on dinh
ADCSRA=0x80|0x40;
while((ADCSRA&0x10)==0x00)hienthi(adc);//doi den khi ADIF=1
return(ADCW);
}
void main(void)
{
DDRC=0xff;
DDRC=0xff;PORTD=0x00;//tat het le 7 doan
adc_init();
while(1)
{
adc=read_adc(2);
hienthi(adc);
}
}
58
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
*Ví dụ 2: Đo nhiệt độ bằng LM35 tại chân ADC7
#include <mega16.h>
#include <delay.h>
unsigned int adc=0;
unsigned char
maled[12]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x9c,
0xc6};
void adc_init(void)
{
DDRA=0x00;//input ADC in PORTA
ADMUX=0x40;//VREF=AVCC
ADCSRA=0x80;//ADCEN=1
#asm("cli");//disable all interrupt
delay_ms(400);//cho mot khoang time de on dinh
}
void hienthi(unsigned int n)
{
unsigned int x,y;
unsigned char m[6];
signed char i,k;
k=0;
x=n;
do
{
y=x%10;
x=x/10;
m[k]=y;
k++;
}
while(x);
for(i=k+1;i>=2;i--) m[i]=m[i-2];
m[1]=10;//do
m[0]=11;//C
for(i=0;i<k+2;i++)
{
PORTC=maled[m[i]];
PORTD=(0x08>>i);
delay_ms(4);
PORTD=0x00;
}
}
unsigned int read_adc(unsigned char kenh)
{
59
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
ADMUX=0x40|kenh;
hienthi(adc);//doi vai ms de kenh duoc thiet lap on dinh
ADCSRA=0x80|0x40;
while((ADCSRA&0x10)==0x00)hienthi(adc);//doi den khi ADIF=1
return(ADCW);
}
void main(void)
{
float nhietdo;
DDRC=0xff;
DDRC=0xff;PORTD=0x00;//tat het le 7 doan
adc_init();
while(1)
{
adc=read_adc(7);//T=100*u (1)
nhietdo=adc;//u=(N*Vref)/1023 (2)
nhietdo=0.4887*nhietdo;//thay (2) vao (1) ta duoc
T=500N/1023=0.4887*N
adc=nhietdo;
hienthi(nhietdo);
}
}
60
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
BÀI 12
ANALOG COMPARATOR
1.CÁC CHÂN LIÊN QUAN
AIN0 (PB2)
AIN1 (PB3)
ADC0 (PA0)
ADC1 (PA1)
ADC2 (PA2)
ADC3 (PA3)
ADC4 (PA4)
ADC5 (PA5)
ADC6 (PA6)
ADC7 (PA7)
61
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
62
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
3.CHI TIẾT CÁC THANH GHI
*Thanh ghi ACSR
63
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
0 1 -
1 0 Khi bit ACO chuyển từ mức cao xuống thấp
1 1 Khi bit ACO chuyển từ mức thấp lên mức cao
4.VÍ DỤ
*So sánh điện áp đầu vào giữa 2 chân AIN0(PB2) và AIN1(PB3) nếu
điện áp chân AIN0 > AIN1 thì 8 led đơn nối PORTC sáng.Nếu AIN0 ≤
AIN1 thì 8 led đơn nối PORTC tắt.
#include <mega16.h>
#include <delay.h>
void analogcp_init(void)
{
DDRB.2=0;//AIN0 la input
DDRB.3=0;//AIN1 la input
ADCSR=0x00;
SFIOR=(SFIOR&0xf7);//ACME=0
#asm("cli");
64
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
delay_ms(400);
}
void main(void)
{
DDRC=0xff;
PORTC=0x00;
analogcp_init();
while(1)
{
if((ACSR&0x20)==0x20) PORTC=0xff;//neu bit ACO=1 thi
PORTC=0xff
else PORTC=0x00;//neu bit ACO=0 thi PORTC=0x00;
}
}
65
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
BÀI 13
TIMER/COUNTER0
(BỘ TIMER/COUNTER 8 BIT)
1.CÁC CHÂN LIÊN QUAN
-Chân đưa xung ngoài vào Timer0 chân T0 (PB0)
-Chân xuất xung đầu ra của bộ Timer0 chân OC0 (PB3)
66
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
67
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
1 0 CTC
1 1 Fast PWM
-Các bit COM01 và COM00: Dùng để chọn trạng thái đầu ra chân OC0
(PB3) với bộ timer0.
+Chế độ NON-PWM (Normal và CTC)
Chế độ Normal giá trị trong thanh ghi TCNT0 sẽ tăng liên tục từ 0 →
255.Khi bị tràn sẽ tự động xóa về 0.
Chế độ CTC giá trị trong thanh ghi TCNT0 sẽ bắt đầu tăng từ 0 sau mỗi
chu kỳ timer0 nếu trong quá trình tăng mà xảy ra trường hợp
TCNT0=OCR0 thì TCNT0 sẽ bị xóa về 0.
Ví dụ 1: Chọn Normal và COM01:00=01
68
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
+Chế độ Fast-PWM
Chế độ Fast-PWM giá trị trong thanh ghi TCNT0 sẽ tăng dần theo mỗi
chu kỳ timer0 từ 0 → max rồi reset về 0.
Bảng thiết lập trạng thái đầu ra chân OC0 ở chế độ Fast – PWM như sau:
69
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
70
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
-Các bit CS02,CS01,CS00: Dùng để chọn nguồn xung cấp cho timer0
71
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
-Bit OCF0: Cờ báo ngắt tác nhân gây ra ngắt compare timer0
Khi giá trị trong thanh ghi TCNT0 = OCR0 thì bit này sẽ tự động bật lên
1
-Bit TOV0: Cờ báo ngắt tràn timer0
Khi giá trị trong thanh ghi TCNT0 bị tràn bit này sẽ tự động bật lên 1
*Thanh ghi TCNT0
Là thanh ghi 8 bit chứa giá trị đếm của timer/counter0
4.VÍ DỤ
*Ví dụ 1: Tạo xung vuông tại chân OC0 có chu kỳ 1ms,Ton=Toff,dùng
thạch anh 8Mhz.
-Ở chế độ CTC ta có:
N0
Txung=2*(OCR0+1)*
Favr
+Chọn N0=64 ta tính ra được OCR0=61
#include <mega16.h>
#include <delay.h>
void ctc_init(void)
{
//fosc=8Mhz,Txung=1ms,N=64,CTC,timer0
TCCR0=0x1b;
OCR0=61;
TCNT0=0x00;
TIMSK=0x00;
TIFR=0x00;
#asm("cli");
}
void main(void)
{
DDRB.3=1;//OC0 is output
ctc_init();
while(1);
}
72
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
*Ví dụ 2: Viết chương trình đếm thời gian giờ,phút,giây bằng timer0
#include <mega16.h>
#include <delay.h>
73
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
unsigned char gio=0,phut=0,giay=0;
unsigned char d=0;
unsigned char
maled[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
void timer0_init(void)
{
//fosc=8Mhz,mode Normal
TCCR0=0x05;//timer0,chia tan 1024
TCNT0=0;//sau 32640us se xay ra ngat 1 lan
TIMSK=0x01;//cho phep ngat tran timer0
TIFR=0x00;
#asm("sei");
}
void hienthi(void)
{
unsigned char i,m[6];
m[0]=gio/10;
m[1]=gio%10;
m[2]=phut/10;
m[3]=phut%10;
m[4]=giay/10;
m[5]=giay%10;
for(i=0;i<6;i++)
{
PORTC=maled[m[i]];
PORTD=(1<<i);
delay_ms(4);
PORTD=0x00;
}
}
interrupt[10] void ngattimer0(void)
{
TCNT0=0;//nap lai gia cho cho TCNT0
d++;
if(d==20)//neu d=20 thi du 1 giay
{
giay++;
d=0;
}
if(giay==60)
{
phut++;
giay=0;
74
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
}
if(phut==60)
{
gio++;
phut=0;
}
if(gio==24) gio=0;
}
void main(void)
{
DDRC=0xff;
DDRD=0xff;
PORTD=0x00;
timer0_init();
while(1)hienthi();
}
75
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
TCCR0=0x06;//timer1,xung ngoai tai chan T0
TCNT0=0;
TIMSK=0x00;//cho phep ngat tran timer1
TIFR=0x00;
#asm("cli");
}
void hienthi(unsigned int n)
{
unsigned int x,y;
unsigned char m[6];
signed char i,k;
x=n;
k=0;
do
{
y=x%10;
x=x/10;
m[k]=y;
k++;
}
while(x);
for(i=0;i<k;i++)
{
PORTC=maled[m[i]];
PORTD=(0x08>>i);
delay_ms(4);
PORTD=0x00;
}
}
void main(void)
{
DDRC=0xff;
DDRD=0xff;
PORTD=0x00;
counter0_init();
while(1)
{
d=TCNT0;
hienthi(d);
}
}
76
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
BÀI 14
TIMER/COUNTER1
(BỘ TIMER/COUNTER 16 BIT)
1.CÁC CHÂN LIÊN QUAN
-Chân đưa xung ngoài vào bộ Timer1 chân T1 (PB1)
-Chân xuất xung đầu ra của Timer1 chân OC1A (PD5)
-Chân xuất xung đầu ra của Timer1 chân OC1B (PD4)
-Chân Input Capture của Timer1 chân ICP1 (PD6)
77
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
78
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
2.CÁC THANH GHI LIÊN QUAN
TCNT1
TCCR1A
TCCR1B
OCR1A(H,L)
OCR1B(H,L)
ICR1(H,L)
TIMSK
TIFR
3.CHI TIẾT CÁC THANH GHI
*Thanh ghi TCCR1A và thanh ghi TCCR1B
TCCR1A
COM1A1 COM1A0 COM1B1 COM1B0 FOC1A FOC1B WGM11 WGM10
TCCR1B
ICNC1 ICES1 WGM13 WGM12 CS12 CS11 CS11
-Các bit FOC1A,FOC1B: Luôn xóa 2 bit này bằng 0
-Bit ICNC1: Thiết lập bộ lọc nhiễu cho đầu vào input capture tại chân
ICP1
=0: Bộ lọc input capture sẽ không hoạt động
=1: Bộ lọc input capture sẽ hoạt động
-Bit ICES1: Chọn tác nhân gây input capture
=0: Khi có cạnh xuống tại chân ICP1 (PD6)
=1: Khi có cạnh xuống tại chân ICP1 (PD6)
-Các bit WGM13,WGM12,WGM11,WGM10: Chọn chế độ hoạt động
của timer/counter1
Update TOV1
W13 W12 W11 W10 MODE TOP
OCR1X Set
0 0 0 0 Normal 0xffff Ngay LT MAX
0 0 0 1 PC 8 bit 0x00ff TOP BOT
0 0 1 0 PC 9 bit 0x01ff TOP BOT
0 0 1 1 PC 10 bit 0x03ff TOP BOT
0 1 0 0 CTC OCR1A Ngay LT MAX
0 1 0 1 Fast 8 bit 0x00ff BOT TOP
0 1 1 0 Fast 9 bit 0x01ff BOT TOP
0 1 1 1 Fast 10 bit 0x03ff BOT TOP
1 0 0 0 P&F ICR1 BOT BOT
1 0 0 1 P&F OCR1A BOT BOT
1 0 1 0 PC ICR1 TOP BOT
1 0 1 1 PC OCR1A TOP BOT
1 1 0 0 CTC ICR1 Ngay LT MAX
1 1 0 1 - - - -
79
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
1 1 1 0 Fast ICR1 BOT TOP
1 1 1 1 Fast OCR1A BOT TOP
+Chế độ CTC
Chế độ này giá trị trong thanh ghi TCNT1 sẽ tăng dần theo mỗi chu kỳ
Timer1 từ 0 → OCR1A (nếu dung kênh A) sau đó bị xóa về 0.
80
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
1 1 Set chân OC1A = 1 khi TCNT1 = OCR1A
81
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
+Chế độ Fast-PWM
Chế độ này giá trị trong thanh ghi TCNT1 sẽ tăng dần theo mỗi chu kỳ
Timer1 từ 0 → TOP sau đó bị xóa về 0.
82
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
-Các bit CS12,CS11,CS10: Dùng để chọn nguồn xung cấp cho timer1
83
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
-Bit TOIE1: Cho phép ngắt tràn timer1
=0: Cấm ngắt tràn timer1
=1: Cho phép ngắt tràn timer1
*Thanh ghi TIFR
-Bit ICF1: Cờ báo tác nhân gây Input Capture xảy ra tại chân ICP1
(PD6)
Khi có tác nhân gây Input Capture tại chân ICP1 thì bit này sẽ tự động bật
lên 1.
-Bit OCF1A: Cờ báo ngắt compare kênh A
Khi giá trị trong thanh ghi TCNT1 = OCR1A bit này sẽ tự động bật lên 1
-Bit OCF1B: Cờ báo ngắt compare kênh B
Khi giá trị trong thanh ghi TCNT1 = OCR1B bit này sẽ tự động bật lên 1
-Bit TOV1: Cờ báo tràn Timer1
Khi giá trị trong thanh ghi TCNT1 bị tràn bit này sẽ tự động bật lên
1.Ngoài ra tác nhân ảnh hưởng đến bit này còn được thiết lập bởi các bit
WGM13,WGM12,WGM11,WGM10.
4.VÍ DỤ
*Ví dụ 1: Viết chương trình điều chế xung vuông tại chân OC1A,OCR1B
Thạch anh dùng 8Mhz.Điều chế xung ở chế độ Fast PWM,TOP=ICR1.
-Xung tại chân OC1A có Ton=500us,Tpwm=1000us
-Xung tại chân OC1B có Ton=250us,Tpwm=1000us
+Ở chế độ Fast PWM ta có:
N1
Tpwm=(TOP+1)*
Favr
+Trong đó: N1 là hệ số chia tần của bộ timer1,Favr là tần số bộ dao động
Ở đây dùng thạch anh ngoài 8Mhz và chọn N1=8 ta sẽ tính ra được
ICR1=TOP=999
OCR1A=500
OCR1B=250
#include <mega16.h>
#include <delay.h>
void fastpwm_init(void)
{
//fosc=8Mhz,N=8,fast pwm,timer1
//TOP=ICR1,Ton(A)=500us,Ton(B)=250us,Tpwm=1000us
TCNT1=0;
ICR1H=0x03;ICR1L=0xe7;//ICR1=999
OCR1A=500;
OCR1B=250;
84
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
TCCR1A=0xa2;
TCCR1B=0x1a;
TIMSK=0x00;
TIFR=0x00;
#asm("cli");
}
void main(void)
{
DDRD.4=1;//OC1B is output
DDRD.5=1;//OC1A is output
fastpwm_init();
while(1);
}
85
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
*Ví dụ 2: Viết chương trình đếm thời gian giờ,phút,giây bằng timer1
#include <mega16.h>
#include <delay.h>
unsigned char gio=0,phut=0,giay=0;
unsigned char d=0;
unsigned char
maled[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
void timer1_init(void)
{
//fosc=8Mhz,mode Normal
TCCR1A=0x00;
TCCR1B=0x02;//timer1,chia tan 8
TCNT1=15535;//sau 50000us se xay ra ngat 1 lan
TIMSK=0x04;//cho phep ngat tran timer1
TIFR=0x00;
#asm("sei");
}
void hienthi(void)
{
unsigned char i,m[6];
m[0]=gio/10;
m[1]=gio%10;
m[2]=phut/10;
86
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
m[3]=phut%10;
m[4]=giay/10;
m[5]=giay%10;
for(i=0;i<6;i++)
{
PORTC=maled[m[i]];
PORTD=(1<<i);
delay_ms(4);
PORTD=0x00;
}
}
interrupt[9] void ngattimer1(void)
{
TCNT1=15535;//nap lai gia cho cho TCNT1
d++;
if(d==20)//neu d=20 thi du 1 giay
{
giay++;
d=0;
}
if(giay==60)
{
phut++;
giay=0;
}
if(phut==60)
{
gio++;
phut=0;
}
if(gio==24) gio=0;
}
void main(void)
{
DDRC=0xff;
DDRD=0xff;
PORTD=0x00;
timer1_init();
while(1)hienthi();
}
87
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
88
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
m[k]=y;
k++;
}
while(x);
for(i=0;i<k;i++)
{
PORTC=maled[m[i]];
PORTD=(0x08>>i);
delay_ms(4);
PORTD=0x00;
}
}
void main(void)
{
DDRC=0xff;
DDRD=0xff;
PORTD=0x00;
counter1_init();
while(1)
{
if(TCNT1>9999) TCNT1=0;
d=TCNT1;
hienthi(d);
}
}
89
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
BÀI 15
GIAO TIẾP USART
1.CÁC CHÂN LIÊN QUAN
-Chân nhận dữ liệu RXD (PD0)
-Chân truyền dữ liệu TXD (PD1)
-Chân tạo xung đồng bộ XCK (PB0)
90
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
91
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
2.CÁC THANH GHI LIÊN QUAN
UCSRA
UCSRB
UCSRC
UBRR(H,L)
UDR
3.CHI TIẾT CÁC THANH GHI
*Thanh ghi UCSRA
92
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
Đồng bộ Favr
UBRR= -1
(USRT) 2*baud
93
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
0 1 1 8 bit
1 0 0 Not use
1 0 1 Not use
1 1 0 Not use
1 1 1 9 bit
-Bit RXB8: Khi giao tiếp ở chế độ 9 bit data,bit này chính là bit thứ 9
trong khung nhận 9 bit.Bit này phải được đọc đầu tiên trước khi nhận các
bit thấp.
-Bit TXD8: Khi giao tiếp ở chế độ 9 bit data,bit này chính là bit thứ 9
trong khung truyền 9 bit.Bit này phải được truyền đi đầu tiên trước khi
truyền các bit thấp.
94
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
0 1 1 8 bit
1 0 0 Not use
1 0 1 Not use
1 1 0 Not use
1 1 1 9 bit
-Bit UCPOL: Thiết lập quá trình truyền và nhận trong chế độ giao tiếp
đồng bộ.
Đồng bộ Favr
UBRR(H,L) = -1
(USRT) 2*baud
95
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
9600
14400
19200
28800
38400
56000
57600
115200
4.CHUẨN RS232 VÀ CHUẨN TTL
*Chuẩn RS232
-Mức 0: +3V→+12V
-Mức 1: -3V →-12V
96
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
97
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
5.VÍ DỤ
*Ví dụ 1: Code truyền nhận dữ liệu giữa máy tính và ATmega16
#include<mega16.h>
#include<delay.h>
void UART_init(void)
{
UBRRH=0;UBRRL=103;
UCSRA=0x02;
UCSRB=0x18;
UCSRC=0x86;
DDRD.0=0;
DDRD.1=1;
#asm("cli");
delay_ms(400);
}
void send_x(unsigned char n)
{
while((UCSRA&0x20)==0x00);
UDR=n;
}
unsigned char get_x(void)
{
while((UCSRA&0x80)==0);
return(UDR);
}
void main()
{
unsigned char x;
98
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
DDRC=0xff;
PORTC=0x00;
UART_init();
while(1)
{
x=get_x();
if(x=='1')
{
PORTC.0=~PORTC.0;
x=0;
}
if(x=='2')
{
PORTC.1=~PORTC.1;
x=0;
}
if(x=='3')
{
PORTC.2=~PORTC.2;
x=0;
}
if(x=='4')
{
PORTC.3=~PORTC.3;
x=0;
}
if(x=='5')
{
PORTC.4=~PORTC.4;
x=0;
}
if(x=='6')
{
PORTC.5=~PORTC.5;
x=0;
}
if(x=='7')
{
PORTC.6=~PORTC.6;
x=0;
}
if(x=='8')
{
99
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
PORTC.7=~PORTC.7;
x=0;
}
if(x=='0')
{
PORTC=0x00;
x=0;
}
if(x=='9')
{
PORTC=0xff;
x=0;
}
if(x=='!')
{
PORTC=~PORTC;
x=0;
}
}
}
*Ví dụ 2: Code truyền nhận dữ liệu giữa máy tính và ATmega16
#include<mega16.h>
#include<delay.h>
unsigned int d=0;
unsigned char kt=1;
unsigned char x=0;
void uart_init(void)
{
//baud=9600 khi FOSC=8000000
//8 bit data,1 bit stop,parity none
UCSRA=0x02;
UCSRB=0x98;//cho phep nhan,cam truyen,cam ngat truyen va ngat
nhan
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x67;
delay_ms(400);
}
void ext_init(void)
{
MCUCR=0x0a;
MCUCSR=0x00;
GICR=0x40;
100
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
GIFR=0x00;
#asm("sei");
delay_ms(400);
d=0;
}
void send_x(unsigned char n)
{
while((UCSRA&0x20)==0x00);//wait UDRE=1;
UDR=n;
}
/*unsigned char read_x(void)
{
while((UCSRA&0x80)==0x00);//wait RXC=1;
return(UDR);
} */
void sendint(unsigned int n)
{
unsigned int x,y;
unsigned char m[6];
signed char i,k;
x=n;
k=0;
do
{
y=x%10;
x=x/10;
m[k]=y;
k++;
}
while(x);
send_x(10);
for(i=k-1;i>=0;i--)
{
send_x(m[i]);
}
send_x(11);
}
interrupt[2] void ngoai0(void)
{
d++;
while(PIND.2==0);
//delay_ms(400);
if(d>60000) d=0;
101
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
kt=1;
}
interrupt[12] void noitiep(void)
{
x=UDR;
if(x=='1')
{
PORTD.3=~PORTD.3;
x=0;
}
if(x=='2')
{
PORTD.4=~PORTD.4;
x=0;
}
if(x=='3')
{
PORTD.5=~PORTD.5;
x=0;
}
if(x=='4')
{
PORTD.6=~PORTD.6;
x=0;
}
if(x=='5')
{
PORTD.7=~PORTD.7;
x=0;
}
}
void main()
{
DDRC=0xff;
DDRD.0=0;//RXD input
DDRD.1=1;//TXD output
DDRD.2=0;//INT0 input
PORTD.2=1;//keo tro bang noi
DDRD.3=1;
DDRD.4=1;
DDRD.5=1;
DDRD.6=1;
DDRD.7=1;
102
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
uart_init();
ext_init();
while(1)
{
if(kt==1)
{
sendint(d);
kt=0;
}
}
}
103
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
BÀI 16
104
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
105
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
106
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
-Bit MSTR: Chọn Master hoặc Slave
=0: Chip đóng vai trò là Slave
=1: Chip đóng vai trò là Master
-Bit CPOL: Chọn trạng thái nghĩ của xung
=0: Trạng thái nghĩ của xung SCK ở mức thấp
=1: Trạng thái nghĩ của xung SCK ở mức cao
-CHPA: Chọn thời điểm thiết lập và lấy mẫu data
=0: Lấy mẫu trước trạng thái nghĩ,thiết lập sau trạng thái nghĩ
=1: Lấy mẫu sau trạng thái nghĩ,thiết lập trước trạng thái nghĩ
-Các bit SPR1,SPR0: Kết hợp với bit SPI2X trong thanh ghi SPSR để
thiết lập nguồn xung cấp cho SPI
107
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
-Slave gửi mã sáng dần sang master,master xuất mã nhận được ra
PORTD.
+Code master
#include<mega16.h>
#include<delay.h>
unsigned char maled[9]={0,1,2,4,8,16,32,64,128};
void spi_master(void)
{
DDRB.4=1;PORTB.4=0;//ss la output
DDRB.5=1;//mosi la output
DDRB.6=0;PORTB=1;//miso la input
DDRB.7=1;//sck la output
SPCR=0x50;
SPSR=0x00;
#asm("cli");
}
unsigned char send_read(unsigned char n)
{
SPSR=0x00;
SPDR=n;
while((SPSR&0x80)==0x00);
return(SPDR);
}
void main(void)
{
signed char i;
DDRD=0xff;
spi_master();
while(1)
{
for(i=0;i<9;i++)
{
PORTD=send_read(maled[i]);
delay_ms(400);
}
}
}
+Code slave
#include<mega16.h>
#include<delay.h>
unsigned char maled[9]={0,1,3,7,15,31,63,127,255};
void spi_slave(void)
{
108
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
DDRB.4=0;PORTB.4=1;//ss la input
DDRB.5=0;PORTB.5=1;//mosi la input
DDRB.6=1;//miso la output
DDRB.7=0;PORTB.7=1;//sck la input
SPCR=0x40;
SPSR=0x00;
#asm("cli");
}
unsigned char send_read(unsigned char n)
{
SPSR=0x00;
SPDR=n;
while((SPSR&0x80)==0x00);
return(SPDR);
}
void main(void)
{
signed char i=0;
DDRD=0xff;
spi_slave();
while(1)
{
PORTD=send_read(maled[i]);
i++;
if(i>8) i=0;
}
}
109
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
BÀI 17
GIAO TIẾP I2C VÀ TWI
110
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
111
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
-Chân xung SCL (PC0)
-Chân dữ liệu SDA (PC1)
112
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
2.ĐẶC ĐIỂM
-Dùng 7 bit địa chỉ,cho phép tối đa lên đến 128 địa chỉ slave khác nhau
-Tốc độ truyền dữ liệu lên đến 400kbps
3.THIẾT LẬP TỐC ĐỘ GIAO TIẾP
Favr
Fscl=
16+2*TWBR*4TWPS
113
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
-Bit TWSTO: Bit tạo tín hiệu STOP
+Khi muốn kết thúc một cuộc gọi chung hoặc kết thúc quá trình TWI ta
đặt bit này của master lên mức 1.
+Ở chế độ slave bit này có thể được dùng để phục hồi một số điều kiện
lỗi.
-Bit TWWC: Cờ báo va chạm
+Bit này sẽ tự động set lên 1 khi xảy ra va chạm.Tức là quá trình cũ chưa
xử lý xong mà quá trình mới lại bắt đầu thì sẽ xảy ra lỗi này.
+Khi bit TWINT đang ở mức thấp mà ta lại đưa data vào thanh ghi
TWDR thì sẽ xảy ra va chạm data.Vì bit khi TWINT tự set lên 1 thì quá
trình trước đó mới hoàn thành.
-Bit TWEN: Cho phép modul TWI hoạt động
=0: Vô hiệu hóa TWI,các chân SDA và SCL là IO bình thường
=1: Cho phép TWI hoạt động,các chân SDA và SCL đóng vai trò là các
chân chức năng của TWI.
-Bit TWIE: Cho phép ngắt TWI
=0: Cấm
=1: Cho phép ngắt TWI
+Khi xong 1 quá trình TWI bit TWINT sẽ tự động set lên 1 để báo hiệu
cho chip,nếu ta bật bit này lên 1 và cho phép ngắt toàn cục thì sẽ nhảy
đến chương trình xử lý ngắt TWI thực hiện.
*Thanh ghi TWSR (Thanh ghi trạng thái)
Favr
Fscl=
16+2*TWBR*4TWPS
+Favr phụ thuộc vào nguồn dao động cao cho AVR,có thể là dao động
thạch anh hoặc dao động nội.
114
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
*Thanh ghi TWBR (Dùng để thiết lập tốc độ xung clock)
*Thanh ghi TWDR (Chứa dữ liệu cần truyền hoặc nhận)
*Thanh ghi TWAR (Thanh ghi địa chỉ)
TWAR={TWA6,TWA5,TWA4,TWA3,TWA2,TWA1,TWA0,TWGCE}
-Các bit TWA6,TWA5,TWA4,TWA3,TWA2,TWA1,TWA0: Chứa địa
chỉ của slave.Khi giao tiếp ta cần nạp địa chỉ của slave vào 7 bit này.
-Bit TWGCE: Dùng để cho phép 1 cuộc gọi chung
=0: Không cho phép cuộc gọi chung
=1: Cho phép tạo cuộc gọi chung
6.VÍ DỤ
-Viết chương hiển thị giờ,phút,giây dùng ds1307 sử dụng TWI
#include <mega16.h>
#include <delay.h>
#include <string.h>
#define twip PORTC
#define twid DDRC
#define pin PINC
#define slave 0x68
#define baud 32
#define write 0
#define read 1
#define start 0xa4
#define stop 0x94
#define clear 0x84
#define ack 0xc4
//----------------------------
//cac ham i2c va ds1307
void i2c_setup(void);
unsigned char ghiblock(unsigned char addr,unsigned char
dulieu[],unsigned char len);
unsigned char readblock(unsigned char addr,unsigned char
dulieu[],unsigned char len);
unsigned char outv(unsigned char bcd);
unsigned char inv(unsigned char dec);
unsigned char send(unsigned char addr,unsigned char n);
//----------------------------
unsigned char
giay=55,phut=59,gio=11,ngay=31,thang=12,nam=9,mode=1,ap=1;
unsigned char time[7];
//***************************
unsigned char
maled[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
void i2c_setup(void)
115
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
{
//set SCL to 400kHz
TWSR = 0x00;
TWBR = 0x0C;
TWCR = (1<<TWEN);//enable TWI
DDRC.0=1;
delay_ms(400);
}
void twi_start(void)
{
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while ((TWCR & (1<<TWINT)) == 0);
}
void twi_stop(void)
{
TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}
void twi_write(unsigned char n)
{
TWDR = n;
TWCR = (1<<TWINT)|(1<<TWEN);
while ((TWCR & (1<<TWINT)) == 0);
}
unsigned char twi_readack(void)
{
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
while ((TWCR & (1<<TWINT)) == 0);
return TWDR;
}
unsigned char twi_readnack(void)
{
TWCR = (1<<TWINT)|(1<<TWEN);
while ((TWCR & (1<<TWINT)) == 0);
return TWDR;
}
unsigned char send(unsigned char addr,unsigned char n)
{
unsigned char x;
twi_start();
if((TWSR&0xf8)!=0x08) return(1);
x=(slave<<1)|write;
twi_write(x);
if((TWSR&0xf8)!=0x18) return(1);
116
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
x=addr;
twi_write(x);
if((TWSR&0xf8)!= 0x28) return(1);
x=n;
twi_write(x);
if((TWSR&0xf8)!= 0x28) return(1);
twi_stop();
return 0;
}
unsigned char readtwi(unsigned char addr)
{
unsigned char x=0;
twi_start();
if((TWSR&0xf8)!=0x08) return(1);
x=(slave<<1)|write;
twi_write(x);
if((TWSR&0xf8)!=0x18) return(1);
x=addr;
twi_write(x);
if((TWSR&0xf8)!=0x28) return(1);
twi_start();
if((TWSR&0xf8)!=0x10) return(1);
x=(slave<<1)|read;
twi_write(x);
if((TWSR&0xf8)!=0x40) return(1);
x=twi_readnack();
if((TWSR&0xf8)!= 0x58) return(1);
twi_stop();
return(x);
}
unsigned char ghiblock(unsigned char addr,unsigned char
dulieu[],unsigned char len)
{
unsigned char i;
unsigned char x;
twi_start();
if((TWSR&0xf8)!=0x08) return(TWSR);//TWSR=0x08 da gui start
x=(slave<<1)|write;
twi_write(x);
if((TWSR&0xf8)!=0x18) return(TWSR);
x=addr;
twi_write(x);
if((TWSR&0xf8)!=0x28) return(TWSR);
117
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
for(i=0;i<len;i++)
{
twi_write(dulieu[i]);
if((TWSR&0xf8)!=0x28) return(TWSR);
}
twi_stop();
return(0);
}
unsigned char readblock(unsigned char addr,unsigned char
dulieu[],unsigned char len)
{
unsigned char i,x;
twi_start();
if((TWSR&0xf8)!=0x08)return(TWSR);
x=(slave<<1)|write;
twi_write(x);
if((TWSR&0xf8)!=0x18)return(TWSR);
x=addr;
twi_write(x);
if((TWSR&0xf8)!=0x28)return(TWSR);
twi_start();
if((TWSR&0xf8)!=0x10)return(TWSR);
x=(slave<<1)|read;
twi_write(x);
if((TWSR&0xf8)!=0x40)return(TWSR);//neu TWSR=0x40 da gui dia
chi slave cung bit read,da nhan ack
for(i=0;i<len-1;i++)
{
dulieu[i]=twi_readack();
if((TWSR&0xf8)!=0x50)return(TWSR);//neu TWSR=0x50 da nhan
data va tra lai ack
}
dulieu[len-1]=twi_readnack();
if((TWSR&0xf8)!=0x58)return(TWSR); //neu TWSR=0x58 da nhan
data va tra lai nack
twi_stop();
return(0);
}
unsigned char send1307(unsigned char addr,unsigned char n)
{
unsigned char x;
twi_start();
if((TWSR&0xf8)!=0x08) return(1);
118
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
x=(slave<<1)|write;
twi_write(x);
if((TWSR&0xf8)!=0x18) return(1);
x=addr;
twi_write(x);
if((TWSR&0xf8)!= 0x28) return(1);
x=inv(n);
twi_write(x);
if((TWSR&0xf8)!= 0x28) return(1);
twi_stop();
return 0;
}
unsigned char read1307(unsigned char addr)
{
unsigned char x=0;
twi_start();
if((TWSR&0xf8)!=0x08) return(1);
x=(slave<<1)|write;
twi_write(x);
if((TWSR&0xf8)!=0x18) return(1);
x=addr;
twi_write(x);
if((TWSR&0xf8)!=0x28) return(1);
twi_start();
if((TWSR&0xf8)!=0x10) return(1);
x=(slave<<1)|read;
twi_write(x);
if((TWSR&0xf8)!=0x40) return(1);
x=twi_readnack();
if((TWSR&0xf8)!= 0x58) return(1);
twi_stop();
return(outv(x));;
}
unsigned char outv(unsigned char bcd)
{
unsigned char l,h;
l=bcd&0x0f;
h=(bcd>>4)*10;
return(h+l);
}
unsigned char inv(unsigned char dec)
{
unsigned char l,h;
119
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
l=dec%10;
h=(dec/10)<<4;
return(h+l);
}
void io_init(void)
{
DDRA=0xff;
DDRB=0xff;
PORTB=0xff;
}
void hienthi(void)
{
unsigned char m[6];
signed char i;
m[0]=time[2]/10;
m[1]=time[2]%10;
m[2]=time[1]/10;
m[3]=time[1]%10;
m[4]=time[0]/10;
m[5]=time[0]%10;
for(i=0;i<6;i++)
{
PORTA=maled[m[i]];
PORTB=~(1<<i);
delay_ms(4);
PORTB=0xff;
}
}
void main(void)
{
io_init();
i2c_setup();
//doan khoi tao thoi gian
//time[2]=inv(12);time[1]=inv(30);time[0]=inv(45);
//time[4]=inv(3);time[5]=inv(10);time[6]=inv(16);
//ghiblock(0,time,7);
/*send(2,inv(10));
send(1,inv(30));
send(0,inv(45));
send(4,inv(3));
send(5,inv(10));
send(6,inv(16));*/
while(1)
120
THÁI XUÂN HUỆ 0981.018.504
LẬP TRÌNH ỨNG DỤNG VI ĐIỀU KHIỂN AVR
{
//readblock(0,time,7);
/*time[0]=readtwi(0);
time[1]=readtwi(1);
time[2]=readtwi(2);
time[4]=readtwi(4);
time[5]=readtwi(5);
time[6]=readtwi(6); */
time[0]=read1307(0);
time[1]=read1307(1);
time[2]=read1307(2);
time[4]=read1307(4);
time[5]=read1307(5);
time[6]=read1307(6);
hienthi();
}
}
121
THÁI XUÂN HUỆ 0981.018.504