Phân tích, xây dựng nguyên lý điều khiển và mạch mô phỏng

Một phần của tài liệu Hướng dẫn lập trình AVR rất hay (Trang 35 - 42)

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

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.

Đứ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.

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: 1 6 6 0, 25.10 ( ) 4.10

o

ts

  

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

6 ax 6 2 8.10 1 65535 0, 25.10 o m n    TCNT

Giá trị nolớn hơn giá trị TCNT1maxkhoả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à: 6

6 1 256 64.10 ( ) 4.10 ts   

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

n   

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

2s

1 65535 31250 34285

TCNT   

Nếu viết trong hệ cơ số 16: TCNT12s 85ED

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

n   

Vì n2 phải là số nguyên dương, nên ta chọn n2 7813 Sai số ở đây là   0,5.64.106 32.10 ( )6 s

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

0,5s

1 65535 7813 57772

TCNT   

Nếu viết trong hệ cơ số 16: TCNT10,5s E1AC

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.

Để 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 z

256  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.

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.

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à.

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

Một phần của tài liệu Hướng dẫn lập trình AVR rất hay (Trang 35 - 42)

Tải bản đầy đủ (PDF)

(66 trang)