STM32学习笔记——外部中断EXTI
Created on: 2012-10-30
Author: zhang bin
学习笔记
for STM32F103C8
redesigned by zhang bin
2012-10-30
versions:V-0.1
All Rights Reserved
main.c如下,注释的比较详细,把下面的例子即说明都看明白基本上就可以用了:
//抢占级别高的会打断其他中断优先执行,而响应级别高的会在其他中断执行完优先执行。
//EXTI:外部中断/事件控制器
//EXTI控制器可以产生高达19个软件事件/中断请求
//将19根线配置为中断源,将19根线配置为事件源,将19根线配置为软件中断/事件线,详见《STM32F103xxx使用手册》
//P135
//在这个文件中主要是进行各种初始化配置,包括GPIO配置、EXTI配置、系统时钟配置等
//中断服务程序则在stm32f10x_it.c文件中,该文件提供所有异常处理程序和外围中断服务程序的模板,详见该文件
#include "stm32f10x_lib.h"
EXTI_InitTypeDef EXTI_InitStructure; //定义外部中断初始化结构体变量 内部含有4个成员 详见EXTI_InitTypeDef的定义
ErrorStatus HSEStartUpStatus;
//定义错误状态变量,是枚举类型
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
int main(void)
{
#ifdef DEBUG
debug();
#endif
RCC_Configuration();
//系统时钟配置
NVIC_Configuration();
//NVIC配置
GPIO_Configuration(); //配置GPIO
//STM32的外部中断不是固定的,是可以映射的。如EXTI6既可以映射到PB6也可以映射到PA6,详见外部中断/事件与GPIO的映射关系
//将IO端口注册至中断线(将IO口映射到中断线N)
//
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource6); //选择GPIO管脚用作外部中断线路
//第一个参数选择用作外部中断线源的GPIO端口 第二个参数是待设置的外部中断线路,可以是GPIO_PinSourcex(x可以0~15)
//配置按钮中断线触发方式
设置中断配置结构体成员
EXTI_InitStructure.EXTI_Line = EXTI_Line6;
//选择外部中断线 EXTI_Line0~EXTI_Line18共19根线
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
//设置为中断请求,可以为EXTI_Mode_Interrupt中断请求或者
//EXTI_Mode_Event事件请求
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //触发方式下降沿触发 还可以为EXTI_Trigger_Rising上升沿触发或者
//EXTI_Trigger_Rising_Falling上升沿下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //中断线使能 ENABLE使能,DISABLE失能
EXTI_Init(&EXTI_InitStructure); //根据参数结构体初始化EXTI中断
EXTI_GenerateSWInterrupt(EXTI_Line6); //产生一个软件中断 EXTI_Line6中断允许
//到此中断配置完成,可以写中断处理函数。
while (1)
{
}
}
void RCC_Configuration(void)
{
//复位RCC外部设备寄存器到默认值
RCC_DeInit();
//打开外部高速晶振
RCC_HSEConfig(RCC_HSE_ON);
//等待外部高速时钟准备好
HSEStartUpStatus = RCC_WaitForHSEStartUp();
//外部高速时钟已经准别好
if(HSEStartUpStatus == SUCCESS)
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
//配置AHB(HCLK)时钟=SYSCLK
RCC_HCLKConfig(RCC_SYSCLK_Div1);
//配置APB2(PCLK2)钟=AHB时钟
RCC_PCLK2Config(RCC_HCLK_Div1);
//配置APB1(PCLK1)钟=AHB 1/2时钟
RCC_PCLK1Config(RCC_HCLK_Div2);
//配置ADC时钟=PCLK2 1/4
RCC_ADCCLKConfig(RCC_PCLK2_Div4);
//配置PLL时钟 == 外部高速晶体时钟*9
8MHz*9MHz=72MHz
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
//配置ADC时钟= PCLK2/4
RCC_ADCCLKConfig(RCC_PCLK2_Div4);
//使能PLL时钟
RCC_PLLCmd(ENABLE);
//等待PLL时钟就绪
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
//配置系统时钟 = PLL时钟
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
//检查PLL时钟是否作为系统时钟
while(RCC_GetSYSCLKSource() != 0x08)
{
}
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_GPIOB
| RCC_APB2Periph_AFIO, ENABLE);
//使能GPIOA,GPIOB和AFIO的APB2
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义配置GPIO的结构体
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
//选中第8个脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);
//用配置好的结构体初始化GPIOB
PB8用于驱动led
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
//选中6脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
//配置浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure);
//初始化GPIOB
PB6脚连接外部中断线6的中断源
//所有的端口都有外部中断的能力,为了使用外部中断线,端口必须配置为输入模式
}
void NVIC_Configuration(void) //配置嵌套向量中断控制器
{
NVIC_InitTypeDef NVIC_InitStructure;//定义初始化NVIC的结构体变量
#ifdef VECT_TAB_RAM
//配置向量表基址
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); //分配中断向量表
#else
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //设置中断优先级
//设置优先级分组:先占优先级和从优先级 输入参数设定优先级分组位长度 本例中NVIC_PriorityGroup_1:先占优先级1为,从优先级3位
//详见《STM32函数说明》P165
//优先级分组只能设定一次
//EXTI5-9共用一个中断源,EXTI10-15共用一个中断源
//详见详见《STM32函数说明》P166
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel; //中断通道 指定IRQ通道
这里指定外部中断线9-5中断 因为使用的是EXTI6
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //设定指定IRQ通道的先占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//设定指定IRQ通道的从优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //设定指定IRQ通道中断使能 DISABLE失能
NVIC_Init(&NVIC_InitStructure);//根据结构体中指定的参数初始化NVIC中断
}
#ifdef DEBUG
void assert_failed(u8* file, u32 line)
{
while (1)
{
}
}
#endif
stm32f10x_it.c文件中的中断服务函数如下:
void EXTI9_5_IRQHandler(void)
//外线路5-9的中断处理程序
{
if(EXTI_GetITStatus(EXTI_Line6) != RESET) //检测制定的EXTI6线路触发请求是否发生。
//该函数检查指定的EXTI线路出发请求是否发生
{
//其实就是对PB8取反
GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)((1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_8))));
//该函数可以对指定的端口位进行操作 指定端口和位,然后指定操作。第三个参数指定待写入的值
//该参数必须取枚举类型BitAction的其中一个值,可以是Bit_RESET:清除数据端口位和Bit_SET:设置数据端口位
//GPIO_ReadOutputDataBit()函数读取指定的IO端口管脚的输出,参数指定端口和位
//EXTI_ClearFlag(EXTI_Line6); //清除中断标志位(必须) 我在网上看到要求必须,但是在本例中并没有这句
EXTI_ClearITPendingBit(EXTI_Line6); //清除EXTI线路挂起位
}
}