参考:
SysTick就是一个定时器而已,只是它放在了NVIC中,主要的目的是为了给操作系统提供一个硬件上的中断(号称滴答中断)。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。
使用SysTick
的方法其实很简单,只需要在main.c
的初始化中添加SysTick_Config()
函数,设定嘀嗒时间,并在对应的中断函数中清除对应的标志即可。
SysTick_Config()
函数在core_riscv.h
中:
#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFFFFFFFFFFF)
#define SysTick_CTLR_INIT (1 << 5)
#define SysTick_CTLR_MODE (1 << 4)
#define SysTick_CTLR_STRE (1 << 3)
#define SysTick_CTLR_STCLK (1 << 2)
#define SysTick_CTLR_STIE (1 << 1)
#define SysTick_CTLR_STE (1 << 0)
#define SysTick_SR_CNTIF (1 << 0)
RV_STATIC_INLINE uint32_t SysTick_Config(uint64_t ticks)
{
if((ticks - 1) > SysTick_LOAD_RELOAD_Msk)
return (1); /* Reload value impossible */
SysTick->CMP = ticks - 1; /* set reload register */
PFIC_EnableIRQ(SysTick_IRQn);
SysTick->CTLR = SysTick_CTLR_INIT |
SysTick_CTLR_STRE |
SysTick_CTLR_STCLK |
SysTick_CTLR_STIE |
SysTick_CTLR_STE; /* Enable SysTick IRQ and SysTick Timer */
return (0); /* Function successful */
}
这里在初始化时,通过设置系统计数控制寄存器SysTick->CTLR
将SysTick
设置为了向上计数从0开始,并使能了自动重载计数,计数器时钟源为HCLK,同时使能了计数器中断,启动计数器。
关于SysTick
计数时间的计算很简单,看下面就行:
// 设定嘀嗒时间 1000ms
#define SYSTICK_INTERVAL (1000)
// 自动重新加载计数值,计数时钟60M的话,以1ms为例,参数是60000
SysTick_Config( GetSysClock() / 1000 * SYSTICK_INTERVAL); //设定嘀嗒时间1000ms
这里我是在新建工程的串口模板工程中修改的:
#include "CH58x_common.h"
uint8_t TxBuff[] = "This is a tx exam\r\n";
uint8_t RxBuff[100];
uint8_t trigB;
// 设定嘀嗒时间 1000 ms
#define SYSTICK_INTERVAL (1000)
// SysTick完成一次计时中断的标志
volatile uint8_t systick_flag = 0;
/*********************************************************************
* @fn main
*
* @brief 主函数
*
* @return none
*/
int main()
{
SetSysClock(CLK_SOURCE_PLL_60MHz);
// 自动重新加载计数值,计数时钟60M,以1ms为例,参数是60000
SysTick_Config( GetSysClock() / 1000 * SYSTICK_INTERVAL); //设定嘀嗒时间1000ms
/* 配置串口1:先配置IO口模式,再配置串口 */
GPIOA_SetBits(GPIO_Pin_9);
GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU); // RXD-配置上拉输入
GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA); // TXD-配置推挽输出,注意先让IO口输出高电平
UART1_DefInit();
// 中断方式:接收数据后发送出去
UART1_ByteTrigCfg(UART_7BYTE_TRIG);
trigB = 7;
UART1_INTCfg(ENABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
PFIC_EnableIRQ(UART1_IRQn);
PRINT("GetSysClock: %d\n", GetSysClock());
while(1)
{
if(systick_flag)
{
systick_flag = 0;
UART1_SendString("SysTick_Handler\n", strlen("SysTick_Handler\n"));
}
}
}
// SysTick中断函数
__INTERRUPT
__HIGH_CODE
void SysTick_Handler()
{
systick_flag = 1;
SysTick->SR = 0; // 清除中断标志
// UART1_SendString("SysTick_Handler\r\n", strlen("SysTick_Handler\r\n"));
}
/*********************************************************************
* @fn UART1_IRQHandler
*
* @brief UART1中断函数
*
* @return none
*/
__INTERRUPT
__HIGH_CODE
void UART1_IRQHandler(void)
{
volatile uint8_t i;
switch(UART1_GetITFlag())
{
case UART_II_LINE_STAT: // 线路状态错误
{
// UART1_GetLinSTA();
break;
}
case UART_II_RECV_RDY: // 数据达到设置触发点
for(i = 0; i != trigB; i++)
{
RxBuff[i] = UART1_RecvByte();
UART1_SendByte(RxBuff[i]);
}
break;
case UART_II_RECV_TOUT: // 接收超时,暂时一帧数据接收完成
i = UART1_RecvString(RxBuff);
UART1_SendString(RxBuff, i);
break;
case UART_II_THR_EMPTY: // 发送缓存区空,可继续发送
break;
case UART_II_MODEM_CHG: // 只支持串口0
break;
default:
break;
}
}
测试效果如下: