天天看點

【ARM裸闆】定時器中斷示例與分析

1.定時器結構分析

  • 1.每來一個CLK,TCNTn減1
  • 2.當

    TCNTn == TCMPn

    時,(可以把對應的PWM引腳翻轉)
    • TCNTn

      TCMPn

      的值來自寄存器

      TCNPBn

      TCMTBn

  • 3.TCNTn繼續減1,當

    TCNTn == 0

    時,可以産生中斷(PWM引腳再次翻轉)
  • 4.

    TCNTn == 0

    時,可自動加載初值
    【ARM裸闆】定時器中斷示例與分析

2.初始化

  • 1.設定時鐘源
  • 2.設定初值
  • 3.加載初值,啟動Timer
  • 4.設定為自動加載
  • 5.中斷相關
【ARM裸闆】定時器中斷示例與分析
  • 需要設定:1.Prescaler,2.MUX(Divider),3.TCMPB0(不是PWM測試,是以該不需要設定),4.TCNTB0,5.TCON0
【ARM裸闆】定時器中斷示例與分析

2.1 設定時鐘源

【ARM裸闆】定時器中斷示例與分析
  • 由上公式:
  • 設定Prescaler
  • 設定MUX
/* 1.設定timer0的時鐘
	 * Timer CLK = PCLK / {prescaler value+1} / {divider value}
	 *               50000000/(99+1)/(16) = 31250
	 */
	TCFG0 = 99;    //Prescaler = 99,用于timer0,timer1
	TCFG1 &= ~0xFF;
	TCFG1 |= 3;    //MUX0=1/16(即是 divider value)
           

2.2 設定初值

//2.設定timer0的初值
	TCNTB0 = 15625;  //0.5s中斷一次(15625/31250=0.5s)
           
【ARM裸闆】定時器中斷示例與分析

2.3 手動加載初值

  • 手動加載初值至TCNT0與TCMT0,啟動timer0
  • 置1
【ARM裸闆】定時器中斷示例與分析

2.4 清除手動加載

  • 清零

2.5 設定自動重裝載并啟動

【ARM裸闆】定時器中斷示例與分析

3. 構造函數指針

  • 把每一個中斷的處理函數放置在指針數組中,當發生中斷時,通過判斷中斷号,調用對應的函數即可

3.1 定義

  • 定義函數指針,指針的變量名為

    irq_func

typedef void (*irq_func)(int);

    irq_func irq_array[32];//定義存放函數指針數組(即:數組中存放的是函數指針)
           
  • typedef void(*Func)(void)

    的用途,先來看下其基本用法
typedef void (*func)(void);  
	void myfunc(void);  
	func pfun = myfunc;/*指派*/  
	pfun();/*調用*/  
           

3.2 由來

  • typedef void(*Func)(void);

    的由來
  • 其實這樣的形式聲明函數指針是有"問題"的。如果仿照變量類型聲明,聲明函數指針似乎應該這樣:

但是c标準的建立者沒有這樣做,不知道為什麼,而選擇了這樣的聲明:

C編譯器非常清楚,這就是在聲明一個void(*)() 類型的函數指針variable。

3.4 注冊函數

/* 注冊中斷
 * param:1.中斷号,2.中斷服務函數
*/
void register_irq(int irq,irq_func fp)
{
	irq_array[irq] = fp;//将fp指向的函數位址 存放在arr中

	INTMSK &= (1<<irq);
}
           
  • eg:

3.5 調用函數

/* 中斷處理函數
 *
*/
void handle_irq_c(void)
{
	/* 1.分辨中斷源 */
	int bit = INTOFFSET;//判斷誰在請求中斷

	/* 2.調用對應的處理函數 */
	irq_array[bit](bit); //irq_array存放的是函數指針,加一個()即表示調用該函數

	/* 3.清中斷 :從源頭開始清 */
	SRCPND = (1<<bit);
	INTPND = (1<<bit);
}