Giáo trình Cơ sở và phát triển AVR

BÀI 1 : GIỚI THIỆU VỀ VI ĐIỀU KHIỂN AVR

- Giới thiệu chung về vi điều khiển.

- Giới thiệu về vi điều khiển Atmega32.

- Lập trình cho Atmega32.

1. Giới thiệu về vi điều khiển

Khái niệm vi điều khiển (microcontroller – MC) đã khá quen thuộc với các

sinh viên CNTT, điện tử, điều khiển tự động cũng nhƣ Cơ điện tử Nó là một

trong những IC thích hợp nhất để thay thế các IC số trong việc thiết kế mạch

logic. Ngày nay đã có những MC tích hợp đủ tất cả các chức năng của mạch logic.

Nói nhƣ vậy không có nghĩa là các IC số cũng nhƣ các IC mạch số lập trình đƣợc

khác nhƣ PLC không cần dùng nữa. MC cũng có những hạn chế mà rõ ràng

nhất là tốc độ chậm hơn các mạch logic MC cũng là một máy tính – máy tính

nhúng vì nó có đầy đủ chức năng của một máy tính. Có CPU, bộ nhớ chƣơng

trình, bộ nhớ dữ liệu, có I/O và các bus trao đổi dữ liệu.

pdf 150 trang phuongnguyen 7300
Bạn đang xem 20 trang mẫu của tài liệu "Giáo trình Cơ sở và phát triển AVR", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

Tóm tắt nội dung tài liệu: Giáo trình Cơ sở và phát triển AVR

Giáo trình Cơ sở và phát triển AVR
0 
ĐẠI HỌC BÁCH KHOA HÀ NỘI 
 TRUNG TÂM ĐÀO TẠO TÀI NĂNG VÀ CHẤT LƢỢNG CAO 
GIÁO TRÌNH CƠ SỞ VÀ PHÁT TRIỂN AVR 
 Giảng viên hướng dẫn : PGS.PHAN BÙI KHÔI 
 Sinh viên : NGUYỄN VĂN TOẢN SHSV: 20092792 
 LÊ MINH NGHĨA 20091878 
 DƢƠNG VĂN HÀ 20090882 
 Lớp : KSTN-CƠ ĐIỆN TỬ K54 
HÀ NỘI, 6/2013 
1 
2 
Lời Nói Đầu 
 Với nhiệm vụ được phân công : “ Phát triển Kit vi điều khiển AVR “ trong 
thời gian thực tập kỹ thuật ; bên cạnh những kiến thức sẵn có về vi điều khiển 
AVR, cộng thêm một số tìm hiểu bổ sung nhóm em gồm bạn Lê Minh Nghĩa , 
Dương Văn Hà và Nguyễn Văn Toản đã hoàn thành tốt nhiệm vụ được giao . Cụ 
thể, nhóm đã thực hiện test phần cứng của một số bộ Kit bằng code riêng do nhóm 
tự viết, thêm vào đó nhóm đã thực hiện một số bài toán mở rộng : “ điều khiển 
đèn giao thông ; điều khiển và hiển thị tốc độ động cơ một chiều, nhiệt độ và đồng 
hồ thời gian thực bằng máy tính PC và hiển thị ra LCD;điều khiển động cơ bằng 
phím bấm, nhấn phím và hiển thị vị trí của phím được nhấn” . Nhóm đã củng 
cố , bổ sung lý thuyết và đưa thêm một số ý kiến cải tiến để hoàn thiện bộ giáo 
trình AVR . Toàn bộ công việc nhóm thực hiện đã được trình bày cụ thể trong nội 
dung giáo trình . 
 Qua thời gian thực tập , nhóm em đã thu nhận được rất nhiều kinh nghiệm 
cũng như tác phong làm việc thực tế ; đây thực sự là những kiến thức rất bổ ích 
để nhóm em tiếp cận với môi trường làm việc chuyên nghiệp. Thay mặt nhóm , em 
xin được gửi lời cảm ơn chân thành nhất tới PGS.PHAN BÙI KHÔI và thầy 
PHẠM HỒNG THÁI đã tạo điều kiện cho nhóm em có cơ hội học hỏi và nghiên 
cứu. 
Nhóm em xin chân thành cảm ơn Thầy ! 
3 
Mục Lục 
BÀI 1 : GIỚI THIỆU VỀ VI ĐIỀU KHIỂN AVR ................................................ 5 
1. Giới thiệu về vi điều khiển ........................................................................... 5 
 2. Giới thiệu về vi điều khiển AVR......6 
