stm32上最方便的定时器Systick[操作寄存器+库函数]

发布者:czc天天最新更新时间:2017-02-06 来源: eefocus关键字:stm32  定时器  Systick 手机看文章 扫描二维码
随时随地手机看文章

Systick 是stm32上一个用处很多的内设,所有基于arm-cortex m3 的芯片都有这个定时器,所以考虑到平台的可移植性时,可以多使用Systick。

 

Systick 是一个24位数据宽度的倒计数定时器,其计数范围只能到 1677215(2^24),当计数到0时会从RELOAD寄存器 中自动重装定时初值。只要不把SysTick的控制及状态寄存器中的使能位清除,计数器就不会停止。

 

SysTick 可以产生中断、设置中断优先级,有专门的中断处理函数SysTick_Handler().库函数作为ST公司自己的推出的框架, 在中断这方面做了更为细致的处理。

库函数包含的头文件是 stm32f10x.h  这个文件中 列出了完整的stm32中断向量表(截取部分):

/******  Cortex-M3 Processor Exceptions Numbers ***************************************************/
  NonMaskableInt_IRQn         = -14,    /*!< 2 Non Maskable Interrupt                             */
  MemoryManagement_IRQn       = -12,    /*!< 4 Cortex-M3 Memory Management Interrupt              */
  BusFault_IRQn               = -11,    /*!< 5 Cortex-M3 Bus Fault Interrupt                      */
  UsageFault_IRQn             = -10,    /*!< 6 Cortex-M3 Usage Fault Interrupt                    */
  SVCall_IRQn                 = -5,     /*!< 11 Cortex-M3 SV Call Interrupt                       */
  DebugMonitor_IRQn           = -4,     /*!< 12 Cortex-M3 Debug Monitor Interrupt                 */
  PendSV_IRQn                 = -2,     /*!< 14 Cortex-M3 Pend SV Interrupt                       */
  SysTick_IRQn                = -1,     /*!< 15 Cortex-M3 System Tick Interrupt                   */

/******  STM32 specific Interrupt Numbers *********************************************************/
  WWDG_IRQn                   = 0,      /*!< Window WatchDog Interrupt                            */
  PVD_IRQn                    = 1,      /*!< PVD through EXTI Line detection Interrupt            */
  TAMPER_IRQn                 = 2,      /*!< Tamper Interrupt                                     */
  RTC_IRQn                    = 3,      /*!< RTC global Interrupt                                 */
  FLASH_IRQn                  = 4,      /*!< FLASH global Interrupt                               */
  RCC_IRQn                    = 5,      /*!< RCC global Interrupt                                 */
  EXTI0_IRQn                  = 6,      /*!< EXTI Line0 Interrupt                                 */
  EXTI1_IRQn                  = 7,      /*!< EXTI Line1 Interrupt                                 */
  EXTI2_IRQn                  = 8,      /*!< EXTI Line2 Interrupt                                 */
  EXTI3_IRQn                  = 9,      /*!< EXTI Line3 Interrupt                                 */
  EXTI4_IRQn                  = 10,     /*!< EXTI Line4 Interrupt                                 */
  DMA1_Channel1_IRQn          = 11,     /*!< DMA1 Channel 1 global Interrupt                      */
  DMA1_Channel2_IRQn          = 12,     /*!< DMA1 Channel 2 global Interrupt                      */
  DMA1_Channel3_IRQn          = 13,     /*!< DMA1 Channel 3 global Interrupt                      */
  DMA1_Channel4_IRQn          = 14,     /*!< DMA1 Channel 4 global Interrupt                      */
  DMA1_Channel5_IRQn          = 15,     /*!< DMA1 Channel 5 global Interrupt                      */
  DMA1_Channel6_IRQn          = 16,     /*!< DMA1 Channel 6 global Interrupt                      */
  DMA1_Channel7_IRQn          = 17,     /*!< DMA1 Channel 7 global Interrupt                      */

其中就包含了对系统级中断的处理,有SysTick的中断定义。

在 库函数的Cmsis\core_cm3.h文件中的中断配置函数也区分了系统中断 和 其他中断的区分处理 :

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  */
}

其中 SysTick_Config()函数也在这个文件中:

