目录
1.PWM定时器
2.看门狗定时器
3.RTC定时器
一、PWM定时器
(1)S5PV210有5个PWM定时器。其中0、1、2、3各自对应一个外部GPIO,可以通过这些对应的GPIO产生PWM波形信号并输出;timer4没有对应的外部GPIO(因此不是为了生成PWM波形而是为了产生内部定时器中断而生的)
(2)S5PV210的5个PWM定时器的时钟源为PCLK_PSYS,timer0和timer1共同使用一个预分频器、timer2、3、4共同使用一个预分频器;每个timer有一个专用的独立的分频器;预分频器和分频器构成了2级分频系统,将PCLK_PSYS两级分频后生成的时钟供给timer模块作为时钟周期。
PWM定时器中有关寄存器
XpwmTOUT2/GPD0_2
TCNT:是用来减的
TCNTB:是用来写的(决定周期)
TCNTO:是用来读的
TCMPB:决定PWM波形的占空比
PWM波形的周期T = TCNTB*Timer Input Clock Frequency
Timer Control Register (CON, R/W, Address = 0xE250_0008)
void timer2_pwm_init(void)
{
// 设置GPD0_2引脚,将其配置为XpwmTOUT_2
rGPD0CON &= ~(0xf<<8);
rGPD0CON |= (2<<8);
// 设置PWM定时器的一干寄存器,使其工作
rTCFG0 &= ~(0xff<<8);
rTCFG0 |= (65<<8); // prescaler1 = 65, 预分频后频率为1MHz
rTCFG1 &= ~(0x0f<<8);
rTCFG1 |= (1<<8); // MUX2设置为1/2,分频后时钟周期为500KHz
// 时钟设置好,我们的时钟频率是500KHz,对应的时钟周期是2us。也就是说每隔2us
// 计一次数。如果要定的时间是x,则TCNTB中应该写入x/2us
rCON |= (1<<15); // 使能auto-reload,反复定时才能发出PWM波形
//rTCNTB2 = 250; // 0.5ms/2us = 500us/2us = 250
//rTCMPB2 = 125; // duty = 50%
rTCNTB2 = 50;
rTCMPB2 = 25;
// 第一次需要手工将TCNTB中的值刷新到TCNT中去,以后就可以auto-reload了
rCON |= (1<<13); // 打开自动刷新功能
rCON &= ~(1<<13); // 关闭自动刷新功能
rCON |= (1<<12); // 开timer2定时器。要先把其他都设置好才能开定时器
}
二、看门狗定时器
看门狗定时器和PWM几乎是同样的套路:
1.预分频
2.分频器
3.中断使能、禁止
4.WTDAT、WTCNT
当计数时间到达时:
1.选择中断(中断类型号、中断服务子程序、绑定)
2.复位
#define WTCON (0xE2700000)
#define WTDAT (0xE2700004)
#define WTCNT (0xE2700008)
#define WTCLRINT (0xE270000C)
#define rWTCON (*(volatile unsigned int *)WTCON)
#define rWTDAT (*(volatile unsigned int *)WTDAT)
#define rWTCNT (*(volatile unsigned int *)WTCNT)
#define rWTCLRINT (*(volatile unsigned int *)WTCLRINT)
// 初始化WDT使之可以产生中断
void wdt_init_reset(void)
{
// 第一步,设置好预分频器和分频器,得到时钟周期是128us
rWTCON &= ~(0xff<<8);
rWTCON |= (65<<8); // 1MHz
rWTCON &= ~(3<<3);
rWTCON |= (3<<3); // 1/128 MHz, T = 128us
// 第二步,设置中断和复位信号的使能或禁止
rWTCON &= ~(1<<2); // disable wdt interrupt
rWTCON |= (1<<0); // enable wdt reset
// 第三步,设置定时时间
// WDT定时计数个数,最终定时时间为这里的值×时钟周期
rWTDAT = 10000; // 定时1.28s
rWTCNT = 10000; // 定时1.28s
// 其实WTDAT中的值不会自动刷到WTCNT中去,如果不显式设置WTCON中的值,它的值就是
// 默认值,然后以这个默认值开始计数,所以这个时间比较久。如果我们自己显式的
// 设置了WTCNT和WTDAT一样的值,则第一次的定时值就和后面的一样了。
//rWTDAT = 1000; // 定时0.128s
//rWTCNT = 1000; // 定时0.128s
// 第四步,先把所有寄存器都设置好之后,再去开看门狗
rWTCON |= (1<<5); // enable wdt
}
三、RTC定时器
(1)real time clock,真实时间,就是所谓的xx年x月x日x时x分x秒星期x
(2)RTC是SoC中一个内部外设,RTC有自己独立的晶振提供RTC时钟源(32.768KHz),内部有一些寄存器用来记录时间(年月日时分秒星期)。一般情况下为了在系统关机时时间仍然在走,还会给RTC提供一个电池供电。
(1)INTP 中断挂起寄存器
(2)RTCCON RTC控制寄存器
(3)RTCALM ALMxxx 闹钟功能有关的寄存器
(4)BCDxxx 时间寄存器
设置闹钟
void rtc_set_alarm(void)
{
rALMSEC = num_2_bcd(23);//可以扩展
rRTCALM |= 1<<0;
rRTCALM |= 1<<6;
}
struct rtc_time
{
unsigned int year;
unsigned int month;
unsigned int date; // 几号
unsigned int hour;
unsigned int minute;
unsigned int second;
unsigned int day; // 星期几
};
#include "main.h"
#define RTC_BASE (0xE2800000)
#define rINTP (*((volatile unsigned long *)(RTC_BASE + 0x30)))
#define rRTCCON (*((volatile unsigned long *)(RTC_BASE + 0x40)))
#define rTICCNT (*((volatile unsigned long *)(RTC_BASE + 0x44)))
#define rRTCALM (*((volatile unsigned long *)(RTC_BASE + 0x50)))
#define rALMSEC (*((volatile unsigned long *)(RTC_BASE + 0x54)))
#define rALMMIN (*((volatile unsigned long *)(RTC_BASE + 0x58)))
#define rALMHOUR (*((volatile unsigned long *)(RTC_BASE + 0x5c)))
#define rALMDATE (*((volatile unsigned long *)(RTC_BASE + 0x60)))
#define rALMMON (*((volatile unsigned long *)(RTC_BASE + 0x64)))
#define rALMYEAR (*((volatile unsigned long *)(RTC_BASE + 0x68)))
#define rRTCRST (*((volatile unsigned long *)(RTC_BASE + 0x6c)))
#define rBCDSEC (*((volatile unsigned long *)(RTC_BASE + 0x70)))
#define rBCDMIN (*((volatile unsigned long *)(RTC_BASE + 0x74)))
#define rBCDHOUR (*((volatile unsigned long *)(RTC_BASE + 0x78)))
#define rBCDDATE (*((volatile unsigned long *)(RTC_BASE + 0x7c)))
#define rBCDDAY (*((volatile unsigned long *)(RTC_BASE + 0x80)))
#define rBCDMON (*((volatile unsigned long *)(RTC_BASE + 0x84)))
#define rBCDYEAR (*((volatile unsigned long *)(RTC_BASE + 0x88)))
#define rCURTICCNT (*((volatile unsigned long *)(RTC_BASE + 0x90)))
#define rRTCLVD (*((volatile unsigned long *)(RTC_BASE + 0x94)))
// 函数功能:把十进制num转成bcd码,譬如把56转成0x56
static unsigned int num_2_bcd(unsigned int num)
{
// 第一步,把56拆分成5和6
// 第二步,把5和6组合成0x56
return (((num / 10)<<4) | (num % 10));
}
// 函数功能:把bcd码bcd转成十进制,譬如把0x56转成56
static unsigned int bcd_2_num(unsigned int bcd)
{
// 第一步,把0x56拆分成5和6
// 第二步,把5和6组合成56
return (((bcd & 0xf0)>>4)*10 + (bcd & (0x0f)));
}
void rtc_set_time(const struct rtc_time *p)
{
// 第一步,打开RTC读写开关
rRTCCON |= (1<<0);
// 第二步,写RTC时间寄存器
rBCDYEAR = num_2_bcd(p->year - 2000);
rBCDMON = num_2_bcd(p->month);
rBCDDATE = num_2_bcd(p->date);
rBCDHOUR = num_2_bcd(p->hour);
rBCDMIN = num_2_bcd(p->minute);
rBCDSEC = num_2_bcd(p->second);
rBCDDAY = num_2_bcd(p->day);
// 最后一步,关上RTC的读写开关
rRTCCON &= ~(1<<0);
}
void rtc_get_time(struct rtc_time *p)
{
// 第一步,打开RTC读写开关
rRTCCON |= (1<<0);
// 第二步,读RTC时间寄存器
p->year = bcd_2_num(rBCDYEAR) + 2000;
p->month = bcd_2_num(rBCDMON);
p->date = bcd_2_num(rBCDDATE);
p->hour = bcd_2_num(rBCDHOUR);
p->minute = bcd_2_num(rBCDMIN);
p->second = bcd_2_num(rBCDSEC);
p->day = bcd_2_num(rBCDDAY);
// 最后一步,关上RTC的读写开关
rRTCCON &= ~(1<<0);
}
void rtc_set_alarm(void)
{
rALMSEC = num_2_bcd(23);
rRTCALM |= 1<<0;
rRTCALM |= 1<<6;
}
void isr_rtc_alarm(void)
{
static int i = 0;
printf("rtc alarm, i = %d...", i++);
rINTP |= (1<<1);
intc_clearvectaddr();
}
printf("---rtc write time test---");
struct rtc_time tWrite =
{
.year = 2015,
.month = 8,
.date = 9,
.hour = 18,
.minute = 11,
.second = 3,
.day = 0,
};
rtc_set_time(&tWrite);
printf("---rtc read time test---");
struct rtc_time tRead;
while (1)
{
rtc_get_time(&tRead);
printf("The time read is: %d:%d:%d:%d:%d:%d:%d.", tRead.year, tRead.month, tRead.date, tRead.hour, tRead.minute, tRead.second, tRead.day);
// 读写之间做点延时
volatile int i, j;
for (i=0; i<10000; i++)
for (j=0; j<1000; j++);
printf("-------");
}
uart_init();
system_init_exception();
rtc_set_alarm();
intc_setvectaddr(NUM_RTC_ALARM, isr_rtc_alarm);
intc_enable(NUM_RTC_ALARM);
struct rtc_time tRead;
struct rtc_time tWrite =
{
.year = 2020,
.month = 8,
.date = 9,
.hour = 18,
.minute = 11,
.second = 3,
.day = 0,
};
rtc_set_time(&tWrite);
while (1)
{
rtc_get_time(&tRead);
printf("The time read is: %d.", tRead.second);
volatile int i, j;
for (i=0; i<10000; i++)
for (j=0; j<1000; j++);
printf("-------");
}