大家好,我是陈滨。本人学STM32也有几个月的时间,从对ARM望而生畏到现在会开发STM32程序,途中付出也不少,很多人看到ARM处理器那些复杂的寄存器,都望而却步;但是本人没有这样子,反而越复杂越想征服它!在开发的过程中,本人积累了不少经验,这个就有其中的RTC。这不,最近在开发3264万年历就积累了这个知识。大家都知道STM32F103系列的RTC只是一个秒计数器,没有提供真正的年月日功能,网上很多资料都把这个计数器进行60进制处理得到时间,但是这个方法效率很低不说,闰年闰月还不好处理;这个是一个问题,而且在设置的时候,处理也是一个问题!经过本人苦苦的研究发现:KEIL已经帮我们完成这个问题。KEIL里面有一个头文件,叫time.h,专门针对32位处理器处理实时时钟功能,该文件支持把计数器直接转换成时间信息,也支持设置时间信息,还支持计算两地的时间差,并且自动计算出星期信息,支持从1970年到2108年的计算,更有趣的是,该文件还支持把计数器的值直接打印成字符串,下面是本人将这个功能直接打印在液晶屏的结果:

下面本人将按实际教大家来写这个程序:
在该头文件中,定义了一个结构体TM:
struct tm {
int tm_sec; /* seconds after the minute, 0 to 60
(0 - 60 allows for the occasional leap second) */
int tm_min; /* minutes after the hour, 0 to 59 */
int tm_hour; /* hours since midnight, 0 to 23 */
int tm_mday; /* day of the month, 1 to 31 */
int tm_mon; /* months since January, 0 to 11 */
int tm_year; /* years since 1900 */
int tm_wday; /* days since Sunday, 0 to 6 */
int tm_yday; /* days since January 1, 0 to 365 */
int tm_isdst; /* Daylight Savings Time flag */
union { /* ABI-required extra fields, in a variety of types */
struct {
int __extra_1, __extra_2;
};
struct {
long __extra_1_long, __extra_2_long;
};
struct {
char *__extra_1_cptr, *__extra_2_cptr;
};
struct {
void *__extra_1_vptr, *__extra_2_vptr;
};
};
};
从以上的结构体注释可以看出(虽然本人的英语很差,但还是看得懂):在结构体中声明了很多变量,其中的tm_sec就是秒,范围是0-59;还有tm_min,自然就是分钟,下面的tm_hour不用我说了吧?到了tm_yday这个是今年到现在的天数,可以不用管,下面是tm_isdst是设置保存标志,一般也不用管。那么怎么从这个结构体得到时间信息或者是设置时间呢?在这个头文件中,定义了一个函数:
extern _ARMABI struct tm *localtime(const time_t * /*timer*/) __attribute__((__nonnull__(1)));
这个函数的功能是输入一个32位秒计算值,输出一个时间信息结构体,好,现在我来写这个程序:
首先创建一个函数,名字就叫Get_time吧:
void Get_time()
{
u32 temp;
u8 sec,min,hour,day,week,month,year; //定义时间信息变量
struct tm *loca; //定义一个结构体指针
temp=RTC->CNTH; //从STM32的RTC中取出高16数据赋值给临时变量temp
temp<<=16; //左移16位把数据移向高16位
time_count=temp|RTC->CNTL; //从STM32的RTC中读取低16数据与高16数据相或得到一个32位数据,这个关系数学计算,本人的数学还可以,哈哈
loca=localtime(&time_count); 将这个32位数据地址赋值给locatime的参数入口,这个时候这个函数开始工作,接下来可以读取信息了
sec=loca->tm_sec; ///取出秒信息,这个关系到C语言的指针知识,如果你看不懂,再去学习
min=loca->tm_min; //取出分钟,下面以此类推
hour=loca->tm_hour;
day=loca->tm_mday;
week=loca->wday;
month=loca->tm_mon;
year=loca->tm_year;
}
以上是得到时间日期的信息,头文件定义了下面的函数:
extern _ARMABI time_t mktime(struct tm * /*timeptr*/) __attribute__((__nonnull__(1)));
这个函数的功能是输入一个结构体时间信息,输出一个32位计数值,下面本人再写个程序,将设置的时间日期信息写入RTC:
void Set_time(u8 sec,u8 s_min,u8 s_hour,u8 s_day,u8 s_month,u16 s_year)
{
struct tm Rtc; //定义一个时间结构体
u32 tim;
Rtc.tm_sec=sec; //将参数的值赋值给设置值
Rtc.tm_min=s_min;
Rtc.tm_hour=s_hour;
Rtc.tm_mday=s_day;
Rtc.tm_mon=s_month-1; //月份从0-11,填入的是1-12,所以减去1
Rtc.tm_year=s_year-1900; //减去1900年,这个是由keil的函数决定的
Rtc.tm_isdst=-1;
tim=mktime(&Rtc);
PWR->CR=PWR_CR_DBP; //取消后备保护
RTC->CRL=RTC_CRL_CNF; //进入STM32配置模式
RTC->CNTH=tim>>16;
RTC->CNTL=tim&0xffff;
RTC->CRL&=0x2f; //退出配置模式
while(!(RTC->CRL&RTC_CRL_RTOFF)); //等待写入完成
PWR->CR=0; //打开保护
}
注意:星期是无需设置的,该函数自动会计算生成!
以上是读出和写入的功能,文件中还定义了另外一个函数:
extern _ARMABI unsigned char *asctime(const struct tm * /*timeptr*/) __attribute__((__nonnull__(1)));
这个就是本文开头的功能了,就是输入一个时间结构体,输出字符串信息,这个不难了吧?大家自己研究。
|