Systick 是stm32上一个用处很多的内设,所有基于arm-cortex m3 的芯片都有这个定时器,所以考虑到平台的可移植性时,可以多使用Systick。
Systick 是一个24位数据宽度的倒计数定时器,其计数范围只能到 1677215(2^24),当计数到0时会从RELOAD寄存器 中自动重装定时初值。只要不把SysTick的控制及状态寄存器中的使能位清除,计数器就不会停止。
SysTick 可以产生中断、设置中断优先级,有专门的中断处理函数SysTick_Handler().库函数作为ST公司自己的推出的框架, 在中断这方面做了更为细致的处理。
库函数包含的头文件是 stm32f10x.h 这个文件中 列出了完整的stm32中断向量表(截取部分):
01
|
/****** Cortex-M3 Processor Exceptions Numbers ***************************************************/
|
02
|
NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */
|
03
|
MemoryManagement_IRQn = -12, /*!< 4 Cortex-M3 Memory Management Interrupt */
|
04
|
BusFault_IRQn = -11, /*!< 5 Cortex-M3 Bus Fault Interrupt */
|
05
|
UsageFault_IRQn = -10, /*!< 6 Cortex-M3 Usage Fault Interrupt */
|
06
|
SVCall_IRQn = -5, /*!< 11 Cortex-M3 SV Call Interrupt */
|
07
|
DebugMonitor_IRQn = -4, /*!< 12 Cortex-M3 Debug Monitor Interrupt */
|
08
|
PendSV_IRQn = -2, /*!< 14 Cortex-M3 Pend SV Interrupt */
|
09
|
SysTick_IRQn = -1, /*!< 15 Cortex-M3 System Tick Interrupt */
|
11
|
/****** STM32 specific Interrupt Numbers *********************************************************/
|
12
|
WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */
|
13
|
PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */
|
14
|
TAMPER_IRQn = 2, /*!< Tamper Interrupt */
|
15
|
RTC_IRQn = 3, /*!< RTC global Interrupt */
|
16
|
FLASH_IRQn = 4, /*!< FLASH global Interrupt */
|
17
|
RCC_IRQn = 5, /*!< RCC global Interrupt */
|
18
|
EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */
|
19
|
EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */
|
20
|
EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */
|
21
|
EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */
|
22
|
EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */
|
23
|
DMA1_Channel1_IRQn = 11, /*!< DMA1 Channel 1 global Interrupt */
|
24
|
DMA1_Channel2_IRQn = 12, /*!< DMA1 Channel 2 global Interrupt */
|
25
|
DMA1_Channel3_IRQn = 13, /*!< DMA1 Channel 3 global Interrupt */
|
26
|
DMA1_Channel4_IRQn = 14, /*!< DMA1 Channel 4 global Interrupt */
|
27
|
DMA1_Channel5_IRQn = 15, /*!< DMA1 Channel 5 global Interrupt */
|
28
|
DMA1_Channel6_IRQn = 16, /*!< DMA1 Channel 6 global Interrupt */
|
29
|
DMA1_Channel7_IRQn = 17, /*!< DMA1 Channel 7 global Interrupt */
|
其中就包含了对系统级中断的处理,有SysTick的中断定义。
在 库函数的Cmsis\core_cm3.h文件中的中断配置函数也区分了系统中断 和 其他中断的区分处理 :
1
|
static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
|
4
|
SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M3 System Interrupts */
|
6
|
NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for device specific Interrupts */
|
其中 SysTick_Config()函数也在这个文件中:
01
|
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
|
03
|
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
|
05
|
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */
|
06
|
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
|
07
|
SysTick->VAL = 0; /* Load the SysTick Counter Value */
|
08
|
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
|
09
|
SysTick_CTRL_TICKINT_Msk |
|
10
|
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
|
11
|
return (0); /* Function successful */
|
所以库函数中可以将SysTick作为一个中断操作。
但是直接操作寄存器,包含的头文件是 stm32f10x_lib.h ,中断向量表在stm32f10x_nvic.h 中(截取部分):
01
|
/* IRQ Channels --------------------------------------------------------------*/
|
02
|
#define WWDG_IRQChannel ((u8)0x00) /* Window WatchDog Interrupt */
|
03
|
#define PVD_IRQChannel ((u8)0x01) /* PVD through EXTI Line detection Interrupt */
|
04
|
#define TAMPER_IRQChannel ((u8)0x02) /* Tamper Interrupt */
|
05
|
#define RTC_IRQChannel ((u8)0x03) /* RTC global Interrupt */
|
06
|
#define FLASH_IRQChannel ((u8)0x04) /* FLASH global Interrupt */
|
07
|
#define RCC_IRQChannel ((u8)0x05) /* RCC global Interrupt */
|
08
|
#define EXTI0_IRQChannel ((u8)0x06) /* EXTI Line0 Interrupt */
|
09
|
#define EXTI1_IRQChannel ((u8)0x07) /* EXTI Line1 Interrupt */
|
10
|
#define EXTI2_IRQChannel ((u8)0x08) /* EXTI Line2 Interrupt */
|
11
|
#define EXTI3_IRQChannel ((u8)0x09) /* EXTI Line3 Interrupt */
|
12
|
#define EXTI4_IRQChannel ((u8)0x0A) /* EXTI Line4 Interrupt */
|
并没有对systick做定义,所以直接操作寄存器,需要通过查询标志位的方式,查看Systick的状态。
本例将实现用Systick 产生一个100ms的定时器,让GPIO_Pin_5管脚led灯闪烁。
操作寄存器
在stm32f10x_map.h中,包含了对SysTick的结构体定义:
typedef struct
{
vu32 CTRL;
vu32 LOAD;
vu32 VAL;
vuc32 CALIB;
} SysTick_TypeDef;
手册上对SysTick的介绍并不详细,各个寄存器的各位定义如下:
systick的时钟来自外部时钟,经倍频器后再8分频作为时钟信号。
代码如下: (sys.h 代码参照 )
05
|
#define LED0 PAout(4)// PA4
|
08
|
void Gpio_Init(void);//初始化
|
10
|
void SysTick_Delay(u32 time);
|
16
|
Gpio_Init(); //初始化与LED连接的硬件接口
|
18
|
SysTick_Delay(100000);
|
25
|
}while(temp&0x01&&!(temp&(1<<16))); //查询COUNTFLAG标志位,等待时间到达
|
31
|
void SysTick_Delay(u32 us)
|
34
|
u8 us_radix=72/8;//us延时倍乘数 SYSTICk的时钟固定为HCLK时钟的1/8,这里使用系统时钟72MHz
|
35
|
SysTick->CTRL&=0xfffffffb;//bit2清空,选择外部时钟 HCLK/8
|
36
|
SysTick->LOAD=us*us_radix; //时间加载
|
37
|
SysTick->VAL=0x00; //清空计数器
|
38
|
SysTick->CTRL=0x01; //开始倒数
|
40
|
//SysTick->CTRL=0x00; //关闭计数器
|
41
|
//SysTick->VAL =0X00; //清空计数器
|
47
|
RCC->APB2ENR|=1<<2; //使能PORTA时钟
|
49
|
GPIOA->CRL&=0XFFF0FFFF;
|
50
|
GPIOA->CRL|=0X00030000;//PA4 推挽输出
|
51
|
GPIOA->ODR|=1<<4; //PA4 输出高
|
库函数操作
在旧版本的库函数中,有较多的可配置内容。但是在固件库V3.5中,对Systick寄存器的只有一个函数:
SysTick_Config(uint32_t ticks); //注意这是一个24位计数器,超出24位则返回配置错误,返回1
该函数设置了自动重载入计数器(LOAD)的值,SysTick IRQ的优先级,复位了计数器(VAL)的值,开始计数并打开SysTick IRQ中断。SysTick时钟默认使用系统时钟(72MHz)。
在标准外设库中移除了SysTick的驱动,因此用户必须调用CMSIS定义的函数。 驱动已经包含在了Cmsis文件夹中;
但是查看源代码可以知道,在标准外设库(Libraries/src)中有一个misc.c文件,其中提供了一个修改SysTick默认时钟的函数:
02
|
* @brief Configures the SysTick clock source.
|
03
|
* @param SysTick_CLKSource: specifies the SysTick clock source.
|
04
|
* This parameter can be one of the following values:
|
05
|
* @arg SysTick_CLKSource_HCLK_Div8: AHB clock divided by 8 selected as SysTick clock source.
|
06
|
* @arg SysTick_CLKSource_HCLK: AHB clock selected as SysTick clock source.
|
09
|
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
|
11
|
/* Check the parameters */
|
12
|
assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));
|
13
|
if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
|
15
|
SysTick->CTRL |= SysTick_CLKSource_HCLK;
|
19
|
SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
|
可以选择systick 的时钟是否是HCLK(AHB)时钟 或者是HCLK的八分频时钟。
库函数操作代码如下:
main.c:
01
|
#include "stm32f10x.h"
|
03
|
void RCC_Configuration(void);
|
04
|
void GPIO_Configuration(void);
|
12
|
if(SysTick_Config(1*7200000)) //配置错误返回1,max 16777216 默认72Mhz 时钟 ,100ms延时
|
14
|
GPIO_SetBits(GPIOA , GPIO_Pin_4); //错误处理
|
22
|
void GPIO_Configuration(void)
|
24
|
GPIO_InitTypeDef GPIO_InitStructure;
|
26
|
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5;
|
27
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
28
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
29
|
GPIO_Init(GPIOA , &GPIO_InitStructure);
|
33
|
void RCC_Configuration(void)
|
35
|
/* 定义枚举类型变量 HSEStartUpStatus */
|
36
|
ErrorStatus HSEStartUpStatus;
|
41
|
RCC_HSEConfig(RCC_HSE_ON);
|
43
|
HSEStartUpStatus = RCC_WaitForHSEStartUp();
|
44
|
/* 判断HSE起是否振成功,是则进入if()内部 */
|
45
|
if(HSEStartUpStatus == SUCCESS)
|
47
|
/* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */
|
48
|
RCC_HCLKConfig(RCC_SYSCLK_Div1);
|
49
|
/* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */
|
50
|
RCC_PCLK2Config(RCC_HCLK_Div1);
|
51
|
/* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */
|
52
|
RCC_PCLK1Config(RCC_HCLK_Div2);
|
54
|
//FLASH_SetLatency(FLASH_Latency_2);
|
56
|
// FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
|
57
|
/* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */
|
58
|
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
|
62
|
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
|
64
|
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
|
65
|
/* 等待PLL成为SYSCLK时钟源 */
|
66
|
while(RCC_GetSYSCLKSource() != 0x08);
|
68
|
/* 打开APB2总线上的GPIOA时钟*/
|
69
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
|
stm3210x_it.c //中断处理函数
1
|
#include "stm32f10x_it.h"
|
3
|
void SysTick_Handler(void)
|
5
|
GPIO_WriteBit(GPIOA , GPIO_Pin_5,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5))); //翻转GPIO_Pin_5的电平
|
}
阅读(1507) | 评论(0) | 转发(0) |