【WCH蓝牙系列芯片】-基于CH585开发板—系统 SysTick 定时器应用

------------------------------------------------------------------------------------------------------------------------------------

  在CH585芯片中,内核自带了一个 32 位计数器(SysTick),支持 HCLK 或者 HCLK/8 作为时基,具有较高优先级。SysTick只是它放在了NVIC中,主要的目的是为了给操作系统提供一个硬件上的中断(号称滴答中断)。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。SysTick是基于32M高频晶振工作,所以32M不停止,则嘀嗒定时器一直存在,通常用于系统时间管理和实时操作系统(RTOS)的任务调度。

  CH592的嘀嗒定时器是内核自带的64位计数器。

image

  设置好嘀嗒时间后,计数满会进入到中断并需要手动清除标志

SysTick中断触发程序

#include "CH58x_common.h"
volatile uint32_t systick_irq_count = 0;
/*********************************************************************
 * @fn      DebugInit
 * @brief   调试初始化
 * @return  none
 */
void DebugInit(void)
{
    GPIOA_SetBits(GPIO_Pin_14);
    GPIOPinRemap(ENABLE, RB_PIN_UART0);
    GPIOA_ModeCfg(GPIO_Pin_15, GPIO_ModeIN_PU);
    GPIOA_ModeCfg(GPIO_Pin_14, GPIO_ModeOut_PP_5mA);
    UART0_DefInit();
}
/*********************************************************************
 * @fn      main
 * @brief   主函数
 * @return  none
 */
int main()
{
    HSECFG_Capacitance(HSECap_18p);
    SetSysClock(SYSCLK_FREQ);
    /* 配置串口调试 */
    DebugInit();
    PRINT("Start @ChipID=%02X\n", R8_CHIP_ID);
    printf("\r\n============================================\r\n");
    printf(" Build Date: %s\r\n", __DATE__);
    printf(" Build Time: %s\r\n", __TIME__);
    printf("============================================\r\n");

    SysTick_Config(FREQ_SYS*10);    //设置为FREQ_SYS/1000,则1ms进入一次中断。这个地方设置10秒
    while(1)
    {
        PRINT("SYS_GetSysTickCnt = %d\r\n", SYS_GetSysTickCnt());    //获取计数时间,计数满会进入中断并清0。
        mDelaymS(200);
    }
}
__INTERRUPT
__HIGH_CODE
/*嘀嗒定时器中断函数*/
void SysTick_Handler()
{
    systick_irq_count++;
    PRINT("\r\n---------------------------------------\r\n");
    PRINT("[SysTick IRQ] count =  %d\r\n", systick_irq_count);
    PRINT("---------------------------------------\r\n\r\n");

    SysTick->SR = 0;                    //清除中断标志
}

image

  为了功能验证测试,在systick中断加了打印,来观察systick计数值满了之后,进入中断后,清除中断标志位。CPU 正在执行主循环(while(1)),当 10 秒时间到达时,硬件强制打断了主循环,跳到了 SysTick_Handler() 中执行打印,将systick_irq_count+1,并且将数值打印出来,执行完清理标志位后,又回到了主循环继续干活,观察打印的数据之后,基本是在运行10秒左右就会进入systick中断。

  可以利用 SysTick 计数来测量程序的运行时间,作为调试程序的方式。

  在蓝牙从机中建立一个用于ADC+DMA采集的任务事件,用TMOS任务1秒执行一次这个任务事件,通过记录SysTick计数值来计算出ADC+DMA运行一次所需要的时间大概在多少。

  先在主函数中,注册一个新的TMOS的任务函数,设定一个任务时间,启动1秒的SBP_ADC_DMA_TEST_EVT的任务事件

image

  在TMOS任务处理函数中,调用ADC_DMA_TEST()启动ADC的DMA采集,并且打印出计数值计算出的时间参数。

/* TMOS 定时任务处理函数:每1000ms执行一次 */
uint16_t TEST_ProcessEventtt(uint8_t task_id, uint16_t events)
{
    if(events&SBP_ADC_DMA_TEST_EVT)
    {
        // 打印出总耗时
        PRINT("--> Task execution time: %d us\r\n\r\n", time_us);

        ADC_DMA_TEST();  // 启动新一轮的ADC DMA采集,通道3
        tmos_start_task(ttTaskId, SBP_ADC_DMA_TEST_EVT, 1600);

        return events ^ SBP_ADC_DMA_TEST_EVT;
    }
}

在ADC_DMA_TEST函数中,对ADC引脚进行初始化后,直接通过 t_start = SysTick->CNT;记录ADC开始的SysTick的值

image

image

  当ADC测量完后,DMA数据搬运结束之后,调用 stop_ADC()停止ADC采集,在调用t_end = SYS_GetSysTickCnt();记录任务结束时的 SysTick 计数值。t_diff = t_end - t_start; 然后将开启记录的数据和结束记录的数据相减,将用time_us = t_diff / (FREQ_SYS / 1000000);计算出本次ADC采集所需要的时间

image

最后在TMOS任务事件中,将计算出来的时间

image

通过打印可以看到差不多运行ADC+DMA的采集之后,差不多在651uS左右。

image

除此之后,还可以利用定时器计数的方式来计算出程序运行的时间参数,

image

image

  注:在蓝牙程序中调用systick只是为了初始化时取一个随机数,用户是可以正常使用systick的,需要注意的是开启低功耗后systick是不工作的。嘀嗒定时器在经过睡眠唤醒后,计数会被清除。需要重新使能。

 

posted on 2026-06-03 17:12  凡仕  阅读(132)  评论(0)    收藏  举报