STM32各模块学习笔记.docx
《STM32各模块学习笔记.docx》由会员分享,可在线阅读,更多相关《STM32各模块学习笔记.docx(40页珍藏版)》请在冰豆网上搜索。
STM32各模块学习笔记
STM32中断优先级和开关总中断
一,中断优先级:
STM32(Cortex-M3)中的优先级概念
STM32(Cortex-M3)中有两个优先级的概念——抢占式优先级和响应优先级,有人把响应优先级称作'亚优先级'或'副优先级',每个中断源都需要被指定这两种优先级。
具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套,或者说高抢占式优先级的中断可以嵌套低抢占式优先级的中断。
当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。
如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理哪一个。
既然每个中断源都需要被指定这两种优先级,就需要有相应的寄存器位记录每个中断的优先级;在Cortex-M3中定义了8个比特位用于设置中断源的优先级,这8个比特位可以有8种分配方式,如下:
所有8位用于指定响应优先级
最高1位用于指定抢占式优先级,最低7位用于指定响应优先级
最高2位用于指定抢占式优先级,最低6位用于指定响应优先级
最高3位用于指定抢占式优先级,最低5位用于指定响应优先级
最高4位用于指定抢占式优先级,最低4位用于指定响应优先级
最高5位用于指定抢占式优先级,最低3位用于指定响应优先级
最高6位用于指定抢占式优先级,最低2位用于指定响应优先级
最高7位用于指定抢占式优先级,最低1位用于指定响应优先级
这就是优先级分组的概念。
--------------------------------------------------------------------------------
Cortex-M3允许具有较少中断源时使用较少的寄存器位指定中断源的优先级,因此STM32把指定中断优先级的寄存器位减少到4位,这4个寄存器位的分组方式如下:
第0组:
所有4位用于指定响应优先级
第1组:
最高1位用于指定抢占式优先级,最低3位用于指定响应优先级
第2组:
最高2位用于指定抢占式优先级,最低2位用于指定响应优先级
第3组:
最高3位用于指定抢占式优先级,最低1位用于指定响应优先级
第4组:
所有4位用于指定抢占式优先级
可以通过调用STM32的固件库中的函数NVIC_PriorityGroupConfig()选择使用哪种优先级分组方式,这个函数的参数有下列5种:
NVIC_PriorityGroup_0=>选择第0组
NVIC_PriorityGroup_1=>选择第1组
NVIC_PriorityGroup_2=>选择第2组
NVIC_PriorityGroup_3=>选择第3组
NVIC_PriorityGroup_4=>选择第4组
接下来就是指定中断源的优先级,下面以一个简单的例子说明如何指定中断源的抢占式优先级和响应优先级:
//选择使用优先级分组第1组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//使能EXTI0中断
NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//指定抢占式优先级别1
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;//指定响应优先级别0
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
//使能EXTI9_5中断
NVIC_InitStructure.NVIC_IRQChannel=EXTI9_5_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//指定抢占式优先级别0
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//指定响应优先级别1
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
要注意的几点是:
1)如果指定的抢占式优先级别或响应优先级别超出了选定的优先级分组所限定的范围,将可能得到意想不到的结果;
2)抢占式优先级别相同的中断源之间没有嵌套关系;
3)如果某个中断源被指定为某个抢占式优先级别,又没有其它中断源处于同一个抢占式优先级别,则可以为这个中断源指定任意有效的响应优先级别。
二,开关总中断:
在STM32/Cortex-M3中是通过改变CPU的当前优先级来允许或禁止中断。
PRIMASK位:
只允许NMI和hardfault异常,其他中断/异常都被屏蔽(当前CPU优先级=0)。
FAULTMASK位:
只允许NMI,其他所有中断/异常都被屏蔽(当前CPU优先级=-1)。
在STM32固件库中(stm32f10x_nvic.c和stm32f10x_nvic.h)定义了四个函数操作PRIMASK位和FAULTMASK位,改变CPU的当前优先级,从而达到控制所有中断的目的。
下面两个函数等效于关闭总中断:
voidNVIC_SETPRIMASK(void);
voidNVIC_SETFAULTMASK(void);
下面两个函数等效于开放总中断:
voidNVIC_RESETPRIMASK(void);
voidNVIC_RESETFAULTMASK(void);
上面两组函数要成对使用,不能交叉使用。
例如:
第一种方法:
NVIC_SETPRIMASK();//关闭总中断
NVIC_RESETPRIMASK();//开放总中断
第二种方法:
NVIC_SETFAULTMASK();//关闭总中断
NVIC_RESETFAULTMASK();//开放总中断
常常使用
NVIC_SETPRIMASK();//DisableInterrupts
NVIC_RESETPRIMASK();//EnableInterrupts
STM32时钟系统
STM32资料2009-09-2314:
53阅读72评论0
字号:
大大中中小小
在STM32中,有五个时钟源,为HSI、HSE、LSI、LSE、PLL。
①、HSI是高速内部时钟,RC振荡器,频率为8MHz。
②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。
③、LSI是低速内部时钟,RC振荡器,频率为40kHz。
④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。
⑤、PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。
倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。
图1HSE/LSE时钟源
其中40kHz的LSI供独立看门狗IWDG使用,另外它还可以被选择为实时时钟RTC的时钟源。
另外,实时时钟RTC的时钟源还可以选择LSE,或者是HSE的128分频。
RTC的时钟源通过RTCSEL[1:
0]来选择。
STM32中有一个全速功能的USB模块,其串行接口引擎需要一个频率为48MHz的时钟源。
该时钟源只能从PLL输出端获取,可以选择为1.5分频或者1分频,也就是,当需要使用USB模块时,PLL必须使能,并且时钟频率配置为48MHz或72MHz。
另外,STM32还可以选择一个时钟信号输出到MCO脚(PA8)上,可以选择为PLL输出的2分频、HSI、HSE、或者系统时钟。
系统时钟SYSCLK,它是供STM32中绝大部分部件工作的时钟源。
系统时钟可选择为PLL输出、HSI或者HSE。
系统时钟最大频率为72MHz,它通过AHB分频器分频后送给各模块使用,AHB分频器可选择1、2、4、8、16、64、128、256、512分频。
其中AHB分频器输出的时钟送给5大模块使用:
①、送给AHB总线、内核、内存和DMA使用的HCLK时钟。
②、通过8分频后送给Cortex的系统定时器时钟。
③、直接送给Cortex的空闲运行时钟FCLK。
④、送给APB1分频器。
APB1分频器可选择1、2、4、8、16分频,其输出一路供APB1外设使用(PCLK1,最大频率36MHz),另一路送给定时器(Timer)2、3、4倍频器使用。
该倍频器可选择1或者2倍频,时钟输出供定时器2、3、4使用。
⑤、送给APB2分频器。
APB2分频器可选择1、2、4、8、16分频,其输出一路供APB2外设使用(PCLK2,最大频率72MHz),另一路送给定时器(Timer)1倍频器使用。
该倍频器可选择1或者2倍频,时钟输出供定时器1使用。
另外,APB2分频器还有一路输出供ADC分频器使用,分频后送给ADC模块使用。
ADC分频器可选择为2、4、6、8分频。
在以上的时钟输出中,有很多是带使能控制的,例如AHB总线时钟、内核时钟、各种APB1外设、APB2外设等等。
当需要使用某模块时,记得一定要先使能对应的时钟。
需要注意的是定时器的倍频器,当APB的分频为1时,它的倍频值为1,否则它的倍频值就为2。
连接在APB1(低速外设)上的设备有:
电源接口、备份接口、CAN、USB、I2C1、I2C2、UART2、UART3、SPI2、窗口看门狗、Timer2、Timer3、Timer4。
注意USB模块虽然需要一个单独的48MHz时钟信号,但它应该不是供USB模块工作的时钟,而只是提供给串行接口引擎(SIE)使用的时钟。
USB模块工作的时钟应该是由APB1提供的。
连接在APB2(高速外设)上的设备有:
UART1、SPI1、Timer1、ADC1、ADC2、所有普通IO口(PA~PE)、第二功能IO口。
下图是STM32用户手册中的时钟系统结构图,通过该图可以从总体上掌握STM32的时钟系统。
STM32外部中断之二
STM32资料2009-09-1021:
18阅读243评论0
字号:
大大中中小小
STM32外部中断配置
1配置中断
1、分配中断向量表:
/*SettheVectorTablebaselocationat0x20000000*/
NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);
2、设置中断优先级:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);//设置中断优先级
3、初始化外部中断:
/*允许EXTI4中断*/
NVIC_InitStructure.NVIC_IRQChannel=EXTI4_IRQChannel;//中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=PreemptionPriorityValue;//强占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;//次优先级
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//通道中断使能
NVIC_Init(&NVIC_InitStructure);//初始化中断
注意:
如果我们配置的外部针脚为PA4,或PB4,或PC4,PD4等,那么采用的外部中断也必须是EXTI4,同样,如果外部中断针脚是PA1,PB1,PC1,PD1那么中断就要用EXTI1,其他类推。
2配置GPIO针脚作为外部中断的触发事件
1、选择IO针脚
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;
注意,如果的针脚是端口的4号针脚,配置的中断一定是EXTI4
2、配置针脚为输入
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
3、初始化针脚
GPIO_Init(GPIOD,&GPIO_InitStructure);
3配置EXTI线,使中断线和IO针脚线连接上
1、将EXTI线连接到IO端口上
将EXTI线4连接到端口GPIOD的第4个针脚上
GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource4);
注意:
如果配置的针脚是4号,那么参数必须是GPIO_PinSource4
如果配置的针脚是3号,那么参数必须是GPIO_PinSource3
2、配置中断边沿
/*配置EXTI线0上出现下降沿,则产生中断*/
EXTI_InitStructure.EXTI_Line=EXTI_Line4;
注意:
如果配置的4号针脚,那么EXTI_Line4是必须的
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿触发
EXTI_InitStructure.EXTI_LineCmd=ENABLE;//中断线使能
EXTI_Init(&EXTI_InitStructure);//初始化中断
EXTI_GenerateSWInterrupt(EXTI_Line4);//EXTI_Line4中断允许
到此中断配置完成,可以写中断处理函数。
举例:
配置函数
/*************************************************************************
*函数名NVIC_Configration
*描述配置各个中断寄存器
*输入无
*输出无
*返回值无
****************************************************************************/
voidNVIC_Configration(void)
{
NVIC_InitTypeDefNVIC_InitStructure;
//#ifdefVECT_TAB_RAM
/*SettheVectorTablebaselocationat0x20000000*/
NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);
//#else/*VECT_TAB_FLASH*/
/*SettheVectorTablebaselocationat0x08000000*/
//NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);
//#endif
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);//设置中断优先级
/*允许EXTI4中断*/
NVIC_InitStructure.NVIC_IRQChannel=EXTI4_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=PreemptionPriorityValue;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
/*允许EXTI9中断*/
NVIC_InitStructure.NVIC_IRQChannel=EXTI9_5_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
/*配置SysTick处理优先级:
优先级以及子优先级*/
}
/************************************************************************
*函数名:
GPIO_Configuration(void)
*描述:
配置TIM2阵脚
*输入:
无
*输出:
无
*返回:
无
************************************************************************/
voidGPIO_Configuration(void){
/*GPIO_InitTypeDefGPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);*/
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_All;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure);
/*配置GPIOD的第一个管角为浮动输入*/
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOD,&GPIO_InitStructure);
/*配置GPIOB的第9个管脚为浮动输入*/
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
/**************************************************************
*函数SysTick_Configuration
*描述设置SysTick
*输入无
*输出无
*返回值无
***************************************************************/
voidSysTick_Configuration(void)
{
/*配置HCLK时钟做为SysTick时钟源*/
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//系统时钟8分频72MHz
NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick,8,2);
/*SysTickInterrupteach1000HzwithHCLKequalto72MHz*/
SysTick_SetReload(9000);//中断周期1ms
/*EnabletheSysTickInterrupt*/
SysTick_ITConfig(ENABLE);//打开中断
SysTick_CounterCmd(SysTick_Counter_Enable);
SysTick_CounterCmd(SysTick_Counter_Clear);
}
/******************************************************************************
*函数名EXTI_Configuration
*描述配置EXTI线
*输入无
*输出无
*返回值无
******************************************************************************/
voidEXTI_Configuration(void){
/*将EXTI线0连接到PA0*/
GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource4);
/*配置EXTI线0上出现下降沿,则产生中断*/
EXTI_InitStructure.EXTI_Line=EXTI_Line4;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_Init(&EXTI_InitStructure);
EXTI_GenerateSWInterrupt(EXTI_Line4);
/*将EXTI线9连接到PB9上*/
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource9);
/*将EXTI线9上出现下降沿产生中断*/
EXTI_InitStructure.EXTI_Line=EXTI_Line9;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_Init(&EXTI_InitStructure);
EXTI_GenerateSWInterrupt(EXTI_Line9);
}
中断函数:
voidEXTI4_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line4)