- Tại sao lại hẹn giờ khi chúng ta có Delay ()?
- Bộ hẹn giờ vi điều khiển PIC:
- Giải thích về lập trình và làm việc:
- Sơ đồ mạch và mô phỏng Proteus:
Đây sẽ là hướng dẫn thứ năm trong Loạt bài Hướng dẫn về PIC của chúng tôi, sẽ giúp bạn tìm hiểu và sử dụng Bộ định thời trong PIC16F877A. Trong các hướng dẫn trước của chúng tôi, chúng tôi đã bắt đầu với Giới thiệu về PIC và MPLABX IDE, sau đó chúng tôi viết chương trình PIC đầu tiên của mình để nhấp nháy đèn LED bằng PIC và sau đó tạo Trình tự nhấp nháy đèn LED bằng cách sử dụng chức năng trì hoãn trong Vi điều khiển PIC. Bây giờ chúng ta hãy sử dụng cùng một trình tự nhấp nháy LED mà chúng ta đã sử dụng trong phần cứng hướng dẫn trước đó và với điều này, chúng ta sẽ Học cách sử dụng Bộ hẹn giờ trong MCU PIC của chúng ta. Chúng tôi vừa thêm một nút nữa trong bảng LED cho hướng dẫn này. Đi qua hướng dẫn để tìm hiểu thêm.
Bộ hẹn giờ là một trong những khóa học quan trọng đối với một lập trình viên nhúng. Mọi ứng dụng mà chúng tôi thiết kế bằng cách nào đó sẽ liên quan đến ứng dụng định thời gian, chẳng hạn như BẬT hoặc TẮT thứ gì đó sau một khoảng thời gian nhất định. Được rồi, nhưng tại sao chúng ta cần bộ định thời khi chúng ta đã có macro trễ (__delay_ms ()) làm điều tương tự !!
Tại sao lại hẹn giờ khi chúng ta có Delay ()?
Macro Độ trễ được gọi là độ trễ "kết xuất". Bởi vì trong quá trình thực hiện chức năng Delay, MCU chỉ tạo ra một khoảng thời gian trễ. Trong quá trình này, MCU không thể nghe các giá trị ADC của nó hoặc đọc bất kỳ thứ gì từ các Thanh ghi của nó. Do đó không nên sử dụng chức năng Trì hoãn ngoại trừ các ứng dụng như đèn LED nhấp nháy trong đó Thời gian trễ không cần chính xác hoặc lâu.
Macro độ trễ cũng có các thông số ngắn sau,
- Giá trị của độ trễ phải là một hằng số đối với macro độ trễ; nó không thể thay đổi trong quá trình thực hiện chương trình. Do đó, nó vẫn được lập trình viên xác định.
- Độ trễ sẽ không chính xác so với việc sử dụng Bộ hẹn giờ.
- Không thể tạo các giá trị độ trễ lớn hơn bằng macro, ví dụ: không thể tạo độ trễ nửa giờ bằng macro độ trễ. Độ trễ tối đa có thể được sử dụng dựa trên bộ tạo dao động Crystal được sử dụng.
Bộ hẹn giờ vi điều khiển PIC:
Về mặt vật lý, bộ định thời là một thanh ghi có giá trị liên tục tăng lên 255, và sau đó nó bắt đầu lại: 0, 1, 2, 3, 4… 255…. 0, 1, 2, 3……Vân vân.
Các PIC16F877A PIC MCU có ba Modules hẹn giờ. Chúng có tên là Timer0, Timer1 và Timer2. Bộ định thời 0 và Bộ định thời 2 là Bộ định thời 8 bit và Bộ định thời 1 là Bộ định thời 16 bit. Trong hướng dẫn này, chúng tôi sẽ sử dụng Timer 0 cho ứng dụng của mình. Khi chúng ta hiểu Timer 0, chúng ta cũng sẽ dễ dàng làm việc trên Timer 1 và Timer 2.
Bộ đếm / đếm thời gian mô-đun Timer0 có các tính năng sau:
- Bộ đếm / bộ đếm thời gian 8 bit
- Có thể đọc và ghi được
- Bộ định mức có thể lập trình phần mềm 8-bit
- Chọn đồng hồ bên trong hoặc bên ngoài
- Gián đoạn khi tràn từ FFh đến 00h
- Chọn cạnh cho đồng hồ bên ngoài
Để bắt đầu sử dụng bộ đếm thời gian, chúng ta nên hiểu một số thuật ngữ ưa thích như bộ định thời 8-bit / 16-bit, bộ định thời, bộ định thời ngắt và tiêu cự. Bây giờ, chúng ta hãy xem mỗi cái thực sự có ý nghĩa gì. Như đã nói trước đó, có cả Bộ định thời 8 bit và 16 bit trong MCU PIC của chúng tôi, sự khác biệt chính giữa chúng là Bộ định thời 16 bit có Độ phân giải tốt hơn nhiều so với Bộ định thời 8 bit.
Prescaler là tên cho một phần của bộ vi điều khiển chia xung nhịp bộ dao động trước khi nó đạt đến mức logic làm tăng trạng thái bộ định thời. Phạm vi của id bộ định hạng trước là từ 1 đến 256 và giá trị của Bộ định hạng sẵn có thể được đặt bằng cách sử dụng Thanh ghi TÙY CHỌN (Giống như thanh ghi mà chúng tôi đã sử dụng cho điện trở kéo lên). Ví dụ, nếu giá trị của bộ đếm trước là 64, thì cứ mỗi xung thứ 64, Bộ định thời sẽ được tăng thêm 1.
Khi bộ đếm thời gian tăng lên và khi nó đạt đến giá trị lớn nhất là 255, nó sẽ kích hoạt một ngắt và tự khởi tạo trở lại 0 lần nữa. Ngắt này được gọi là Ngắt bộ định thời. Sự gián đoạn này thông báo cho MCU rằng thời gian cụ thể này đã kết thúc.
Các Fosc là viết tắt của Tần số của dao động, nó là tần số của Crystal sử dụng. Thời gian thực hiện cho thanh ghi Timer phụ thuộc vào giá trị của Prescaler và giá trị của Fosc.
Giải thích về lập trình và làm việc:
Trong hướng dẫn này, chúng tôi sẽ đặt hai nút làm hai đầu vào và 8 đèn LED làm 8 đầu ra. Nút đầu tiên sẽ được sử dụng để đặt thời gian trễ (500ms cho mỗi lần nhấn) và nút thứ hai sẽ được sử dụng để bắt đầu nhấp nháy trình tự hẹn giờ. Ví dụ: nếu nút đầu tiên được nhấn ba lần (500 * 3 = 1500ms), độ trễ sẽ được đặt trong 1,5 giây và khi nhấn nút hai, mỗi đèn LED sẽ BẬT và TẮT với độ trễ thời gian được xác định trước. Kiểm tra Video trình diễn ở cuối Hướng dẫn này.
Bây giờ, với những điều cơ bản này, chúng ta hãy xem xét chương trình của chúng tôi được đưa ra ở cuối phần Code.
Không sao nếu bạn không nhận được chương trình, nhưng nếu bạn đã làm vậy !! Tạo cho mình một cookie và kết xuất chương trình để tận hưởng kết quả đầu ra của bạn. Đối với những người khác, tôi sẽ chia chương trình thành các phần có ý nghĩa và giải thích cho bạn những gì đang xảy ra trong mỗi khối.
Như mọi khi, vài dòng đầu tiên của mã là Cài đặt cấu hình và tệp tiêu đề, tôi sẽ không giải thích điều này vì tôi đã làm điều đó trong các hướng dẫn trước đây của mình.
Tiếp theo, chúng ta hãy bỏ qua tất cả các dòng và chuyển thẳng vào hàm void main, bên trong chúng ta có cấu hình PORT cho Timer0.
void main () {/ ***** Cấu hình cổng cho bộ hẹn giờ ****** / OPTION_REG = 0b00000101; // Timer0 với freq bên ngoài và 64 là prescalar // Cũng cho phép PULL UPs TMR0 = 100; // Nạp giá trị thời gian cho 0,0019968s; delayValue có thể nằm trong khoảng 0-256 chỉ TMR0IE = 1; // Kích hoạt bit ngắt bộ định thời trong thanh ghi PIE1 GIE = 1; // Bật ngắt toàn cục PEIE = 1; // Bật ngắt ngoại vi / *********** ______ *********** /
Để hiểu điều này, chúng ta phải xem Đăng ký TÙY CHỌN trong biểu dữ liệu PIC của chúng tôi.
Như đã thảo luận trong hướng dẫn trước, bit 7 được sử dụng để kích hoạt Điện trở kéo lên yếu cho PORTB. Nhìn vào hình trên, bit 3 được tạo thành 0 để hướng dẫn MCU rằng bộ định mức sau đang được đặt sẽ được sử dụng cho Bộ hẹn giờ chứ không phải cho WatchDogTimer (WDT). Chế độ hẹn giờ được chọn bằng cách xóa bit 5 T0CS
(OPTION_REG <5>)
Bây giờ, các bit2-0 được sử dụng để đặt giá trị bộ đếm trước cho bộ định thời. Như thể hiện trong bảng trên để đặt giá trị bộ đếm trước là 64, các bit phải được đặt là 101.
Tiếp theo, chúng ta hãy xem xét các thanh ghi được liên kết với Timer0
Bộ định thời sẽ bắt đầu tăng sau khi được đặt và tràn sau khi đạt đến giá trị 256, để cho phép Bộ định thời ngắt trong thời gian này, thanh ghi TMR0IE phải được đặt ở mức cao. Vì bản thân Timer 0 là một thiết bị ngoại vi nên chúng ta phải kích hoạt Ngắt ngoại vi bằng cách tạo PEIE = 1. Cuối cùng chúng ta phải kích hoạt Ngắt toàn cục để MCU sẽ được thông báo về Ngắt trong bất kỳ hoạt động nào, điều này được thực hiện bằng cách đặt GIE = 1.
Độ trễ = ((256-REG_val) * (Prescal * 4)) / Fosc
Công thức trên được sử dụng để tính giá trị của Delay.
Ở đâu
REG_val = 100;
Prescal = 64
Fosc = 20000000
Điều này trên tính toán cho, Độ trễ = 0,0019968 giây
Dòng tiếp theo là đặt Cổng I / O.
/ ***** Cấu hình cổng cho I / O ****** / TRISB0 = 1; // Hướng dẫn MCU rằng chân PORTB 0 được sử dụng làm đầu vào cho nút 1. TRISB1 = 1; // Hướng dẫn MCU rằng chân PORTB 1 được sử dụng làm đầu vào cho nút 1. TRISD = 0x00; // Hướng dẫn MCU rằng tất cả các chân trên PORT D là ngõ ra PORTD = 0x00; // Khởi tạo tất cả các chân thành 0 / *********** ______ *********** /
Điều này giống với hướng dẫn trước của chúng tôi vì chúng tôi đang sử dụng cùng một phần cứng. Ngoại trừ việc chúng tôi đã thêm một nút khác làm đầu vào. Điều này được thực hiện bởi dòng TRISB1 = 1.
Tiếp theo, bên trong vòng lặp while vô hạn, chúng ta có hai khối mã. Một được sử dụng để nhận đầu vào bộ đếm thời gian từ người dùng và cái kia để thực hiện chuỗi độ trễ trên các đèn LED. Tôi đã giải thích chúng bằng cách sử dụng các nhận xét đối với mỗi dòng.
while (1) {count = 0; // Không chạy bộ đếm thời gian khi đang ở trong vòng lặp chính // ******* Nhận số trễ từ người dùng **** ////// if (RB0 == 0 && flag == 0) // Khi đầu vào cho trước {get_scnds + = 1; // get_scnds = get_scnds + http: // Biến tăng cờ = 1; } if (RB0 == 1) // Để ngăn cờ tăng liên tục = 0; / *********** ______ *********** /
Một biến được gọi là get_scnds được tăng lên mỗi khi người dùng nhấn nút 1. Biến cờ (do phần mềm xác định) được sử dụng để giữ quá trình tăng cho đến khi người dùng bỏ ngón tay ra khỏi nút.
// ******* Thực thi trình tự có độ trễ **** ////// while (RB1 == 0) {PORTD = 0b00000001 <
Khối tiếp theo sẽ hoạt động nếu nút hai được nhấn. Vì người dùng đã xác định độ trễ thời gian cần thiết bằng cách sử dụng nút một và nó đã được lưu trong biến get_scnds. Chúng tôi sử dụng một biến có tên là hscnd, biến này được điều khiển bởi ISR (Interrupt service routine).
Quy trình phục vụ ngắt là một Ngắt sẽ được gọi mỗi khi Timer0 bị tràn. Hãy để chúng tôi xem nó đang được ISR điều khiển như thế nào trong khối tiếp theo, giống như chúng ta muốn tăng thời gian trễ lên nửa giây (0,5 giây) trên mỗi lần nhấn nút thì chúng ta cần tăng biến hscnd cho mỗi nửa giây. Vì chúng tôi đã lập trình bộ đếm thời gian của mình vượt quá dòng chảy trong mỗi 0,0019968s (~ 2ms), do đó, để đếm nửa giây, biến đếm phải là 250 vì 250 * 2ms = 0,5 giây. Vì vậy, khi số đếm nhận được 250 (250 * 2ms = 0,5 giây), có nghĩa là nó đã được nửa giây, vì vậy chúng tôi tăng hscnd lên 1 và khởi tạo số lượng bằng không.
void ngắt timer_isr () {if (TMR0IF == 1) // Cờ hẹn giờ đã được kích hoạt do tràn bộ định thời {TMR0 = 100; // Nạp bộ định thời Giá trị TMR0IF = 0; // Xóa cờ ngắt đếm thời gian ++; } if (count == 250) {hscnd + = 1; // hscnd sẽ được tăng lên sau mỗi nửa giây count = 0; }}
Vì vậy, chúng tôi sử dụng giá trị này và so sánh nó với hscnd của chúng tôi và thay đổi đèn LED của chúng tôi dựa trên thời gian do người dùng xác định. Nó cũng rất giống với hướng dẫn trước.
Đó là chúng tôi đã hiểu và làm việc cho chương trình của mình.
Sơ đồ mạch và mô phỏng Proteus:
Như thường lệ, hãy xác minh đầu ra bằng Proteus trước, tôi đã liên kết ở đây các tệp giản đồ của Proteus.
Thêm một nút vào bảng LED trước đó của chúng tôi và phần cứng của chúng tôi đã sẵn sàng hoạt động. Nó sẽ trông giống như sau:
Sau khi kết nối xong, Tải lên mã và xác minh kết quả. Nếu bạn có bất kỳ vấn đề xin vui lòng sử dụng phần bình luận. Cũng xem Video bên dưới để hiểu toàn bộ quá trình.