在 Timer 這篇中已介紹相關基本觀念,本篇將配合實際範例進行操作,使用 N9H31 的 ETIMER 控制 LED 定時閃爍,並透過 UART 輸出訊息。
本範例以官方提供的 ETIMER_Periodic 為基礎進行修改。原始範例僅透過 UART 輸出計數秒數,未對應到開發板上的 LED,因此本篇額外加入 GPIO 控制,使 LED 能夠呈現固定週期的亮滅。同時,透過 serial port tool(例如 Arduino Serial Monitor)觀察 UART 訊息時間戳記,可進一步驗證 Timer 的實際運作頻率。
實驗目的
透過 Timer 定時觸發中斷:
- 控制 LED 週期性亮滅
- 透過 UART 輸出訊號,觀察時間間隔
使用範例
官方範例 ETIMER_Periodic
程式碼
核心概念:Timer 週期性產生中斷 → CPU 進入 ISR → 在 ISR 中控制 LED 並輸出 UART 訊息。
範例是基於 Nuvoton 官方 Sample Code(ETIMER_Periodic)進行修改,僅作為學習與教學用途,以下為修改後的範例程式:
static int state = 0;
/**
* ETIMER0 interrupt handler. Toggle LED state and print message every time timer timeout.
*/
void ETMR0_IRQHandler(void)
{
ETIMER_ClearIntFlag(0);
if (state)
{
/* LED ON */
outpw(REG_GPIOF_DATAOUT, inpw(REG_GPIOF_DATAOUT) & ~BIT10);
outpw(REG_GPIOI_DATAOUT, inpw(REG_GPIOI_DATAOUT) & ~BIT10);
state = 0;
sysprintf("H\n");
}
else
{
/* LED OFF */
outpw(REG_GPIOF_DATAOUT, inpw(REG_GPIOF_DATAOUT) | BIT10);
outpw(REG_GPIOI_DATAOUT, inpw(REG_GPIOI_DATAOUT) | BIT10);
state = 1;
sysprintf("L\n");
}
}
/*-----------------------------------------------------------------------------*/
int main(void)
{
sysDisableCache();
sysFlushCache(I_D_CACHE);
sysEnableCache(CACHE_WRITE_BACK);
sysInitializeUART();
sysprintf("\nETIMER0 periodic + LED toggle test\n");
/* Enable ETIMER0 clock */
outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | (1 << 4));
/* Enable GPIO clock */
outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | (1 << 3));
/* PF10 PI10 set as GPIO function */
outpw(REG_SYS_GPF_MFPH, inpw(REG_SYS_GPF_MFPH) & ~(0xF << 8));
outpw(REG_SYS_GPI_MFPH, inpw(REG_SYS_GPI_MFPH) & ~(0xF << 8));
/* PF10 PI10 set as output */
outpw(REG_GPIOF_DIR, inpw(REG_GPIOF_DIR) | BIT10);
outpw(REG_GPIOI_DIR, inpw(REG_GPIOI_DIR) | BIT10);
/* PF10 PI10 initial low */
outpw(REG_GPIOF_DATAOUT, inpw(REG_GPIOF_DATAOUT) & ~BIT10);
outpw(REG_GPIOI_DATAOUT, inpw(REG_GPIOI_DATAOUT) & ~BIT10);
/* Set timer frequency to 1Hz */
ETIMER_Open(0, ETIMER_TOGGLE_MODE, 1);
/* Enable timer interrupt */
ETIMER_EnableInt(0);
sysInstallISR(HIGH_LEVEL_SENSITIVE | IRQ_LEVEL_1, ETMR0_IRQn, (PVOID)ETMR0_IRQHandler);
sysSetLocalInterrupt(ENABLE_IRQ);
sysEnableInterrupt(ETMR0_IRQn);
/* Start Timer 0 */
ETIMER_Start(0);
while (1)
;
}
補充說明:本範例同時控制 PF10 與 PI10,因為開發板上分別對應兩顆 LED。透過 Timer 中斷同時切換兩個 GPIO,可快速驗證 Timer 與中斷機制是否正常運作。函式說明
ETIMER_Open(timerNo, mode, freq)
- 設定 Timer 的運作模式與目標頻率。
- 設定 Timer mode(One-shot / Periodic / Continuous / Toggle)
- 自動計算 prescaler 與 compare value
- 回傳實際可達到的頻率(可能略有誤差)
注意:此函式不會啟動 Timer,需搭配 ETIMER_Start()
ETIMER_EnableInt(timerNo)
啟用 Timer 中斷功能。
sysInstallISR(level, irq, handler)
註冊中斷服務函式(ISR)
將 interrupt source 對應到 handler
sysSetLocalInterrupt(ENABLE_IRQ)
啟用 CPU 層級中斷(全域開關)
sysEnableInterrupt(irq)
啟用中斷控制器(AIC)中的指定 IRQ
ETIMER_Start(timerNo)
啟動 Timer 計數
ETIMER_ClearIntFlag(timerNo)
清除 Timer 中斷旗標
ETMR0_IRQHandler()
- Timer 中斷服務函式(ISR)
- 要處理的事情
目前流程:清除中斷旗標 -> 執行應用邏輯(toggle LED + UART 輸出)
原則:保持簡短 避免阻塞
Timer 中斷的觸發需要同時啟用:1. Timer 中斷功能(ETIMER_EnableInt)2. 中斷控制器(sysEnableInterrupt)3. CPU 中斷(sysSetLocalInterrupt)
三者缺一不可。
實驗結果
沒有留言:
發佈留言