6讲 中断应用概览、EXTI中断外部事件控制器、SysTick系统定时器
内容纲要

6讲 中断应用概览、EXTI中断外部事件控制器、SysTick系统定时器

file

  • 中断类型

file

  • 控制中断的寄存器---NVIC

file

NVIC 是Arm 厂商定义的,对于不同的芯片使用Arm 的内核,不同的公司会根据需求对NVIC 进行裁剪

file

file

file

  • 当中断到来时,先比较优先级分组,然后再比较优先级。就可以用4位来表示80多种甚至更多的中断优先级
  • 如果组优先级和子优先级一致的话,那么就对比硬件优先级。

file

file

  • 中断编程的顺序

file

中断优先级 对内核 和外设 都有效,并非内核优先级大于外设的。

  • 系统内核优先级只有下图的可以编程

file

file

file

中断服务函数尽量写在 "stm32f4xx_it.c" 文件中,当然只是建议,因为便于管理。

file

  • 如果中断函数名写错了,那么在启动文件的中断向量表会执行默认函数,当然你也可以写如果中断未执行应该怎么做。

    file

    上图 B . 汇编语言表示死循环,程序会停在这里。

8讲 EXTI---外部 中断/事件 控制器 (External interrupt / event controller)

file

  • EXTI 功能框图

file

  • 与门

file

  • 或门

file

  • 定义EXTI 结构体成员

file

file

这四个结构体成员对应如下的寄存器

file

关于EXTI_Line 我的理解是,0-15代表GPIOx的接口引脚,,另外7种代表7个可配置内核的中断

file

file

/** @defgroup EXTI_Lines 
  * @{
  */

#define EXTI_Line0       ((uint32_t)0x00001)     /*!< External interrupt line 0 */
#define EXTI_Line1       ((uint32_t)0x00002)     /*!< External interrupt line 1 */
#define EXTI_Line2       ((uint32_t)0x00004)     /*!< External interrupt line 2 */
#define EXTI_Line3       ((uint32_t)0x00008)     /*!< External interrupt line 3 */
#define EXTI_Line4       ((uint32_t)0x00010)     /*!< External interrupt line 4 */
#define EXTI_Line5       ((uint32_t)0x00020)     /*!< External interrupt line 5 */
#define EXTI_Line6       ((uint32_t)0x00040)     /*!< External interrupt line 6 */
#define EXTI_Line7       ((uint32_t)0x00080)     /*!< External interrupt line 7 */
#define EXTI_Line8       ((uint32_t)0x00100)     /*!< External interrupt line 8 */
#define EXTI_Line9       ((uint32_t)0x00200)     /*!< External interrupt line 9 */
#define EXTI_Line10      ((uint32_t)0x00400)     /*!< External interrupt line 10 */
#define EXTI_Line11      ((uint32_t)0x00800)     /*!< External interrupt line 11 */
#define EXTI_Line12      ((uint32_t)0x01000)     /*!< External interrupt line 12 */
#define EXTI_Line13      ((uint32_t)0x02000)     /*!< External interrupt line 13 */
#define EXTI_Line14      ((uint32_t)0x04000)     /*!< External interrupt line 14 */
#define EXTI_Line15      ((uint32_t)0x08000)     /*!< External interrupt line 15 */
#define EXTI_Line16      ((uint32_t)0x10000)     /*!< External interrupt line 16 Connected to the PVD Output */
#define EXTI_Line17      ((uint32_t)0x20000)     /*!< External interrupt line 17 Connected to the RTC Alarm event */
#define EXTI_Line18      ((uint32_t)0x40000)     /*!< External interrupt line 18 Connected to the USB OTG FS Wakeup from suspend event */                                    
#define EXTI_Line19      ((uint32_t)0x80000)     /*!< External interrupt line 19 Connected to the Ethernet Wakeup event */
#define EXTI_Line20      ((uint32_t)0x00100000)  /*!< External interrupt line 20 Connected to the USB OTG HS (configured in FS) Wakeup event  */
#define EXTI_Line21      ((uint32_t)0x00200000)  /*!< External interrupt line 21 Connected to the RTC Tamper and Time Stamp events */                                               
#define EXTI_Line22      ((uint32_t)0x00400000)  /*!< External interrupt line 22 Connected to the RTC Wakeup event */
#define EXTI_Line23      ((uint32_t)0x00800000)  /*!< External interrupt line 23 Connected to the LPTIM Wakeup event */

