giao trinh avr

66
1 Mc lc Mđầu .......................................................................................................................................................... 2 1 Gii thiu vi xlý AVR ............................................................................................................................ 3 2 Mt sphn mm, thiết bhtrcho vic lp trình AVR..................................................................... 5 2.1 Phn mm CodeVision ...................................................................................................................... 5 2.2 Phn mm mô phng Proteus ........................................................................................................... 5 2.3 Mch np và phn mm np ............................................................................................................ 6 3 ng dng ca vi xlý ATmega16 ............................................................................................................ 7 3.1 Điu khin I/O (In/Out)..................................................................................................................... 7 3.2 Ngt ngoài (Interrupt) ....................................................................................................................... 8 3.3 Timer/Counter ................................................................................................................................... 9 3.4 Điu khin độ rng xung – PWM ................................................................................................... 11 3.4.1 Khái nim độ rng xung ............................................................................................................ 11 3.4.2 To PWM bng ATmega16 ....................................................................................................... 11 3.5 Chuyn đổi ADC .............................................................................................................................. 14 3.6 Giao tiếp USART ............................................................................................................................. 16 3.6.1 Các thut ngđược dùng trong giao tiếp USART ..................................................................... 16 3.6.2 Giao tiếp USART trên ATmega16 ............................................................................................ 17 4 Các bài tp ví d...................................................................................................................................... 19 4.1 Lp trình điu khin thiết bngoài (Led, động cơ…) ................................................................... 19 4.1.1 Phân tích mch đin ................................................................................................................... 19 4.1.2 Xây dng nguyên lý điu khin ................................................................................................. 19 4.1.3 Mô phng trên Proteus............................................................................................................... 21 4.1.4 Lp trình cho vi x................................................................................................................ 22 4.1.5 Chy thtrên mch mô phng ................................................................................................... 29 4.2 Lp trình ngt ngoài (INT) ............................................................................................................. 31 4.2.1 Phân tích mch đin ................................................................................................................... 31 4.2.2 Nguyên lý điu khin và xây dng mch mô phng trên Proteus.............................................. 31 4.2.3 Lp trình cho vi x................................................................................................................ 32 4.3 Lp trình Timer/Counter................................................................................................................ 35 4.3.1 Phân tích, xây dng nguyên lý điu khin và mch mô phng .................................................. 35 4.3.2 Lp trình cho vi x................................................................................................................ 35 4.4 Điu khin độ rng xung PWM ...................................................................................................... 42 4.4.1 Phân tích mch đin ................................................................................................................... 42 4.4.2 Nguyên lý điu khin ................................................................................................................. 42 4.4.3 Xây dng mch mô phng trên Proteus ..................................................................................... 43 4.4.4 Lp trình cho vi x................................................................................................................ 43 4.5 Chuyn đổi ADC .............................................................................................................................. 46 4.5.1 Phân tích mch đin ................................................................................................................... 46 4.5.2 Nguyên lý điu khin và mch mô phng trên Proteus ............................................................. 47 4.5.3 Lp trình cho vi x................................................................................................................ 49 4.6 Truyn nhn dliu vi máy tính.................................................................................................. 58 4.6.1 Phân tích mch đin ................................................................................................................... 58 4.6.2 Nguyên lý điu khin và mch mô phng ................................................................................. 58 4.6.3 Lp trình cho vi x................................................................................................................ 59 Phlc ......................................................................................................................................................... 64

Upload: ngo-xuan-truong

Post on 05-Aug-2015

2.192 views

Category:

Documents


5 download

TRANSCRIPT

Page 1: Giao trinh avr

1

Mục lục

Mở đầu .......................................................................................................................................................... 2

1 Giới thiệu vi xử lý AVR ............................................................................................................................ 3

2 Một số phần mềm, thiết bị hỗ trợ cho việc lập trình AVR..................................................................... 5

2.1 Phần mềm CodeVision ...................................................................................................................... 5 2.2 Phần mềm mô phỏng Proteus ........................................................................................................... 5 2.3 Mạch nạp và phần mềm nạp ............................................................................................................ 6

3 Ứng dụng của vi xử lý ATmega16 ............................................................................................................ 7

3.1 Điều khiển I/O (In/Out) ..................................................................................................................... 7 3.2 Ngắt ngoài (Interrupt) ....................................................................................................................... 8 3.3 Timer/Counter ................................................................................................................................... 9 3.4 Điều khiển độ rộng xung – PWM ................................................................................................... 11

3.4.1 Khái niệm độ rộng xung ............................................................................................................ 11 3.4.2 Tạo PWM bằng ATmega16 ....................................................................................................... 11

3.5 Chuyển đổi ADC .............................................................................................................................. 14 3.6 Giao tiếp USART ............................................................................................................................. 16

3.6.1 Các thuật ngữ được dùng trong giao tiếp USART ..................................................................... 16 3.6.2 Giao tiếp USART trên ATmega16 ............................................................................................ 17

4 Các bài tập ví dụ ...................................................................................................................................... 19

4.1 Lập trình điều khiển thiết bị ngoài (Led, động cơ…) ................................................................... 19 4.1.1 Phân tích mạch điện ................................................................................................................... 19 4.1.2 Xây dựng nguyên lý điều khiển ................................................................................................. 19 4.1.3 Mô phỏng trên Proteus ............................................................................................................... 21 4.1.4 Lập trình cho vi xử lý ................................................................................................................ 22 4.1.5 Chạy thử trên mạch mô phỏng ................................................................................................... 29

4.2 Lập trình ngắt ngoài (INT) ............................................................................................................. 31 4.2.1 Phân tích mạch điện ................................................................................................................... 31 4.2.2 Nguyên lý điều khiển và xây dựng mạch mô phỏng trên Proteus .............................................. 31 4.2.3 Lập trình cho vi xử lý ................................................................................................................ 32

4.3 Lập trình Timer/Counter ................................................................................................................ 35 4.3.1 Phân tích, xây dựng nguyên lý điều khiển và mạch mô phỏng .................................................. 35 4.3.2 Lập trình cho vi xử lý ................................................................................................................ 35

4.4 Điều khiển độ rộng xung PWM ...................................................................................................... 42 4.4.1 Phân tích mạch điện ................................................................................................................... 42 4.4.2 Nguyên lý điều khiển ................................................................................................................. 42 4.4.3 Xây dựng mạch mô phỏng trên Proteus ..................................................................................... 43 4.4.4 Lập trình cho vi xử lý ................................................................................................................ 43

4.5 Chuyển đổi ADC .............................................................................................................................. 46 4.5.1 Phân tích mạch điện ................................................................................................................... 46 4.5.2 Nguyên lý điều khiển và mạch mô phỏng trên Proteus ............................................................. 47 4.5.3 Lập trình cho vi xử lý ................................................................................................................ 49

4.6 Truyền nhận dữ liệu với máy tính.................................................................................................. 58 4.6.1 Phân tích mạch điện ................................................................................................................... 58 4.6.2 Nguyên lý điều khiển và mạch mô phỏng ................................................................................. 58 4.6.3 Lập trình cho vi xử lý ................................................................................................................ 59

Phụ lục ......................................................................................................................................................... 64

Page 2: Giao trinh avr

2 Mở đầu Hiện nay các vi xử lý, hay vi điều khiển (MCU – Micro Controller Unit) đang được sử

dụng rộng rãi trong nhiều kĩnh vực như: điều khiển, tự động hóa, đo đạc, truyền thông… So với các phương pháp điều khiển, đo đạc truyền thống (cơ khí, điện tử tương tự…), thì sử dụng vi xử lý có các ưu điểm như: nhỏ gọn, ít tốn năng lượng, thời gian đáp ứng nhanh, có thể lập trình được…

Vi xử lý họ AVR của hãng ATMEL hiện đang được sử dụng tương đối phổ biến. Vi xử lý họ AVR là các vi xử lý lập trình được. Sau khi được lập trình, vi xử lý sẽ hoạt động theo thuật toán được viết trong lập trình của người dùng. Như vậy người dùng có thể lập trình cho vi điều khiển hoạt động theo ý đồ của mình để giải quyết một các bài toán (điều khiển, đo đạc…).

Trong lập trình cho vi điều khiển, thường sử dụng ngôn ngữ lập trình C và có liên quan tới cấu trúc của vi xử lý, để người đọc chưa được học về ngôn ngữ lập trình C hoặc cấu trúc vi xử lý có thể dễ dàng theo dõi, những phần đó sẽ được diễn giải theo cách càng đơn giản càng tốt. Như vậy người đọc có thể theo dõi tài liệu mà không thấy quá khó hiểu, tuy nhiên cũng vì thế nên các kiến thức được trình bày không đầy đủ và chỉ ở mức cơ bản nhất, để người đọc có thể nhanh chóng tự lập trình được một số ứng dụng cơ bản với vi điều khiển AVR.

Page 3: Giao trinh avr

3 1 Giới thiệu vi xử lý AVR AVR là tên gọi chung các vi xử lý của hãng ATMEL. Hãng ATMEL sản xuất các vi xử

lý với các chức năng, khả năng tính toán khác nhau, được đặt tên khác nhau: ATtiny25, ATtiny48…,ATmega8, ATmega16, ATmega128…

Các vi xử lý khác nhau thì khác nhau về dung lượng bộ nhớ ROM, RAM, các khối chức năng, số lượng chân… Trong tài liệu này, các hướng dẫn và ví dụ được viết cho vi xử lý ATmega16. Sơ đồ chân, các khối chức năng và cách sử dụng, đặc tính làm việc… của vi lý được nhà sản xuất ghi trong file “datasheet” kèm theo, có thể tìm trên internet.

Hình 1: Vi xử lý ATmega16

Các vi xử lý được lập trình bằng ngôn ngữ lập trình (trong tài liệu này sử dụng ngôn ngữ lập trình C) nhờ các phần mềm (AVRStudio, CodeVision…).

Các vi xử lý đều có chung một số đặc tính điện khi làm việc như sau: • Điện áp làm việc là +5V. • Dòng điện qua các chân của vi xử lý nhỏ (cỡ vài chục mA), nên không thể đấu

trực tiếp vi điều khiển với các thiết bị công suất lớn (động cơ…). Vi xử lý Atmega 16 có 2 kiểu đóng gói khác nhau, loại đóng gói như hình sau là loại

thường, phổ biến nhất, 40 chân theo sơ đồ:

Hình 2:Sơ đồ chân của Atmega16

Tất cả các chân của ATmega16 được đánh số thứ tự từ 1 đến 40 như hình vẽ, chiều của vi xử lý được lấy theo đầu lõm hoặc chấm tròn trên vi xử lý.

Khi làm việc, các chân của vi điều khiển có hai mức trạng thái là 0 và 1. Trạng thái 0 ứng với mức điện áp 0 V còn trạng thái 1 ứng với mức điện áp +5V.

Page 4: Giao trinh avr

4 Chức năng của các chân trên vi xử lý ATmega16 như sau:

• Chân 10 – VCC: Là chân cấp nguồn +5V cho vi xử lý. • Chân 11 và 31 – GND: Là hai chân nối với nguồn âm. Khi thiết kế mạch, phải

nối cả hai chân 11 và 31 với nguồn âm. • Chân 9 – RESET: Bình thường chân 9 ở trạng thái 0, khi cấp điện +5V vào chân

RESET, trạng thái của nó từ 0 lên 1, và reset lại toàn bộ hoạt động của vi xử lý, tương đương với việc ngắt nguồn nuôi vi xử lý rồi cấp nguồn lại.

• Chân 12 – XTAL1 và 13 – XTAL2: Là hai chân nối với thạch anh. Thạch anh là một linh kiện có tác dụng tạo dao động điện, vi xử lý sẽ hoạt động theo các dao động này (ví dụ 4Mhz, 12 Mhz…). Trong một số trường hợp có thể dùng thạch anh được gắn sẵn trong vi xử lý, hai chân XTAL1 và XTAL2 được bỏ trống.

• Chân 30 – AVCC: Là chân cấp nguồn cho khối chuyển đổi ADC (Analog to Digital Converter). ACD là một chức năng của vi xử lý, cho phép đo điện áp đặt tại chân 33, 34, …, 40 của vi xử lý. Xem thêm mục Chuyển đổi ADC.

• Chân 32 – AREF: Điện áp tham chiếu. Chân AREF được sử dụng khi cần dùng chức năng ADC của vi điều khiển. Khi cần dùng chức năng ADC, người dùng cần đặt vào chân AREF một điện áp, gọi là điện áp tham chiếu. Xem thêm mục Sử dụng ADC.

• Các chân 1 … 8: Được nhóm chung thành một “cổng”, gọi là PORT B, từng chân trong Port B được ký hiệu PB0, PB1, …, PB7 ứng với các chân từ 1 đến 8. Các chân này có thể đảm nhiệm các chức năng khác nhau, tùy vào thiết lập của người dùng khi lập trình.

• Các chân 14 … 21: Được nhóm chung thành một “cổng”, gọi là PORT D, từng chân trong Port D được ký hiệu PD0, PD1, …, PD7 ứng với các chân từ 14 đến 21. Các chân này có thể đảm nhiệm các chức năng khác nhau, tùy vào thiết lập của người dùng khi lập trình.

• Các chân 22 … 29: Được nhóm chung thành một “cổng”, gọi là PORT C, từng chân trong Port C được ký hiệu PC0, PC1, …, PC7 ứng với các chân từ 22 đến 29. Các chân này có thể đảm nhiệm các chức năng khác nhau, tùy vào thiết lập của người dùng khi lập trình.

• Các chân 33 … 40: Được nhóm chung thành một “cổng”, gọi là PORT A, từng chân trong Port A được ký hiệu PA0, PA1, …, PA7 ứng với các chân từ 1 đến 8. Các chân này có thể đảm nhiệm các chức năng khác nhau, tùy vào thiết lập của người dùng khi lập trình.

Tóm tắt 1 Vi xử lý ATmega16: Ø Là vi xử lý lập trình được. Ø Điện áp làm việc +5V, dòng nhỏ. Ø Có 4 port là Port A, Port B, Port C, Port D. Mỗi port có 8 chân, có thể đảm

nhiệm các chức năng khác nhau.

Page 5: Giao trinh avr

5 2 Một số phần mềm, thiết bị hỗ trợ cho việc lập trình AVR 2.1 Phần mềm CodeVision Phần mềm CodeVision là phần mềm hỗ trợ lập trình cho vi xử lý AVR bằng ngôn ngữ

C. Cách sử dụng cụ thể CodeVision được viết trong các ví dụ trong tài liệu.

Hình 3: Giao diện CodeVision

2.2 Phần mềm mô phỏng Proteus

Hình 4: Giao diện Proteus

Proteus là phần mềm mô phỏng mạch điện trên máy tính, có giao diện trực quan, với các linh kiện điện tử được sắp xếp trên màn hình và được nối dây, đặt các thông số để có thể chạy thử mạch điện trên máy tính.

Proteus có sẵn rất nhiều các linh kiện điện tử có thể tìm thấy trên thị trường, bao gồm cả các vi xử lý AVR. Các lệnh theo ngôn ngữ C sau khi được viết bằng CodeVision có thể được đưa vào Proteus để chạy vi xử lý AVR tương ứng. Dùng Proteus ta có thể kiểm tra xem lập trình viết trong CodeVision đã đúng hay chưa, như vậy không cần thiết phải thử trên mạch thật, tiết kiệm thời gian, tiền bạc.

Tuy nhiên do là mô phỏng trên máy tính, nên một số phần quan trọng trong mạch thực (nguồn điện, sự tương thích về công suất giữa các phần tử…) không được tính đến, dẫn tới mạch điện mô phỏng chỉ có giá trị tham khảo, kiểm tra nguyên lý hoạt động trước khi tiến hành làm mạch thật.

Page 6: Giao trinh avr

6 2.3 Mạch nạp và phần mềm nạp Sau khi thử trên Proteus, và làm một mạch điện thật bên ngoài có vi xử lý AVR, để cho

vi xử lý AVR chạy được những gì đã lập trình, phải nạp chương trình cho nó (gần giống như cài phần mềm cho máy tính), muốn làm điều đó chúng ta cần mạch nạp và phần mềm nạp.

