学习来源:哔哩哔哩大学 UP主:江科大自化协
一. 中断系统
(1)中断 :在主程序运行过程中,出现特定的中断触发条件,使得CPU暂停当前正在运行的程序,而去处理中断程序,完成后,又返回原来被暂停的位置继续工作
(2)中断优先 :当有多个中断开始时,CPU会根据事情的轻重响应更加紧急的中断
中断嵌套 :一个中断正常进行,又来一个更高级的中断,会先去做刚来的高级的中断,然后依次返回
(3)一般中断函数都是在一个子函数里的,这个函数不需要我们调用,当中断来临时,自动由硬件调用这个函数
二. STM32的中断
(1)68个可屏蔽中断通道,包含EXTI,TIM,ADC,USART,SPI,IIC,RTC等多个外设
(2) 使用NVIC统一管理中断,每个中断有16个可编程的优先等级,可对优先级分组
三 . EXTI简介
(1)EXTI外部中断
(2)EXTI可监测指定GPIO口的电平信号,当GPIO口的电平变化时,EXTI就立刻向NVIC发出中断申请,经过NVIC裁决后,让CPU执行中断程序
(3)触发方式 :上升沿(低变高),下降沿(高变低),双边沿(前两个都可以),软件出发(写代码出发,和GPIO没关系)
(4)GPIO :支持所有GPIO口,但是相同的Pin不能触发中断
(5)通道数 :16个Pin,(外加PVD输出,RTC闹钟,USB唤醒,以太网唤醒)
(6)触发响应方式: 中断响应,事件响应
所以PA0 PB0 PC0只能有一个触发,不能同时触发(因为数据选择器只能选择一根线)
四. AFIO复用IO口
在STM32中,AFIO口主要完成两个任务:复用功能引脚重映射,中断引脚选择
外部中断(EXTI)基本结构
五.代码部分
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "coder.h"
int16_t Num;//给了Num赋值
int main(void)
{
//OLED ENCODER初始化,初始化完才能用
OLED_Init();
coder_Init();
OLED_ShowString(1, 1, "Num:");
while (1)
{
Num += Encoder_Get();
OLED_ShowSignedNum(1, 5, Num, 5);
}
}
code.c
#include "stm32f10x.h" // Device header
int16_t coder_Count;//定义一个带符号变量
void coder_Init(void)
{
//两个中断的初始化代码,初始化时钟,GPIOB,AFIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//AFIO的部分
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);
//指定的中断线为EXTI_LINE1和EXTI_LINE0
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStructure);
//中断分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//中断优先级,对两个通道分别设置优先级
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_InitStructure);
}
//把变量返回回去,返回变化值,所以返回count(这里是用了一个技巧,间接返回了count(把值付给temp让temp回去))
int16_t coder_Get(void)
{
int16_t Temp;
Temp = coder_Count;
coder_Count = 0;
return Temp;
}
//接下来是中断的中断函数
void EXTI0_IRQHandler(void)
{
//检查一下中断标志位
if (EXTI_GetITStatus(EXTI_Line0) == SET)
{
//判断一下另一个引脚的电平
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
//如果是就反转
coder_Count --;
}
//清除中断标志位
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
//下面这个也是一样的,只是换了线,如果是9——15就把两个放一起,用一个中断就行
void EXTI1_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line1) == SET)
{
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
{
coder_Count ++;//正转
}
EXTI_ClearITPendingBit(EXTI_Line1);
}
}