单片机
返回首页

第四课 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;

}

}


进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 离子检测器电路分析

  • 非常简单的150W功放电路图

  • 如何使用LED驱动器LM3915制作振动计

  • 分享一个电网倾角计电路

  • 使用NE555和磁簧开关的橱柜照明电路

  • 电谐波图形均衡器示意图

    相关电子头条文章