在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

第二十八章 RTC——實時時鐘

W55MH32 ? 來源:W55MH32 ? 作者:W55MH32 ? 2025-06-20 14:08 ? 次閱讀

單芯片解決方案,開啟全新體驗——W55MH32 高性能以太網單片機

W55MH32是WIZnet重磅推出的高性能以太網單片機,它為用戶帶來前所未有的集成化體驗。這顆芯片將強大的組件集于一身,具體來說,一顆W55MH32內置高性能Arm? Cortex-M3核心,其主頻最高可達216MHz;配備1024KB FLASH與96KB SRAM,滿足存儲與數據處理需求;集成TOE引擎,包含WIZnet全硬件TCP/IP協議棧、內置MAC以及PHY,擁有獨立的32KB以太網收發緩存,可供8個獨立硬件socket使用。如此配置,真正實現了All-in-One解決方案,為開發者提供極大便利。

在封裝規格上,W55MH32 提供了兩種選擇:QFN100和QFN68。

W55MH32L采用QFN100封裝版本,尺寸為12x12mm,其資源豐富,專為各種復雜工控場景設計。它擁有66個GPIO、3個ADC、12通道DMA、17個定時器、2個I2C、5個串口、2個SPI接口(其中1個帶I2S接口復用)、1個CAN、1個USB2.0以及1個SDIO接口。如此豐富的外設資源,能夠輕松應對工業控制中多樣化的連接需求,無論是與各類傳感器、執行器的通信,還是對復雜工業協議的支持,都能游刃有余,成為復雜工控領域的理想選擇。 同系列還有QFN68封裝的W55MH32Q版本,該版本體積更小,僅為8x8mm,成本低,適合集成度高的網關模組等場景,軟件使用方法一致。更多信息和資料請進入網站或者私信獲取。

此外,本W55MH32支持硬件加密算法單元,WIZnet還推出TOE+SSL應用,涵蓋TCP SSL、HTTP SSL以及 MQTT SSL等,為網絡通信安全再添保障。

為助力開發者快速上手與深入開發,基于W55MH32L這顆芯片,WIZnet精心打造了配套開發板。開發板集成WIZ-Link芯片,借助一根USB C口數據線,就能輕松實現調試、下載以及串口打印日志等功能。開發板將所有外設全部引出,拓展功能也大幅提升,便于開發者全面評估芯片性能。

若您想獲取芯片和開發板的更多詳細信息,包括產品特性、技術參數以及價格等,歡迎訪問官方網頁,我們期待與您共同探索W55MH32的無限可能。

wKgZPGgbOfaANhwzACodXd3sVzg463.png

第二十八章 RTC——實時時鐘

本章參考資料:《W55MH32數據手冊》、《W55MH32參考手冊》的《電源控制PWR》及《實時時鐘RTC》章節。

1 RTC實時時鐘簡介

W55MH32的RTC外設(Real Time Clock),實質是一個掉電后還繼續運行的定時器。從定時器的角度來說,相對于通用定時器TIM外設,它十分簡單, 只有很純粹的計時和觸發中斷的功能;但從掉電還繼續運行的角度來說,它卻是W55MH32中唯一一個具有如此強大功能的外設。 所以RTC外設的復雜之處并不在于它的定時功能,而在于它掉電還繼續運行的特性。

以上所說的掉電,是指主電源VDD斷開的情況,為了RTC外設掉電繼續運行,必須接上鋰電池給W55MH32的RTC、 備份發卡通過VBAT引腳供電。當主電源VDD有效時,由VDD給RTC外設供電; 而當VDD掉電后,由VBAT給RTC外設供電。但無論由什么電源供電,RTC中的數據都保存在屬于RTC的備份域中, 若主電源VDD和VBAT都掉電,那么備份域中保存的所有數據將丟失。備份域除了RTC模塊的寄存器, 還有42個16位的寄存器可以在VDD掉電的情況下保存用戶程序的數據,系統復位或電源復位時,這些數據也不會被復位。

從RTC的定時器特性來說,它是一個32位的計數器,只能向上計數。它使用的時鐘源有三種,分別為高速外部時鐘的128分頻(HSE/128)、 低速內部時鐘LSI以及低速外部時鐘LSE;使HSE分頻時鐘或LSI的話,在主電源VDD掉電的情況下,這兩個時鐘來源都會受到影響, 因此沒法保證RTC正常工作。因此RTC一般使用低速外部時鐘LSE,在設計中,頻率通常為實時時鐘模塊中常用的32.768KHz, 這是因為32768 = 2的15次方,分頻容易實現,所以它被廣泛應用到RTC模塊。在主電源VDD有效的情況下(待機), RTC還可以配置鬧鐘事件使W55MH32退出待機模式。

