这是系统外设和系统配置管理。
打开它后可以看到对应的英文:This file provides firmware functions to manage the SYSCFG peripheral.也就是这个文档提供固件函数去处理系统配置(SYSCFG =system config)的外设。往下拉会看到如下英文,顺便给你翻译下:
This driver provides functions for:
(#) Remapping the memory accessible in the code area using SYSCFG_MemoryRemapConfig()(使用SYSCFG_MemoryRemapConfig函数重映射在代码区域的可访问存储区)
(#) Swapping the internal flash Bank1 and Bank2 this features is only visible for
STM32F42xxx/43xxx devices Devices. (交换外部flash的bank1和bank2,不过这个功能只能用在STM32F42xxx/43xxx 系列)
(#) Manage the EXTI lines connection to the GPIOs using SYSCFG_EXTILineConfig()(使用SYSCFG_EXTILineConfig管理外部中断线和GPIO的链接)
(#) Select the ETHERNET media interface (RMII/RII) using SYSCFG_ETH_MediaInterfaceConfig()(使用SYSCFG_ETH_MediaInterfaceConfig函数选择以太网设备接口)
-@- SYSCFG APB clock must be enabled to get write access to SYSCFG registers,
using RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);(使用RCC_APB2PeriphClockCmd函数开启syscfg时钟,只有这样才能访问SYSCFG 寄存器)
总之打开固件文档后你都会知道它是干嘛的
MCS-51系列单片机各中断源的入口地址由硬件事先设定,分配如下:中断源入口地址外部中断0----0003H定时器T0中断----000BH外部中断1----0013H定时器T1中断----001BH串行口中断----0023H使用时,通常在这些中断入口地址处存放一条绝对跳转指令,使程序跳转到用户安排的中断服务程序的起始地址上去。
给你发个相关的配置外部中断的寄存器版函数,你可以参考下:
//外部中断配置函数
//只针对GPIOA~I;不包括PVD,RTC,USB_OTG,USB_HS,以太网唤醒等
//参数:
//GPIOx:0~8,代表GPIOA~I
//BITx:需要使能的位;
//TRIM:触发模式,1,下升沿;2,上降沿;3,任意电平触发
//该函数一次只能配置1个IO口,多个IO口,需多次调用
//该函数会自动开启对应中断,以及屏蔽线
void Ex_NVIC_Config(u8 GPIOx,u8 BITx,u8 TRIM)
{
u8 EXTOFFSET=(BITx%4)*4;
RCC-APB2ENR|=114; //使能SYSCFG时钟
SYSCFG-EXTICR[BITx/4]=~(0x000FEXTOFFSET);//清除原来设置!!!
SYSCFG-EXTICR[BITx/4]|=GPIOxEXTOFFSET; //EXTI.BITx映射到GPIOx.BITx
//自动设置
EXTI-IMR|=1BITx; //开启line BITx上的中断(如果要禁止中断,则反操作即可)
if(TRIM0x01)EXTI-FTSR|=1BITx; //line BITx上事件下降沿触发
if(TRIM0x02)EXTI-RTSR|=1BITx; //line BITx上事件上升降沿触发
}
寄存器配置一定要看手册来配,不然谁会
STM32的GPIO多很多,所有的GPIO口都可用作外部中断,但同组的只能选择一个,如GPIOA的第1脚与其他都是1脚(如GPIOC的第一脚)的归为一组,所以SYSCFG-EXTICR[0] = ~(0x0f (0 * 4));这句是来配置外部中断0的中断线选择GPIOA的,即GPIOA的第0脚;
EXTICR[0]是选择外部中断0到3的,其他以此类推。
例如你的按键为PC5,则你选择外部中断5,
SYSCFG-EXTICR[1] = ~(0x0f (1 * 4));
配置成上升沿触发EXTI-RTSR |= 1 5;
或者配置成下降沿触发EXTI-FTSR |= 1 5;
或者两者都行,这需要看你的外部电路,按下由低电平转高则选上升沿
最后开放对应中断线的请求EXTI-IMR |= 1 5;
后面那几行根据你的要求写中断分组,中断优先级,最后写你的中断函数
具体情况具体对待,你可以看我下面的实验对号入座来分析你的问题:
实验目的:
当按键按下时,让PF10引脚的LED灯亮,
当按键再次按下时,让PF10引脚的LED灯灭;
无论按下与否,PF9引脚的LED灯循环闪烁;
实验步骤:
实验程序:
[cpp] view plain copy
/***********************************led.c*********************************/
#include "stm32f4xx.h" //在SYSTEM目录下可以找到
#include "sys.h"
void LED_Init(void){
RCC-AHB1ENR = 15; //使能GPIO端口的F时钟
GPIO_Set(GPIOF,PIN9|PIN10,GPIO_MODE_OUT,GPIO_OTYPE_PP,GPIO_SPEED_25M,GPIO_PUPD_PU);
PFout(9) = 1;
PFout(10) = 1;
}
[cpp] view plain copy
/***********************************led.h*********************************/
#ifndef _LED_H
#define _LED_H
void LED_Init(void);
#endif
[cpp] view plain copy
/********************************************key.c***************************************/
#include "sys.h"
void Key_Init(void){
RCC-AHB1ENR|=14; //使能PORTE时钟
//void GPIO_Set(GPIO_TypeDef* GPIOx,u32 BITx,u32 MODE,u32 OTYPE,u32 OSPEED,u32 PUPD);//GPIO设置函数
GPIO_Set(GPIOE,PIN3,GPIO_MODE_IN,0,0,GPIO_PUPD_PU); //PE3设置上拉输入,这样的话,
//当按键没有按下时,默认电平为高;
}
[cpp] view plain copy
/********************************************key.h***************************************/
#ifndef _KEY_H
#define _KEY_H
void Key_Init(void);
#endif
[cpp] view plain copy
/************************************exti.c********************************/
#include "sys.h"
#include "delay.h"
#include "stm32f4xx.h"
/*
本示例的作用就是,
当按键按下时,蜂鸣器发出声音,
当按键再次按下时,蜂鸣器静音;
*/
/*
中断初始化函数:
主要是关于寄存器的相关配置
*/
void EXTI3_Init(void){
//方法一:
RCC-APB2ENR |= 1 14; //开启SYSCFG时钟
SYSCFG-EXTICR[0] |= 0x4 12;//设置IO口与中断线的映射关系;
EXTI-IMR |= 1 3; //开启对应中断线上的中断
EXTI-FTSR |= 1 3; //设置中断触发条件
//SCB和NVIC,可参考STM32F3与STM32F4系列Cortex M4内核编程手册.pdf
SCB-AIRCR |= 0x5 8; //设置分组
NVIC-IP[9] |= 0; //设置优先级,具体可分析MY_NVIC_Init()函数;
NVIC-ISER[0] |= 1 9; //使能中断;
//方法二:
/************************************
使用SYSTEM目录下提供的API来实现,
具体可参考正点原子示例
************************************/
}
void EXTI3_IRQHandler(void){
/*
此按键,在按键按下时,处理不是很到位,
有待进一步改进,主要是在连按那一个环节。
*/
delay_ms(20); //消抖
if(PEin(3) == 0){
PFout(10) = !PFout(10);
}
/*
在中断里边最后记得清中断:
*/
EXTI-PR |= 1 3;
}
[cpp] view plain copy
/*************************************exti.h*******************************/
#ifndef _EXTI_H
#define _EXTI_H
void EXTI3_Init(void);
#endif
[cpp] view plain copy
/*************************************test.c*******************************/
#include "sys.h"
#include "delay.h"
#include "key.h"
#include "beep.h"
#include "exti.h"
#include "led.h"
//int i = 0;
int main(void){
Stm32_Clock_Init(336,8,2,7);//设置时钟,168Mhz
delay_init(168); //初始化延时函数
Beep_Init();
Key_Init();
EXTI3_Init();
LED_Init();
while(1){
PFout(9) = 0;
delay_ms(500);
PFout(9) = 1;
delay_ms(500);
}
}
实验分析:
我们主要分析一下exti.c中的寄存器设置的这几个步骤:
1. RCC-APB2ENR |= 1 14;
这一步的作用就是使能SYSCFG时钟,
在使用外部中断的时候一定要先使能SYSCFG时钟;
2. SYSCFG-EXTICR[0] |= 0x4 12;
这一步的作用就是设置IO口与中断线的映射关系;
那么问题来了,我如何知道的我的IO口与哪根中断线是关联起来的呢?
而我们是通过KEY1按键,对应的IO口就是PE3,所以由上图的映射关系,我们知道,我们应该选择中断线3与之对应;
在官方提供的头文件stm32f4xx.h中,我们可以看到:
[cpp] view plain copy
typedef struct
{
__IO uint32_t MEMRMP; /*! SYSCFG memory remap register, Address offset: 0x00 */
__IO uint32_t PMC; /*! SYSCFG peripheral mode configuration register, Address offset: 0x04 */
__IO uint32_t EXTICR[4]; /*! SYSCFG external interrupt configuration registers, Address offset: 0x08-0x14 */
uint32_t RESERVED[2]; /*! Reserved, 0x18-0x1C */
[cpp] view plain copy
__IO uint32_t CMPCR; /*! SYSCFG Compensation cell control register, Address offset: 0x20 */
SYSCFG_TypeDef;
结合上述三幅图,我们可以得知:
由于PE3对应的中断线为EXTI3,所以,我们我们这里仅需配置EXTI3,而EXTI3是在SYSCFG_EXTICR1中的;
所以我们仅需配置SYSCFG_EXTICR1寄存器的12位-15位为0100,而SYSCFG_EXTICR1寄存器在配置文件中,
对应的是SYSCFG-EXTICR[0],所以我们就写成了SYSCFG-EXTICR[0] |= 0x4 12;
3. EXTI-IMR |= 1 3;
这条语句的作用就是:开启对应中断线上的中断
由于我们操作的中断线是EXTI3,而IMR寄存器各位解释如下:
所以对应的,我们操作EXTI_IMR寄存器的第3位MR3即可;
所以这条语句就写成了:EXTI-IMR |= 1 3
4. EXTI-FTSR |= 1 3;
这条语句的作用就是设置中断触发条件;
在我的开发板中,当按键按下时,其端口就会变成低电平,在没有按下时,其是为高电平的;
因为我们key.c中,将按键的引脚设置成了上拉;所以在这里,我得将其设置成下降沿触发;
与此同时,查看EXTI_FTSR寄存器,可以看到:
又由于我们这条中断线是中断线3,所以这条语句就写成了:EXTI-FTSR |= 1 3
5. SCB-AIRCR |= 0x5 8;
这条语句的作用就是:设置分组;
所以,在这里我们只需设置SCB的AIRCR的 bit10-8即可;查看SCB的结构体,得知:
[cpp] view plain copy
typedef struct
{
__I uint32_t CPUID; /*! Offset: 0x000 (R/ ) CPUID Base Register */
__IO uint32_t ICSR; /*! Offset: 0x004 (R/W) Interrupt Control and State Register */
__IO uint32_t VTOR; /*! Offset: 0x008 (R/W) Vector Table Offset Register */
__IO uint32_t AIRCR; /*! Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */
__IO uint32_t SCR; /*! Offset: 0x010 (R/W) System Control Register */
__IO uint32_t CCR; /*! Offset: 0x014 (R/W) Configuration Control Register */
__IO uint8_t SHP[12]; /*! Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */
__IO uint32_t SHCSR; /*! Offset: 0x024 (R/W) System Handler Control and State Register */
__IO uint32_t CFSR; /*! Offset: 0x028 (R/W) Configurable Fault Status Register */
__IO uint32_t HFSR; /*! Offset: 0x02C (R/W) HardFault Status Register */
__IO uint32_t DFSR; /*! Offset: 0x030 (R/W) Debug Fault Status Register */
__IO uint32_t MMFAR; /*! Offset: 0x034 (R/W) MemManage Fault Address Register */
__IO uint32_t BFAR; /*! Offset: 0x038 (R/W) BusFault Address Register */
__IO uint32_t AFSR; /*! Offset: 0x03C (R/W) Auxiliary Fault Status Register */
__I uint32_t PFR[2]; /*! Offset: 0x040 (R/ ) Processor Feature Register */
__I uint32_t DFR; /*! Offset: 0x048 (R/ ) Debug Feature Register */
__I uint32_t ADR; /*! Offset: 0x04C (R/ ) Auxiliary Feature Register */
__I uint32_t MMFR[4]; /*! Offset: 0x050 (R/ ) Memory Model Feature Register */
__I uint32_t ISAR[5]; /*! Offset: 0x060 (R/ ) Instruction Set Attributes Register */
uint32_t RESERVED0[5];
__IO uint32_t CPACR; /*! Offset: 0x088 (R/W) Coprocessor Access Control Register */
} SCB_Type;
所以,在这里,我们把这条语句写成了SCB-AIRCR |= 0x5 8;
亦即设置成了101,也就是抢占优先级占2位,响应优先级占2位;
注:抢占优先级和响应优先级一样,其值越低则表示其优先级越高;
上述说的子优先级也就是我们说的响应优先级;
6. NVIC-IP[9] |= 0;
有上条语句,我们可以得知:IP寄存器由240个8bit的寄存器组成,每个可屏蔽中断占用8bit,这样总共可以表示240个可屏蔽中断,
而STM32F4只用到了其中的82个。IP[81]~IP[0]分别对应中断81~0.而每个可屏蔽中断占用的8bit并没有全部使用,而是只用了高4位;
这4位,又分为抢占优先级和响应优先级;抢占优先级在前,响应优先级在后;也就是说,抢占优先级在高位,响应优先级在低位;
而我们又知道:我们这个中断是外部中断3,所以查看中断向量表可知:
由此可知,EXTI3在中断的位置为9,所以我们只需要设置NVIC-IP[9] 即可;
在这里我们把NVIC-IP[9] |= 0;则表示,我们设置外部中断3的抢占优先级为0,响应优先级也为0,其各占2位;
7. NVIC-ISER[0] |= 1 9;
这一步的作用就是使能中断;
ISER是一个中断使能寄存器组;这里用8个32位寄存器来控制,每个位控制一个中断;但是STM32F4的可屏蔽中断
最多只有82个,所以对我们来说,有用的就是三个(ISER[0~2]),总共可以表示96个中断;而STM32F4只用了其中的
前82个中断,ISER[0]的0bit~31分别对应中断0~31;ISER[1]的bit0~32对应中断32~63;ISER[2]的bit0~32对应中断64~81;
在这里,我们知道:我们的EXTI3对应的中断的位置是9,所以我们只需设置ISER[0]的第9位即可;所以我们在这里就将这条
语句写成了:NVIC-ISER[0] |= 1 9;
8.至于外部中断函数的名称如何编写,我们可以从启动文件中去找到;
当我们设置的外部中断函数与启动文件中定义的名称一致时,
那么当这个中断条件满足时,就会去中断函数里边执行其函数体;
我们只需要在中断发生后,记得清中断,防止中断重复发生;
注意事项:
在本实验中,关于按键处理那一块,处理不是很到位,
主要应该是处在连按这一块,暂时没去整它,待我需要时,再去整整。
转载于 ,感谢原作者非常详细的指导学习。
STM32 中断初识
前段时间经常用stm32f4 discovery,但是因为对NVIC , EXTI不是很了解,所以使用的过程中一直都在避免使用中断,这两天没什么事决定来学习一下stm32 的中断,写一下自己的心得,如有谬误之处,欢迎指正。
我把用到的几份文档寄存器的文档(RM0090)、《Cortex-M技术参考手册》、《Cortex™-M4 Devices Generic User Guide》、《ARMv7-M Architecture Reference Manual》放在百度云,需要的自取
密码:4g91网页链接
本文标签:stm32中syscfg