高精度延时函数rt_hw_us_delay在CH32V203C8T6的实现

高精度延时函数rt_hw_us_delay在CH32V203C8T6的实现

但其实有SysTick的单片机的用法都差不多

参考:
RT-Thread文档中心-内核-时钟管理-高精度延时
[001] [RT-Thread 学习笔记] 高精度延时函数 rt_hw_us_delay 的陷阱与优化

官方文档给了一个例程,但是这里的SysTick是递减方式的

该函数通过一个 tcnt 变量将当前计数值 tnow 与上一时刻的计数值 told 的差值进行累加(注意 SysTick->VAL
为递减计数器),当累加值 tcnt≥延时节拍 ticks 时跳出循环,而 tcnt 最大值为 0xffff
ffff,不可能出现死循环的情况。

#include <board.h>
void rt_hw_us_delay(rt_uint32_t us)
{
    rt_uint32_t ticks;
    rt_uint32_t told, tnow, tcnt = 0;
    rt_uint32_t reload = SysTick->LOAD;

    /* 获得延时经过的 tick 数 */
    ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
    /* 获得当前时间 */
    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;
            }
        }
    }
}

这里我用的CH32V203C8T6,使用了WCH官方EVT内的例程,其中SysTick默认配置成为了递增计数器

extern uint32_t SystemCoreClock;

static uint32_t _SysTick_Config(rt_uint32_t ticks)
{
    NVIC_SetPriority(SysTicK_IRQn, 0xf0);
    NVIC_SetPriority(Software_IRQn, 0xf0);
    NVIC_EnableIRQ(SysTicK_IRQn);
    NVIC_EnableIRQ(Software_IRQn);

    SysTick->CTLR = 0;
    SysTick->SR = 0;
    SysTick->CNT = 0;
    SysTick->CMP = ticks - 1;
    SysTick->CTLR = 0xF;        // 向上计数
    return 0;
}

系统计数控制寄存器(STK_CTLR)描述如下:
在这里插入图片描述
RTT官方文档的例程的SysTick是递减方式的,这里如果不想更改SysTick初始化的话,就修改一下rt_hw_us_delay内的计算:

void rt_hw_us_delay(rt_uint32_t us)
{
    rt_uint32_t ticks;
    rt_uint32_t told, tnow, tcnt = 0;
    rt_uint32_t reload = SysTick->CMP;

    /* 获得延时经过的 tick 数 */
    ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
    /* 获得当前时间 */
    told = SysTick->CNT;
    while (1)
    {
        /* 循环获得当前时间,直到达到指定的时间后退出循环 */
        tnow = SysTick->CNT;
        if (tnow != told)
        {
            if (tnow < told)
            {
                // 取决于 SysTick->CNT 递增或递减,这里是递增的
                // 通过一个 tcnt 变量将当前计数值 tnow 与上一时刻的计数值 told 的差值进行累加(注意 SysTick->VAL 为递减还是递增计数器)
                // ,当累加值 tcnt≥延时节拍 ticks 时跳出循环,而 tcnt 最大值为 0xffff ffff,不可能出现死循环的情况
//                tcnt += told - tnow;
                tcnt += reload - told + tnow;
            }
            else
            {
//                tcnt += reload - tnow + told;
                tcnt += tnow - told;
            }
            told = tnow;
            if (tcnt >= ticks)
            {
                break;
            }
        }
    }
}

用一个IO引脚切换电平测试下修改后的rt_hw_us_delay()函数

static void test_us(void)
{
    BUZZER_ON;
    rt_hw_us_delay(900);
    BUZZER_OFF;
}
MSH_CMD_EXPORT(test_us, test_us);

逻辑分析仪实测如下:
在这里插入图片描述
但其实只把SysTick初始化为递减计数器可能会更方便点,这样用RTT官方文档例程那种方式就可以了:

static uint32_t _SysTick_Config(rt_uint32_t ticks)
{
    NVIC_SetPriority(SysTicK_IRQn, 0xf0);
    NVIC_SetPriority(Software_IRQn, 0xf0);
    NVIC_EnableIRQ(SysTicK_IRQn);
    NVIC_EnableIRQ(Software_IRQn);

    SysTick->CTLR = 0;
    SysTick->SR = 0;
    SysTick->CNT = 0;
    SysTick->CMP = ticks - 1;
//    SysTick->CTLR = 0xF;        // 向上计数
    SysTick->CTLR = 0x001F; // 向下计数   0----    1 1111
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值