关于LED的寄存器配置,比较简单,在此就不在简述。实现systick的定时或者定时中断,首先要配置时钟源,systick是挂在AHB总线上的
寄存器配置主要用到STK_CTRL和STK_VAL,如图
配置时钟来源代码:
uint8_t SYSTEM_SetClock(uint8_t freq)
{
uint32_t rccCrHserdy = 0;
uint32_t faultTime = 0, RCC_CFGR_PLL;
/* 选择倍频系数 */
switch(freq)
{
case(32):
RCC_CFGR_PLL = RCC_CFGR_PLLMULL4;
break;
case(40):
RCC_CFGR_PLL = RCC_CFGR_PLLMULL5;
break;
case(48):
RCC_CFGR_PLL = RCC_CFGR_PLLMULL6;
break;
case(56):
RCC_CFGR_PLL = RCC_CFGR_PLLMULL7;
break;
case(64):
RCC_CFGR_PLL = RCC_CFGR_PLLMULL8;
break;
case(72):
RCC_CFGR_PLL = RCC_CFGR_PLLMULL9;
break;
default:
return 0xFF;
}
/*复位RCC_CR寄存器*/
RCC_Reset();
/*开启外部时钟*/
RCC->CR &= (~RCC_CR_HSEON);
RCC->CR |= RCC_CR_HSEON;//设置第16位
/*检测外部时钟开启成功*/
do
{
rccCrHserdy = RCC->CR & RCC_CR_HSERDY;//检测第17位是否为1
faultTime++;//检测时间
}
while ((faultTime<0x0FFFFFFF) && (rccCrHserdy==0));
/* 如果外部时钟开启成功*/
if ((RCC->CR & RCC_CR_HSERDY) != 0)
{
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE;
/* Flash 2 wait state */
FLASH->ACR &= (~(uint32_t)FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t) FLASH_ACR_LATENCY_2;
/*AHB(0000)、APB2(000)不分频(即PLL输出时钟)*/
/*APB1(100)要2分频(因最大只能36MHZ)*/
RCC->CFGR &= (~(RCC_CFGR_HPRE | RCC_CFGR_PPRE1 | RCC_CFGR_PPRE2));
RCC->CFGR |= (RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE1_DIV2
| RCC_CFGR_PPRE2_DIV1);
/*设置HSE为输入时钟,同事HSE不分频*/
RCC->CFGR &= (~(uint32_t)(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE ));
RCC->CFGR |= (RCC_CFGR_PLLSRC);
/*设置PLL倍频系数为9倍*/
RCC->CFGR &= (~RCC_CFGR_PLLMULL);//先清除原来的设置
RCC->CFGR |= (RCC_CFGR_PLL);//设置倍频系数
/*打开PLL使能*/
RCC->CR |= RCC_CR_PLLON;
/*等待开启PLL开启成功*/
while ((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/*将PLL作为SYSCLK的时候来源*/
RCC->CFGR &= (~RCC_CFGR_SW);//先清除先前的设置
RCC->CFGR |= RCC_CFGR_SW_PLL;
/*等待PLL作为SYSCLK时钟启动成功*/
while ((RCC->CFGR & RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL)
{
}
}/*end of if((RCC->CR & RCC_CR_HSERDY) != 0)*/
/*如果外部时钟开启失败*/
else
{
RCC_Reset();
return 0xFF;
}
return 0;
}
这段代码,跟配置系统时钟基本一样,可以移植。
配置systick代码:
void SYSTICK_Config(void)
{
/* 时钟是72MHZ时,所以计数72次(最大为16777215),就是1us */
/* 主要是为了设置时钟 */
if(SysTick_Config(72) == 0)//开启成功返回0
{
/* 调用这个设置函数的时候默认是直接打开计数器的,现在把它关掉。 */
/* 关闭中断 */
SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk);
}
}
重要的是SysTick_Config(72)
而SysTick_Config():
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
return (1UL); /* Reload value impossible */
}
SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
SysTick->VAL = 0UL; /* 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 (0UL); /* Function successful */
}
实现的功能:判断载入值是否大于2的24次方,如果满足条件,就装载,之后给systick中断分组,设置优先级,这里设置的是最低优先级,这个优先级设置挺有意思,可以深入研究下。
最后使能定时器。
延时函数:
void SYSTICK_Delay1s(uint16_t s)
{
uint32_t countValue;
s *= 5;
SysTick->LOAD = 72000 * 200 - 1; //设置重装数值, 72MHZ时延时200ms
SysTick->VAL = 0; //清零计数器
SysTick->CTRL |= ((uint32_t)0x01 << 1); // 使能中断
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //打开计时器
do
{
countValue = SysTick->CTRL;
if(countValue & (1 << 16)) //当到200ms是计数减1
{
s--;
}
}
while(s); //等待时间到来
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数器
}
看注释就可以。
主函数:
#include <stm32f10x.h>
#include "system.h"
#include "led.h"
int F=1;
/****************************************************************************
* Function Name : main
* Description : Main program.
* Input : None
* Output : None
* Return : None
****************************************************************************/
void SysTick_Handler(void)
{
uint8_t ledState=0x10;
static uint16_t Time_Count = 0;
if(++Time_Count>=5)
{
if(F==1)
{
ledState = 0x10;
}
else if(F==-1)
{
ledState=0x8;
}
LED_SetState(ledState);
if(F==-1)
{
F=1;
}
else if(F==1)
{
F=-1;
}
Time_Count=0;
}
}
int main(void)
{
uint8_t ledState = 0xE0;
/* 初始化 */
SYSTEM_SetClock(72); //设置时钟,给AHB赋值时钟来源
LED_Config();
SYSTICK_Config();
while(1)
{
/* 选择 */
ledState =0xF8;
LED_SetState(ledState);
SYSTICK_Delay1s(3); //利用系统滴答定时器
ledState =0x1F;
LED_SetState(ledState);
SYSTICK_Delay1s(3); //利用系统滴答定时器延时
}
}
SysTick_Handler是Systick中断服务函数,定义在启动文件中,我的是在STM32F10x.s中
中断内容自己编写。
实现效果:
STM32