打印
[技术问答]

问个延时函数问题

[复制链接]
529|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
huahuagg|  楼主 | 2020-2-17 22:04 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
clk的延时函数最小延时是多少
/**************************************************************************//**
* [url=home.php?mod=space&uid=288409]@file[/url]     main.c
* [url=home.php?mod=space&uid=895143]@version[/url]  V3.00
* $Revision: 2 $
* $Date: 15/02/13 3:18p $
* @brief
*           A sample code for LED blanking.
*
* @note
* Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/
#include <stdio.h>
#include "M058S.h"

#define PLLCON_SETTING  CLK_PLLCON_50MHz_HXT
#define PLL_CLOCK       50000000

void SYS_Init(void)
{

    /*---------------------------------------------------------------------------------------------------------*/
    /* Init System Clock                                                                                       */
    /*---------------------------------------------------------------------------------------------------------*/

    /* Enable Internal RC 22.1184MHz clock */
    CLK->PWRCON |= CLK_PWRCON_OSC22M_EN_Msk;

    /* Waiting for Internal RC clock ready */
    while(!(CLK->CLKSTATUS & CLK_CLKSTATUS_OSC22M_STB_Msk));

    /* Switch HCLK clock source to Internal RC and and HCLK source divide 1 */
    CLK->CLKSEL0 &= ~CLK_CLKSEL0_HCLK_S_Msk;
    CLK->CLKSEL0 |= CLK_CLKSEL0_HCLK_S_HIRC;
    CLK->CLKDIV &= ~CLK_CLKDIV_HCLK_N_Msk;
    CLK->CLKDIV |= CLK_CLKDIV_HCLK(1);

    /* Enable external XTAL 12MHz clock */
    CLK->PWRCON |= CLK_PWRCON_XTL12M_EN_Msk;

    /* Waiting for external XTAL clock ready */
    while(!(CLK->CLKSTATUS & CLK_CLKSTATUS_XTL12M_STB_Msk));

    /* Set core clock as PLL_CLOCK from PLL */
    CLK->PLLCON = PLLCON_SETTING;
    while(!(CLK->CLKSTATUS & CLK_CLKSTATUS_PLL_STB_Msk));
    CLK->CLKSEL0 &= (~CLK_CLKSEL0_HCLK_S_Msk);
    CLK->CLKSEL0 |= CLK_CLKSEL0_HCLK_S_PLL;

    /* Update System Core Clock */
    /* User can use SystemCoreClockUpdate() to calculate PllClock, SystemCoreClock and CycylesPerUs automatically. */
    //SystemCoreClockUpdate();
    PllClock        = PLL_CLOCK;            // PLL
    SystemCoreClock = PLL_CLOCK / 1;        // HCLK
    CyclesPerUs     = PLL_CLOCK / 1000000;  // For SYS_SysTickDelay()

    /* Enable UART module clock */
    CLK->APBCLK |= CLK_APBCLK_UART0_EN_Msk;

    /* Select UART module clock source */
    CLK->CLKSEL1 &= ~CLK_CLKSEL1_UART_S_Msk;
    CLK->CLKSEL1 |= CLK_CLKSEL1_UART_S_HXT;

    /*---------------------------------------------------------------------------------------------------------*/
    /* Init I/O Multi-function                                                                                 */
    /*---------------------------------------------------------------------------------------------------------*/

    /* Set P3 multi-function pins for UART0 RXD , TXD and CKO */
    SYS->P3_MFP &= ~(SYS_MFP_P30_Msk | SYS_MFP_P31_Msk);
    SYS->P3_MFP |= (SYS_MFP_P30_RXD | SYS_MFP_P31_TXD);

}

void UART0_Init()
{
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init UART                                                                                               */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Reset UART0 */
    SYS->IPRSTC2 |=  SYS_IPRSTC2_UART0_RST_Msk;
    SYS->IPRSTC2 &= ~SYS_IPRSTC2_UART0_RST_Msk;

    /* Configure UART0 and set UART0 Baudrate */
    UART0->BAUD = UART_BAUD_MODE2 | UART_BAUD_MODE2_DIVIDER(__HXT, 115200);
    UART0->LCR = UART_WORD_LEN_8 | UART_PARITY_NONE | UART_STOP_BIT_1;
}

