第四课 MC9S08DZ60之实时计数器RTC
2021-04-07 来源:eefocus
本章介绍一个利用实时中断,设计的调度模块。利用该模块,不仅可以让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 #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< /* 返回的数值用位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; } }