完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1、中断简介 中断:程序在运行过程中发生了外部或内部事件时,中断了正在执行的程序,转到外部或内部事件中去执行别的任务。 (1)中断的作用
以之前学习的串口接收数据为例,比较使用中断与否的效果:(2)中断入口 在单片机内部有一块空间专门用来存放地址,该地址已经和相应的中断绑定在一起了(芯片厂商处理的)。当中断发生时,CPU会跑到该内存空间中查找中断入口地址,该地址就是中断入口。该地址对于开发人员而言,可读性较差,所以芯片厂商在芯片设计时将该地址重新取名(便于记忆和理解),即中断服务函数名,在stm32里,中断服务函数名是不可自定义,所有的中断服务函数名都已经被设定好了。因此在编写中断服务函数时绝对不能写错,如果写错,CPU就找不到中断的入口。如中断地址0x233947hff取中断服务函数名为USART1_IRQHandler,这对应着同一个中断事件。 中断服务函数在XXX_md.s文件。(3)中断优先级 把事件的紧急情况或执行事件的先后顺序称为优先级。使用到优先级的目的:为了区分这些事情的重要程度,即事件执行时的先后顺序。优先级就是一个数值,数值越小,优先级越高。每个中断优先级可以分为自然(固定不变的)和可控(程序员可以配置)两种。中断自带的优先级编号称为自然优先级。可控优先级就是可以由程序员自行修改的优先级。 (4)中断嵌套 中断嵌套只发生在抢占优先级不一样的情况下。中断嵌套:就是中断在执行的时候在中断中又出现了一个中断。 中断嵌套目的:处理更紧急的事情。中断嵌套中需要将嵌套的中断优先级设置的更高。因为高优先级的任务可以打断或抢占低优先级的任务。 2、Cortex-M4——中断体系 中断体系就是管理中断的一套机制。 (1)Cortex-M4-中断架构 在芯片的内核里专门有一个管理中断机制的模块——NVIC(嵌套向量中断控制器)控制器。M4内核专门负责处理中断相关问题的机构,专门做中断管理相关的事务。 注意:NVIC控制器属于内核级的模块,所以在中文手册找不到,到芯片内核编程手册:《Cortex M3与M4权威指南.pdf》在第7章异常和中断中详细讲中断体系中查看。所有的中断都是在NVIC控制器中控制的,如下图所示。
NVIC控制器总共提供了255个中断入口。具体见《Cortex M3与M4权威指南.pdf》 ①系统及SysTick中断入口共15个(内核固定的)。 注意:这是内核级中断,中断控制器必须响应,内核中断不能够被打断也不能被设置优先级,具有固定的优先级。这15个中断源是由ARM设计的。②片上外设或IO口中断入口16到255总共240个。 注意:该部分中断由芯片厂商决定(不是内核极的),由芯片生产者决定。(3) Cortex-M4中断管理方式 Cortex-M4 NVIC控制器中1 ~ 15个系统中断不能被打断也不可以设置优先级,他们的优先级是固定的,且发生事件时必须要响应。剩下的16~255总共240个中断属于外部或片上外设中断,他们可以自由的设置中断优先级,且每一种中断都具有三种类型的优先级:可控优先级(抢占优先级,响应优先级),自然优先级。 ①抢占优先级:当其中一个中断正在执行时,其他的中断是否可以打断正在执行的中断。 M4 NVIC控制器通过分组来设置各个中断的优先级的方式来管理各个中断。在CM4里面,系统会给每一个中断源都分配一个8位寄存器来存放它的优先级(抢占优先级和响应优先级)。在这8位寄存器里面,一部分用于存放抢占优先级,另一部分存放响应优先级。8位寄存器的理想情况下的分布情况如下(抢占优先级位数+响应优先级位数=8bit): Cortex-M4-NVIC 中得知抢占优先级+响应优先级最多占8位,最少3位。(一个范围,具体占几位取决于芯片生产商)M4内核中的中断可分为8组,不同的组抢占和响应的位数不一样,可以设置的优先级的范围也不一样。如下表所示。 注意:抢占优先级最大有128级别,响应优先级最大有256级别。往SCB(系统控制块)->AIRCR寄存器的PRIGROUP3位(8 ~ 10)中写入不同值(分组值0~7)即可决定系统中,中断的抢占优先级位数和响应优先级位数。 一个系统在使用中断之前,必须确定优先级分组,也就是确定抢占优先级和响应优先级的位数,从而决定抢占优先级和响应优先级的可设置范围。 (4)Cortex-M4-NVIC控制器中断相关函数介绍 3、STM32——中断体系 (1)STM32-NVIC控制器简介 STM32-NVIC控制器结构和内核的一样,只是中断入口或者来源发生了变化。见《STM32F4xx中文参考手册.pdf》中断章节。1)设置分组&优先级 M4内核的NVIC控制器抢占+响应优先级设置总共占用8bit表示。而ARM公司规定:不是所有的芯片厂商都要使用8位。最多可以使用8bit,最少不少于3bit。可以根据需要使用(比如自己芯片功能等)。比如ST公司就是使用4位,NXP(恩智浦)公司使用5位。这里讲的是STM32F40X的中断分组设置(使用4bit)。抢占优先级位数+响应优先级位数=4bit。 知识总结:(2)STM32-NVIC控制器相关函数及配置方法 在NVIC控制器中打开相应中断功能叫做:核心级中断使能。(3)STM32外设中断原理 经过核心级中断使能的中断并未真正的打开,还需要打开相关外设的中断,即模块级中断。即要真正使用中断功能要实现核心级中断使能+模块级中断使能。 中断过程分析: 书写中断服务函数注意事项:4、说明 本博客设置 USART1接收中断为例。串口1模块级中断寄存器(USART_CR1): 一、单片机利用中断接收字符串 现象:串口助手发送字符串到单片机,单片机将接收到的字符串又发送到串口助手。1、在usart.c文件中编写中断接收字符串函数 先初始化,再编写接收函数。 void Usart1_Init(u32 brr) { //1、开串口USART1和GPIOA组时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1 ,ENABLE); GPIO_InitTypeDef GPIO_InitStruct; //定义结构体变量 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; //配置为复用推挽输出 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; //输出速度为2MHz GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; //选定管脚PA9 GPIO_Init(GPIOA,&GPIO_InitStruct); //调用初始化函数 //2、初始化USART1 USART_InitTypeDef USART_InitStruct; USART_InitStruct.USART_BaudRate = brr; //波特率 USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //禁止硬件流控 USART_InitStruct.USART_Mode = USART_Mode_Tx|USART_Mode_Rx; //全双工通信 USART_InitStruct.USART_Parity = USART_Parity_No; //禁止奇偶校验 USART_InitStruct.USART_StopBits = USART_StopBits_1; //1个停止位 USART_InitStruct.USART_WordLength = USART_WordLength_8b; //8bit数据位 USART_Init(USART1, &USART_InitStruct); //中断 USART_ITConfig(USART1,USART_IT_RXNE, ENABLE); //使能USART1接收中断 USART_ITConfig(USART1,USART_IT_IDLE, ENABLE); //使能USART1空闲中断 判断通信什么时候结束 NVIC_SetPriority (USART1_IRQn, NVIC_EncodePriority (7-2, 1, 2)); //设置抢占和响应的优先级级别,并将合成的优先级设置给USART1中断源 NVIC_EnableIRQ (USART1_IRQn); //使能NVIC控制器中断开关,即打开串口1在NVIC控制器当中的开关,这一步必须要 //3、使能串口1 USART_Cmd( USART1, ENABLE); } //使用中断方式接收字符串。 u8 buff[50]; u8 rev_ok; /* 1.中断服务函数不可以有返回值,也不可以有形参 2.中断服务函数名名字已经固定好,不可以由程序员自己更改 3.中断服务函数,不需要声明,也不需要调用,它的本质和main函数一样,其工作原理是和main函数抢CPU的使用权 */ void USART1_IRQHandler(void) { static u8 i = 0;//static 修饰的静态局部变量只执行初始化一次 if( USART_GetITStatus(USART1, USART_IT_RXNE) ) //接收中断 { USART_ClearFlag(USART1,USART_FLAG_RXNE); //清除接收中断标志位 buff = USART_ReceiveData(USART1); i++; } if( USART_GetITStatus(USART1, USART_IT_IDLE) ) //空闲中断 { if(USART1->DR) //读DR寄存器 清空闲标志位 { ; } buff = ' |