NVIC配置说明及例子代码汉化注释.docx
《NVIC配置说明及例子代码汉化注释.docx》由会员分享,可在线阅读,更多相关《NVIC配置说明及例子代码汉化注释.docx(35页珍藏版)》请在冰豆网上搜索。
NVIC配置说明及例子代码汉化注释
STM32中Cortex-M3寄存器说明-NVIC寄存器组、系统控制SCB寄存器组、嘀嗒定时...
在STM32中用到了Cortex-M3定义的三组寄存器,有关这三组寄存器的说明不在STM32的技术手册中,需要参考ARM公司发布的Cortex-M3TechnicalReferenceManual(r2p0)。
在STM32的固件库中定义了三个结构体与这三个寄存器组相对应,这三个结构体与ARM手册中寄存器的对应关系如下:
一、NVIC寄存器组
STM32的固件库中有如下定义:
typedefstruct
{
vu32ISER[2];
u32RESERVED0[30];
vu32ICER[2];
u32RSERVED1[30];
vu32ISPR[2];
u32RESERVED2[30];
vu32ICPR[2];
u32RESERVED3[30];
vu32IABR[2];
u32RESERVED4[62];
vu32IPR[11];
}NVIC_TypeDef;
它们对应ARM手册中的名称为
ISER=InterruptSet-EnableRegisters
ICER=InterruptClear-EnableRegisters
ISPR=InterruptSet-PendingRegister
ICPR=InterruptClear-PendingRegister
IABR=ActiveBitRegister
IPR=InterruptPriorityRegisters
每个寄存器有240位,以InterruptSet-EnableRegisters说明,ISER[0]对应中断源0~31,ISER[1]对应中断源32~63,STM32只有60个中断源,所以没有ISER[2:
7]。
参考STM32技术参考手册中的中断向量表,中断源的位置为:
位置0-WWDG=WindowWatchdoginterrupt
位置1-PVD=PVDthroughEXTILinedetectioninterrupt
位置2-TAMPER=Tamperinterrupt
......
位置58-DMA2_Channel3=DMA2Channel3globalinterrupt
位置59-DMA2_Channel4_5=DMA2Channel4andDMA2Channel5globalinterrupts
二、系统控制寄存器组
STM32的固件库中有如下定义:
typedefstruct
{
vuc32CPUID;
vu32ICSR;
vu32VTOR;
vu32AIRCR;
vu32SCR;
vu32CCR;
vu32SHPR[3];
vu32SHCSR;
vu32CFSR;
vu32HFSR;
vu32DFSR;
vu32MMFAR;
vu32BFAR;
vu32AFSR;
}SCB_TypeDef;/*SystemControlBlockStructure*/
它们对应ARM手册中的名称为
CPUID=CPUIDBaseRegister
ICSR=InterruptControlStateRegister
VTOR=VectorTableOffsetRegister
AIRCR=ApplicationInterrupt/ResetControlRegister
SCR=SystemControlRegister
CCR=ConfigurationControlRegister
SHPR=SystemHandlersPriorityRegister
SHCSR=SystemHandlerControlandStateRegister
CFSR=ConfigurableFaultStatusRegisters
HFSR=HardFaultStatusRegister
DFSR=DebugFaultStatusRegister
MMFAR=MemManageAddressRegister
BFAR=BusFaultAddressRegister
AFSR=AuxiliaryFaultStatusRegister
三、系统时钟寄存器组
STM32的固件库中有如下定义:
typedefstruct
{
vu32CTRL;
vu32LOAD;
vu32VAL;
vuc32CALIB;
}SysTick_TypeDef;
它们对应ARM手册中的名称为
CTRL=SysTickControlandStatusRegister
LOAD=SysTickReloadValueRegister
VAL=SysTickCurrentValueRegister
CALIB=SysTickCalibrationValueRegister
----------------------------------------------------------------------------------------------------------------------
SYSTICK
我不得不说意法半导体确实有点风骚!
甚至有点变态。
我对ST文档STM32F10XXX参考手册的编辑水平真是不敢恭维。
手册中好多说明都是含糊不清,甚至将好多对初学者来说很重要的地方都一笔带过,让人着实摸不着头脑。
比如前面我说过的关于NVIC嵌套向量中断控制器的介绍,这部分我认为是非常重要的,但当你看完他这部分介绍,你根本不会设置中断服务程序,他有哪些寄存器都不知道,更别说去设置了,NVIC的详细介绍是在Cotex-M3中有详细的介绍,不多说。
今天我们说的是systick定时器。
systick定时器和我上面说的情况一样,在手册中根本没有介绍。
我费了九牛二虎之力才在一个犄角格拉里找到systick定时器的英文版的说明。
在Cotex-M3有介绍,为什么要找STM32的介绍,是因为功能设置上还有点区别。
首先看一下systick定时器的作用,下面是Cotex-M3里的一段话:
SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:
15)。
在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。
例如,为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。
因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。
Cortex‐M3处理器内部包含了一个简单的定时器。
因为所有的CM3芯片都带有这个定时器,软件在不同CM3器件间的移植工作得以化简。
该定时器的时钟源可以是内部时钟(FCLK,CM3上的自由运行时钟),或者是外部时钟(CM3处理器上的STCLK信号)。
不过,STCLK的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同,你需要检视芯片的器件手册来决定选择什么作为时钟源。
(知道我为什么找ST关于systick的说明了吧)。
下面介绍STM32中的systick,Systick部分内容属于NVIC控制部分,一共有4个寄存器,名称和地址分别是:
STK_CSR, 0xE000E010 -- 控制寄存器
STK_LOAD, 0xE000E014 -- 重载寄存器
STK_VAL, 0xE000E018 -- 当前值寄存器
STK_CALRB, 0xE000E01C -- 校准值寄存器
首先看STK_CSR控制寄存器:
寄存器内有4个位t具有意义
第0位:
ENABLE,Systick使能位 (0:
关闭Systick功能;1:
开启Systick功能)
第1位:
TICKINT,Systick中断使能位 (0:
关闭Systick中断;1:
开启Systick中断)
第2位:
CLKSOURCE,Systick时钟源选择 (0:
使用HCLK/8作为Systick时钟;1:
使用HCLK作为Systick时钟)
第3位:
COUNTFLAG,Systick计数比较标志,如果在上次读取本寄存器后,SysTick已经数到了0,则该位为1。
如果读取该位,该位将自动清零
STK_LOAD 重载寄存器:
Systick是一个递减的定时器,当定时器递减至0时,重载寄存器中的值就会被重装载,继续开始递减。
STK_LOAD 重载寄存器是个24位的寄存器最大计数0xFFFFFF。
STK_VAL当前值寄存器:
也是个24位的寄存器,读取时返回当前倒计数的值,写它则使之清零,同时还会清除在SysTick控制及状态寄存器中的COUNTFLAG标志。
STK_CALRB 校准值寄存器:
这个寄存器好像目前的水平我还用不到,大体意思明白点,把英文说明放这吧:
位31NOREF:
1=没有外部参考时钟(STCLK不可用)0=外部参考时钟可用
位30SKEW:
1=校准值不是准确的1ms0=校准值是准确的1ms
位[23:
0]:
Calibrationvalue
IndicatesthecalibrationvaluewhentheSysTickcounterrunsonHCLKmax/8asexternalclock.Thevalueisproductdependent,pleaserefertotheProductReferenceManual,SysTickCalibrationValuesection.WhenHCLKisprogrammedatthemaximumfrequency,theSysTickperiodis1ms.Ifcalibrationinformationisnotknown,calculatethecalibrationvaluerequiredfromthefrequencyoftheprocessorclockorexternalclock.
SysTick定时器除了能服务于操作系统之外,还能用于其它目的:
如作为一个闹铃,用于测量时间等。
要注意的是,当处理器在调试期间被喊停(halt)时,则SysTick定时器亦将暂停运作。
下面我们就应用SysTick定时器来裸奔,把它作为一个定时器来用,还是老一套,在寄存器头文件中添加定义寄存器:
//*****************************************************************
//* SystemTick-Register
//*******************************************************************
#defineSYSTICK_TENMS (*((volatileunsignedlong*)0xE000E01C))
#defineSYSTICK_CURRENT (*((volatileunsignedlong*)0xE000E018))
#defineSYSTICK_RELOAD (*((volatileunsignedlong*)0xE000E014))
#defineSYSTICK_CSR (*((volatileunsignedlong*)0xE000E010))
配置systick寄存器:
voidSysTick_Configuration(void)
{
SYSTICK_CURRENT=0;//当前值寄存器
SYSTICK_RELOAD=20000;//重装载寄存器,系统时钟20M中断一次1mS
SYSTICK_CSR|=0x06;//HCLK作为Systick时钟,Systick中断使能位
}
中断处理:
voidSysTick_Handler(void)//中断函数
{
externunsignedlongTimingDelay;//延时时间,注意定义为全局变量
SYSTICK_CURRENT=0;
if(TimingDelay!
=0x00)
TimingDelay--;
}
利用systick的延时函数:
unsignedlongTimingDelay; //延时时间,注意定义为全局变量
voidDelay(unsignedlongnTime) //延时函数
{
SYSTICK_CSR|=0x07; //使能SysTick计数器
TimingDelay=nTime;//读取延时时间
while(TimingDelay!
=0);//判断延时是否结束
SYSTICK_CSR|=0x06;//关闭SysTick计数器
}
intmain()
{
SystemInit0(); //系统(时钟)初始化
stm32_GpioSetup();//GPIO初始化
SysTick_Configuration();//配置systick定时器
while
(1)
{
GPIO_PORTB_ODR|=(1<<5);
Delay(1000);//1S
GPIO_PORTB_ODR&=~(1<<5);
Delay(1000);//1S
}
}
完成!
Delay(1000);实现了1S的精确延时,利用Delay(unsignedlongnTime);配合systick定时器可以实现任意时间的精确延时,当然通过定时器TIMx也是可以这样做的,我只是用它来说明systick定时器的用法
----------------------------------------------------------------------------------------------------------------------
STM32入门教程系统时钟SysTick
(一)背景介绍
在传统的嵌入式系统软件按中通常实现Delay(N)函数的方法为:
for(i=0;i<=x;i++);
x---对应于对应于N毫秒的循环值
对于STM32系列微处理器来说,执行一条指令只有几十个ns,进行for循环时,要实现N毫秒的x值非常大,而且由于系统频率的宽广,很难计算出延时N毫秒的精确值。
针对STM32微处理器,需要重新设计一个新的方法去实现该功能,以实现在程序中使用Delay(N)。
(二)STM32SysTick介绍
Cortex-M3的内核中包含一个SysTick时钟。
SysTick为一个24位递减计数器,SysTick设定初值并使能后,每经过1个系统时钟周期,计数值就减1。
计数到0时,SysTick计数器自动重装初值并继续计数,同时内部的COUNTFLAG标志会置位,触发中断(如果中断使能情况下)。
在STM32的应用中,使用Cortex-M3内核的SysTick作为定时时钟,设定每一毫秒产生一次中断,在中断处理函数里对N减一,在Delay(N)函数中循环检测N是否为0,不为0则进行循环等待;若为0则关闭SysTick时钟,退出函数。
注:
全局变量TimingDelay,必须定义为volatile类型,延迟时间将不随系统时钟频率改变。
(三)STSysTick库文件
使用ST的函数库使用systick的方法
1、调用SysTick_CounterCmd() --失能SysTick计数器
2、调用SysTick_ITConfig() --失能SysTick中断
3、调用SysTick_CLKSourceConfig() --设置SysTick时钟源。
4、调用SysTick_SetReload() --设置SysTick重装载值。
5、调用SysTick_ITConfig() --使能SysTick中断
6、调用SysTick_CounterCmd() --开启SysTick计数器
(四)SystemTick工程实战
外部晶振为8MHz,9倍频,系统时钟为72MHz,SysTick的最高频率为9MHz(最大为HCLK/8),在这个条件下,把SysTick效验值设置成9000,将SysTick时钟设置为9MHz,就能够产生1ms的时间基值,即SysTick产生1ms的中断。
/*Configurethesystemclocks*/
RCC_Configuration();
SysTick_Configuration();
第一步:
配置RCC寄存器和SysTick寄存器
RCC_Configuration:
配置RCC寄存器
voidRCC_Configuration(void)
{
/*RCCsystemreset(fordebugpurpose)*/
RCC_DeInit();
/*EnableHSE*/
RCC_HSEConfig(RCC_HSE_ON);
/*WaittillHSEisready*/
HSEStartUpStatus=RCC_WaitForHSEStartUp();
if(HSEStartUpStatus==SUCCESS)
{
/*HCLK=SYSCLK*/
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/*PCLK2=HCLK*/
RCC_PCLK2Config(RCC_HCLK_Div1);
/*PCLK1=HCLK/2*/
RCC_PCLK1Config(RCC_HCLK_Div2);
/*Flash2waitstate*/
FLASH_SetLatency(FLASH_Latency_2);
/*EnablePrefetchBuffer*/
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/*PLLCLK=8MHz*9=72MHz*/
RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);
/*EnablePLL*/
RCC_PLLCmd(ENABLE);
/*WaittillPLLisready*/
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET)
{
}
/*SelectPLLassystemclocksource*/
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/*WaittillPLLisusedassystemclocksource*/
while(RCC_GetSYSCLKSource()!
=0x08)
{
}
}
/*EnableGPIOAandAFIOclocks*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|
RCC_APB2Periph_AFIO,ENABLE);
}
SysTick_Configuration:
配置SysTick
voidSysTick_Configuration(void)
{
/*SelectAHBclock(HCLK)asSysTickclocksource*/
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
/*SetSysTickPriorityto3*/
NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick,3,0);
/*SysTickinterrupteach1mswithHCLKequalto72MHz*/
SysTick_SetReload(72000);
/*EnabletheSysTickInterrupt*/
SysTick_ITConfig(ENABLE);
}
第二步:
配置SysTick中断函数
这里我们定义了一个TestSig全局变量,用于我们使用Keil软件自带的逻辑分析仪来分析.
volatilevu32TimingDelay=0;
vu8TestSig=0;
voidSysTickHandler(void)
{
TimingDelay--;
if(TimingDelay%2)
{
TestSig=1;
}
else
{
TestSig=0;
}
}
第三步:
编写Delay延时函数