[TOC]
stm32学习笔记001
新建keil5工程
- 装好keil5
- project->new..project,选择目标文件夹
- 选好后把stm32库文件中有关启动和各种库粘贴到starup文件夹下;
- 在魔术棒->c/c++里面,添加define 为USE_STDPERIPH_DRIVER,,并把library文件夹添加到includepath里
寄存器点灯(任务1.1)
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include "stm32f10x.h" int main() { RCC->APB2ENR = 0x00000008; GPIOB->CRL = 0x00300033; GPIOB->ODR = 0x00000000; while(1); }
|
代码解析:
- RCC->APB2ENR = 0x00000008;
RCC代表寄存器,APB2ENR代表APB2外设时钟使能寄存器

要想使用各个外设(定义见文末附录),就要先把这个外设使能
有官方手册可看出,GPIOB口在APB2中使能,且在“3”编号上,把3这个编号赋值1,其他为0,四个一组转换成16进制,得出0x00000008;

GPIOx_CRL: 1.x:GPIO 后面的字母 2.CRL的L:LOW,代表低寄存器(H代表高)

ODR的O:output

库函数点灯(任务1.2):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,ENABLE);
GPIO_InitTypeDef GPIO_InitStructurePF11;
GPIO_InitStructurePF11.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructurePF11.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructurePF11.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOF,&GPIO_InitStructurePF11);
GPIO_ResetBits(GPIOF,GPIO_Pin_11);
|
涉及的可选参数详见附录

