天天看點

第四課 MC9S08DZ60之實時計數器RTC

本章介紹一個利用實時中斷,設計的排程子產品。利用該子產品,不僅可以讓I/O管腳輸出特定占空比的方波,還可以讓程式有序的去排程。

建議讀者先自行閱讀晶片資料第15章的内容,内容不多。晶片資料可以到我的百度盤下載下傳,該晶片的中英文的資料分别https://pan.baidu.com/s/1dgVbkE https://pan.baidu.com/s/1o9qFU5c,如果對英文不是很熟悉,那就閱讀中文的。

1.摘取文字來了解這款晶片的RTC

    第一句:15.1.2 Features 中“ 8-bit up-counter”upcounter就是向上計數,比如一個變量從0開始然後1、2、3...一直往上       加。

    第二句:15.1.2 Features中“...software selectable clock sources...”"— 1-kHz internal Low Power Oscillator (LPO) ;

    — External clock (ERCLK);— 32-kHz internal clock (IRCLK)"可為RTC提供的驅動時鐘源,一共有三個分别為                     LPO;MCGERCLK;MCGIRCLK,可以參看本系列《第二課 MC9S08DZ60之多功能時鐘發生器S08MCGV1》中對系統時鐘及系    統時鐘圖的說明。

    第三句:15.3.1 RTC Status and Control Register (RTCSC) 

       A.要知道RTCSC寄存器中包含中斷置起标志RTIF,且Writing a logic 1 TO RTIF clears the bit and the real-time             interrupt request .寫1到RTIF位及清除中斷标志。

         B. 要知道RTCSC寄存器中包含時鐘源的選擇位 RTCLKS,且隻有3個不同的源。

         C.要知道RTCSC寄存器中包含計數比對成功後,中斷使能與否的設定位 RTIE.

         D.要知道RTCSC寄存器中包含為8位RTCCNT使用的預分頻 RTCPS。

    第四句:15.3.2 RTC Counter Register (RTCCNT)中“writing to RTCMOD, or writing different values to RTCLKS and     RTCPS clear the count to 0x00.  每次寫比對數值RTCMOD或者重新選擇時鐘源,先前的計數RTCCNT都會清零,重新開        始新的計數。另外本單片機隻有8位計數器,計數最大次數為0xFF,那麼最長可以設計的比對時常為255*T每一次計數所要花的時間。T每一次計數所要花的時間由選擇的時鐘源和預分頻值決定。

    第五句:15.3.3 RTC Modulo Register (RTCMOD)中“ These eight read/write bits contain the modulo value used to                   reset the count to 0x00 upon a compare match and set the RTIF status bit”包含模值用于比對向上計數器寄                     存器RTCCNT中的值,一旦RTCMOD和RTCCNT中的值相等,就會清零RTCCNT和置起中斷标志RTIF。

2.分析‘’15.4.1 RTC Operation Example‘’中的例子實作過程

    下圖Figure 15-6為RTC計數溢出計數執行個體,圖中第一個時序LPO 1-kHz代表的是RTCLKS=0,RTC的時鐘源為LPO1kHz,周期為1ms。第二個時序預分頻RTCPS為0xA,也即是十進制的10.查表Table 15-3,找到預分頻系數為除4(2^2次方)。那麼經過預分頻後的頻率為1000/4= 250Hz,周期為4ms。由下圖Figure 15-2得出,每4ms計數器RTCCNT up counter一次,當RTCCNT中的計數值等于RTCMOD中的值。那麼中斷标志RTIF置起,RTCCNT也清零,并重新開始計數。

第四課 MC9S08DZ60之實時計數器RTC
第四課 MC9S08DZ60之實時計數器RTC
第四課 MC9S08DZ60之實時計數器RTC

第三 代碼部分

     注:時鐘的配置設定可以參看《第二課 MC9S08DZ60之多功能時鐘發生器S08MCGV1》

    注:如果有對codewarrior編譯器中斷函數的寫法及使用不明确的,可以到https://pan.baidu.com/s/1dvjxq_B_cJArXCUY92tHAw下載下傳資料,看文中“3.4 編寫中斷服務函數”。

    利用8MHz外部時鐘MCGERCLK作為RTC時鐘源,并設定預分頻為2000,最終用4KHz,每個計數時間為T=1/4k=0.25ms,這樣的話,把比對值RTCMOD寫0,也即是每個T時間就置起中斷RTIF,讓後進入interrupt server function函數中。

頭檔案.H

#ifndef _DATA_TYPE_H_H
#define _DATA_TYPE_H_H

typedef char            INT8;
typedef unsigned char   UINT8;
typedef unsigned short  USHORT16;
typedef unsigned int    UNIT16;
typedef unsigned long   ULONG32;
typedef short           SHORT16;
typedef long            LONG32;
typedef unsigned char   BOOL;
#endif

           
#ifndef _RTC_H_H
#define _RTC_H_H