2 RTC外設框圖剖析

RTC外設框圖如下:

wKgZO2gxiSqAKuc3AAMaVQnnMmg254.png

框圖中淺灰色的部分都是屬于備份域的,在VDD掉電時可在VBAT的驅動下繼續運行。 這部分僅包括RTC的分頻器,計數器,和鬧鐘控制器。若VDD電源有效,RTC可以觸發RTC_Second(秒中斷)、 RTC_Overflow(溢出事件)和RTC_Alarm(鬧鐘中斷)。從結構圖可以分析到,其中的定時器溢出事件無法被配置為中斷。 若W55MH32原本處于待機狀態,可由鬧鐘事件或WKUP事件(外部喚醒事件,屬于EXTI模塊,不屬于RTC)使它退出待機模式。 鬧鐘事件是在計數器RTC_CNT的值等于鬧鐘寄存器RTC_ALR的值時觸發的。

在備份域中所有寄存器都是16位的, RTC控制相關的寄存器也不例外。它的計數器RTC_CNT的32位由RTC_CNTL和RTC_CNTH兩個寄存器組成,分別保存定時計數值的低16位和高16位。 在配置RTC模塊的時鐘時,通常把輸入的32768Hz的RTCCLK進行32768分頻得到實際驅動計數器的時鐘 TR_CLK =RTCCLK/32768= 1 Hz, 計時周期為1秒,計時器在TR_CLK的驅動下計數,即每秒計數器RTC_CNT的值加1。

由于備份域的存在,使得RTC核具有了完全獨立于APB1接口的特性, 也因此對RTC寄存器的訪問要遵守一定的規則。

系統復位后,默認禁止訪問后備寄存器和RTC,防止對后備區域(BKP)的意外寫操作。 執行以下操作使能對后備寄存器和RTC的訪問:

設置RCC_APB1ENR寄存器的PWREN和BKPEN位來使能電源和后備接口時鐘。

設置PWR_CR寄存器的DBP位使能對后備寄存器和RTC的訪問。

設置后備寄存器為可訪問后,在第一次通過APB1接口訪問RTC時,因為時鐘頻率的差異,所以必須等待APB1與RTC外設同步, 確保被讀取出來的RTC寄存器值是正確的。若在同步之后,一直沒有關閉APB1的RTC外設接口,就不需要再次同步了。

如果內核要對RTC寄存器進行任何的寫操作,在內核發出寫指令后,RTC模塊在3個RTCCLK時鐘之后,才開始正式的寫RTC寄存器操作。 由于RTCCLK的頻率比內核主頻低得多,所以每次操作后必須要檢查RTC關閉操作標志位RTOFF,當這個標志被置1時,寫操作才正式完成。

當然,以上的操作都具有庫函數,讀者不必具體地查閱寄存器。

3 UNIX時間戳

在使用RTC外設前,還需要引入UNIX時間戳的概念。

如果從現在起,把計數器RTC_CNT的計數值置0,然后每秒加1, RTC_CNT什么時候會溢出呢?由于RTC_CNT是32位寄存器, 可存儲的最大值為(232-1),即這樣計時的話,在232秒后溢出,即它將在今后的136年時溢出:

N = 232/365/24/60/60 ≈136年

假如某個時刻讀取到計數器的數值為X = 60*60*24*2,即兩天時間的秒數,而假設又知道計數器是在2011年1月1日的0時0分0秒置0的, 那么就可以根據計數器的這個相對時間數值,計算得這個X時刻是2011年1月3日的0時0分0秒了。而計數器則會在(2011+136)年左右溢出, 也就是說到了(2011+136)年時,如果我們還在使用這個計數器提供時間的話就會出現問題。在這個例子中,定時器被置0的這個時間被稱為計時元年, 相對計時元年經過的秒數稱為時間戳,也就是計數器中的值。

