本章介紹一個利用實時中斷,設計的排程子產品。利用該子產品,不僅可以讓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之多功能時鐘發生器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;
}
}