|
目前共有6篇帖子。
【程序】使用外部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; } }
|
|
|