Mạch nạp là một mạch điện nối giữa vi xử lý và máy tính, còn phầm mềm nạp được cài trên máy tính để điều khiển mạch nạp. Sau khi nạp, chương trình chúng ta viết bằng AVRStudio sẽ được nhớ trong bộ nhớ của vi xử lý, và vi xử lý sẽ hoạt động theo như chương trình đó.

Tóm tắt 2

Ø Lập trình bằng ngôn ngữ C cho vi điều khiển AVR bằng phần mềm CodeVision hoặc AVRStudio.

Ø Chạy mô phỏng vi xử lý trên máy tính để kiểm tra bằng phần mềm Proteus. Ø Nạp chương trình cho vi xử lý bằng mạch nạp và phần mềm Khazama.

Page 7: Giao trinh avr

7 3 Ứng dụng của vi xử lý ATmega16 Các chức năng cơ bản của vi xử lý ATmega16 sẽ được trình bày trong tài liệu gồm có:

• Chức năng I/O (In/Out). • Ngắt ngoài (INT – INTerrupt). • Đếm thời gian (Timer/Counter). • Điều khiển độ rộng xung (PWM – Pulse Width Module). • Chuyển đổi ADC (Analog to Digital Converter). • Truyền nhận dữ liệu với máy tính (USART – Universal Synchronous and

Asynchronous serial Receiver and Transmitter). Còn các chức năng khác của ATmega16 như SPI, … sẽ không được trình bày ở đây. 3.1 Điều khiển I/O (In/Out) Điều khiển I/O, hay còn gọi là điều khiển Vào/Ra, là một chức năng cơ bản nhất của vi

xử lý. Chức năng I/O cho phép người lập trình gán trạng thái 0 hoặc 1 (ứng với mức điện áp 0V và +5V tương ứng) cho một hoặc nhiều chân trong các Port A, B, C hoặc D. Nói cách khác, người lập trình có thể điều khiển điện áp tại một chân bất kỳ trong số 4 port ở mức 0V hoặc +5V.

Với chức năng In/Out, vi xử lý có thể điều khiển bật/tắt trực tiếp hoặc gián tiếp các thiết bị ngoài như đèn Led, động cơ điện…

Nếu muốn sử dụng một chân nào đó trong số các port A, B, C hoặc D (chẳng hạn như chân PB6), khi lập trình người dùng phải thiết lập chức năng I/O cho chân PB6. Cách thiết lập sẽ được trình bày trong ví dụ Lập trình điều khiển thiết bị ngoài.

Tóm tắt 3.1 Dùng chức năng I/O điều khiển trạng thái các chân vi xử lý.

Page 8: Giao trinh avr

8 3.2 Ngắt ngoài (Interrupt) Ngắt (Interrupt) trong AVR, bao gồm cả ngắt ngoài, là một tín hiệu khẩn cấp gửi đến bộ

xử lý, yêu cầu bộ xử lý dừng các công việc hiện tại (A) để thực hiện một việc nào đó (B). Sau khi khi kết thúc B, bộ xử lý sẽ quay về làm tiếp việc A đang dang dở. Tín hiệu khẩn cấp đó có thể đến từ bên trong vi xử lý (từ bộ Timer, USART…) hoặc từ bên ngoài (nhấn một nút bấm…).

Ngắt ngoài là loại ngắt duy nhất độc lập với các thiết bị của vi xử lý, vì tín hiệu ngắt đến từ bên ngoài, ví dụ như khi người dùng bấm một nút bấm ở bên ngoài…

Trên Atmega16 có ba bộ ngắt ngoài, ứng với các chân 16 (PD2), 17 (PD3) và chân 3 (PB2), ký hiệu lần lượt là INT0, INT1 và INT2.

Hình sau thể hiện một tín hiệu ngắt tạo ra bằng một button (nút bấm) tới ngắt INT0.

Hình 5: Tín hiệu ngắt

Với mạch điện button như hình trên, khi chưa nhấn nút, điện áp đặt trên chân INT0 gần bằng +5V. Khi nhấn nút, chân INT0 được nối với GND nên điện áp chân INT0 lúc này là 0V. Sau khi nhả nút, điện áp chân INT0 lại trở về +5V.

Quá trình điện áp chân INT0 giảm nhanh tử gần +5V xuống 0V gọi là Falling Edge (cạnh xuống), còn quá trình điện áp tăng từ 0V lên +5V gọi là Rising Edge (cạnh lên). Người dùng có thể lập trình cho ngắt INT0 hoạt động khi xảy ra Falling Edge, Rising Edge hoặc cả hai.

• Nếu chọn Falling Edge, ngắt xảy ra khi vừa nhấn xong nút. • Nếu chọn Rising Edge, ngắt xảy ra khi nhả xong nút. • Nếu chọn cả Falling Edge và Rising Edge, ngắt sẽ xảy ra 2 lần khi vừa nhấn xong

nút và sau khỉ nhả xong nút. Cách kích hoạt chức năng ngắt ngoài INT0, INT1 hoặc INT2 và cách lựa chọn cạnh

xuống/cạnh lên được hướng dẫn trong ví dụ Lập trình ngắt ngoài. Ngắt ngoài thường dùng để thực hiện giao tiếp giữa người và vi xử lý (thông qua thao

tác nhấn nút), hoặc có thể dùng để đếm sự kiện bên ngoài (ví dụ như số sản phẩm đi qua cảm biến)…

Tóm tắt 3.2 Ø ATmega16 có 3 ngắt. Ø Ngắt theo cạnh xuống, cạnh lên hoặc cả hai.

Page 9: Giao trinh avr

9 3.3 Timer/Counter Timer/Counter, hay còn gọi là bộ đếm thời gian, bộ định thời… có chức năng đếm, hoặc

định ra một khoảng thời gian và cả đếm sự kiện. Trên một số vi xử lý, timer/counter còn có thêm chức năng điều chỉnh độ rộng xung (PWM). Trên ATmega16 có 3 bộ timer/counter, gọi tắt là T/C0, T/C1,T/C2.

Các bộ T/C hoạt động bằng cách đếm số xung dao động của thạch anh nuôi vi xử lý theo tỉ lệ (Prescale) 1:1 hoặc 1:8,... Thạch anh, như đã nói ở phần 1, tạo ra dao động để vi xử lý hoạt động. Mỗi linh kiện thạch anh có một tần số dao động nhất định (ví dụ 4 Mhz, 12Mhz…). Mỗi chu kỳ dao động ứng với một khoảng thời gian Δt nhỏ, bằng cách đếm các dao động này, các bộ T/C có thể định ra các khoảng thời gian khác nhau. Ví dụ với thạch anh 1Mhz, thì chu kỳ dao động là:

66

1 10 ( ) 1( )1.10

t s sµ−∆ = = =

Nếu muốn xác định một khoảng thời gian 1 s 1000m sµ= , bộ T/C sẽ phải dùng một biến đếm để đếm đủ 1000 lần. Các biến đếm đó được đặt tên là TCNT0, TCNT1 hoặc TCNT2 tùy theo bộ T/C0, T/C1, T/C2 tương ứng.

Các biến đếm TCNT được lưu trong vi xử lý bằng 8 hoặc 16 bit (bit là các ô nhớ trong vi xử lý và chỉ có hai trạng thái 0 hoặc 1, tổ hợp của các bit này sẽ tương ứng với giá trị của biến TCNT theo hệ nhị phân). Thường dùng tên gọi T/C 8 bit hoặc T/C 16 bit chính là nói tới số bit dùng để lưu giá trị của biến TCNT.

Vì số bit bị giới hạn, nên khả năng đếm của biến TCNT bị giới hạn (với 8 bit, có thể đếm tối đa từ 0 đến 255), dẫn tới khoảng thời gian xác định được nếu đếm trực tiếp số dao dộng của thạnh anh cũng bị giới hạn.

Giải pháp đưa ra là đếm theo tỉ lệ (prescale) đã nói ở trên. Thay vì đếm mỗi dao động một lần, nếu đếm theo tỉ lệ, ví dụ 1:8, thì cứ 8 dao động của thạnh anh, T/C mới đếm một lần, tức là giá trị TCNT tăng thêm 1.

Hình 6: Đếm theo tỉ lệ 1:1 và 1:8

Như vậy với ví dụ ở trên, để định được khoảng thời gian 1ms, bộ T/C chỉ cần đếm: 1000 125

8= (lần)

Lúc này biến đếm TCNT chỉ phải chạy, ví dụ như từ giá trị ban đầu 131 tới giá trị tối đa 255 (đủ 125 lần đếm). Khi biến TCNT tới giá trị 255, thì sẽ được reset về giá trị ban đầu để đếm tiếp, đồng thời xảy ra ngắt. Do vậy tín hiệu ngắt của T/C là khi biến TCNT tới giá trị cực đại, và ngắt có T/C tạo ra gọi là ngắt trong.

Page 10: Giao trinh avr

10 Cách chọn tỉ lệ, giá trị ban đầu, giá trị tối đa và các thiết lập liên quan khác của T/C sẽ

được trình bày trong ví dụ Lập trình Timer/Counter. Tóm tắt 3.3

Ø Timer/Counter (T/C) tạo ngắt trong theo các quãng thời gian định trước. Ø ATmega16 có 2 T/C 8 bit và 1 T/C 16 bit. Ø Biến đếm TCNT và tỉ lệ Prescale.

Page 11: Giao trinh avr

11 3.4 Điều khiển độ rộng xung – PWM 3.4.1 Khái niệm độ rộng xung Để hiểu khái niệm độ rộng xung, ta xét mạch điện đơn giản sau đây:

Hình 7: Mạch điện ví dụ độ rộng xung

Một động cơ được mắc nối tiếp với một nút bấm như hình vẽ. Nếu ta bấm nút, động cơ sẽ chạy, nhả nút, động cơ sẽ dừng. Điện áp giữa hai đầu động cơ có dạng xung như trên hình 7. Nếu nhấn, nhả nút bấm theo chu kỳ, thì điện áp hai đầu động cơ cũng thay đổi theo chu kỳ, lúc này sẽ có khái niệm Time Period và Duty Cycle. Duty Cycle là thời gian điện áp ở mức +5V, còn Time Period là chu kỳ của xung, bao gồm Duty Cycle và thời gian điện áp bằng 0V còn lại.

Nếu giảm Duty Cycle, thì động cơ chạy chậm lại. Ngược lại, nếu tăng Duty Cycle thì động cơ chạy nhanh lên. Duty Cycle giảm tối thiểu bằng 0 và tăng tối đa bằng Time Period.

Điều chỉnh độ rộng xung chính là điều chỉnh Duty Cycle, và đôi khi là cả Time Period. 3.4.2 Tạo PWM bằng ATmega16 Vì điều chỉnh độ rộng xung là điều chỉnh thời gian Time Period và thời gian Duty Cycle,

vì vậy có thể dùng T/C để tạo PWM. Vi xử lý ATmega16 có thể tạo cùng lúc 4 tín hiệu PWM, gọi là 4 kênh PWM tại các

chân như hình sau:

Hình 8: Vị trí các chân có thể dùng để tạo tín hiệu PWM

Trong đó PWM0 do T/C0 tạo ra, PWM1A và PWM1B dó T/C1 tạo ra, PWM2 do T/C2 tạo ra. Muốn tạo PWM nào thì ta cần phải thiết lập T/C tương ứng.

Page 12: Giao trinh avr

12 Để dễ hiểu hãy lấy ví dụ muốn tạo tín hiệu PWM tại chân PD4 (PWM1B), ta phải dùng

T/C1 và thiết lập cho T/C1 ở chế độ tạo PWM. T/C1 là timer/counter 16 bit, do đó biến TCNT1 có thể đếm tới giá trị MAX là 65535.

Ý tưởng ở đây là biến TCNT1 chạy từ 0 tới giá trị OCR1B, sau đó chạy tiếp tới giá trị ICR1. Trong đó OCR1B là một giá trị do người dùng đặt trước ứng với khoảng thời gian Duty Cycle. Giá trị ICR1 cũng là một giá trị do người dùng đặt trước nhưng ứng với Time Period. Như vậy khi biến TCNT1 chạy từ 0 qua OCR1B tới ICR1, điện áp trên chân OC1B sẽ thay đổi theo Duty Cycle và Time Period tương ứng.

T/C1 có 3 chế độ hoạt động để tạo PWM là: • Fast PWM (PWM tần số cao). • Phase correct PWM (PWM với pha chính xác). • Phase correct and frequency correct PWM (PWM với pha và tần số chính xác).

Ba chế độ trên khác nhau ở cách tính Duty Cycle và sai số điều khiển. Trong tài liệu này sẽ giới thiệu hai chế độ thông dụng nhất là Fast PWM.

Fast PWM:

Hoạt động của T/C1 ở chế độ tạo Fast PWM có thể được biểu diễn qua đồ thị dưới:

Hình 9: Chế độ Fast PWM

Max là giá trị cực đại mà biến TCNT1 có thể đếm được, với T/C1 là Timer/Counter 16 bit nên Max = 65535. Khi thiết lập các giá trị cho OCR1B và ICR1 không được vượt quá giá trị Max này.

Ở chế độ Fast PWM biến TCNT1 đếm xung thạch anh theo tỉ lệ Prescale định trước, chạy từ 0 tới OCR1B, lúc này điện áp trên chân OC1B là +5V. Khi TCNT1 chạy từ OCR1B tới ICR1, điện áp chân OC1B là 0V. Đồng thời khi TCNT1 chạm mốc ICR1, biến TCNT1 được reset về 0 để tiếp tục đếm cho chu kỳ tiếp theo.

Như vậy thời gian biến TCNT1 chạy từ 0 tới OCR1B ứng với Duty Cycle, thời gian biến TCNT1 chạy từ 0 tới ICR1 ứng với Time Period.

Page 13: Giao trinh avr

13 Chẳng hạn muốn tạo một xung PWM có Time Period là 2ms, Duty Cycle là 1 ms với

thạch anh 4 Mhz, tỉ lệ Prescale = 8, ta có: Mỗi dao động thạch anh ứng với khoảng thời gian là:

6 36

1 0, 25.10 ( ) 0,25.10 ( s)4.10

s mτ − −= = =

Mỗi lần đếm của biến TCNT1 ứng với khoảng thời gian là: 3 38. 8.0,25.10 2.10 ( )msτ − −Τ = = =

Suy ra để tạo được Time Period (chu kỳ) của PWM là 2 ms, ta phải cho biến TCNT1 đếm 1000 lần, từ 0 tới 1000, tức là giá trị ICR1 = 1000.

Tương tự, để tạo được Duty Cycle của PWM là 1 ms, thì giá trị OCR1B = 500. Thông thường khi lập trình, người ta cố định giá trị ICR1 ngay từ đầu (Time Period cố

định), còn giá trị OCR1B được thay đổi khi vi xử lý hoạt động, nhằm tạo ra PWM có Duty Cycle thay đổi.

Cách kích hoạt chế độ Fast PWM, chọn các giá trị OCR1B, ICR1 và các thông số khác sẽ được trình bày trong ví dụ Điều khiển độ rộng xung PWM.

Tóm tắt 3.4 Ø PWM tạo ra do bộ T/C, ATmega16 có 4 kênh PWM (tại chân OC0;

OC1A; OC1B; OC2). Ø PWM dùng điều chỉnh tốc độ động cơ, động cơ bước và động cơ servo. Ø Tạo PWM nhờ biến TCNT và các giá trị OCR và ICR. Điều chỉnh độ rộng

xung bằng cách điều chỉnh giá trị OCR.

Page 14: Giao trinh avr

14 3.5 Chuyển đổi ADC Trong các ứng dụng đo lường và điều khiển bằng vi xử lý, bộ chuyển đổi tương tự-số

(ADC) là một thành phần rất quan trọng. Các đại lượng vật lý như nhiệt độ, áp suất, dòng điện,… đều có thể dùng cảm biến và các mạch xử lý để chuyển về dạng tín hiệu điện áp. Trên vi xử lý ATmega16, có thể đo 8 điện áp khác nhau đặt trên các 8 chân thuộc PORT A, gọi là 8 kênh ADC, được ký hiệu là ADC0, …, ADC7. Điện áp cấp cho bộ chuyển đổi ADC là +5V và được cấp qua chân AVCC.

Hình 10: 8 kênh ADC của ATmega16