#define TASK_ALGOR_END    50 //周期T=50*0.25=12.5ms
#define TASK_CALIB_END    20 //周期T=20*0.25=5ms
#define TASK_CAN_END     400 //周期T=400*0.25=100ms
#define TASK_EXT_CAN_END 4000//周期T=4000*0.25=1000ms

enum LECU_TASK_LIST_CODE 
{
	LECU_TASK_CALIBRATION = 0x0001,
	LECU_TASK_ALGORITHM = 0x0002,
	LECU_TASK_CAN_MAIL = 0x0004,
	LECU_TASK_CAN_MAIL_EXT = 0x0008,	
};

//  =============

/*
向RTCSC中RTIF位寫1,用于清楚中斷置起的标志位
*/
void ClearRTIF(void);
/*
clk = 0x00 1kHz低功率振蕩器LPO
clk = 0x01 外部時鐘ERCLK
clk = 0x1x 内部時鐘IRCLK
*/
void SelectCLKS(UINT8 clk);
/*
SW = 1 real time interrupt request enable
SW = 0 real time interrupt request disable
*/
void SetInterrupt(UINT8 SW);
/*
選擇時鐘源和預分頻除數
clk = 0x00 1kHz低功率振蕩器LPO
clk = 0x01 外部時鐘ERCLK
----------------------------------------------------------------------------------------------------------------
|clk       |                       preScaler                                                                    |
|-----------                                                                                                    |
|          |0  |  1  |2    | 3   | 4   | 5   | 6   | 7   |  8   |9     |10    |11  |12    |  13  |14    |15     |
|---------------------------------------------------------------------------------------------------------------|          
|0         |OFF| 2^3 | 2^5 | 2^6 | 2^7 | 2^8 | 2^9 | 2^10|  1   |2     |2^2   |10  | 2^4  |  10^2|5x10^2| 10^3  |
|---------------------------------------------------------------------------------------------------------------|
|1         |OFF| 2^10| 2^11| 2^12| 2^13| 2^14| 2^15| 2^16|  10^3|2x10^3|5x10^3|10^4|2x10^4|5x10^4|10^5  | 2x10^5|
----------------------------------------------------------------------------------------------------------------
*/
void SelectClkAndPrescaler(UINT8 clk ,UINT8 preScaler);
/*
設定與計數器比對溢出值modValue
*/
void SetRTCMOD(UINT8 modValue);
/*
初始化各task的初始值
TaskAlgorEnd 初始設計周期為每0.25*50 = 12.5ms,複位或重新開機到第一次執行TaskAlgorEnd任務的時間
             T=(50-tskAlgorEnd)*0.25計。
TaskCalibEnd 初始設計周期為5ms,其他類同 TaskAlgorEnd
TaskCANEnd   初始設計周期為100ms 其他類同TaskAlgorEnd
TaskCANExtEnd初始化設計周期1000ms其他類同TaskAlgorEnd
各個task的周期可以通過宏:
                         TASK_ALGOR_END
                         TASK_CALIB_END
                         TASK_CAN_END
                         TASK_EXT_CAN_END
              修改後周期計算公式eg.T=TASK_ALGOR_END*0.25ms 
*/
void InitialTaskValue(UINT8 tskAlgorEnd,UINT8 tskCalibEnd,USHORT16 tskCANEnd,USHORT16 tskCANExtEnd);
void InitialTaskList(UINT8 tskList);
/*
每個任務執行完成後要清除,
taskBitPosition:
bit0--TaskCalibEnd
bit1--TaskAlgorEnd
bit2--TaskCANEnd
bit3--TaskCANExt
bitx--其它未開放
*/
void ClearTaskList(UINT8 taskBitPosition);
/*
傳回的數值用位1,0分别表示任務執行與否
bit0--TaskCalibEnd
bit1--TaskAlgorEnd
bit2--TaskCANEnd
bit3--TaskCANExt
bitx--其它未開放
*/
UINT8 GetTaskList(void);

//example  for RTC initialization
void SetupRTC(void);
//for 0.25ms 
void interrupt VectorNumber_Vrtc RTC_ISR(void);

#endif


           
源檔案.C
           
#include <hidef.h>
#include "derivative.h"
#include "DataType.h"
#include "RTC.h"

//static UINT8 flag=0;//---test--for RTC------ 
//------VARIABLES PLACE HERE-----------------
static UINT8 countTaskAlgorEnd = 0;
static UINT8 countTaskCalibEnd = 0;
static USHORT16 countTaskCANEnd = 0;
static USHORT16 countTaskCANExtEnd = 0;
static USHORT16 sTaskList = 0;
//------LOCAL FUNC PLACE HERE-----------------

//--------------------------------------------