大多數操作系統都是利用時間戳和計時元年來計算當前時間的,而這個時間戳和計時元年大家都取了同一個標準——UNIX時間戳和UNIX計時元年。 UNIX計時元年被設置為格林威治時間1970年1月1日0時0分0秒,大概是為了紀念UNIX的誕生的時代吧, 而UNIX時間戳即為當前時間相對于UNIX計時元年經過的秒數。因為unix時間戳主要用來表示當前時間或者和電腦有關的日志時間(如文件創立時間,log發生時間等), 考慮到所有電腦文件不可能在1970年前創立,所以用unix時間戳很少用來表示1970前的時間。

在這個計時系統中,使用的是有符號的32位整型變量來保存UNIX時間戳的,即實際可用計數位數比我們上面例子中的少了一位, 少了這一位,UNIX計時元年也相對提前了,這個計時方法在2038年1月19日03時14分07秒將會發生溢出,這個時間離我們并不遠。 由于UNIX時間戳被廣泛應用到各種系統中,溢出可能會導致系統發生嚴重錯誤,屆時,很可能會重演一次“千年蟲”的問題,所以在設計預期壽命較長的設備需要注意。

在網絡上搜索“UNIX時間戳”可找到一些網站提供當前實時的UNIX時間戳,見下圖某網站顯示的實時UNIX時間戳:

wKgZPGgxiSmASso2AABBZKpowfM340.png

4 與RTC控制相關的庫函數

W55MH32標準庫對RTC控制提供了完善的函數,使用它們可以方便地進行控制,本小節對這些內容進行講解。

4.1 等待時鐘同步和操作完成

RTC區域的時鐘比APB時鐘慢,訪問前需要進行時鐘同步,只要調用庫函數RTC_WaitForSynchro()即可,而如果修改了RTC的寄存器, 又需要調用RTC_WaitForLastTask()函數確保數據已寫入,見代碼清單:RTC-1 :

代碼清單:RTC-1 等待時鐘同步和操作完成

/**
* @brief  等待RTC寄存器與APB時鐘同步 (RTC_CNT, RTC_ALR and RTC_PRL)
* @note   在APB時鐘復位或停止后,在對RTC寄存器的任何操作前,必須調用本函數
* @param  None
* @retval None
*/
void RTC_WaitForSynchro(void)
{
    /* 清除 RSF 寄存器位 */
    RTC->CRL &= (uint16_t)~RTC_FLAG_RSF;
    /* 等待至 RSF 寄存器位為SET */
    while ((RTC->CRL & RTC_FLAG_RSF) == (uint16_t)RESET) {
    }
}

/**
* @brief  等待上一次對 RTC寄存器的操作完成
* @note   修改RTC寄存器后,必須調用本函數
* @param  None
* @retval None
*/
void RTC_WaitForLastTask(void)
{
    /* 等待至 RTOFF 寄存器位為SET*/
    while ((RTC->CRL & RTC_FLAG_RTOFF) == (uint16_t)RESET) {
    }
}

這兩個庫函數主要通過while循環檢測RTC控制寄存器的RSF和RTOFF位實現等待功能。

4.2 使能備份域涉及RTC配置

默認情況下,RTC所屬的備份域禁止訪問,可使用庫函數PWR_BackupAccessCmd()使能訪問,見代碼清單:RTC-2 :

代碼清單:RTC-2 使能備份域訪問

/**
* @brief  使能對 RTC 和 backup 寄存器的訪問.
* @param   ENABLE 或 DISABLE.
* @retval None
*/
void PWR_BackupAccessCmd(FunctionalState NewState)
{
    *(__IO uint32_t *) CR_DBP_BB = (uint32_t)NewState;
}

該函數通過PWR_CR寄存器的DBP位使能訪問,使能后才可以訪問RTC相關的寄存器,然而若希望修改RTC的寄存器, 還需要進一步使能RTC控制寄存器的CNF位使能寄存器配置,見代碼清單:RTC-3:

代碼清單:RTC-3 進入和退出RTC配置模式

/**
* @brief  進入 RTC 配置模式 .
* @param  None
* @retval None
*/
void RTC_EnterConfigMode(void)
{
    /* 設置 CNF 位進入配置模式 */
    RTC->CRL |= RTC_CRL_CNF;
}

/**
* @brief  退出 RTC 配置模式 .
* @param  None
* @retval None
*/
void RTC_ExitConfigMode(void)
{
    /* 清空  CNF 位退出配置模式 */
    RTC->CRL &= (uint16_t)~((uint16_t)RTC_CRL_CNF);
}

這兩個庫函數分別提供了進入和退出RTC寄存器的配置模式,一般情況下它們由庫函數調用。

4.3 設置RTC時鐘分頻