Điện áp đặt tại một trong số các kênh ADC, ví dụ ADC0, sẽ được bộ chuyển đổi ADC của ATmega16 đo và trả lại một giá trị tương ứng. Để hiểu rõ hơn về hoạt động của ADC ta cần hiểu một số khái niệm sau:

Điện áp tham chiếu - Vref: Là giá trị lớn nhất mà bộ ADC có thể đo được. Trong đo đạc truyền thống, với các thiết bị đo, chúng ta cũng gặp khái niệm “giá trị lớn nhất mà thiết bị có thể đo được”. Ví dụ như một đồng hồ đo áp suất có thể đo được tối đa 70 bar, có nghĩa là đồng hồ này chỉ dùng để đo áp suất nhỏ hơn 70 bar.

Với ADC trên ATmega16, Vref (điện áp tham chiếu) được người lập trình đặt trước khi kích hoạt chức năng ADC. Có 3 cách chọn điện áp tham chiếu như sau:

• Chọn điện áp so sánh bằng điện áp trên chân VREF. • Chọn điện áp so sánh bằng +5V, nối chân VREF với chân AVCC. • Chọn điện áp tham chiếu nội – Vref = 2,56 V. Điện áp tham chiếu nội này được

tạo ra bên trong vi xử lý, người dùng không cần cấp điện áp qua chân VREF. Độ phân giải: Cho biết mức độ chính xác của phép đo bằng chuyển đổi ADC, cũng là số

bit dùng để chứa giá trị đầu ra của bộ chuyển đổi ADC. Chuyển đổi ADC trên ATmega16 là bộ ADC 10 bit, giá trị bộ ADC trả về sau khi đo có giá trị từ 0 đến 1023, ứng với 1023 khoảng chia.

Hoạt động của ADC có thể giải thích đơn giản như sau, đầu tiên vi xử lý chia nhỏ điện áp tham chiếu Vref làm 1023 khoảng, sau đó so sánh giá trị điện áp đặt tại chân đầu vào ADC xem điện áp cần đo đó nằm ở khoảng bao nhiêu. Giá trị ADC đo được chính là số thứ tự của khoảng điện áp tương ứng.

Hình 11: Hoạt động của ADC

Page 15: Giao trinh avr

15 Như hình trên, Vref được chia làm 1023 khoảng, từ 0 đến 1023. Điện áp cần đo Vin đặt

vào chân ADC0, sau khi đo, bộ ADC sẽ trả về giá trị i, là khoảng điện áp ứng với Vin. Như vậy giá trị điện áp Vin cần đo là:

ef1023in riV V=

Với độ phân giải không đổi, ta thấy nếu càng giảm Vref thì các khoảng điện áp càng thu nhỏ, tức là ta đo được điện áp Vin càng chính xác. Tuy nhiên Vref không được nhỏ hơn giá trị lớn nhất của Vin.

Các cách kích hoạt bộ chuyển đổi ADC, chọn kênh đo, điện áp tham chiếu và đo bằng ADC sẽ được trình bày trong ví dụ Chuyển đôi ADC.

Tóm tắt 3.5 Ø Dùng ADC để đo điện áp tại các kênh ADC. ATmega16 có 8 kênh ADC

với độ phân giải 10 bit. Ø Chọn Vref không quá lớn để phép đo được chính xác. Ø Điện áp cần đo: =

Page 16: Giao trinh avr

16 3.6 Giao tiếp USART USART được trình bày trong tài liệu này là một chuẩn truyền thông nối tiếp không đồng

bộ giữa các thiết bị digital. Chức năng USART trên vi xử lý ATmega16 là một trong số các chức năng vi xử lý dùng để truyền/nhận dữ liệu với các thiết bị khác (máy tính, vi xử lý khác…).

3.6.1 Các thuật ngữ được dùng trong giao tiếp USART Truyền thông nối tiếp không đồng bộ: Trong nhiều bài toán cần sử dụng vi xử lý và

máy tính kết nối với nhau. Trong quá trình làm việc đó vi xử lý cần trao đổi dữ liệu với máy tính, ví dụ như vi xử lý gửi giá trị đo đạc bằng ADC về máy tính và máy tính gửi tín hiệu điều khiển xuống vi xử lý…

Giả sử dữ liệu cần trao đổi là các mã có chiều dài 8 bit, cách đơn giản nhất là kết nối 1 PORT (8 bit) của vi điều khiển với máy tính, mỗi dây nối sẽ chịu trách nhiệm truyền/nhận 1 bit dữ liệu. Đây gọi là cách giao tiếp song song, cách này là cách đơn giản nhất, nhưng nhược điểm của cách truyền này là số đường truyền quá nhiều, giá trị càng lớn thì số đường truyền cũng sẽ nhiều thêm.

Trong truyền thông nối tiếp dữ liệu được truyền từng bit trên 1 (hoặc một ít) đường truyền, vì thế tiết kiệm đường truyền dữ liệu. Hình sau mô tả sự so sánh giữa 2 cách truyền song song và nối tiếp trong việc truyền con số 187 thập phân (tức 10111011 nhị phân).

Hình 12: Phương pháp truyền song song (a) và nối tiếp (b)

Vì dữ liệu cần được “chia nhỏ” thành từng bit khi truyền/nhận, tốc độ truyền nối tiếp sẽ bị giảm. Mặt khác, để đảm bảo tính chính xác của dữ liệu, bộ truyền và bộ nhận cần có những “thỏa hiệp” hay những tiêu chuẩn nhất định.

Khái niệm “đồng bộ” để chỉ sự “báo trước” trong quá trình truyền. Lấy ví dụ thiết bị 1 (tb1) kết với với thiết bị 2 (tb2) bởi 2 đường, một đường dữ liệu và 1 đường xung nhịp. Cứ mỗi lần tb1 muốn gửi 1 bit dữ liệu, tb1 điều khiển đường xung nhịp chuyển từ mức thấp lên mức cao báo cho tb2 sẵn sàng nhận một bit. Bằng cách “báo trước” này tất cả các bit dữ liệu có thể truyền/nhận dễ dàng với ít “rủi ro” trong quá trình truyền. Tuy nhiên, cách truyền này đòi hỏi ít nhất 2 đường truyền cho 1 quá trình (gửi hoặc nhận dữ liệu).

Khác với cách truyền đồng bộ, truyền thông “không đồng bộ” chỉ cần một đường truyền cho một quá trình. “Khung dữ liệu” đã được chuẩn hóa bởi các thiết bị nên không cần đường xung nhịp báo trước dữ liệu đến. Ví dụ 2 thiết bị đang giao tiếp với nhau theo phương pháp này, chúng đã được thỏa thuận với nhau rằng cứ 1ms thì sẽ có 1 bit dữ liệu truyền đến, như thế thiết bị nhận chỉ cần kiểm tra và đọc đường truyền mỗi mili-giây để đọc các bit dữ liệu và sau đó kết hợp chúng lại thành dữ liệu có ý nghĩa. Truyền thông nối tiếp không đồng bộ vì thế hiệu quả hơn truyền thông đồng bộ (không cần nhiều đường truyền). Tuy nhiên, để quá trình truyền thành công thì việc tuân thủ các tiêu chuẩn truyền là hết sức quan trọng.

Baud rate (tốc độ Baud): như trong ví dụ trên về việc truyền 1 bit trong 1ms, bạn thấy rằng để việc truyền và nhận không đồng bộ xảy ra thành công thì các thiết bị tham gia phải “thống nhất” nhau về khoảng thời dành cho 1 bit truyền, hay nói cách khác tốc độ truyền phải

Page 17: Giao trinh avr

17

được cài đặt như nhau trước, tốc độ này gọi là tốc độ Baud. Theo định nghĩa, tốc độ baud là số bit truyền trong 1 giây. Ví dụ nếu tốc độ baud được đặt là 19200 thì thời gian dành cho 1 bit truyền là 1/19200 ~ 52.083us.

Frame (khung truyền): Khung truyền bao gồm các quy định về số bit trong mỗi lần truyền, các bit “báo” như bit Start và bit Stop, các bit kiểm tra như Parity, ngoài ra số lượng các bit trong một data cũng được quy định bởi khung truyền. Hình dưới là một ví dụ của một khung truyền theo UART, khung truyền này được bắt đầu bằng một start bit, tiếp theo là 8 bit data, sau đó là 1 bit parity dùng kiểm tra dữ liệu và cuối cùng là 1 bits stop.

Hình 13: Khung truyền theo USART

Start: start là bit đầu tiên được truyền trong một frame truyền, bit này có chức năng báo cho thiết bị nhận biết rằng có một gói dữ liệu sắp được truyền tới. Start là bit bắt buộc phải có trong khung truyền.

Data: data hay dữ liệu cần truyền là thông tin chính mà chúng ta cần gửi và nhận. Thường data gồm 8 bit.

Parity bit: parity là bit dùng kiểm tra dữ liệu truyền đúng không (một cách tương đối). Parity bit không phải là bit bắt buộc và vì thế chúng ta có thể loại bit này khỏi khung truyền (các ví dụ trong tài liệu này không dùng bit parity).

Stop bits: stop bits là một hoặc các bit báo cho thiết bị nhận rằng một gói dữ liệu đã được gởi xong. Stop bits là các bits bắt buộc xuất hiện trong khung truyền.

3.6.2 Giao tiếp USART trên ATmega16 Vi điều khiển Atmega16 có 1 module truyền thông nối tiếp USART. Với chế độ truyền

nối tiếp không đồng bộ (cụ thể trong tài liệu này là giao tiếp với máy tính), chúng ta sử dụng 2 chân của Atmega16 để phục vụ cho truyền nhận dữ liệu là: chân truyền dữ liệu – TxD (Transmitted Data) và chân nhận dữ liệu – RxD (Reveived Data).

Hình 14: Hai chân RXD và TXD dùng trong giao tiếp với máy tính

Mô-đun USART trên chip Atmega16 hoạt động theo chế độ quá trình truyền và nhận dữ liệu có thể xảy ra đồng thời.

Khi sử dụng USART để giao tiếp với máy tính, phải thiết lập các thông số hoạt động ở vi xử lý và trên máy tính giống nhau, bao gồm:

Page 18: Giao trinh avr

18

• Baud rate: Baud rate càng cao, tốc độ truyền càng nhanh, tuy nhiên xác suất xảy ra lỗi trong quá trình truyền/nhận cũng lớn hơn. Thường chọn Baud rate = 9600 với các ứng dụng không đòi hỏi tốc độ cao.

• Frame: Khung truyền bao gồm start bit, data, parity bit và stop bit, trong đó start bit là cố định và không thay đổi. Ví dụ trong tài liệu này sẽ lấy khung truyền có 8 bit data, không dùng parity bit và 1 bit stop.

USART của ATmega16 cũng có tính năng ngắt. Ngắt của USART xảy ra khi hoàn tất gửi xong một dữ liệu, hoặc nhận xong một dữ liệu. Tính năng ngắt khi nhận xong một dữ liệu sẽ được dùng trong ứng dụng truyền dữ liệu từ vi xử lý về máy tính.

Cách kích hoạt mô-đun USART, thiết lập các thông số Baud rate, Frame… và cách sử dụng USART sẽ được trình bày trong ví dụ Giao tiếp USART.

Tóm tắt 3.6 Ø Kết nối với máy tính dùng chức năng USART. Ø Baud rate = 9600; khung truyền có 8 bit data, 1 bit stop, không dùng

parity. Ø Ngắt khi truyền/nhận dữ liệu hoàn tất.

Page 19: Giao trinh avr

19 4 Các bài tập ví dụ Tất cả các mạch điện sử dụng vi xử lý lập trình được đều được thiết kế theo trình tự:

• Phân tích mạch: Yêu cầu, đặc điểm làm việc, … • Xây dựng nguyên lý điều khiển. • Vẽ mạch mô phỏng. • Lập trình cho vi xử lý. • Kiểm tra lập trình trên mạch mô phỏng, sửa lỗi lập trình hoặc mạch nguyên lý

nếu phát hiện lỗi. • Làm mạch thật. Kiểm tra lỗi trên mạch thật và tiến hành sửa hoặc làm lại mạch

nếu cần thiết. Các bài tập ví dụ trong tài liệu này sẽ hướng dẫn người đọc chạy mô phỏng trên phần

mềm Proteus. Phần chạy thử trên mạch thật được thực hiện trên mạch đã được làm sẵn, sẽ có sơ đồ nguyên lý và sơ đồ đi dây kèm theo.

4.1 Lập trình điều khiển thiết bị ngoài (Led, động cơ…) Đây là ví dụ đầu tiên và đơn giản nhất trong các ví dụ ứng dụng vi xử lý, vì vậy sẽ được

viết kỹ từng bước và giải thích thật đơn giản. Bài ví dụ “Lập trình điều khiển thiết bị ngoài” đang nói tới thực ra là điều khiển đóng-

ngắt các thiết bị ngoài (đèn Led, động cơ…) thay cho công-tắc điện, và là dạng điều khiển đơn giản nhất trong các ứng dụng của vi điều khiển.

Mạch điện trong ví dụ này sẽ làm việc như sau: Điều khiển đèn Led sáng/tắt theo chu kỳ 0,5 giây.

4.1.1 Phân tích mạch điện Với bất cứ một dự án (Project) thiết kế mạch điện nào, công việc đầu tiên cũng đều là

phân tích mạch điện cần thiết kế. Dựa vào yêu cầu và đặc điểm làm việc, chúng ta có thể xây dựng được nguyên lý làm việc của các khối cơ bản của mạch (khối điều khiển, khối công suất…) và lập trình cho vi xử lý.

Với ví dụ điều khiển Led như trên, yêu cầu và đặc điểm làm việc như sau: • Led sáng rồi tắt theo chu kỳ 0,5 giây. • Giữa các lần sáng/tắt của Led, không điều khiển thêm thiết bị nào khác. • Led có công suất bé (cỡ 0,1 W).

4.1.2 Xây dựng nguyên lý điều khiển Như ở phần 1 đã nói, người dùng có thể lập trình để điều khiển điện áp tại một hay một

số chân của vi điều khiển. Có hai mức điện áp là 0V và +5V, và được gán với trạng thái 0 và 1 tương ứng. Ví dụ chân số 6 (PB5) của vi điều khiển ở trạng thái 1, tức là tại chân đó có điện áp +5V, còn nếu ở trạng thái 0, tức là tại chân đó có điện áp bằng 0 (nối đất – GND).

Ý tưởng đưa ra là ta có thể dùng điện áp này để chạy một thiết bị nào đó nối trực tiếp với chân của vi điều khiển. Tuy nhiên với điện áp +5V, đồng thời dòng điện cho phép nhỏ (vài chục mA), nên ta chỉ có thể nối trực tiếp vào vi điều khiển những thiết bị có công suất rất nhỏ, ví dụ như: đèn LED.

Page 20: Giao trinh avr

20

Hình 15: Nối trực tiếp vi xử lý với thiết bị có công suất nhỏ

Thực tế, để có thể điều khiển những thiết bị có công suất lớn hơn (hoặc làm cho Led sáng hơn), người ta không nối trực tiếp vi điều khiển với thiết bị, mà qua một mạch công suất. Có thể hiểu mạch công suất như một rơ-le trong mạch điện dân dụng.

Hình 16: Sơ đồ dùng điện thế 5V công suất nhỏ để điều khiển Mo-tơ 12V công suất lớn

Có nhiều linh kiện điện tử có thể thay thế cho một rơ-le, điển hình là các transistor. Hình sau thể hiện nguyên lý hoạt động của mạch:

Hình 17: Vi xử lý điều khiển đóng/mở transistor để điều khiển tải

Một mạch tương tự như mạch transistor trình bày ở trên được gọi là mạch công suất, còn khối vi xử lý được gọi là mạch điều khiển.

Bình thường khi chân 6 của vi điều khiển (nối với chân B của transistor) ở trạng thái 0 (0V), thì transistor đóng, tức là E và C không thông nhau.

Khi vi điều khiển chuyển trạng thái chân 6 sang 1 (+5V), transistor mở, tức là dòng điện từ nguồn có thể chạy từ E sang C, qua tải rồi về âm.

Như vậy thay đổi trạng thái chân 6 sẽ điều khiển bật/tắt được Led.

