新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > NEC V850 之 定時器TMM0

NEC V850 之 定時器TMM0

作者: 時間:2016-12-03 來源:網(wǎng)絡 收藏
時鐘的事情搞定了,下面就是和時間有關系的定時器了。看了下有3個定時器分別是AA,AB,M。其中M是最簡單的一個,只有一個功能就是計數(shù)。感覺和STM32的systick有異曲同工之妙。就是為操作系統(tǒng)留的心跳時鐘啊。所以先搞他吧。

先說說這個TMM的時鐘特性吧,有一個16位的比較寄存器(TM0CMP0),最大計數(shù)范圍就是0~65535了。另外定時器TMM0不支持自動重裝初值,所以在中斷服務函數(shù)里除了要清標志位還要重新裝入初值。然后這個定時器機器簡單只有一個可屏蔽中斷就是溢出中斷。

本文引用地址:http://butianyuan.cn/article/201612/325100.htm

下面說下他的計數(shù)時間的計算方法。關于系統(tǒng)時鐘和內部設備時鐘在上一篇博文里說過了,系統(tǒng)時鐘如果是32MHz,那么內部設備時鐘也是32MHz,如果想分頻只有在具體的外設分頻器處分頻。

系統(tǒng)時鐘是32MHz;

TMM0分頻系數(shù)為不分頻,則TMM0的時鐘是32MHz;

一個時鐘定時器記一次數(shù),則記一次數(shù)的時間是1 / 32MHz = 0.03125 us;

假如我現(xiàn)在需要定時1ms就是1000us,需要的計數(shù)次數(shù)就是 1000us / 0.03125us = 32000 次。

所以應該給比較寄存器(TM0CMP0)賦值(32000 - 1)次,因為在定時器計時開始時需要消耗3~4個時鐘周期,所以我們不減去1,直接給比較寄存器賦值32000次,做為誤差補償,但是隨著計時時長的增加,誤差會在一定程度上積累。大家要根據(jù)具體需要來進行設置校準。

現(xiàn)在我們知道在系統(tǒng)時鐘為32MHz時,TMM0不分頻的最大計時為65536 * 0.03125 = 2.048 ms,如果我們需要定時的時長比較長,就需要對TMM0的時鐘進行分頻,如果我們需要的定時時長為1s,

系統(tǒng)時鐘是32MHz;

TMM0分頻系數(shù)設置為512分頻,則TMM0的時鐘是 32000000Hz / 512 = 62500Hz;

定時器記一次數(shù)的時間就是 1 / 62500Hz = 0.000016s = 16 us;

我們需要的定時時長是1s,需要的計數(shù)次數(shù)為 1s = 1000000us / 16us = 62500 次。

定時器的定時范圍是有最大值的,同時要注意的是,他也是有最小值的,這就是他的I/O口翻轉速率,經(jīng)過測試,70f3630這款MCU在定時器TMM0下,最小計數(shù)單元為5us,如果再低就意味著I/O口的翻轉速率更高,則會得到比較大的誤差值,下面有一個對照表來列舉一組測試說明,并會附圖。

計算定時時長比較寄存器(TM0CMP0)值實際測量時長備注
1us32 (TMM0 = fxx)2.0625us附圖1
5us160 (TMM0 = fxx)5.063us附圖2
10us320 (TMM0 = fxx)10.031us
30us960 (TMM0 = fxx)30.001us
50us1600 (TMM0 = fxx)50.06us
1ms32000(TMM0 = fxx)1.000ms附圖3
1s62500(TMM0 = fxx/512)999.9ms
上面這個表說明了,在定時時長很小的時候誤差很大,在定時時長很大的時候,雖然相對誤差小,但是也有比較大的絕對誤差,所以這其中的數(shù)值補償要根據(jù)實際情況具體問題具體分析。下面來看下附圖:


說完了理論,來說說代碼部分。操作TMM0需要用到3個寄存器分別是
  • 可屏蔽中斷控制寄存器(定時器M ) TM0EQIC0
  • TMM0 比較寄存器0 TM0CMP0
  • TMM0 控制寄存器0 TM0CTL0

