打印
[其他ST产品]

stm32中断模型和中断初始化(EXTI、NVIC、timer、AFIO)

[复制链接]
694|37
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
sj8zw8|  楼主 | 2023-9-25 19:04 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
中断



    stm32的架构图可以看到,挂载在APB2上的外设有GPIO、EXTI、AFIO
    GPIO的所有引脚默认是与输入输出寄存器相连映射的
    AFIO算是一个不是外设的外设,因为它主要是用来将引脚重映射到其它外设寄存器的,但是对它操作也需要开启相应的时钟,所以也就放在了这里

使用特权

评论回复
沙发
sj8zw8|  楼主 | 2023-9-25 19:05 | 只看该作者
从引脚到->EXTI中断控制器->NVIC控制器的整个硬件架构
通用I/O端口以下图的方式连接到16个外部中断/事件线上,配置AFIO_EXTICRx寄存器
该部分主要是将引脚重映射到终端线上,也就是下下个图里的输入线

但是再这个之前必须先要将该寄存器外设的时钟打开(如下寄存器0位),才能对该寄存器操作

使用特权

评论回复
板凳
sj8zw8|  楼主 | 2023-9-25 19:05 | 只看该作者


使用特权

评论回复
地板
sj8zw8|  楼主 | 2023-9-25 19:06 | 只看该作者
在中断控制器

使用特权

评论回复
5
sj8zw8|  楼主 | 2023-9-25 19:06 | 只看该作者
以下为相应的寄存器

使用特权

评论回复
6
sj8zw8|  楼主 | 2023-9-25 19:06 | 只看该作者
NVIC控制器

使用特权

评论回复
7
sj8zw8|  楼主 | 2023-9-25 19:06 | 只看该作者
相应寄存器

使用特权

评论回复
8
sj8zw8|  楼主 | 2023-9-25 19:07 | 只看该作者
注意点
除了NVIC的Pending位以外,EXTI有相应的Pending位在EXTI寄存器中,TIMER等也是,所以在中断处理函数中要调用相应的清除函数EXTI_ClearITPendingBit,TIM_ClearITPendingBit等,而NVIC的Pending位在进入中断处理函数时会被硬件清除

使用特权

评论回复
9
sj8zw8|  楼主 | 2023-9-25 19:07 | 只看该作者
上面左边的是NVIC,下面有个pending位,右边是EXTI里也有一个pend位

使用特权

评论回复
10
sj8zw8|  楼主 | 2023-9-25 19:07 | 只看该作者

使用特权

评论回复
11
sj8zw8|  楼主 | 2023-9-25 19:08 | 只看该作者
根据如上顺序,就可以写出库函数的中断函数配置初始化步骤如下:


#include "stm32f10x_conf.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_exti.h"
#include "stdio.h"
#include "key.h"
#include "common.h"

/*首先将引脚配置为输入模式并初始化*/
void key_init(MODE mode) //首先需要确定某个引脚这里为GPIOC14为中断输入的引脚,然后将该引脚设置为输入模式,再初始化
{
        GPIO_InitTypeDef key;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
        key.GPIO_Pin = GPIO_Pin_14;
        key.GPIO_Mode = GPIO_Mode_IPD;
        key.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOC,&key);

    if(interrupt == mode)
    {
        key_exit_init();
        key_NVIC_init();

    }
    else
    {
        
    }
   
}

/*配置中断控制器,并初始化*/
/*在定义中断前首先要定义中断源的输入,也就是相应引脚的输入方式,根据该方式来确定是采用上升沿还是下降沿触发中断*/
void key_exit_init()
{
        EXTI_InitTypeDef key_exit; //定义中断参数结构体
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO寄存器的外设时钟
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource14); //选择exti信号源,将PC13引脚映射到中断线上
       
       
       
       
        key_exit.EXTI_Line = EXTI_Line14; //选择外部中断线14
       
       
        key_exit.EXTI_Mode = EXTI_Mode_Interrupt; //定义为中断模式
        key_exit.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //中断采用上升下降沿触发方式
        key_exit.EXTI_LineCmd = ENABLE;     //中断使能
        EXTI_Init(&key_exit);             //将结构体参数代入,中断使能

}


/*配置NVIC控制器,并初始化*/
void key_NVIC_init()
{
        NVIC_InitTypeDef key_nvic;
        key_nvic.NVIC_IRQChannel = EXTI15_10_IRQn;   //中断线10-15都是连接同一中断处理函数
        key_nvic.NVIC_IRQChannelPreemptionPriority = 0;
        key_nvic.NVIC_IRQChannelSubPriority = 1;
        key_nvic.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&key_nvic);
}


//在中断函数和多线程中可以使用全局变量
u8 key_int_flag = 0;
void EXTI15_10_IRQHandler()
{
        //不要写循环,不要有延时,不要有阻塞
        if (SET== EXTI_GetITStatus(EXTI_Line14))
        {
                if(key_int_flag==1)
        {
            key_int_flag=0;
                        printf("led on !\r\n");
        }
        else
        {
            key_int_flag++;
                        printf("led off !\r\n");
        }
        EXTI_ClearITPendingBit(EXTI_Line14);
        }
       
       
}

使用特权