Page 21: Giao trinh avr

21 4.1.3 Mô phỏng trên Proteus Mô phỏng trên Proteus tức là xây dựng mạch nguyên lý và chạy thử nghiệm trên máy

tính bằng phần mềm Proteus. Trình tự tiến hành mô phỏng mạch nguyên lý đóng/mở transistor bằng Proteus như sau:

Hình 18: Mở thư viện Proteus

Mở phần mềm Proteus, click vào các biểu tượng “1” và “2” để chọn lịnh kiện. Sau khi click vào “2”, một của sổ mới sẽ hiện ra, cho phép chọn linh kiện.

Hình 19: Thư viện Proteus

Gõ tên linh kiện vào ô Keywords, ví dụ “mega16”, các linh kiện tìm được sẽ hiện bên ô Result, click chuột để chọn linh kiên ATMEGA16 như trên hình 2.

Gõ tiếp “npn” để tìm linh kiện transistor loại PNP, gõ “led” để tìm linh kiện LED. Sau đó sắp xếp và nối dây cho các linh kiện như trong hình 3.

Page 22: Giao trinh avr

22

Hình 20: Mạch mô phỏng ví dụ Điều khiển thiết bị ngoài

4.1.4 Lập trình cho vi xử lý Lập trình chi vi xử lý AVR, cũng như với các vi xử lý khác, nên tiến hành theo các bước

như sau, để tạo thuận lợi trong việc xây dựng thuật toán, kiểm tra và sửa lỗi lập trình. • Xác định yêu cầu làm việc của vi xử lý. • Xây dựng thuật toán điều khiển. • Chuẩn bị lập trình và viết chương trình điều khiển. • Kiểm tra và sửa lỗi.

a) Xác định yêu cầu làm việc của vi xử lý Trong ví dụ này, vi xử lý chỉ cần điều khiển trạng thái của chân số 6 của vi xử lý (có ký

hiệu PB5/MOSI trên Proteus) thay đổi giữ mức 0 (0V) và 1 (+5V) theo chu kỳ 0,5 giây.

b) Xây dựng thuật toán điều khiển. Thuật toán điều khiển ở trong bài ví dụ này khá đơn giản, theo sơ đồ sau:

Hình 21: Sơ đồ thuật toán điều khiển vi xử lý

Sơ đồ được giải thích như sau: • Khi được cấp điện, vi xử lý chuẩn bị cho bước “Bắt đầu”, bao gồm thiết lập chân

PB5 (ứng với chân số 6 của vi xử lý) là chân điều khiển, có trạng thái ban đầu là 0 (Led tắt).

• Sau đó vi xử lý làm việc theo chiều các mũi tên. Đầu tiên là đặt trạng thái chân PB5 = 1 để Led sáng.

• Đợi 0,5 s. • Đặt trạng thái PB5 = 0 để Led tắt. • Đợi 0,5 s. • Quay lại bước thứ 2 (PB5 = 1). • …….

Việc vi xử lý lặp đi lặp lại các bước như trên được gọi là “lặp”. Có nhiều cách để tạo vòng lặp và điều khiển vòng lặp, sẽ được trình bày trong các ví dụ.

Page 23: Giao trinh avr

23 c) Chuẩn bị lập trình bằng phần mềm CodeVision. Mở phần mềm CodeVision, nhấn Ctrl+N để tạo Project (dự án) mới, trong hộp thoại

“Create New File” chọn “Project” rồi nhấn “OK” à “Yes”.

Hình 22: Tạo project mới

Hình 23: Sử dụng CodeWizardAVR

Hộp thoại “CodeWizardAVR” hiện ra, chọn tên chip là ATmega16, và chọn tần số hoạt động của chip (ví dụ 4000000 Hz = 4Mhz).

Hình 24: Chọn vi xứ lý và tần số hoạt động

Hộp thoại “CodeWizardAVR còn có nhiểu mục khác, ứng với các chức năng của vi xử lý như USART, ADC, External IRQ (ngắt) đã nói trong phần giới thiệu. Nhưng nếu chỉ cần điều khiển trạng thái các chân của vi xử lý, ta chỉ cần vào mục Ports để quy định chức năng vào/ra của chân vi xử lý.

Page 24: Giao trinh avr

24

Hình 25: Thiết lập các Port

Trên Proteus chúng ta muốn dùng chân số 6 của vi xử lý, có ký hiệu PB5, tức là chân ứng với Bit 5 của Port B, vì vậy chúng ta set Bit 5 thành “Out” như trên hình.

Sau khi thiết lập ban đầu cho Atmega16 xong, click “File” à “Generate, Save and Exit”.

Hình 26: Tạo và lưu project

Sau đó sẽ có 3 hộp thoại hiện ra để lưu các file cần thiết. Đặt tên và lưu các file đó vào cùng một thư mục như trong hình.

Page 25: Giao trinh avr

25

Hình 27: Chọn thư mục lưu project

Sau khi lưu xong ta sẽ thấy một ô để viết các lệnh lập trình theo ngôn ngữ C. Các dòng lệnh chúng ta viết sẽ được lưu trong file “bai1.c”.

Hình 28: Nơi viết các dòng lệnh

d) Viết chương trình điều khiển. Khi mới tạo ra file bai1.c đã được ghi rất nhiều dòng lệnh, do phần mềm tự tạo ra theo

các thiết lập ở phần “CodeWizardAVR” chúng ta vừa làm. Tuy nhiên với bài này, chúng ta chỉ cần theo tác ở một vài vị trí trong file “bai1.c”. Trình tự tiến hành được trình bày như sau:

Include các file header: Viết thêm dòng lệnh #include <delay.h> vào vị trí như trong hình dưới. File delay.h là một file có sẵn của phần mềm Codevision, dùng khi muốn delay (trì hoãn, tạm dừng) quá trình làm việc của vi xử lý trong một khoảng thời gian định trước, trong ví dụ ta dùng để tạm dừng 0,5 s.

Page 26: Giao trinh avr

26

Hình 29: “Include” các file *.h cần thiết

CodeVision có nhiều file *.h khác nhau (h là viết tắt của header), mỗi file *.h đó được tạo sẵn cho các ứng dụng của vi xử lý. Tên một số file *.h và chức năng của các file đó được cho như bảng.

Tên file Chức năng liên quan delay.h Tạm dừng vi xử lý. stdio.h Giao tiếp với máy tính. LCD.h Ghi các ký tự ra LCD

Một số file *.h và chức năng liên quan. Khi muốn sử dụng tính năng nào có liên quan, thì ta thêm dòng lệnh #include <*.h> vào vị trí đã nói ở trên. Vòng lặp while chính: Trong file bai1.c vừa tạo ra cũng đã có sẵn một vòng lặp while

liên tục (vòng lặp while chính), đây là nơi viết các dòng lệnh (code) cho bài tập Điều khiển thiết bị ngoài.

Hình 30: Vòng lặp while liên tục được tạo sẵn

Các dòng chữ sau ký hiệu “//” chỉ có ý nghĩa chú thích, không ảnh hưởng tới lập trình. Vòng lặp while có cú pháp:

while (x) {

Các dòng lệnh }

Trong đó x gọi biến logic (chỉ nhận giá trị đúng hoặc sai tương ứng với 1 hoặc 0), vòng lặp while có nghĩa là chừng nào biến x có giá trị đúng, vi xử lý sẽ thực hiện lặp đi lặp lại các dòng lệnh viết trong vòng lặp.

Page 27: Giao trinh avr

27 Như trên hình ta thấy while (1), có nghĩa là x luôn bằng 1, và vòng lặp này xảy ra

mãi trong suốt quá trình hoạt động có vi xử lý. Nhắc lại thuật toán điều khiển đơn giản đã được trình bày ở trên:

Hình 31: Thuật toán điều khiển đơn giản cho ví dụ

Quá trình lặp đi lặp lại các bước trên hình có thể được thực hiện bằng một vòng lặp while, ở đây ta dùng vòng lặp while mà phân mềm Code vision đã tạo sẵn.

Như vậy có thể hình dung các lệnh trong vòng lặp while chính như sau: while (1) { Đưa trạng thái chân PB5 = 1 (bật Led); Đợi 0,5 s; Đưa trạng thái chân PB5 = 0 (tắt Led); Đợi 0,5 s; }

Các lênh trong vòng lặp while: Để cụ thể hóa các bước trong vòng lặp while ở trên, ta phải viết các bước đó thành các lệnh (code) theo ngôn ngữa lập trình.

- Đưa trạng thái (set trạng thái) chân PB5 về 1 hoặc 0: Với phần mềm CodeVision, có thể set trạng thái cho các chân bằng lệnh:

PORTx.y = z; Trong đó: x là tên PORT tường ứng, ví dụ chân PB5 thì x là B.

Y là thứ tự chân (từ 0 đến 7), ví chân PB5 thì y là 5. Z là trạng thái muốn set, ví dụ 0 hoặc 1.

Như vậy để set trạng thái chân PB5 lên 1, ta dùng lệnh: PORTB.5 = 1;

Còn muốn sét trạng thái chân PB5 xuống 0, ta dùng lệnh PORTB.5 = 0; - Đợi 0,5 s:

Để đợi (tạm dừng chương trình) trong một khoảng thời gian (tính bằng ms hoặc µs), ta phải include file delay.h và dùng lệnh sau:

Tính bằng ms: delay_ms(x); Tính bằng µs: delay_us(x);

Trong đó x là số ms hoặc µs tương ứng ta muốn chương trình đợi. Trong ví dụ ta muốn dừng chương trình trong khoảng thời gian là 0,5 s = 500 ms = 500 000 µs, thì dùng lệnh sau:

delay_ms(500); hoặc delay_us(500000);

Như vậy cấu trúc và các lệnh trong vòng lặp while cho ví dụ sẽ là:

Page 28: Giao trinh avr

28

while (1) {

PORTB.5 = 1; delay_ms(500);

PORTB.5 = 0; delay_ms(500);

}

Hình 32: Đoạn code trong vòng lặp while

e) Kiểm tra lỗi cú pháp và complie. Sau khi viết hết các code, nhấn CTRL+F9 để tiến hành complie (biên dịch từ ngôn ngữ

C sang ngôn ngữ máy), phần mềm CodeVision sẽ tiến hành kiểm tra các lỗi cú pháp, cũng như các thủ tục khác được viết trong file “bai1.c”. Nếu không có sai sót, phần mềm sẽ tạo ra file “bai1.hex” lưu trong thư mục “/bai1/exe/”. File này sẽ dùng để chạy mô phỏng trên Proteus và nạp cho vi xứ lý khi làm mạch thật.

Nếu có lỗi cú pháp hoặc các thủ tục khác trong quá trình lập trình, CodeVision sẽ thông báo có lỗi và có ghi chú lỗi để người lập trình có thể tìm ra và sửa lỗi.

Hình 33: Ví dụ về lỗi thiếu dấu “;” ở câu lệnh

Chỉ dẫn báo lỗi tìm thấy sau khi check đến dòng 120, và lỗi thực sự thì nằm ở dòng 119 Quá trình kiểm tra và sửa lỗi cú pháp lặp đi lặp lại tới khi CodeVision thông báo không

còn lỗi và tạo file *.hex thành công.

Page 29: Giao trinh avr

29 4.1.5 Chạy thử trên mạch mô phỏng Sau khi lập trình và có được file “bai1.hex”, ta tiến hành chạy thử trên mạch mô phỏng.

Trở lại mạch mô phỏng bằng phần mềm Proteus:

Hình 34: Mạch nguyên lý xây dựng trên Proteus của ví dụ

Click đúp vào biểu tượng vi xử lý ATmega16 trên mạch mô phỏng, hợp thoại Edit Component của ATmega 16 sẽ mở ra:

Hình 35: Hộp thoại Edit Component

Trong hộp thoại Edit Component, ở ô Program File, click chọn đường dẫn tới file bai1.hex vừa tạo ra bằng phần mềm CodeVision. Ở ô CKSEL Fuses, chọn tần số cho thạch anh là 4Mhz.

Sau khi thiết lập xong, nhấn nút Start ở góc dưới bên trái màn hình để chạy mạch mô phỏng, nếu các bước trên làm chính xác, thì kết quả trên màn hình sẽ thấy đèn Led sáng nhấp nháy theo chu kỳ 0,5s. Nếu muốn dừng mô phỏng, nhấn nút Stop.

Page 30: Giao trinh avr

30

Hình 36: Nút Start và Stop

Quan sát trên màn hình, sẽ thấy màu của chân PB5 nhấp nháy xanh đỏ theo chu kỳ 0,5s. Màu đỏ ứng với mức điện áp +5V, màu xanh ứng với mức điện áp 0v. Khi chân PB5 màu đỏ thì Led sáng, khi chân PB5 màu xanh thì đèn tắt đúng như nguyên lý điều khiển đã trình bày.

Như vậy sau bài tập Điều khiển thiết bị ngoài, người đọc có thể tự mở rộng thêm, ví dụ như nháy nhanh rồi nháy chậm theo chu kỳ, điều khiển 2 hay nhiều đèn Led cùng lúc và cho chúng phối hợp sáng/tắt với nhau theo ý muốn, hiển thị trên led 7 thanh, điều khiển bật/tắt động cơ...

Tóm tắt 4.1

Ø Điều khiển thiết bị ngoài qua mạch công suất. Ø Các theo tác trên các phần mềm Proteus và CodeVision. Ø Khái niệm delay, lặp… Ø Các file header, set trạng thái các chân của vi xử lý. Câu hỏi mở rộng: Ø Điều khiển nhiều led bằng nhiều chân của vi điều khiển. Ø Hiển thị số trên led 7 thanh (cấu tạo và nguyên lý hoạt động của led 7

thanh xem ở phần phụ lục).

Page 31: Giao trinh avr

31 4.2 Lập trình ngắt ngoài (INT) Ngắt ngoài là một tính năng của vi xử lý ATmega16 cho phép vi xử lý giao tiếp với

người dùng (qua thao tác bấm nút) hoặc nhận biết sự kiện bên ngoài (đếm sự kiện). Bài ví dụ lập trình ngắt ngoài sẽ trình bày trong tài liệu này như sau: Điều khiển tốc độ

nhấp nháy của đèn led (0,5s hoặc 2s) qua thao tác nhấn nút điều khiển. 4.2.1 Phân tích mạch điện Ban đầu khi cấp điện, vi xử lý điều khiển sáng/tắt đèn led theo chu kỳ 0,5s. Khi người dùng nhấn nút điều khiển, chu kỳ sáng/tắt đèn led được điều chỉnh thành 2s. Khi người dùng nhấn nút điều khiển lần nữa, chu kỳ sáng/tắt đèn led lại được điều chỉnh

về 0,5s. … Như vậy ta thấy về cơ bản, phần lập trình điều khiển sáng/tắt led tương tự như ví dụ Điều

khiển thiết bị ngoài, chỉ khác ở chỗ chu kỳ sáng/tắt (trong hàm delay_ms()) được thay đổi theo tác động bấm nút của người dùng nhờ tính năng ngát ngoài.

4.2.2 Nguyên lý điều khiển và xây dựng mạch mô phỏng trên Proteus Nguyên lý điều khiển giống như trong bài ví dụ Điều khiển thiết bị ngoài. Mạch mô phỏng trên Proteus cũng tương tự ví dụ Điều khiển thiết bị ngoài, trừ việc có

thêm một nút bấm đưa vào chân PD2/INT0 để điều khiển ngắt INT0.

Hình 37: Mạch mô phỏng ví dụ Lập trình sử dụng ngắt

Page 32: Giao trinh avr

32 4.2.3 Lập trình cho vi xử lý

a) Xác định yêu cầu làm việc của vi xử lý Vi xử lý điều khiển bật/tắt đèn Led theo chu kỳ 0,5s và 2s theo tác động bấm nút của

người dùng.

b) Xây dựng thuật toán điều khiển Thuật toán cho ví dụ được thể hiện trên sơ đồ sau:

Hình 38: Sơ đồ thuật toán ví dụ Lập trình sử dụng ngắt ngoài Ý tưởng của thuật toán này như sau Chu kỳ nháy được đặt bằng một biến x, trong chương trình, x hoặc có giá trị 500 (0,5s)