3. Lập trình cho AVR ...................................................................................... 8 
BÀI 2 : GIAO TIẾP VÀO RA I/O .................................................................. 1414 
1. Giới thiệu giao tiếp vào ra I/O ................................................................. 144 
2. Cách cấu hình chức năng IO .................................................................... 144 
3. Ví dụ minh họa ........................................................................................ 155 
BÀI 3 : GIAO TIẾP VỚI LED 7 THANH ...................................................... 1919 
1. Cơ bản về led 7 thanh ................................................................................ 19 
2. Nguyên lí lập trình cho led 7 thanh .......................................................... 200 
3. Ví dụ minh họa ........................................................................................ 211 
BÀI 4 : GIAO TIẾP VỚI BÀN PHÍM ................................................................ 27 
1. Cơ bản về phím bấm .................................................................................. 27 
2. Chƣơng trình ví dụ..................................................................................... 27 
3. Kĩ thuật chống rung bàn phím.................................................................... 28 
BÀI 5 : BỘ CHUYỂN ĐỔI ADC ....................................................................... 31 
1. Giới thiệu về ADC ................................................................................... 311 
2. Cách cấu hình ADC trong Code Vision cho Atmega32. .......................... 322 
3. Ví dụ minh họa ........................................................................................ 322 
BÀI 6 : GIAO TIẾP LCD ................................................................................... 36 
1. Giới thiệu về LCD 16x2 ............................................................................ 36 
2. Cách cấu hình cho LCD trong Code Vision cho Atmega32 ....................... 50 
3. Bài tập ....................................................................................................... 52 
BÀI 7 : GIAO TIẾP VỚI LED MA TRẬN ......... Error! Bookmark not defined.3 
1. Cơ bản về led ma trận .............................................................................. 533 
2. Tạo font cho led ma trận .......................................................................... 533 
3. Ví dụ minh họa. ....................................................................................... 555 
BÀI 8: GIAO TIẾP MÁY TÍNH ....................................................................... 556 
4 
1. Cơ bản về giao tiếp RS232 ...................................................................... 566 
2. Cách cấu hình module UART trong Code Vision ...................................... 57 
3. Ví dụ.......................................................................................................... 58 
BÀI 9 : GIAO TIẾP I2C .................................................................................... 677 
1. Giới thiệu chung về I2C ........................................................................... 677 
2. Module I
2
C trong Atmega32 .................................................................... 744 
3. Ví dụ.......................................................................................................... 80 
BÀI 10 : ĐỘNG CƠ BƢỚC ............................................................................. 844 
1. Cơ bản về động cơ bƣớc .......................................................................... 844 
2. Các mạch điều khiển động cơ bƣớc ......................................................... 844 
3. Ví dụ........................................................................................................ 888 
BÀI 11 : GIAO TIẾP VỚI CỔNG LPT .............................................................. 90 
1. Cơ bản về cổng LPT .................................................................................. 90 
2. Ví dụ minh họa ........................................................................................ 933 
BÀI 12 : GIAO TIẾP VỚI MA TRẬN PHÍM ................................................... 945 
1. Cơ bản về ma trận phím ........................................................................... 955 
2. Ví dụ minh họa ........................................................................................ 966 
BÀI 13 : TIMER ............................................................................................... 989 
1. Giới thiệu về timer ................................................................................... 999 
2. Ví dụ minh họa ...................................................................................... 1088 
BÀI 14 : NGẮT ............................................................................................ 11111 
1. Giới thiệu về ngắt ................................................................................ 11111 
2. Các bƣớc cấu hình cho ngắt hoạt động ................................................ 11313 
3. Ví dụ.................................................................................................... 11414 
BÀI 15 : ĐIỀU KHIỂN ĐỘNG CƠ MỘT CHIỀU............................................ 117 
1. Giới thiệu về điều khiển động cơ một chiều ............................................. 117 
2. Ví dụ minh họa ........................................................................................ 118 
BÀI 16 : GIAO TIẾP VỚI GLCD..................... Error! Bookmark not defined.20 
1. Cơ bản về GLCD ..................................... Error! Bookmark not defined.20 
2. Ví dụ minh họa ........................................ Error! Bookmark not defined.24 
BÀI TOÁN MỞ RỘNG ...130 
5 
BÀI 1 : GIỚI THIỆU VỀ VI ĐIỀU KHIỂN AVR 
- Giới thiệu chung về vi điều khiển. 
- Giới thiệu về vi điều khiển Atmega32. 
- Lập trình cho Atmega32. 
1. Giới thiệu về vi điều khiển 
Khái niệm vi điều khiển (microcontroller – MC) đã khá quen thuộc với các 
sinh viên CNTT, điện tử, điều khiển tự động cũng nhƣ Cơ điện tử Nó là một 
trong những IC thích hợp nhất để thay thế các IC số trong việc thiết kế mạch 
logic. Ngày nay đã có những MC tích hợp đủ tất cả các chức năng của mạch logic. 
Nói nhƣ vậy không có nghĩa là các IC số cũng nhƣ các IC mạch số lập trình đƣợc 
khác nhƣ PLC không cần dùng nữa. MC cũng có những hạn chế mà rõ ràng 
nhất là tốc độ chậm hơn các mạch logic MC cũng là một máy tính – máy tính 
nhúng vì nó có đầy đủ chức năng của một máy tính. Có CPU, bộ nhớ chƣơng 
trình, bộ nhớ dữ liệu, có I/O và các bus trao đổi dữ liệu. 
Cần phân biệt khái niệm MC với khái niệm vi xử lý (microprocessor – MP) 
nhƣ 8088 chẳng hạn. MP chỉ là CPU mà không có các thành phần khác nhƣ bộ 
nhớ I/O, bộ nhớ. Muốn sử dụng MP cần thêm các chức năng này, lúc này ngƣời ta 
gọi nó là hệ vi xử lý (microprocessor system). Do đặc điểm này nên nếu để lựa 
chọn giữa MC và MP trong một mạch điện tử nào đó thì tất nhiên ngƣời ta sẽ chọn 
MC vì nó sẽ rẻ tiền hơn nhiều do đã tích hợp các chức năng khác vào trong chip. 
Vậy để một vi điều khiển chạy đƣợc thì cần những điều kiện gì : 
- Thứ nhất là nguồn cấp, nguồn cấp là cái đầu tiên, cơ bản nhất trong các mạch 
điện tử, và vấn đề về nguồn là 1 trong những vấn đề rất đau đầu. Không có 
nguồn thì không thể gọi là 1 mạch điện đƣợc. Nguồn cấp cho vi điều khiển là 
nguồn 1 chiều. 
6 
- Thứ hai là mạch dao động, mạch dao động để làm gì ? Giả sử các bạn lập trình 
cho con AVR : đến thời điểm A làm 1 công việc gì đó, thế thì nó lấy cái gì để 
xác định đƣợc thời điểm nào là thời điểm A ? Đó chính là mạch dao động. Ví 
dụ nhƣ mọi ngƣời đều thống nhất vào một giờ chuẩn để làm việc. Cả hệ thống 
vi điều khiển cũng vậy, cả hệ thống khi đó đều lấy xung nhịp clock – xung 
nhịp mạch dao động làm xung nhịp chuẩn để hoạt động. 
- Thứ ba là ngoại vi, ngoại vi ở đây là các thiết bị để giao tiếp với vi điều khiển 
để thực hiện 1 nhiệm vụ nào đó mà vi điều khiển đƣa ra. Ví dụ nhƣ các bạn 
muốn điều khiển động cơ 1 chiều, nhƣng vì vi điều khiển chỉ đƣa ra các mức 
điện áp 0-5V, và dòng điều khiển cỡ mấy chục mA, với nguồn cấp này thì ko 
thể nối trực tiếp động cơ vào vi điều khiển để điều khiển, mà phải qua 1 thiết bị 
khác gọi là ngoại vi, chính xác hơn ở đây là driver, ngƣời ta dùng driver để có 
thể điều khiển đƣợc các dòng điện lớn từ các nguồn điện nhỏ. Các bàn phím, 
công tắc là các ngoại vi. 
- Thứ 4 là chƣơng trình, ở đây là file .hex để nạp cho vi điều khiển, chƣơng trình 
chính là thuật toán mà bạn triển khai thành các câu lệnh rồi biên dịch thành mã 
hex để nạp vào vi điều khiển. 
Các công cụ để học AVR : 
- Ngôn ngữ lập trình : C, ASM 
- Phần mềm lập trình : IAR, CodeVisionAVR 
- Mạch nạp : STK200/300/500, Burn-E 
- Mạch phát triển : Board trắng, phần mềm mô phỏng, kit 
2. Giới thiệu về vi điều khiển AVR. 
AVR là họ vi điều khiển 8 bit theo công nghệ mới, với những tính năng rất 
mạnh đƣợc tích hợp trong chip của hãng Atmel theo công nghệ RISC, nó mạnh 
ngang hàng với các họ vi điều khiển 8 bit khác nhƣ PIC, PSoC. Do ra đời muộn 
hơn nên họ vi điều khiển AVR có nhiều tính năng mới đáp ứng tối đa nhu cầu của 
ngƣời sử dụng, so với họ 8051, 89xx sẽ có độ ổn định, khả năng tích hợp, sự 
mềm dẻo trong việc lập trình và rất tiện lợi. 
Các tính năng mới của họ AVR: 
 Giao diện SPI đồng bộ. 
 Các đƣờng dẫn vào/ra (I/O) lập trình đƣợc. 
 Giao tiếp I2C. 
 Bộ biến đổi ADC 10 bit. 