Q: 如果PA0 和PB0 同时连到EXTI 中断源上,那么同一时间中断信号来的时候谁先执行?

S:可以通过读取GPIO 的IDR 寄存器,来判断谁先执行,总有一个先后顺序

//代码如下,头疼,找问题点花了我好长一段时间。

main.c

#include "stm32f4xx.h"
#include "bsp_led.h"
#include "./exti/bsp_exti.h"

int main(void)
{
    /* 在这里添加你自己的程序 */

    LED_GPIO_Config();
    EXTI_Key_Config();

    while(1){};

}

bsp_led.c

#include "./LED/bsp_led.h"   

 /**
  * @brief  初始化控制LED的IO
  * @param  无
  * @retval 无
  */
void LED_GPIO_Config(void)
{       
        /*定义一个GPIO_InitTypeDef类型的结构体*/
        GPIO_InitTypeDef GPIO_InitStructure;

        /*开启LED相关的GPIO外设时钟*/
        RCC_AHB1PeriphClockCmd ( LED1_GPIO_CLK|
                               LED2_GPIO_CLK|
                               LED3_GPIO_CLK, ENABLE); 

        /*选择要控制的GPIO引脚*/                                                               
        GPIO_InitStructure.GPIO_Pin = LED1_PIN; 

        /*设置引脚模式为输出模式*/
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;   

    /*设置引脚的输出类型为推挽输出*/
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

    /*设置引脚为上拉模式*/
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

        /*设置引脚速率为2MHz */   
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; 

        /*调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO*/
        GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure); 

    /*选择要控制的GPIO引脚*/                                                               
        GPIO_InitStructure.GPIO_Pin = LED2_PIN; 
    GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStructure); 

    /*选择要控制的GPIO引脚*/                                                               
        GPIO_InitStructure.GPIO_Pin = LED3_PIN; 
    GPIO_Init(LED3_GPIO_PORT, &GPIO_InitStructure); 

        /*关闭RGB灯*/
        LED_RGBOFF;     
}
/*********************************************END OF FILE**********************/

bsp_led.h

#ifndef __LED_H
#define __LED_H

#include "stm32f4xx.h"

//引脚定义
/*******************************************************/
//R 红色灯
#define LED1_PIN                  GPIO_Pin_6                 
#define LED1_GPIO_PORT            GPIOF                      
#define LED1_GPIO_CLK             RCC_AHB1Periph_GPIOF

//G 绿色灯
#define LED2_PIN                  GPIO_Pin_7                 
#define LED2_GPIO_PORT            GPIOF                      
#define LED2_GPIO_CLK             RCC_AHB1Periph_GPIOF

//B 蓝色灯
#define LED3_PIN                  GPIO_Pin_8                 
#define LED3_GPIO_PORT            GPIOF                       
#define LED3_GPIO_CLK             RCC_AHB1Periph_GPIOF
/************************************************************/

/** 控制LED灯亮灭的宏,
    * LED低电平亮,设置ON=0,OFF=1
    * 若LED高电平亮,把宏设置成ON=1 ,OFF=0 即可
    */
#define ON  0
#define OFF 1

/* 带参宏,可以像内联函数一样使用 */
#define LED1(a) if (a)  \
                    GPIO_SetBits(LED1_GPIO_PORT,LED1_PIN);\
                    else        \
                    GPIO_ResetBits(LED1_GPIO_PORT,LED1_PIN)

#define LED2(a) if (a)  \
                    GPIO_SetBits(LED2_GPIO_PORT,LED2_PIN);\
                    else        \
                    GPIO_ResetBits(LED2_GPIO_PORT,LED2_PIN)

#define LED3(a) if (a)  \
                    GPIO_SetBits(LED3_GPIO_PORT,LED3_PIN);\
                    else        \
                    GPIO_ResetBits(LED3_GPIO_PORT,LED3_PIN)

