打印
[DemoCode下载]

最新M471K系列单片机开发板测评:定时器库函数超好用

[复制链接]
1448|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gaoyang9992006|  楼主 | 2021-9-12 19:14 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
之前点灯都是用的延时函数,这次用定时器做,为了体现出新唐BSP的好用,关于配置定时器的部分,我们全部使用BSP提供的库函数。
思路:定时器属于片内外设,因此初始化需要完成以下内容:
使能定时器模块的时钟,启用定时器;
设置定时器模块的时钟源,这里要根据你启用了哪些时钟源;

这里我们通过定时器中断来修改一个LED的状态,所以要使能定时器模块的中断功能;
学过51的都知道51单片机对应的中断模块启用后,还要开启总中断,ARM也不例外,
要将启用的定时器中断加入到嵌套向量中断控制器NVIC.类似于开启总中断(其实还是不一样的,我们先这么理解);
然后还要设置定时器运行的模式和中断周期(这里库函数提供的传入参数是频率),最后就是按下启动开关,让定时器运行。
#include"NuMicro.h"
#include<stdio.h>

void SYS_Init(void)
{
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init System Clock                                                                                       */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Unlock protected registers */
    SYS_UnlockReg();

    /* Set XT1_OUT(PF.2) and XT1_IN(PF.3) to input mode */
    PF->MODE &= ~(GPIO_MODE_MODE2_Msk | GPIO_MODE_MODE3_Msk);

    /* Enable HIRC clock (Internal RC 48 MHz) */
    CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);

    /* Wait for HIRC clock ready */
    CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);

    /* Set core clock as 96MHz from PLL */
    CLK_SetCoreClock(FREQ_96MHZ);

    /* Set PCLK0/PCLK1 to HCLK/2 */
    CLK->PCLKDIV = (CLK_PCLKDIV_APB0DIV_DIV2 | CLK_PCLKDIV_APB1DIV_DIV2);

    /* Enable UART clock */
    CLK_EnableModuleClock(UART0_MODULE);

        CLK_EnableModuleClock(TMR0_MODULE);               
               
    /* Select UART clock source from HIRC */
    CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));
       
        CLK_SetModuleClock(TMR0_MODULE,CLK_CLKSEL1_TMR0SEL_HIRC,0);

    /* Update System Core Clock */
    /* User can use SystemCoreClockUpdate() to calculate SystemCoreClock. */
    SystemCoreClockUpdate();

    /* Set GPB multi-function pins for UART0 RXD and TXD */
    SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB12MFP_Msk | SYS_GPB_MFPH_PB13MFP_Msk))    |       \
                    (SYS_GPB_MFPH_PB12MFP_UART0_RXD | SYS_GPB_MFPH_PB13MFP_UART0_TXD);

/* Lock protected registers */
    SYS_LockReg();
}

void TMR0_IRQHandler(void)
{
    if(TIMER_GetIntFlag(TIMER0) == 1)
    {
        /* Clear Timer0 time-out interrupt flag */
        TIMER_ClearIntFlag(TIMER0);
                        PB14 ^=1;
    }

}

int main(void)
{
        int i=0;

        SYS_Init();

        UART_Open(UART0, 115200);
        printf("Hello World\n");
        GPIO_SetMode(PB,BIT14,GPIO_MODE_OUTPUT);
        PB14=1;

        TIMER_Open(TIMER0,TIMER_PERIODIC_MODE,1);
        TIMER_EnableInt(TIMER0);
        /* Enable Timer0 NVIC */
        NVIC_EnableIRQ(TMR0_IRQn);
        /* Start Timer0 counting */
        TIMER_Start(TIMER0);
        while(1)
        {

        }

}
TIMER_Open(TIMER0,TIMER_PERIODIC_MODE,1);
这里设置的第三个参数是频率,设置为1,那么LED就会以2秒一个周期闪烁,因此1秒修改一次LED的状态。
如果想设置LED以频率1Hz闪烁,那么就将该参数设置为2。
比如我们用串口打印LED的状态
#include"NuMicro.h"
#include<stdio.h>

void SYS_Init(void)
{
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init System Clock                                                                                       */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Unlock protected registers */
    SYS_UnlockReg();

    /* Set XT1_OUT(PF.2) and XT1_IN(PF.3) to input mode */
    PF->MODE &= ~(GPIO_MODE_MODE2_Msk | GPIO_MODE_MODE3_Msk);

    /* Enable HIRC clock (Internal RC 48 MHz) */
    CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);

    /* Wait for HIRC clock ready */
    CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);

    /* Set core clock as 96MHz from PLL */
    CLK_SetCoreClock(FREQ_96MHZ);

    /* Set PCLK0/PCLK1 to HCLK/2 */
    CLK->PCLKDIV = (CLK_PCLKDIV_APB0DIV_DIV2 | CLK_PCLKDIV_APB1DIV_DIV2);

    /* Enable UART clock */
    CLK_EnableModuleClock(UART0_MODULE);

        CLK_EnableModuleClock(TMR0_MODULE);               
               
    /* Select UART clock source from HIRC */
    CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));
       
        CLK_SetModuleClock(TMR0_MODULE,CLK_CLKSEL1_TMR0SEL_HIRC,0);

    /* Update System Core Clock */
    /* User can use SystemCoreClockUpdate() to calculate SystemCoreClock. */
    SystemCoreClockUpdate();

    /* Set GPB multi-function pins for UART0 RXD and TXD */
    SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB12MFP_Msk | SYS_GPB_MFPH_PB13MFP_Msk))    |       \
                    (SYS_GPB_MFPH_PB12MFP_UART0_RXD | SYS_GPB_MFPH_PB13MFP_UART0_TXD);

