STM32-(16):Systick 系统时钟

上一篇:STM32-(15):如何用ID号保护自己的劳动成果 下一篇:STM32-(17):SPI与数码管(数码管)

Systick的两大作用:
1、可以产生精确延时(原先的Delay只是盲等)
2、可以提供给操作系统一个单独的心跳(时钟)节拍

通常实现Delay(N)函数的方法为:

for(i = 0; i <= x; i ++);
x…对应于对应于N毫秒的循环值

对于STM32系列微处理器来说,执行一条指令只有几十个 ns,进行for循环时,要实现N毫秒的x值非常大,而且由于系 统频率的宽广,很难计算出延时N毫秒的精确值。针对STM32 微处理器,需要重新设计一个新的方法去实现该功能,以实现在 程序中使用Delay(N)。

Cortex-M3的内核中包含一个SysTick时钟。SysTick为一个24 位递减计数器,SysTick设定初值并使能后,每经过1个系统时钟周期,计数值就减1。计数到0时,SysTick计数器自动重装初值并继续计数,同时内部的COUNTFLAG标志会置位,触发中断(如果中断使能)。

外部晶振为8MHz,9倍频,系统时钟为72MHz,SysTick的最高频率为9MHz (最大为HCLK/8),在这个条件下,把SysTick效验值设置成9000,将SysTick时钟设置为9MHz,就能够产生1ms的时间基值,即SysTick产生1ms的中断。

STM32-(16):Systick 系统时钟_第1张图片
STM32-(16):Systick 系统时钟_第2张图片
STM32-(16):Systick 系统时钟_第3张图片
SysTick->CALIB 不常用,在这里我们也用不到,故不介绍了。

STM32-(16):Systick 系统时钟_第4张图片

初始化设置步骤:

使用ST的函数库使用systick的方法:
1、 调用 SysTick_CounterCmd()失能 SysTick 计数器
2、 调用 SysTick_ITConfig()失能 SysTick 中断
3、 调用 SysTick_CLKSouceConfig()设置 SysTick 时钟源。
4、 调用 SysTick_SetReload()设置 SysTick 重装载值。
5、 调用 SysTickJTConfig ( ) 使 能 SysTick 中断
6、 调用 SysTick_CounterCmd()开启 SysTick 计数器

//示例
void SysTick_Config(void)
{
	/* Disable SysTick Counter */
	SysTick_CounterCmd(SysTick_Counter_Disable);
	/* Disable the SysTick Interrupt */
	SysTick_ITConfig(DISABLE);
	/* Configure HCLK clock as SysTick clock source */
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);  //72MHz/8 = 9MHz
	/* SysTick interrupt each 1000 Hz with HCLK equal to 72MHz */
	SysTick_SetReload (9000);
	/* Enable the SysTick Interrupt */
	SysTick_ITConfig(ENABLE);
	/* Enable SysTick Counter */
	SysTick_CounterCmd(SysTick_Counter_Enable);
}

自己动手编写一个DelayMs的程序,实现精确延时。

void Delay_MS(u16dly)
{
	Delay = dly;
	while( Delay);//这里的Delay的值受下方函数Delay值的影响
}

extern vu16 Delay;
void SysTickHandler(void) //中断服务程序
{
	Delay--;	//每次COUNTFLAG标志置位,都会触发中断
}

以上例子的特点:①精准;②仍然是忙等(while)

那如何既精准又能去忙别的呢?

实验:利用Systick完成对分秒计时的时钟,通过上位机观察这个时钟的变化

main.c

/*Include---------------------------*/
#include"stm32f10x_lib.h"		//包含所有的头文件
#include

//----------------函数声明--------------------
void Delay_MS(u16 dly);
void RCC_Configuration(void);
void GPIO_Configuration(void);
void USART3_Configuration(void);

u8  tab[]="\nHello! everyone,welcome to class!";

void SYSTICK_Configuration(void)
{
	SysTick_CounterCmd(SysTick_Counter_Disable);		//失能 SysTick 计数器
	SysTick_ITConfig(DISABLE);		//失能 SysTick 中断
	//设置 SysTick 时钟源      
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);  //9Mhz  系统时钟除以8
    //设置 SysTick 重装载值
	SysTick_SetReload(9000*1000);   //9000/9Mhz  再另外乘以1000,得到的单位时间为1s
	//SysTick_ITConfig(ENABLE);  //这里不使用
    SysTick_CounterCmd(SysTick_Counter_Enable);		//开启 SysTick 计数器
}
/*******************************************************************************
* Function Name  : main
* Description    : Main program.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/ 
int main(void)
{
	#ifdef DEBUG
	debug();
	#endif
	
	u8 sec,min;
	//u16  data;

	//------------初始化------------
	RCC_Configuration();
	GPIO_Configuration();
	USART3_Configuration();
	SYSTICK_Configuration();

	printf("\n The Time is: ");	
	sec = 30;
	min = 1;		//从一分三十秒开始计数,实现当秒数大于60,分数进位
	//------------将秒和分的数据上传到上位机------------
	while(1)
	{ 
		FlagStatus Status;
		Status = SysTick_GetFlagStatus(SysTick_FLAG_COUNT); 
		if(Status == RESET)  //标志位清零不做操作
		{ 
		 
		} 
		else 		//标志位置1,秒数增加
		{ 
		 	sec++;
			if(sec == 60)
			{
				sec = 0;
				min++;
			}
			printf("%d:%d\t",min,sec);
		}
	}	
}

/*******************************************************************************
* Function Name  : Delay_Ms
* Description    : delay 1 ms.
* Input          : dly (ms)
* Output         : None
* Return         : None
*******************************************************************************/
void Delay_MS(u16 dly)
{
	u16 i,j;
	for(i=0;i0;j--);
}