/* 直接操作寄存器的方法控制IO */
#define digitalHi(p,i)           {p->BSRRL=i;}       //设置为高电平
#define digitalLo(p,i)           {p->BSRRH=i;}       //输出低电平
#define digitalToggle(p,i)   {p->ODR ^=i;}       //输出反转状态  //按位异或,当位分别位1与0 是,取得结果为1

/* 定义控制IO的宏 */
#define LED1_TOGGLE     digitalToggle(LED1_GPIO_PORT,LED1_PIN)
#define LED1_OFF            digitalHi(LED1_GPIO_PORT,LED1_PIN)
#define LED1_ON             digitalLo(LED1_GPIO_PORT,LED1_PIN)

#define LED2_TOGGLE     digitalToggle(LED2_GPIO_PORT,LED2_PIN)
#define LED2_OFF            digitalHi(LED2_GPIO_PORT,LED2_PIN)
#define LED2_ON             digitalLo(LED2_GPIO_PORT,LED2_PIN)

#define LED3_TOGGLE     digitalToggle(LED3_GPIO_PORT,LED3_PIN)
#define LED3_OFF            digitalHi(LED3_GPIO_PORT,LED3_PIN)
#define LED3_ON             digitalLo(LED3_GPIO_PORT,LED3_PIN)

/* 基本混色,后面高级用法使用PWM可混出全彩颜色,且效果更好 */

//红
#define LED_RED  \
                    LED1_ON;\
                    LED2_OFF;\
                    LED3_OFF

//绿
#define LED_GREEN       \
                    LED1_OFF;\
                    LED2_ON;\
                    LED3_OFF

//蓝
#define LED_BLUE    \
                    LED1_OFF;\
                    LED2_OFF;\
                    LED3_ON

//黄(红+绿)                    
#define LED_YELLOW  \
                    LED1_ON;\
                    LED2_ON;\
                    LED3_OFF
//紫(红+蓝)
#define LED_PURPLE  \
                    LED1_ON;\
                    LED2_OFF;\
                    LED3_ON

//青(绿+蓝)
#define LED_CYAN \
                    LED1_OFF;\
                    LED2_ON;\
                    LED3_ON

//白(红+绿+蓝)
#define LED_WHITE   \
                    LED1_ON;\
                    LED2_ON;\
                    LED3_ON

//黑(全部关闭)
#define LED_RGBOFF  \
                    LED1_OFF;\
                    LED2_OFF;\
                    LED3_OFF        

    void LED_GPIO_Config(void);

#endif /* BSP_LED_H */

bsp_exti.c

#include "./exti/bsp_exti.h"

