一、标准库中断原理
1.1中断
计算机在执行程序过程中,当出现异常情况(断电等)或特殊请求(数据传输等)时,计算机暂停现行程序的运行,转向对这些异常情况或特殊请求进行处理,处理完毕后再返回到现行程序的中断处,继续执行原程序,这就是“中断”。
1.2中断处理过程
中断处理流程:中断请求、中断响应、中断服务和中断返回
单重中断处理流程如下
多重中断处理流程:
1.3stm32内部处理机制:
1.4中断优先级
NVIC_PriorityGroup | 抢占优先级 取值范围 | 响应优先级 取值范围 | 描述 |
NVIC_PriorityGroup_0 | 0 | 0~15 | 抢占优先级占0位, 响应优先级占4位 |
NVIC_PriorityGroup_1 | 0,1 | 0~7 | 抢占优先级占1位, 响应优先级占3位 |
NVIC_PriorityGroup_2 | 0,1,2,3 | 0,1,2,3 | 抢占优先级占2位, 响应优先级占2位 |
NVIC_PriorityGroup_3 | 0,1,2,3,4,5,6,7 | 0,1 | 抢占优先级占3位, 响应优先级占1位 |
NVIC_PriorityGroup_4 | 0~15 | 0 | 抢占优先级占4位, 响应优先级占0位 |
1.5STM32的外部中断EXTI
STM32芯片之外的外设的中断(I/O端口)由EXTI和NVIC共同负责,即STM32的每一个GPIO引脚都可以配置成一个外部中断触发源
1.6EXTI标准外设库一般调用步骤:
二、按键点灯
2.1任务:
用stm32F103核心板的GPIOA端一管脚接一个LED,GPIOB端口一引脚接一个开关(用杜邦线模拟代替)。采用中断模式编程,当开关接高电平时,LED亮灯;接低电平时,LED灭灯。如果完成后,尝试在main函数while循环中加入一个串口每隔1s 发送一次字符的代码片段,观察按键中断对串口发送是否会带来干扰或延迟。
2.2KEIL代码实现:
中断实现:exti_key.h
#ifndef __EXTI_KEY_H
#define __EXTI_KEY_H
#include "stm32f10x.h"
void EXTI_Key_Init(void);
#endif
中断实现:exti_key.c
#include "exti_key.h"
#include "misc.h"
void EXTI_Key_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
EXTI_InitTypeDef EXTI_InitStructure;//定义一个名为 EXTI_InitStructure 的结构体变量,用于配置外部中断线
EXTI_ClearITPendingBit(EXTI_Line3);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource3);//清除外部中断线3的中断挂起位
EXTI_InitStructure.EXTI_Line = EXTI_Line3;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//设置外部中断模式为中断模式。
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
uint8_t led =1;
void EXTI3_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line3) != RESET)
{
led = ~led;
if(led == 1)
GPIO_ResetBits(GPIOB,GPIO_Pin_1);
else
GPIO_SetBits(GPIOB,GPIO_Pin_1);
}
EXTI_ClearITPendingBit(EXTI_Line3);
}
主函数:
#include "stm32f10x.h"
#include "usart.h"//串口通信的头文件
//#include "led.h"
#include "exti_key.h"
void delay(uint16_t time)
{
uint16_t i =0;
while(time--){
i=12000;
while(i--);
}
}
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//打开时钟
//固定模式配置
GPIO_InitTypeDef Led_init;
Led_init.GPIO_Mode = GPIO_Mode_Out_PP;
Led_init.GPIO_Pin = GPIO_Pin_1;
Led_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &Led_init);
GPIO_ResetBits(GPIOB,GPIO_Pin_1);//点亮LED灯
//中断函数
EXTI_Key_Init();
usart_init();
while(1)
{
usartSendStr(USART1,"Hello word\r\n");
delay(1000);
}
}
2.3实验结果:
通过按键实现LED点灯:
按键控制灯
三、串口中断实验
3.1字符中断
要求:当stm32接收到字符“stop stm32!”时,停止持续发送“hello windows!”; 当接收到字符“go stm32!”时,持续发送“hello windows!”
代码实现:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
//当输入的指令为0时,发送提示并改变flag
if(c=='s'){
flag=0;
HAL_UART_Transmit(&huart1, (uint8_t *)&tips2, strlen(tips2),0xFFFF);
}
//当输入的指令为1时,发送提示并改变flag
else if(c=='t'){
flag=1;
HAL_UART_Transmit(&huart1, (uint8_t *)&tips1, strlen(tips1),0xFFFF);
}
//当输入不存在指令时,发送提示并改变flag
else {
flag=0;
HAL_UART_Transmit(&huart1, (uint8_t *)&tips, strlen(tips),0xFFFF);
}
//重新设置中断
HAL_UART_Receive_IT(&huart1, (uint8_t *)&c, 1);
}
3.2结果展示:
四、总结
通过本次的中断实验和串口通信,进一步加强了对中断的理解。对于点灯、执行嵌入式开发的操作,中断是非常方便的,理解了理念后更加有助于自己对嵌入式的开发,收获良多。串口通信的代码撰写也加强了对汇编语言的理解,实现通过stm32板子收发数据并控制事件,嵌入式逐渐入门。本人才疏学浅,若有不对的地方还望读者海涵。