STM32笔记
STM32笔记
SWD连接开发板
什么是SWD
SWD与JTAG同属调试接口,是芯片在设计之初就预制的对芯片进行开发调试并在开发板上预留的接口,
JTAG接口
目前开发板上的接口大多是20PIN的,与此对应的关系如下:
DAPLink在JTAG接口连接
只用连接3根线 SWD、SWCLK、GND。对应关系为
连接时要注意将接口摆放与图片一致后接线,这样不容易弄反
GPIO
通用输入输出接口
GPIO_MODE
(1)GPIO_Mode_AIN 模拟输入
模式:GPIO_Mode_AIN
TTL肖特基触发器
(2)GPIO_Mode_IN_FLOATING 浮空输入
模式:GPIO_Mode_IN_FLOATING
上、下拉都不启用
(3)GPIO_Mode_IPD 下拉输入
模式:GPIO_Mode_IPD
默认低电平
下拉电阻启用
(4)GPIO_Mode_IPU 上拉输入
模式:GPIO_Mode_IPU
默认高电平
上拉电阻启用
小结
上拉输入模式:区别在于没有输入信号的时候默认输入高电平(因为有弱上拉)。下拉输入模式:区别在于没有输入信号的时候默认输入低电平(因为有弱下拉)。对于浮空输入模式顾名思义也就是输入什么信号才是什么信号,对于浮空输入要保证有明确的输入信号。
(5)GPIO_Mode_Out_OD 开漏输出
模式:GPIO_Mode_Out_OD
开漏:有一极处于开路状态(或称为高阻态)


