利用对象储存做网站,ps网站页面设计教程,网页设计实训总结2000字,网站建设公司电话销售客源目录
一、中断系统
1、中断的原理
2、中断类型
外部中断
定时器中断
DMA中断
3、中断处理函数
中断标志位清除
中断服务程序退出
二、实际应用
中断控制LED
任务要求
代码示例
中断控制串口通信
任务要求1
代码示例
任务要求2
代码示例
总结 学习目标 学习stm32中断原理和开发编程方法实现中断点亮LED灯中断发送消息。 一、中断系统
STM32微控制器的中断系统是其功能强大和灵活性的重要组成部分。中断允许微控制器在执行主程序的同时及时响应外部事件或内部条件的变化从而实现高效的实时控制和数据处理。核心的中断控制器是NVICNested Vectored Interrupt Controller负责管理和分发所有的中断请求并支持优先级分组使开发人员能够为不同的中断源设置不同的优先级。STM32支持多种类型的中断包括外部中断、定时器中断、串口中断和DMA中断。每种中断类型都有特定的配置方式和中断服务程序编写规范以确保及时和有效地处理相应的事件。中断使能和中断优先级设置是配置中断系统的关键步骤同时需要编写高效的中断服务程序以便快速响应并尽快恢复主程序的执行。这些特性使得STM32在广泛的嵌入式应用中表现出色为实时控制和数据处理提供了强大支持。
1、中断的原理
下面通过一个生活中的例子帮助更好的去理解中断 可以看到图中由最开始的看书转到最后的去卫生间这个过程中看书就受到了中断。我们将看书看作主程序快递电话、肚子疼视为中断源取快递和去卫生间视为中断服务程序 但是通过箭头可以看到最后还是返回到了看书的 “主程序” 所以中断还存在返回我们叫做中断返回。
在计算机中执行程序过程中当出现异常情况断电等或特殊请求数据传输等时计算机暂停现行程序的运行转向对这些异常情况或特殊请求进行处理处理完毕后再返回到现行程序的中断处继续执行原程序这就是“中断”。
中断的主要处理流程为中断请求——中断响应——中断服务——中断返回
中断请求中断请求是中断源向CPU发出中断请求信号此时中断控制系统的中断请求寄存器被置位向CPU请求中断
中断响应CPU的中断系统判断中断源的中断请求是否符合中断响应条件如果符合条件则暂时中断当前程序并控制程序跳转到中断服务程序
中断服务为处理中断而编写的程序称为中断服务程序是由开发人员针对具体中断所要实现的功能进行设计和编写的需要由开发人员来实现
中断返回CPU退出中断服务程序返回到中断请求响应之前被中止的位置继续执行主程序。这部分操作同样由硬件来实现不需要开发人员进行处理 当发生了异常或中断内核要想响应这些异常或中断就需要知道这些异常或中断的服务程序的入口地址再由入口地址找到相应的中断服务程序由中断入口地址组成的表称作中断向量表如下图。 STM32中断系统的结构和工作原理如下
中断请求来源STM32的中断请求可以来自外部和内部两个方面。外部中断是由GPIO口引脚的电平或边沿信号变化触发而内部中断通常是由硬件模块如定时器、ADC或软件产生的。
NVIC控制器在STM32中所有中断请求都由NVICNested Vectored Interrupt Controller控制器进行管理和调度。NVIC是一个基于向量表的中断控制器通过优先级和向量表来实现对中断请求的管理。
中断分组STM32将中断分为多个组别每个组别包含一组中断请求。不同组别的中断请求可以具有不同的优先级并且可以使用优先级抢占和屏蔽机制来确保系统的实时性和可靠性。STM32中断分组方式可选为0~4个前缀用于设定中断优先级组和亚组。
中断服务程序当中断事件发生后CPU会暂停当前任务并跳转到相应的中断服务程序处理该事件。中断服务程序通常包括以下几个步骤保存CPU寄存器的值包括堆栈指针、程序计数器等处理中断请求根据外部或内部中断的类型进行相应的处理如清除标志位、读取数据等操作执行用户自定义代码根据实际需求执行用户自定义的代码段恢复CPU寄存器的值将保存在堆栈中的寄存器值恢复到其原始状态以便CPU继续执行之前的任务
中断优先级STM32中所有中断请求都具有唯一的编号IRQn并且可以根据编号和中断分组方式确定其优先级。优先级高的中断可以打断正在执行的低优先级中断从而确保系统的实时性和可靠性。如果多个中断请求的优先级相同则可以使用优先级抢占机制来确定响应顺序 2、中断类型
外部中断
EXTI外部中断/事件控制器支持19个外部中断/事件请求每个中断/事件都有独立的触发和屏蔽设置具有中断模式和事件模式两种设置模式。
其是一种通过配置GPIO引脚并使用EXTI线路实现的事件处理机制。在初始化GPIO引脚为输入并设置相应的中断触发方式后可以通过编写中断服务程序来响应外部事件。例如配置GPIO引脚为上升沿触发当引脚接收到上升沿信号时会触发预先定义的中断服务程序以便快速处理事件。这种机制使得STM32能够高效地监听和响应外部触发事件广泛应用于各种应用场景中。 输入线EXTI有19个中断/事件输入线这些输入线可以通过寄存器设置为任意一个GPIO,也可以是一些外设事件。边沿检测电路它会根据上升沿触发选择寄存器EXTI_RTSR和下降沿出发选择器EXTI_FTSR对应的设置来控制信号触发。
上升沿触发选择寄存器要配置STM32微控制器的外部中断以在上升沿触发时响应首先需通过GPIO的配置寄存器如GPIOxCRH或GPIOxCRL将相应引脚设置为输入模式。接着在EXTIx_RTSR寄存器中设置相应的位来使能对应的外部中断线x的上升沿触发。最后在NVIC中使能对应外部中断的中断处理。这些步骤确保了当引脚接收到上升沿信号时系统能够及时调用预定义的中断服务程序来处理事件。
下降沿触发选择寄存器要配置STM32微控制器的外部中断以在下降沿触发时响应首先需通过GPIO的配置寄存器如GPIOx_CRH或GPIOx_CRL将相应引脚设置为输入模式。接着在EXTIx_FTSR寄存器中设置相应的位来使能对应的外部中断线x的下降沿触发。最后在NVIC中使能对应外部中断的中断处理。这些步骤确保了当引脚接收到下降沿信号时系统能够及时调用预定义的中断服务程序来处理事件。
GPIO的中断是以组为单位的同组的外部中断公用一条外部中断线。
例如PA0、PB0、PC0、PD0、PE0、PF0、PG0这些为一组如果使用PA0作为外部中断源那么PB0、PC0、PD0、PE0、PF0、PG0就不能同时再作为外部中断使用了在此情况下只能使用类似于PB1、PC2这种末端序号不同的外部中断源。
GPIO引脚和外部中断线的映射关系图如下 定时器中断
STM32微控制器的定时器是关键的外设用于生成精确的时间延迟和周期性任务。通过选择合适的定时器类型如通用定时器TIM或基本定时器TIM6/TIM7配置工作模式和中断触发条件可以实现定时器中断功能。配置过程包括设置时钟源、计数器初值和自动重装载寄存器以及使能中断并编写相应的中断服务程序。这些步骤确保了定时器可以在达到预设计数值时产生中断请求从而实现精确的时间控制和周期性任务执行适用于实时操作系统、通信协议和其他时间敏感应用。
要配置STM32微控制器的定时器中断首先选择适合需求的定时器如TIM1、TIM2等配置其工作模式、时钟源和计数周期。通过使能定时器中断控制寄存器中的更新中断位UIE允许定时器溢出时产生中断请求。
时钟和预分频设置选择适当的时钟源和预分频器以确定定时器的计数频率。计数器设置设置定时器的计数器初值和自动重装载寄存器ARR确定定时器的计数周期。中断使能通过使能定时器中断使能寄存器中的相应中断使能位如UIE允许定时器溢出时产生中断请求。
然后编写中断服务程序来处理定时器中断事件包括清除中断标志、执行特定的定时任务并重新配置定时器。最后确保在主程序中使能全局中断以确保定时器中断能够正常触发和处理。这些步骤能够有效配置和利用STM32定时器中断功能用于实现各种时间相关的应用和功能需求。
DMA中断 在STM32微控制器中DMA直接存储器访问提供了高效的数据传输机制允许外设和内存之间直接交换数据无需CPU的干预从而提升系统效率和响应速度。DMA传输完成时可触发中断通知CPU通过使能DMA中断并配置中断服务程序可以实现在数据传输完成时执行额外操作或启动后续任务适用于实时数据处理、高速数据采集和图形显示等应用场景有效优化系统性能和数据处理效率。
3、中断处理函数 中断标志位清除
void EXTI0_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line0) ! RESET){EXTI_ClearITPendingBit(EXTI_Line0);// 接中断服务程序代码}
}
中断服务程序退出
void EXTI0_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line0) ! RESET){EXTI_ClearITPendingBit(EXTI_Line0);// 接中断服务程序代码}NVIC_ClearPendingIRQ(EXTI0_IRQn);
二、实际应用
中断控制LED
任务要求
用stm32F103核心板的GPIOA端一管脚接一个LEDGPIOB端口一引脚接一个开关用杜邦线模拟代替。采用中断模式编程当开关接高电平时LED亮灯接低电平时LED灭灯。如果完成后尝试在main函数while循环中加入一个串口每隔1s 发送一次字符的代码片段观察按键中断对串口发送是否会带来干扰或延迟。
代码示例
LED.c
#include stm32f10x.h // Device header/*** 函 数LED初始化* 参 数无* 返 回 值无*/
void LED_Init(void)
{/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin GPIO_Pin_All;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOA, GPIO_InitStructure); GPIO_ResetBits(GPIOA, GPIO_Pin_0);
} exti_key.c #include exti_key.h
#include misc.hvoid EXTI_Key_Init(void)
{ GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);GPIO_InitStructure.GPIO_Pin GPIO_Pin_1; // 使用 B 口的引脚 1GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOB, GPIO_InitStructure);NVIC_InitTypeDef NVIC_InitStructure;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitStructure.NVIC_IRQChannel EXTI1_IRQn; // 使用与 GPIOB 引脚 1 相关的外部中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority 1;NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE;NVIC_Init(NVIC_InitStructure); EXTI_InitTypeDef EXTI_InitStructure;EXTI_ClearITPendingBit(EXTI_Line1); GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1); // 将 GPIOB 和引脚 1 配置为外部中断EXTI_InitStructure.EXTI_Line 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);
}
main.c
#include stm32f10x.h // Device header
#include LED.h
#include exti_key.hint main(void)
{LED_Init();GPIO_ResetBits(GPIOA,GPIO_Pin_0);EXTI_Key_Init();while (1){}
}
//void EXTI1_IRQHandler(void)
//{
// if(EXTI_GetITStatus(EXTI_Line1) ! RESET)
// {
// GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)((1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_0))));
// EXTI_ClearITPendingBit(EXTI_Line1);
// }
//}
//两种方法
uint8_t led 1;void EXTI1_IRQHandler(void)
{if(EXTI_GetITStatus(EXTI_Line1) ! RESET){led ~led; //状态翻转//如果等于1则PB1复位点亮否则置1熄灭if(led 1)GPIO_ResetBits(GPIOA,GPIO_Pin_0);elseGPIO_SetBits(GPIOA,GPIO_Pin_0); }EXTI_ClearITPendingBit(EXTI_Line1); //清除EXTI1的中断标志位
}
即可实现中断控制LED灯亮灭。
中断控制串口通信
任务要求1
当stm32接收到1个字符“s”时停止持续发送“hello windows!”; 当接收到1个字符“t”时持续发送“hello windows!”
代码示例
#include stm32f10x.h
#include misc.h
#include string.hvolatile uint8_t send_enabled 0; // 全局变量控制发送行为void USART_Configuration(void) {USART_InitTypeDef USART_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;// 打开 GPIO 与 USART 端口的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);// 配置 USART1 Tx (PA.09) 为复用推挽输出GPIO_InitStructure.GPIO_Pin GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOA, GPIO_InitStructure);// 配置 USART1 Rx (PA.10) 为浮空输入GPIO_InitStructure.GPIO_Pin GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA, GPIO_InitStructure);// 配置 USART 参数USART_InitStructure.USART_BaudRate 9600;USART_InitStructure.USART_WordLength USART_WordLength_8b;USART_InitStructure.USART_StopBits USART_StopBits_1;USART_InitStructure.USART_Parity USART_Parity_No;USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode USART_Mode_Rx | USART_Mode_Tx;USART_Init(USART1, USART_InitStructure);// 使能 USARTUSART_Cmd(USART1, ENABLE);// 使能接收中断USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);// 配置 NVICNVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority 0;NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE;NVIC_Init(NVIC_InitStructure);
}void USART1_IRQHandler(void) {if(USART_GetITStatus(USART1, USART_IT_RXNE) ! RESET) {char data USART_ReceiveData(USART1);if(data s) { // 接收到 s 停止发送send_enabled 0;} else if (data t) { // 接收到 t 开始发送send_enabled 1;}USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
}void Delay(__IO uint32_t nCount) {for(; nCount ! 0; nCount--);
}int main(void) {SystemInit();USART_Configuration();char *str hello windows!\r\n;while(1) {if(send_enabled) {for(uint32_t i 0; i strlen(str); i) {while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET);USART_SendData(USART1, str[i]);}}Delay(5000000);}
}
任务要求2
当stm32接收到字符“stop stm32!”时停止持续发送“hello windows!”; 当接收到字符“go stm32!”时持续发送“hello windows!”(提示要将接收到的连续字符保存到一个字符数组里进行判别匹配。写一个接收字符串的函数。
代码示例
NVIC.c
#include stm32f10x.h // Device headervoid NVIC_Configuration(void) {NVIC_InitTypeDef NVIC_InitStructure;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);NVIC_InitStructure.NVIC_IRQChannel USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelSubPriority 0;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0;NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE;NVIC_Init(NVIC_InitStructure);
}
Serial.c
#include stm32f10x.h // Device header
#include stdio.h
#include stdarg.h/*** 函 数串口初始化* 参 数无* 返 回 值无*/
void Serial_Init(void)
{/*开启时钟*/USART_InitTypeDef USART_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);// USART Tx (PA.09) 配置为复用推挽输出GPIO_InitStructure.GPIO_Pin GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOA, GPIO_InitStructure);// USART Rx (PA.10) 配置为浮空输入GPIO_InitStructure.GPIO_Pin GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA, GPIO_InitStructure);USART_InitStructure.USART_BaudRate 9600;USART_InitStructure.USART_WordLength USART_WordLength_8b;USART_InitStructure.USART_StopBits USART_StopBits_1;USART_InitStructure.USART_Parity USART_Parity_No;USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode USART_Mode_Rx | USART_Mode_Tx;USART_Init(USART1, USART_InitStructure);USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 开启接收中断USART_Cmd(USART1, ENABLE);
}
main.c
#include stm32f10x.h
#include misc.h
#include string.h
#include Delay.h
#include Serial.h
#include NVIC.h#define BUFFER_SIZE 100
volatile char buffer[BUFFER_SIZE];
volatile int buffer_index 0;
volatile int send_enabled 0;void USART1_IRQHandler(void) {if (USART_GetITStatus(USART1, USART_IT_RXNE) ! RESET) {char data (char)USART_ReceiveData(USART1);if (buffer_index BUFFER_SIZE - 1) {buffer[buffer_index] data;buffer[buffer_index] \0; // 保持字符串结尾char* temp_buffer (char*)buffer; // 创建一个非 volatile 指针if (strstr(temp_buffer, stop stm32!) ! NULL) {send_enabled 0;buffer_index 0; // 清空缓冲区} else if (strstr(temp_buffer, go stm32!) ! NULL) {send_enabled 1;buffer_index 0; // 清空缓冲区}}}
}int main(void) {SystemInit();Serial_Init();NVIC_Configuration();char *str hello windows!\r\n;while (1) {if (send_enabled) {for (uint32_t i 0; i strlen(str); i) {while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET);USART_SendData(USART1, str[i]);}}Delay_ms(500);}
}
最后使用串口助手即可野火以及其他串口助手均可。
总结
本章内容理解上不存在太多有问题的地方对于中断的理解更像是正51单片机的另一个翻版对于实践过程中的问题远远多于理论理解关于软件的操作环境的配置串口的调试运行都是之前学习的逐渐累积在学习上没有一蹴而就要脚踏实地做好每一步才可以更好更快更高效率完成任务。