7 
 Các kênh băm xung PWM. 
 Các chế độ tiết kiệm năng lƣợng nhƣ sleep, stand by..vv. 
 Một bộ định thời Watchdog. 
 3 bộ Timer/Counter 8 bit. 
 1 bộ Timer/Counter 16 bit. 
 1 bộ so sánh analog. 
 Bộ nhớ EEPROM. 
 Giao tiếp USART..vv. 
Atmelga32 có đầy đủ tính năng của họ AVR, về giá thành so với các loại khác 
thì giá thành là vừa phải khi nghiên cứu và làm các công việc ứng dụng tới vi điều 
khiển. Tính năng : 
 Bộ nhớ 32KB Flash có khả năng đọc, ghi 10000 lần 
 1024 byte EEPROM có khả năng đọc, ghi 100000 lần. 
 2KB SRAM. 
 8 kênh đầu vào ADC 10 bit. 
 Đóng vỏ 40 chân , trong đó có 32 chân vào ra dữ liệu chia làm 4 PORT 
A,B,C,D. Các chân này đều có chế độ pull_up resistors. 
 Hỗ trợ các giao tiếp UART, SPI, I2C. 
 1 bộ so sánh analog, 4 kênh PWM. 
 2 bộ timer/counter 8 bit, 1 bộ timer/counter1 16 bit. 
 1 bộ định thời Watchdog. 