使用RCC相關的庫函數選擇RTC使用的時鐘后,可以使用庫函數RTC_SetPrescaler()進行分頻, 一般會把RTC時鐘分頻得到1Hz的時鐘,見代碼清單:RTC-4:

代碼清單:RTC-4 設置RTC時鐘分頻

/**
* @brief  設置RTC分頻配置
* @param  PrescalerValue: RTC 分頻值.
* @retval None
*/
void RTC_SetPrescaler(uint32_t PrescalerValue)
{
    RTC_EnterConfigMode();
    /* 設置 RTC 分頻值的 MSB  */
    RTC->PRLH = (PrescalerValue & PRLH_MSB_MASK) >> 16;
    /* 設置 RTC 分頻值的 LSB  */
    RTC->PRLL = (PrescalerValue & RTC_LSB_MASK);
    RTC_ExitConfigMode();
}

在函數中,使用RTC_EnterConfigMode()和RTC_ExitConfigMode()進入和退出RTC寄存器配置模式, 配置時把函數參數PrescalerValue寫入到RTC的PRLH和PRLL寄存器中。

4.4 設置、獲取RTC計數器及鬧鐘

RTC外設中最重要的就是計數器以及鬧鐘寄存器了,它們可以使用RTC_SetCounter()、RTC_GetCounter()以及RTC_SetAlarm()庫函數操作,見代碼清單:RTC-5:

代碼清單:RTC-5 設置RTC計數器及鬧鐘

/**
* @brief  設置 RTC 計數器的值 .
* @param  CounterValue: 要設置的RTC計數器值.
* @retval None
*/
void RTC_SetCounter(uint32_t CounterValue)
{
    RTC_EnterConfigMode();
    /* 設置 RTC 計數器的 MSB  */
    RTC->CNTH = CounterValue >> 16;
    /* 設置 RTC 計數器的 LSB  */
    RTC->CNTL = (CounterValue & RTC_LSB_MASK);
    RTC_ExitConfigMode();
}

/**
* @brief  獲取 RTC 計數器的值 .
* @param  None
* @retval 返回RTC計數器的值
*/
uint32_t RTC_GetCounter(void)
{
    uint16_t tmp = 0;
    tmp = RTC->CNTL;
    return (((uint32_t)RTC->CNTH ALRH = AlarmValue >> 16;
    /* 設置 RTC 鬧鐘的 LSB  */
    RTC->ALRL = (AlarmValue & RTC_LSB_MASK);
    RTC_ExitConfigMode();
}

利用RTC_SetCounter()可以向RTC的計數器寫入新數值,通常這些數值被設置為時間戳以更新時間。

RTC_GetCounter()函數則用于在RTC正常運行時獲取當前計數器的值以獲取當前時間。

RTC_SetAlarm()函數用于配置鬧鐘時間,當計數器的值與鬧鐘寄存器的值相等時, 可產生鬧鐘事件或中斷,該事件可以把睡眠、停止和待機模式的W55MH32芯片喚醒。

5 實時時鐘

5.1 代碼解析

1.頭文件包含

#include 
#include 
#include 
#include "delay.h"
#include "w55mh32.h"

這里包含了標準庫的頭文件stdlib.h、string.h和stdio.h,以及自定義的頭文件delay.h和w55mh32.h。

2.全局變量和函數聲明

USART_TypeDef *USART_TEST = USART1;

void UART_Configuration(uint32_t bound);
void NVIC_Configuration(void);
void RCC_ClkConfiguration(void);
void RTC_Configuration(void);
void Time_Adjust(void);
void Time_Show(void);

__IO uint32_t TimeDisplay = 0;

USART_TEST:指定使用的串口為USART1。

聲明了一系列函數,用于串口配置、中斷向量表配置、時鐘配置、RTC 配置、時間調整和顯示。

TimeDisplay:一個易變的全局變量,用于標記是否需要顯示時間。

3.main()函數

int main(void)
{
    RCC_ClocksTypeDef clocks;

    delay_init();

    RCC_ClkConfiguration();

    UART_Configuration(115200);
    printf("RTC Calendar Test.n");
    RCC_GetClocksFreq(&clocks);

    printf("n");
    printf("SYSCLK: %3.1fMhz, HCLK: %3.1fMhz, PCLK1: %3.1fMhz, PCLK2: %3.1fMhz, ADCCLK: %3.1fMhzn",
           (float)clocks.SYSCLK_Frequency / 1000000, (float)clocks.HCLK_Frequency / 1000000,
           (float)clocks.PCLK1_Frequency / 1000000, (float)clocks.PCLK2_Frequency / 1000000, (float)clocks.ADCCLK_Frequency / 1000000);

    NVIC_Configuration();
    if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
    {
        printf("rRTC not yet configured....n");
        RTC_Configuration();

        printf("RTC configured....n");

        Time_Adjust();
        BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
    }
    else
    {
        if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)
        {
            printf("Power On Reset occurred....n");
        }
        else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)
        {
            printf("External Reset occurred....n");
        }

        printf("No need to configure RTC....n");
        RTC_WaitForSynchro();

        RTC_ITConfig(RTC_IT_SEC, ENABLE);
        RTC_WaitForLastTask();
    }

    RCC_ClearFlag();

    Time_Show();

    while (1);
}