GPIO输入输出(任务2)
读取输入的方法
读取输入寄存器(IDR)
1 2 3 4 5 6 7 8 9 10 11 12
|
int pinState;
pinState = (GPIOF->IDR & GPIO_PIN_x) ? 1 : 0;
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==Bit_RESET) { }
|
读取输出寄存器(ODR)
1 2 3 4 5 6 7
| int pinState;
pinState = (GPIOF->ODR & GPIO_PIN_x) ? 1 : 0;
|
二者的区别
IDR反应实际物理状态,ODR反应代码设置的状态(不一定是实际)
假设有一个 GPIO 引脚配置为输出模式,在代码中设置了它为高电平,但这个引脚连接了一个外部电路,外部电路强行把这个引脚拉低了的话,二者的区别就会显现
- IDR:反映这个引脚的实际电平为低电平,因为它受到了外部电路的影响。
- ODR:仍然会反映你在代码中设置的高电平,因为它表示的是你通过 MCU 设置的输出值,而不是实际的电平。
延时函数的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| void SysTick_Init(void) { SysTick_Config(SystemCoreClock / 1000); }
volatile uint32_t sysTickCounter = 0;
void SysTick_Handler(void) { if (sysTickCounter > 0) { sysTickCounter--; } }
void Delay_ms(uint32_t ms) { sysTickCounter = ms; while (sysTickCounter != 0) { } }
|
具体过程如下:
sysTickCounter 被设置为延时的毫秒数。
每 1 毫秒,SysTick 触发中断,调用 SysTick_Handler() 函数,递减 sysTickCounter
因此,起到延时作用的是SysTick_Handler() 函数
当 sysTickCounter 减到 0 时,while 循环结束,延时函数完成。
SysTick_Handler() 只有在倒计时中每隔 1 毫秒被调用一次,并且只有在 sysTickCounter > 0 时它才会递减计数器。一旦计数器减到 0,SysTick_Handler() 仍然会被 1 毫秒触发一次,只不过它不再执行任何递减操作
总代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
| #include "stm32f10x.h"
void SysTick_Init(void) {
SysTick_Config(SystemCoreClock / 1000); }
volatile uint32_t sysTickCounter = 0;
void Delay_ms(uint32_t ms) { sysTickCounter = ms; while (sysTickCounter != 0) {
} }
int main(void) {
SysTick_Init();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_InitStructurePB0; GPIO_InitStructurePB0.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStructurePB0.GPIO_Pin=GPIO_Pin_0; GPIO_InitStructurePB0.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructurePB0);
GPIO_ResetBits(GPIOB,GPIO_Pin_0);
GPIO_InitTypeDef GPIO_InitStructurePB1; GPIO_InitStructurePB1.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStructurePB1.GPIO_Pin=GPIO_Pin_1; GPIO_InitStructurePB1.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructurePB1);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,ENABLE);
GPIO_InitTypeDef GPIO_InitStructurePF11; GPIO_InitStructurePF11.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructurePF11.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructurePF11.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOF,&GPIO_InitStructurePF11); GPIO_ResetBits(GPIOF,GPIO_Pin_11); GPIO_SetBits(GPIOB,GPIO_Pin_1);
while(1) { if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==Bit_RESET) { Delay_ms(1000); GPIO_ResetBits(GPIOB,GPIO_Pin_1); GPIO_SetBits(GPIOB,GPIO_Pin_0); Delay_ms(1000);
} else { GPIO_SetBits(GPIOB,GPIO_Pin_1); GPIO_ResetBits(GPIOB,GPIO_Pin_0);
} } }
|
外部中断
一个按键的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| #include "stm32f10x.h" #include <stdio.h> volatile uint32_t sysTickCounter = 0; void EXTI_Config(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOF,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.EXTI_Line=EXTI_Line0; EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; EXTI_Init(&EXTI_InitStructure); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; NVIC_Init(&NVIC_InitStructure); } void EXTI0_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line0)==SET) { if(GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_11)==Bit_SET) { GPIO_ResetBits(GPIOF,GPIO_Pin_11); } else { GPIO_SetBits(GPIOF,GPIO_Pin_11); } EXTI_ClearITPendingBit(EXTI_Line0); } }
int main(void) { EXTI_Config(); while(1) { }
}
|
两个按键的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| #include "stm32f10x.h" #include <stdio.h> volatile uint32_t sysTickCounter = 0; void EXTI_Config(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOF,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOF,&GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.EXTI_Line=EXTI_Line0; EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; EXTI_Init(&EXTI_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOF,GPIO_PinSource1); EXTI_InitStructure.EXTI_Line=EXTI_Line1; EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; EXTI_Init(&EXTI_InitStructure); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; NVIC_Init(&NVIC_InitStructure); } void EXTI0_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line0)==SET) { GPIO_ResetBits(GPIOF,GPIO_Pin_11); } EXTI_ClearITPendingBit(EXTI_Line0); }
void EXTI1_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line1)==SET) { GPIO_SetBits(GPIOF,GPIO_Pin_11); } EXTI_ClearITPendingBit(EXTI_Line1);
}
int main(void) { EXTI_Config();
while(1) {
}
}
|
视频:
一个按键的:
点击查看视频
两个按键的:
点击查看视频
附录(信息整合)
外设相关信息
------
### 2. **USART / UART(通用异步收发器)**
#### 功能:
USART(Universal Synchronous Asynchronous Receiver Transmitter)或 UART 是常用于串行通信的外设,支持异步和同步通信。它通常用于与计算机、外部模块或其他微控制器之间的通信。
#### 常见用途:
- **调试接口**:将调试信息发送到串口终端,帮助开发人员实时查看系统运行状态。
- **模块通信**:与蓝牙模块、GPS 模块、GSM 模块等外设进行数据交互。
- **设备通信**:与传感器、执行器、其他微控制器通信。
#### 特点:
- **波特率**:支持多种波特率设置(如 9600、115200),可以适应不同速度的通信需求。
- 数据格式
:灵活设置数据位、停止位、校验位等,适应不同协议需求。
- 常见配置:8 数据位、1 停止位、无校验位。
- **硬件流控**:支持 RTS/CTS 硬件流控,减少数据丢失风险,特别适合高速通信。
- **中断和 DMA 支持**:可以通过中断或 DMA 传输数据,减少 CPU 负担,提高系统效率。
- **多处理器模式**:允许多处理器间的串行通信,通过地址标识进行选择性通信。
#### 实际应用:
使用 STM32 的 `USART2` 端口与计算机串口终端通信,将传感器数据通过 UART 发送到终端,以进行实时监控。
------
### 3. **SPI(串行外设接口)**
#### 功能:
SPI(Serial Peripheral Interface)是一种高速的同步串行通信接口,通常用于与外部传感器、存储设备(如 EEPROM、Flash)和显示器等外设进行通信。STM32 的 SPI 接口支持全双工通信,可以同时发送和接收数据。
#### 常见用途:
- **存储器通信**:与 SPI 闪存或 EEPROM 进行高速读写操作。
- **显示器控制**:与 OLED、LCD 屏幕进行通信,快速刷新显示内容。
- **传感器数据读取**:获取 MEMS 传感器、加速度计、陀螺仪等传感器的数据。
- **音频模块**:通过 SPI 与音频芯片通信,进行音频数据的传输和控制。
#### 特点:
- **主从模式**:SPI 支持主从通信模式,STM32 可以配置为主设备或从设备。
- **高数据速率**:SPI 的通信速率可达几十 MHz,适合高速数据传输应用。
- **全双工通信**:支持同时发送和接收数据,适合需要高速双向通信的场景。
- **多从设备支持**:通过片选引脚(CS),可以连接多个从设备,灵活控制不同的外设。
#### 实际应用:
使用 STM32 作为主设备,通过 SPI 接口读取外部 EEPROM 的数据,或者驱动 OLED 显示屏显示图像数据。
------
### 4. **I2C(集成电路互联)**
#### 功能:
I2C 是一种常用的双线串行通信协议,适用于低速外围设备(如传感器、存储器、RTC 模块)的通信。它只需要两根线:SCL(时钟)和 SDA(数据),即可在多主多从架构中进行通信。
#### 常见用途:
- **传感器通信**:与温度传感器、压力传感器等低速设备通信。
- **存储器接口**:如 I2C EEPROM,用于存储配置信息或日志。
- **RTC(实时时钟)模块**:读取实时时钟的日期和时间信息。
- **显示模块**:驱动 I2C 协议的 OLED 或 LCD 显示屏。
#### 特点:
- **双线通信**:使用 SDA 和 SCL 两条线,减少通信接口数量。
- **多主多从支持**:允许多个设备同时连接到同一条总线上,支持多主设备通信。
- **地址识别**:每个从设备都有唯一的 7 位或 10 位地址,主设备通过地址访问特定从设备。
- **多种通信速率**:支持标准模式(100kHz)、快速模式(400kHz)和高速模式(1MHz)。
#### 实际应用:
使用 STM32 的 I2C 接口与温度传感器通信,周期性读取环境温度,并通过串口将数据发送到电脑进行监控。
------
### 5. **ADC(模数转换器)**
#### 功能:
ADC(Analog to Digital Converter)用于将模拟信号转换为数字信号,是读取传感器等模拟设备数据的重要接口。STM32 的 ADC 通常具有多通道和高分辨率的特点,适用于高精度的模拟信号采集。
#### 常见用途:
- **传感器信号采集**:采集温度传感器、电位器等模拟设备的信号。
- **电压监测**:监测电池电压、电源电压等,防止过充或欠压情况。
- **音频输入**:在音频处理应用中,采集麦克风或音频信号。
- **环境监测**:用于光照强度、气体浓度等的模拟数据读取。
#### 特点:
- **多通道支持**:STM32 的 ADC 通常支持多通道采样,可以轮询多个模拟信号源。
- **高分辨率**:支持 12 位甚至 16 位分辨率,确保高精度的数据转换。
- **连续转换模式**:可以配置为连续采样模式,持续采集模拟信号。
- **DMA 支持**:与 DMA 协同工作,允许大数据量的自动采集而无需占用 CPU。
- **采样时间可调**:可以根据不同输入信号源的阻抗调整采样时间,确保准确性。
#### 实际应用:
使用 ADC 接口读取电位器的模拟信号,通过 ADC 转换为数字信号后进行处理,调整系统的输出参数,如控制 LED 的亮度或调整电机转速。
------
### 6. **TIM(定时器)**
#### 功能:
定时器(TIM)是 STM32 中非常强大的外设,支持计时、事件控制、PWM 生成、输入捕获、输出比较等功能。STM32 中有多种类型的定时器,可用于不同的任务。
#### 常见用途:
- **时间延迟**:生成精确的时间延迟,用于定时任务或周期性中断。
- **PWM 生成**:控制电机转速、调光 LED 亮度、音频输出等。
- **输入捕获**:测量输入信号的脉冲宽度或频率,如测速应用。
- **事件计数**:用于记录外部事件的发生次数,如脉冲计数。
#### 特点:
- **多种模式**:支持单次计时、周期性计时等多种模式。
- **高精度计时**:可以通过定时器预分频器实现高精度时间控制,支持从微秒级别到数秒级别的计时任务。
- **PWM 输出**:定时器支持多通道 PWM 输出,可以同时控制多个设备,如控制多路 LED 的亮度或多轴电机的速度。
- **输入捕获/输出比较**:输入捕获用于精确测量输入信号的时间特性,输出比较用于在特定时间输出控制信号。
#### 实际应用:
配置 STM32 的 TIM 定时器生成 PWM 信号控制直流电机的转速,或者通过输入捕获功能测量外部信号的频率。
GPIO_InitTypeDef,EXTI_InitTypeDef,NVIC_InitTypeDef等常用的def的各个参数及使用方法
1. GPIO_InitTypeDef
GPIO_InitTypeDef
是用于配置 GPIO 引脚的结构体。它的成员变量决定了引脚的工作模式、输出类型、速度以及上下拉电阻配置。
结构体定义:
1 2 3 4 5 6 7
| typedef struct { uint32_t GPIO_Pin; // GPIO 引脚号 GPIOMode_TypeDef GPIO_Mode; // GPIO 模式(输入、输出、复用、模拟) GPIOSpeed_TypeDef GPIO_Speed; // GPIO 速度 GPIOOType_TypeDef GPIO_OType; // GPIO 输出类型(推挽/开漏) GPIOPuPd_TypeDef GPIO_PuPd; // GPIO 上拉/下拉电阻配置 } GPIO_InitTypeDef;
|
参数说明:
- **
GPIO_Pin
**:指定要配置的 GPIO 引脚。可以是以下常量的组合,用于同时配置多个引脚:
GPIO_Pin_0
, GPIO_Pin_1
, GPIO_Pin_2
, …, GPIO_Pin_15
。
- **
GPIO_Mode
**:设置引脚的工作模式。可以选择以下模式:
GPIO_Mode_IN
:输入模式。
GPIO_Mode_OUT
:输出模式。
GPIO_Mode_AF
:复用模式(用于外设,如 USART、SPI 等)。
GPIO_Mode_AN
:模拟模式(用于 ADC)。
- **
GPIO_Speed
**:配置引脚的速度,主要用于输出模式。速度取决于应用需求以及外设要求:
GPIO_Speed_2MHz
:低速(2MHz)。
GPIO_Speed_25MHz
:中速(25MHz)。
GPIO_Speed_50MHz
:高速(50MHz)。
GPIO_Speed_100MHz
:非常高速(100MHz)。
- **
GPIO_OType
**:输出类型,决定引脚是推挽还是开漏输出。主要用于输出模式:
GPIO_OType_PP
:推挽输出。
GPIO_OType_OD
:开漏输出。
- **
GPIO_PuPd
**:配置上拉或下拉电阻,主要用于输入模式:
GPIO_PuPd_NOPULL
:无上拉或下拉电阻。
GPIO_PuPd_UP
:上拉电阻。
GPIO_PuPd_DOWN
:下拉电阻。
使用示例:
1 2 3 4 5 6 7 8 9
| GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // 使能 GPIOA 时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; // 配置 PA5 引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; // 输出模式 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // 推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 50MHz 速度 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; // 无上拉/下拉 GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化 GPIOA 引脚
|
2. EXTI_InitTypeDef
EXTI_InitTypeDef
用于配置外部中断(EXTI),STM32 的 EXTI 模块可以通过 GPIO 引脚引发外部中断。
结构体定义:
1 2 3 4 5 6
| typedef struct { uint32_t EXTI_Line; // 外部中断线 EXTIMode_TypeDef EXTI_Mode; // 中断模式或事件模式 EXTITrigger_TypeDef EXTI_Trigger; // 中断触发条件(上升沿、下降沿、双边沿) FunctionalState EXTI_LineCmd; // 外部中断使能或禁用 } EXTI_InitTypeDef;
|
参数说明:
- **
EXTI_Line
**:指定要配置的 EXTI 线,范围从 EXTI_Line0
到 EXTI_Line15
,对应不同的 GPIO 引脚(例如,EXTI_Line0
对应 GPIO 0 号引脚)。
- **
EXTI_Mode
**:配置 EXTI 的模式,可以是以下两种:
EXTI_Mode_Interrupt
:中断模式。
EXTI_Mode_Event
:事件模式,不产生中断,但可以触发事件。
- **
EXTI_Trigger
**:设置中断触发条件,可以选择以下触发条件:
EXTI_Trigger_Rising
:上升沿触发。
EXTI_Trigger_Falling
:下降沿触发。
EXTI_Trigger_Rising_Falling
:上升沿和下降沿都触发。
- **
EXTI_LineCmd
**:用于使能或禁用 EXTI 线:
ENABLE
:使能 EXTI 线。
DISABLE
:禁用 EXTI 线。
使用示例:
1 2 3 4 5 6 7 8 9 10
| EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); // 使能 SYSCFG 时钟 SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0); // 将 PA0 配置为 EXTI_Line0
EXTI_InitStructure.EXTI_Line = EXTI_Line0; // 配置 EXTI Line0 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // 中断模式 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; // 上升沿触发 EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 使能 EXTI Line0 EXTI_Init(&EXTI_InitStructure); // 初始化 EXTI
|
3. NVIC_InitTypeDef
NVIC_InitTypeDef
用于配置嵌套向量中断控制器 (NVIC),用于管理中断优先级并使能中断请求。
结构体定义:
1 2 3 4 5 6
| typedef struct { uint8_t NVIC_IRQChannel; // 要配置的中断通道 uint8_t NVIC_IRQChannelPreemptionPriority; // 抢占优先级 uint8_t NVIC_IRQChannelSubPriority; // 响应优先级 FunctionalState NVIC_IRQChannelCmd; // 中断使能或禁用 } NVIC_InitTypeDef;
|
参数说明:
- **
NVIC_IRQChannel
**:指定要配置的中断通道。例如:
EXTI0_IRQn
:EXTI Line0 的中断。
TIM2_IRQn
:TIM2 定时器的中断。
- **
NVIC_IRQChannelPreemptionPriority
**:设置抢占优先级,数值越低优先级越高。在 STM32F4 中通常支持 4 位优先级划分。
- **
NVIC_IRQChannelSubPriority
**:设置响应优先级,用于同一抢占优先级下的多个中断之间的调度,数值越低优先级越高。
- **
NVIC_IRQChannelCmd
**:使能或禁用中断通道:
ENABLE
:使能中断通道。
DISABLE
:禁用中断通道。
使用示例:
1 2 3 4 5 6 7
| NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; // 配置 EXTI Line0 中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; // 抢占优先级 1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; // 响应优先级 1 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断 NVIC_Init(&NVIC_InitStructure); // 初始化 NVIC
|
综合示例:外部中断配置
假设我们要配置一个按键中断,按下按键时通过 EXTI 触发 PA0 引脚的中断,以下是完整的配置流程:
- 配置 GPIO 引脚为输入模式:
1 2 3 4 5 6 7
| GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 配置 PA0 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; // 输入模式 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; // 无上拉/下拉 GPIO_Init(GPIOA, &GPIO_InitStructure);
|
- 配置 EXTI:
1 2 3 4 5 6 7 8 9 10
| EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0); // 配置 EXTI Line0 对应 PA0
EXTI_InitStructure.EXTI_Line = EXTI_Line0; // 配置 EXTI Line0 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // 中断模式 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; // 上升沿触发 EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 使能 EXTI Line0 EXTI_Init(&EXTI_InitStructure);
|
- 配置 NVIC:
1 2 3 4 5 6 7
| NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; // 配置 EXTI0 中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; // 抢占优先级 0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; // 响应优先级 0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断 NVIC_Init(&NVIC_InitStructure);
|