8 
Sơ đồ chân Atmega32 
Mô tả chức năng các chân của atmega32 
- Vcc và GND 2 chân cấp nguồn cho vi điều khiển hoạt động. 
- Reset đây là chân reset cứng khởi động lại mọi hoạt động của hệ thống. 
- 2 chân XTAL1, XTAL2 các chân tạo bộ dao động ngoài cho vi điều khiển, các 
chân này đƣợc nối với thạch anh (hay sử dụng loại 4M), tụ gốm (22p). 
- Chân Vref thƣờng nối lên 5v(Vcc), nhƣng khi sử dụng bộ ADC thì chân này 
đƣợc sử dụng làm điện thế so sánh, khi đó chân này phải cấp cho nó điện áp cố 
định, có thể sử dụng diode zener: 
- Chân Avcc thƣờng đƣợc nối lên Vcc nhƣng khi sử dụng bộ ADC thì chân này 
đƣợc nối qua 1 cuộn cảm lên Vcc với mục đích ổn định điện áp cho bộ biến 
đổi. 
3. Lập trình cho AVR 
Giới thiệu 
Để lập trình cho AVR, chúng ta có thể sử dụng 2 ngôn ngữ cơ bản là C và 
ASM. Nhìn chung, 2 ngôn ngữ này có những ƣu và nhƣợc điểm riêng. 
Ngôn ngữ ASM có ƣu điểm là gọn nhẹ, giúp ngƣời lập trình nắm bắt sâu 
hơn về phần cứng. Tuy nhiên lại có nhƣợc điểm là phức tạp, khó triển khai về mặt 
thuật toán, không thuận tiện để xây dựng các chƣơng trình lớn. 
Ngƣợc lại ngôn ngữ C lại dễ dung, tiện lợi, dễ debug, thuận tiện để xây 
dựng các chƣơng trình lớn. Nhƣng nhƣợc điểm của ngôn ngữ C là khó giúp ngƣời 
lập trình hiểu biết sâu về phần cứng, các thanh ghi, tập lệnh của vi điều khiển, hơn 
9 
nữa, xét về tốc độ, chƣơng trình viết bằng ngôn ngữ C chạy chậm hơn chƣơng 
trình viết bằng ngôn ngữ ASM. 
Tùy vào từng bài toán, từng yêu cầu cụ thể mà ta chọn lựa ngôn ngữ lập 
trình cho phù hợp. 
Có rất nhiều phần mềm lập trình cho AVR, nhƣ Code Vision, IAR, 
AVRStudio, trong đó Code Vision là một trong những phần mềm khá nổi tiếng 
và phổ biến. Trong khuôn khổ giáo trình này, chúng ta sẽ sử dụng phần mềm 
Code Vision để lập trình cho AVR. 
Giao diện phần mềm Code Vision 
Tạo project trong Code Vision : 
Để tạo Project mới chọn trên menu: File -> New đƣợc nhƣ sau: 
10 
Chọn Project sau đó click chuột vào OK đƣợc cửa sổ hỏi xem có sử dụng 
Code Winzard không: 
Chọn Yes đƣợc cửa sổ CodeWinzardAVR nhƣ sau : 
11 
- Sử dụng chíp AVR nào và thạch anh tần số bao nhiêu ta nhập vào tab Chip. Để 
khởi tạo cho các cổng IO ta chuyển qua tab Ports. 
- Các chân IO của AVR mặc định trạng thái IN, muốn chuyển thành trạng thái 
OUT để có thể đƣa các mức logic ra ta click chuột vào các nút IN (mầu trắng) 
để nó chuyển thành OUT trong các Tab Port. Sau đó chọn File -> Generate, 
Save and Exit. 
12 
Sau đó ta save project lại : 
Ta đƣợc nhƣ sau : 
13 
Nhƣ vậy là chúng ta đã tạo xong project trong Code Vision. 
14 
BÀI 2 : GIAO TIẾP VÀO RA I/O 
- Cơ bản về gi ... 00; 
// Timer(s)/Counter(s) Interrupt(s) initialization 
TIMSK=0x01; // TOIE0=1, cho phep co ngat khi tran 
// Global enable interrupts 
#asm("sei") 
while (1) 
 { 
 Led11 = 1; Led12 = 0; 
 LED7SEG1 = code[chuc1]; 
 Led11 = 0; Led12 = 1; 
 LED7SEG1 = code[donvi1]; 
 Led21 = 1; Led22 = 0; //PORTD=1; 
 LED7SEG2 = code[chuc1]; 
 Led21 = 0; Led22 = 1; //PORTD=2; 
 LED7SEG2 = code[donvi2]; 
 if ((counter%120)==0) 
 { 
 hien_thi_led(); 
 } 
 };} 