static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{ 
  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible */
                                                               
  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Cortex-M0 System Interrupts */
  SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */
  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作为一个中断操作。

但是直接操作寄存器,包含的头文件是 stm32f10x_lib.h ,中断向量表在stm32f10x_nvic.h 中(截取部分):

/* IRQ Channels --------------------------------------------------------------*/
#define WWDG_IRQChannel              ((u8)0x00)  /* Window WatchDog Interrupt */
#define PVD_IRQChannel               ((u8)0x01)  /* PVD through EXTI Line detection Interrupt */
#define TAMPER_IRQChannel            ((u8)0x02)  /* Tamper Interrupt */
#define RTC_IRQChannel               ((u8)0x03)  /* RTC global Interrupt */
#define FLASH_IRQChannel             ((u8)0x04)  /* FLASH global Interrupt */
#define RCC_IRQChannel               ((u8)0x05)  /* RCC global Interrupt */
#define EXTI0_IRQChannel             ((u8)0x06)  /* EXTI Line0 Interrupt */
#define EXTI1_IRQChannel             ((u8)0x07)  /* EXTI Line1 Interrupt */
#define EXTI2_IRQChannel             ((u8)0x08)  /* EXTI Line2 Interrupt */
#define EXTI3_IRQChannel             ((u8)0x09)  /* EXTI Line3 Interrupt */
#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.png

systick的时钟来自外部时钟,经倍频器后再8分频作为时钟信号。

 

代码如下:    (sys.h 代码参照 stm32 直接操作寄存器开发环境配置

#include  
#include "system.h"		

//LED  按键端口定义
#define LED0 PAout(4)// PA4


void Gpio_Init(void);//初始化		   

void SysTick_Delay(u32 time);

int main(void)
{	
	u32 temp;			  
	Rcc_Init(9); //系统时钟设置
	Gpio_Init();		  	 //初始化与LED连接的硬件接口

	SysTick_Delay(100000);

	while(1)
	{	
		do
		{
			temp=SysTick->CTRL;
		}while(temp&0x01&&!(temp&(1<<16)));  //查询COUNTFLAG标志位,等待时间到达 
		  
		LED0 = !LED0;
	}
}

void SysTick_Delay(u32 us)
{		
	    	 
	u8 us_radix=72/8;//us延时倍乘数  SYSTICk的时钟固定为HCLK时钟的1/8,这里使用系统时钟72MHz 
	SysTick->CTRL&=0xfffffffb;//bit2清空,选择外部时钟  HCLK/8
	SysTick->LOAD=us*us_radix; //时间加载	  		 
	SysTick->VAL=0x00;        //清空计数器
	SysTick->CTRL=0x01;      //开始倒数  	 
	
	//SysTick->CTRL=0x00;       //关闭计数器
	//SysTick->VAL =0X00;       //清空计数器	
}


void Gpio_Init(void)
{
	RCC->APB2ENR|=1<<2;    //使能PORTA时钟	   	 
	   	 
	GPIOA->CRL&=0XFFF0FFFF; 
	GPIOA->CRL|=0X00030000;//PA4 推挽输出   	 
    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默认时钟的函数:

/**
  * @brief  Configures the SysTick clock source.
  * @param  SysTick_CLKSource: specifies the SysTick clock source.
  *   This parameter can be one of the following values:
  *     @arg SysTick_CLKSource_HCLK_Div8: AHB clock divided by 8 selected as SysTick clock source.
  *     @arg SysTick_CLKSource_HCLK: AHB clock selected as SysTick clock source.
  * @retval None
  */
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
{
  /* Check the parameters */
  assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));
  if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
  {
    SysTick->CTRL |= SysTick_CLKSource_HCLK;
  }
  else
  {
    SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
  }
}

可以选择systick 的时钟是否是HCLK(AHB)时钟 或者是HCLK的八分频时钟。

库函数操作代码如下:



main.c:

#include "stm32f10x.h"

void RCC_Configuration(void);
void GPIO_Configuration(void);

int main(void)
{

  	RCC_Configuration();
  	GPIO_Configuration();

	if(SysTick_Config(1*7200000))	 //配置错误返回1,max 16777216   默认72Mhz 时钟 ,100ms延时
	{							
		GPIO_SetBits(GPIOA , GPIO_Pin_4); 	//错误处理 								
	}
	while(1);
	
}


  
void GPIO_Configuration(void)
{
  	GPIO_InitTypeDef GPIO_InitStructure;

  	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5;
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;			
  	GPIO_Init(GPIOA , &GPIO_InitStructure); 
}


void RCC_Configuration(void)
{
	/* 定义枚举类型变量 HSEStartUpStatus */
	ErrorStatus HSEStartUpStatus;

  	/* 复位系统时钟设置*/
  	RCC_DeInit();
  	/* 开启HSE*/
  	RCC_HSEConfig(RCC_HSE_ON);
  	/* 等待HSE起振并稳定*/
  	HSEStartUpStatus = RCC_WaitForHSEStartUp();
	/* 判断HSE起是否振成功,是则进入if()内部 */
  	if(HSEStartUpStatus == SUCCESS)
  	{
    	/* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */
    	RCC_HCLKConfig(RCC_SYSCLK_Div1); 
    	/* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */
    	RCC_PCLK2Config(RCC_HCLK_Div1); 
    	/* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */
    	RCC_PCLK1Config(RCC_HCLK_Div2);
    	/* 设置FLASH延时周期数为2 */
    	//FLASH_SetLatency(FLASH_Latency_2);
    	/* 使能FLASH预取缓存 */
    	//  FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    	/* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */
    	RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
    	/* 使能PLL */ 
    	RCC_PLLCmd(ENABLE);
    	/* 等待PLL输出稳定 */
    	while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
    	/* 选择SYSCLK时钟源为PLL */
    	RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    	/* 等待PLL成为SYSCLK时钟源 */
    	while(RCC_GetSYSCLKSource() != 0x08);
  	} 
  	/* 打开APB2总线上的GPIOA时钟*/
  	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

	
}

 stm3210x_it.c  //中断处理函数


#include "stm32f10x_it.h"

void SysTick_Handler(void)
{
	GPIO_WriteBit(GPIOA , GPIO_Pin_5,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5)));	//翻转GPIO_Pin_5的电平

}   