hoặc 2000 (2s). Khi ngắt ngoài được kích hoạt, chương trình ngắt gán giá trị x = 2000 (nếu giá trị hiện

thời của x = 500), hoặc gán giá trị x = 500 (nếu giá trị hiện thời của x = 2000). Chương trình chính sẽ thực hiện điều khiển nháy led với chu kỳ x. Như vậy khi người dùng nhấn nút, sẽ kích hoạt ngắt ngoài, đổi giá trị biến x, đèn led sẽ

được điều khiển nhấp nháy theo giá trị biến x tương ứng.

c) Chuẩn bị lập trình bằng phần mềm CodeVision. Các bước chọn vi xử lý, tần số thạch anh, chức năng I/O cho chân PB5 được thực hiện

giống như ví dụ Điều khiển thiết bị ngoài. Để kích hoạt tính năng INT0, trong cửa sổ CodeWizardAVR, chọn thẻ External IRQ

(ngắt ngoài) và thiết lập như hình sau.

Hình 39: Kích hoạt INT0

Trong ô “Mode”, click chọn “Falling Edge” để chọn chế độ kích hoạt ngắt ở cạnh lên.

d) Viết chương trình điều khiển. Trong ví dụ này có sử dụng biến x để đặc trưng cho chế độ làm việc của mạch. Biến là

một khái niệm trong lập trình, để chỉ các giá trị số, giá trị logic, chuỗi ký tự, matrận… Biến có thể có giá trị không đổi hoặc thay đổi trong lập trình tùy thuộc vào cách sử dụng.

Page 33: Giao trinh avr

33 Mỗi kiểu biến có đặc trưng khác nhau (để chỉ giá trị số, giá trị logic…), muốn sử dụng

biến trong lập trình cần phải có bước “khai báo”. Bao gồm khai báo tên biến (x, y, bien1, bien2,…) và kiểu dữ liệu(char, str, …). Các kiểu và thuộc tính của kiểu dữ liệu được cho trong bản phần phụ lục.

Trong ví dụ này ta khai báo biến x là biến kiểu int (giá trị số nguyên từ -32768 ~ +32767).

Include thêm file header sau: delay.h. Khai báo biến bằng dòng lệnh: char x=500; Ở đây chúng ta gán cho x giá trị

x=500 ngay từ đầu, để khi cấp điện, đèn led nhấp nháy ngay với chu kỳ 0,5s.

Hình 40: Khai báo biến và nơi viết chương trình ngắt

Viết chương trình phục vụ ngắt ngoài: Trình phục vụ ngắt ngoài được viết tại vị trí như trong hình trên. Cấu trúc chương trình ngắt có thể được hình dung như sau:

interrupt [EXT_INT0] void ext_int0_isr(void) { Nếu x=500, gán giá trị x=2000; Nếu x không bằng 500, gán giá trị x=500; } Phép so sánh điều kiện “nếu” ở trên trong lập trình được gọi là phép so sánh if, cấu trúc

của lệnh if như sau: if (biểu thức so sánh) { Các dòng lệnh A; } else { Các dòng lệnh B; } Trong đó “biểu thức so sánh” là một biểu thức logic, giá trị trả về là 0 hoặc 1. Ví dụ khi

muốn so sánh giá trị của x (có giá trị hiện thời là 2000) xem có bằng 500 hay không, ta viết: x == 500;

Ký hiệu hai dấu bằng “==” là ký hiệu của phép so sánh, như dòng lệnh trên, giá trị trả về sẽ bằng 0, vì giá trị hiện thời của x là 2000 khác 500

x == 500 = 0; Nếu biểu thức so sánh trả về giá trị 1, các dòng lệnh a sẽ được thực hiện, nếu giá trị biểu

thức so sánh trả về bằng không, các dòng lệnh B sẽ được thực hiện.

Page 34: Giao trinh avr

34 Như vậy đoạn code của chương trình ngắt như sau: if (x==500) { x=2000; } else { x=500; } Lúc này toàn bộ code được viết như sau:

Hình 41: Code chương trình ngắt

Chương trình trong vòng lặp while chính tương tự như trong ví dụ Điều khiển thiết bị ngoài, chỉ khác ở chỗ giá trị 500 ms chu kỳ nháy được thay bằng biến x.

Hình 42: Đoạn code trong vòng lặp while chính

Sau khi viết code, kiểm tra, sửa lỗi và complie thành công, dùng mạch mô mỏng vừa tạo trên phân mềm Proteus để chạy mô phỏng.

Tóm tắt Ø Cách hoạt động của ngắt ngoài. Ø Biến và kiểu dữ liệu của biến. Ø So sánh if.

Câu hỏi mở rộng Điều khiển led 7 thanh hiện các số từ tăng từ 0 đến 9 theo thao tác nhấn nút của người dùng.

Page 35: Giao trinh avr

35 4.3 Lập trình Timer/Counter Các bộ T/C trên ATmega16 có thể đảm nhiệm các vai trò khác nhau với cách thức hoạt

động và thiết lập khác nhau, nên cấu trúc và cách sử dụng tương đối phức tạp. Vì vậy ví dụ cho lập trình T/C được trình bày sau đây là chức năng đơn giản nhất của bộ T/C, chức năng định thời. Đồng thời, để ví dụ càng đơn giản hơn với người đọc, hoạt động của mạch trong ví dụ này giống như hoạt động của mạch bài ví dụ Lập trình ngắt ngoài INT.

Đề bài: Dùng bộ T/C điều khiển bật/tắt đèn led theo chu kỳ 0,5s hoặc 2s theo tác động của người dùng.

4.3.1 Phân tích, xây dựng nguyên lý điều khiển và mạch mô phỏng Do yêu cầu hoạt động của mạch giống với mạch ví dụ Lập trình ngắt ngoài INT, nên các

bước phân tích mạch, xây dựng nguyên lý điều khiển và mạch mô phỏng trên Proteus được tiến hành giống như trong ví dụ Lập trình ngắt ngoài.

4.3.2 Lập trình cho vi xử lý

a) Xác định yêu cầu làm việc của vi xử lý Vi xử lý điều khiển thay đổi mức trạng thái 0 và 1 của chân PB5 theo chu kỳ 0,5s hoặc

2s theo tác động ngoài. Chu kỳ thay đổi được tạo ra nhờ bộ T/C.

b) Xây dựng thuật toán điều khiển Người đọc sau khi đọc phân giới thiệu chữ năng IN/OUT, ngắt ngoài, T/C và làm ví dụ

Lập trình ngắt ngoài sẽ thấy rằng với bài tập này chỉ cần dùng hàm delay_ms() đơn giản để tạo chu kỳ thay đổi trạng thái chân điều khiển (PB5). Tuy nhiên chức năng định thời của bộ T/C khác với hàm delay_ms() ở chỗ T/C tạo khoảng thời gian theo các ngắt trong, còn hàm delay_ms() tạo các khoảng thời gian bằng cách dừng chương trình chính trong vòng lặp while chính. Với các bài toán sử dụng nhiều chức năng của vi xử lý hơn, tính dừng chương trình của hàm delay_ms() có thể ảnh hưởng xấu và làm sai lệch hoạt động của vi xử lý so với ý đồ lập trình ban đầu.

Để dễ hiểu, ta lấy ví dụ so sánh hoạt động của vi xử lý với một trường hợp ngoài thực tế hay gặp trong gia đình như sau:

Có hai mẹ con, mẹ đi làm, con ở nhà học bài. Tới 10h mẹ gọi điện dặn con đến 10h30 nấu cơm (nấu cơm sau 30’).

- Việc học bài của con ứng với chương trình được viết trong vòng lặp while chính. - Việc mẹ gọi điện dặn nấu cơm ứng với ngắt ngoài. - Khoảng thời gian từ 10h tới 10h30 ứng với khoảng thời gian xác định nhờ hàm

delay hoặc T/C.

Hình 43:Ví dụ so sánh hoạt động của vi xử lý

Page 36: Giao trinh avr

36

Đứa con có 2 cách để thực hiện việc mẹ dặn như sau: - Đứng tại nồi cơm mà không làm bất cứ hành động nào khác trong vòng 30’, sau đó

mới nấu cơm, rồi quay lại học tiếp. Cách này ứng với hàm delay, vì hàm delay dừng chương trình trong vòng lặp while chính, tức là việc học của đứa con.

- Tiếp tục học và hẹn đồng hồ 30’, khi đồng hồ báo, đứa con mới đi nấu cơm, sau khi nấu xong thì quay lại học tiếp. Cách này ứng với phương pháp dùng T/C, việc đồng hồ báo 30’ ứng với ngắt xảy ra trong bộ T/C.

Hình 44: Hoạt động của đứa con ứng với hàm delay và T/C

Như vậy có thể thấy nếu dùng T/C, thì chương trình trong vòng lặp while chính vẫn được tiếp tục thực hiện khi vi xử lý đang đếm khoảng thời gian. Điều này rất quan trọng khi lập trình sử dụng cùng lúc nhiều chức năng khác nhau của vi xử lý, vì việc xác định khoảng thời gian không làm gián đoạn tới các tiến trình hoạt động khác.

Sau khi hiểu sự khác nhau cơ bản giữa việc định thời gian bằng T/C và hàm delay, chúng ta đi xây dựng thuật toán điều khiển. Như trong phần giới thiệu chức năng T/C của ATmega16, bộ T/C1, để thay đổi quãng thời gian xảy ra ngắt của bộ T/C1, chúng ta cần thay đổi giá trị ban đầu của biến TCNT1 ứng với các khoảng thời gian 0,5s và 2s. Kết hợp với các ví dụ trên, ta có thể đưa ra sơ đồ làm việc của bộ Int0 và T/C1 như sau:

Hình 45: Sơ đồ làm việc bộ INT0 và T/C1

Việc thay đổi giá trị của biến TCNT1 ứng với chu kỳ 0,5s và 2s được thực hiện trong chương trình ngắt ngoài INT0 tương tự như thay đổi biến x trong ví dụ Lập trình ngắt ngoài INT.

Bộ T/C1 sẽ liên tục định ra các khoảng thời gian dựa theo biến TCNT1. Khi đếm được đủ khoảng thời gian tương ứng, chương trình ngắt của bộ T/C1 sẽ chuyển

trạng thái chân PB5 để điều khiển bật/tắt led.

Page 37: Giao trinh avr

37 Việc xác định giá trị cần gán cho biến TCNT1 ứng với các chu kỳ 0,5s và 2s cho vi xử lý

ATmega16, tần số thạch anh 4Mhz như sau:

Chu kỳ dao động thạch anh: 66

1 0,25.10 ( )4.10ot s−∆ = =

Nếu Prescale =1, để xác định được khoảng thời gian 2s, cần phải đếm:

6ax6

2 8.10 1 655350,25.10o mn TCNT−= = > =

Giá trị on lớn hơn giá trị ax1mTCNT khoảng 122 lần, tra datasheet của vi xử lý ATmega16 (bảng 48 trang 113) ta thấy ATmega16 cho phép chọn Prescale bằng 1; 8; 64; 256; 1024. Vậy ta chọn Prescale = 256.

Với Prescale = 256, chu kỳ đếm của biến TCNT1 là: 66

1256 64.10 ( )4.10

t s−∆ = =

Khi đó để xác định được chu kỳ 2s thì số lần phải đế làm: 1 6

2 3125064.10

n −= =

Giá trị ban đầu của biến TCNT1 ứng với chu kỳ 2s là:

2s1 65535 31250 34285TCNT = − = Nếu viết trong hệ cơ số 16: 2s1 85EDTCNT =

Tương tự để xác định được chu kỳ 0,5s thì số lần phải đếm là: 2 6

0,5 7812,564.10

n −= =

Vì 2n phải là số nguyên dương, nên ta chọn 2 7813n =

Sai số ở đây là 6 60,5.64.10 32.10 ( )sτ − −∆ = = Giá trị ban đầu của biến TCNT1 ứng với chu kỳ 0,5s là:

0,5s1 65535 7813 57772TCNT = − = Nếu viết trong hệ cơ số 16: 0,5s1 E1ACTCNT =

Sau khi xác định được các giá trị TCNT ban đầu, ta tiến hành lập trình cho vi điều khiển.

c) Chuẩn bị lập trình bằng phần mềm CodeVisionAVR Các bước chọn vi xử lý, tần số thạch anh, thiết lập In/Out chân PB5, thiết lập ngắt ngoài

INT0 giống như trong ví dụ Lập trình ngắt ngoài. Ngoài ra vì ví dụ này sử dụng bộ T/C1 nên chúng ta phải thiết lập các thông số ban đầu cho T/C1.

Hình 46: Thiết lập ban đầu cho bộ T/C1

Page 38: Giao trinh avr

38 Để kích hoạt bộ T/C1, trong cửa sổ CodeWizardAVR, ta vào mục Timers à Timer1.

Chế độ mặc định của T/C1 là chức năng định thời: Normal top=0xFFFF (chế độ định thời bình thường, giá trị TOP = FFFF theo hệ cơ số 16, tức là bằng 65535 trong hệ sơ số thập phân). Để chọn Prescale, kích hoạt ngắt của T/C1, giá trị ban đầu của biến TCNT1, ta làm qua 3 bước như trên hình 46.

• Bước 1 – Chọn Prescale: Ta đã chọn tần số thạch anh là 4Mhz = 4000 Khz,

Prescale = 256, tức là tần số làm việc của bộ T/C1 là 4000 15.625 z256

Kh= . Trong

mục Clock value, ta click chọn tần số làm việc của bộ T/C1 là 15,625 Khz. • Bước 2 – Kích hoạt ngắt T/C1: Để kích hoạt ngắt T/C1 khi đếm được khoảng

thời gian mong muốn (0,5s hoặc 2s ứng với thời điểm biến TCNT1 đếm tới 65535), ta click chọn “Timer1 Overflow” trong mục Interrupt on.

• Bước 3 – Chọn giá trị ban đầu cho biến TCNT1 viết theo hệ sơ số thập phân trong ô Value. Ta chọn giá trị “e1ac” ứng với 0,5s. Trong chương trình, ta có thể thay đổi giá trị này thành “85ed” tương ứng với chu kỳ 2s.

d) Viết chương trình điều khiển Như ở phần xây dựng thuật toán điều khiển, ta thấy rằng quá trình điều khiển trạng thái

chân PB5 không nằm trong vòng lặp while chính. Việc chọn giá trị TCNT1 ban đầu được thực hiện trong chương trình ngắt ngoài INT0 và thay đổi trạng thái chân PB5 được thực hiện trong chương trình ngắt của T/C1.

Do không sử dụng hàm delay_ms()cũng như các tính năng nào khác cần có file header, nên ta không cần include thêm file header nào khác.

Khai báo biến x kiểu unsigned int để gán giá trị biến TCNT1 ban đầu. Như đã nói kiểu int có giá trị từ -32768 tới +32767, còn kiểu unsigned int có giá trị từ 0 tới +65535, vì vậy ta chọn kiểu dữ liệu unsigned int.

Hình 47: Chương trình ngắt ngoài và ngắt của T/C1

Như trên hình 48, chúng ta chỉ thao tác trong chương trình ngắt ngoài và chương trình ngắt của T/C1.

Page 39: Giao trinh avr

39 Chương trình ngắt ngoài INT0 Tương tự như trong ví dụ lập trình ngắt ngoài, chương trình ngắt ngoài trong ví dụ này

cũng có chức năng thay đổi giá trị của biến x. Như đã trình bày ở trên, ứng với chu kỳ 0,5s hoặc 2s ta có giá trị của biến x là x = 0xE1AC và x = 0x85ED.

Hai ký tự 0x ở trên là hai ký tự dùng để thông báo cho vi xử lý biết rằng giá trị viết đằng sau theo hệ cơ số 16. Nếu muốn viết theo hệ cơ số 2, thì hai ký tự tương ứng sẽ là 0b. Còn nếu viết theo hệ sơ số 10 thì không cần chèn 2 ký tự vào trước giá trị.

Ví dụ số 214 trong hệ thập phân ứng với 11010110 trong hệ cơ số 2 và D6 trong hệ cơ số 16. Khi viết vào chương trình, để cho vi xử lý hiểu thì ta phải viết