- Mô phỏng trên phần mềm Proteus: 
135 
Bài 3: Điều khiển tốc độ động cơ 1 chiều theo từng mức bằng ma trận bàn phím 
- Sử dụng khả năng xuất xung điều rộng (PWM – Pulse Width Modulation) của 
Atmega32 để điều khiển tốc độ động cơ DC 
- Giải thuật: 
+ Khai báo vào ra cho chip. 
Cài đặt các bit cho timer/counter 1 của mega32 để làm việc ở chế độ xuất 
xung điều rộng. Cụ thể: 
Trong bài toán này: tần số xung nhịp vào ra là 4MHz, Mode 14 (Fast 
PWM) đƣợc sử dụng, chu kì 20ms, do đó prescale của T/C1 đƣợc chọn là 8, 
giá trị TOP là TOP = ICR1=10000. 
Các chân PD4(OCB1), PD5(OCA1) đƣợc khai báo là các đầu ra xuất xung 
PWM. 
PORTB nối với LCD 
PORTA nối với ma trận bàn phím 4x4 
+ Nhận biết phím bấm từ ma trận bàn phím, thay đổi giá trị của các thanh 
ghi OCR1A, OCR1B để có mức điều khiển tƣơng ứng. 
- Lập trình trên phần mềm CodeVision 
#include 
#asm 
 .equ __lcd_port=0x18 ;PORTB 
#endasm 
#include 
#define TOP 10000 
float ratio=0.5; // t/T=ratio 
136 
// Timer 1 overflow interrupt service routine 
interrupt [TIM1_OVF] void timer1_ovf_isr(void) 
{ 
// Place your code here 
} 
// Timer 1 output compare A interrupt service routine 
interrupt [TIM1_COMPA] void timer1_compa_isr(void) 
{ 
// Place your code here 
OCR1A = TOP*ratio; 
} 
// Timer 1 output compare B interrupt service routine 
interrupt [TIM1_COMPB] void timer1_compb_isr(void) 
{ 
// Place your code here 
OCR1B = TOP*ratio; 
} 
// PORTB - LCD 
void main(void) 
{ 
int i,row=0, col=0, phim = -4; 
int phim_old =-4,phim_new =-4; 
char code[]={0xEF, 0xDF, 0xBF, 0x7F}; 
// {1110.1111, 1101.1111, 1011.1111, 0111.1111} 
PORTA=0xFF; 
DDRA=0xF0; // col1-PINA.0, col2-PINA.1,..., ROW1=PORTA.4,ROW2=PORTA.5 
PORTB=0xFF; 
DDRB=0xFF; // PORTB connects with LCD, is ouput 
// Port D initialization 
PORTD=0x00; 
DDRD=0x30; //0011.0000 PORTD.4=OC1B, PORTD.5=OC1A 
// Timer/Counter 1 initialization 
// Clock source: System Clock 
// Clock value: 500.000 kHz, prescale = 8 
// Mode: Fast PWM top=ICR1 , mode = 14 
// OC1A output: Non-Inv. , COM1A1=1,COM1A0=0 
// OC1B output: Non-Inv. , COM1B1=1,COM1B0=0 
// Noise Canceler: Off 
// Input Capture on Falling Edge 
// Timer 1 Overflow Interrupt: On 
// Input Capture Interrupt: Off 
// Compare A Match Interrupt: On 
// Compare B Match Interrupt: On 
TCCR1A=0xA2; //1010.0010 
TCCR1B=0x1A; //0001.1010 
137 
TCNT1H=0x00; // Bottom = 0x0000 
TCNT1L=0x00; 
ICR1H = 0x27; // Top = ICR1 = 0x2710 = 10000 = 10.000*2us = 20ms = Time period 
ICR1L = 0x10; 
OCR1A = TOP*ratio; // 50% 
OCR1B = TOP*ratio; // 50% 
// Timer(s)/Counter(s) Interrupt(s) initialization 
TIMSK=0x1C; 
// Global enable interrupts 
#asm("sei") 
lcd_init(16); 
lcd_putsf("Speed: 50%"); 
while (1) 
 { 
 for (i=0;i<4;i++) 
 { 
 PORTA = code[i]; 
 if (PINA.0 == 0) {row = i+1; col = 1;} //column 1 
 if (PINA.1 == 0) {row = i+1; col = 2;} 
 if (PINA.2 == 0) {row = i+1; col = 3;} 
 if (PINA.3 == 0) {row = i+1; col = 4;} 
 } 
 // xAC dinh phim duoc bam la phim nao 
 phim = 4*row+col-4; 
 phim_new = phim; 
 if (phim >= 0 && phim_new!=phim_old) // co phim duoc bam 
 { 
 if (phim == 1) 
 { 
 ratio = 0.2; 
 lcd_control(1); 
 lcd_putsf("Speed: 20%"); 
 } 
 else { 
 if (phim == 2) 
 { 
 ratio = 0.4; 
 lcd_control(1); 
 lcd_putsf("speed: 40%"); 
 } 
 else { 
 if (phim==3) 
 { 
 ratio = 0.75; 
 lcd_control(1); 
 lcd_putsf("Speed: 75%"); 
 } 
 else 
 { 
 ratio=0.5; 
 lcd_control(1); 
138 
 lcd_putsf("Speed: 50%"); 
 } 
 } 
 } 
 } 
 }; 
} 
- Mô phỏng trên phần mềm Proteus: 
Bài 4: Điều khiển và hiển thị tốc độ động cơ 1 chiều, nhiệt độ, thời gian bằng máy 
tính PC và màn hình LCD. 
- Nội dung: 
Kết hợp các module: điều khiển tốc độ động cơ, đo nhiệt độ bằng LM35, 
đồng hồ thời gian thực DS1307, giao tiếp với máy tính PC, hiển thị trên 
LCD. 
- Ghép nối phần cứng: 
+ LCD nối với PORTB của chip Atmega32 
+ Chân ADC0 (PA0) nối với LM35 
+ 2 chân I2C là SCL và SDA của DS1307 đƣợc nối với 2 chân SCL, SDA 
tƣơng ứng trên vđk. 
+ Cổng comm nối với 2 chân RxD, TxD trên PORTD của Atmega32 
+ Chân AREF đƣợc nối lên nguồn 5V thông qua điện cảm để làm điện áp 
tham chiếu. 
- Giải thuật: 
+ Khai báo đầu vào ra, truyền thông UART, I2C, chuyển đổi ADC với điện 
áp tham chiếu trên chân AREF, các timer/counter0 để làm bộ định thời xử 
lý từng việc, timer/counter 1 dùng để điều khiển tốc độ động cơ 
+ Giao tiếp với máy tính PC thông qua phần mềm Hercule. 
- Chƣơng trình đƣợc thực hiện trên phần mềm CodeVision 
139 
#include 
#include 
// I2C Bus functions 
#asm 
 .equ __i2c_port=0x15 ;PORTC 
 .equ __sda_bit=1 
 .equ __scl_bit=0 
