intTypePromotion=1
zunia.vn Tuyển sinh 2024 dành cho Gen-Z zunia.vn zunia.vn
ADSENSE

Cùng nghiên cứu AVR

Chia sẻ: Nd Khuong | Ngày: | Loại File: PDF | Số trang:219

460
lượt xem
213
download
 
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

AVR là một họ vi điều khiển do hãng Atmel sản xuất (Atmel cũng là nhà sản xuất dòng vi điều khiển 89C51 mà có thể bạn đã từng nghe đến). AVR là chip vi điều khiển 8 bits với cấu trúc tập lệnh đơn giản hóa-RISC(Reduced Instruction Set Computer), một kiểu cấu trúc đang thể hiện ưu thế trong các bộ xử lí.

Chủ đề:
Lưu

Nội dung Text: Cùng nghiên cứu AVR

  1. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE CÙNG NGHIÊN CỨU AVR Ntinside 1
  2. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE BÀI 1 - LÀM QUEN AVR 3 BÀI 2 - CẤU TRÚC AVR 14 BÀI 3 - NGẮT NGOÀI 27 BÀI 4 – TIMER - COUNTER 40 BÀI 5 – GIAO TIẾP UART 64 BÀI 6 - CHUYỂN ĐỔI ADC 81 BÀI 7 – GIAO TIẾP SPI 97 BÀI 8 – GIAO TIẾP TWI - I2C 110 BÀI 9 - KEYPAD 138 BÀI 10 - TEXT LCD 144 BÀI 11 - GRAPHIC LCD 171 BÀI 12 - C CHO AVR 199 BÀI 13 - THIẾT LẬP FUSE BIT 211 Ntinside 2
  3. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE Bài 1 - Làm quen AVR I. Giới thiệu. AVR là một họ vi điều khiển do hãng Atmel sản xuất (Atmel cũng là nhà sản xuất dòng vi đ iều khiển 89C51 mà có thể bạn đã từng nghe đến). AVR là chip vi điều khiển 8 bits với cấu trúc tập lệnh đơn giản hóa-RISC(Reduced Instruction Set Computer), một kiểu cấu trúc đang thể h iện ưu thế trong các bộ xử lí. Tại sao AVR: so với các chip vi điều khiển 8 bits khác, AVR có nhiều đặc tính hơn hẳn, hơn cả trong tính ứng dụng (dễ sử dụng) và đặc biệt là về chức năng: Gần nh ư chúng ta không cần mắc thêm bất kỳ linh kiện phụ nào khi • sử dụng AVR, thậ m chí không cần nguồn tạo xung clock cho chip (thường là các khối thạch anh). Thiết b ị lập trình (mạch nạp) cho AVR rất đơn giản, có loại mạch nạp • chỉ cần vài điện trở là có thể làm được. một số AVR còn hỗ trợ lập trình on – chip bằng bootloader không cần mạch nạp… Bên cạnh lập trình bằng ASM, cấu trúc AVR được thiết kế tương • thích C. Nguồn tài nguyên về source code, tài liệu, application note…rất lớn • trên internet. Hầu hết các chip AVR có những tính năng (features) sau: • Có thể sử dụng xung clock lên đến 16MHz, hoặc s ử dụng xung clock nội lên đến 8 MHz (sai số 3 %) Bộ nhớ ch ương trình Flash có thể lập trình lại rất nhiều lần và dung lượng lớn, có SRAM (Ram tĩnh) lớn, và đặc biệ t có bộ nhớ lưu trữ lập trình được EEPROM. Bộ nhớ ch ương trình Flash có thể lập trình lại rất nhiều lần và dung lượng lớn, có SRAM (Ram tĩnh) lớn, và đặc biệ t có bộ nhớ lưu trữ lập trình được EEPROM. Nhiều ngõ vào ra (I/O PORT) 2 hướng (bi-directional). 8 bits, 16 bits timer/counter tích hợp PWM. Các bộ chuyể n đối Analog – Digital phân giải 10 bits, nhiều kênh. Ntinside 3
  4. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE Chức năng Analog comparator. Giao diện nối tiế p USART (tương thích chuẩn nối tiếp RS- 232). Giao diện nối tiế p Two –Wire –Serial (tương thích chuẩn I2C) Master và Slaver. Giao diện nối tiế p Serial Peripheral Interface (SPI) ... Một số chip AVR thông dụng: AT90S1200 AT90S2313 AT90S2323 and AT90S2343 AT90S2333 and AT90S4433 AT90S4414 and AT90S8515 AT90S4434 and AT90S8535 AT90C8534 ATtiny10, ATtiny11 and ATtiny12 ATtiny15 ATtiny22 ATtiny26 ATtiny28 ATmega8/8515/8535 ATmega16 ATmega161 ATmega162 ATmega163 ATmega169 ATmega32 ATmega323 ATmega103 ATmega64/128/2560/2561 AT86RF401. .... Trong bài viết này tôi sử dụng chip ATmega8 để làm ví dụ, tôi chọn ATmega8 vì đây là loạ i chip thuộc dòng AVR mới nhất, nó có đầy đủ các Ntinside 4
  5. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE tính nă ng của AVR nhưng lại nhỏ gọn (gói PDIP có 28 chân) và low cost nên các bạn có thể mua để tự mình tạo ứng dụng. Tại sao Assembly (ASM): bạn có thể không cần biết về cấu trúc của AVR vẫn có thể lập trình cho AVR bằng các phần mềm hỗ trợ ngôn ngữ cấp cao như BascomAVR (Basic) hay CodevisionAVR (C), tuy nhiên đó không phải là mục đích của bài viết này. Để h iểu thấu đáo về AVR bạn phải lập trình bằng chính ngôn ngữ của nó, ASM. Như vậ y lập trình bằng ASM giúp bạn hiểu tường tận về AVR, và tất nhiên để lập trình được bằng ASM bạn phải hiểu về cấu trúc AVR….Một lý do khác bạn mà tôi khuyên bạn nên lập trình bằng ASM là các trình dịch (compiler) ASM cho AVR là hoàn toàn miễ n phí, và nguồn source code cho AVR viết bằng ASM là rất lớn. Tuy nhiên một khi bạn đã thành thạo AVR và ASM bạn có thể sử dụng các ngôn ngữ cấp cao như C để viết ứng dụng vì ưu điểm của ngôn ngữ cấp cao là giúp bạn dễ dàng thực hiện các phép toán đại số 16 hay 32 bit (vốn là vấn đề khó khăn khi lập trình bằng ASM). II. Công cụ . Trình biên dịch: có rất nhiều trình biên dịch bạn có thể sử dụng đế biên dịch code của bạn thành file intel hex để nạp vào chip, một số trình dịch quen thu ộc có thể kể đến nh ư sau: • AvrStudio: là trình biên dịch ASM chính th ức cung cấp bởi Atmel, đây là trình biên dịch hoàn toàn miễn phí và tất nhiên là tốt nhất cho lập trình AVR bằng ASM. Phiên bản hiện tại là 4.18 SP1, bạn có thể download ph ần mềm AvrStudio tạitrang web chính thức của Atmel h oặc bản 4.623 tại đ ây. • Wavrasm: cũng được cung cấp bở i Atmel, nó chính là tiền thân củ a AvrStudio. Hiện tại wavrasm không còn đượ c sử dụng nhiều vì so với AvrStudio trình biên d ịch này có nhiều h ạng chế, nếu bạn quan tâm có thể d ownload tại đây. • WinAVR hay avr-gcc: là bộ trình d ịch đượ c phát triển bởi gnu, ngôn ngữ sử dụng là C và có th ể đượ c dùng tích hợp với AvrStudio (dùng Avrstudio làm trình biên tập – editor). Đặc biệt bộ biên d ịch này cũ ng miễn phí và đa số n gu ồn source code C được viết bằng bộ này, vì vậy nó rất lí tưởng cho bạn khi viết các ứng dụng chuyên nghiệp. Việc lập trình bằng avrgcc tôi sẽ đ ề cập trong những ph ần sau. • CodeVisionAvr: một ch ương trình bằng ngôn ngữ C rất hay cho AVR, h ỗ trợ nhiều thư viện lập trình. Tuy nhiên là chương trình thương mại. Bạn có thể d ownload bản demo (đầy đủ chức năng nhưng nhưng giới hạn dung lượng bộ nhớ ch ương trình 2KB) tại Website hpinfotech ICCAVR: lập trình C cho avr, download bản demo. • • BascomAVR: lập trình cho AVR bằng basic, đ ây là trình biên dịch khá hay và dễ sử dụng, h ỗ trợ rất nhiều thư viện. Tuy nhiên rất khó debug lỗi và không thích hợp cho việc tìm hiểu AVR. Vì vậy tôi không bạn khuyến khích bạn sử dụng trình dịch này. Bạn có thể download bản demo (4K limit). Ntinside 5
  6. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE • Và còn rất nhiều trình biên d ịch khác cho AVR mà tôi không kể ra đ ây, nhìn chung tất cả các trình biên dịch này h ỗ trợ C hoặc Basic hoặc thậm chí Pascal. Việc ch ọn 1 trình biên d ịch tùy thuộc vào mụ c đ ích, vào mức độ ứng dụng, vào kinh nghiệm sử dụng và nhiều lý do khác n ữa. Ví dụ tôi thường dùng Avrstudio và avrgcc khi học sử dụng AVR và khi viết th ư viện. Nhưng khi cần viết ch ương trình ứng dụng tôi thường chọn avrgcc và CodeVisionAVR. Trong bài viết này tôi hướng dẫn bạn sử dụng AvrStudio để viế t chương trình cho AVR bằng ASM. Chương trình nạ p (Chip Programmer): đa số các trình biên dịch (AvrStudio, CodeVisionAVR, Bascom…) đều tích hợp sẵn 1 chương trình nạp chip hỗ trợ nhiều loại mạch nạp nên bạn không quá lo lắng. Trong trường hợp khác, bạn có thể sử dụng các chương trình nạp như Icprog hay Ponyprog…là các ch ương trình nạp miễn phí cho AVR. Việc chọn và sử dụng chương trình nạp sẽ được giới thiệu trong các bài sau. Mạch nạp: tham khảo bài viết giới thiệu mạch nạp AVR. Chương trình mô phỏng: avr simulator là trình mô phỏng và debbug được tích hợp sẵn trong Avrstudio, avr simulator cho phép bạn quan sát trạng thái các thanh ghi bên trong AVR nên rất phù hợp để bạn debug chương trình. Proteus là chương trình thứ hai tôi muốn nói đến, Proteus không những mô phỏng hoạt động bên trong chip mà còn mô phỏng mạch điện tử. Proteus mô phỏng rất trực quan, nó là 1 công cụ hữu ích khi các bạn chưa có điều kiện làm các mạch điện tử. III. Ví dụ đầu tiên của bạn. Sau khi download AvrStudio, bạn hãy cài đăt phần mềm trên máy của bạn, quá trình cài đặt rất đơn giản, bạn hãy theo các mặc định và nhấn “next” để cài đặt. Trong bài đầu tiên này chúng ta sẽ viết thử 1 chương trình đơn giản cho AVR sau đó chạy mô phỏng bằng Proteus. Có thể có một số câu lệnh các bạn sẽ không hiểu, nhưng đừng lo lắng quá, trong bài thứ 2 chúng ta sẽ học về cấu trúc AVR các bạn sẽ được giải thich rõ hơn. Để thực hiện ví dụ này, bạn hãy tạo một Project bằng AVRStudio, phần hướng dẫn chi tiết cho việc tạo Project trong AVRStudio bạn hãy tham khảo ở bài hướng dẫn AVRStudio.Đoạn code ví dụ trong bài đầu tiên này được trình bày trong List1. List 1. Đoạn code đầu tiên của bạn. 1 .CSEG 2 .INCLUDE "M8DEF.INC" Ntinside 6
  7. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE 3 .ORG 0x000 4 RJMP BATDAU 5 6 .ORG 0x020 7 BATDAU: 8 ; KHOI TAO CAC DIEU KIEN DAU 9 LDI R16, HIGH(RAMEND) 10 LDI R17, LOW(RAMEND) 11 OUT SPH, R16 12 OUT SPL, R17 13 LDI R16, 0xFF; 14 OUT DDRB, R16 15 16 ; CHUONG TRINH CHINH 17 MAIN: 18 LDI R16, 0B00000001 19 OUT PORTB, R16 20 RCALL DELAY 21 22 LDI R16, 0B00000010 23 OUT PORTB, R16 24 RCALL DELAY 25 26 LDI R16, 0B00000100 27 OUT PORTB, R16 28 RCALL DELAY 29 30 LDI R16, 0B00001000 31 OUT PORTB, R16 32 RCALL DELAY 33 34 LDI R16, 0B00010000 35 OUT PORTB, R16 36 RCALL DELAY 37 38 LDI R16, 0B00100000 39 OUT PORTB, R16 40 RCALL DELAY 41 Ntinside 7
  8. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE 42 LDI R16, 0B01000000 43 OUT PORTB, R16 44 RCALL DELAY 45 46 LDI R16, 0B10000000 47 OUT PORTB, R16 48 RCALL DELAY 49 50 RJMP MAIN 51 ; CHUONG TRING CON DELAY 65535 chu ky (khoang 65535us 52 neu xung ;clock cho chip la 1M) 53 DELAY: 54 LDI R20, 0xFF 55 DELAY0: 56 LDI R21, 0xFF 57 DELAY1: 58 DEC R21 59 BRNE DELAY1 60 DEC R20 61 BRNE DELAY0 RET Trước khi tìm hiểu ý nghĩa đoạn code, hãy nhìn 1 lượt qua đoạn code. Trước hết việc viết HOA hay viết thường là không quan trọng, bạn có thể viết đoạn code với bất cứ hình thức nào miễn đúng cú pháp, từ khóa là được. Trong đoạn code: • Bạn thấy 1 số từ có màu BLUE (ví dụ LDI, OUT, RJMP, RCALL, RET…)đó là các INSTRUCTiON, tức là các câu lệnh của ngôn ngữ ASM, bạn có thể đọc tài liệu “AVR INSTRUCTION” đ ể tìm hiểu tất cả các INSTRUCTION. Các INSTRUCTION sau đó sẽ được trình d ịch dịch thành các mã tương ứng. • Một số từ bắt đ ầu bằng bằng dấu ch ấm “.” là các DIRECTIVE (ví dụ .INCLUDE hay .ORG )đó cũng là những từ khóa mặc định của ASM AVR, các DIRECTIVE không phải là mã lệnh mà ch ỉ là các chỉ dẫn về địa chỉ bộ nhớ, khở i động bộ nhớ , đ ịnh ngh ĩa macro…và không được trình dịch dịch thành mã. Chi tiết về DIRECTIVE có th ể tìm th ấy trong các tài liệu về ASM AVR, dưới đây tôi tóm tắt các DIRECTIVE và chức năng của chúng như sau: Ntinside 8
  9. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE • Thông thường 1 INSTRUCTION đ ượ c theo sau bởi 2 toán h ạng – operand (tuy nhiên có nhiều trường hợ p chỉ có 1 toán h ạng hoặc không có toán h ạng), khi đó toán hạng thứ nh ất sẽ là các THANH GHI. của AVR (như đã đ ề cập, chúng ta sẽ kh ảo sát thanh ghi AVR trong các bài sau), ví dụ : “LDI R16, 0xFF;” trong đó toán hạng “R16” là tên 1 thanh ghi trong AVR, và “0xFF” là 1 hằng số d ạng hexadecimal có giá trị tương ứng là 255 dạng th ập phân hay 11111111 nhị phân. • Các từ theo sau bởi d ấu “:” là các nhãn – label (ví d ụ MAIN, DELAY…), đó là từ d o chúng ta tự đặt, nó th ực ch ất là 1 vị trí trong bộ nhớ chương trình, có th ể sử dụng nhãn như 1 chương trình con. • Ph ần đ i sau d ấu “;” gọi là giải thích – comment, phần này không được biên dịch, bạn có thể ghi comment ở bất cứ đ âu trong chương trình với yêu cầu phải sử dụng d ấu “;” trước nó. Giả i thích đoạ n code:có thể chia đoạn code trên thành 4 phần: phần đầu chứa các DIRECTIVE và lệnh RJMP dùng để xác định các đ ịa chỉ bộ nhớ chương trình, phần 2 là khởi tạo một số điều kiện đầu cho Stack Pointer và PORT, phần 3 là chương trình chính, và phần 4 là chương trình con ( chú ý đây chỉ là cách bố trí của riêng tôi, một khi đã quen thuộc, bạn có thể bố trí chương trình theo cách riêng của bạn). Phần 1 và phần 2: • .CSEG Ch ỉ thị .CSEG: Code Segment báo cho trình biên dịch rằng ph ần code theo sau là phần chương trình thực thi, ph ần này sẽ được download vào bộ nhớ chương trình của chip. Ntinside 9
  10. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE .INCLUDE "M8DEF.INC" Ch ỉ thị .INCLUDE báo cho trình biên dịch bắt đầu đọc 1 file đính kèm, trong trường hợp trên là file “M8DEF.INC”, đây là file chứa các khai báo cho chip Atmega8 như thanh ghi, ngắt…cho việc truy xuất trong chương trình của bạn, đ ây là dòng bắt bu ộc, nếu bạn lập trình cho chip khác bạn hãy đổi tên file đính kèm, ví dụ “m32def.inc” cho chip ATmega32… bạn có thể tìm thấy các file này trong thư mụ c “C:\Program Files\Atmel\AVR Tools\AvrAssembler2\Appnotes”. .ORG 0x000 Ch ỉ thị .ORG: Set Program Origin, set vị trí trong bộ nhớ sẽ đượ c tác đ ộng đến, trong trường hợ p trên, .ORG 0x000 xác đ ịnh ph ần code theo ngay sau sẽ nằm ở địa ch ỉ 000, vị trí đầu tiên, trong bộ nhớ chương trình. Và dòng lênh trong vị trí đầu tiên đó là: RJMP BATDAU RJMP: Relative Jump là lệnh nh ảy không điều kiện đến 1 vị trí trong bộ nhớ, trong trường hợp trên là nhảy đ ến nhãn BATDAU, và nhãn BATDAU nằm ở vị trí 0x020 (số hexadecimal, 0x020 =32 decimal) vì nó được khai báo ngay sau DIRECTIVE .ORG 0x020. .ORG 0x020 BATDAU Nh ư thế phần bộ nhớ chương trình n ằm giữa 0 và 0x020 không được sử dụng trong đoạn code của chúng ta, phần này đ ượ c sử dụng cho mục đ ích khác, đó là các vectơ n gắt ( không đượ c đ ề cập ở đ ây). Ti ếp theo: ; KHOI TAO CÁC DIEU KIEN DAU LDI R16, HIGH(RAMEND) LDI R17, LOW(RAMEND) OUT SPH, R16 OUT SPL, R17 Bốn dòng code trên khở i tạo cho Stack Pointer, chúng ta sẽ tìm hiểu phần này trong các bài về Stack và chương trình con. Lờ i khuyên: các bạn nên khở i đ ộng 1 chươ ng trình theo cách trên và chúng ta sẽ hiểu chúng rõ hơn sau này ! LDI R16, 0xFF OUT DDRB, R16 Ntinside 10
  11. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE Bạn chú ý 2 dòng trên và những gì tôi giải thích sau đây, 2 dòng này có tác d ụng khởi động PORTB của chip ATmega8 tác d ụng như các ngõ xuất tín hiệu (OUTPUT). Trước h ết hãy quan sát chip ATmega8 trong hình sau Hình 1: chip ATmega8. Bạn có thể thấy chip này gồm 28 chân, trông đó có các chân đ ượ c ghi là PB0(chân 14), PB1(chân 15),…,PB7(chân 10), đó là các chân của PORTB. PORT là khái niệm chỉ các ngõ xuất nhập. Trong AVR, PORT có th ể giao tiếp theo 2 hướng (bi – directional), có thể dùng để xu ất hoặc nhận thông tin, mỗi PORT có 8 chân. Chip Atmega8 có 3 PORT có tên tương ứng là PORTB, PORTC và PORTD (một số chip AVR khác có 4 hoặc 6 PORT). PORT đượ c coi là “cửa ngõ” then ch ốt củ a vi đ iều khiển. Trong AVR, mỗi PORT liên quan đ ến 3 thanh ghi (8 bits) có tên tương ứng là DDRx, PINx, và PORTx với “x” là tên của PORT, mỗi bit trong thanh ghi tương ứng vớ i mỗi chân củ a PORT. Trong trường hợ p củ a Atmega8 “x” là B, C hoặc D. Ví dụ chúng ta quan tâm đ ến PORTB thì 3 thanh ghi tương ứng có tên là DDRB, PINB và PORTB, trong đó 2 thanh ghi PORTB và PINB đượ c n ối trực tiếp vớ i các chân củ a PORTB, DDRB là thanh ghi điều khiển h ướng ( Input hoặc Output). Viết giá trị 1 vào một bit trong thanh ghi DDRB thì chân tương ứng của PORTB sẽ là chân xu ất (Output), ngược lại giá trị 0 xác lập chân tương ứng là ngõ nhập. Sau khi viết giá trị điều khiển vào DDRB, việc truy xuất PORTB đượ c thực hiện thông qua 2 thanh ghi PINB và PORTB. Quay lại với 2 dòng code của chúng ta, dòng đầu: “LDI R16, 0xFF”, với LDI – LoaD Immediately, dòng lệnh có ý ngh ĩa là load giá trị 0xFF vào thanh ghi R16, R16 là tên 1 thanh ghi trong bộ nhớ của AVR, 0xFF là 1 h ằng số có dạng thập lục phân, ký hiệu “0x” nói lên điều đó, bạn cũng có th ể dùng ký hiệu khác là “$” để ch ỉ 1 số thập lục phân, ví dụ &FF, và 0xFF=255(th ập phân)=0B11111111 (nhị phân). Như thế sau dòng đ ầu thanh ghi R16 có giá trị là 11111111 (nhị phân). Dòng th ứ 2: “OUT DDRB, R16” nghĩa là xuất giá trị từ thanh ghi R16 ra thanh ghi DDRB, tóm lại sau 2 dòng trên giá trị DDRB như sau: 1 1 1 1 1 1 1 1 Ntinside 11
  12. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE Có th ể bạn sẽ h ỏi tải sao chúng không sử dụng 1 dòng duy nh ất là “LDI DDRB, 0xFF” hay “OUT DDRB, 0xFF”, chúng ta không thể vì lệnh LDI chỉ cho phép th ực hiện trên các thanh ghi R16,…R31 và lệnh OUT không thực hiện được với các h ằng số. Và vì DDRB=11111111 nên trong trường hợp này tất cả các chân củ a PORTB đ ã sẵn sàng cho việc xuất d ữ liệu. Lúc này thanh ghi PINB không có tác dụng, thanh ghi PORTB sẽ là thanh ghi xuất, ghi giá trị vào thanh ghi này sẽ tác đ ộng đến các chân của PORTB.1 Phần 3: Chương trình chính • MAIN: LDI R16, 0B00000001 OUT PORTB, R16 RCALL DELAY Bạn chỉ cần chú ý 4 dòng trên trong toàn bộ phần chương trình chính, trước hết “MAIN:” ch ỉ là 1 nhãn do chúng ta tự đặt tên, giống như 1 “cột mốc” trong chương trình thôi. Dòng “LDI R16, 0B00000001” thì bạn đã hiểu, chỉ có 1 khác biệt nh ỏ là tôi sử dụng hằng số d ạng nhị phân cho bạn d ễ hiểu hơn. Và dòng “OUT PORTB, R16” để xu ất giá trị 0 B00000001 có sẵn trong R16 ra thanh ghi PORTB, lúc này chân PB0 củ a chip sẽ lên 1 (5V) và các chân còn lại sẽ ở mức 0 (0V). Dòng thứ 3: “RCALL DELAY” là lệnh gọi chương trình con DELAY, tạm hoãn trước khi thực hiện các dòng lệnh tiếp theo: LDI R16, 0B00000010 OUT PORTB, R16 RCALL DELAY Ba dòng lệnh này cũng giống ba dòng trên, nhưng giá trị xuất ra lúc này là 0B00000010, chân PB1 sẽ lên 5V và các chân khác xu ống mức 0V. Và cứ như thế đến đoạn cu ối: LDI R16, 0B10000000 OUT PORTB, R16 RCALL DELAY RJMP MAIN Sau khi kết thức 3 dòng trên chân PB7 sẽ lên 5V, kết thúc 1 vòng • xoay. Cuối cùng là quay vế đầu chương trình chính bằng dòng “RJMP MAIN” • Bây giờ chắc bạn đ ã đoán được chương trình của chúng ta th ực hiện việc gì, đó là quét xoay vòng các chân củ a PORTB, nếu chúng ta kết nối các chân của PORTB với các LED, chúng ta sẽ có 1 hiệu ứng quét LED xoay vòng, chúng ta thực hiện điều này bằng ph ần mềm Proteus. Ntinside 12
  13. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE • Ph ần 4: chương trinh con DELAY: đoạn chương trình này không làm gì cả ngoài việc trì hoãn 1 khoảng thời gian, tuy nhiên bạn chưa thể h iểu nó ngay được. Đây chỉ là 1 ví dụ đơn giản, tôi cố gắng th ực hiện nó theo cách dễ h iểu nhất cho bạn, vì thế đoạn code có vẻ h ơi dài dòng, bạn hãy thực hiện lại đoạn chương trình chính bằng đoạn code của bạn. Phần cuối cùng là biên dịch đ oạn code thành file intel hex để đổ vào chip, nhấn phím F7 đ ể biên dịch. Sau khi biên d ịch bạn sẽ có 1 file tên “avr1.hex” trong thưc mục project, chúng ta sẽ dùng file này đ ổ vào chip sau này. IV. Mô phỏng bằng Proteus. Chúng ta hãy thử n ghiệm đoạn chương trình của chúng ta bằng Proteus. Nếu bạn thực hiện đúng kết quả sẽ như minh họa trong hình 2 Hướng dẫn cụ thể cách vẽ mạch điện và mô phỏng bằng phần mề m Proteus bạn hãy xem bài "Mô phỏng Proteus". Hình 2. Mô phỏng. Ntinside 13
  14. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE Bài 2 - Cấu Trúc AVR I. Giới thiệu. Bài này tiế p tục bài đầu tiên trong loạt bài giới thiệu về AVR, nếu sau bài "Làm quen AVR" bạn đã phần nào biết cách lập trình cho AVR bằng AVRStudio thì trong bài này, chúng ta sẽ tìm hiểu kỹ hơn về cấu trúc của AVR. Sau bài này, bạn sẽ: Hiểu được cấu trúc AVR, cấu trúc bộ nhớ và cách thức hoạt đ ộng của • chip. Hiểu về Stack và cách hoạt động. • Biết được mộ t số instruction cơ bản truy xuất bộ nhớ. • Học các instruction rẽ nhánh và vòng lặp. • Chương trình con (Subroutine) và Macro. • Cải tiến ví dụ trong bài 1. • Viết 1 ví dụ minh họa cách sử dụng bộ nhớ và vòng lặp. • II. Tổ chức của AVR. AVR có cấu trúc Harvard, trong đó đường truyền cho bộ nhớ dữ liệu (data memory bus) và đường truyền cho bộ nhớ chương trình (program memory bus) được tách riêng. Data memory bus chỉ có 8 bit và được kết nối với hầu hết các thiết bị ngoại vi, với register file. Trong khi đó program memory bus có độ rộng 16 bits và chỉ phục vụ cho instruction registers. Hình 1 mô tả cấu trúc bộ nhớ của AVR. Bộ nhớ c hương trình (Program memory): Là bộ nhớ Flash lập trình được, trong các chip AVR cũ (như AT90S1200 hay AT90S2313…) bộ nhớ chương trình chỉ gồm 1 phần là Application Flash Section nhưng trong các chip AVR mới chúng ta có thêm phần Boot Flash setion. Boot section sẽ được khảo sát trong các phần sau, trong bài này khi nói về bộ nhớ chương trình, chúng ta tự hiểu là Application section. Thực chất, application section bao gồm 2 phần: phần chứa các instruction (mã lệnh cho hoạt động của chip) và phần chứa các vector ngắt (interrupt vectors). Các vector ngắt nằm ở phần đầu của application section (từ đ ịa chỉ 0x0000) và dài đến bao nhiêu tùy thuộc vào loạ i chip. Phần chứa instruction nằm liền sau đó, chương trình viết cho chip phải được load vào phần này. Xem lại phần đầu của ví dụ trong bài 1: Ntinside 14
  15. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE .ORG 0x000 RJMP BATDAU .ORG 0x020 Trong ví dụ này, ngay sau khi set vị trí 0x000 bằng chỉ thị (DIRECTIVE) .ORG 0x000 chúng ta dùng instruction RJMP để nhảy đến vị trí 0x020, như thế phần bộ nhớ chương trình từ 0x00 đến 0x01F không được sử dụng (vì trong ví dụ này chúng ta không sử dụng các vector ngắt). Chương trình chính đ ược bắt đầu từ địa chỉ 0x020, con số 0 x020 là do người lập trình chọn, thật ra các vector ngắt của chip ATMEGA8 chỉ kéo dài đến địa chỉ 0 x012, vì vậ y chương trình chính có thể được bắt đầu từ bất cứ vị trí nào sau đó. Để biết độ dài các vector ngắt của từng chip bạn hãy tham khảo datasheet của chip đó. Vì chức năng chính của bộ nhớ chương trình là chứa instruction, chúng ta không có nhiều cơ hộ i tác động lên bộ nhớ này khi lập trình cho chip, vì thế đối với người lập trình AVR, bộ nhớ này “không quá quan trọng”. Tất cả các thanh ghi quan trọng cần khảo sát nằ m trong bộ nhớ dữ liệu của chip. Hình 1. Tổ chức bộ nhớ của AVR. Bộ nhớ dữ liệu (data memory): Đây là phần chứa các thanh ghi quan trọng nhất của chip, việc lập trình cho chip phần lớn là truy cập bộ nhớ này. Bộ nhớ dữ liệu trên các chip AVR có độ lớn khác nhau tùy theo mỗi chip, tuy nhiên về cơ bản phần bộ nhớ này được chia thành 5 phần: Phần 1: là phần đầu tiên trong bộ nhớ dữ liệu, nh ư mô tả trong hình 1, phần này bao gồm 32 thanh ghi có tên gọ i là register file (RF), hay General Ntinside 15
  16. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE Purpose Rgegister – GPR, hoặc đơn giản là các Thanh ghi. Tất cả các thanh ghi này đều là các thanh ghi 8 bits như trong hình 2. Hình 2. Thanh ghi 8 bits. Tất cả các chip trong họ AVR đều bao gồm 32 thanh ghi Register File có địa chỉ tuyệ t đối từ 0x0000 đến 0x001F. Mỗi thanh ghi có thể chứa giá trị dương từ 0 đến 255 hoặc các giá trị có dấu từ -128 đến 127 hoặc mã ASCII của một ký tự nào đ ó…Các thanh ghi này được đặt tên theo thứ tự là R0 đến R31. Chúng được chia thành 2 phần, phần 1 bao gồ m các thanh ghi từ R0 đến R15 và phần 2 là các thanh ghi R16 đến R31. Các thanh ghi này có các đặc điể m sau: Được truy cập trực tiếp trong các instruction. • Các toán tử, phép toán thực hiện trên các thanh ghi này chỉ cần 1 chu • kỳ xung clock. Register File được kế t nối tr ực tiếp với bộ xử lí trung tâm – CPU của • chip. Chúng là nguồn chứa các số hạng trong các phép toán và cũng là đích • chứa kết quả trả lạ i của phép toán. Để minh họa, hãy xét ví dụ th ực hiện phép cộng 2 thanh ghi bằng instruction ADD như sau: ADD R1, R2 Bạn thấy trong dòng lệnh trên, 2 thanh ghi R1 và R2 được sử dụng trực tiếp vớ i tên của chúng, dòng lệnh trên khi đượ c dịch sang opcode để d ownload vào chip sẽ có d ạng: 0000110000010010 trong đó 00001=1 tức thanh ghi R1 và 00010 = 2 chỉ thanh ghi R2. Sau phép cộng, kết qu ả sẽ được lưu vào thanh ghi R1. Tất cả các instruction sử dụng RF làm toán hạng đều có th ể truy nhập tất cả các RF một cách trực tiếp trong 1 chu kỳ xung clock, ngoại trừ SBCI, SUBI, CPI, ANDI và LDI, các instruction này ch ỉ có thể truy nhập các thanh ghi từ R16 đ ến R31. Thanh ghi R0 là thanh ghi duy nhất đượ c sử dụng trong instruction LPM (Load Program Memory). Các thanh ghi R26, R27, R28, R29, R30 và R31 ngoài chức năng thông thường còn đượ c sử dụng như các con trỏ (Pointer register) trong một số instruction truy xu ất gián tiếp. Chúng ta sẽ kh ảo sát vấn đ ề con trỏ sau này. Hình 3 mô tả các chức năng phụ củ a các thanh ghi. Ntinside 16
  17. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE Hình 3. Register file. Tóm lại 32 RF củ a AVR đượ c xem là 1 ph ần của CPU, vì thế chúng đượ c CPU sử dụng trực tiếp và nhanh chóng, để gọi các thanh ghi này, chúng ta không cần gọi địa ch ỉ mà chỉ cần gọi trực tiếp tên của chúng. RF thường được sử dụng như các toán h ạng (operand) của các phép toán trong lúc lập trình. Phần 2 : là ph ần n ằm ngay sau register file, phần này bao gồm 64 thanh ghi đ ượ c gọi là 64 thanh ghi nh ập/xu ất (64 I/O register) hay còn gọi là vùng nhớ I/O (I/O Memory). Vùng nhớ I/O là cửa ngõ giao tiếp giữa CPU và thiết bị ngoại vi. Tất cả các thanh ghi điều khiển, trạng thái…củ a thiết bị ngoại vi đều n ằm ở đ ây. Xem lại ví dụ trong bài 1, trong đó tôi có đ ề cập về việc điều khiển các PORT của AVR, mỗi PORT liên quan đ ến 3 thanh ghi DDRx, PORTx và PINx, tất cả 3 thanh ghi này đều n ằm trong vùng nhớ I/O. Xa hơn, n ếu muốn truy xu ất các thiết bị ngoại vi khác như Timer, chuyển đổi Analog/Digital, giao tiếp USART…đều thực hiện thông qua việc đ iều khiển các thanh ghi trong vùng nhớ này. Vùng nhớ I/O có thể đượ c truy cập như SRAM hay như các thanh ghi I/O. Nếu sử dụng instruction truy xuất SRAM để truy xuất vùng nhớ này thì địa chỉ của chúng được tính từ 0 x0020 đến 0x005F. Nhưng nếu truy xuất như các thanh ghi I/O thì địa chỉ của chúng đựơ c tính từ 0x0000 đ ến 0x003F. Xét ví dụ instruction OUT dùng xu ất giá trị ra các thanh ghi I/O, lệnh này sử dụng địa ch ỉ kiểu thanh ghi, cấu trúc của lệnh như sau: OUT A, Rr, trong đó A là địa chỉ của thanh ghi trong vùng nhớ I/O, Rr là thanh ghi RF, lệnh OUT xuất giá trị từ thanh ghi Rr ra thanh ghi I/O có địa chỉ là A. Giả sử chúng ta mu ốn xuất giá trị chứa trong R6 ra thanh ghi điều khiển hướng củ a PORTD, tức thanh ghi DDRD, địa ch ỉ tính theo vùng I/O của thanh ghi DDRD là 0x0011, như th ế câu lệnh của chúng ta sẽ có d ạng: OUT 0x0011, R6. Tuy nhiên trong 1 trường hợ p khác, n ếu muốn truy xuất DDRD theo dạng SRAM, ví dụ lệnh STS hay LDS, thì phải dùng địa chỉ tuyệt đ ối củ a thanh ghi này, tức giá trị 0 x0031, khi đó lệnh OUT ở trên đ ượ c viết lại là STS 0x0031, R6. Để thống nhấ t cách sử dụng từ ngữ, từ bây giờ chúng ta dùng khái niệm “địa ch ỉ I/O” cho các thanh ghi trong vùng nhớ I/O đ ể nói đến địa chỉ không tính phần Register File, khái niệm “địa chỉ bộ nhớ” của thanh ghi là ch ỉ đ ịa ch ỉ tuyệt đố i của chúng trong SRAM. Ví dụ thanh ghi DDRD có “địa chỉ I/O” là 0x0011 và “địa ch ỉ bộ nhớ” của nó là 0x0031, “địa ch ỉ bộ nhớ” = “địa chỉ I/O” + 0x0020. Ntinside 17
  18. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE Vì các thanh ghi trong vùng I/O không được hiểu theo tên gọi nh ư các Register file, khi lập trình cho các thanh ghi này, người lập trình cần nhớ địa chỉ củ a từng thanh ghi, đây là việc tương đối khó khăn. Tuy nhiên, trong h ầu hết các phần mềm lập trình cho AVR, địa chỉ củ a tất cả các thanh ghi trong vùng I/O đ ều đượ c định nghĩa trướ c trong 1 file Definition, bạn chỉ cần đính kèm file này vào ch ương trình củ a bạn là có thể truy xuất các thanh ghi vớ i tên gọi của chúng. Giả sử trong ví dụ ở bài 1, để lập trình cho chip Atmega8 bằng AVRStudio, dòng th ứ 2 chúng ta sử dụng INCLUDE "M8DEF.INC" để load file đ ịnh nghĩa cho chip ATMega8, file M8DEF.INC. Vì vậy, trong sau này khi muốn sử dụng thanh ghi DDRD bạn chỉ cần gọi tên củ a chúng, như: OUT DDRD,R6. Phần 3: RAM tĩnh, nội (internal SRAM), là vùng không gian cho chứa các biến (tạm thời hoặc toàn cụ c) trong lúc thực thi chương trình, vùng này tương tự các thanh RAM trong máy tính nhưng có dung lượng khá nh ỏ (khoảng vài KB, tùy thuộc vào loại chip). Phần 4: RAM ngoại (external SRAM), các chip AVR cho phép người sử dụng gắn thêm các bộ nhớ ngoài để chứa biến, vùng này thực chất chỉ tồn tại khi nào người sử dụng gắn thêm bộ nhớ n goài vào chip. Phần 5: EEPROM (Electrically Ereasable Programmable ROM) là một phần quan trọng của các chip AVR mớ i, vì là ROM nên bộ nhớ n ày không bị xóa ngay cả khi không cung cấp ngu ồn nuôi cho chip, rất thích hợp cho các ứng dụng lưu trữ dữ liệu. Như trong hình 1, ph ần bộ nhớ EEPROM đượ c tách riêng và có đ ịa ch ỉ tính từ 0x0000. Câu hỏi bây giờ là AVR hoạt đ ộng như thế nào? Hình 4 biểu diễn cấu trong bên trong củ a 1 AVR. Bạn th ấy rằng 32 thanh ghi trong Register File đượ c kết nối trực tiếp với Arithmetic Logic Unit -ALU (ALU cũng đ ượ c xem là CPU của AVR) bằng 2 line, vì thế ALU có thể truy xuất trực tiếp cùng lúc 2 thanh ghi RF chỉ trong 1 chu kỳ xung clock (vùng đượ c khoanh tròn màu đ ỏ trong hình 4). Hình 4. Cấu trúc bên trong AVR. Các instruction đượ c chứa trong bộ nhớ chương trình Flash memory dưới dạng các thanh ghi 16 bit. Bộ nhớ chương trình đượ c truy cập trong mỗi chu kỳ xung clock và 1 instruction chứa trong program memory sẽ đ ược load vào trong instruction register, instruction register tác đ ộng và lựa ch ọn register file cũ ng như RAM cho Ntinside 18
  19. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE ALU thực thi. Trong lúc thực thi chương trình, địa ch ỉ của dòng lệnh đang thực thi được quyết định bở i một bộ đếm ch ương trình – PC (Program counter). Đó chính là cách thức hoạt động củ a AVR. AVR có ưu đ iểm là hầu hết các instruction đều được thực thi trong 1 chu kỳ xung clock, vì vậy có thể nguồn clock lớn nh ất cho AVR có thể nh ỏ hơn 1 số vi điều khiển khác như PIC nhưng thờ i gian thực thi vẫn nhanh hơn. III. Stack. S tack được hiểu như là 1 “tháp” d ữ liệu, dữ liệu được chứa vào stack ở đỉnh “tháp” và d ữ liệu cũng được lấy ra từ đỉnh. Kiểu truy cập dữ liệu của stack gọi là LIFO (Last In First Out – vào sau ra trước). Hình 5 th ể hiện cách truy cập d ữ liệu củ a stack. Hình 5. Stack. Khái niệm và cách th ức hoạt động của stack có th ể đượ c áp dụng cho AVR, bằng cách khai báo một vùng nhớ trong SRAM là stack ta có th ể sử dụng vùng nhớ n ày như một stack thực thụ . Để khai báo một vùng SRAM làm stack chúng ta cần xác lập địa chỉ đầu của stack bằng cách xác lập con trỏ stack-SP (Stack Pointer). SP là 1 con trỏ 16 bit bao gồm 2 thanh ghi 8 bit SPL và SPH (chữ L là LOW ch ỉ thanh ghi mang giá trị byte th ấp của SP, và H = HIGH), SPL và SPH n ằm trong vùng nhớ I/O. Giá trị gán cho thanh ghi SP sẽ là địa chỉ khởi động của stack. Quay lại ví dụ ở bài 1, phần khởi tạo các đ iều kiện đ ầu. ; KHOI TAO CÁC DIEU KIEN DAU LDI R16, HIGH(RAMEND) LDI R17, LOW(RAMEND) OUT SPH, R16 OUT SPL, R17 Bốn dòng khai báo trên mục đích là gán giá trị củ a RAMEND cho con trỏ SP, RAMEND (tức End of Ram) là biến ch ứa địa ch ỉ lớn nhất của RAM nội trong AVR, biến này được đ ịnh nghĩa trong file M8DEF.INC. Như thế sau 4 dòng trên, con trỏ SP chứa giá trị cuối cùng củ a SRAM hay nói cách khác vùng stack bắt đ ầu từ vị trí cuối cùng củ a bộ nhớ SRAM. Nhưng tại sao là vị trí cuối cùng mà không là 1 giá trị khác. Có th ể giải thích như sau: stack trong AVR hoạt đ ộng từ trên xu ống, sau khi dữ liệu được đẩy vào stack, SP sẽ giảm giá trị vì th ế khởi động SP ở vị trí cuối cùng củ a SRAM sẽ tránh đ ược việc mất dữ liệu do ghi đè. Bạn có thể khở i đ ộng stack với 1 địa chỉ khác, tuy nhiên vì lý do an toàn, nên khở i động stack ở RAMEND. Hai instruction dùng cho truy cập stack là PUSH và POP, trong đó PUSH dùng đẩy dữ liệu vào stack và POP dùng lấy dữ liệu ra khỏi stack. Dữ liệu được đẩy vào và lấy ra khỏi stack tại vị trí mà con trỏ SP trỏ đến. Ví dụ cho chip ATMega8, RAMEND=0x045F, sau khi khởi động, con trỏ SP trỏ đ ến vị trí 0x045F trong SRAM, nếu ta viết các câu lệnh sau: LDI R1, 1 PUSH R1 LDI R1, 5 PUSH R1 LDI R1, 8 PUSH R1 Ntinside 19
  20. SƯU TẦM VÀ BIÊN SOẠN BỞI NTINSIDE Khi đó nội dung của stack sẽ như trong hình 6. Hình 6. Nội dung stack trong ví dụ . Sau mỗi lần PUSH dữ liệu, SP sẽ giảm 1 đơn vị và trỏ vào vị trí tiếp theo. Bây giờ n ếu ta dùng POP đ ể lấy d ữ liệu từ stack, POP R2, thì R2 sẽ mang giá trị củ a ngăn nhớ 0 x045D, tức R2=8. Trước khi instruction POP đượ c thực hiện, con trỏ SP được tăng lên 1 đơn vị, sau đó dữ liệu sẽ được lấy ra từ vị trí mà SP trỏ đ ến trong stack. Stack trong AVR không phải là “vô đ áy”, nghĩa là chúng ta ch ỉ có thể P USH d ữ liệu vào stack ở 1 độ sâu nh ất định nào đấy (phụ thuộc vào chip). Sử dụng stack không đúng cách đôi khi sẽ làm ch ương trình thực thi sai hoặc tốn thờ i gian thực thi vô ích. Vì th ế không nên sử dụng stack chỉ để lưu các biến thông thường. Ứng dụng phổ biến nhất của stack là sử dụng trong các chương trình con (Subroutine), khi chúng ta cần “nh ảy” từ một vị trí trong chương trình chính đ ến 1 ch ương trình con, sau khi thực hiện chương trình con lại mu ốn quay về vị trí ban đầu trong chương trình chính thì Stack là ph ương cách tối ưu dùng để chứa bộ đ ếm chương trình trong trường hợ p này. Xem lại ví dụ trong bài 1, trong ch ương trình chính chúng ta dùng lệnh RCALL DELAY đ ể nh ảy đến đoạn chương trình con DELAY, RCALL là lệnh nhảy đến 1 vị trí trong bộ nhớ chương trình, trước khi nh ảy, PC được cộng thêm 1 và PUSH một cách tự động vào stack. Cuối chương trình con DELAY, chúng ta dùng instruction RET, instruction này POP dữ liệu từ stack ra PC một cách tự đ ộng, bằng cách này chúng ta có thể quay lại vị trí trước đó. Chính vì các lệnh RCALL và RET sử dụng stack một cách tự động nên ta phải khở i đ ộng stack ngay từ đ ầu, n ếu không chương trình sẽ thực thi sai ch ức năng. Tóm lại cần khở i động stack ở đ ầu chương trình và không nên sử dụng stack một cách tùy thích nếu chưa th ật cần thiết. IV. Thanh ghi trạng thái - SREG (STATUS REGISTRY). Nằm trong vùng nhớ I/O, thanh ghi SREG có địa chỉ I/O là 0x003F và địa chỉ bộ nhớ là 0x005F (th ường đ ây là vị trí cu ối cùng của vùng nhớ I/O) là một trong số các thanh ghi quan trọng nhất của AVR, vì th ế mà tôi dành ph ần này để giới thiệu về thanh ghi này. Thanh ghi SREG chứa 8 bit cờ (flag) chỉ trạng thái của bộ xử lí, tất cả các bit này đều bị xóa sau khi reset, các bit này cũng có thể được đ ọc và ghi bởi ch ương trình. Chức năng của từng bit đượ c mô tả như sau: Hình 7. Thanh ghi trạng thái. • Bit 0 – C (Carry Flag: Cờ nhớ): là bit nhớ trong các phép đ ại số h oặc logic, ví d ụ thanh ghi R1 chứa giá trị 200, R2 chứa 70, chúng ta thực hiện phép cộng có nhớ : ADC R1, R2, sau phép cộng, kết qu ả sẽ được lưu lại trong thanh ghi R1, trong khi kết quả thực là 270 mà thanh ghi R1 lại ch ỉ có kh ả năng chứa tối đa giá trị 255 (vì có 8 bit) nên trong trường hợp này, giá trị lưu lại trong R1 thực chất chỉ là 14, đồng thời cờ C được set lên 1 (vì 270=100001110, trong đó 8 bit sau 00001110 =14 sẽ được lưu lại trong R1). • Bit 1 – Z (Zero Flag: Cờ 0): cờ n ày đ ượ c set nếu kết quả phép toán đại số h ay phép Logic bằng 0. Ntinside 20
ADSENSE

CÓ THỂ BẠN MUỐN DOWNLOAD

 

Đồng bộ tài khoản
2=>2