/*---------------------------------------------------------------------------------------------------------*/
/*  Main Function                                                                                          */
/*---------------------------------------------------------------------------------------------------------*/
int32_t main(void)
{
    int32_t i;
   
    /* Unlock protected registers */
    SYS_UnlockReg();

    /* Init System, peripheral clock and multi-function I/O */
    SYS_Init();

    /* Lock protected registers */
    SYS_LockReg();

    /* Init UART0 for printf */
    UART0_Init();

    printf("\n\nCPU [url=home.php?mod=space&uid=72445]@[/url] %dHz\n", SystemCoreClock);

    /*
        This sample code will blinking LED on NuTiny EVB board of M058SSAN.
        The I/O for LED is P2.3 or P3.6
    */

    printf("+---------------------------------------+\n");
    printf("|    NuTiny EVB LED Sample Code         |\n");
    printf("+---------------------------------------+\n");
   
    /* Init P2.3 and P3.6 to be output mode */
    P2->PMD = (P2->PMD & ~(0x3 << 2*3)) | (1 << 2*3);
    P3->PMD = (P3->PMD & ~(0x3 << 2*6)) | (1 << 2*6);
   
    while(1)
    {
        /* Toggle P2.3 */
        P23 ^= 1;
        
        /* Toggle P3.6 */
        P36 ^= 1;
        
        /* Delay 200ms */
        for(i=0;i<2;i++)
            CLK_SysTickDelay(100000);
    }
   
   
}


使用特权

评论回复
沙发
huahuagg|  楼主 | 2020-2-17 22:04 | 只看该作者
CLK_SysTickDelay,这个延时函数最小延时多少,能精确到几个us?

使用特权

评论回复
板凳
幸福小强| | 2020-2-17 22:40 | 只看该作者
应该可以达到1us

使用特权

评论回复
地板
xixi2017| | 2020-2-17 22:45 | 只看该作者
精度应该在5us内。

使用特权

评论回复
5
jasontu| | 2020-2-18 09:29 | 只看该作者
假如使用者想要產生精確的延遲時間,建議使用__nop()函數來組合達成。__nop()函數能夠產生1個精確的CPU時脈週期延遲時間。然而,由於flash的速度低於CPU的時脈速度,在CPU內部有快取優化的技術,編譯器也會自動針對程式做優化,造成__nop()函數組合出來的時間會與預期的時間不同。因此,建議將程式碼放置於SRAM中執行,以避免優化造成的非預期延遲時間問題。

以產生2 us的延遲時間為例:
(1) CPU時脈: 32MHz => 1 CPU 時脈週期花費 1/32000000 sec = 31.25 ns
(2) 2 us 延遲時間 = 2000 s / 31.25 s = 64 次CPU時脈週期

1. 於KEIL的專案中加入一個新的.c檔案

2. 將檔案位置指定至SRAM, 設定Linker

4. 撰寫產生延遲的程式碼

由於執行一次for迴圈需要花費5個CPU時脈週期的時間,因此我們可以使用以下的方式達到2us的時間延遲

(1) 執行一次for迴圈需要5個CPU時脈週期
(2) 執行一次__NOP()指令需要1個CPU時脈週期
(3) 64個CPU時脈週期 = 8 ( 5(for迴圈) + 3 * 1( __NOP() ) )

void Delay_Test_Function(void)
{
    for(i = 0; i < 8 ; i++)     /* Delay for 2 micro seconds. */
    {
        __NOP();
        __NOP();
        __NOP();
    }
}

5. 測試
使用者可以利用下列程式碼進行延遲時間的測試,透過示波器量測I/O toggle的時間,以觀察延遲函數是否精準。由於CPU需要下指令讓I/O轉態,因此觀察到的時間中需要增加轉態的指令時間(PA0 = 0)。

執行一次PA = 0需花費11 CPU指令週期,這意味著I/O會持續(64+11) * 31.25 ns = 2.34375 us的時間才進行轉態。

void Delay_Test_Function(void)
{
    uint32_t i, DelayCNTofCPUClock = 8;
    PA0 = 1;
    for(i = 0; i < DelayCNTofCPUClock ; i++)     /* Delay for 2 micro seconds. */
    {
        __NOP();
        __NOP();
        __NOP();
    }
    PA0 = 0;
}

使用特权

评论回复
6
598330983| | 2020-2-18 13:46 | 只看该作者
这个延时已经非常可以了,可以满足大部分的时序电路需求。

使用特权

评论回复
7
wahahaheihei| | 2020-2-18 20:54 | 只看该作者
51就不要想着太精准了

使用特权

评论回复
8
antusheng| | 2020-2-20 12:53 | 只看该作者
延时函数和设置的过程也需要时间。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

139

主题

1254

帖子

2

粉丝