/*******************************************************************************
* Function Name  : RCC_Configuration
* Description    : Configures the different system clocks.
* Input          : None
* Output         : None
* Return         : None
************************************************************ *******************/
void RCC_Configuration(void)
{
	//----------使用外部RC晶振-----------
	RCC_DeInit();			//初始化为缺省值
	RCC_HSEConfig(RCC_HSE_ON);	//使能外部的高速时钟 
	while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);	//等待外部高速时钟使能就绪
	
	FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);	//Enable Prefetch Buffer
	FLASH_SetLatency(FLASH_Latency_2);		//Flash 2 wait state
	
	RCC_HCLKConfig(RCC_SYSCLK_Div1);		//HCLK = SYSCLK
	RCC_PCLK2Config(RCC_HCLK_Div1);			//PCLK2 =  HCLK
	RCC_PCLK1Config(RCC_HCLK_Div2);			//PCLK1 = HCLK/2
	RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);	//PLLCLK 8MHZ * 9 =72MHZ(SYSCLK)
	RCC_PLLCmd(ENABLE);			//Enable PLLCLK

	while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);	//Wait till PLLCLK is ready
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);	//Select PLL as system clock
	while(RCC_GetSYSCLKSource()!=0x08);		//Wait till PLL is used as system clock source
	
	//---------打开相应外设时钟--------------------(在这里,需要打开的都是外设时钟,而Systick属于内核,会自动开启)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO,ENABLE);	//使能APB2外设的GPIOA的时钟		 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
}

/*******************************************************************************
* Function Name  : GPIO_Configuration
* Description    : 初始化GPIO外设
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void GPIO_Configuration(void)
{
	GPIO_InitTypeDef	GPIO_InitStructure;		//声明一个结构体变量

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; 	//选择PC.10(TXD) 和 PC.11
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	 //管脚频率为50MHZ
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	 //输出模式为复用推挽输出
	GPIO_Init(GPIOC,&GPIO_InitStructure);				 //初始化GPIOC寄存器
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; 	//选择PC.10(TXD) 和 PC.11(RXD)
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	 //管脚频率为50MHZ
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	 //输出模式为浮空输入
	GPIO_Init(GPIOC,&GPIO_InitStructure);				 //初始化GPIOA寄存器		
	
	//将USART3的TXD和RXD重映射到PC10和pc11
	GPIO_PinRemapConfig(GPIO_PartialRemap_USART3,ENABLE);		
} 

void USART3_Configuration(void)
{
	USART_InitTypeDef  U3;
	U3.USART_BaudRate =9600;
	U3.USART_WordLength = USART_WordLength_8b;
	U3.USART_StopBits = USART_StopBits_1;
	U3.USART_Parity = USART_Parity_No;
	U3.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;
	U3.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 
	USART_Init(USART3, &U3);

	USART_Cmd(USART3,ENABLE);
}

/*******************************************************************************
* Function Name  : fputc
* Description    : 重定向这个C库(stdio)printf函数  文件流——》串口USART1
* Input          : ch,*f
* Output         : None
* Return         : None
*******************************************************************************/ 

int fputc(int ch,FILE *f)
{
	//ch送给USART1
	USART_SendData(USART3, ch);
	//等待发送完毕
	while(USART_GetFlagStatus(USART3, USART_FLAG_TC)==RESET) ;
	//返回ch
	return(ch);
}

程序运行结果

STM32-(16):Systick 系统时钟_第5张图片
注:下位机(ARM的Coretex芯片)发送到上位机的显示窗口(PC机串口),这个串口工具的输入窗口可以发送数据(图中内容为“源享科技”的地方),就是从上位机发送到下位机。

上一篇:STM32-(15):如何用ID号保护自己的劳动成果 下一篇:STM32-(17):SPI与数码管(数码管)

你可能感兴趣的:(STM32-(16):Systick 系统时钟)