初始化延時函數delay_init()。

配置系統時鐘RCC_ClkConfiguration()。

配置串口UART_Configuration(115200),并輸出測試信息。

獲取系統時鐘頻率并輸出。

配置中斷向量表NVIC_Configuration()。

檢查備份寄存器BKP_DR1的值,如果不等于0xA5A5,則進行 RTC 配置和時間調整;否則,根據復位標志輸出相應信息,并使能 RTC 秒中斷。

清除 RCC 標志位。

進入Time_Show()函數,循環顯示時間。

最后進入無限循環。

4.Time_Display()函數

void Time_Display(uint32_t TimeVar)
{
    uint32_t THH = 0, TMM = 0, TSS = 0;

    if (RTC_GetCounter() == 0x0001517F)
    {
        RTC_SetCounter(0x0);
        RTC_WaitForLastTask();
    }

    THH = TimeVar / 3600;
    TMM = (TimeVar % 3600) / 60;
    TSS = (TimeVar % 3600) % 60;

    printf("Time: %0.2d:%0.2d:%0.2dn", THH, TMM, TSS);
}

該函數用于將秒數轉換為小時、分鐘和秒,并輸出當前時間。如果 RTC 計數器達到0x0001517F,則將其重置為0。

5.Time_Show()函數

void Time_Show(void)
{
    printf("nr");
    while (1)
    {
        if (TimeDisplay == 1)
        {
            Time_Display(RTC_GetCounter());
            TimeDisplay = 0;
        }
    }
}

該函數進入一個無限循環,當TimeDisplay為1時,調用Time_Display()函數顯示當前時間,并將TimeDisplay重置為0。

6.RTC_Configuration()函數

void RTC_Configuration(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

    PWR_BackupAccessCmd(ENABLE);

    BKP_DeInit();

    RCC_LSICmd(ENABLE);
    while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
    {
    }

    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);

    RCC_RTCCLKCmd(ENABLE);

    RTC_WaitForSynchro();

    RTC_WaitForLastTask();

    RTC_ITConfig(RTC_IT_SEC, ENABLE);

    RTC_WaitForLastTask();

    RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */

    RTC_WaitForLastTask();
}

該函數用于配置 RTC,包括使能電源和備份域時鐘、允許訪問備份域、復位備份寄存器、使能低速內部時鐘(LSI)、選擇 RTC 時鐘源、使能 RTC 時鐘、等待 RTC 同步、使能 RTC 秒中斷和設置 RTC 預分頻器。

7.USART_Scanf()函數

uint8_t USART_Scanf(uint32_t value)
{
    uint32_t index  = 0;
    uint32_t tmp[2] = {0, 0};

    while (index < 2)
    {
        while (USART_GetFlagStatus(USART_TEST, USART_FLAG_RXNE) == RESET)
        {
        }
        tmp[index++] = (USART_ReceiveData(USART_TEST));
        if ((tmp[index - 1] < 0x30) || (tmp[index - 1] > 0x39))
        {
            printf("nrPlease enter valid number between 0 and 9");
            index--;
        }
    }
    index = (tmp[1] - 0x30) + ((tmp[0] - 0x30) * 10);

    if (index > value)
    {
        printf("nrPlease enter valid number between 0 and %d", value);
        return 0xFF;
    }
    return index;
}

該函數用于從串口讀取兩個數字字符,并將其轉換為一個兩位數的整數。如果輸入的字符不是數字或超出了指定范圍,則提示用戶重新輸入。

8.Time_Regulate()函數

