【华大测评】+华大HC32F460开发板之systick延时函数

最近经过各种国产MCU的摧残,一开始我还觉得代码风格不是很好的华大460开发板代码,在我眼里又好了起来。之前时间在调试HC32L130,用了之后我对华大的MCU开始有了好的印象。最近又有点空了,决定再全面整下F460。
老规矩,先看第一个DEMO,gpio输出控制LED的例程。在看到F460给出例程的us级别的延时函数:
void Ddl_Delay1us(uint32_t u32Cnt)
{
    uint32_t u32Cyc = 1ul;
    volatile uint32_t i = 0ul;

if(SystemCoreClock > 10000000ul)
    {
        u32Cyc = SystemCoreClock / 10000000ul;
        while(u32Cnt-- > 0ul)
        {
            i = u32Cyc;
            while (i-- > 0ul)
            {
                ;
            }
        }
    }
    else
    {
         while(u32Cnt-- > 0ul)
         {
            ;
         }
    }
}

这样只是大概的软件延时。如果仅仅做个大概调试,那没问题,但我觉得官方还是应该给出精确
时间的延时。毕竟是官方么,应该要更权威要更谨慎些。
为啥不直接读systick的值来做延时呢?查了下华大HC460的数据手册和参考手册,对systick都无详细的讲解,真是奇怪,难道这个定时器
不入华大的眼,直接几乎给忽略了,给的例程里面也没有。
systick定时器还是挺重要的,可以做OS系统的心跳节拍,也可以作为延时的定时器。下面用systick
做延时:
为了不和模拟的延时冲突,新建delay.h和delay.c。
具体函数如下:
我查了下,虽然华大的HC460相关DEMO没提到systick,但是它也是基于CM4内核的,在core_cm4.h的
面有该寄存器的定义和应该配置应用函数。
寄存器定义:

相关配置函数:

下面我们参照修改下:
初始化函数,配置1ms中断一次,留在这功能将来移植OS可能要用到:
目前中断函数里面不写。
void delay_init(void)
{       
    SysTick->LOAD  = (uint32_t)(SystemCoreClock/1000);                /* set reload register 1KHz */
    NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
    SysTick->VAL   = 0UL;                                             /* Load the SysTick Counter Value */

SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                     SysTick_CTRL_TICKINT_Msk   |
                     SysTick_CTRL_ENABLE_Msk;                         /* Enable SysTick IRQ and SysTick Timer */
}
//us延时
void delay_us(uint32_t u32Cnt)
{
        uint32_t ticks;
    uint32_t told,tnow,tcnt=0;
    uint32_t reload=SysTick->LOAD;  //sysTick load  1ms中断
       
    ticks=u32Cnt*(SystemCoreClock/1000000);//转换成1us基本单位的节拍
    told=SysTick->VAL;
    while(1)
    {
        tnow=SysTick->VAL;
        if(tnow!=told)
        {

if(tnow<told)tcnt+=told-tnow;
            else tcnt+=reload-tnow+told;
            told=tnow;
            if(tcnt>=ticks)break;
        }
    }
}
//ms延时
void delay_ms(uint32_t u32Cnt)
{
        uint32_t ticks;
    uint32_t told,tnow,tcnt=0;
    uint32_t reload=SysTick->LOAD;  //sysTick load  1ms中断
       
    ticks=u32Cnt*(SystemCoreClock/1000);//转换成1ms基本单位的节拍
    told=SysTick->VAL;
    while(1)
    {
        tnow=SysTick->VAL;
        if(tnow!=told)
        {

if(tnow<told)tcnt+=told-tnow;
            else tcnt+=reload-tnow+told;
            told=tnow;
            if(tcnt>=ticks)break;
        }
    }
}

在main函数的while循环里面检测10us,LED0引脚反转一次,截取示波器波形:
systick延时的抓起图片:

软件延时抓取的延时:

显然systick定时器更胜一筹。
再用串口助手简易测试下时间间隔:
测试程序:
        printf("Begin。。。\r\n");
        LED0_TOGGLE();
        Ddl_Delay1ms(300);
                //delay_ms(300);
        LED1_TOGGLE();
        Ddl_Delay1ms(300);
                //delay_ms(300);
        LED2_TOGGLE();
        Ddl_Delay1ms(300);
                //delay_ms(300);
        LED3_TOGGLE();
        Ddl_Delay1ms(300);
                //delay_ms(300);
        /* de-init if necessary */
        //PORT_DeInit();
                printf("End。。。\r\n");

用systick的延时函数delay_ms做延时:

能看出2次之间间隔几乎就是1.2ms
用软件延时Ddl_Delay1ms做延时:

能看出2次之间间隔几乎就是1.8ms

当然也可能是我自己把频率调到168M的缘故,导致SystemCoreClock / 10000000ul的商
为16.8,结果可能进位还是啥的。这里列出仅仅是参考对应,要求不严格,2种都可用。
PS:
可能是我自己没找到HC32F460关于systick的说明。
如果谁有麻烦上传一份。
好了,今天就到这。

(0)

相关推荐