//3.配置NVIC    //嵌套向量中断控制器
 static void NVIC_Configuration(void)
{

    //设置优先级组为1
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

    //void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
    //创建结构体
    NVIC_InitTypeDef NVIC_InitStruct;

    /*************  KEY1  **************************/
    //配置中断源
    NVIC_InitStruct.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;
    //配置抢占优先级
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
    //配置子优先级
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
    //使能中断通道
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    //初始化
    NVIC_Init(&NVIC_InitStruct);

    /*************  KEY1 END **************************/

    /****************** KEY2 *******************/
    NVIC_InitStruct.NVIC_IRQChannel = KEY2_INT_EXTI_IRQ;
    NVIC_Init(&NVIC_InitStruct);

    /****************** KEY2  END *******************/

}

 void EXTI_Key_Config(void)
{
    //1.初始化需要连接到EXTI 线的GPIO

    RCC_AHB1PeriphClockCmd(KEY1_INT_GPIO_CLK | KEY2_INT_GPIO_CLK, ENABLE);

    //设置按键1引脚
    GPIO_InitTypeDef InitGPIOstruct;
    InitGPIOstruct.GPIO_Mode = GPIO_Mode_IN;
    InitGPIOstruct.GPIO_OType = GPIO_OType_PP;  
    InitGPIOstruct.GPIO_Pin = KEY1_INT_GPIO_PIN;
    InitGPIOstruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    InitGPIOstruct.GPIO_Speed = GPIO_Low_Speed;

    GPIO_Init(KEY1_INT_GPIO_PORT,&InitGPIOstruct);

    //设置按键2引脚
    InitGPIOstruct.GPIO_Pin = KEY2_INT_GPIO_PIN;

    GPIO_Init(KEY2_INT_GPIO_PORT,&InitGPIOstruct);

    //2.初始化EXTI
    /****************** KEY1 ************************/
    //使能SYSCFG 时钟,该时钟位于APB2 外设总线下。
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);   //开启系统配置(SYSCFG) 时钟 目的是未来用得到 EXTICR4

    //使GPIO 引脚添加到EXTI中断源上
    //void       SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex);
    SYSCFG_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE, KEY1_INT_EXTI_PINSOURCE);   //Q: 既然这里配置了引脚?为什么下面的结构体也要配置?

    EXTI_InitTypeDef EXTI_Struct;
    EXTI_Struct.EXTI_Line = KEY1_INT_GPIO_PIN;
    EXTI_Struct.EXTI_Mode = EXTI_Mode_Interrupt;  //配置成中断模式, (而不是事件模式)
    EXTI_Struct.EXTI_LineCmd = ENABLE;
    EXTI_Struct.EXTI_Trigger = EXTI_Trigger_Rising;   //配置上升沿触发。  (上升沿/下降沿/都选)

    EXTI_Init(&EXTI_Struct);

    /****************** KEY1 END ************************/

    /******************    KEY2   ************************/
    SYSCFG_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE, KEY2_INT_EXTI_PINSOURCE); 

    EXTI_Struct.EXTI_Line = KEY2_INT_GPIO_PIN;
    EXTI_Struct.EXTI_Mode = EXTI_Mode_Interrupt;  //配置成中断模式, (而不是事件模式)
    EXTI_Struct.EXTI_LineCmd = ENABLE;
    EXTI_Struct.EXTI_Trigger = EXTI_Trigger_Falling;   //配置下降沿沿触发//区别于上,用于测试。  (上升沿/下降沿/都选)

    EXTI_Init(&EXTI_Struct);
    /******************    KEY2 END  ************************/

    //3.配置NVIC
    NVIC_Configuration();
}

    //4.编写中断服务函数
/*中断服务函数在 "stm32f4xx_it.c" 中 */

bsp_exti.h

#ifndef BSP_EXTI_H
#define BSP_EXTI_H

#include "stm32f4xx.h"

/****************引脚定义****************************/
#define KEY1_INT_GPIO_PORT                      GPIOA
#define KEY1_INT_GPIO_CLK                       RCC_AHB1Periph_GPIOA
#define KEY1_INT_GPIO_PIN                       GPIO_Pin_0
#define KEY1_INT_EXTI_PORTSOURCE                EXTI_PortSourceGPIOA
#define KEY1_INT_EXTI_PINSOURCE                 EXTI_PinSource0
#define KEY1_INT_EXTI_LINE                      EXTI_Line0
#define KEY1_INT_EXTI_IRQ                       EXTI0_IRQn

#define KEY1_IRQHandler                         EXTI0_IRQHandler

#define KEY2_INT_GPIO_PORT                      GPIOC
#define KEY2_INT_GPIO_CLK                       RCC_AHB1Periph_GPIOC
#define KEY2_INT_GPIO_PIN                       GPIO_Pin_13
#define KEY2_INT_EXTI_PORTSOURCE                EXTI_PortSourceGPIOC
#define KEY2_INT_EXTI_PINSOURCE                 EXTI_PinSource13
#define KEY2_INT_EXTI_LINE                      EXTI_Line13
#define KEY2_INT_EXTI_IRQ                       EXTI15_10_IRQn

#define KEY2_IRQHandler                         EXTI15_10_IRQHandler

/**************************************************/

void EXTI_Key_Config(void);
//void NVIC_Configuration(void);

#endif /*BSP_EXTI_H*/  

stm32f4xx_it.c