关键字:stm32  定时器  Systick 引用地址:stm32上最方便的定时器Systick[操作寄存器+库函数]

上一篇:stm32的按键扫描[操作寄存器+库函数]
下一篇:用stm32点个灯[操作寄存器+库函数]

推荐阅读最新更新时间:2024-03-16 15:32

STM32跑ucosII系统之信号和消息邮箱介绍
写在前面: “信号”可以单纯的理解为一个信号量(trig触发用),在任务1中传递一个信号给任务2,那么,任务2接收到这个信号,会往下执行。 “消息邮箱”也可以理解为一个信号量,只不过这个消息可以携带内容:比如变量的值。 一、事件——任务之间通信的中间环节 任务间的同步依赖于任务间的通信。 在 UCOSII 中,是使用信号量、邮箱(消息邮箱)和消息队列这些被称作事件的中间环节来实现任务之间的通信的 . 发送事件 请求事件 任务1 ------------ 事件 ------------ 任务2 任务 1 是发信方,任务 2 是收信方。任务 1 负责把信息发送到事件上,这项 操作叫做发送事件。任
[单片机]
stm32专题十九:FatFs文件系统简介
在上一篇博客中,是使用SPI-FLASH存储整数、小数和字符串等,通过调用SPI_FLASH_BufferWrite函数,把数组内容写入到SPI Flash芯片的指定地址上,在需要的时候从该地址把数据读取出来,再对读出来的数据以ASCII码的格式进行解读。 但是,这样直接存储数据会带来极大的不便,如难以记录有效数据的位置,难以确定存储介质的剩余空间,以及应以何种格式来解读数据。就如同一个巨大的图书馆无人管理,杂乱无章地存放着各种书籍,难以查找所需的文档。对于SPI Flash芯片或者SD卡之类的大容量设备,我们需要一种高效的方式来管理它的存储内容。 这些管理方式即为文件系统,它是为了存储和管理数据,而在存储介质建立的一种组
[单片机]
<font color='red'>stm32</font>专题十九:FatFs文件系统简介
MSP430单片机定时器B中断实验
本程序是基于MSP430单片机内部定时器B中断实验,功能:用定时器B来精确流水灯时间间隔. #include MSP430F149.h #define uchar unsigned char #define uint unsigned int uchar LedData=0x80; uchar num=50;//中断50次让LED右移一位 //定时器A初始化 void InitTimerB(){ TBCTL=TBSSEL1+ID1+ID0+MC0+TBCLR;//选择1/8SMCLK 增计数 清除TAR TBCCTL0=CCIE;//CCR0中断允许 比较模式 TBCCR0=10000;//时间间隔10ms } //定时器
[单片机]
STM32的USART中断死循环,形成死机。
直接说重点:我用的是 STM32F103 芯片 USART2_IRQHandler 总是中断,程序死循环。 1、出现问题: 原程序的中断处理程序是: void USART2_IRQHandler(void) { u8 key = 0; USART_ClearFlag(USART2,USART_FLAG_TC ); //清除中断标志 if(USART_GetITStatus(USART2,USART_IT_RXNE)!=Bit_RESET)//检查指定的usart是否发生了中断 { key=USART_ReceiveData(USART2); // do something at this; } } 运行结果:程序
[单片机]
51单片机硬件定时器设定的初值问题
网上查了很多解释关于51单片机硬件定时设定的文章,发现说的不是特别透彻,可能大家觉得一些类似基本感念的问题就不用澄清了,所以对于我这样的入门小白理解起来有些障碍,这里我把自己的理解解释的细致多一些,希望能给同道中人一些帮助。 说到定时前需要澄清几个概念:震荡周期,状态周期,机器周期,指令周期。(学习什么知识概念必须掌握清楚,否则就“糊”了!) 震荡周期:(来自百度百科)在单片机系统中,定时器需要借助单片机内部提供的脉冲进行定时,此时,定时的依据是CPU提供的周期性振荡,振荡一次所需的时间称为振荡周期。单片机系统也可以通过外部晶体振荡器(也被称为晶振)提供振荡进行工作。 对于震荡周期的理解:计算机系统中通常需要同时处理多
[单片机]
STM32入门学习之GPIO(STM32F030F4P6基于CooCox IDE)(一)
1、CooCox IDE当前最新版本为V2,不过个人看网上的示例大都是基于旧版本的,个人也试过新版本,发现一些操作还不习惯,在此也还是介绍旧版本1.7.8。 http://www.coocox.org/software/coide.php 2、运行CoIDE,点击菜单栏的Project——New Project,填写项目名称HelloGPIO 3、选择Chip 4、选择ST——STM32F03x——STM32F030F4P6 5、系统将弹出 Repository,这里可直接选择程序需要的库,勾选GPIO,系统将自动勾选RCC、CMSIS BOOT、M0 Cmsis Core等,并直接生成对应 6、打开mai
[单片机]
<font color='red'>STM32</font>入门学习之GPIO(STM32F030F4P6基于CooCox IDE)(一)
STM32内置CRC模块的使用
所有的STM32芯片都内置了一个硬件的CRC计算模块,可以很方便地应用到需要进行通信的程序中,这个CRC计算模块使用常见的、在以太网中使用的计算多项式: X32 + X26 + X23 + X22 + X16 + X12 + X11 + X10 +X8 + X7 + X5 + X4 + X2 + X + 1 写成16进制就是:0x04C11DB7 使用这个内置CRC模块的方法非常简单,既首先复位CRC模块(设置CRC_CR=0x01),这个操作把CRC计算的余数初始化为 0xFFFFFFFF;然后把要计算的数据按每32位分割为一组数据字,并逐个地把这组数据字写入CRC_DR寄存器(既下图中的绿色框),写完所有的数据字后,就可
[单片机]
<font color='red'>STM32</font>内置CRC模块的使用
51单片机与汇编之定时器中断闪烁LED
话不多说,先上程序 ORG 0000h AJMP START ORG 000BH AJMP TIME0 START: MOV 66H,#0 MOV TMOD,#00000001B MOV TH0,#0BBH MOV TL0,#0CCH SETB EA SETB ET0 SETB TR0 AJMP $ TIME0: PUSH ACC PUSH PSW MOV TH0,#0BBH MOV TL0,#0CCH INC 66H MOV A,66H CJNE A,#30,TIME00 CPL P1.0 MOV 66H,#0 TIME00: POP PSW POP ACC RETI END 这段程序的达成的目标是:用定时器产生一个中断,中断内
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved