SysTick 简介
SysTick—系统定时器是属于 CM3 内核中的一个外设,内嵌在 NVIC 中。系统定时器是一个 24bit的向下递减的计数器,计数器每计数一次的时间为 1/SYSCLK,一般我们设置系统时钟 SYSCLK等于 72M。当重装载数值寄存器的值递减到 0 的时候,系统定时器就产生一次中断,以此循环往复。
因为 SysTick 是属于 CM3 内核的外设,所以所有基于 CM3 内核的单片机都具有这个系统定时器,使得软件在 CM3 单片机中可以很容易的移植。系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。
SysTick 寄存器介绍
SysTick—系统定时器有 4 个寄存器,简要介绍如下。在使用 SysTick 产生定时的时候,只需要配置前三个寄存器,最后一个校准寄存器不需要使用。
SysTick寄存器汇总
寄存器名称 | 寄存器描述 |
---|---|
CTRL | SysTick控制及状态寄存器 |
LOAD | SysTick重装载数值寄存器 |
VAL | SysTick当前数值寄存器 |
CALIB | SysTick校准数值寄存器 |
SysTick控制及状态寄存器
位段 | 名称 | 类型 | 复位值 | 描述 |
---|---|---|---|---|
16 | COUNTFLAG | R/W | 0 | 如果在上次读取本寄存器后,SysTick已经计数位0,则该位为1 |
2 | CLKSOURCE | R/W | 0 | 时钟源选择位,0=AHB/8,1=处理器时钟AHB |
1 | TICKINT | R/W | 0 | 1=SysTick倒数计到0时产生SysTick异常请求,0=数到0时无动作。也可以通过读取COUNTFLAG标志位来确定计数器是否递减到0 |
0 | ENABLE | R/W | 0 | SysTick定时器的使能位 |
SysTick重装载数值寄存器
位段 | 名称 | 类型 | 复位值 | 描述 |
---|---|---|---|---|
23:0 | RELOAD | R/W | 0 | 当倒数计数置零时,将被重装载的值 |
SysTick当前数值寄存器
位段 | 名称 | 类型 | 复位值 | 描述 |
---|---|---|---|---|
23:0 | CURRENT | R/W | 0 | 读取时返回当前倒计数的值,写他则使置清零,同时还会清除SysTick控制及状态寄存器中的COUNTFLAG标志 |
SysTick校准数值寄存器
位段 | 名称 | 类型 | 复位值 | 描述 |
---|---|---|---|---|
31 | NOREF | R | 0 | 1=没有外部参考时钟(STCLK 不可用) |
0=外部参考时钟可用 | ||||
30 | SKEW | R | 1 | 1=校准值不是准确的 10ms |
0=校准值是准确的 10ms | ||||
23:0 | TENMS | R | 0 | 10ms 的时间内倒计数的格数。芯片设计者应该通过 Cortex-M3 的输入信号提供该数值。若该值读回零,则表示无法使用校准功能 |
SysTick 定时实验
利用 SysTick 产生 1s 的时基,LED 以 1s 的频率闪烁。
硬件设计
SysTick 属于单片机内部的外设,不需要额外的硬件电路,剩下的只需一个 LED 灯即可。
软件设计
我们创建了两个文件:bsp_SysTick.c 和 bsp_ SysTick.h 文件用来存放 SysTick驱动程序及相关宏定义,中断服务函数放在 stm32f10x_it.c 文件中。(别忘了添加.h文件的路径)
编程要点
1、设置重装载寄存器的值
2、清除当前数值寄存器的值
3、配置控制与状态寄存器
代码分析
SysTick 属于内核的外设,有关的寄存器定义和库函数都在内核相关的库文件 core_cm3.h 中。
SysTick 配置库函数
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
/* 不可能的重装载值,超出范围*/
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1);
// 设置重装载寄存器
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;
// 设置中断优先级
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
// 设置当前数值寄存器
SysTick->VAL = 0;
// 设置系统定时器的时钟源为 AHBCLK=72M
// 使能系统定时器中断
// 使能定时器
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0); /* Function successful */
}
用固件库编程的时候我们只需要调用库函数 SysTick_Config() 即可,形参 ticks 用来设置重装载寄存器的值,最大不能超过重装载寄存器的值 224,当重装载寄存器的值递减到 0 的时候产生中断,然后重装载寄存器的值又重新装载往下递减计数,以此循环往复。紧随其后设置好中断优先级,最后配置系统定时器的时钟等于 AHBCLK=72M,使能定时器和定时器中断,这样系统定时器就配置好了,一个库函数搞定。
SysTick_Config() 库函数主要配置了 SysTick 中的三个寄存器:LOAD、VAL 和 CTRL,有关具体的部分看代码注释即可。
配置 SysTick 中断优先级
static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
if(IRQn < 0) {
SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M3 System Interrupts */
else {
NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for device specific Interrupts */
}
函数首先先判断形参 IRQn 的大小,如果是小于 0,则表示这个是系统异常,系统异常的优先级由内核外设 SCB 的寄存器 SHPRx 控制,如果大于 0 则是外部中断,外部中断的优先级由内核外设 NVIC 中的 IPx 寄存器控制。
因为 SysTick 属于内核外设,跟普通外设的中断优先级有些区别,并没有抢占优先级和子优先级的说法。在 STM32F103 中,内核外设的中断优先级由内核 SCB 这个外设的寄存器:SHPRx(x=1.2.3)来配置。有关 SHPRx 寄存器的详细描述可参考《Cortex-M3 内核编程手册》4.4.8 章节。
下面我们简单介绍下这个寄存器。
SPRH1-SPRH3 是一个 32 位的寄存器,但是只能通过字节访问,每 8 个字段控制着一个内核外设的中断优先级的配置。在 STM32F103 中,只有位 7:4 这高四位有效,低四位没有用到,所以内核外设的中断优先级可编程为:0~15,只有 16 个可编程优先级,数值越小,优先级越高。如果软件优先级配置相同,那就根据他们在中断向量表里面的位置编号来决定优先级大小,编号越小,优先级越高。
系统异常优先级字段
异常 | 字段 | 寄存器描述 |
---|---|---|
Memory management fault | PRI_4 | SHPR1 |
Bus fault | PRI_5 | SHPR1 |
Usage fault | PRI_6 | SHPR1 |
SVCall | PRI_11 | SHPR2 |
PendSV | PRI_14 | SHPR3 |
SysTick | PRI_15 | SHPR3 |
如果要修改内核外设的优先级,只需要修改下面三个寄存器对应的某个字段即可。
在系统定时器中,配置优先级为 (1 « __NVIC_PRIO_BITS) - 1),其中宏 __NVIC_PRIO_BITS为 4,那计算结果就等于 15,可以看出系统定时器此时设置的优先级在内核外设中是最低的,如果要修改优先级则修改这个值即可,范围为:0~15。
// 设置系统定时器中断优先级
NVIC_SetPriority (SysTick_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
但是,问题来了,刚刚我们只是学习了内核的外设的优先级配置。如果我同时使用了 systick 和片上外设呢?而且片上外设也刚好需要使用中断,那 systick 的中断优先级跟外设的中断优先级怎么设置?会不会因为 systick 是内核里面的外设,所以它的中断优先级就一定比内核之外的外设的优先级高?
外设在设置中断优先级的时候,首先要分组,然后设置抢占优先级和子优先级。而 systick 这类内核的外设在配置的时候,只需要配置一个寄存器即可,取值范围为 0~15。既然配置方法不同,那如何区分两者的优先级?下面举例说明。
比如配置一个外设的中断优先级分组为 2,抢占优先级为 1,子优先级也为 1,systick 的优先级为固件库默认配置的 15。当我们比较内核外设和片上外设的中断优先级的时候,我们只需要抓住NVIC 的中断优先级分组不仅对片上外设有效,同样对内核的外设也有效。我们把 systick 的优先级 15 转换成二进制值就是 1111(0b),又因为 NVIC 的优先级分组 2,那么前两位的 11(0b) 就是3,后两位的 11(0b) 也是 3。无论从抢占还是子优先级都比我们设定的外设的优先级低。如果当两个的软件优先级都配置成一样,那么就比较他们在中断向量表中的硬件编号,编号越小,优先级越高。
SysTick 初始化函数(bsp_SysTick.c中)
/**
* @brief 启动系统滴答定时器 SysTick
* @param 无
* @retval 无
*/
void SysTick_Init(void)
{
if (SysTick_Config(SystemCoreClock / SysTime)) // ST3.5.0库版本
{
//初始化出错
while (1);
}
}
(在bsp_SysTick.h中)
//系统滴答定时器中断时间,分别为1ms,10us,1us
/* SystemFrequency / 1000 1ms中断一次
* SystemFrequency / 100000 10us中断一次
* SystemFrequency / 1000000 1us中断一次
*/
#define OMs 0 //修改宏选择使用那个时间
#define TUs 1
#if OMs
#define SysTime 1000
#elif TUs
#define SysTime 100000
#else
#define SysTime 1000000
#endif
SysTick 初始化函数由用户编写,里面调用了 SysTick_Config() 这个固件库函数,通过设置该固件库函数的形参,就决定了系统定时器经过多少时间就产生一次中断。
SysTick 中断时间的计算
SysTick 定时器的计数器是向下递减计数的,计数一次的时间 TDEC=1/CLKAHB,当重装载寄存器中的值 VALUELOAD减到 0 的时候,产生中断,可知中断一次的时间 TINT=VALUELOAD*TDEC=VALUELOAD/CLKAHB,其中 CLKAHB=72MHZ。如果设置 VALUELOAD为 72,那中断一次的时间TINT=72/72M=1us。不过 1us 的中断没啥意义,整个程序的重心都花在进出中断上了,根本没有时间处理其他的任务。
SysTick_Config(SystemCoreClock / 100000)
SysTick_Config()的形我们配置为 SystemCoreClock / 100000=72M/100000=720,从刚刚分析我们知道这个形参的值最终是写到重装载寄存器 LOAD 中的,从而可知我们现在把 SysTick 定时器中断一次的时间 TINT=720/72M=10us。
SysTick 定时时间的计算
当设置好中断时间 TINT后,我们可以设置一个变量 t,用来记录进入中断的次数,那么变量 t 乘以中断的时间 TINT就可以计算出需要定时的时间。
SysTick 定时函数(bsp_SysTick.c)
现在我们定义一个微秒级别的延时函数,形参为 nTime,当用这个形参乘以中断时间 TINT就得出我们需要的延时时间,其中 TINT我们已经设置好为 10us。
/**
* @briefus 延时程序,10us 为一个单位
* @param
*@arg nTime: Delay_us( 1 ) 则实现的延时为 1 * 10us = 10us
* @retval无
*/
void Delay_us(__IO u32 nTime)
{
TimingDelay = nTime;
while (TimingDelay != 0);
}
函数 Delay_us() 中我们等待 TimingDelay 为 0,当 TimingDelay 为 0 的时候表示延时时间到。变量TimingDelay 在中断函数中递减,即 SysTick 每进一次中断即 10us 的时间 TimingDelay 递减一次。
SysTick 中断服务函数(stm32f10x_it.c中)
void SysTick_Handler(void)
{
TimingDelay_Decrement();
}
中断复位函数调用了另外一个函数 TimingDelay_Decrement(),原型如下:(bsp_SysTick.c中)
/**
* @brief 获取节拍程序
* @param 无
* @retval 无
* @attention 在 SysTick 中断函数 SysTick_Handler()调用
*/
void TimingDelay_Decrement(void)
{
if (TimingDelay != 0x00)
{
TimingDelay--;
}
}
别忘记定义全局变量TimingDelay
TimingDelay 的值等于延时函数中传进去的 nTime 的值,比如 nTime=100000,则延时的时间等于100000*10us=1s。
测试函数(bsp_SysTick.c中)
/**
* @brief 使用中断的方法,滴答定时器测试函数
* @param 无
* @retval 无
*/
void TimingDelay_Interrupt_Test(void)
{
/* LED 端口初始化 */
LED_GPIO_Config();
/* 配置SysTick 为10us中断一次 */
SysTick_Init();
for(;;)
{
LED_RED;
Delay_10us(100000); // 100000 * 10us = 1000ms
LED_GREEN;
Delay_10us(100000); // 100000 * 10us = 1000ms
LED_BLUE;
Delay_10us(100000); // 100000 * 10us = 1000ms
}
}
初始化了 LED 和 SysTick,然后在一个 while 循环中以 1s 的频率让 LED 闪烁。
另外一种更简洁的定时编程
上面的实验,我们是使用了中断,而且经过多个函数的调用,还使用了全局变量,理解起来挺费劲的,其实还有另外一种更简洁的写法。我们知道,systick 的 counter 从 reload 值往下递减到 0 的时候,CTRL 寄存器的位 16:countflag 会置 1,且读取该位的值可清 0,所有我们可以使用软件查询的方法来实现延时。(在bsp_SysTick.c中)
// couter 减1的时间 等于 1/systick_clk
// 当counter 从 reload 的值减小到0的时候,为一个循环,如果开启了中断则执行中断服务程序,
// 同时 CTRL 的 countflag 位会置1
// 这一个循环的时间为 reload * (1/systick_clk)
/**
* @brief 直接查询CTRL寄存器,进行us级延时
* @param us为延时多少us
* @retval 无
*/
void SysTick_Delay_Us( __IO uint32_t us)
{
uint32_t i;
SysTick_Config(SystemCoreClock/1000000);
for(i=0;i<us;i++)
{
// 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
while( !((SysTick->CTRL)&(1<<16)) );
}
// 关闭SysTick定时器
SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
}
/**
* @brief 直接查询CTRL寄存器,进行ms级延时
* @param ms为延时多少ms
* @retval 无
*/
void SysTick_Delay_Ms( __IO uint32_t ms)
{
uint32_t i;
SysTick_Config(SystemCoreClock/1000);
for(i=0;i<ms;i++)
{
// 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
// 当置1时,读取该位会清0
while( !((SysTick->CTRL)&(1<<16)) );
}
// 关闭SysTick定时器
SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;
}
/**
* @brief 不使用中断的方法,轮循,滴答定时器测试函数
* @param 无
* @retval 无
*/
void TimingDelay_Test(void)
{
/* LED 端口初始化 */
LED_GPIO_Config();
/* 配置SysTick 为10us中断一次 */
SysTick_Init();
for(;;)
{
LED_RED;
SysTick_Delay_Ms(100); // 100ms
LED_GREEN;
SysTick_Delay_Ms(100); // 100ms
LED_BLUE;
SysTick_Delay_Ms(100); // 100ms
}
}
注:轮循的方法虽然便于理解,但是相当于浪费CPU部分性能,在延时的时候CPU被占用,而且中断还开着,还不断查询寄存器,极大的浪费CPU性能。(其实我感觉有点脱裤子放屁)(别想着修改为S级别,因为那个初始化中断的时间会给的特别大,然后就内存溢出了GG)
代码
bsp_SysTick.c
/**
* *****************************************************************************
* @file bsp_SysTick.c
* @brief 系统滴答定时器
* @author (六千里)
* @date 2024-03-15
* @copyright 无
* *****************************************************************************
*/
#include "bsp_SysTick.h"
/**
* *****************************************************************************
* 使用的全局变量
* *****************************************************************************
*/
__IO uint32_t TimingDelay;
/**
* @brief 启动系统滴答定时器 SysTick
* @param 无
* @retval 无
*/
void SysTick_Init(void)
{
if (SysTick_Config(SystemCoreClock / SysTime)) // ST3.5.0库版本
{
//初始化出错
while (1);
}
}
/**
* @brief us延时程序,10us为一个单位
* @param
* @arg nTime: Delay_us( 1 ) 则实现的延时为 1 * 10us = 10us
* @retval 无
*/
void Delay_10us(__IO u32 nTime)
{
TimingDelay = nTime;
// 使能滴答定时器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
while(TimingDelay != 0);
}
/**
* @brief 获取节拍程序
* @param 无
* @retval 无
* @attention 在 SysTick 中断函数 SysTick_Handler()调用
*/
void TimingDelay_Decrement(void)
{
if (TimingDelay != 0x00)
{
TimingDelay--;
}
}
/**
* @brief 使用中断的方法,滴答定时器测试函数
* @param 无
* @retval 无
*/
void TimingDelay_Interrupt_Test(void)
{
/* LED 端口初始化 */
LED_GPIO_Config();
/* 配置SysTick 为10us中断一次 */
SysTick_Init();
for(;;)
{
LED_RED;
Delay_10us(100000); // 100000 * 10us = 1000ms
LED_GREEN;
Delay_10us(100000); // 100000 * 10us = 1000ms
LED_BLUE;
Delay_10us(100000); // 100000 * 10us = 1000ms
}
}
// couter 减1的时间 等于 1/systick_clk
// 当counter 从 reload 的值减小到0的时候,为一个循环,如果开启了中断则执行中断服务程序,
// 同时 CTRL 的 countflag 位会置1
// 这一个循环的时间为 reload * (1/systick_clk)
/**
* @brief 直接查询CTRL寄存器,进行us级延时
* @param us为延时多少us
* @retval 无
*/
void SysTick_Delay_Us( __IO uint32_t us)
{
uint32_t i;
SysTick_Config(SystemCoreClock/1000000);
for(i=0;i<us;i++)
{
// 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
while( !((SysTick->CTRL)&(1<<16)) );
}
// 关闭SysTick定时器
SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
}
/**
* @brief 直接查询CTRL寄存器,进行ms级延时
* @param ms为延时多少ms
* @retval 无
*/
void SysTick_Delay_Ms( __IO uint32_t ms)
{
uint32_t i;
SysTick_Config(SystemCoreClock/1000);
for(i=0;i<ms;i++)
{
// 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
// 当置1时,读取该位会清0
while( !((SysTick->CTRL)&(1<<16)) );
}
// 关闭SysTick定时器
SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;
}
/**
* @brief 不使用中断的方法,轮循,滴答定时器测试函数
* @param 无
* @retval 无
*/
void TimingDelay_Test(void)
{
/* LED 端口初始化 */
LED_GPIO_Config();
/* 配置SysTick 为10us中断一次 */
SysTick_Init();
for(;;)
{
LED_RED;
SysTick_Delay_Ms(100); // 100ms
LED_GREEN;
SysTick_Delay_Ms(100); // 100ms
LED_BLUE;
SysTick_Delay_Ms(100); // 100ms
}
}
bsp_SysTick.h
#ifndef __BSP_SYSTICK_H
#define __BSP_SYSTICK_H
/**
* *****************************************************************************
* 包含的头文件
* *****************************************************************************
*/
#include "stm32f10x.h"
/**
* *****************************************************************************
* 宏定义
* *****************************************************************************
*/
//系统滴答定时器中断时间,分别为1ms,10us,1us
/* SystemFrequency / 1000 1ms中断一次
* SystemFrequency / 100000 10us中断一次
* SystemFrequency / 1000000 1us中断一次
*/
#define OMs 0 //修改宏选择使用那个时间
#define TUs 1
#if OMs
#define SysTime 1000
#elif TUs
#define SysTime 100000
#else
#define SysTime 1000000
#endif
/**
* *****************************************************************************
* .c文件中包含的函数
* *****************************************************************************
*/
void SysTick_Init(void);
void Delay_10us(__IO u32 nTime);
void TimingDelay_Decrement(void);
void TimingDelay_Interrupt_Test(void);
void TimingDelay_Test(void);
void SysTick_Delay_Ms( __IO uint32_t ms);
void SysTick_Delay_Us( __IO uint32_t us);
#endif /*__BSP_SYSTICK_H*/
stm32f10x_conf,h
/**
******************************************************************************
* @file Project/STM32F10x_StdPeriph_Template/stm32f10x_conf.h
* @author MCD Application Team
* @version V3.5.0
* @date 08-April-2011
* @brief Library configuration file.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F10x_CONF_H
#define __STM32F10x_CONF_H
/* Includes ------------------------------------------------------------------*/
/* Uncomment/Comment the line below to enable/disable peripheral header file inclusion */
#include "stm32f10x_adc.h"
#include "stm32f10x_bkp.h"
#include "stm32f10x_can.h"
#include "stm32f10x_cec.h"
#include "stm32f10x_crc.h"
#include "stm32f10x_dac.h"
#include "stm32f10x_dbgmcu.h"
#include "stm32f10x_dma.h"
#include "stm32f10x_exti.h"
#include "stm32f10x_flash.h"
#include "stm32f10x_fsmc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_i2c.h"
#include "stm32f10x_iwdg.h"
#include "stm32f10x_pwr.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_rtc.h"
#include "stm32f10x_sdio.h"
#include "stm32f10x_spi.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_wwdg.h"
#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
/**
*自己书写文件的头文件
**/
#include "bsp_led.h"
#include "bsp_key.h"
#include "bsp_led_bitbang.h"
#include "bsp_clkconfig.h"
#include "bsp_mcooutput.h"
#include "bsp_exti.h"
#include "bsp_SysTick.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Uncomment the line below to expanse the "assert_param" macro in the
Standard Peripheral Library drivers code */
/* #define USE_FULL_ASSERT 1 */
/* Exported macro ------------------------------------------------------------*/
#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr: If expr is false, it calls assert_failed function which reports
* the name of the source file and the source line number of the call
* that failed. If expr is true, it returns no value.
* @retval None
*/
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0)
#endif /* USE_FULL_ASSERT */
#endif /* __STM32F10x_CONF_H */
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
stm32f10x_it.c
/**
******************************************************************************
* @file Project/STM32F10x_StdPeriph_Template/stm32f10x_it.c
* @author MCD Application Team
* @version V3.5.0
* @date 08-April-2011
* @brief Main Interrupt Service Routines.
* This file provides template for all exceptions handler and
* peripherals interrupt service routine.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_it.h"
/** @addtogroup STM32F10x_StdPeriph_Template
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/******************************************************************************/
/* Cortex-M3 Processor Exceptions Handlers */
/******************************************************************************/
/**
* @brief This function handles NMI exception.
* @param None
* @retval None
*/
void NMI_Handler(void)
{
}
/**
* @brief This function handles Hard Fault exception.
* @param None
* @retval None
*/
void HardFault_Handler(void)
{
/* Go to infinite loop when Hard Fault exception occurs */
while (1)
{
}
}
/**
* @brief This function handles Memory Manage exception.
* @param None
* @retval None
*/
void MemManage_Handler(void)
{
/* Go to infinite loop when Memory Manage exception occurs */
while (1)
{
}
}
/**
* @brief This function handles Bus Fault exception.
* @param None
* @retval None
*/
void BusFault_Handler(void)
{
/* Go to infinite loop when Bus Fault exception occurs */
while (1)
{
}
}
/**
* @brief This function handles Usage Fault exception.
* @param None
* @retval None
*/
void UsageFault_Handler(void)
{
/* Go to infinite loop when Usage Fault exception occurs */
while (1)
{
}
}
/**
* @brief This function handles SVCall exception.
* @param None
* @retval None
*/
void SVC_Handler(void)
{
}
/**
* @brief This function handles Debug Monitor exception.
* @param None
* @retval None
*/
void DebugMon_Handler(void)
{
}
/**
* @brief This function handles PendSVC exception.
* @param None
* @retval None
*/
void PendSV_Handler(void)
{
}
/**
* @brief 系统滴答定时器中断函数,10us中断一次
* @param None
* @retval None
*/
void SysTick_Handler(void)
{
TimingDelay_Decrement();
}
/**
* @brief 按键1中断处理函数
* @param None
* @retval None
*/
void KEY1_IRQHandler(void)
{
//确保是否产生了 EXTI Line 中断
if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) == SET){
//再次检查信号是否来自KEY1,上升沿
if(GPIO_ReadInputDataBit(KEY1_INT_GPIO_PORT,KEY1_INT_GPIO_PIN)){
// LED1 取反
LED1_TOGGLE;
//清除中断标志
EXTI_ClearFlag(KEY1_INT_EXTI_LINE);
}
}
}
/**
* @brief 按键2中断处理函数
* @param None
* @retval None
*/
void KEY2_IRQHandler(void)
{
//确保是否产生了 EXTI Line 中断
if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE) == SET){
//再次检查信号是否来自KEY2,下降沿
if(GPIO_ReadInputDataBit(KEY2_INT_GPIO_PORT,KEY2_INT_GPIO_PIN) == RESET){
// LED2 取反
LED2_TOGGLE;
//清除中断标志位
EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);
}
}
}
/******************************************************************************/
/* STM32F10x Peripherals Interrupt Handlers */
/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
/* available peripheral interrupt handler's name please refer to the startup */
/* file (startup_stm32f10x_xx.s). */
/******************************************************************************/
/**
* @brief This function handles PPP interrupt request.
* @param None
* @retval None
*/
/*void PPP_IRQHandler(void)
{
}*/
/**
* @}
*/
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
main.c
/**
* *****************************************************************************
* @file main.c
* @brief 主函数
* @author (六千里)
* @date 2024-03-10
* @copyright 无
* *****************************************************************************
*/
#include "stm32f10x.h"
int main(void)
{
// 来到这里的时候,系统的时钟已经被配置成72M。
#if 0
TimingDelay_Interrupt_Test();
#else
TimingDelay_Test();
#endif
}