(6)GPIO_Mode_Out_PP 推挽输出
模式:GPIO_Mode_Out_PP
推:使用单片机电压推送高电源电压
挽:使用低电压把外面电流拉进来
小结:
推挽输出 | 开漏输出 | |
---|---|---|
高电平 | P-MOS激活N-MOS断开,3.3V | P-MOS断开N-MOS断开,外部决定 |
低电平 | P-MOS断开N-MOS激活,0V | P-MOS断开N-MOS激活,0V |
优点 | 直接输出3.3V | 配合外部电路更加灵活 |
缺点 | 只能输出3.3V | 高电平是高阻态,无输出能力 |
(7)GPIO_Mode_AF_OD 复用开漏输出
模式:GPIO_Mode_IPD
管脚复用状态下的开漏输出
(8)GPIO_Mode_AF_PP 复用推挽输出
模式:GPIO_Mode_IPD
管脚复用状态下的推挽输出
GPIO库函数简单说明
- GPIO_DeInit 重新初始化外围设备GPIOx相关寄存器到它的默认复位值
- GPIO_AFIODeInit 初始化交错功能(remap, event control和 EXTI 配置) 寄存器
- GPIO_Init 根据GPIO_初始化结构指定的元素初始化外围设备GPIOx
- GPIO_StructInit 填充GPIO_初始化结构(GPIO_InitStruct)内的元素为复位值
- GPIO_ReadInputDataBit 读指定端口引脚输入数据
- GPIO_ReadInputData 读指定端口输入数据
- GPIO_ReadOtputDataBit 读指定端口引脚输出数据
- GPIO_ReadOtputData 读指定端口输出数据
- GPIO_SetBits 置1指定的端口引脚
- GPIO_ResetBits 清0指定的端口引脚
- GPIO_WriteBit 设置或清除选择的数据端口引脚
- GPIO_Write 写指定数据到GPIOx端口寄存器
- GPIO_ANAPinConfig 允许或禁止 GPIO 4 模拟输入模式
- GPIO_PinLockConfig 锁定GPIO引脚寄存器
- GPIO_EventOutputConfig 选择GPIO引脚作为事件输出
- GPIO_EventOutputCmd 允许或禁止事件输出
- GPIO_PinRemapConfig 改变指定引脚的影射
- GPIO_EMIConfig 允许或禁止GPIO 8 和 9 的EMI 模式
PNP继电器
继电器原理图如下:
1. 工作状态分析
当PE2管脚输出为低电压,PNP三极管发射极(2号管脚)与集电极(3号管脚)导通,PNP三极管的发射极(2号管脚)与基极(1号管脚)导通,此时继电器处于工作状态,LED被点亮。此时继电器JDQ工作(因两侧存在电压差,2号管脚高),此时电流方向为2->1、2->3。
2. 静止状态分析
当PE2管脚为开路时,PNP三极管发射极(2号管脚)与基极(1号管脚)不存在电压差,此时电流被断开,不存在电流。继电器关闭,LED不点亮。
上拉电阻、下拉电阻、不上拉也不下拉
1、上拉电阻: 将电路连接到外部电源,提升电压。常用于漏极开路输出
2、不上拉也不下拉: 电路无变化连接到外部电源,常用于推挽输出
3、下拉电阻: 输入低电平
继电器与按钮Demo
案例实现点击key0继电器吸合两秒后自动关闭
mian.c
copy
- 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
int main(void)
{
delay_init(); //延时函数初始化
LED_Init(); //初始化与LED连接的硬件接口
JDQ_Init(); //初始化蜂鸣器端口
Key_Init();
while(1)
{
LED1 =0;
JDQ = 1;
delay_ms(100);
if(KEY0 == 0){
LED0 = 0;
JDQ = 0;
KEY0 = 1;
delay_ms(1000);
delay_ms(1000);
}
LED0 = 1;
JDQ = 1;
}
}
led.c
copy
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
//初始化PB5和PE5为输出口.并使能这两个口的时钟
//LED IO初始化
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); //使能PB,PE端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0-->PB.5 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB.5
GPIO_SetBits(GPIOB,GPIO_Pin_5); //PB.5 输出高
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED1-->PE.5 端口配置, 推挽输出
GPIO_Init(GPIOE, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
GPIO_SetBits(GPIOE,GPIO_Pin_5); //PE.5 输出高
}
jdq.c
copy
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
//初始化PE2为输出口.并使能这个口的时钟
//继电器初始化
void JDQ_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); //使能GPIOE端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //JDQ-->PE.2 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //开漏输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度为50MHz
GPIO_Init(GPIOE, &GPIO_InitStructure); //根据参数初始化GPIOE.2
GPIO_ResetBits(GPIOE,GPIO_Pin_2);//设置继电器关闭
}
优化按钮捕捉,检测按钮是否被处于空状态,代码编写提示、对按钮全过程检测
copy
- 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
int getKey0Static(void);
int main(void)
{
delay_init(); //延时函数初始化
LED_Init(); //初始化与LED连接的硬件接口
JDQ_Init(); //初始化蜂鸣器端口
Key_Init();
LED1 =0;
JDQ = 1;
while(1)
{
int key0Static = getKey0Static();
if( key0Static == 1){
JDQ=~JDQ;
}
}
}
int getKey0Static(void){
static int key_up = 1;//按钮原位置
if(key_up&&KEY0 == 0){
delay_ms(30);
if(KEY0 ==0){
key_up = 0;
return 1;
}
return 0;
}else if(KEY0==1){
key_up = 1;
return 0;
}
return 0;
}
C语言按位操作
>>= 右移后赋值
例如 x=0x08 x>>=3
计算步骤如下:
- x=0000 1000
- 右移3位0000 0001
- 赋值后为0000 0001
- 结果x=0x01
<<= 左移后赋值
例如 x=0x08 x<<=3
- x=0000 1000
- 左移三位 0100 0000
- 赋值后为 0100 0000
- 结果 x=0x40
&= 按位与后赋值
例如 x=0x08 x &= 0x03
- x = 0000 1000
- 0x03=0000 0011
- end 0000 0000
- 赋值后为 0000 0000
- x=0x00
^= 按位异或后赋值
异或:两个不一样取1,一样取0
例如 x=0x09 x ^= 0x03
- x = 0000 1001
- 0x03=0000 0011
- end 0000 1010
- 赋值后为 0000 1010
- 结果x=0x0A
|= 按位或后赋值
有一个1就取1,两个都为0才取0
例如 x=0x08 x |= 0x03
- x = 0000 1000
- 0x03=0000 0011
- end 0000 1011
- 赋值后为 0000 1011
- 结果x=0x0B
小结
- 或等于(|=)常用于对某一位赋值,因其后给的数与原数或后原数的1保持不变,只改变其他为0的位,
- 与等于(&=)常用来对某一位或多个位清零,引起有0就为0,只有两个1才不为0的特性。要保留1位的就赋1,清除的就赋0
时钟树
为什么要设置时钟,一是寄存器是由D触发器组成的,只有送来了时钟,触发器才能被改写值,这样寄存器才能工作;二是现在的功能过多功耗顶不住,所以现在的芯片是使用那个功能就对时钟和串口使能用哪个功能。
简述
- HSE、LSE分别为高速和低速外部时钟,一般为晶振产生。高速外部时钟输入范围为4-16MHz,低速外部时钟为定频40kHz
- HSI、LSI分别为高速和低速内部时钟,一般为内部RC震荡电路产生受温度影响。高速内部时钟为定频8MHz,低速内部时钟为定频32.768kHz
- 红圈2为选择器,选择应用哪个源作为输出时钟信号
- 红圈3为倍频器,将信号倍频x2~x16,
- 红圈5为分频器,将信号分频为/1、/2、/4、/8、/16、/64、/128、/256
设置系统时钟库函数
copy
- 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
static void SetSysClockTo72(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
// ① 使能HSE,并等待HSE稳定
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
// 等待HSE启动稳定,并做超时处理
do {
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while ((HSEStatus == 0)
&&(StartUpCounter !=HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET) {
HSEStatus = (uint32_t)0x01;
} else {
HSEStatus = (uint32_t)0x00;
}
// HSE启动成功,则继续往下处理
if (HSEStatus == (uint32_t)0x01) {
//-----------------------------------------------------------
// 使能FLASH 预存取缓冲区 */
FLASH->ACR |= FLASH_ACR_PRFTBE;
// SYSCLK周期与闪存访问时间的比例设置,这里统一设置成2
// 设置成2的时候,SYSCLK低于48M也可以工作,如果设置成0或者1的时候,
// 如果配置的SYSCLK超出了范围的话,则会进入硬件错误,程序就死了
// 0:0 < SYSCLK <= 24M
// 1:24< SYSCLK <= 48M
// 2:48< SYSCLK <= 72M */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
//------------------------------------------------------------
// ② 设置AHB、APB2、APB1预分频因子
// HCLK = SYSCLK
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
//PCLK2 = HCLK
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
//PCLK1 = HCLK/2
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
// ③ 设置PLL时钟来源,设置PLL倍频因子,PLLCLK = HSE * 9 = 72 MHz
RCC->CFGR &= (uint32_t)((uint32_t)
~(RCC_CFGR_PLLSRC
| RCC_CFGR_PLLXTPRE
| RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE
| RCC_CFGR_PLLMULL9);
// ④ 使能 PLL
RCC->CR |= RCC_CR_PLLON;
// ⑤ 等待PLL稳定
while ((RCC->CR & RCC_CR_PLLRDY) == 0) {
}
// ⑥ 选择PLL作为系统时钟来源
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
// ⑦ 读取时钟切换状态位,确保PLLCLK被选为系统时钟
while ((RCC->CFGR&(uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08){
}
} else {// 如果HSE启动失败,用户可以在这里添加错误代码出来
}
}
中断
F103系统异常清单
stm32F103有8个系统异常(把Reset、HardFault算上有10个)
F103外部中断清单
位置 | 优先级 | 优先级类型 | 名称 | 说明 | 地址 |
---|---|---|---|---|---|
0 | 7 | 可设置 | WWDG | 窗口定时器中断 | 0x0000_0040 |
1 | 8 | 可设置 | PVD | 连到EXTI的电源电压检测(PVD)中断 | 0x0000_0044 |
2 | 9 | 可设置 | TAMPER | 侵入检测中断 | 0x0000_0048 |
3 | 10 | 可设置 | RTC | 实时时钟(RTC)全局中断 | 0x0000_004C |
4 | 11 | 可设置 | FLASH | 闪存全局中断 | 0x0000_0050 |
5 | 12 | 可设置 | RCC | 复位和时钟控制(RCC)中断 | 0x0000_0054 |
6 | 13 | 可设置 | EXTI0 | EXTI线0中断 | 0x0000_0058 |
7 | 14 | 可设置 | EXTI1 | EXTI线1中断 | 0x0000_005C |
8 | 15 | 可设置 | EXTI2 | EXTI线2中断 | 0x0000_0060 |
9 | 16 | 可设置 | EXTI3 | EXTI线3中断 | 0x0000_0064 |
10 | 17 | 可设置 | EXTI4 | EXTI线4中断 | 0x0000_0068 |
11 | 18 | 可设置 | DMA1通道1 | DMA1通道1全局中断 | 0x0000_006C |
12 | 19 | 可设置 | DMA1通道2 | DMA1通道2全局中断 | 0x0000_0070 |
13 | 20 | 可设置 | DMA1通道3 | DMA1通道3全局中断 | 0x0000_0074 |
14 | 21 | 可设置 | DMA1通道4 | DMA1通道4全局中断 | 0x0000_0078 |
15 | 22 | 可设置 | DMA1通道5 | DMA1通道5全局中断 | 0x0000_007C |
16 | 23 | 可设置 | DMA1通道6 | DMA1通道6全局中断 | 0x0000_0080 |
17 | 24 | 可设置 | DMA1通道7 | DMA1通道7全局中断 | 0x0000_0084 |
18 | 25 | 可设置 | ADC1_2 | ADC1和ADC2的全局中断 | 0x0000_0088 |
19 | 26 | 可设置 | USB_HP_CAN_TX | USB高优先级或CAN发送中断 | 0x0000_008C |
20 | 27 | 可设置 | USB_LP_CAN_RX0 | USB低优先级或CAN接收0中断 | 0x0000_0090 |
21 | 28 | 可设置 | CAN_RX1 | CAN接收1中断 | 0x0000_0094 |
22 | 29 | 可设置 | CAN_SCE | CANSCE中断 | 0x0000_0098 |
23 | 30 | 可设置 | EXTI9_5 | EXTI线[9:5]中断 | 0x0000_009C |
24 | 31 | 可设置 | TIM1_BRK | TIM1刹车中断 | 0x0000_00A0 |
25 | 32 | 可设置 | TIM1_UP | TIM1更新中断 | 0x0000_00A4 |
26 | 33 | 可设置 | TIM1_TRG_COM | TIM1触发和通信中断 | 0x0000_00A8 |
27 | 34 | 可设置 | TIM1_CC | TIM1捕获比较中断 | 0x0000_00AC |
28 | 35 | 可设置 | TIM2 | TIM2全局中断 | 0x0000_00B0 |
29 | 36 | 可设置 | TIM3 | TIM3全局中断 | 0x0000_00B4 |
30 | 37 | 可设置 | TIM4 | TIM4全局中断 | 0x0000_00B8 |
31 | 38 | 可设置 | I2C1_EV | I2C1事件中断 | 0x0000_00BC |
32 | 39 | 可设置 | I2C1_ER | I2C1错误中断 | 0x0000_00C0 |
33 | 40 | 可设置 | I2C2_EV | I2C2事件中断 | 0x0000_00C4 |
34 | 41 | 可设置 | I2C2_ER | I2C2错误中断 | 0x0000_00C8 |
35 | 42 | 可设置 | SPI1 | SPI1全局中断 | 0x0000_00CC |
36 | 43 | 可设置 | SPI2 | SPI2全局中断 | 0x0000_00D0 |
37 | 44 | 可设置 | USART1 | USART1全局中断 | 0x0000_00D4 |
38 | 45 | 可设置 | USART2 | USART2全局中断 | 0x0000_00D8 |
39 | 46 | 可设置 | USART3 | USART3全局中断 | 0x0000_00DC |
40 | 47 | 可设置 | EXTI15_10 | EXTI线[15:10]中断 | 0x0000_00E0 |
41 | 48 | 可设置 | RTCAlarm | 连到EXTI的RTC闹钟中断 | 0x0000_00E4 |
42 | 49 | 可设置 | USB唤醒 | 连到EXTI的从USB待机唤醒中断 | 0x0000_00E8 |
43 | 50 | 可设置 | TIM8_BRK | TIM8刹车中断 | 0x0000_00EC |
44 | 51 | 可设置 | TIM8_UP | TIM8更新中断 | 0x0000_00F0 |
45 | 52 | 可设置 | TIM8_TRG_COM | TIM8触发和通信中断 | 0x0000_00F4 |
46 | 53 | 可设置 | TIM8_CC | TIM8捕获比较中断 | 0x0000_00F8 |
47 | 54 | 可设置 | ADC3 | ADC3全局中断 | 0x0000_00FC |
48 | 55 | 可设置 | FSMC | FSMC全局中断 | 0x0000_0100 |
49 | 56 | 可设置 | SDIO | SDIO全局中断 | 0x0000_0104 |
50 | 57 | 可设置 | TIM5 | TIM5全局中断 | 0x0000_0108 |
51 | 58 | 可设置 | SPI3 | SPI3全局中断 | 0x0000_010C |
52 | 59 | 可设置 | UART4 | UART4全局中断 | 0x0000_0110 |
53 | 60 | 可设置 | UART5 | UART5全局中断 | 0x0000_0114 |
54 | 61 | 可设置 | TIM6 | TIM6全局中断 | 0x0000_0118 |
55 | 62 | 可设置 | TIM7 | TIM7全局中断 | 0x0000_011C |
56 | 63 | 可设置 | DMA2通道1 | DMA2通道1全局中断 | 0x0000_0120 |
57 | 64 | 可设置 | DMA2通道2 | DMA2通道2全局中断 | 0x0000_0124 |
58 | 65 | 可设置 | DMA2通道3 | DMA2通道3全局中断 | 0x0000_0128 |
59 | 66 | 可设置 | DMA2通道4_5 | DMA2通道4和DMA2通道5全局中断 | 0x0000_012C |
NVIC
NVIC(Nested Vectored Interrupt Controller)嵌套向量中断控制器
M3原生NVIC支持共支持 1 至 240 个外部中断输入(通常外部中断写作 IRQs)。
结构体:
一般常用ISER用来使能中断,ICER用来失能中断,IP用来设置中断优先级。
copy
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
typedef struct {
__IO uint32_t ISER[8]; // 中断使能寄存器
uint32_t RESERVED0[24];
__IO uint32_t ICER[8]; // 中断清除寄存器
uint32_t RSERVED1[24];
__IO uint32_t ISPR[8]; // 中断使能悬起寄存器
uint32_t RESERVED2[24];
__IO uint32_t ICPR[8]; // 中断清除悬起寄存器
uint32_t RESERVED3[24];
__IO uint32_t IABR[8]; // 中断有效位寄存器
uint32_t RESERVED4[56];
__IO uint8_t IP[240]; // 中断优先级寄存器(8Bit wide)
uint32_t RESERVED5[644];
__O uint32_t STIR; // 软件触发中断寄存器
} NVIC_Type;
优先级
在NVIC 有一个专门的寄存器:中断优先级寄存器NVIC_IPRx,用来配置外部中断的优先级,IPR宽度为8bit, 原则上每个外部中断可配置的优先级为0~255,数值越小,优先级越高。但是绝大多数CM3芯片都会精简设计, 以致实际上支持的优先级数减少,在F103中,只使用了高4bit,如下所示:
由此4个bit来设置优先级,stm32对4个bit的应用(或者说划分)做了排列组合并分成组如下
优先级分组 | 抢占优先级使用bit位数 | 抢占优先级对应级别范围 | 子优先级(响应优先级)使用bit数 | 子优先级(响应优先级)对应级别范围 |
---|---|---|---|---|
NVIC_PriorityGroup_0 | 0 | 0 | 4 | [0,15](2^4) |
NVIC_PriorityGroup_1 | 1 | [0,1] | 3 | [0,7](2^3) |
NVIC_PriorityGroup_2 | 2 | [0,3](2^2) | 2 | [0,3](2^2) |
NVIC_PriorityGroup_3 | 3 | [0,7](2^3) | 1 | [0,1] |
NVIC_PriorityGroup_4 | 5 | [0,15](2^4) | 0 | 0 |
优先级比较顺序
- 抢占优先级(高先行)
- 子优先级(小先行)
- 硬件中断编号(小先行)
外部中断 EXTI
EXTI(External interrupt/event controller)管理了控制器的20个中断/事件线。 每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。EXTI可以实现对每个中断/事件线进行单独配置, 可以单独配置为中断或者事件,以及触发事件的属性
功能框图
虽然还不懂,现在先加上以后懵懂了再说
EXTI功能框图
- 斜杠并标注“20”字样,这个表示在控制器内部类似的信号线路有20个
- EXTI可分为两大部分功能,一个是产生中断(红色线),另一个是产生事件(绿色线),这两个功能从硬件上就有所不同
- 编号1是输入线,EXTI控制器有19个中断/事件输入线,这些输入线可以通过寄存器设置为任意一个GPIO
- 产生中断线路目的是把输入信号输入到NVIC,进一步会运行中断服务函数,实现功能,这样是软件级的
- 产生事件线路目的就是传输一个脉冲信号给其他外设使用, 并且是电路级别的信号传输,属于硬件级的
中断事件线
中断/事件线 | 输入源 |
---|---|
EXTI[0-15] | PnO(n为A、B、C、D、E、F、G、H、I) |
EXTI16 | PVD输出 |
EXTI17 | RTC闹钟事件 |
EXTI18 | USB唤醒事件 |
EXTI19 | 以太网唤醒事件(仅限互联网型) |
库函数结构体 EXTI_InitTypeDef
copy
- 1
- 2
- 3
- 4
- 5
- 6
typedef struct {
uint32_t EXTI_Line; // 中断/事件线
EXTIMode_TypeDef EXTI_Mode; // EXTI模式
EXTITrigger_TypeDef EXTI_Trigger; // 触发类型
FunctionalState EXTI_LineCmd; // EXTI使能
} EXTI_InitTypeDef;
- EXTI_Line:EXTI中断/事件线选择,可选EXTI0至EXTI19,可参考表 EXTI中断_事件线 选择
- EXTI_Mode:EXTI模式选择,可选为产生中断(EXTI_Mode_Interrupt)或者产生事件(EXTI_Mode_Event)
- EXTI_Trigger:EXTI边沿触发事件,可选上升沿触发(EXTI_Trigger_Rising)、 下降沿触发( EXTI_Trigger_Falling)或者上升沿和下降沿都触发( EXTI_Trigger_Rising_Falling)
- EXTI_LineCmd:控制是否使能EXTI线,可选使能EXTI线(ENABLE)或禁用(DISABLE)
编程要点
- 初始化用来产生中断的GPIO;
- 初始化EXTI;
- 配置NVIC;
- 编写中断服务函数
中断函数与中断/事件线关系
在STM32中有启动文件 startup_stm32fXXX.s
文件中有对应中断/事件线与中断函数名称之间关系已经规定好了,除此以外也可以通过宏定义方式按照自己的定义方式来写中断函数(这句不懂,我先跳过)。
如图摘抄了外部中断0-15的中断线与对应中断函数的定义关系
本文作者:伊芙利特
本文链接:https://www.cnblogs.com/yuknight/p/17602112.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律