214 hoặc 0b11010110 hoặc 0xD6 Sau khi làm ví dụ Lập trình ngắt ngoài, ta thấy chương trình con trong ví dụ này cũng

tương tự như sau: interrupt [EXT_INT0] void ext_int0_isr(void) { if (x == 0xE1AC) { x = 0x85ED; } else { x = 0xE1AC; }; }

Hình 49: Chương trình ngắt ngoài INT0

Chương trình ngắt của T/C1 Chương trình ngắt của T/C1 xảy ra khi biến TCNT1 đếm tới giá trị TOP (ở đây là

65535). Theo như thuật toán đã xây dựng, ngắt của T/C1 sẽ nghịch đảo trạng thái của chân PB5 và gán lại giá trị của biến TCNT1 bằng giá trị của biến x.

Khi tạo project, cấu trúc trong chương trình ngắt của T/C1 đã có sẵn như sau.

Page 40: Giao trinh avr

40

Hình 50: Ngắt của T/C1

Như hình trên, phần gán lại giá trị cho biến TCNT1 đã được viết sẵn, và luôn luôn gán lại giá trị E1AC đã thiết lập trong phần chuẩn bị T/C1. Vì vậy phải sửa lại đoạn code này để gán giá trị x cho biến TCNT1 thay vì giá trị E1AC. Người đọc có thể dễ dàng thấy rằng chỉ cần thay giá trị E1AC ở đoạn code trên bằng giá trị x như sau:

TCNT1H=x >> 8; TCNT1L=x & 0xff;

Để hiểu rõ đoạn code trên, người đọc cần phải có kiến thức về cấu trúc các thanh ghi, cũng như các phép dịch bit, các phép toán logic trong lập trình C. Để đơn giản hơn, có thể dùng chỉ một lệnh duy nhất sau đây để thay cho đoạn code trên.

TCNT1=x; Như vậy đoạn code dùng để gán lại giá trị cho biến TCNT1 sau khi sửa lại như sau.

Hình 51: Chương trình ngắt của T/C1 sau khi sửa

Tiếp theo ta cần viết đoạn code điều khiển trạng thái của chân PB5 vào trong chương trình ngắt của T/C1. Trong các ví dụ trước, người đọc đã biết cách gán trạng thái cho chân PB5 trực tiếp bằng 0 hoặc 1. Tuy nhiên có một cách ngắn hơn để thực hiện việc nghịch đảo trạng thái chân PB5 bằng dòng lệnh sau:

PORTB.5 = ~PORTB.5; Ký hiệu ~ ở trên là ký hiệu của phép nghịch đảo, dùng trong các phép toán logic. Câu

lệnh trên có nghĩa là giá trị trạng thái chân PB5 sẽ được gán bằng nghịch đảo của giá trị trạng thái chân PB5 hiện tại. Nếu trạng thái chân PB5 đang là 1, thì sau khi qua câu lệnh này, trạng thái chân PB5 sẽ được gán bằng 0 và ngược lại.

Như vậy chương trình ngắt của T/C1 sẽ là.

Hình 52: Chương trình ngắt củaT/C1 sau khi hoàn thiện

Page 41: Giao trinh avr

41 Sau khi viết xong, toàn bộ code viết thêm trong ví dụ này sẽ như sau.

Hình 53: Code của ví dụ Timer/Counter

Sau khi viết code, kiểm tra và complie thành công, chạy thử trên mạch mô phỏng Proteus, người đọc sẽ thấy mạch hoạt động như trong ví dụ Lập trình ngắt ngoài. Ban đầu led sẽ nháy theo chu kỳ 0,5s, khi nhấn nút, chu kỳ nháy là 2s, nhấn nút lần nữa, chu kỳ nháy sẽ trở về 0,5s…

Tóm tắt Ø Hoạt động của T/C1, phối hợp hoạt động của T/C1 và INT0. Ø Phép toán nghịch đảo.

Mở rộng 1. Đo số lần nhấn nút trong vòng 1 giây và hiển thị trên các led 7 thanh.

Page 42: Giao trinh avr

42 4.4 Điều khiển độ rộng xung PWM PWM là một chế độ hoạt động của các bộ Timer trên vi xử lý ATmega16. Để hiểu rõ

hơn cách tạo ra xung PWM, hãy đọc kỹ lại phần giới thiệu chức năng PWM của vi xử lý ATmega16.

Đề bài ví dụ Điều khiển độ rộng xung PWM như sau: dùng bộ T/C1 tạo xung vuông, Time Period 5ms, Duty Cycle được thay đổi bằng 1ms hoặc 4 ms theo tác động nhấn nút của người dùng. Xung này dùng điều khiển động cơ DC và hiển thị trên thiết bị Oscilloscope.

4.4.1 Phân tích mạch điện Đây là mạch nguyên lý điều khiển động cơ DC bằng PWM. Dựa theo đề bài và các hức

năng của ATmega16 đã được giới thiệu, ta phân tích hoạt động của mạch như sau: • Vi xử lý ATmega16 tạo xung PWM tại chân OC1A (chân PD5), điều khiển động

cơ DC qua mạch công suất. • Mạch ngắt ngoài được kết nối với vi xử lý qua chân INT2 (PB2), ứng với khối

ngắt ngoài INT2, để thay đổi Duty Cycle. • Chân OC1A cũng được nối với thiết bị Oscilloscope để hiển thị dạng xung vuông.

4.4.2 Nguyên lý điều khiển Nguyên lý điều khiển của mạch cũng tương tự như nguyên lý điều khiển thiết bị ngoài

nói chung. Đó là vi xử lý điều khiển mạch công suất, mạch công suất điều khiển thiết bị ngoài theo tín hiệu từ vi xử lý. Tuy nhiên trong các mạch công suất có chu kỳ đóng/ngắt nhanh (cỡ ms), thay vì sử dụng transistor thường thì người ta thường sử dụng các transistor công suất (IRF 540, 740…). Các transistor công suất hoạt động cũng tương tự như các transistor thường, chỉ khác ở các thông số như dòng mở hoặc điện áp mở, công suất phụ tải tối đa…

Hình 54: Nguyên lý mạch công suất dùng IRF540N trên Proteus

Như phần giới thiệu PWM, nếu giữ nguyên chu kỳ, tăng/giảm Duty Cycle của xung PWM thì thời gian đóng/ngắt của IRF cũng thay đổi, nhờ vậy thời gian đóng/ngắt mạch điện qua động cơ cũng thay đổi tương ứng, làm thay đổi tốc độ động cơ DC.

Page 43: Giao trinh avr

43 4.4.3 Xây dựng mạch mô phỏng trên Proteus Từ mục phân tích mạch điện, ta thấy mạch điện mô phỏng gồm có vi xử lý ATmega16,

mạch của khối ngắt ngoài, mạch công suất IRF540, động cơ DC và Oscilloscope.

Hình 55: Mạch nguyên lý điều khiển động cơ DC bằng PWM

Sau khi chọn các linh kiện từ thư viện và thiết bị Oscilloscope, chúng ta sắp xếp và nối dây cho các linh kiện như hình 55. Chú ý các chân đầu vào của INT2 và đầu ra xung PWM OC1A sẽ tương ứng với quá trình chuẩn bị lập trình sau này.

4.4.4 Lập trình cho vi xử lý

a) Xác định yêu cầu làm việc của vi xử lý Yêu cầu làm việc của vi xử lý trong bài ví dụ này là: Tạo xung PWM tại chân OC1A,

chu kỳ (Time Period) 20ms, Duty Cycle hoặc 1 ms hoặc 2ms theo sự kiện ngắt ngoài INT2.

b) Xây dựng thuật toán điều khiển Trước khi xây dựng thuật toán điều khiển PWM người đọc cần nắm rõ nguyên lý hoạt

động của bộ PWM đã được giới thiệu ở phần đầu tài liệu. Sau khi nắm rõ cơ bản nguyên lý hoạt động chế độ PWM của T/C1 trong ATmega16,

chúng ta thấy rằng Time Period và Duty Cycle phụ thuộc lần lượt vào giá trị hai biến ICR và OCR. Như vậy trong ví dụ này, với chu kỳ 20ms không đổi, Duty Cycle 1 ms hoặc 2ms thì ta chỉ cần thay đổi giá trị biến OCR trong chương trình ngắt ngoài.

Hình 56: Sơ đồ làm việc của ngắt ngoài và T/C1 ở chế độ tạo PWM

Thuật toán cũng tương tự như ở ví dụ Timer/Counter, chỉ khác ở chỗ chương trình ngắt ngoài dùng để thay đổi biến OCR1A thay vì giá trị x, và bộ T/C1 làm việc ở chế độ tạo xung PWM.

Page 44: Giao trinh avr

44 Bộ T/C1 có nhiều cách để tạo ra xung PWM (xem lại phần giới thiệu chức năng tạo

PWM ở phần trước), trong bài ví dụ sẽ trình bày chế độ Fast PWM.

Hình 57: Chế độ Fast PWM

Nhắc lại chế độ Fast PWM như ở hình 57, ta thấy rằng các giá trị ICR1, OCR1A cần được tính tương tự như khi tính giá trị biến TCNT1 ban đầu ở ví dụ Timer/Counter.

Chu kỳ dao động thạch anh: 66

1 0, 25.10 ( )4.10ot s−∆ = =

Chọn Prescale = 8, suy ra chu kỳ làm việc bộ T/C1: 6 6 30,25.10 .8 2.10 ( ) 2.10 ( s)t s m− − −∆ = = =

Giá trị ICR1 ứng với 5ms là: 3

5R1 25002.10

IC −= =

Nếu viết trong hệ cơ số 16: R1 9C4IC =

Giá trị OCR1A ứng với Duty Cycle 1ms là: 1 s 3

1R1A 5002.10mOC −= =

Nếu viết trong hệ cơ số 16: 1 sR1A 1 4mOC F=

Giá trị OCR1A ứng với Duty Cycle 2ms là: 1,5 s 3

4R1A 20002.10mOC −= =

Nếu viết trong hệ cơ số 16: 1,5 sR1A 7D0mOC =

Sau khi xác định các giá trị ICR1, OCR1A ta tiến hành lập trình cho vi xử lý ATmega16.

c) Chuẩn bị lập trình bằng phần mềm CodeVision Thiết lập các thông số và chức năng của vi xử lý ban đầu như sau.

• Vi xử lý ATmega16, thạch anh 4 Mhz. • Thiết lập In/Out cho chân OC1A. • Kích hoạt ngắt ngoài INT2.

Page 45: Giao trinh avr

45

Hình 58: Thiết lập T/C1 tạo PWM

Thiết lập T/C1 ở chế độ Fast PWM như sau. 1. Prescale = 8. 2. Chế độ: Fast PWM top = ICR1. 3. Out. A: Non-Inv. 4. Giá trị ICR1 = 9C4. 5. Giá trị OCR1A ban đầu = 1F4.

d) Viết chương trình điều khiển Cũng tương tự như ví dụ Timer/Counter, ta thấy răng quá trình ngắt ngoài cũng như tạo

PWM không liên quan tới vòng lặp while chính. Ta chỉ cần thao tác ở phần khai báo biến và chương trình ngắt ngoài, còn bộ T/C1 sẽ luôn hoạt động để tạo PWM theo giá trị OCR1A mong muốn.

Phần chương trình ngắt ngoài người đọc hãy thử tự viết, tương tự như phần khai báo biến và chương trình ngắt ngoái của ví dụ Timer/Counter, rồi so sánh với mẫu sau.

Hình 59: Chương trình ngắt ngoài

Sau khi viết xong, kiểm tra và complie thành công, kiểm tra trên mạch mô phỏng, nhấn nút để quan sát tốc độ động cơ thay đổi xung PWM trên Oscilloscope.

Tóm tắt Ø Chế độ PWM cuat T/C. Ø Cách điều khiển PWM. Mở rộng Ø Tìm hiểu và điều khiển góc quay động cơ servo.

Page 46: Giao trinh avr

46 4.5 Chuyển đổi ADC Ví dụ này sẽ hướng dẫn người đọc sử dụng chức năng chuyển đỏi ADC trên vi xử lý

Atmega16. Để bài: Dùng vi xử lý đo điện áp ở đầu ra mạch phân áp (dùng biến trở, từ 0~+5V) và

hiển thị trên led 7 thanh tới mức 0,1V. Người đọc cần xem lại phần giới thiệu chức năng chuyển đổi ADC để hiểu cách hoạt

động của bộ chuyển đổi ADC Để có thể hiển thị kết quả đo trên led 7 thanh thì người đọc cần phải biết cách điều khiển

led 7 thanh. 4.5.1 Phân tích mạch điện Theo như đề bài, ta thấy mạch điện gồm có 3 khối: Vi xử lý, mạch phân áp và hiển thị

bằng led 7 thanh.

a) Mạch phân áp Mạch phân áp là mạch điện hoạt động theo nguyên lý đơn giản sau.

Hình 60: Nguyên lý phân áp

Xét một mạch điện như hình vẽ, 1R và 2R mắc nối tiếp, được cấp điện áp oV . Các điện áp

rơi trên trở 1R và 2R là:

11

1 2o

RV VR R

=+

và 21

1 2o

RV VR R

=+

Nếu thay đổi giá trị của 1R hoặc 2R , điện áp 1V và 2V cũng thay đổi theo. Như vậy từ một

điện áp 8oV V= , ta có thể thu được điện áp 1V hoặc 2V theo yêu cầu (chẳng hạn như

1 5V V= + để đưa vào chân vi xử lý chẳng hạn).

Để có thể thay đổi 1R và 2R trong quá trình sử dụng, người ta dùng biến trở, nguyên tắc hoạt động của biến trở như sau.

Hình 61: Nguyên lý hoạt động biến trở

Biến trở là một linh kiện điện, thường có 3 chân (1), (2), (3), với điện trở hai chân 1-2 bằng 1R và điện trở hai chân 3-2 bằng 2R , trong đó 1 2 oR R R+ = không đổi. Khi điều chỉnh để

lấy điện áp outV ở chân (2), người ta thay đổi điện áp 1R và 2R . Công thức tính điện áp ra là.

2out in

o

RV VR

=

Page 47: Giao trinh avr

47 b) Hiển thị led 7 thanh Điện áp đưa vào vi xử lý thay đổi từ 0 tới +5V, và yêu cầu độ chính xác tới mức điện áp

0,1V, như vậy chúng ta cần 2 led 7 thanh cho bài ví dụ này. Để đơn giản hơn với người đọc, trong bài ví dụ này sẽ không trình bày cách hiển thị led

7 thanh bằng phương pháp quet led, mà để 2 led 7 thanh hoạt động độc lập.

Hình 62: Led 7 thanh Anốt chung

Hình 62 giới thiệu cấu trúc của 1 led 7 thanh anốt chung. Muốn cho đoạn led nào sáng (ví dụ đoạn b và đoạn c để hiển thị số 1), ta phải cấp điện áp dương vào chân COM và để mức trạng thái các đầu b và c là 0, các chân còn lại có mức trạng thái là 1. Như vậy nối toàn bộ 8 chân a, b,…, dp của led 7 thanh vào vi xử lý, ta có thể dùng chức năng In/Out để hiển thị số trên led 7 thanh.

4.5.2 Nguyên lý điều khiển và mạch mô phỏng trên Proteus Từ các bước phân tích trên, ta đưa ra nguyên lý điều khiển như sau.

Hình 63: Nguyên lý điều khiển

Điện áp thay đổi từ 0 tới +5V từ mạch phân áp sẽ được đưa vào vi điều khiển (qua các chân ADC). Khối chuyển đổi ADC sẽ chuyển tín hiệu điện áp thành giá trị số tương ứng để vi điều khiển điều khiển các led 7 thanh hiển thị giá trị điện áp đo được.

Từ nguyên lý điều khiển và phân tích mạch điện, ta tiến hành xây dựng mạch nguyên lý mô phỏng trên Proteus với các linh kiện.

• Vi xử lý Atmega16. • Biến trở 10k. • 2 led 7 thanh loại Anốt chung.

Page 48: Giao trinh avr

48

Hình 64: Mạch môp hỏng trên Proteus

Do điện áp đặt vào kênh ADC có giá trị từ 0 tới +5V nên ta sẽ chọn điện áp tham chiếu AREF bằng điện áp đặt vào chân VACC, trên hình 64, chân AREF được nối với chân AVCC.