/**
  ******************************************************************************
  * @file    Project/STM32F4xx_StdPeriph_Templates/stm32f4xx_it.c 
  * @author  MCD Application Team
  * @version V1.8.0
  * @date    04-November-2016
  * @brief   Main Interrupt Service Routines.
  *          This file provides template for all exceptions handler and 
  *          peripherals interrupt service routine.
  ******************************************************************************
  * @attention
  *
  * <h2><center>© COPYRIGHT 2016 STMicroelectronics</center></h2>
  *
  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
  * You may not use this file except in compliance with the License.
  * You may obtain a copy of the License at:
  *
  *        http://www.st.com/software_license_agreement_liberty_v2
  *
  * Unless required by applicable law or agreed to in writing, software 
  * distributed under the License is distributed on an "AS IS" BASIS, 
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_it.h"
#include "./exti/bsp_exti.h"
#include "bsp_led.h"

/** @addtogroup Template_Project
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/******************************************************************************/
/*            Cortex-M4 Processor Exceptions Handlers                         */
/******************************************************************************/

/**
  * @brief  This function handles NMI exception.
  * @param  None
  * @retval None
  */
void NMI_Handler(void)
{
}

/**
  * @brief  This function handles Hard Fault exception.
  * @param  None
  * @retval None
  */
void HardFault_Handler(void)
{
  /* Go to infinite loop when Hard Fault exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles Memory Manage exception.
  * @param  None
  * @retval None
  */
void MemManage_Handler(void)
{
  /* Go to infinite loop when Memory Manage exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles Bus Fault exception.
  * @param  None
  * @retval None
  */
void BusFault_Handler(void)
{
  /* Go to infinite loop when Bus Fault exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles Usage Fault exception.
  * @param  None
  * @retval None
  */
void UsageFault_Handler(void)
{
  /* Go to infinite loop when Usage Fault exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles SVCall exception.
  * @param  None
  * @retval None
  */
void SVC_Handler(void)
{
}

/**
  * @brief  This function handles Debug Monitor exception.
  * @param  None
  * @retval None
  */
void DebugMon_Handler(void)
{
}

/**
  * @brief  This function handles PendSVC exception.
  * @param  None
  * @retval None
  */
void PendSV_Handler(void)
{
}

/**
  * @brief  This function handles SysTick Handler.
  * @param  None
  * @retval None
  */
void SysTick_Handler(void)
{

}

void EXTI0_IRQHandler(void)   // EXTI0_IRQHandler 是宏定义,真实的函数名不是它,真正的函数名在启动文件中,TIP:中断函数都在中断向量表里面可以找到
{
        //ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
    if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET)
    {
        LED1_TOGGLE;
        EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE); //清除中断标志位,Q:EXTI_ClearITPendingBit() 和 EXTI_ClearFlag() 函数的区别?
    }

}

void EXTI15_10_IRQHandler(void)
{
        //ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
    if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET)
    {
        LED2_TOGGLE;
        EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE); 
    }

}

/******************************************************************************/
/*                 STM32F4xx Peripherals Interrupt Handlers                   */
/*  Add here the Interrupt Handler for the used peripheral(s) (PPP), for the  */
/*  available peripheral interrupt handler's name please refer to the startup */
/*  file (startup_stm32f4xx.s).                                               */
/******************************************************************************/

/**
  * @brief  This function handles PPP interrupt request.
  * @param  None
  * @retval None
  */
/*void PPP_IRQHandler(void)
{
}*/

/**
  * @}
  */ 

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

注意:细心。。。。这个BUG我找了半天。。由于是宏定义,编译器又不报错。。。

file

10讲 系统定时器 SysTick

file

  • SysTick 功能框图

    file

  1. 重装载寄存器------24位

    file

  2. 当前数值寄存器----读这个数会表示当前计数器这个值

file

  1. SysTick 控制及状态寄存器
    file

STK_CTRL 控制及状态寄存器

file

SysTick 唯一的固件库函数

file

  • 此处 1UL << __NVIC_PRIO_BITS 这个宏定义代表4,此处是1 左移 4位,上图的这行代码代表将优先级数字置为最高(即优先级最低)。(上一章节有讲,优先级由4个二进制数组成,优先级数字越高,则优先级越低)

SysTick 例程

file

实验要求:让SysTick 产生1s 的定时,让LED亮灭。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