目录
- 需求
- 一、串口中断过程与作用
- 二、中断实现流程
- 1.中断优先级分组
- 2.配置串口中断
- 三、需求的实现
需求
1.设备上电后四个灯灭。
2.按下KEY1,LED1灯亮,同时串口发送“LED1灯亮”。
3.再次按下KEY1,LED1灯灭,同时串口发送“LED1灯灭”。
4.加入中断,添加串口控制LED灯,且和按键相互不冲突。
一、串口中断过程与作用
1、外设发出中断请求
2、处理器暂停当前执行的任务,保护现场,将当前位置的PC地址压栈;
3、程序跳转到中断服务程序,执行中断服务程序;
4、恢复现场,将栈顶的值回送给PC;
5、跳转到被中断的位置开始执行下一个指令
中断服务函数:
相对于正常子函数,中断服务函数有以下需要注意的地方:
1、中断服务函数不能传入参数;
2、中断服务函数不能有返回值;
3、中断服务函数应该做到短小精悍,快入快出,禁止延时性的过程。
4、不要在中断函数中使用printf函数,会带来重入和性能问题。
5、不要加浮点型(double,float)运算
中断重入:就是在一个中断程序执行过程中又被另一个中断打断,转而又去执行另一个中断程序。
中断的部分专业术语
中断源:引起中断的原因,或者能够发出中断请求信号的来源统称为中断源
中断优先级:中断同时到来,谁先执行。数字越小,优先级越高。
中断响应:中断事件发生,Cortex-M3内核准备执行该事件,即为中断响应。
中断嵌套:可嵌套的内核 – 中断可以被其他中断打断。(Cortex-M)
不可嵌套的内核 – 不可以打断。
中断挂起:中断事件发生了,但是Cortex-M内核还没准备去执行。
中断服务函数: 中断发生后,要执行的程序。(固定格式)
二、中断实现流程
1.中断优先级分组
NVIC 支持由软件指定的优先级。通过对中断优先级寄存器的8位 IPR_N 区执行写操作,来将中断的优先级指定为 0~255,见中断优先级寄存器。硬件优先级随着中断号的增加而降低。 0 优先级最高, 255 优先级最低。指定软件优先级后,硬件优先级(默认优先级)无效。
利用系统控制块(SCB)中一个名为优先级分组的配置寄存器(属于SCB中的应用中断和复位控制寄存器)将每个具有可编程优先级的优先级配置寄存器可被分为两部分。上半部分(左边的位)为分组(抢占)优先级﹐而下半部分(右边的位)则为子优先级。事实上stm32只用了4位优先级,分组时从优先级高位向低位方向分组。
抢占优先级:高抢占优先级中断到来,可以打断低抢占优先级的;
次级优先级:两个抢占优先级一样高的中断,并且同时到来,判断次级优先级,谁高谁先执行
整个工程使用中断之前先设置优先级分组,并且只用分组一次。
内核里面有8位可以配置中断的优先级分组:(stm32只支持四位优先级分组:高四位)
每个中断都要设置中断优先级:抢占优先级能够打断低抢占优先级的中断
x表示抢占,y是次级,高亮部分是有效部分
了解了以上之后,我们就可以开始配置寄存器了
NVIC_SetPriorityGrouping(X);
直接在这个函数中填写分组的序号X即可。
注意:该函数要放在main函数中,类似于初始化。
组号为7时只能打断主程序,不能打断中断。
分组代码如下:
2.配置串口中断
首先要打开手册找串口1的接收非空中断使能位置,由查询可知CR1控制寄存器的第五位即为接收非空中断使能位置,置1打开即可。
配置中断通道的优先级。
优先级配置函数:
NVIC_SetPriority();
注意:值为0~15但是只有高4位有用。
最后,使能中断通道打开即可使用中断函数。
使能中断通道函数:
NVIC_EnableIRQ();
注意:每个中断通道都能单独打开和关闭。
中断函数:
(USART1->SR&0x1<<5)!=0 执行该中断函数的原因有很多,所以判断一下是不是接收导致的
data = USART1->DR; 读操作,同时也是清空中断标志位
库函数配置
库函数中断接收
三、需求的实现
#include "usart.h"
#include "stdio.h"void Usart1_Config()
{//开时钟:GPIOA,USART1RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);//配置对应的IO口 PA9(tx):复用推挽 PA10(RX):浮空输入GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStruct);GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;GPIO_Init(GPIOA,&GPIO_InitStruct);//配置串口1 8数据位,0校验位,1停止位,波特率115200USART_InitTypeDef USART_InitStruct = {0};//可以通过结构体类型跳转USART_InitStruct.USART_BaudRate = 115200;//波特率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;USART_InitStruct.USART_WordLength = USART_WordLength_8b;USART_Init(USART1,&USART_InitStruct);USART_Cmd(USART1,ENABLE);//配置串口1的中断//在串口1产生接收的时候,会产生中断,我们直接去中断函数里面处理就可以了//选择串口1的中断原因USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//USART1->CR1 |= 0x1<<5;//使能串口1的接收非空中断NVIC_SetPriority(USART1_IRQn,7);//设置优先级0~15NVIC_EnableIRQ(USART1_IRQn);//使能中断通道
}