Điện áp ra từ mạch phân áp được đưa vào chân PA0 (ADC0). Bộ chuyển đổi ADC sẽ đo điện áp tại kênh ADC0 này và vi điều khiển sẽ hiển thị giá trị đo được trên 2 led 7 thanh. 2 led 7 thanh sẽ được điều khiển bàng 2 cổng là PORT C và PORT D. Led 7 thanh (I) hiển thị chữ số hàng đơn vị, led 7 thanh (II) hiển thị chữ số sau dấu phẩy.

Page 49: Giao trinh avr

49 4.5.3 Lập trình cho vi xử lý

a) Xác định yêu cầu làm việc của vi xử lý Theo như các bước phần tích yêu cầu làm việc của mạch, ta thấy vi xử lý trong ví dụ

Chuyển đổi ADC cần phải sử dụng các khối là: khối chuyển đổi 1 kênh ADC, chức năng In/Out của 2 PORT C và PORT D.

Do điện áp đặt vào kênh ADC có giá trị từ 0 tới +5V nên ta sẽ chọn điện áp tham chiếu AREF bằng điện áp đặt vào chân VACC, tức bằng +5V.

Để giảm nhẹ yêu cầu tính toán, đòng thời cũng để phù hợp với khả năng quan sát của mắt người, ta yêu cầu vi xử lý tiến hành đo điện áp và hiển thị lên led 7 thanh theo chu kỳ 0,25s.

b) Xây dựng thuật toán điều khiển Thuật toán điều khiển của ví dụ Chuyển đổi ADC có thể lấy như trong hình sau.

Hình 65: Thuật toán điều khiển

Điện áp đặt tại chân PA0 sẽ được bộ chuyển đổi ADC đo và trả về giá trị số tương ứng (từ 0 tới 1023 ứng với giá trị điện áp từ 0 đên +5V). Từ giá trị số này sẽ phải qua bước quy đổi, để tính ra điện áp, cũng như chữ số hàng đơn vị và chữ số hàng chục của giá trị điện áp. Hai chữ số này sẽ được hiển thị trên led 7 thanh qua các công PORT C và PORT D. Các bước trên sẽ lặp lại với chu kỳ 0,5s.

Như vậy người đọc có thể thấy rằng các bước trên sẽ được thực hiện trong vòng lặp while chính. Trong bài viết này sẽ giới thiệu khái niệm về chương trình con. Đây là cách thức hay được dùng trong lập trình, nhất là lập trình các dự án phức tạp.

Tính giá trị hàng đơn vị và 1 chữ số sau dấu phẩy Như đã giới thiệu, sau khi đo điện áp, bộ chuyển đổi sẽ trả về giá trị số nguyên (đặt là

ADC_val) từ 0 tới 1023 ứng với khoảng điện áp đo được. Công thức điện áp đặt vào kênh ADC là:

5.1023inV =

ADC_val

Giá trị inV thu được có thể là số lẻ, chẳng hạn 2,28…V. Nếu vậy thì quá trình xác định chữ số sau dấu phẩy (chữ số “2”) sẽ phải dùng các thuật toán phức tạp. Để đơn giản ta tìm cách đưa 1 chữ số sau dấu phẩy sang bên trái dấu phẩy. Để làm điều đó chúng ta nhân giá trị thực của điện áp cần đo inV với 10, được giá trị điện áp tính toán Vtt.

ttADC_valV = 5. .101023

Nếu ban đầu chúng ta đặt kiểu biến cho biến Vtt là giá trị nguyên dương (char, int, …), thì với giá trị ví dụ của Vin=2,28…V, ta sẽ thu được giá trị của Vtt là: 22,8… làm tròn

Page 50: Giao trinh avr

50

thành 23, tức là Vtt=23. Để xác định được chữ số “2”, ta lại tiến hành chia Vtt cho 10 và gán cho một biến nguyên dương, đặt là dvi (đơn vị).

dvi = Vtt/10= 23/10= 2,3 làm tròn thành dvi = 2 Để xác định được chữ số “3”, ta vẫn chia Vtt cho 10, nhưng lấy phần dư và gán cho biến

nguyên sdp (sau dấu phẩy). sdp = Vtt-10*dvi = 23-10*2= 3

Hiển thị ra led 7 thanh Như đã trình bày, việc hiển thị các chữ số lên led 7 thanh được quyết định bởi tổ hợp

trạng thái các chân trong PORT điều khiển. Ở các ví dụ trước, người đọc đã biết cách điều khiển trạng thái của một chân trong PORT bằng lệnh (PORTx.y = z;). Tuy nhiên nếu phải điều khiển cùng lúc cả 8 chân trong một cổng (trong trường hợp này là để điều khiển led 7 thanh), người ta sử dụng lệnh

PORTx = z; Trong đó: x là tên Port cần gán trạng thái (cả 8 chân). z là giá trị gán. Giá trị trạng thái của mỗi chân hoặc bằng 0 hoặc bằng 1, để dùng lệnh trên, người ta xếp

trạng thái cần gán của 8 chân trong Port lần lượt cạnh nhau, làm thành một số nhị phân. Chân số 7 6 5 4 3 2 1 0 Trạng thái 1 1 1 1 1 0 0 1 Số z 1 1 1 1 1 0 0 1

Bảng trạng thái các chân của PORTC để hiển thị số 1 trên led 7 thanh.

Như trên mạch mô phỏng, để PORT C điều khiển led 7 thanh hiển thị số 1, thì hai đoạn led b và c sáng, ứng với hai chân PC1 và PC2 ở trạng thái 0, còn các chân khác ở trạng thái 1. Từ bảng trên suy ra số z bằng 11111001 trong hệ nhị phân. Nếu chuyển sang hệ cơ số 16 thì z bằng F9. Như vậy nếu muốn gán trạng thái PORTC để hiển thị số 1 như trên, thì ta viết:

PORTD = 0b11111001; hoặc

PORTD = 0xF9; Với sơ đồ nối dây như mạch mô phỏng, ta có mã hex (cơ số 16) của các chữ số trên led 7

thanh như sau.

Hình 66: Bảng mã hex của bài ví dụ

Page 51: Giao trinh avr

51 c) Chuẩn bị lập trình bằng phần mềm CodeVision Thiết lập ban đầu với các thông số: vi xử lý Atmega16, thạch anh 4Mhz, tất cả các chân

của PORT C và PORT D là “out”, kích hoạt ADC. Các bước thiết lập chức năng In/Out cho các PORT C và PORT D làm tương tự như các

ví dụ trước, việc kích hoạt chức năng ADC theo như hình sau.

Hình 67: Kích hoạt chức năng ADC

Trong hộp thoại CodeWizardAVR chọn ADC, đánh đấu vào mục “ADC Enabled”. Trong ô “Volt. Ref:” chọn AVCC pin để chọn điện áp tham chiếu cho khối ADC là điện áp +5V tại chân AVCC.

Trong hộp thoại “Clock:”, click chọn tần số làm việc của bộ ADC. Tần số làm việc càng cao, tốc độ chuyển đổi càng nhanh, nhưng sai số càng sao. Trong ví dụ chọn này chọn giá trị tần số làm việc cảu bộ ADC là 250 kHz.

d) Viết chương trình điều khiển Trong ví dụ này có dùng hàm delay, nên trước tiên hãy include file delay.h (nếu chương

trình chưa include file delay.h sẵn). Khai báo các biến sau.

• Vtt kiểu char chứa giá trị điện áp tính toán. • dvi và sdp kiểu char chứa giá trị chữ số hàng đơn vị và chữ số sau dấu phẩy.

Chương trình ADC và tính các chữ số Trong chương trình, sau khi đã kích hoạt bộ ADC ở phần chuẩn bị, việc yêu cầu vi xử lý

tiến hành đọc giá trị ADC được thực hiện bằng dòng lệnh. read_adc(0);

Trong đó read_adc(0) là chương trình được phần mềm tạo sẵn cho chức năng ADC,

trong dấu ngoặc () là số thứ tự kênh ADC cần đo. Trong ví dụ ta đưa điện áp vào kênh ADC0, nên số thứ tự kênh ADC cần đo là 0. Khi qua lệnh này, vi xử lý sẽ đo điện áp tại kênh ADC0 và trả về giá trị số tương ứng.

Chương trình tính giá trị điện áp và các chữ số cần tìm như sau. Vtt=5*10*read_adc(0)/1023; dvi=Vtt/10; sdp=Vtt-dvi*10;

Page 52: Giao trinh avr

52 Toán tử VÀ (&) Theo như yêu cầu hoạt động của mạch, 2 led 7 thanh dùng để hiển thị điện áp đo được

với 1 chữ số sau dấu phẩy, như vậy led 7 thanh (I) phải luôn sáng dấu chấm (dp) để hiển thị dấu phẩy. Có hai cách để làm cho dấu chấm trên led 7 thanh (I) luôn sáng là.

• Viết mã hex lại cho led 7 thanh (I) với trạng thái chân PC7 luôn bằng 0 và điều khiển trạng thái PORT C bằng mã hex này.

• Sử dụng phép toán logic để đưa mã hex ở hình 65 thành mã hex mới với trạng thái chân PC7 luôn bằng 0.

Quá trình viết lại mã hex để hiển thị dấu phẩy (dp) tương tự như viết mã hex đã trình bày ở trên, người đọc hãy tự làm để có thể tự mình viết được các mã hex cho led 7 thanh. Trong bài ví dụ này sẽ trình bày các sử dụng phép toán logic, để người đọc được tiếp cận với cách viết code khác so với các ví dụ từ đầu tài liệu.

Như đã trình bày, để hiện thị chữ số sau dấu phẩy ở led (II), ta dùng lệnh. PORTD = z;

Trong đó z là mã hex trong bảng 65 ứng với số cần hiển thị (giá trị của biến sdp), ví dụ như để hiển thị số 2, ta viết.

PORTD = 0xA4; Để điều khiển led 7 thanh (I) hiển thị chữ số với dấu phẩy (dp) luôn sáng (ví dụ như để

hiển thị chữ số “2.”, ta dùng toán tử logic VÀ “&” như sau. PORTC = 0xA4 & 0x7F;

Trong đó A4 là mã hex của chữ số 2 không dấu chấm (trong bảng 65), còn 7F trong hệ cơ số 16 chính là 01111111 trong hệ nhị phân. Để giải thích rõ hơn, hãy xem bản dưới.

Thứ tự chân 7 6 5 4 3 2 1 0 Z = 0xA4 1 0 1 0 0 1 0 0 0x7F 0 1 1 1 1 1 1 1 0xA4 & 0x7F 0 0 1 0 0 1 0 0 PORTC 0 0 1 0 0 1 0 0

Bảng trạng PORTC sau phép toán VÀ (&). Nếu coi trạng thái 1 ứng với “đúng” (Đ), còn trạng thái 0 ứng với “sai” (S), theo suy luận

logic thông thường ta sẽ có. • Chân 7: Đ và S sẽ thành S. • Chân 6, 4, 3, 1, 0: S và Đ sẽ thành S. • Chân 5, 2: Đ và Đ sẽ thành Đ.

So sánh trạng thái PORTD hiển thị chữ số “2” và trạng thái PORTC hiển thị chữ số “2.” theo bảng sau.

PORTD (“2”) 1 0 1 0 0 1 0 0 PORTC (“2.”) 0 0 1 0 0 1 0 0

So sánh trạng thái PORT D và PORTC khi cùng hiển thị số “2”. Ta thấy sau khi dùng phép toán VÀ (&), từ trạng thái như của PORTD (0xA4) sẽ chuyển

thành trạng thái như của PORTC (0xA4 & 0x7F), chỉ khác nhau ở bit số 7 (điều khiển đoạn led dp). Bit số 7 của PORTC luôn có giá trị 0, vì vậy đoạn led dp của led 7 thanh (I) luôn sáng.

Page 53: Giao trinh avr

53 Chương trình hiển thị led Về cơ bản, sau khi biết về phép so sánh if ở các ví dụ trên, người đọc sẽ nhận ra rằng có

thể dùng nhiều phép so sánh if để điều khiển trạng thái các PORT điều khiển led, ví dụ để điều khiển led (II).

• Nếu sdp = 0, gán trạng thái PORTD = 0xC0; • Nếu sdp = 1, gán trạng thái PORTD = 0xF9; • …

Như vậy để điều khiển một led 7 thanh hiển thị 10 chữ số từ 0 tới 9, cần phải có 10 phép so sánh if, 2 led 7 thanh thì sẽ phải dùng 20 phép so sánh if. Để giảm bớt khối lượng dòng lệnh (nhằm tiết kiệm bộ nhớ và giảm tải cho vi xử lý), người ta gộp nhiều lệnh if thành lệnh swich…case.

Lấy ví dụ điều khiển hiển thị led 7 thanh (II) để hiển thị 10 số từ 0 đến 9, cấu trúc lệnh swich…case như sau.

Hình 68: Lệnh switch...case điều khiển PORTD

Ý nghĩa của cấu trúc swich…case trên như sau. Vi xử lý sẽ so sánh giá trị của biến sdp, nếu sdp = 0 thì thực hiện các lệnh 0, nếu sdp = 1 thì sẽ thực hiện các lệnh 1,…

Các lệnh 0, 1, 2,… sẽ gán trạng thái cho PORTD bằng giá trị mã hex tương ứng. Cấu trúc điều khiển PORTC cũng tương tự, chỉ khác ở chỗ gia trị gán cho PORT được

thay đổi để hiển thị dấu phẩy (dp).

Page 54: Giao trinh avr

54

Hình 69: Cấu trúc switch...case điều khiển PORTC

Chương trình con Hai đoạn chương trình điều khiển hiển thị led trên có thể đặt trực tiếp vào vòng lặp

while, khi đó vòng lặp while chính sẽ có dạng.

Hình 70: Cấu trúc vòng lặp while

Người đọc hãy viết thêm vào trong vòng lặp while ở trên và thử chạy mô phỏng trên Proteus. Tuy nhiên để quá trình lập trình rõ ràng, dễ theo dõi, với các tập lệnh có thể được nhóm lại như các lệnh swich…case ở trên, người ta thường dùng chương trình con.

Page 55: Giao trinh avr

55

Hình 71: Hình dung về chương trình con

Như hình 70, nhóm các lệnh 1,2,…,n thay vì được viết trong vòng lặp while chính, có thể được nhóm lại trong chương trình con x. Khi muốn thức hiện các lệnh 1,2,…,n này, ta chỉ việc đưa tên “chương trình con x” vào vòng lặp while chính.

Như vậy, việc tách một hoặc nhiều nhóm lệnh ra thành chương trình con sẽ giúp người lập trình dễ nẵm bắt được quá trình lập trình, đồng thời giảm số lượng dòng code trong vòng lặp while chính trong trường hợp cần phải dùng nhiều lần các tập lệnh giống nhau.

Trong chương trình CodeVision, các chương trình con được viết bên ngoài trước chương trình chính void main(void), trong trường hợp bài ví dụ này, hai chương trình con điều khiển led (I) và (II) được viết sau khi khai báo biến như trong hình.

Hình 72: Hai chương trình con

Trên hình 71 là hai chương trình con. Chương trình con led1 điều khiển hiển thị trên led 7 thanh (I), chương trình con led2 điều khiển hiển thị trên led (II). Sau đây sẽ trình bày cách viết chương trình con led2.

Một chương trình con được khai báo trong CodeVisionAVR theo cú pháp sau. void “tên chương trình con” (khai báo biến) {

Tập lệnh trong chương trình con; }

Trong đó “tên chương trình con” là tên tùy ý theo người lập trình, với điều khiển không có dấu cách, không có chữ số đứng đầu, không dùng ký hiệu đặc biệt. Trong lập trình không đuwọc đặt hai chương trình con có tên giống nhau. Trong ví dụ trên, ta đặt tên chương trình con điều khiển hiển thị led 7 thanh (II) là led2.

Phần khai báo biến trong dấu ngoặc ()là nơi khai báo các biến chỉ dùng trong chương trình con, gọi là biến cục bộ (chương trình con vẫn có thể sử dụng biến được khai báo đầu

Page 56: Giao trinh avr

56

chương trình, gọi là biến toàn cục, ví dụ như biến dvi và sdp). Trong chương trình con led2 ta thấy không có biến cục bộ (chỉ có câu lệnh switch...case với biến dvi hoặc sdp), trong trường hợp này trong dấu ngoặc sẽ được viết là (void).

Như vậy bố cục của chương trình con led2 sẽ như sau. void led1(void) { switch...case điều khiển led II; }

Sau khi đưa toàn bộ cấu trúc switch...case điều khiển led (II), ta có toàn bộ chương trình con led2 như sau.

Hình 73: Chương trình con led2

Tương tự, chương trình con led1 được viết như sau.

Hình 74: Chương trình con led1

Nếu hiểu sơ bộ về chương trình con, người đọc cũng sẽ thấy rằng hàm read_adc(0) trình bày ở trên cũng là một chương trình con được phần mềm tạo sẵn để sử dụng.

Page 57: Giao trinh avr

57 Vòng lặp while chính Sau khi khai báo biến và viết chương trình con như các bước trên, vòng lặp while chính

điều khiển đo và hiển thị điện áp như sau.

Hình 75: Vòng lặp while chính

Người đọc hãy tự viết các phần đã trình bày ở trên vào phần mềm CodeVisionAVR, kiểm tra và chạy thử trên Proteus.

Hình 76: Chạy mô phỏng trên Proteus

Nếu làm đúng như các bước trên, điện áp đầu ra mạch phân áp sẽ được đo và hiện thị trên led 7 thanh như hình trên. Dùng chuột thay đổi giá trị biến trở để thay đổi hiển thị trên led 7 thanh.

Tóm tắt Ø Mạch phân áp, led 7 thanh Anốt chung. Ø Sử dụng chức năng ADC, tính điện áp cần đo và các chữ số cần thiết. Ø Điều khiển trạng thái của các PORT. Ø Chương trình con. Mở rộng Ø Hiển thị 2 led 7 thanh ở bài ví dụ bằng phương pháp quét led (chung một

PORT điều khiển, mỗi led 7 thanh sáng rồi tắt luân phiên trong 5ms).

Page 58: Giao trinh avr

58 4.6 Truyền nhận dữ liệu với máy tính Ví dụ trong tài liệu này sẽ hướng dẫn người đọc thiết lập và sử dụng chức năng truyền

nhận dữ liệu với máy tính bằng USART ở mức độ đơn giản. Đề bài: Lập trình sử dụng chức năng USART của Atmega16, đo điện áp từ mạch phân áp

(0~+5V) và gửi về máy tính. 4.6.1 Phân tích mạch điện Từ đề bài, ta thấy mạch điện của ví dụ có các khối sau.

• Vi xử lý. • Mạch phân áp. • Thiết bị nhận dữ liệu từ vi xử lý.

Vi xử lý trong ví dụ vẫn dùng Atmega16, mạch phân áp và ngắt ngoài giống như các ví dụ đã trình bày. Thiết bị nhận dữ liệu truyền về từ vi xử lý có thể là máy vi tính (qua cổng COM) hoặc thiết bị VIRTUAL TERMINAL khi mô phỏng trên Proteus.

Mạch điện hoạt động như sau: vi xử lý tiến hành đo điện áp từ mạch phân áp đặt trên kênh ADC và gửi giá trị đo về và hiển thị trên thiết bị Terminal.

4.6.2 Nguyên lý điều khiển và mạch mô phỏng Nguyên lý điều khiển của bài ví dụ này được cho như hình dưới.

Hình 77: Nguyên lý điều khiển bài ví dụ

Điện áp từ đầu ra mạch phân áp được đưa vào kênh ADC của vi xử lý Atmega16. Khi có tín hiệu bàn phím từ trình Terminal, vi xử lý sẽ đo điện áp đặt vào kênh ADC và gửi giá trị đo được tới trình Terminal.

Từ nguyên lý điều khiển, ta xây dựng mạch mô phỏng như sau.

Hình 78: Mạch mô phỏng trên Proteus

Chú ý: chân RXD của vi xử lý phải nối với chân TXD của trình Terminal và ngược lại.

Page 59: Giao trinh avr

59 4.6.3 Lập trình cho vi xử lý

a) Xác định yêu cầu làm việc của vi xử lý Từ đề bài và nguyên lý điều khiển, các chức năng của Atmega16 cần dùng trong ví dụ

