PIC18x Timer 分享 I
今天課程的重點是 PIC Timer 的介紹,首先我們來觀察一下 Timer 是怎麼一回事呢?
首先開啟 MPLAB 後,點選 "Debugger | Select Tool | MPLAB SIM" 開啟軟體模擬的功能
接著點選 "Debugger | Settings",將處理器的頻率設定為 4MHz (方便後面計算),同時將 Buffer Size 設定為 4M lines (方便捕捉更多的波形)
接著點選 "Debugger | StopWatch",它可說是一個非常好用的工具 (後面的驗證都靠它了,只是不曉得它的名字為甚麼叫 StopWatch?(不要看嗎?))
點選 "View | Watch",把要觀察的 T0CON、TMR0L 加進來,並將初始值分別設定為 0x80、0x00
最後點選 "View | Program Memory" 把程式記憶體叫出來,順便排一下畫面,再按右上角的 Reset 就可以開始觀察了 (如果按 Reset 的話,暫存器的值必須重新設定)
點選右上角的 單步執行 (Step Into),可以發現每執行兩個指令週期, TMR0L 會加 1 (前面有一段不穩定的狀態不會增加,可以先忽略)
同時在 Stopwatch 也可以看到總共執行了 7 個指令週期,花了 7uSecs
按右上角的 Reset 重置,同時將 T0CON、TMR0L 分別輸入 0x81、0x00,再重覆上面的步驟可以發現每執行 4 個指令週期,TMR0L 會加 1
如果把 T0CON 輸入 0x82,則每執行 8 個指令週期,TMR0L 會加 1
為甚麼會這樣呢?
首先請看 PIC18F4520 Data Sheet (Page 126) 關於 TIMER0 在 8-BIT 模式下的方塊圖 (原圖 PSA 選擇有誤,已修正)
同理 T0CON 設定為 0x81 時,就是將除頻設定為 1 : 4;而 0x82 則是 1 : 8
所以如果要 1 : 1 的話,就是將 T1CON 設定為 0x88 (就請大家自己觀察囉!)
觀察到此為止,結下來就是要實作 1ms 的計時了,要達到這個目的,我們可以
要如何驗證程式是否正確呢?
我們可以在上圖 Line 18 的位置設定中斷點,當第 1 次中斷時,點選 Stopwatch 的 Zero 將 Instruction Cycles & Time 歸零,然後再度執行就可以看到兩次中斷花費的時間約為 1000uSecs (多執行幾次可以看到會有些誤差)
從底下的 RC0 波形輸出可以看到 1 個方波的週期約 2000 指令週期
首先開啟 MPLAB 後,點選 "Debugger | Select Tool | MPLAB SIM" 開啟軟體模擬的功能
接著點選 "Debugger | Settings",將處理器的頻率設定為 4MHz (方便後面計算),同時將 Buffer Size 設定為 4M lines (方便捕捉更多的波形)
接著點選 "Debugger | StopWatch",它可說是一個非常好用的工具 (後面的驗證都靠它了,只是不曉得它的名字為甚麼叫 StopWatch?(不要看嗎?))
點選 "View | Watch",把要觀察的 T0CON、TMR0L 加進來,並將初始值分別設定為 0x80、0x00
最後點選 "View | Program Memory" 把程式記憶體叫出來,順便排一下畫面,再按右上角的 Reset 就可以開始觀察了 (如果按 Reset 的話,暫存器的值必須重新設定)
點選右上角的 單步執行 (Step Into),可以發現每執行兩個指令週期, TMR0L 會加 1 (前面有一段不穩定的狀態不會增加,可以先忽略)
同時在 Stopwatch 也可以看到總共執行了 7 個指令週期,花了 7uSecs
按右上角的 Reset 重置,同時將 T0CON、TMR0L 分別輸入 0x81、0x00,再重覆上面的步驟可以發現每執行 4 個指令週期,TMR0L 會加 1
如果把 T0CON 輸入 0x82,則每執行 8 個指令週期,TMR0L 會加 1
為甚麼會這樣呢?
首先請看 PIC18F4520 Data Sheet (Page 126) 關於 TIMER0 在 8-BIT 模式下的方塊圖 (原圖 PSA 選擇有誤,已修正)
- T0CS 可用來選擇 Timer0 第一階段的 Clock 來源
- 0 表示使用內部的 Clock Fosc / 4,若晶片使用的頻率為 4MHz (我們先前設定的),則 Clock 為 4MHz / 4 = 1MHz (故週期為 1 / 1MHz = 1us)
- 1 表示使用外部的 T0CKI pin 當作 Clock 輸入,而 T0SE 則用來控制輸入的相位,0 表示正常輸入,1 表示反向
- PSA 選擇 Timer0 第二階段的 Clock 來源
- 0 表示前段的 Clock 需經過一組除頻電路,除頻比例由 T0PS<2:0> 選擇
- 111 = 1 : 256
- 110 = 1 : 128
- 101 = 1 : 64
- 100 = 1 : 32
- 011 = 1 : 16
- 010 = 1 : 8
- 001 = 1 : 4
- 000 = 1 : 2
- 1 表示前段的 Clock 直接輸出
- 0 表示前段的 Clock 需經過一組除頻電路,除頻比例由 T0PS<2:0> 選擇
- 接下來經過 Sync with internal Clocks,這應該是前面觀察時,一開始不穩態的原因
- 最後存到 TMR0L 就可以開始計時了
同理 T0CON 設定為 0x81 時,就是將除頻設定為 1 : 4;而 0x82 則是 1 : 8
所以如果要 1 : 1 的話,就是將 T1CON 設定為 0x88 (就請大家自己觀察囉!)
觀察到此為止,結下來就是要實作 1ms 的計時了,要達到這個目的,我們可以
- 1us x 1000 次
- 1us x 500 次 (1 : 2 除頻)
- 1us x 250 次 (1 : 4 除頻)
- 1us x 125 次 (1 : 8 除頻)
main.c
#include <myapp.h> void main(void) { unsigned char T0BK; // 記錄 Timer0 計數值 CLR(TRISC, BIT0); // 設定 RC0 為輸出 T0CON = 0x82; // 開啟 Timer0 並設定除頻為 1 : 8 T0BK = TMR0L + 125; // 初始化 T0BK 為目前 TMR0L 往後數 125 次 while (1) { while (TMR0L != T0BK) // 若 Timer0 未數到 T0BK 則繼續等待 //while ((TMR0L-T0BK) < 125) { } T0BK += 125; // 數到 125 次後則繼續往後推遲 125 次 TGL(LATC, BIT0); // 將 RC0 反向輸出 } }
要如何驗證程式是否正確呢?
我們可以在上圖 Line 18 的位置設定中斷點,當第 1 次中斷時,點選 Stopwatch 的 Zero 將 Instruction Cycles & Time 歸零,然後再度執行就可以看到兩次中斷花費的時間約為 1000uSecs (多執行幾次可以看到會有些誤差)
從底下的 RC0 波形輸出可以看到 1 個方波的週期約 2000 指令週期
討論:
- 由於這是用軟體的方式在控制方波輸出,故多多少少會有一些誤差 (C 語言的 1 行 while 變成組合語言包含 6~8 指令)
- while 迴圈利用 TMR0L == T0BK 來捕捉計數結束,是否會有漏接的可能?
- 若利用另一種方式 (TMR0L - T0BK) < 125 來當作計數的條件,則 T0BK += 125; 是否需考慮溢位的可能?(事實證明不用)
留言
you provide us this info let me appreciation as well your helpful
because I feel this lesson very hardly...
BR,
BEN(No 26)
~Joseph
I have most issue need do that on weekly....
thank
Ben
thanks a lot