uint32_t Time_Regulate(void)
{
    uint32_t Tmp_HH = 0xFF, Tmp_MM = 0xFF, Tmp_SS = 0xFF;

    printf("rn==============Time Settings=====================================");
    printf("rn  Please Set Hours");

    while (Tmp_HH == 0xFF)
    {
        Tmp_HH = USART_Scanf(23);
    }
    printf(":  %d", Tmp_HH);
    printf("rn  Please Set Minutes");
    while (Tmp_MM == 0xFF)
    {
        Tmp_MM = USART_Scanf(59);
    }
    printf(":  %d", Tmp_MM);
    printf("rn  Please Set Seconds");
    while (Tmp_SS == 0xFF)
    {
        Tmp_SS = USART_Scanf(59);
    }
    printf(":  %d", Tmp_SS);

    return ((Tmp_HH * 3600 + Tmp_MM * 60 + Tmp_SS));
}

該函數用于通過串口與用戶交互,讓用戶設置小時、分鐘和秒,并將其轉換為秒數返回。

9.Time_Adjust()函數

void Time_Adjust(void)
{
    RTC_WaitForLastTask();
    RTC_SetCounter(Time_Regulate());
    RTC_WaitForLastTask();
}

該函數用于調整 RTC 計數器的值,調用Time_Regulate()函數獲取用戶設置的時間,并將其設置到 RTC 計數器中。

10.NVIC_Configuration()函數

void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;

    /* Configure one bit for preemption priority */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

    /* Enable the RTC Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel                   = RTC_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

該函數用于配置中斷向量表,設置中斷優先級分組為NVIC_PriorityGroup_1,并使能 RTC 中斷。

11.UART_Configuration()函數

void UART_Configuration(uint32_t bound)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate            = bound;
    USART_InitStructure.USART_WordLength          = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits            = USART_StopBits_1;
    USART_InitStructure.USART_Parity              = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;

    USART_Init(USART_TEST, &USART_InitStructure);
    USART_Cmd(USART_TEST, ENABLE);
}

該函數用于配置串口USART1,包括使能 USART1 和 GPIOA 時鐘、配置 GPIO 引腳、設置串口參數(波特率、數據位、停止位、奇偶校驗等),并使能串口。

12.SER_PutChar()和fputc()函數

int SER_PutChar(int ch)
{
    while (!USART_GetFlagStatus(USART_TEST, USART_FLAG_TC));
    USART_SendData(USART_TEST, (uint8_t)ch);

    return ch;
}

int fputc(int c, FILE *f)
{
    /* Place your implementation of fputc here */
    /* e.g. write a character to the USART */
    if (c == 'n')
    {
        SER_PutChar('r');
    }
    return (SER_PutChar(c));
}

SER_PutChar()函數用于向串口發送一個字符。

fputc()函數是標準庫中用于輸出字符的函數,這里將其重定向到串口輸出,并且在輸出換行符時自動添加回車符。

5.2 下載驗證

wKgZO2gxiSmAOyQYAACFGPh8Lpg108.png

6 RTC_LSICalib

6.1 代碼解析

1. 主函數 main()

int main(void) {
    // 初始化串口,打印系統時鐘信息
    UART_Configuration(115200);
    printf("RTC LSI Calib Test.n");
    // 配置RTC、TIM5、NVIC
    RTC_Configuration();
    TIM_Configuration();
    NVIC_Configuration();
    // 等待TIM5測量完成
    while (OperationComplete != 2); 
    // 計算LSI頻率并設置RTC預分頻
    if (PeriodValue != 0) {
        LsiFreq = (uint32_t)((uint32_t)(clocks.PCLK1_Frequency * 2) / (uint32_t)PeriodValue);
    }
    printf("LsiFreq: %d Hzn", LsiFreq);
    RTC_SetPrescaler(LsiFreq - 1);
    while (1);
}

流程:初始化串口后,配置 RTC、TIM5 和中斷,測量 LSI 頻率,最后設置 RTC 預分頻。

2. TIM5 配置(TIM_Configuration)

void TIM_Configuration(void) {
    // 使能時鐘,重映射LSI到TIM5_CH4
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
    GPIO_PinRemapConfig(GPIO_Remap_TIM5CH4_LSI, ENABLE);
    // 配置TIM5時基:不分頻,向上計數,周期0xFFFF
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
    // 配置輸入捕獲:通道4,上升沿捕獲
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;
    TIM_ICInit(TIM5, &TIM_ICInitStructure);
    TIM_Cmd(TIM5, ENABLE);
    TIM_ITConfig(TIM5, TIM_IT_CC4, ENABLE);
}

