LPC54608 之 SysTick 应用


一、概述

大家平时都是怎样实现延时功能的呢?for 循环比较简单,但不够精确,定时器比较准确,但稍微更复杂一点,而且还要占用用一个定时器资源,那么有没有既简单又精确的延时方法呢?当然有,这不,SysTick 就登场了。SysTick 定时器是 Cortex-M4 的一个组成部分,它是一个 24 位计数器,使用专用异常向量,由系统时钟或 SYSTICKCLK 内部计时。 由于 SysTick 定时器是 CPU 的一部分,它提供了一个基于 ARM cortex 的设备的标准定时器,从而促进了软件的移植。


二、SysTick 基础知识


2.1
结构框图


SysTick 计时器的结构框图如下图所示。


图 1. SysTick 结构框图


2.2 SysTick
相关寄存器


SysTick 相关的寄存器比较简单,只有以下四个。


图 2. SysTick 寄存器

(1) SYST_CSR 控制状态寄存器主要是使能、中断使能、时钟源的选择等,当使用 SysTick 分频时, CPU 的频率必须不低于SysTick 分频时钟的 2.5 倍。

(2) SYST_RVR 的值是当计数到 0 时,加载到 SysTick 中的值。

(3) SYST_CVR存储 SysTick 当前的计数值。

(4) SYST_CALIB 是一个只读的校准寄存器,其值在配置系统时钟时由 SYSTCKCAL 寄存器提供,我们无需配置。


三、
SysTick 的使用


前面描述了 SysTick 的寄存器,可以通过直接写寄存器来使用,也可以通过调用 SDK 的函数来使用,这里以后者为例,介绍一下 SysTick 的使用。


3.1 SysTick_Config()
函数


打开文件 core_cm4.h 可以找到 SysTick_Config() 函数,如下图所示。


图 3. SDK 的 SysTick_Config() 函数

这个函数主要做了以下配置:

  • 设置重装值
  • 将当前计数值清 0 ,防止之前的计数值影响
  • 配置控制寄存器,使能 SysTick 、使能中断、选择系统时钟作为时钟源

我们可以直接利用这个函数进行 SysTick 的配置,当然,喜欢写寄存器的小伙伴也可以通过直接配置寄存器来完成。


3.2
具体使用


直接调用 SysTick_Config() 进行配置,入口参数为两次中断之间的计数值,比如配置为 1ms 中断一次,如下图。


图 4. 配置 SysTick

接下来是延时函数,比较简单,n 为延时的 ms ,如下图。


图 5. 延时函数

最后,别忘了 SysTick 的中断服务函数,让延时函数的时间变量自减即可,如下图。


图 6. SysTick_Handler() 函数

至此,我们就配置好了一个 1ms 级的延时函数了,接下来在需要延时的地方直接调用 “ SysTick_DelayTicks(uint32_t n);  ”就可以了。


四、LPC54608 之 SysTick 延时实验


4.1
实验目的


通过本实验,理解并掌握 SysTick 延时功能。


4.2
开发环境

硬件: LPC54608 开发板

软件: MCUXpresso v11.3.0 开发环境,SDK_2.9.0_LPC54608J512


4.3
实验描述


本实验以 延时 1000ms 翻转 LED 为例,使用 SysTick 进行精确延时。


4.4
软件设计

(1)按照上述步骤配置 SysTick 即可使用,这里我们延时 1000ms 如下图。


图 7. 软件设计


4.5
实验结果

可以看到 LED3 在有节奏地翻转,抓取引脚波形,可以看到延时时间比较精确。


图 8. LED 引脚波形

4.6 实验代码

/***********************  Standard C Included Files  ***********************/

#include "pin_mux.h"
#include "board.h"
#include "fsl_debug_console.h"
#include "fsl_gpio.h"
#include "stdio.h"

#define APP_BOARD_TEST_LED_PORT 2U
#define APP_BOARD_TEST_LED_PIN 2U


/******************************* Variables *******************************/
volatile uint32_t g_systickCounter;


/******************************* Code *******************************/
void SysTick_Handler(void)
{
if (g_systickCounter != 0U)
{
g_systickCounter--;
}
}



void SysTick_DelayTicks(uint32_t n)
{
g_systickCounter = n;

while (g_systickCounter != 0U)
{
}
}



int main(void)
{
uint32_t port_state = 0;

/* Define the init structure for the output LED pin*/
gpio_pin_config_t led_config = {
kGPIO_DigitalOutput,
0,
};

/* Board pin, clock, debug console init */
/* attach 12 MHz clock to FLEXCOMM0 (debug console) */
CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);

BOARD_InitPins();
BOARD_BootClockPLL180M();
BOARD_InitDebugConsole();

/* Print a note to terminal. */
PRINTF("\r\n GPIO Driver example\r\n");
PRINTF("\r\n The LED is taking turns to shine.\r\n");

/* Init output LED GPIO. */
GPIO_PinInit(GPIO, APP_BOARD_TEST_LED_PORT, APP_BOARD_TEST_LED_PIN, &led_config);
GPIO_PinWrite(GPIO, APP_BOARD_TEST_LED_PORT, APP_BOARD_TEST_LED_PIN, 1);

/* Port masking */
GPIO_PortMaskedSet(GPIO, APP_BOARD_TEST_LED_PORT, 0x0000FFFF);
GPIO_PortMaskedWrite(GPIO, APP_BOARD_TEST_LED_PORT, 0xFFFFFFFF);
port_state = GPIO_PortRead(GPIO, APP_BOARD_TEST_LED_PORT);
PRINTF("\r\n Standard port read: %x\r\n", port_state);
port_state = GPIO_PortMaskedRead(GPIO, APP_BOARD_TEST_LED_PORT);
PRINTF("\r\n Masked port read: %x\r\n", port_state);

/* Set systick reload value to generate 1ms interrupt */
SysTick_Config(SystemCoreClock / 1000U);

while (1)
{
GPIO_PortToggle(GPIO, APP_BOARD_TEST_LED_PORT, 1u << APP_BOARD_TEST_LED_PIN);

/* Delay 1000 ms */
SysTick_DelayTicks(1000U);

}
}

 

五、参考资料

(1)LPC546XX 系列相关资料均可在 NXP 官网下载,网址如下:

https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/lpc54000-cortex-m4-/power-efficient-microcontrollers-mcus-with-advanced-peripherals-based-on-arm-cortex-m4-core:LPC546XX?&tid=vanLPC546XX

★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★博文作者未开放评论功能