stm32f103中断系统的C语言库函数实现
1.了解中断
说到中断就必须要说为什么要中断; 中断即是中途断开,去做更重要的事。过程分为四步:
1.中断请求(中断源对主程序(单个中断)或者对中断服务程序(前面已经发生了中断,再次遇到中断)提出中断要求)
2.中断响应(是一个过程,收到中断请求后,由系统自动跳转到中断向量地址(一般是固定的),根据中断向量处的指令跳转到中断服务程序入口地址。C语言的库函数已经规定好响应外设的中断服务程序名,调用,在函数内编写相应的中断服务程序即可)
3.中断服务(执行中断服务程序)
4.中断返回(返回主程序或者次级中断服务程序)
中断功能很好(大大提高了计算机的运行的效率(“同时”处理很多事)和实时性(中断来了可以很快得到处理))。
stm32的中断性能就非常棒。STM32F10x系列最多有84个中断,当然,不是所有中断都可以被我们配置,少部分中断是系统的必要操作,比如复位、硬件失效、时钟安全系统等。但大多数中断是让用户配置的。
以STM32F103为例,可配置(屏蔽)的中断有60个。
2.嵌套向量中断控制器NVIC
嵌套-即中断的嵌套,我们知道计算机的运行都是逻辑性特别强的,那么中断的嵌套也一定有一个规则来定义。在STM32中,把中断分为抢占优先级(打断其他中断的能力强弱,数值越小,优先级越高)和响应优先级,判断两个中断的优先级先看相应优先级,如果抢占优先级相同,就看响应优先级的高低(优先级数值越小,优先级越高),如果都相同,则比较中断向量地址(中断产生后自动跳转的地址,在程序中是固定的,不用设定)。
我们的NVIC就是来定义中断的优先级的。说到这里我们还需要知道一种寄存器组(多个同类寄存器)-中断优先级寄存器组,在STM32F103系列中有15个这样的寄存器,一个寄存器为32位。一个中断(对了,我们这里的中断说的都是可屏蔽中断,也就是可以设置的中断)由8位控制,因此一个寄存器可以控制4个可屏蔽中断,一共有15x4=60 个可屏蔽中断。具体到单个8位中,只有高四位是有用的,通过这4位可以将中断优先级分为5组,分别为0、1、2、3、4、5组
组别 | 优先级分配 |
---|---|
0 | 0位抢占优先级、4位响应优先级 |
1 | 1位抢占优先级、3位响应优先级 |
2 | 2位抢占优先级、2位响应优先级 |
3 | 3位抢占优先级、1位响应优先级 |
4 | 4位抢占优先级、0位响应优先级 |
(注:”位“代表二进制位数,“级”代表优先级的高低。0位代表在此组中可以设置的该种(抢占或者响应)优先级没有 2 0 2^{0} 20=1,全都一样相当于没有,不可以设置。1位代表可以设置的优先级可以为 2 1 2^{1} 21,可以为0级和1级,以此类推)
3、外部中断/事件控制器EXTI
STM32提供19个中断通道,其中16个可供用户自由支配,分别为EXTI0~EXTI15通道,EXTI16-EXTI18通道分配给了STM32的RTC,PVD以及USB的使用。其主要特性如下:
1.每个中断事件都有独立的触发为和屏蔽位。
2.每个中断通道都有专门的状态位。
3.支持多达19个中断源请求。
4.可以检测到脉冲宽度低于APB2时钟宽度的外部信号。
外部中断信号从I/0口进入,可设置位上升沿有效,下降沿有效或者上升沿+下降沿有效。随后与软件中断寄存器相应位进行逻辑或运算。之后的信号便分为两路。途中上路信号为中断请求,下路信号为事件请求。两个请求有效的前提是中断屏蔽寄存器和事件屏蔽寄存器中相应位要置1。
(这里注意一下挂起寄存器,每次中断服务函数执行完后需要将其清零,不然会一直产生中断请求)
4.中断流程
4.1 RCC配置
功能:设置系统各个部分的时钟,是一个最基本的设置
代码如下:
void RCC_Configuration(void)
{
{
/*此大括号内的内容如果在时钟系统完整的单片机上可以按照默认值,不用特意设置*/
ErrorStatus HSEStartUpStatus; /*定义枚举类型变量 */
/* HSEStartUpStatus */
RCC_DeInit(); /*系统复位时钟设置
RCC_HSEConfig(RCC_HSE_ON);
HSEStartUpStatus = RCC_WaitForHSEStartUP();
if(HSEStartUpStatus == SUCCESS)
{
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK2Config(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_SYSCLK_Div1);
FLASH_SetLatency(FLASH_Latency_2);
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while(RCC_GetSYSCLKSource()!=0X08);
}
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE)
}
4.2 NVIC设置
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
#ifdef VECT_TAB_RAM
NVIC _SetVectorTable(NVIC_VectTab_RAM,0x0);
#else
NVIC _SetVectorTable(NVIC_VectTab_FLASH,0x0);
#endif
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChanel = EXTI0_IQRn;
NVIC_InitStructure.NVIC_IRQChanelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChanelSubPriority =0;
NVIC_InitStructure.NVIC_IRQChanelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
4.3 GPIO设置
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIO,&GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);
}
4.4 中断通道设置
void USART_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_Parity = USART_StopBits_1;
USART_InitStructure.USART_HardwareFlowContrl = USART_HardwareFlowControl_None;
USART_Init(USART1,&USART_InitStructure);
USART_Cmd(USART1,ENABLE);
}
4.5 EXTI设置
void EXTI_IQRHandler()
{
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
5.总结
中断的实现最基本的是要设置时钟,然后就是设置要用到的I/O口,进行输入输出和中断功能、复用功能的配置。接着就是用NVIC给中断源(0~19)进行优先级分配。然后设置你要控制的设备。最后设置EXTI。