实时定时器(RTT)基于一个32位的计数器,用来对可编程16位预分频器的转翻次数进行统计。从而统计 经过 的秒数。关时定时器
可产生周期性的中断和触发报警。
由四个寄存器组成,RTT_MR模式寄存器,RTT_AR报警寄存器,RTT_VR数值寄存器,RTT_SR状态寄存器
以下程序是RTT_AR数值 作为LED闪烁的延迟时间,并使能中断,当计数值达到RTT_AR寄存器的设定值发生RTT中断,
在中断中反转LED。
以下程序是基于寄存器的,没有用库,建立程序时不要选库工程。
程序如下:
#include "sam.h"
#define PRESCALE (1u<<10)
/* LED 使用的GPIO引脚 */
#define LED1_GPIO PIO_PA0
/* LED 闪烁的周期 */
#define LED1_OFF_MS 200
#define LED1_ON_MS 300
/*[子程序]*/
/*读取RTT数值寄存器RTT_VRR*/
uint32_t ReadRTT_CRTV(void)
{
uint32_t v1;
uint32_t v2;
/* 通过连续读取两次RTT_VR的值以增加准确性 */
while(1)
{
v1 = (RTT->RTT_VR) & RTT_VR_CRTV_Msk;
v2 = (RTT->RTT_VR) & RTT_VR_CRTV_Msk;
if (v1 == v2)
{
return v1;
}
}
}
/*计算设定时间,RTT记数器应增加的值*/
inline uint32_t CalcRTTNeedInc(unsigned int ms)
{
/* 计数器加一的频率 */
const uint32_t freq = CHIP_FREQ_SLCK_RC / PRESCALE;
/* 计算延迟后,计数器需要增加的值
* need_inc = ms /1000 / (1/freq) */
return (ms * freq / 1000);
}
/*[中断程序]*/
/* RTT 中断处理函数
* 在这里主要就进行LED1引脚电平的切换了*/
void RTT_Handler(void)
{
/*通过读取状态寄存器清除Alarm */
uint32_t a = RTT->RTT_SR;
/*读取当前的计数值*/
uint32_t begin_rttv = ReadRTT_CRTV();
uint32_t int_gap_ms ;
uint32_t need_inc;
if ((PIOA->PIO_ODSR & LED1_GPIO) == 0)
{
/* 现在引脚电平为低,LED是亮的 */
/* 灭灯 */
PIOA->PIO_SODR = LED1_GPIO;
/* 设置下次中断唤醒间隔的时间 */
int_gap_ms = LED1_OFF_MS;
}
else
{
/* 现在引脚电平为高,LED是灭的 */
/* 亮灯 */
PIOA->PIO_CODR = LED1_GPIO;
/* 设置下次中断唤醒间隔的时间 */
int_gap_ms = LED1_ON_MS;
}
/* 计算并设置下一次中断的条件 */
need_inc = CalcRTTNeedInc(int_gap_ms);
/*设定报警值*/
RTT->RTT_AR = RTT_AR_ALMV(begin_rttv + need_inc - 1);
return;
}
int main(void)
{
/* Initialize the SAM system */
SystemInit();
/* 关闭看门狗 */
WDT->WDT_MR = WDT_MR_WDDIS;
/* 初始化PIO,让PIO控制器直接控制引脚 */
PIOA->PIO_PER = LED1_GPIO;
/* 引脚输出使能 */
PIOA->PIO_OER = LED1_GPIO;
/* 引脚输出写使能 */
PIOA->PIO_OWER = LED1_GPIO;
/* 启用中断 */
NVIC_ClearPendingIRQ(RTT_IRQn);
NVIC_EnableIRQ(RTT_IRQn);
/*设置RTT 时钟分频,重置32位计数器,报警会触发中断,其中RTT_MR_xx表示RTT_MR寄存器xx位域*/
RTT->RTT_MR = RTT_MR_RTPRES(PRESCALE) /*RTT时钟分频*/
| RTT_MR_RTTRST /*重置32位计数器*/
| RTT_MR_ALMIEN; /*使RTT_SR寄存器报警位ALMIEN触发中断*/
/* 计算第一次中断的时间, RTT_AR 寄存器存储报警时间设定值*/
RTT->RTT_AR = RTT_AR_ALMV(ReadRTT_CRTV() + CalcRTTNeedInc(LED1_ON_MS) -1);
while(1);
}
运行结果,LED以亮占多数中间灭一下。
|