|  | 
        
          |  | 【程序】使用外部32.768kHz晶振作为RTC的时钟源(库函数版) |  
          |   一派掌門 二十級 | 
              #include <stm32f10x.h>
 uint8_t seg8[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xa7, 0xa1, 0x86, 0x8e};
 
 void ser_in(uint8_t data)
 {
 uint8_t i;
 for (i = 0; i < 8; i++)
 {
 GPIO_ResetBits(GPIOB, GPIO_Pin_9); // SCLK=>PB9
 if (data & 0x80)
 GPIO_SetBits(GPIOB, GPIO_Pin_7); // DIO=>PB7
 else
 GPIO_ResetBits(GPIOB, GPIO_Pin_7);
 data <<= 1;
 GPIO_SetBits(GPIOB, GPIO_Pin_9);
 }
 }
 
 void par_out(void)
 {
 GPIO_ResetBits(GPIOB, GPIO_Pin_8); // RCLK=>PB8
 GPIO_SetBits(GPIOB, GPIO_Pin_8);
 }
 
 int main(void)
 {
 GPIO_InitTypeDef gpio;
 TIM_TimeBaseInitTypeDef tim;
 
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP | RCC_APB1Periph_TIM6, ENABLE);
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
 
 PWR_BackupAccessCmd(ENABLE); // 允许写入Backup寄存器
 RCC_BackupResetCmd(ENABLE); // 复位Backup Domain
 RCC_BackupResetCmd(DISABLE); // 必须清除复位标志, 否则下面的RCC_RTCCLKConfig函数会执行失败
 
 RCC_LSEConfig(RCC_LSE_ON); // 开外部低速晶振LSE
 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); // RTC选LSE时钟
 RCC_RTCCLKCmd(ENABLE); // 开RTC时钟
 
 RTC_SetPrescaler(0x7fff); // 分频得到1s周期
 RTC_WaitForLastTask();
 RTC_SetCounter(0x12345678); // 设置新时钟值
 RTC_WaitForLastTask(); // 等待设置完毕
 
 // 数码管扫描管脚配置
 gpio.GPIO_Mode = GPIO_Mode_Out_PP;
 gpio.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
 gpio.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_Init(GPIOB, &gpio);
 
 // 数码管扫描中断
 TIM_TimeBaseStructInit(&tim);
 tim.TIM_Period = 24;
 tim.TIM_Prescaler = 7199;
 TIM_TimeBaseInit(TIM6, &tim);
 TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
 TIM_Cmd(TIM6, ENABLE);
 NVIC_EnableIRQ(TIM6_IRQn);
 
 while (1);
 }
 
 void TIM6_IRQHandler(void)
 {
 static uint8_t i = 0;
 static uint32_t n;
 if (i == 0)
 n = RTC_GetCounter();
 if (TIM_GetFlagStatus(TIM6, TIM_FLAG_Update) == SET)
 {
 TIM_ClearFlag(TIM6, TIM_FLAG_Update);
 ser_in(seg8[n & 0x0f]);
 ser_in(1 << i);
 par_out();
 n >>= 4;
 i = (i + 1) % 8;
 }
 }
 
 |  
          |   一派掌門 二十級 | 
              【开机时只读取不写入RTC时钟的程序】int main(void)
 {
 GPIO_InitTypeDef gpio;
 TIM_TimeBaseInitTypeDef tim;
 
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
 RTC_WaitForSynchro(); // 开机后必须等待RTC寄存器同步
 
 // 数码管扫描管脚配置
 gpio.GPIO_Mode = GPIO_Mode_Out_PP;
 gpio.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
 gpio.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_Init(GPIOB, &gpio);
 
 // 数码管扫描中断
 TIM_TimeBaseStructInit(&tim);
 tim.TIM_Period = 24;
 tim.TIM_Prescaler = 7199;
 TIM_TimeBaseInit(TIM6, &tim);
 TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
 TIM_Cmd(TIM6, ENABLE);
 NVIC_EnableIRQ(TIM6_IRQn);
 
 while (1);
 }
 
 |  |
 
         
          |   一派掌門 二十級 | 
              【RTC->CRL寄存器中标志位的变化规律】开机时只有RTOFF为1,此时RTC->CRL=0x20。
 当RTC->CNT和RTC->DIV寄存器同步完毕后,RSF自动置位,RTC->CRL=0x28。此时才允许读取这两个寄存器的内容(否则读到的内容会出错)。
 过了大约1秒钟,SECF置位,然后RTC->CNT自动加1,此时RTC->CRL=0x29。只要软件不清除SECF位,那么SECF就会一直为1,RTC->CRL的值保持在0x29上。
 
 另外,RSF、OWF和ALRF位都只能由软件清零,硬件置1。
 RTOFF位只读,CNF位可读可写。
 
 |  |
 
         
          |   一派掌門 二十級 | 
                            【开机时只读取不写入RTC时钟的程序】 int main(void) {     GPIO_InitTypeDef gpio;...
			  注意:这里所提到的开机,是指V_BAT后备电池未被撤销,或只是按下了复位键而未切断主电源。 否则就必须重新设置RTC寄存器,不可以直接运行该程序。             |  |
 
         
          |   一派掌門 二十級 | 
              【闹钟中断的使用】#include <stm32f10x.h>
 
 uint8_t seg8[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xa7, 0xa1, 0x86, 0x8e};
 uint8_t num = 0;
 uint8_t ready = 0;
 
 void ser_in(uint8_t data)
 {
 uint8_t i;
 for (i = 0; i < 8; i++)
 {
 GPIO_ResetBits(GPIOB, GPIO_Pin_9); // SCLK=>PB9
 if (data & 0x80)
 GPIO_SetBits(GPIOB, GPIO_Pin_7); // DIO=>PB7
 else
 GPIO_ResetBits(GPIOB, GPIO_Pin_7);
 data <<= 1;
 GPIO_SetBits(GPIOB, GPIO_Pin_9);
 }
 }
 
 void par_out(void)
 {
 GPIO_ResetBits(GPIOB, GPIO_Pin_8); // RCLK=>PB8
 GPIO_SetBits(GPIOB, GPIO_Pin_8);
 }
 
 int main(void)
 {
 GPIO_InitTypeDef gpio;
 TIM_TimeBaseInitTypeDef tim;
 
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP | RCC_APB1Periph_TIM6, ENABLE);
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
 
 // 数码管扫描管脚配置
 gpio.GPIO_Mode = GPIO_Mode_Out_PP;
 gpio.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
 gpio.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_Init(GPIOB, &gpio);
 
 // 数码管扫描中断
 TIM_TimeBaseStructInit(&tim);
 tim.TIM_Period = 24;
 tim.TIM_Prescaler = 7199;
 TIM_TimeBaseInit(TIM6, &tim);
 TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
 TIM_Cmd(TIM6, ENABLE);
 NVIC_EnableIRQ(TIM6_IRQn);
 NVIC_SetPriority(TIM6_IRQn, 1); // 较低优先级
 
 PWR_BackupAccessCmd(ENABLE); // 允许写入Backup寄存器
 RCC_BackupResetCmd(ENABLE); // 复位Backup Domain
 RCC_BackupResetCmd(DISABLE); // 必须清除复位标志, 否则下面的RCC_RTCCLKConfig函数会执行失败
 
 RCC_LSEConfig(RCC_LSE_ON); // 开外部低速晶振LSE
 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); // RTC选LSE时钟
 RCC_RTCCLKCmd(ENABLE); // 开RTC时钟
 
 RTC_SetPrescaler(0x7fff); // 分频得到1s周期
 RTC_WaitForLastTask();
 RTC_SetCounter(2007); // 设置新时钟值
 RTC_WaitForLastTask(); // 等待设置完毕
 ready = 1;
 
 RTC_SetAlarm(2017);
 RTC_WaitForLastTask(); // 必须调用这个函数, 否则无法写入成功
 RTC_ITConfig(RTC_IT_ALR, ENABLE);
 NVIC_EnableIRQ(RTC_IRQn);
 NVIC_SetPriority(RTC_IRQn, 0);
 
 while (1);
 }
 
 void TIM6_IRQHandler(void)
 {
 static uint8_t i = 0;
 static uint32_t n;
 if (i == 0)
 n = RTC_GetCounter() % 10000;
 if (TIM_GetFlagStatus(TIM6, TIM_FLAG_Update) == SET)
 {
 TIM_ClearFlag(TIM6, TIM_FLAG_Update);
 if (ready || i >= 5)
 ser_in(seg8[n % 10]);
 else
 ser_in(0xbf);
 ser_in(1 << i);
 par_out();
 n /= 10;
 
 i = (i + 1) % 8;
 if (i == 4)
 {
 i = 5;
 n = num;
 }
 }
 }
 
 void RTC_IRQHandler(void)
 {
 // 这个中断将在2017切换到2018的一瞬间触发
 if (RTC_GetITStatus(RTC_IT_ALR) == SET)
 {
 RTC_ClearITPendingBit(RTC_IT_ALR);
 num++;
 }
 }
 
 |  |
 
         
          |   一派掌門 二十級 | 
              【从下面的程序可以看出,RTC->DIV寄存器的值从RTC->PRL=32767开始倒计数到0,速度非常快,每隔1秒钟就能完成一个周期】void TIM6_IRQHandler(void)
 {
 static uint8_t i = 0;
 static uint32_t n;
 if (i == 0)
 n = RTC_GetDivider(); // 32位整型, 但只显示十进制的最后8位
 if (TIM_GetFlagStatus(TIM6, TIM_FLAG_Update) == SET)
 {
 TIM_ClearFlag(TIM6, TIM_FLAG_Update);
 ser_in(seg8[n % 10]);
 ser_in(1 << i);
 par_out();
 n /= 10;
 i = (i + 1) % 8;
 }
 }
 
 |  |
 
         |  |  |