|
目前共有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; } }
|
|
|