TRƯỜNG ĐẠI HỌC NHA TRANG
KHOA CƠ KHÍ
THỰC HÀNH ỨNG DỤNG VI ĐIỀU KHIỂN
Nội dung:
Học phần cung cấp cho người học:nguyên lý hoạt động chung của vi điều khiển,
chức năng của các mô đun để học viên biết cách thức điều khiển các khối chức năng, giao
tiếp giữa chúng với nhau và với hệ thống chấp hành.
Kết quả:
Sinh viên sử dụng bo điều khiển Atmega32 để điều khiển đèn LED, khởi động
động cơ DC.
Phổ biến nội quy học: thời gian học, cách đánh giá, chia nhóm (3-4 sv)
Yêu cầu học: viết báo cáo(xác định chân cho led, điện trở, cách sử dụng mạch
nạp)
Chuẩn bị: Linh kiện làm mạch VĐK, DC có Encoder, LED 7D, LCD 16x2, LM 35
1
BÀI 1: HOÀN THÀNH PHẦN CỨNG CỦA MẠCH VDK
Nội dung: Làm mạch VĐK, mạch LCD
1.1.
STT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1.2.
Linh kiện làm mạch VĐK
Chức năng
Điều khiển led, nút nhấn,…
Ổn áp nguồn dương 5v DC
1000uF/16v, 1000uF/25v
Lọc xung ở tần số thấp
8 con 1K
Hạn dòng
104 : 2 conTụ pi 18 : 2 con Lọc xung ở tần số cao
Tạo xung cho VDK
Chống ngược dòng
2 chân : 8 cái
Đưa tín hiệu vào cho VDK
8 con
Phát quang
Cấp nguồn cho VDK
5 cái 8 chân, 1 cái 6 chân
Nối dây cắm cái
40 chân
Bảo vệ Atmega
Cách ly mạch với đất
Nạp chương trình cho Atmega
Pin 8: 4 dây
Kết nối tín hiệu vào ra
Tên linh kiện
Atmega16
7805
Tụ hóa
Điện trở
Tụ không phân cực
Thạch anh
Diode
Nút nhấn nhỏ
Led
Cổng nguồn
Hàng rào
Đế cắm IC
Ốc vít
Mạch nạp
Dây cắm cái
Hoàn thành mạch vi điều khiển
Sử dụng sơ đồ
nguyên lí, sơ đồ
khối để lắp linh kiện
lên mạch
Hướng
dẫn
làm mạch LCD
2
Trình tự làm mạch:
- Mua linh kiện
- Chà mạch in
- Cố định tờ giấy với mạch in
- Cắm bàn là, để số 3/5 Max
- Ủi mạch in khoảng 3 7 phút
- Gỡ giấy ra khỏi mạch
- Dùng bút tô lại những chỗ bị đứt mạch in
- Ngâm hóa chất
- Sau khi ăn mòn hết, rửa lại với nước sạch
- Pha nhựa thông với xăng thơm
- Quét dung dịch đã pha để bảo vệ mạch phơi khô để chống oxy hóa
- Khoan mạch
- Kiểm tra mạch có bị chập không
- Lắp và hàn linh kiện
- Kiểm tra mạch có bị chập không
- Kiểm tra chiều các linh kiện
- Kiểm tra nguồn cấp
- Cắm điện vào mạch lần 1 (Khoảng 2 giây)
- Cắm điện vào mạch lần 2 (Khoảng 10 giây)
- Cắm điện vào mạch lần 3 (Khoảng 1 phút)
- Kiểm tra nguồn ra của con 7805
- Lắp VĐK và cắm điện
- Nạp chương trình
- Chạy thử
3
USB nạp:
- 8 sợ dây cắm 2 đầu(1 đực; 1 cái);
- 1 nguồn cắm usb.
Cách nối dây:
-
Đầu dây đực thứ nhất cắm vào VCC.
-
Đầu dây đực thứ 2 cắm vào RST.
-
Đầu dây đực thứ 3 cắm vào NC.
-
Đầu dây đực thứ 4 cắm vào MOSI.
-
Đầu dây đực thứ 5 cắm vào MISO.
-
Đầu dây đực thứ 6 cắm vào GND.
-
Tất cả các đầu dây cái cắm vào hàng rào cổng nguồn.
4
BÀI 2: KIỂM TRA MẠCH VĐK, CHẠY LED, LED 7D
Nội dung:
-
Nạp chương trình và chạy thử led
Kết nối LCD, Led 7 đoạn, LM35
2.1. Kiểm tra và hoàn chỉnh mạch vi điều khiển
- Kiểm tra mạch có bị chập hay không ?
- Kiểm tra led báo hiệu có sáng hay không ?
- Kiểm tra điện áp ra có đúng hay không ?
- Nối dây từ nút nhấn qua Led xem nút nhấn có hoạt động không?
- Đo các thông số điện áp đầu vào – ra có đúng không?
2.2. Nạp chương trình và chạy thử led
Bước 1: Đấu dây cho LED, Atmega16 có 4 PORT (A, B, C, D). Ở đây chọn PORT D
(dùng dây cái)
Bước 2 : Cài đặt chương trình viết code và nạp chip ( Dùng phần mềm Codevision AVR
3.12 và ProgISP )
Các bước để tạo project trong Cvavr:
-
Bước 1: File/New/Project
Bước 2: Hiện tab/chọn “Yes”
Bước 3: Hiện tab/chọn AT90,Atiny,Atmega/chọn “OK”
Bước 4: Chọn Atmega (đang dùng Atmega16)
Bước 5: Chọn tần số thạch anh (ví dụ 8.0000 MHz)
Bước 6: Program/Generate, Save and exit/ lưu file với 3 tên giống nhau
Bước 7: Biên dịch để kiểm tra lỗi “Chọn Build the Project”” (No erros, no
warning) → OK
Bước 8: Viết chương trình trên file hex vừa tạo
5
Vì đang muốn lập trình hiệu ứng cho Led nên tín hiệu của PORTA sẽ là tín hiệu ra
(Out), Kích Out từ Bit0 – Bit7.
Trong đó Out ở cổng A là cổng xuất ra. Với số 0 thể hiện ở mức thấp, và số 1 thể
hiện ở mức cao.
Chọn PORTB là PORT lấy tín hiệu đầu vào từ nút nhấn và treo trở cho nút nhấn
Ví dụ: cách viết một chương trình điều khiển LED
#include
//Khai báo thư viện cho chip
#include //Khai báo thư viện trễ
void main(void) //Đây là chương trình chính
{
DDRA = 0xFF; //đóng công tắc nối đất ở PORTD
PORTA = 0x00; //mở công tắc treo trở
delay_ms(1000); //cho trễ trong vòng 1 giây
PORTA = 0xFF; //đóng công tắc treo trở
delay_ms(1000); //cho trễ trong vòng 1 giây
}
2.3.
Giải thích về chương trình LED
Trường hợp 1:Thanh ghi DDR ở mức 0(mức 1 là đóng khóa k và mức 0 là mở
khóa k)
- Khi PORT ở mức 1 thì LED sẽ không sáng. Vì điện thế trên LED = 0V
6
- Khi PORT ở mức 0 thì LED cũng sẽ không sáng. Vì điện thế trên LED không thể
xác định được
Trường hợp 2: Thanh ghi DDR ở mức 1:
-
Khi PORT ở mức 1 thì LED sẽ không sáng. Vì điện thế trên LED = 0V.
Khi PORT ở mức 0 thì LED sẽ sáng. Vì điện thế trên bóng đèn = 5V theo công
thức UAB= |UA- UB|
Chú thích:
-
-
-
2.4.
Thanh ghi DDRA dùng để xác định tính hiệu vào hay ra (in hay out) của PORTA.
Như đã nói ở trên, vì dùng để điều khiển led nên cho DDRA=0xFF (hay
DDRA=0b11111111).
Ở đây “x” và “b” là tiền tố quyết định cách viết ở sau, với “x” ta viết chuỗi số ở
sau dưới dạng thập lục phân, ngược lại với “b” ta viết dưới dạng nhị phân. Giá trị
1 là out còn giá trị 0 là in.
Thanh ghi PORTA dùng để xác định trạng thái của các chân, ở đây mình ghi là
PORTA==0xFF=0b11111111, với 1 là mức áp ra bằng 0V (tắt) và 1 là mức 5V
(sáng), tùy theo nguyên lí của mạch mà mức 1 sáng hay tắt là khác nhau.
Nạp chương trình
- Mở phần mềm ProgISP
- Chọn chip Atmega16
- Chọn Erase để xóa chương trình cũ
- Chọn Load Flash → Mở thư mục lưu chương trình → Vào Debug/Exe →
Chọn file chương trình (.hex)
- Chạy chương trình (Auto) để nạp code.
7
2.5.
Led 7 đoạn
Bước 1: Chuẩn bị
-
Mạch VDK Atmega16
Mạch nạp chíp
Một LED 7 đoạn dương chung
Trở 330Ohm.
1 bóng báo đèn nguồn và 1 trở 1kOhm.
Bước 2: Nối dây
Led 7 đoạn gồm có 10 chân như hình dưới đây
Trong đó
-
8 chân a,b,c,d,e,f,g,dp tương tự như 8 con led.
2 chân còn lại là chân nguồn nhưng ta chỉ cần dùng 1 chân là được. Và để xác
định chân đó là chân (+) hay (-) thì cần phải xác định led 7 đoạn này là chung
(+) hay chung (-), từ đó cấp nguồn tương ứng cho chân đó.
Lưu ý
-
Đối với chân nguồn cần phải thêm vào 1 còn trở ( chọn 330Ω) để giảm áp qua
các Led.
Các chân của VĐK phải cắm tương ứng với chân Led 7 đoạn để tiện lập trình.
Cắm nguồn vào cho LED 7 đoạn( Nhớ có điện trở hạn dòng nếu không sẽ cháy
LED)
Cắm 8 chân LED còn lại vào bất kỳ PORT nào của VDK (Chọn PORTA) theo
thứ tự từ a dp
tương ứng với PORTA là từ 0 7
Bài tập:
-
Viết hiển thị số trên Led 7 đoạn
8
BÀI 3:LẬP TRÌNH LED VÀ SỬ DỤNG LCD
Nội dung:
- Lập trình hiệu ứng Led
- Hiển thị LCD
3.1. Hiệu ứng Led
3.2.LCD
Bước 1: Đấu dây cho LCD
Chọn bất kỳ PORT nào để kết nối VDK với LCD. Chọn PORTA;
Trong 1 PORT của ATMEGA16 có 8 chân
LCD có 2 cách kết nối: 1 là kết nối 8 chân 2 là 7 chân. Ở đây chọn cách kết nối 7
chân( Trong 8 chân bỏ 1 chân).
Tiếp theo (từ mạch kết nối VDK với LCD) nối dây ra màn hình LCD (đúng theo
thứ tự từ 1 đến 16).
Mạch kết nối VDK với LCD cần phải cấp nguồn 5V.
Bước 2: Viết chương trình
Các bước tạo file hex như ở trên LED.
Ở bước 5 chọn xong tần số thạch anh, chọn tiếp Alphanumeric LCD
Chọn như hình: “chọn Enable/tab sẽ hiện như hình/chọn PORT (ở đây dùng
PORTA)/Chọn bit 0 1 2 3 5 6 7 (bỏ chân 4 vì không dùng đến )
Cuối cùng làm tiếp như bước 6 ở trên LED.
9
Dùng lcd_ puts (“”) để hiển thị dữ liệu lên LCD, ta cộng thêm 48 là để đổi số từ số
thập phân sang ký tự số ASCII để truyền lên LCD Text để nó hiển thị được.
Viết chương trình cho LCD
#include //Khai báo thư viện cho chip
#include //Tạo một thư viện trể
#include //tạo thư viện cho LCD
Ví dụ
{
lcd_init(16);
lcd_clear();
// xóa màn hình LCD
lcd_gotoxy(0,0);
// vị trí dấu nhấp nháy (0,0)
lcd_puts("CDT");
// in chữ “CDT”
lcd_putchar((z/100)+48);
// in số hàng trăm của z
lcd_putchar((z%100/10)+48);
// in số hàng chục của z
lcd_putchar((z%10)+48);
// in số hàng đơn vị của z
}
Nạp code cho LCD bằng chương trình Progisp 1.72
Bài tập:
- Viết các hiệu ứng chạy led
- Viết chương trình hiển thị số và chữ lên LCD
10
BÀI 4: ĐO NHIỆT ĐỘ VÀ HIỂN THỊ LÊN LCD
Nội dung:
- Đo nhiệt độ từ LM 35
- Hiển thị lên LCD
Chuẩn bị
- LM 35
- Mạch vi điều khiển
Thực hiện
-
Nối PORT cho LCD ( PORT A)
Nối dây cho LED
Cấp nguồn cho LM 35 (5V)
PORTA.* với chân giữa của LM35.
4.1. Cảm biến LM35.
Chân 1:là chân cấp điện áp tham chiếu từ
mức(4v đến 30v).Ở đây LM35 được cấp nguồn 5v từ
vi điều khiển.
Chân 2:là chân điện áp ra Vout. Kết nối với chân
PORTA trong vi điều khiển.
Chân 3:là chân nối đất.
4.2. ADC
ADC = Vin (28 - 1)/Vref với ADC 8bit
ADC = Vin (210 - 1)/Vref với ADC 10bit
Cách lấy nhiệt độ từ LM35 qua giao tiếp ADC.
-
ADC 10 Bit = 2^10=1024
Điện áp tham chiếu Vref = 5V = 5000mV
LM35 (10 mV / 1 độ C)
Vậy bắt đầu từ 2C thì cứ mỗi 2.048 (ADC) thì nhiệt độ tăng thêm 1
Xác định nhiệt độ đo được qua số đo trên chân ADC:
Ta có: 5000 mV -- ứng với -- 1023 (thang đo ADC 10 bít)
Vậy : 10 mV -- ứng với -- 10 x 1024/5000 = 2,046 (ADC)
11
Con số 2,046 tính được đó chính là lượng thay đổi trên chân ADC ứng với thay đổi
10mV ở đầu ra LM35 hay ứng với thay đổi 1 độ C trên LM35.
=> Nhiệt độ đo được: Nhiệt độ = ADC_Read(0) / 2,046 (độ C) + 2 .
Viết chương trình :
Tạo project mới để viết chương trình hiển thị nhiệt độ trên LCD
Ví dụ:
void Nhiet_do(void)
{
T=(read_adc(0)/2.046 + 2)
}
Bài tập: Đo nhiệt độ hiển thị LCD
12
BÀI 5: ĐIỀU KHIỂN NÚT NHẤN, TIMER
Nội dung:
-
Điều khiển nút nhấn
Timer
Chuẩn bị:
- Nối dây ra nút nhấn(Chọn 1 PORT tùy ý)
- Nối dây ra LED(Chọn 1 PORT tùy ý trong 3
PORT còn lại)
- Ở đây nối nút nhấn ở PORTD và LED ở PORTA
- Kết nối mạch nạp với máy tính
- Chọn T sang P( Pullup, tự giữ) để đóng công tắc
treo trở
Ví dụ:
#include
#include
void main(void)
{
PORTD.0=1; PORTD.1=1; DDRA=0XFF;
while(1)
{
if(PIND.0==0)
{
while(1)
{
PORTA=0X00;
delay_ms(1);
PORTA=0XFF;
delay_ms(19);
if(PIND.1==0) break;
}
}
else if(PIND.1==0)
{
while(1)
{
PORTA=0X00;
delay_ms(19);
PORTA=0XFF;
delay_ms(1);
13
if(PIND.0==0)
break;
}
}
else
PORTA=0XFF;
}
}
TIMER
Ngắt: Interrupt.
Khi có một tín hiêu ngắt nào đó đến bộ xử lý, bộ xử lý dừng hoạt động đang làm
để xử lý ngắt. Với chương trình chính thì tín hiệu ngắt được ưu tiên.
Ngắt rất hay được sử dụng bởi tính thực hiện tức thì của nó. Có rất nhiều tín hiệu
ngắt trong AVR. Ngắt ngoài, ngắt timer, ngắt SPI, và các ngắt này được quy định sự ưu
tiên trước sau trong datasheet.
Một tín hiệu ngắt người ta gọi là vector ngắt: interrupt vector
STT Tên ngắt
Địa chỉ chương trình
Miêu tả chức năng
1
RESET
0X000
Ngắt phần cứng Reset
2
INT0
0x001
Ngắt ngoài tại chân INT0
3
INT1
0x002
Ngắt ngoài tại chân INT1
4
TIMER2 COMP 0x003
Ngắt so sánh timer 2
5
TIMER2 OVF
0x004
Ngắt tràn timer 2
6
TIMER1 CAPT
0x005
Ngắt chụp sự kiện timer 1
7
TIMER1
COMPA
0x006
Ngắt so sánh A timer 1
8
TIMER1
COMPB
0x007
Ngắt so sánh B timer 1
Ngắt ngoài: INT0, INT1
14
Ngắt ngoài là quá trình tác động từ bên ngoài vào bên trong VĐK làm cho VĐK
thực hiện 1 ngoại lệ nào đó. Có 4 kiểu :
Ngắt mức thấp Low Level : chỉ xảy ra ngắt khi chân INT0 hoặc INT1 ở mức thấp.
Ngắt thay đổi logic Any Change : bất kỳ thay đổi logic nào trên chân INT0 hoặc
INT1.
Ngắt sườn lên Rising Edge ( logic 0 lên logic 1)
Ngắt sườn xuống Falling Edge ( logic 1 lên logic 0)
Sườn xuống
Sườn lên
Tần số f = x Hz ( trong 1s sự kiện làm 1 lần)
Vi dụ : f = 2Hz Ta có T (chu kỳ)= 1(s)/f = 1000ms/2Hz= 500ms
Do đó thời gian trễ (delay) sẽ là T/2 ( vì LED sẽ sang / tắt trong 1 T) là
500/2=250ms. Và ta sẽ dùng time đễ xác định thời gian này.
Timer 0 có giá trị 8 bit = 256
Cách tính Timer để 60ms thì ngắt: mạch sử dụng thạch anh 8000Mhz vậy nên trong
1000ms Timer sẽ đếm được 8.000.000/256 lần. Vậy để tính được 60ms ta lấy
((8.000.000/256)*60)/1000
Ví dụ 1:
int Dem=0;//Khai báo biến Dem và gán gia trị bằng 0
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)//Chương trình Timer
{
Dem++;//Biến đếm bắt đầu tăng giá trị
15
if(Dem>=1875)//Khi biến đếm bằng hoặc hơn 1875 thì thực hiện chương trình
{
Dem=0;//Đặt biến đếm lại về 0
PORTA.0=~PORTA.0;//Đảo ngược tín hiệu PORTA.0
}
}
Ví dụ 2:
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
/*
f=125000Hz; Chọn tần số f
t= 1 / f = 8 (us) Tính chu kì t
Để số xung nhịp được chẵn, thì ta khởi tạo cho TCNT0=6
TCNT0: 6 -> 255, duoc 250 xung nhip
Từ số xung nhịp ta tính được thời gian tràn của chân TCNT0
-> Ttran= 250*8 = 2000 (us)
Chọn thời gian mà ta muốn, ở đây chọn 60ms
Neu bien dem tang 60000/2000=30 lan thi duoc 60 (ms)
*/
dem++;
TCNT0 = 6;
}
void main(void)
{
#asm("sei")
while (1)
{
if (dem>=30)
//So sánh biến dem với giá trị đã tính toán
{
PORTA.0 = ~PORTA.0;
//Đúng đk thì đảo trạng thái Led
dem=0;
//Trả giá trị dem về 0
}
}
16
}
Vi dụ 3:
Chọn time0 = 8bit = 256
Chọn số đập xung= 31250/256=122 (lần/1s=1000ms)
122 lần = 1000ms
? lần = 60ms
=> đếm số lần đập xung trong 60ms = (122*60)/1000 = 7 lần
Bài tập:
-
Lập trình để đèn nhấp nháy mỗi 60ms
Lập trình cho nút nhấn hiển thị các hiệu ứng led
Lập trình fLED1 = 1Hz, fLED1 = 2Hz, fLED3 = 3Hz
BÀI 6: ĐO TỐC ĐỘ ĐỘNG CƠ DC HIỂNTHỊ LÊN LCD
Nội dung:
6.1.
Động cơ DC Encoder
Đo tốc độ hiển thị LCD
Cấu tạo động cơ DC encoder 334
Cách nối dây cho encoder
- Động cơ encoder gồm 2 dây động cơ
(motor), 2 dây cấp nguồn cho encoder
(vcc và gnd) và 2 dây tín hiệu (A,B)
- Nối dây cấp nguồn cho động cơ và
encoder
- Nối chân A hoặc chân B với chân
INT0 của vi điều khiển
Chương trình cho encoder
-
6.2.
Chọn timers/counters
Chọn External interruptschọn INT0
Chọn Alphanumeric LCD như chương trình LCD
Nối dây tương ứng từ PORTA qua LCD, chân A của Encoder qua chân INT0, cấp
nguồn 5V cho Encoder và LCD, cấp nguồn 3-12V cho động cơ DC.
Cách tính tốc độ động cơ
V (vận tốc) = S (vòng)/ t (thời gian)
17
V: vòng/thời gian
T : thời gian đếm xung ( ở đây là 100ms)
S : số xung/ số vạch chia trên 1 vòng
unsigned int xung = 0;
interrupt [EXT_INT0] void ext_int0_isr(void)
{
xung++;
}
Vị dụ:
- Cách tính đo tốc độ động cơ:
+ Trước hết ta dùng Timer để đếm số xung thực hiện trong thời gian Timer. Với
Timer 100ms ta có cách tính sau. Vì là thạch anh 8000Mhz nên số lần đếm trong thời
gian 100ms sẽ bằng: ((8.000.000/256)*100)/1000.
+ Sau khoảng thời gian 100ms ta sẽ có tốc độ động cơ bằng Số xung/100ms. Để
tính ra số vòng quay ta cần chuyển số xung về số vòng và 100ms về phút. Ta lấy Số
Xung/334 vì đĩa quay của Encoder quay 1 vòng được 334 xung. Để đổi 100ms sang 1
phút ta nhân thêm vào 10*60 (Nhân 10 để chuyển sang giây, và nhân thêm 60 để chuyển
sang phút).
Vậy ta có công thức để tính Timer là >3250 và công thức để tính tóc độ động cơ là
(Số Xung/334)*600.
// External Interrupt 0 service routine
unsigned int Xung=0, Dem=0,i=0; //Khai báo biến đếm, đếm xung và i
interrupt [EXT_INT0] void ext_int0_isr(void)
{
Xung++;
//Tăng giá trị xung khi có thay đổi
}
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
Dem++;
if(Dem>3125) //100ms thì ngắt
{
Dem=0; //Trả giá trị đếm về 0
i=Xung; //Gắn giá trị i bằng xung
Xung=0; //Trả giá trị xung về 0
18
}
}
Bài tập: Hiển thị tốc độ động cơ lên LCD
19