/*
向RTCSC中RTIF位寫1,用于清楚中斷置起的标志位
*/
void ClearRTIF(void) {
    RTCSC |= 0x80;/* Write 1 to clear RTIF bit */
}
/*
clk = 0x00 1kHz低功率振蕩器LPO
clk = 0x01 外部時鐘ERCLK
clk = 0x1x 内部時鐘IRCLK
*/
void SelectCLKS(UINT8 clk) {
    UINT8 temp = RTCSC;
    RTCSC = ( temp & 0x9F ) | (( clk << 5 ) & 0x60);
}
/*
SW = 1 real time interrupt request enable
SW = 0 real time interrupt request disable
*/
void SetInterrupt(UINT8 SW) {
    if(1 == SW)
        RTCSC |= 1<<4;
    else
        RTCSC &= ~(1<<4);
}
/*
選擇時鐘源和預分頻除數
clk = 0x00 1kHz低功率振蕩器LPO
clk = 0x01 外部時鐘ERCLK
----------------------------------------------------------------------------------------------------------------
|clk       |                       preScaler                                                                    |
|-----------                                                                                                    |
|          |0  |  1  |2    | 3   | 4   | 5   | 6   | 7   |  8   |9     |10    |11  |12    |  13  |14    |15     |
|---------------------------------------------------------------------------------------------------------------|          
|0         |OFF| 2^3 | 2^5 | 2^6 | 2^7 | 2^8 | 2^9 | 2^10|  1   |2     |2^2   |10  | 2^4  |  10^2|5x10^2| 10^3  |
|---------------------------------------------------------------------------------------------------------------|
|1         |OFF| 2^10| 2^11| 2^12| 2^13| 2^14| 2^15| 2^16|  10^3|2x10^3|5x10^3|10^4|2x10^4|5x10^4|10^5  | 2x10^5|
----------------------------------------------------------------------------------------------------------------
*/
void SelectClkAndPrescaler(UINT8 clk ,UINT8 preScaler) {
    UINT8 temp = RTCSC;
    RTCSC = ( temp & 0x90 ) | ((( clk << 5 ) | preScaler)& 0x6F);
}
/*
設定與計數器比對溢出值modValue
*/
void SetRTCMOD(UINT8 modValue) {
    RTCMOD = modValue;
}
/*
初始化各task的初始值
TaskAlgorEnd 初始設計周期為每0.25*50 = 12.5ms,複位或重新開機到第一次執行TaskAlgorEnd任務的時間
             T=(50-tskAlgorEnd)*0.25計。
TaskCalibEnd 初始設計周期為5ms,其他類同 TaskAlgorEnd
TaskCANEnd   初始設計周期為100ms 其他類同TaskAlgorEnd
TaskCANExtEnd初始化設計周期1000ms其他類同TaskAlgorEnd
各個task的周期可以通過宏:
                         TASK_ALGOR_END
                         TASK_CALIB_END
                         TASK_CAN_END
                         TASK_EXT_CAN_END
              修改後周期計算公式eg.T=TASK_ALGOR_END*0.25ms 
*/
void InitialTaskValue(UINT8 tskAlgorEnd,UINT8 tskCalibEnd,USHORT16 tskCANEnd,USHORT16 tskCANExtEnd) {
    countTaskAlgorEnd = tskAlgorEnd;
    countTaskCalibEnd = tskCalibEnd;
    countTaskCANEnd   = tskCANEnd;
    countTaskCANExtEnd= tskCANExtEnd;
}
void InitialTaskList(UINT8 tskList) {
   sTaskList  = tskList;
}
/*
每個任務執行完成後要清除,
taskBitPosition:
bit0--TaskCalibEnd
bit1--TaskAlgorEnd
bit2--TaskCANEnd
bit3--TaskCANExt
bitx--其它未開放
*/
void ClearTaskList(UINT8 taskBitPosition) {
    sTaskList &= ~(1<<taskBitPosition);
}
/*
傳回的數值用位1,0分别表示任務執行與否
bit0--TaskCalibEnd
bit1--TaskAlgorEnd
bit2--TaskCANEnd
bit3--TaskCANExt
bitx--其它未開放
*/
UINT8 GetTaskList(void) {
    return sTaskList;
}


void SetupRTC(void) {
  
    SelectClkAndPrescaler(0x01,9);
    SetInterrupt(1);
    ClearRTIF();
}

#pragma TRAP_PROC
void interrupt VectorNumber_Vrtc RTC_ISR(void) 
{
	//----------------------- 
	countTaskAlgorEnd ++;
	countTaskCalibEnd ++;
	countTaskCANEnd ++;
	countTaskCANExtEnd ++;
	RTCSC |= 0x80;/* Write 1 to clear RTIF bit */

	if ( countTaskAlgorEnd >= TASK_ALGOR_END ) 
	{
		countTaskAlgorEnd = 0;
		sTaskList |= LECU_TASK_ALGORITHM;
	}
	if ( countTaskCalibEnd >= TASK_CALIB_END ) 
	{
		countTaskCalibEnd = 0;
		sTaskList |= LECU_TASK_CALIBRATION;
	}
	if ( countTaskCANEnd >= TASK_CAN_END ) 
	{
		countTaskCANEnd = 0;
		sTaskList |= LECU_TASK_CAN_MAIL;
	}
	if ( countTaskCANExtEnd >= TASK_EXT_CAN_END ) 
	{
		countTaskCANExtEnd = 0;
		sTaskList |= LECU_TASK_CAN_MAIL_EXT;
	}
}
           

繼續閱讀