作用:將 LSI 信號連接到 TIM5_CH4,配置 TIM5 為輸入捕獲模式,測量 LSI 的周期。

3. RTC 配置(RTC_Configuration)

void RTC_Configuration(void) {
    // 使能電源和備份域時鐘,允許訪問備份域
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
    PWR_BackupAccessCmd(ENABLE);
    // 選擇LSI作為RTC時鐘源
    RCC_LSICmd(ENABLE);
    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
    RCC_RTCCLKCmd(ENABLE);
    // 配置RTC預分頻:根據測量的LSI頻率設置
    RTC_SetPrescaler(40000); 
    BKP_RTCOutputConfig(BKP_RTCOutputSource_Second);
}

作用:使能 LSI,將其作為 RTC 時鐘源,配置 RTC 預分頻器,輸出秒信號。

4. NVIC 配置(NVIC_Configuration)

void NVIC_Configuration(void) {
    // 設置中斷優先級分組
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    // 配置RTC中斷:最高優先級
    NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
    NVIC_Init(&NVIC_InitStructure);
    // 配置TIM5中斷:子優先級2
    NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
    NVIC_Init(&NVIC_InitStructure);
}

作用:設置 RTC 和 TIM5 的中斷優先級,確保中斷正確響應。

這段代碼通過 TIM5 測量 LSI 頻率,動態配置 RTC 預分頻,確保 RTC 計時精度,適用于需要校準 LSI 的嵌入式場景,如 RTC 時鐘源校準。

6.2 下載驗證

wKgZPGgxiSmAZq3-AABsVZJKe5Q418.png

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 單片機
    +關注

    關注

    6065

    文章

    44946

    瀏覽量

    648081
  • 實時時鐘
    +關注

    關注

    4

    文章

    308

    瀏覽量

    66916
  • 定時器
    +關注

    關注

    23

    文章

    3297

    瀏覽量

    117454
  • RTC
    RTC
    +關注

    關注

    2

    文章

    615

    瀏覽量

    68449