程序操作上有3部分,分別是 開始定時器 , 關閉定時器 , 定時器初始化。

  • 開始定時器(TMM0_Start)
    1. 清TMM0中斷標志位,設置寄存器 TM0EQIC0 的第7位 TM0EQIF0 為 0 ;
    2. 允許響應TMM0中斷,設置寄存器 TM0EQIC0 的第6位 TM0EQMK0 為 0;
    3. 開定時器使能端,設置寄存器TM0CTL0 的第7位 TM0CE 為 1 。
  • 關閉定時器(TMM0_Stop)
    1. 關定時器使能端,設置寄存器TM0CTL0 的第7位 TM0CE 為 0;
    2. 禁止響應TMM0中斷,設置寄存器 TM0EQIC0 的第6位 TM0EQMK0 為 1;
    3. 清TMM0中斷標志位,設置寄存器 TM0EQIC0 的第7位 TM0EQIF0 為 0 。
  • 定時器初始化(TMM0_Init)
    1. 關閉定時器,執(zhí)行TMM0_Stop;
    2. 設置中斷優(yōu)先級,設置寄存器 TM0EQIC0 的后3位 ,確定TMM0的中斷優(yōu)先級;
    3. 設置定時器分頻系數(shù),設置寄存器 TM0CTL0 的后3位,確定TMM0的運行時鐘;
    4. 設置比較寄存器初值,設置寄存器 TM0CMP0的值,確定觸發(fā)溢出中斷的計數(shù)次數(shù)。

有了上面的準備,下面我們在main函數(shù)里先初始化定時器然后再調用開始定時器,一定不要忘記開總中斷;然后在中斷服務程序里寫入用戶代碼加上重新賦初值和清標志位的操作就可以了,這樣定時器就能夠正常工作了,下面是部分代碼,請參閱:

代碼出處:timer.c

/*******************************************************************************
* Function Name : TMM0_Start
* Description : 開始TMMO計數(shù)
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void TMM0_Start( void )
{
TM0EQIF0 = 0; // 設置TM0EQIC0 的第7位中斷標志位位 0 ,清除定時器M0的中斷響應標志
TM0EQMK0 = 0; // 設置TM0EQIC0 的第6位中斷屏蔽位為 0 ,允許產(chǎn)生定時器M0中斷
TM0CE = 1; // 設置TM0CTL0 的最高位TM0CE為 1 ,定時器計數(shù)啟動
}

/*******************************************************************************
* Function Name : TMM0_Stop
* Description : 停止TMM0計數(shù)
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void TMM0_Stop( void )
{
TM0CE = 0; // 設置TM0CTL0 的最高位TM0CE為 0 ,禁止定時器時鐘啟動
TM0EQMK0 = 1; // 設置TM0EQIC0 的第6位中斷屏蔽位為 1 ,禁止產(chǎn)生定時器M0中斷
TM0EQIF0 = 0; // 設置TM0EQIC0 的第7位中斷標志位位 0 ,清除定時器M0的中斷響應標志
}

/*******************************************************************************
* Function Name : TMM0_Init
* Description : TMM0初始化
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void TMM0_Init( void )
{
TMM0_Stop(); // 首先禁止定時器

TM0EQIC0 |= 0x07; // 設置TM0EQIC0 的低3位 中斷優(yōu)先級值 全為1,為最低中斷優(yōu)先級
TM0CTL0 = TMM_INTERNAL_CLOCK0 ; // 設置TMOCTL0 的低3位TMM0預分頻器值 全為0 ,不分頻
TM0CMP0 = 32000; // 設置TM0CMP0 定時器計數(shù)比較寄存器 的值為32000,初值定時為1ms
}

/*******************************************************************************
* Function Name : TMM0_ChangeTimerCondition
* Description : 修改定時器計數(shù)變量值
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void TMM0_ChangeTimerCondition( unsigned short regvalue )
{
TM0CMP0 = regvalue; // 設置TM0CMP0 定時器計數(shù)比較寄存器
}

/*******************************************************************************
* Function Name : MD_INTTM0EQ0
* Description : 定時器TMM0溢出中斷服務函數(shù)
* Input : None
* Output : None
* Return : None
*******************************************************************************/
#pragma vector = INTTM0EQ0_vector
__interrupt void MD_INTTM0EQ0(void)
{
P9L_bit.no4 = ~P9L_bit.no4 ; // 端口P94翻轉,LED閃爍

TM0CMP0 = 32000; // 定時器TMM0不支持自動重裝初值,一定要在執(zhí)行完用戶程序后重裝初值
TM0EQIF0 = 0; // 清除定時器中斷標志位
}

在高亮處更改TMM0分頻系數(shù)。

代碼出處:main.c

void main( void )
{
SystemClkInit(); // 初始化系統(tǒng)時鐘為32MHz
/* PCL setting */
PCLM = CG_PCL_DISABLE; // 關閉可編程時鐘輸出

__DI(); // 關閉總中斷
PMC9L_bit.no4 = 0 ; // 設置P94為輸入輸出口模式
PM9L_bit.no4 = 0 ; // 設置P94端口方向為輸出
TMM0_Init(); // 定時器TMM0初始化
__EI(); // 打開總中斷

TMM0_Start(); // 定時器TMM0開始計數(shù)

while (1);
}

最后把相關寄存器的datasheet截圖上傳下:



關鍵詞: NECV850定時器TMM

評論


技術專區(qū)

關閉