外部中断实验:
本次实验是在基础工程建立的基础上进行的
点击跳转: 基础项目建立
题目:
PB8、 PB0作为中断请求输入端,PA0-PA7作为推挽输出,输出速度50MHz, 接8个LED灯。主程序实现的功能:8个LED灯流水显示。中断服务程序实现的功能-EXTI8:高4位、低4位LED灯交替闪6次。EXTI0:8位LED灯全闪4次。 EXTI0可以嵌套EXTI8。
题目详解:
- PB8、PB0作为中断请求输入端:GPIOB的引脚8和0设置为输入端
- PA0-PA7作为推挽输出,输出速度50MHz, 接8个LED灯:对GPIOA设置
- 8个LED灯流水显示:对PA0-PA7操作
- 中断服务程序实现的功能-EXTI8:高4位、低4位LED灯交替闪6次:PA0~ PA3 与 PA4~ PA7交替闪烁六次
- EXTI0:8位LED灯全闪4次:PA0-PA7闪四次
- EXTI0可以嵌套EXTI8:引脚0的抢占优先级比引脚8的高(当8执行后立即执行0,0的操作会抢断8,会先执行0然后再会到8)
工程文件简介:
-
CMSIS
(1)core_cm3.c:提供ARM Cortex-M3内核的接口,管理内核的控制和协调。
(2)system_stm32f10x.c:设置系统时钟和总线时钟,配置STM32的启动和外设寄存器。 -
Library
(1)stm32f10x_flash.c:管理STM32的闪存操作,如擦除、编程和读取数据。
(2)stm32f10x_gpio.c:控制STM32的通用输入/输出(GPIO)引脚,读取或设置其状态。
(3)stm32f10x_rcc.c:配置和管理STM32的复位和时钟控制(RCC),包括系统时钟、时钟源和分频。
(4)misc.c:包含一些杂项功能,如初始化函数和延迟函数。
(5)stm32f10x_exti.c:管理STM32的外部中断(EXTI),配置、触发或处理外部中断。 -
STARTUP
(1)startup_stm32f10x_hd.s:初始化处理器和设置堆栈的启动文件。 -
USER
(1)stm32f10x_it.c:处理STM32的中断,包括配置、触发或处理中断。
(2)stm32f10x_conf.h:包含STM32的一些配置选项,如系统时钟频率和外设时钟频率。
实验过程
1.在基础项目建立的项目上再添加两个文件:
2.配置User中的main.c文件
/*Include---------------------------*/
#include"stm32f10x.h" // 包含所需的STM32F10x系列的头文件
#include<stdio.h>
//----------------函数声明--------------------
void Delay_MS(u16 dly); // 声明延迟函数,以毫秒为单位
void RCC_Configuration(void); // 声明系统时钟配置函数
void GPIO_Configuration(void); // 声明GPIO配置函数
void EXTI_Configuration(); // 声明外部中断配置函数
void NVIC_Configuration(); // 声明中断向量表配置函数
/*******************************************************************************
* Function Name : main
* Description : 主程序。
* Input : None
* Output : None
* Return : None
*******************************************************************************/
int main(void)
{
/* ------------- 从这里开始 -------------- */
u8 i; // 定义一个8位无符号整数变量 i
RCC_Configuration(); // 调用系统时钟配置函数
GPIO_Configuration(); // 调用GPIO配置函数
EXTI_Configuration(); // 调用外部中断配置函数
NVIC_Configuration(); // 调用中断向量表配置函数
while(1) // 无限循环
{
for(i=0;i<8;i++){ // 循环8次,控制GPIO输出
GPIO_Write(GPIOA,0x01<<i); // 在GPIOA端口写入一个值,控制LED等输出
Delay_MS(500); // 延迟500毫秒
}
}
/* ------------- 从这里结束 -------------- */
}
/*******************************************************************************
* Function Name : Delay_Ms
* Description : 延迟1毫秒。
* Input : dly (毫秒)
* Output : None
* Return : None
*******************************************************************************/
void Delay_MS(u16 dly)
{
u16 i, j;
for(i=0; i<dly; i++) // 外层循环,用于控制延迟的次数
for(j=1000; j>0; j--); // 内层循环,用于实现延迟
}
/*******************************************************************************
* Function Name : RCC_Configuration
* Description : 配置不同的系统时钟。
* Input : None
* Output : None
* Return : None
*******************************************************************************/
// 系统时钟配置函数
void RCC_Configuration(void)
{
//----------启用外部RC振荡-----------
RCC_DeInit(); // 将时钟配置为复位值
RCC_HSEConfig(RCC_HSE_ON); // 启用外部高速振荡器
while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); // 等待外部高速振荡器就绪
// 配置FLASH存储器
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); // 启用预取缓冲区
FLASH_SetLatency(FLASH_Latency_2); // Flash存储器延迟为2个等待周期
// 配置时钟分频系数
RCC_HCLKConfig(RCC_SYSCLK_Div1); // HCLK = SYSCLK
RCC_PCLK2Config(RCC_HCLK_Div1); // PCLK2 = HCLK
RCC_PCLK1Config(RCC_HCLK_Div2); // PCLK1 = HCLK/2
// 配置PLL时钟
RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9); // PLLCLK = 8MHz * 9 = 72MHz
RCC_PLLCmd(ENABLE); // 启用PLLCLK
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); // 等待PLLCLK就绪
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // 选择PLL作为系统时钟
while(RCC_GetSYSCLKSource()!=0x08); // 等待PLL作为系统时钟源生效
// 启用GPIOA和GPIOB的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); // 启用APB2外设GPIOA的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); // 启用APB2外设GPIOB的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); // 启用AFIO的时钟
}
/* ------------- 从这里开始 -------------- */
// GPIO配置函数
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO;
// 配置PA0~PA7引脚为推挽输出模式,最大输出速率为50MHz
GPIO.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO.GPIO_Speed = GPIO_Speed_50MHz; //输出速率为50MHz
GPIO.GPIO_Mode = GPIO_Mode_Out_PP; // 将PA0~PA7引脚设置为推挽输出模式
GPIO_Init(GPIOA , &GPIO); // 初始化GPIOA
// 配置PB8和PB0引脚为带上拉输入模式 // 配置PB8和PB0
GPIO.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_8;
GPIO.GPIO_Mode = GPIO_Mode_IPU; // 将PB8和PB0引脚为带上拉输入模式
GPIO_Init(GPIOB , &GPIO); // 初始化GPIOB
}
// 外部中断配置函数
void EXTI_Configuration(void)
{
EXTI_InitTypeDef EXTI_InitStructure; // 定义结构体变量
// 配置外部中断线8(对应PB8引脚)
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource8); // 将GPIOB引脚8配置为外部中断线
EXIT_Delnit(); // 对外部终端初始化,清除引脚的引用
EXTI_InitStructure.EXTI_Line = EXTI_Line8; // 将GPIOB的引脚8设置为外部中断线
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // 中断模式 (还有事件模式)
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发模式(有高电平转换为低电平) (还有上升言模式、上升下降沿模式)
EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 指定启用外部中断线,允许相应的中断请求触发
EXTI_Init(&EXTI_InitStructure); // 初始化外部中断控制器的配置
// 配置外部中断线0(对应PB0引脚)
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0); // 将GPIOB引脚0配置为外部中断线
EXTI_InitStructure.EXTI_Line = EXTI_Line0; // 将GPIOB的引脚0设置为外部中断线
EXTI_Init(&EXTI_InitStructure); // 初始化外部中断控制器的配置
}
// 中断向量表配置函数
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure; // 定义结构体变量
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); // 设置优先级分组为第一组
// 配置外部中断9到5的中断通道
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; // 配置的是外部中断线9到5的中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 设置抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 设置响应优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 启用该中断通道
NVIC_Init(&NVIC_InitStructure); // 初始化嵌套向量中断控制器
// 配置外部中断0的中断通道
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; // 配置的是外部中断线0的中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 设置抢占优先级为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 设置响应优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 启用该中断通道
NVIC_Init(&NVIC_InitStructure); // 初始化嵌套向量中断控制器
}
/* ------------- 从这里结束 -------------- */
3.配置User中的stm32f10x_it.c
/**
******************************************************************************
* @file Project/STM32F10x_StdPeriph_Template/stm32f10x_it.c
* @author MCD Application Team
* @version V3.5.0
* @date 08-April-2011
* @brief Main Interrupt Service Routines.
* This file provides template for all exceptions handler and
* peripherals interrupt service routine.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_it.h"
/** @addtogroup STM32F10x_StdPeriph_Template
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/******************************************************************************/
/* Cortex-M3 Processor Exceptions Handlers */
/******************************************************************************/
// Cortex-M3 处理器的异常处理函数
/**
* @brief This function handles NMI exception.
* @param None
* @retval None
*/
void NMI_Handler(void)
{
// 处理 NMI 异常
}
// ...(其他异常处理函数,如 HardFault_Handler、MemManage_Handler等)
/******************************************************************************/
/* STM32F10x Peripherals Interrupt Handlers */
/******************************************************************************/
// STM32F10x 外设的中断处理函数
/**
* @brief EXTI9_5_IRQHandler 处理外部中断线5到9的中断。
* @param None
* @retval None
*/
// 当EXTI9-5的中断发生时,会调用这个中断处理函数
void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetFlagStatus(EXTI_Line8) != RESET) // 检查Line8(即Pin8上的外部中断)是否被触发。如果已经触发,会返回一个非零值
{
u8 i; // 定义一个8位无符号整数变量i,用于循环控制
for(i=0; i<6; i++){ // 对i进行一个从0到5的循环
GPIO_Write(GPIOA, 0x0F); // 高四位灯亮
Delay_MS(500); // 延迟500毫秒,让LED灯亮起来。
GPIO_Write(GPIOA, 0xF0); // 低四位灯灭
Delay_MS(500);
}
}
EXTI_ClearFlag(EXTI_Line8); // 清除Line8的中断标志,意味着我们处理了这次中断,不会再被这个中断再次打断
}
/**
* @brief EXTI0_IRQHandler 处理外部中断线0的中断。
* @param None
* @retval None
*/
void EXTI0_IRQHandler(void)
{
if (EXTI_GetFlagStatus(EXTI_Line0) != RESET) { // 检查Line8(即Pin8上的外部中断)是否被触发。如果已经触发,会返回一个非零值
u8 i; // 定义一个8位无符号整数变量i,用于循环控制
for (i = 0; i < 4; i++) {
GPIO_Write(GPIOA, 0xFF); // 所有灯全亮
Delay_MS(2000);
GPIO_Write(GPIOA, 0x00); // 所有灯全灭
Delay_MS(2000);
}
}
EXTI_ClearFlag(EXTI_Line0); // 清除Line8的中断标志,意味着我们处理了这次中断,不会再被这个中断再次打断
}
4.编译,选择main.c,点击编译(第一次出错可能,再编译一次):
5.编译成功:
6.仿真:
7.打开GPIOA(输出),GPIOB(输入)
8.运行:
9.调试:
9.1 P0功能测试:
9.2 P8功能测试