收藏 人收藏

    評論

    相關推薦
    熱點推薦

    STM32 RTC實時時鐘(一)

    STM32處理器內部集成了實時時鐘控制器(RTC),因此在實現實時時鐘功能時,無須外擴時鐘芯片即可構建實時時鐘系統。
    的頭像 發表于 07-22 15:41 ?5488次閱讀
    STM32 <b class='flag-5'>RTC</b><b class='flag-5'>實時時鐘</b>(一)

    火力發電廠水汽分析方法 第二十八部分:有機物的測定(紫外吸收法)

    火力發電廠水汽分析方法 第二十八部分:有機物的測定(紫外吸收法)
    發表于 09-11 01:09

    「正點原子Linux連載」第二十五章RTC實時時鐘實驗

    1)實驗平臺:正點原子Linux開發板2)摘自《正點原子I.MX6U嵌入式Linux驅動開發指南》關注官方微信號公眾號,獲取更多資料:正點原子第二十五章RTC實時時鐘實驗 實時時鐘是很
    發表于 01-08 15:57

    什么是實時時鐘RTC)?如何更改RTC的時間?

    什么是實時時鐘RTC)?實時時鐘RTC)的基本功能是什么?實時時鐘RTC)晶體誤差的主要來
    發表于 07-19 08:44

    實時時鐘(RTC)概述

    實時時鐘(RTC)概述RTC(real-time clock),實時時鐘是一個獨立的時鐘,RTC
    發表于 08-03 06:33

    火力發電廠水汽分析方法 第二十八部分:有機物的測定(紫外吸收

    火力發電廠水汽分析方法 第二十八部分:有機物的測定(紫外吸收法) Analytical methods of steam and water in power plants Part
    發表于 06-08 12:10 ?27次下載

    第二十八講 數模和模數轉換器

    第二十八講 數模和模數轉換器 第8章 數模和模數轉換器8.1 概述 8.2 D/A轉換器8.2.3 R-2R倒 T形電阻網絡D
    發表于 03-30 16:34 ?3146次閱讀
    <b class='flag-5'>第二十八</b>講 數模和模數轉換器

    模擬電路網絡課件 第二十八節:集成電路運算放大器的參數

    模擬電路網絡課件 第二十八節:集成電路運算放大器的參數 運算放大器的參數 。VIO的大小反應了運放制造中電路的對稱程度和電位配合情況。VIO值
    發表于 09-17 11:39 ?705次閱讀
    模擬電路網絡課件 <b class='flag-5'>第二十八</b>節:集成電路運算放大器的參數

    實用雙向可控硅應用500例二十八

    實用雙向可控硅應用500例二十八
    發表于 09-19 11:56 ?17次下載
    實用雙向可控硅應用500例<b class='flag-5'>二十八</b>類

    淺談RTC實時時鐘特征與原理

    一、RTC實時時鐘特征與原理 查看STM32中文手冊 16 實時時鐘RTC)(308頁) RTC (Real Time Clock):
    的頭像 發表于 06-30 15:54 ?1.1w次閱讀

    stm32溫濕度傳感器報告_「正點原子NANO STM32開發板資料連載」第二十八章 DHT11 數字溫濕度傳感器實驗...

    1)實驗平臺:alientek NANO STM32F411 V1開發板2)摘自《正點原子STM32F4 開發指南(HAL 庫版》關注官方微信號公眾號,獲取更多資料:正點原子第二十八章 DHT11
    發表于 12-05 16:36 ?14次下載
    stm32溫濕度傳感器報告_「正點原子NANO STM32開發板資料連載」<b class='flag-5'>第二十八章</b>  DHT11 數字溫濕度傳感器實驗...

    STM32CubeMX系列|RTC實時時鐘

    RTC實時時鐘1. RTC實時時鐘簡介2. 硬件設計3. 軟件設計3.1 STM32CubeMX設置3.2 MDK-ARM編程4. 下載驗證
    發表于 12-24 19:15 ?16次下載
    STM32CubeMX系列|<b class='flag-5'>RTC</b><b class='flag-5'>實時時鐘</b>

    輕生活科技將參加第二十八屆廣州國際照明展覽會(GILE)

    輕生活科技將參加6月9日至12日的第二十八屆廣州國際照明展覽會(GILE),屆時我們將展示領先的離線語音控制技術方案
    的頭像 發表于 05-30 10:57 ?676次閱讀
    輕生活科技將參加<b class='flag-5'>第二十八</b>屆廣州國際照明展覽會(GILE)

    CW32實時時鐘RTC)介紹

    CW32實時時鐘RTC)介紹
    的頭像 發表于 10-24 15:36 ?1577次閱讀
    CW32<b class='flag-5'>實時時鐘</b>(<b class='flag-5'>RTC</b>)介紹

    鐳拓新款激光圓管切割機亮相第二十八屆中國五金博覽會

    編輯:鐳拓激光一年一度的五金行業盛會——中國五金博覽會即將在浙江永康國際會展中心隆重開幕,今年已經是第二十八屆了,屆時會有來自全國各地的制造業企業參展。這樣的行業盛會怎么能少得了我們鐳拓激光呢!鐳拓
    的頭像 發表于 09-19 10:38 ?760次閱讀
    鐳拓新款激光圓管切割機亮相<b class='flag-5'>第二十八</b>屆中國五金博覽會
    主站蜘蛛池模板: 1024成人 | 福利社藏经阁 | 亚洲成a人伦理 | 91福利国产在线观看网站 | 97青青| 日本一区二区三区在线观看视频 | 色www国产阿娇 | 韩日精品| 日本女人啪啪 | 色婷婷综合久久久久中文一区二区 | 中国日韩欧美中文日韩欧美色 | 黄色在线看网站 | 日本成人a视频 | 久久精品94精品久久精品 | 国产呦精品系列在线 | 狠狠干最新网址 | 色国产在线视频一区 | 视频一区 在线 | 一区二区三区四区在线免费观看 | haose16在线永久免费 | 四虎影永久在线观看网址 | 日本欧美一区二区免费视 | 免费高清在线视频色yeye | 黄色免费网站在线 | 免费人成在线观看网站品爱网 | 1024手机看片国产 | 亚洲日本中文字幕天天更新 | 四虎一影院区永久精品 | 欧美高清视频一区 | 男人和女人做爽爽视频在线观看 | 综合久久2o19 | 国产精欧美一区二区三区 | 在线看片地址 | 亚洲理论片在线观看 | 日韩三级免费 | 婷婷午夜天 | 女同性进行性行为视频 | 天天躁狠狠躁夜夜躁 | 成人特黄午夜性a一级毛片 成人网18免费下 | 亚洲福利一区二区三区 | 特黄特黄特色大片免费观看 |