/* Lock protected registers */
    SYS_LockReg();
}

void TMR0_IRQHandler(void)
{
        if(TIMER_GetIntFlag(TIMER0) == 1)
        {
                /* Clear Timer0 time-out interrupt flag */
                TIMER_ClearIntFlag(TIMER0);
                if(PB14) {PB14=0;printf("LED is ON  \n");}
               
                else     {PB14=1;printf("LED is OFF \n");}
        }

}

int main(void)
{

        SYS_Init();

        UART_Open(UART0, 115200);
        printf("Hello World\n");
       
        GPIO_SetMode(PB,BIT14,GPIO_MODE_OUTPUT);
        PB14=1;

        TIMER_Open(TIMER0,TIMER_PERIODIC_MODE,1);
        TIMER_EnableInt(TIMER0);
        /* Enable Timer0 NVIC */
        NVIC_EnableIRQ(TMR0_IRQn);
        /* Start Timer0 counting */
        TIMER_Start(TIMER0);
        while(1)
        {

        }

}
因为库函数传递的参数是整数,因此最小频率是1Hz,如何实现类似0.5Hz这种操作呢,那么就需要在中断里计数了,计数2个后再执行,就可以了。更大周期的以此类推。
#include"NuMicro.h"
#include<stdio.h>

//用于记录中断次数
        int val=0;

void SYS_Init(void)
{
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init System Clock                                                                                       */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Unlock protected registers */
    SYS_UnlockReg();

    /* Set XT1_OUT(PF.2) and XT1_IN(PF.3) to input mode */
    PF->MODE &= ~(GPIO_MODE_MODE2_Msk | GPIO_MODE_MODE3_Msk);

    /* Enable HIRC clock (Internal RC 48 MHz) */
    CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);

    /* Wait for HIRC clock ready */
    CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);

    /* Set core clock as 96MHz from PLL */
    CLK_SetCoreClock(FREQ_96MHZ);

    /* Set PCLK0/PCLK1 to HCLK/2 */
    CLK->PCLKDIV = (CLK_PCLKDIV_APB0DIV_DIV2 | CLK_PCLKDIV_APB1DIV_DIV2);

    /* Enable UART clock */
    CLK_EnableModuleClock(UART0_MODULE);

        CLK_EnableModuleClock(TMR0_MODULE);               
               
    /* Select UART clock source from HIRC */
    CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));
       
        CLK_SetModuleClock(TMR0_MODULE,CLK_CLKSEL1_TMR0SEL_HIRC,0);

    /* Update System Core Clock */
    /* User can use SystemCoreClockUpdate() to calculate SystemCoreClock. */
    SystemCoreClockUpdate();

    /* Set GPB multi-function pins for UART0 RXD and TXD */
    SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB12MFP_Msk | SYS_GPB_MFPH_PB13MFP_Msk))    |       \
                    (SYS_GPB_MFPH_PB12MFP_UART0_RXD | SYS_GPB_MFPH_PB13MFP_UART0_TXD);

/* Lock protected registers */
    SYS_LockReg();
}

void TMR0_IRQHandler(void)
{
        if(TIMER_GetIntFlag(TIMER0) == 1)
        {
                val++;
                /* Clear Timer0 time-out interrupt flag */
                TIMER_ClearIntFlag(TIMER0);
//计数5秒后再执行翻转LED命令
                if(val==5)
                {
                        val=0;
                        if(PB14) {PB14=0;printf("LED is ON  \n");}
                       
                        else     {PB14=1;printf("LED is OFF \n");}
               
                }

        }

}

int main(void)
{

       
        SYS_Init();

        UART_Open(UART0, 115200);
        printf("Hello World\n");
       
        GPIO_SetMode(PB,BIT14,GPIO_MODE_OUTPUT);
        PB14=1;

        TIMER_Open(TIMER0,TIMER_PERIODIC_MODE,1);
        TIMER_EnableInt(TIMER0);
        /* Enable Timer0 NVIC */
        NVIC_EnableIRQ(TMR0_IRQn);
        /* Start Timer0 counting */
        TIMER_Start(TIMER0);
        while(1)
        {

        }

}


以上代码都是经过测试有效的,不在附带图片或动画。
关于4种定时器计时模式,请参考技术手册的说明。

使用特权

评论回复
沙发
kiwis66| | 2021-9-13 09:50 | 只看该作者
这是把几种配置综合到一起说了~

使用特权

评论回复
板凳
gaoyang9992006|  楼主 | 2021-9-13 11:21 | 只看该作者
kiwis66 发表于 2021-9-13 09:50
这是把几种配置综合到一起说了~

是的,主要还是为了体现出定时器与中断相关库函数的使用方法,确实比很多厂家的库函数好用。

使用特权

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

本版积分规则

认证:西安公路研究院南京院
简介:主要工作从事监控网络与通信网络设计,以及从事基于嵌入式的通信与控制设备研发。擅长单片机嵌入式系统物联网设备开发,音频功放电路开发。

1971

主题

15979

帖子

210

粉丝