> 文档中心 > 笔记:STM32——IO口的复用功能外部中断

笔记:STM32——IO口的复用功能外部中断

在STM32里面一般有五组寄存器分别是A——E组,每组寄存器的端口基本都有复用功能,这样可以使得端口的不被浪费,而达到极致利用。

使用复用端口的时候需要打开AFIO的时钟才能使用IO口的复用端口。每个端口基本都要外部中断复用功能,如果需要用的话就要配置端口以及外部中断。这里也要注意的是端口的每个Pin只能是不用组别的Pin才能同时用,否则会发生中断冲突。就好像:A组的Pin_0和B组的Pin_0和C组的Pin_0和D组的Pin_0和E组的Pin_0是不能同时用的也就是说引脚号是不能同时使用这个外部中断的,因为外部中断有一个中断优先响应组别。只能是Pin0,Pin1, Pin2,Pin3....Pin15这样子。分别是0~15.所以当中断进入的时候这个组别只能是不同的引脚端口才可以同时进入,否则会冲突。

下面来配置一下B组的Pin13引脚的外部中断

首先把引脚号初始化,这里是读取引脚的电平,用的是红外传感器模块。

void Cont_Init(void){GPIO_InitTypeDef  Cont_InitStruct;  // 定义结构体RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);    //打开时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);    //AFIO复用功能端口钟时钟Cont_InitStruct.GPIO_Mode=GPIO_Mode_IPU;    //上拉输入模式 ,读取电平Cont_InitStruct.GPIO_Pin=GPIO_Pin_13;   //选择引脚13    Cont_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;   //速度    GPIO_Init(GPIOB,&Cont_InitStruct); //写入寄存器B组

下面是配置外部中断相应的引脚,和上面的代码是在同一个初始化函数里面的,配置中断引脚其实跟配置引脚差不多一样的,只是这个中断不用打开时钟,因为内部是一直打开的。根本不需要,然后一样用结构体定义,然后配置里面的模式,和一些触发方式。以及触发的模式。

触发方式有三种:上升沿触发就是识别了之后,拿开就是上升沿触发。下降沿就是一放下去识别就是下降沿触发,还有就是上升和下降沿触发。

GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource13);   //配置相应的外部中断引脚EXTI_InitTypeDef  EXTI_ContInit;  //EXTI外部中断结构体初始化 由于时钟一直打开的所以不需要开启时钟使能EXTI_ContInit.EXTI_Line=EXTI_Line13;     //选择中断的引脚EXTI_ContInit.EXTI_LineCmd=ENABLE;  //   打开使能EXTI_ContInit.EXTI_Mode=EXTI_Mode_Interrupt; //中断触发模式。分别由中断触发和事件触发EXTI_ContInit.EXTI_Trigger=EXTI_Trigger_Rising;   //触发方式为上升沿EXTI_Init(&EXTI_ContInit);   //结构体初始化。

下面的就是配置中断的优先级了,优先级这个代码比较少,所以内容放在的文件都比较杂,需要在misc.c和.h和stm32f10x.h文件以及startup_stn32f10xx_hd.s启动文件里面查看。

首先在misc.h文件的最下面看到一样的配置功能函数。以及初始化结构体,然后把每个结构的定义放出来后,可以看到配置引脚中断号这个定义,需要在stm32f10x.h找到配置的EXTI开头宏定义,分别就是上面说的0~15个。需要看好自己配置的引脚来配置中断号,这里是13引脚所以是10-15中断号,然后抢占优先级和响应优先级,这里只用一个引脚,所以可以随便配置,可以在misc.h文件的注释表里面看到。大概意思反正就是数字越小优先级就越高。

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组,先占优先级是抢占优先级,从占是响应优先级。NVIC_InitTypeDef   NVIC_ContInit;    //中断优先级响应结构体  由于时钟一直是打开的不需要开启时钟NVIC_ContInit.NVIC_IRQChannel=EXTI15_10_IRQn;  //根据引脚中断号需要在#include "stm32f10x.h"文件查看自己选择的启动容量文件的密度NVIC_ContInit.NVIC_IRQChannelCmd=ENABLE;//打开使能NVIC_ContInit.NVIC_IRQChannelPreemptionPriority=1;    //抢占优先级  数字越小,优先级越高NVIC_ContInit.NVIC_IRQChannelSubPriority=1;  //响应优先级    数字越小,优先级越高NVIC_Init(&NVIC_ContInit);

到这里的初始化函数就完成了。

最后需要配置中断函数,每个只能引脚都对应着不同的中断通道,但是中断函数的名字是固定的不可以随便起,中断函数可以在startup_stn32f10xx_hd.s启动文件里面看到一些宏定义,也是一样对应着自己配置的引脚号就选择对应的中断函数通道。这里是13,所以也是用10—15 这个函数通道

,中断函数里面需要设置一些标志号,在EXTI.h文件后面找到,这里需要设置标志位,如果这个配置的触发方式,得到触发那么就会进入到中断,但是每次进入中断都需要清除标志位,不然就会卡死在中断循环里面,怎么样判断有没有进入中断成功呢,

uint16_t Count=0;void  EXTI15_10_IRQHandler (void){    if(EXTI_GetITStatus(EXTI_Line13) == SET)   //设置中断标志位{    Count++;EXTI_ClearITPendingBit(EXTI_Line13);  //清除中断标志位,每次进来都要清楚,不然就会一值在这里循环,出不去中断}}

可以定义一个全局变量,注意只有全局变量好使,然后再利用keil软件的模拟仿真,然后在里面设置一个断点,再中断函数的if(EXTI_GetITStatus(EXTI_Line13) == SET)  这里,然后运行仿真,这个就会跑到这个断点这里,然后还可以再仿真里面新建一个watch窗口,新建一个值,就是全局变量的值。把鼠标放在value那里右键去掉十六进制显示。注意进入放在需要插上STM-Link和模块连接着才行。点击1仿真,2设置断点,3点击watch,4新建值,5运行。然后运行的时候,可以触发红外模块,这里就可以看到这个值的变化,然后也会运行到这个断点这里了。

 这个仿真模式有很大作用,可以很好的测式运行的每一步代码。同时也可以定一个全局变量来计次,包括定时器计数,等等很多功能以及作用。对编写代码以及测试提供了很大的方便。

这里是主函数

#include "cont_cor.h"int main(void){Cont_Init();while(1){   }}