này là: • Chức năng ADC. • Chức năng USART.

Chức năng ngắt ngoài sẽ nhận biết tác động nhấn nút của người dùng. Các bước trong chương trình điều khiển như sau.

• Bộ ADC sẽ đo và vi xử lý tính toán giá trị điện áp. • Vi xử lý lại dùng chức năng USART để truyền giá trị đo được về trình

Terminal. Giá trị điện áp đo được sau khi tính toán có thể là giá trị thập phân với nhiều chữ số sau

dấu phẩy, trong khi giá trị cần đo để xử lý (xử lý và vẽ đồ thị trên máy tính…) chỉ cần khoảng 2 chữ số sau dấu phẩy. Vì vậy chỉ cần gửi giá trị điện áp sau khi đã được làm tròn.

Đồng thời trong lập trình vi xử lý, quá trình xử lý các biến có giá trị thập phân (có dấu phẩy) tương đối phức tạp, phải sử dụng kiểu biến tốn bộ nhờ hơn, cũng như nhiều câu lệnh các phép toán và chuỗi…, vì vậy trong ví dụ này sẽ không hiển thị dấu phẩy (ví dụ giá trị 3,25 sẽ được hiển thanh thành 325).

Trong đo đạc thực tế, giá trị “325” ở trên sau khi gửi về máy tính, sẽ được phần mềm xử lý trên máy tính quy đổi về giá trị thực (325 chuyển về 3,25 bằng cách chia cho 100 chẳng hạn). Cách làm này khiến cho việc lập trình trên vi xử lý đơn giản hơn nhiều.

b) Xây dựng thuật toán điều khiển Từ yêu cầu làm việc của vi xử lý, ta xây dựng thuật toán điều khiển như sau.

Hình 79: Thuật toán của bài ví dụ

Bộ ADC tiến hành đo giá trị điện áp, sau đó giá trị sau khi chuyển về dạng ký tự sẽ được bộ USART truyền tới trình Terminal. Quá trình này lặp đi lặp lại liên tục để đo và gửi giá trị điện áp, như vậy toàn bộ chương trình nằm trong vòng lặp while chính. Việc dừng chương trình trong 0,25s với mục đích để mắt người có thể theo dõi kết quả mô phỏng trên proteus. Trong thực tế đo đạc, chu kỳ đo-chuyển-truyền trên chỉ mất khoảng 10ms.

Lý do phải chuyển giá trị số sang dạng ký tự là vì bộ USART chỉ truyền/nhận dữ liệu dạng các ký tự riêng lẻ, ví dụ như ký tự a, b, c,… ký tự 1, 2, 3…. Chẳng hạn muốn truyền giá trị điện áp 12V về máy tính, trước tiên phải chuyển về dạng ký tự ‘12’(gọi là một chuỗi, bao gồm ký tự ‘1’ và ký tự ‘2’), sau đó bộ USART sẽ truyền lần lượt ký tự ‘1’ và ký tự

Page 60: Giao trinh avr

60

‘2’ này về máy tính. Phần mềm xử lý trên máy tính sẽ ghép hai ký tự trên thành một chuỗi, sau đó chuyển lại thành dạng số.

Hình 80: Quá trình gửi dữ liệu từ vi xử lý về máy tính

c) Chuẩn bị lập trình bằng phần mềm CodeVision Trong bài ví dụ này chỉ sử dụng chức năng ADC và USART của Atmega16, vì vậy trong

bước chuẩn bị chúng ta sẽ kích hoạt và thiết lập ban đầu cho hai chức năng này. Với chức năng ADC, việc kích hoạt và thiết lập ban đầu được tiến hành giống như trong

ví dụ Chuyển đổi ADC, người đọc hãy xem lại và tự tiến hành bước này. Để kích hoạt và thiết lập chức năng USART, làm như hình sau.

Hình 81: Kích hoạt USART

Trong hộp thoại CodeWizardAVR, chọn mục USART và làm các bước. 1. Để kích hoạt chức năng truyền dữ liệu, click chọnvào ô “Transmitter”. 2. Để chọn tốc độ Baud Rate, click và chọn tốc độ Baud Rate trong ô “Baud

Rate”. 3. Để chọn kiểu khung truyền (Frame), chọn trong ô “Communication

Parameters”. Như trên hình 80, ta thấy trong bài ví dụ kích chỉ sử dụng chức năng truyền dữ liệu của

bộ USART. Giống như trong phần giới thiệu tính năng USART, tốc độ Baud Rate = 9600 và khung

truyền 8 Data, 1 Stop, không Parity được chọn như trên hình 80.

Page 61: Giao trinh avr

61 d) Viết chương trình điều khiển Khai báo biến và include các file header Trong chương trình này dùng các biến sau.

• Biến V kiểu unsigned int, biến này dùng để chứa giá trị điện áp không có dấu phẩy (đã nhân với 100).

• Biến chuoi dạng chuỗi 10 ký tự. Khai báo biến chuoi theo cú pháp sau.

char chuoi[10]; Include các file header sau (nếu phần mềm CodeVision đã include sẵn thì không cần viết

thêm vào nữa). • delay.h dùng cho chức năng ngừng chương trình. • stdlib.h dùng cho chức năng chuyển giá trị số thành dạng chuỗi ký tự. • stdio.h dùng cho chức năng USART.

Từ phần xây dựng thuật toán điều khiển, ta thấy rằng toàn bộ chương trình nằm trong

vòng lặp while chính có cấu trúc như sau.

Hình 82: Cấu trúc vòng lặp while chính

Đo giá trị điện áp Sau khi xem bài ví dụ Chuyển đổi ADC, người đọc đã có thể tự viết đoạn code đo giá trị

điện áp trên hình 81. Sau khi viết, hãy so sánh với mẫu tham khảo sau. V = 5*read_adc(0)/10.23;

Chuyển giá trị số thành chuỗi ký tự Mục đích của đoạn code này là chuyển giá trị số trong biến V thành chuỗi ký tự và chữa

trong biễn chuoi. Để chuyển một giá trị nguyên (int) của biến V thành chuỗi ký tự của biến chuoi, sử dụng dòng lệnh sau.

itoa(V, chuoi); Truyền chuỗi ký tự qua bộ USART Để truyền một chuỗi nhiều ký tự (biến chuoi) qua bộ USART, ta dùng hàm puts() sau.

puts(chuoi); Khi gặp lệnh puts(chuoi); vi xử lý sẽ gửi lần lượt các ký tự trong biến chuoi qua

bộ USART như đã trình bày. Còn lệnh dừng chương trình 0,25s người đọc hãy tự viết và tự kiểm tra.

Page 62: Giao trinh avr

62 Sau khi viết xong, toàn bộ code trong vòng lặp while chính như sau.

Hình 83: Vòng lặp while chính

Khi viết xong, kiểm tra và complie thành công, tiến hành chạy trên ạch mô phỏng. Trên mạch mô phỏng. Người đọc hãy nhớ lại rằng trong truyền/nhận USART, thiết bị truyền và nhân phải được thiết lập giống nhau. Từ đầu ví dụ chúng ta mới chỉ thiết lập USART trên vi xử lý, để thiết lập USART trên trình Terminal, mở hộp thoại Edit Component của trình Terminal và chọn các thông số giống với USART trên vi xử lý.

Hình 84: Thiết lập các thông số USART của trình Terminal giống với trên vi xử lý

Sau khi thiết lập trong, chạy mạch mô phỏng, lúc này người đọc sẽ thấy trình Terminal hiển thị kết quả gửi về liên tiếp nhau như sau.

Hình 85: Trình Terminal hiển thị kết quả liên tiếp nhau

Nếu để như hình 84 thì chúng ta không thể theo dõi được kết quả, để dễ theo dõi, hãy lập trình để hiển thị xuống dòng sau mỗi lần gửi một chuỗi ký tự như sau.

Page 63: Giao trinh avr

63 Trở lại phần mềm CodeVision, viết thêm một dòng code vào trong vòng lặp while chính

như hình dưới.

Hình 86: Vòng lặp wlhie chính sau khi sửa

Ý nghĩa có dòng code: putchar(13); là gửi một ký tự thứ 13 trong bảng mã ASCII qua bộ USART. Trong bảng mã ASCII, ký tự thứ 13 là “\r”. Khi gặp ký tự này, trình Terminal sẽ xuống dòng.

Sau khi sửa xong, hãy chạy lại mạch mô phỏng trên Proteus, thay đổi giá trị biến trở và quan sát dữ liệu gửi về trên trình Terminal, nếu làm đúng, các giá trị gửi về sẽ được hiển thị như hình sau.

Hình 87: Trình Terminal hiển thị kết quả đo theo các dòng

Tóm tắt Ø Các kích hoạt và thiết lập USART. Ø Cách gửi dữ liệu qua USART. Ø Các khái niệm và chuỗi và hàm sử dụng cho chuỗi. Mở rộng Ø Tìm hiểu cách nhận dữ liệu qua USART.

Page 64: Giao trinh avr

64 Phụ lục Tên và từ khóa các linh kiện hay dùng trong thư viện Proteus

Tên Từ khóa Vi xử lý AVR tiny2313, mega16… Đèn Led led Led 7 thanh 7seg Điện trở resistor Tụ điện capacitor Transistor transistor IRF540 IRF540 Biến trở pot-hg Đi-ốt diode Nút bấm button Công tắc switch Đèn lamp Động cơ SERVO servo Động cơ bước step

Một số phần tử hay dùng khác trên thanh công cụ của Proteus

Page 65: Giao trinh avr

65 Một số cấu trúc lặp, so sánh trong C hay dùng Lệnh If : - Cú pháp : If ( biểu thức) < lệnh> ; - Diễn giải : nếu biểu thức đúng ( # 0 ) à thực hiện <lệnh> ngược lại nếu biểu thức sai ( = 0 ) à thực hiện lệnh đứng sau câu lệnh if. - Hoặc : If ( biểu thức) <lệnhA>; else < lệnh B); Biểu thức : # 0 ( đúng) à < lệnh A> =0 ( sai ) à < lệnh B>. Lệnh For : - Cú pháp : for ( bt1; bt2 ; bt3) lệnh; - Giải thích : + bt1 : là toán tử gán để tạo giá trị ban đầu cho biến điều khiển. + bt2 : biểu thức điều kiện để thực hiện vòng lặp. + bt3 : biểu thức tăng giá trị của biến điều khiển của vòng lặp. - Ví dụ: For (i=0; i<=100;i=i+2); { Các dòng lệnh A; } Khi i = 0, thực hiện các lệnh A, sau đó giá trị i được tăng thêm 2 thành i=2. Khi i = 2, thực hiện các lệnh A, sau đó giá trị i được tăng thêm 2 thành i=4. … Khi i = 100, thực hiện các lệnh A, sau đó giá trị i được tăng thêm 2 thành

i=102. Khi i không còn nhỏ hơn hoặc bằng 100 nữa, bỏ qua không thực hiện các lệnh A. - Cơ chế hoạt động : a/Tính giá trị của biểu thức bt1 . b/Tính giá trị của bt2 c/ + Nếu giá trị của bt2(=0) là sai máy sẽ ra khỏi lệnh for. + Nếu giá trị của bt2(!=0) là đúng thì máy sẽ thực hiện lệnh. Lệnh while : - Cú pháp : while ( biểu thức) { Các lệnh A; } - Nguyên tắc thực hiện : +b1. Tính giá trị của biểu thức. +b2. Nếu giá trị của biểu thức sai ( = 0 ) thì chương trình ra khỏi vòng while +b3. Nếu giá trị của biểu thức đúng (# 0) thì thực hiện các lệnh A và quay lại

bước 1 (b1).

Page 66: Giao trinh avr

66 Lệnh switch - Cú pháp : switch (biểu thức nguyên).

{ case N1 : lệnh 1; break; case N2 : lệnh 2; break; ..... default : lệnh;

} - Biểu thức nguyên là giá trị nguyên : Ni (i=1,2...) là các số nguyên. - Với biểu thức khác với mọi Ni => thực hiện lệnh sau default.