评论回复
12
sj8zw8|  楼主 | 2023-9-25 19:08 | 只看该作者
定时器中断模型
整个定时器中断模型和EXTI中断模型是差不多的,就是把EXTI那部分换成TIMER,里面的结构体参数,初始化函数换一下,区别在于,EXTI它就是一个中断外设,在使能时就开了中断,而TIMER外设,它只是一个定时器外设,初始化使能时只是使能了它的定时功能,要想再开启它的中断功能,必须调用中断使能函数如下:

TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//溢出中断时钟

还有一个区别是定时器(其实叫计数器更准确)需要选择时钟源,就是要有一个能有上升和下降沿的发生器才能出发计数器计数(这里其实又跟EXTI初始化时选择外部中断触发引脚类似了),但在写单纯的定时器计时功能时需要选用内部的时钟源,为什么没有相应的代码改变相应的寄存器呢?

使用特权

评论回复
13
sj8zw8|  楼主 | 2023-9-25 19:08 | 只看该作者
如下:

使用特权

评论回复
14
sj8zw8|  楼主 | 2023-9-25 19:08 | 只看该作者
相关的寄存器如下:

使用特权

评论回复
15
sj8zw8|  楼主 | 2023-9-25 19:09 | 只看该作者
这里我们对比一下EXTI外设的相关寄存器:



其中TIMx_DIER寄存器实现的功能与EXTI_IMR、EXTI_RTSR、EXTI_FTSR三个寄存器实现的功能一样
TIMx_SR与EXTI_PR实现的功能一样,都是查看中断是不是有效实现了,在中断函数中软件复位的对象

使用特权

评论回复
16
sj8zw8|  楼主 | 2023-9-25 19:10 | 只看该作者
代码如下:
/*
* @Author: your name
* @Date: 2021-01-07 20:26:04
* @LastEditTime: 2021-01-07 22:17:08
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \projc:\Users\zj\Desktop\first_proj\main.c
*/
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_exti.h"
#include "stm32f10x_tim.h"
#include "misc.h"
#include "stdlib.h"

extern void delay_us(u16 time);
extern void delay_ms(u16 time);

       
void delay_us(u16 time)
{
        u16 i=0;
        while(time--)
        {
                i=10;
                while(i--);
        }
}

void delay_ms(u16 time)
{
        u16 i=0;
        while(time--)
        {
                i=12000;
                while(i--);
        }
}
/*
1us : (1 + 1)*(35 + 1) / 72
1s:                (1999 + 1)*(3499 + 1) / 72
*/
void timer2_init(void)
{
        TIM_TimeBaseInitTypeDef timer2;
       
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//打开定时器时钟
       
        //timer2 参数配置
        timer2.TIM_Period = 19999;//自动重装载值 ARR 0-65535
        timer2.TIM_Prescaler = 3499;//定时器分频 PSC 0-65535
        timer2.TIM_ClockDivision =  TIM_CKD_DIV1;//定时器时钟分频 72M Hz
        timer2.TIM_CounterMode = TIM_CounterMode_Up;//计数模式
       
       
        TIM_TimeBaseInit(TIM2,&timer2);//定时器参数初始化
        TIM_Cmd(TIM2,ENABLE);//定时器使能
}


void timer2_nvic(void)
{
        NVIC_InitTypeDef timer2;
       
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//0-3   0-3,每个中断的优先级由8位表示,实际起作用的只有4位(包含抢占和子优先级),这里主要是将优先级寄存器的4位分给抢占和子优先级,配置它们分别占多少位
       
        timer2.NVIC_IRQChannel = TIM2_IRQn;
        timer2.NVIC_IRQChannelSubPriority = 0;
        timer2.NVIC_IRQChannelPreemptionPriority = 1;
        timer2.NVIC_IRQChannelCmd = ENABLE;

        NVIC_Init(&timer2);

}



int main(void)
{
        uart1_init();
        delay_ms(100);
        timer2_init();
        delay_ms(100);
        TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//溢出中断
        delay_ms(100);
        timer2_nvic();
       
        uart1_send("init ok\r\n");
        while(1)
        {

        }

}

void TIM2_IRQHandler(void)
{

        if(SET == TIM_GetITStatus(TIM2,TIM_IT_Update))
        {
                uart1_send("timer-irq-2\r\n");
                TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//手动清除中断标志
        }
       
}



使用特权

评论回复
17
sj8zw8|  楼主 | 2023-9-25 19:10 | 只看该作者
输入捕获计数器
STM32】通用定时器的输入捕获(实例:输入捕获)
输入捕获计数器相比较于单纯的定时器,多了一个输入捕获部分,输出部分,整个的架构如下所示:


使用特权

评论回复
18
sj8zw8|  楼主 | 2023-9-25 19:11 | 只看该作者
时钟选择输入部分
外部输入/时钟模式1

使用特权

评论回复
19
sj8zw8|  楼主 | 2023-9-25 19:12 | 只看该作者
外部触发输入/时钟模式2

使用特权

评论回复
20
sj8zw8|  楼主 | 2023-9-25 19:12 | 只看该作者
时钟模式2的ETP寄存器和时钟模式1的CC2P都是控制边沿检测是上升还是下降沿有效
时钟模式2的滤波器一般不用,这样相比时钟模式1就是多了一个分频器

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

35

主题

306

帖子

1

粉丝