#endasm 
#include 
// My global variables 
#include 
#define TOP 10000 // TOP - timer1 
int timer_counter0=0; // for timer0 
float pwm_ratios=0.5; 
unsigned char h=0,m=0,s=0; // hour, minute, second 
int temperature=0; // gia tri nhiet do duoc chuyen doi 
int setting=0; // setting=0 Normal, setting=1; setting clock, setting=2 setting PWM 
void menu(); 
void menu_clock(); 
void menu_pwm(); 
// Alphanumeric LCD Module functions 
#asm 
 .equ __lcd_port=0x18 ;PORTB 
#endasm 
#include 
#define RXB8 1 
#define TXB8 0 
#define UPE 2 
#define OVR 3 
#define FE 4 
#define UDRE 5 
#define RXC 7 
#define FRAMING_ERROR (1<<FE) 
#define PARITY_ERROR (1<<UPE) 
#define DATA_OVERRUN (1<<OVR) 
#define DATA_REGISTER_EMPTY (1<<UDRE) 
#define RX_COMPLETE (1<<RXC) 
// USART Receiver buffer 
#define RX_BUFFER_SIZE 8 
char rx_buffer[RX_BUFFER_SIZE]; 
#if RX_BUFFER_SIZE<256 
unsigned char rx_wr_index,rx_rd_index,rx_counter; 
#else 
unsigned int rx_wr_index,rx_rd_index,rx_counter; 
#endif 
// This flag is set on USART Receiver buffer overflow 
140 
bit rx_buffer_overflow; 
// USART Receiver interrupt service routine 
interrupt [USART_RXC] void usart_rx_isr(void) 
{ 
char status,data; 
status=UCSRA; 
data=UDR; 
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0) 
 { 
 rx_buffer[rx_wr_index]=data; 
 if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0; 
 if (++rx_counter == RX_BUFFER_SIZE) 
 { 
 rx_counter=0; 
 rx_buffer_overflow=1; 
 }; 
 }; 
} 
#ifndef _DEBUG_TERMINAL_IO_ 
// Get a character from the USART Receiver buffer 
#define _ALTERNATE_GETCHAR_ 
#pragma used+ 
char getchar(void) 
{ 
char data; 
while (rx_counter==0); 
data=rx_buffer[rx_rd_index]; 
if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0; 
#asm("cli") 
--rx_counter; 
#asm("sei") 
return data; 
} 
#pragma used- 
#endif 
// USART Transmitter buffer 
#define TX_BUFFER_SIZE 8 
char tx_buffer[TX_BUFFER_SIZE]; 
#if TX_BUFFER_SIZE<256 
unsigned char tx_wr_index,tx_rd_index,tx_counter; 
#else 
unsigned int tx_wr_index,tx_rd_index,tx_counter; 
#endif 
// USART Transmitter interrupt service routine 
interrupt [USART_TXC] void usart_tx_isr(void) 
{ 
if (tx_counter) 
 { 
 --tx_counter; 
141 
 UDR=tx_buffer[tx_rd_index]; 
 if (++tx_rd_index == TX_BUFFER_SIZE) tx_rd_index=0; 
 }; 
} 
#ifndef _DEBUG_TERMINAL_IO_ 
// Write a character to the USART Transmitter buffer 
#define _ALTERNATE_PUTCHAR_ 
#pragma used+ 
void putchar(char c) 
{ 
while (tx_counter == TX_BUFFER_SIZE); 
#asm("cli") 
if (tx_counter || ((UCSRA & DATA_REGISTER_EMPTY)==0)) 
 { 
 tx_buffer[tx_wr_index]=c; 
 if (++tx_wr_index == TX_BUFFER_SIZE) tx_wr_index=0; 
 ++tx_counter; 
 } 
else 
 UDR=c; 
#asm("sei") 
} 
#pragma used- 
#endif 
// Standard Input/Output functions 
#include 
// Timer 1 overflow interrupt service routine 
interrupt [TIM1_OVF] void timer1_ovf_isr(void) 
{ 
// Reinitialize Timer 1 value 
//TCNT1H=0x2710 >> 8; 
//TCNT1L=0x2710 & 0xff; 
// Place your code here 
} 
// Timer 1 output compare A interrupt service routine 
interrupt [TIM1_COMPA] void timer1_compa_isr(void) 
{ 
// Place your code here 
} 
// Timer 1 output compare B interrupt service routine 
interrupt [TIM1_COMPB] void timer1_compb_isr(void) 
{ 
// Place your code here 
} 
#include 
142 
#define FIRST_ADC_INPUT 0 
#define LAST_ADC_INPUT 7 
unsigned int adc_data[LAST_ADC_INPUT-FIRST_ADC_INPUT+1]; // du lieu ADC duoc 
chuyen doi, nhiet do t=500*acd/1023 
#define ADC_VREF_TYPE 0x00 
// ADC interrupt service routine 
// with auto input scanning 
interrupt [ADC_INT] void adc_isr(void) 
{ 
static unsigned char input_index=0; 
// Read the AD conversion result 
adc_data[input_index]=ADCW; 
// Select next ADC input 
if (++input_index > (LAST_ADC_INPUT-FIRST_ADC_INPUT)) 
 input_index=0; 
ADMUX=(FIRST_ADC_INPUT | (ADC_VREF_TYPE & 0xff))+input_index; 
// Delay needed for the stabilization of the ADC input voltage 
delay_us(10); 
// Start the AD conversion 
ADCSRA|=0x40; 
} 
// Timer 0 overflow interrupt service routine 
// Chia khoang thoi gian thuc hien cac cong viec 
interrupt [TIM0_OVF] void timer0_ovf_isr(void) 
{ 
char str2[5],str[3]; 
// Reinitialize Timer 0 value 
TCNT0=0x65; //0x65=101d, 256-101=155*16us=1.68ms 
// Place your code here 
timer_counter0++; 
if (timer_counter0==595) // 1s, update time, ds1307 
 { 
 rtc_get_time(&h,&m,&s); 
 timer_counter0=0; 
 } 
if (timer_counter0%5==0) // update temperature, 5*1.68=8.64ms for convertsion ADC 
 { 
 temperature = 500*adc_data[0]/1023; 
 } 
if (timer_counter0%500==0) // update pwm_ratio 
 { 
 OCR1A = TOP*pwm_ratios; 
 OCR1B = TOP*pwm_ratios; 
 } 
if (timer_counter0 %550==0) //display LCD 
 { 
 if (setting==0) //lcd_control(1); 
 { 
 lcd_clear(); 
 lcd_putsf("Temp: "); 
 itoa(temperature,str); 
143 
 lcd_puts(str); 
 lcd_putsf(" oC"); 
 lcd_gotoxy(0,1); 
 lcd_putsf("PWM: "); 
 ftoa(100*pwm_ratios,2,str2); 
 lcd_puts(str2); 
 lcd_putsf(" %"); 
 } 
 if (setting==1) 
 { 
 lcd_clear(); 
 lcd_putsf("Setting...time!"); 
 } 
 if (setting==2) 
 { 
 lcd_clear(); 
 lcd_putsf("Setting...PWM!"); 
 } 
 } 
} 
void main(void) 
{ 
unsigned char hh=0,mm=0,ss=0; 
char c=27,c_clock=27,c_pwm=27; 
unsigned char d,mth,y; 
// Declare your local variables here 
PORTA=0x00; 
DDRA=0x00; 
PORTB=0x00; 
DDRB=0x00; 
PORTC=0x00; 
DDRC=0x00; 
PORTD=0x00; 
DDRD=0x30; //0011.0000 PORTD.4-OC1B, PORTD.5-OC1A as output for PWM 
// Timer/Counter 0 initialization 
// Clock source: System Clock 
// Clock value: 62.500 kHz, 4M/64, prescale=64, 64/4M=16us*105=1.68ms 
// Mode: Normal top=FFh 
// OC0 output: Disconnected 
TCCR0=0x03; 
TCNT0=0x65; 
OCR0=0x00; 
// Timer/Counter 1 initialization 
// Clock source: System Clock 
// Clock value: 500.000 kHz, prescale = 8 
// Mode: Fast PWM top=ICR1 , mode = 14 
144 
// OC1A output: Non-Inv. , COM1A1=1,COM1A0=0 
// OC1B output: Non-Inv. , COM1B1=1,COM1B0=0 
// Noise Canceler: Off 
// Input Capture on Falling Edge 
// Timer 1 Overflow Interrupt: On 
// Input Capture Interrupt: Off 
// Compare A Match Interrupt: On 
// Compare B Match Interrupt: On 
TCCR1A=0xA2; //1010.0010 
TCCR1B=0x1A; //0001.1010 
TCNT1H=0x00; // Bottom = 0x0000 
TCNT1L=0x00; 
ICR1H = TOP >> 8; // Top = ICR1 = 0x2710 = 10000 = 10.000*2us = 20ms = Time 
period 
ICR1L = TOP & 0xFF; 
OCR1A = TOP*pwm_ratios; // 50% 
OCR1B = TOP*pwm_ratios; // 50% 
// Timer/Counter 2 initialization 
// Clock source: System Clock 
// Clock value: Timer 2 Stopped 
// Mode: Normal top=FFh 
// OC2 output: Disconnected 
ASSR=0x00; 
TCCR2=0x00; 
TCNT2=0x00; 
OCR2=0x00; 
// External Interrupt(s) initialization 
// INT0: Off 
// INT1: Off 
// INT2: Off 
MCUCR=0x00; 
MCUCSR=0x00; 
// Timer(s)/Counter(s) Interrupt(s) initialization 
TIMSK=0x1D; 
// USART initialization 
// Communication Parameters: 8 Data, 1 Stop, No Parity 
// USART Receiver: On 
// USART Transmitter: On 
// USART Mode: Asynchronous 
// USART Baud Rate: 9600 
UCSRA=0x00; 
UCSRB=0xD8; 
UCSRC=0x86; 
UBRRH=0x00; 
UBRRL=0x19; 
// Analog Comparator initialization 
// Analog Comparator: Off 
145 
// Analog Comparator Input Capture by Timer/Counter 1: Off 
ACSR=0x80; 
SFIOR=0x00; 
// ADC initialization 
// ADC Clock frequency: 31.250 kHz 
// ADC Voltage Reference: AREF pin 
ADMUX=FIRST_ADC_INPUT | (ADC_VREF_TYPE & 0xff); 
ADCSRA=0xCF; 
// I2C Bus initialization 
i2c_init(); 
rtc_set_time(12,12,12); 
rtc_set_date(23,6,13); 
// LCD module initialization 
lcd_init(16); 
lcd_putsf("Welcome"); 
delay_ms(100); 
rtc_get_time(&h,&m,&s); 
menu(); 
// Global enable interrupts 
#asm("sei") 
while (1) 
 { 
 // Place your code here 
 c_pwm=27;c_clock=27;c=27; 
 c = getchar(); 
 if (c=='0') 
 { 
 printf("\n-------Menu------\n"); 
 c=27; 
 menu(); 
 } 
 if (c=='1') 
 { 
 printf("\n-------Clock------\n"); 
 menu_clock(); 
 do 
 { 
 c_clock=getchar(); 
 if (c_clock=='0') 
 { 
 rtc_get_time(&h,&m,&s); 
 rtc_get_date(&d,&mth,&y); 
 printf("\n Time:%d:%d:%d , Date: %d/%d/%d\n",h,m,s,d,mth,y); 
 c_clock=27; 
 menu_clock(); 
 } 
 if (c_clock=='1') 
 { 
146 
 printf("Setting time\n"); 
 setting=1; // setting time for display LCD 
 printf("Hour = "); 
 scanf("%d",&hh); 
 printf("\nMinute = "); scanf("%d",&mm); 
 printf("\nSecond = "); scanf("%d",&ss); 
 i2c_init(); 
 rtc_set_time(hh,mm,ss); 
 setting=0; 
 c_clock=27; 
 menu_clock(); 
 } 
 } 
 while (c_clock=='0' || c_clock=='1' || c_clock==27); 
 } 
 if (c=='2') 
 { 
 printf("\nTemperature is: %d",temperature); 
 c=27; 
 menu(); 
 } 
 if (c=='3') 
 { 
 printf("\n----------PWM--------\n"); 
 menu_pwm(); 
 do 
 { 
 c_pwm=getchar(); 
 if (c_pwm=='0') 
 { 
 printf("\nPWM: %f percent",pwm_ratios); 
 c_pwm=27; 
 menu_pwm(); 
 } 
 if (c_pwm=='1') 
 { 
 setting=2; //setting pwm for display LCD 
 printf("\nSetting PWM"); 
 printf("\npwm_ratios = "); 
 scanf("%f",&pwm_ratios); 
 setting=0; 
 c_pwm=27; 
 menu_pwm(); 
 } 
 } 
 while (c_pwm=='0' || c_pwm=='1' || c_pwm==27); 
 } 
 }; 
} 
void menu() 
{ 
 printf("Press 0: Menu\n"); 
147 
 printf("Press 1: Clock\n"); 
 printf("Press 2: Temperature.\n"); 
 printf("Press 3: PWM...\n"); 
} 
void menu_clock() 
{ 
 printf("Press 0: Show time and date\n"); 
 printf("Press 1: Setting time and date\n"); 
 printf("Press 2: Exit.\n"); 
} 
void menu_pwm() 
{ 
 printf("Press 0: Show PWM\n"); 
 printf("Press 1: Setting PWM\n"); 
 printf("Press 2: Exit.\n"); 
} 
- Mô phỏng trên phần mềm proteus 
148 
- 
149 
Tài liệu tham khảo 
1. Datasheet ATmega8 , ATmega 32 ( ATmel Co. ) . 
2. Datasheet DS1307, LED 7seg , 74HC_HCT595_CNV ,.. 
3. Kỹ thuật vi xỷ lý ( Văn Thế Minh ). 
4. Kỹ thuật vi xử lý và lập trình cho hệ vi xử lý ( Đỗ Xuân Tiến). 
5. HocAVR.com . 

File đính kèm:

  • pdfgiao_trinh_co_so_va_phat_trien_avr.pdf