Đầu tiên là mình xin nói về timer0 cho các dòng 16F/18F. Ta nhìn vào sơ đồ khối chung sau:
- Vậy xung vào timer là gì??? Xung vào timer tức là tần số lệnh - Fcy. Cứ mỗi 1 tần số lệnh thì bộ đếm timer0 sẽ tăng lên 1 đơn vị. Giả sử nếu ta khai báo đi đường 1, tức ko qua bộ prescaler thì 1 xung nguồn (tần số máy - Fosc) = xung vào timer (tần số lệnh -Fcy).
- Giả sử nếu ta khai báo xài prescaler là 1:256 chẳn hạn. Thì tức là bộ đếm timer0 sẽ tăng lên 1 sau 256 chu kỳ lệnh. Ý nói rằng phải có 256 xung vào thì sẽ có 1 xung ra.
- Timer0 của dòng 18F có thể hoạt động ở chế độ 8 bit(0-255) hoặc 16 bit(0-65535)
Nguyên lý hoạt động của timer0 như sau: Nếu ở chế độ 16bit. Khi có một xung timer clock thì bộ đếm TMR0L sẽ tăng lên 1 đơn vị. VD hiện tại là 358 sau khi có thêm 1 timer clock thì giá trị của nó là 359. Đến khi nào giá trị của TMR0L = 65535, và nhận tiếp 1 giá trị thì nó sẽ trở về 0, đồng thời sẽ bật cờ ngắt TIR0IF lên. Lúc này chương trình ngắt Timer0 sẽ chạy. Cờ ngắt này phải được xóa đi sau khi chạy xong chương trình ngắt để lần ngắt sau nó được bật lên lại.
- Cách tính thông số cài đặt cho timer:
Timer bắt đầu = 2^số bít timer - 1 - timer*(Fosc/(4*Prescaler))
VD: Ta cần tạo thời gian là 1s với phần cứng sử dụng thạch anh 25Mhz, xài chế độ 16 bit, prescaler = 256 như sau:
Timer bắt đầu = 2^16 - 1 - 1s*(25000000/4*256)) = 41120.93. Ta làm tròn số này thành 41121.
- Ta lấy số này để cài đặt bộ đếm.
+Nếu sử dụng MPLAB C18 thì dùng lệnh WriteTimer0(41121);
+Nếu sử dụng CCSC thì dùng lệnh Set_timer0(41121);
Lưu ý:
1. Ở PIC16F877a/16F887 thì timer0 sẽ ko có chế độ 16bit, chỉ có chế độ 8 bit (0-255) thôi. Nên nếu xài chế độ 16bit thì chuyển sang timer1 với câu lệnh Set_timer1(41121);. Công thức trên tính chung cho cả timer0,1,2,3.
2. Prescaler ta chọn sao cho giá trị timer bắt đầu phải là con số dương. Tức là 2^16 khi trừ vế sau phải ra con số dương, nếu ra số âm là sai, lúc đó ta phải chọn prescaler khác. Prescaler cho timer0 là 8bit nên có các giá trị sau: 2, 4, 8, 16, 32, 64, 128, 256.
- Nhiều bạn tới đây sẽ hỏi. Công thức trên từ đâu ra. Mình sẽ giải thích cụ thể như sau:
+ Như ta đã biết trong PIC: Tcy = 4*Tosc => Fcy = Fosc/4
- Do đã đi qua bộ Prescaler nên Fcy = Fosc/(4*Prescaler). Tức trong 1 tần số lệnh ta mất Fcy = Fosc/(4*Prescaler) Hz. 1 lần đếm lên của timer mất Tcy = 1/(Fosc/(4*Prescaler)) s. Mà để tính khoảng xung nhịp từ timer bắt đầu đến (2^16 - 1) thì ta phải lấy timer mong muốn chia cho Tcy. Nên ta lấy timer/[1/(Fosc/(4*Prescaler))] = timer*(Fosc/(4*Prescaler)).
- Cuối cùng thì ta chỉ việc lấy con số cao nhất là (2^16 - 1) - timer*(Fosc/(4*Prescaler)) là ra con số cài đặt để bắt đầu đếm.
- Kết luận: Trên đây là mình đã hướng dẫn cách tính thông số cài đặt cho timer. Vì trước giờ thấy nhiều bạn cứ máy móc gán prescaler là 8 hay 16 chẳn hạn và số cài đặt timer bắt đầu đếm cũng lấy đại từ code khác mà ko hiểu dc con số ấy được tính từ đâu ra. Như vậy sau này mọi người đều có thể set timer với mọi giá trị bất kỳ được rồi. Muốn bao nhiêu s cũng được. Nhưng do thạch anh ta sử dụng là 25Mhz khi chia cho 4*Prescaler thì chắc chắn sẽ bị lẻ và làm tròn. Nên tại 1 thời gian nhất định thì đúng là 1s thật, nhưng một thời gian sau nó sẽ ko còn đúng nữa. Nhất là làm về đồng hồ số chẳng hạn, ta khắc phục bằng cách sử dùng 1 thạch anh real time 32768Khz - 2^15. Nên chia cho 4*Prescaler đảm bảo ko bao giờ ra số lẻ. Nhưng mà thạch anh real time này chỉ xài cho timer1 tại chân T1OSC thôi. Timer0 ko được đâu nhé.
Ảnh mô phỏng protues.
Link download project.
http://www.mediafire.com/download/57qvq0y0ubyf8vn/led_timer0.rar
- Từ trái sang phải, ta thấy vào bộ mux (bộ chọn kênh) có 2 nguồn xung đó là Fosc/4 và T0CKI pin. Ở đây mình chỉ đề cập đến Timer0 với bộ Fosc/4 còn nguồn xung T0CKI pin rất ít sử dụng. Tiếp theo sau khi qua bộ mux thì nó lại rẽ ra 2 đường. Một đường là đi trực tiếp vào bộ mux thứ 2. Tức là xung nguồn từ Fosc/4 vào bao nhiêu thì vào bộ mux thứ 2 cũng bấy nhiêu. Đường thứ 2 là qua bộ prescaler. Vậy Prescaler là gì???. Nó là bộ chia tần hay còn gọi là tham số cho bộ chia của timer. Tham số này được cài đặt bởi người dùng theo các tùy chọn định trước. Tương ứng với tham số prescaler được chọn, mỗi lần tăng của timer sẽ được quy định như sau:
Xung vào timer = Xung nguồn / Prescaler
- Vậy xung vào timer là gì??? Xung vào timer tức là tần số lệnh - Fcy. Cứ mỗi 1 tần số lệnh thì bộ đếm timer0 sẽ tăng lên 1 đơn vị. Giả sử nếu ta khai báo đi đường 1, tức ko qua bộ prescaler thì 1 xung nguồn (tần số máy - Fosc) = xung vào timer (tần số lệnh -Fcy).
- Giả sử nếu ta khai báo xài prescaler là 1:256 chẳn hạn. Thì tức là bộ đếm timer0 sẽ tăng lên 1 sau 256 chu kỳ lệnh. Ý nói rằng phải có 256 xung vào thì sẽ có 1 xung ra.
- Timer0 của dòng 18F có thể hoạt động ở chế độ 8 bit(0-255) hoặc 16 bit(0-65535)
Nguyên lý hoạt động của timer0 như sau: Nếu ở chế độ 16bit. Khi có một xung timer clock thì bộ đếm TMR0L sẽ tăng lên 1 đơn vị. VD hiện tại là 358 sau khi có thêm 1 timer clock thì giá trị của nó là 359. Đến khi nào giá trị của TMR0L = 65535, và nhận tiếp 1 giá trị thì nó sẽ trở về 0, đồng thời sẽ bật cờ ngắt TIR0IF lên. Lúc này chương trình ngắt Timer0 sẽ chạy. Cờ ngắt này phải được xóa đi sau khi chạy xong chương trình ngắt để lần ngắt sau nó được bật lên lại.
- Cách tính thông số cài đặt cho timer:
Timer bắt đầu = 2^số bít timer - 1 - timer*(Fosc/(4*Prescaler))
VD: Ta cần tạo thời gian là 1s với phần cứng sử dụng thạch anh 25Mhz, xài chế độ 16 bit, prescaler = 256 như sau:
Timer bắt đầu = 2^16 - 1 - 1s*(25000000/4*256)) = 41120.93. Ta làm tròn số này thành 41121.
- Ta lấy số này để cài đặt bộ đếm.
+Nếu sử dụng MPLAB C18 thì dùng lệnh WriteTimer0(41121);
+Nếu sử dụng CCSC thì dùng lệnh Set_timer0(41121);
Lưu ý:
1. Ở PIC16F877a/16F887 thì timer0 sẽ ko có chế độ 16bit, chỉ có chế độ 8 bit (0-255) thôi. Nên nếu xài chế độ 16bit thì chuyển sang timer1 với câu lệnh Set_timer1(41121);. Công thức trên tính chung cho cả timer0,1,2,3.
2. Prescaler ta chọn sao cho giá trị timer bắt đầu phải là con số dương. Tức là 2^16 khi trừ vế sau phải ra con số dương, nếu ra số âm là sai, lúc đó ta phải chọn prescaler khác. Prescaler cho timer0 là 8bit nên có các giá trị sau: 2, 4, 8, 16, 32, 64, 128, 256.
- Nhiều bạn tới đây sẽ hỏi. Công thức trên từ đâu ra. Mình sẽ giải thích cụ thể như sau:
+ Như ta đã biết trong PIC: Tcy = 4*Tosc => Fcy = Fosc/4
- Do đã đi qua bộ Prescaler nên Fcy = Fosc/(4*Prescaler). Tức trong 1 tần số lệnh ta mất Fcy = Fosc/(4*Prescaler) Hz. 1 lần đếm lên của timer mất Tcy = 1/(Fosc/(4*Prescaler)) s. Mà để tính khoảng xung nhịp từ timer bắt đầu đến (2^16 - 1) thì ta phải lấy timer mong muốn chia cho Tcy. Nên ta lấy timer/[1/(Fosc/(4*Prescaler))] = timer*(Fosc/(4*Prescaler)).
- Cuối cùng thì ta chỉ việc lấy con số cao nhất là (2^16 - 1) - timer*(Fosc/(4*Prescaler)) là ra con số cài đặt để bắt đầu đếm.
- Kết luận: Trên đây là mình đã hướng dẫn cách tính thông số cài đặt cho timer. Vì trước giờ thấy nhiều bạn cứ máy móc gán prescaler là 8 hay 16 chẳn hạn và số cài đặt timer bắt đầu đếm cũng lấy đại từ code khác mà ko hiểu dc con số ấy được tính từ đâu ra. Như vậy sau này mọi người đều có thể set timer với mọi giá trị bất kỳ được rồi. Muốn bao nhiêu s cũng được. Nhưng do thạch anh ta sử dụng là 25Mhz khi chia cho 4*Prescaler thì chắc chắn sẽ bị lẻ và làm tròn. Nên tại 1 thời gian nhất định thì đúng là 1s thật, nhưng một thời gian sau nó sẽ ko còn đúng nữa. Nhất là làm về đồng hồ số chẳng hạn, ta khắc phục bằng cách sử dùng 1 thạch anh real time 32768Khz - 2^15. Nên chia cho 4*Prescaler đảm bảo ko bao giờ ra số lẻ. Nhưng mà thạch anh real time này chỉ xài cho timer1 tại chân T1OSC thôi. Timer0 ko được đâu nhé.
Ảnh mô phỏng protues.
Link download project.
http://www.mediafire.com/download/57qvq0y0ubyf8vn/led_timer0.rar
EmoticonEmoticon