打印
[应用相关]

stm32 外部中断嵌套[操作寄存器+库函数]

[复制链接]
493|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
stm32共有19个外部中断:
  • 线0~15:对应外部I/O口的输入中断
  • 线16:连接到PVD输出。PVD(Programmable Votage Detector),即可编程电压监测器。作用是监视供电电压,在供电电压下降到给定的阀值以下时,产生一个中断,通知软件做紧急处理。当供电电压又恢复到给定的阀值以上时,也会产生一个中断,通知软件供电恢复。
  • 线17:连接到RTC实时时钟产生闹钟事件。
  • 线18:连接到USB唤醒事件
stm32 NVIC中断stm32 USART串口通信 中已经介绍过stm32的中断和串口输出使用方法,本文运用外部中断嵌套,通过串口发送相应信息,验证外部中断嵌套。
按下PA0(按键按下时为低电平)时,打印出如下信息:
EXTI0 IRQHandler enter.
EXTI1 IRQHandler enter.
EXTI2 IRQHandler enter.
EXTI2 IRQHandler return.
EXTI1 IRQHandler return.
EXTI0 IRQHandler return.

直接操作寄存器
对于外部中断EXTI的控制寄存器,MDK定义了如下的结构体:
typedef struct
{
  vu32 IMR;
  vu32 EMR;
  vu32 RTSR;
  vu32 FTSR;
  vu32 SWIER;
  vu32 PR;
} EXTI_TypeDef;


使用特权

评论回复
沙发
工程师犹饿死|  楼主 | 2022-4-29 15:34 | 只看该作者
IMR:中断屏蔽寄存器
这个32位的寄存器只有前19位有效。当位x设置为1时,则开启这个线上的中断。
EMR:事件屏蔽寄存器
只有前19位有效。当位x设置为1时,则开启这个线上的事件触发。
RTSR/FTSR:上升沿/下降沿触发选择寄存器
只有低19位有效,当位x设置为1时,则允许这个线上上升/下降沿触发中断/事件。下降上升沿可以同时设置,则为任意电平触发。
SWIER:软件中断事件寄存器
设置IMR开启某个外部中断后,可以通过向该寄存器对应此外部中断的位x写1,产生一个软件中断,效果通外部中断触发 。
PR:挂起寄存器
当在外部中断线上发生了选择的边沿事件,该位被置’1’。在该位中写入’1’可以清除它,也可以通过改变边沿检测的极性清除。外部中断发生时,相应位置被置1,可以用于查询中断。

使用特权

评论回复
板凳
工程师犹饿死|  楼主 | 2022-4-29 16:04 | 只看该作者
stm32的I/O复用外部中断只有16个,但是引脚却有112(16*7)个之多。为了让每一个I/O口都可以设置为外部中断入口,stm32使用了4个EXTICR寄存器来实现分配。

使用特权

评论回复
地板
工程师犹饿死|  楼主 | 2022-4-29 16:05 | 只看该作者
EXTIx[3:0]:EXTIx配置(x = 0 … 3) (EXTI x configuration)  这些位可由软件读写,用于选择EXTIx外部中断的输入源。
0000对应PA引脚   0001 对应 PB引脚  0010对应PC引脚 0011对应PD引脚   
0100对应PE引脚  0101对应PF引脚  0110对应PG引脚
需要注意的是:实际上 AFIO_EXTICR1 寄存器 对应的操作寄存器是 AFIO->EXTICR[0]
直接操作寄存器代码:
User/main.c
01
#include <stm32f10x_lib.h>   
02
#include "system.h"
03
#include "usart.h"
04
#include "exti.h"  
05

06
void
Gpio_Init(
void
);
07

08
int
main(
void
)
09
{               
10

11
   
Rcc_Init(9);            
//系统时钟设置
12
   
Usart1_Init(72,9600);  
//设置系统时钟和波特率
13

14
   
Gpio_Init();
15

16
   
Exti_Init(GPIO_A,0,FTIR);
//设置PA0~3 为下降沿触发,参数GPIO_x 和 FTIR 在system.h中有定义
17
   
Exti_Init(GPIO_A,1,FTIR);
18
   
Exti_Init(GPIO_A,2,FTIR);
19
     

20
   
Nvic_Init(2,1,EXTI0_IRQChannel,2);   
//设置抢占优先级为2,响应优先级为1,中断分组为2
21
   
Nvic_Init(1,1,EXTI1_IRQChannel,2);   
//设置抢占优先级为1,响应优先级为1,中断分组为2
22
   
Nvic_Init(0,1,EXTI2_IRQChannel,2);   
//设置抢占优先级为0,响应优先级为1,中断分组为2
23

24
   
while
(1);
25
}
26

27

28
void
Gpio_Init(
void
)
29
{
30
   
RCC->APB2ENR|=1<<2;   
//使能PORTA时钟     
31

32
   
GPIOA->CRL&=0x0000FFFF;
// PA0~3设置为浮空输入,PA4~7设置为推挽输出
33
   
GPIOA->CRL|=0x33334444;
34

35
   

36
   
//USART1 串口I/O设置
37

38
   
GPIOA -> CRH&=0xFFFFF00F;  
//设置USART1 的Tx(PA.9)为第二功能推挽,50MHz;Rx(PA.10)为浮空输入
39
   
GPIOA -> CRH|=0x000008B0;     
40
}
User/stm23f10x_it.c

使用特权

评论回复
5
工程师犹饿死|  楼主 | 2022-4-29 16:13 | 只看该作者
01
#include "stm32f10x_it.h"
02
#include "stdio.h"
03

04
void
EXTI0_IRQHandler(
void
)
05
{
06
   
printf
(
"\r\nEXTI0 IRQHandler enter.\r\n"
);
07
   
EXTI->SWIER = 1<<1;   
//产生一个EXTI1上的软件中断,让此中断挂起
08
   
printf
(
"\r\nEXTI0 IRQHandler return.\r\n"
);
09
   
EXTI->PR = 1<<0;   
//清除中断标志位
10
}
11

12
void
EXTI1_IRQHandler(
void
)
13
{
14
   
printf
(
"\r\nEXTI1 IRQHandler enter.\r\n"
);
15
   
EXTI->SWIER = 1<<2;   
//产生一个EXTI2上的软件中断,让此中断挂起
16
   
printf
(
"\r\nEXTI1 IRQHandler return.\r\n"
);
17
   
EXTI->PR = 1<<1;
18
}
19

20
void
EXTI2_IRQHandler(
void
)
21
{
22
   
printf
(
"\r\nEXTI2 IRQHandler enter.\r\n"
);
23
   
printf
(
"\r\nEXTI2 IRQHandler return.\r\n"
);
24
   
EXTI->PR = 1<<2;
25
}   

使用特权

评论回复
6
工程师犹饿死|  楼主 | 2022-4-29 16:14 | 只看该作者
Library/src/exti.c
01
#include <stm32f10x_lib.h>
02
#include "exti.h"
03

04
//外部中断配置函数
05
//只针对GPIOA~G;不包括PVD,RTC和USB唤醒这三个
06
//参数:GPIOx:0~6,代表GPIOA~G;BITx:需要使能的位;TRIM:触发模式,1,下升沿;2,上降沿;3,任意电平触发
07
//该函数一次只能配置1个IO口,多个IO口,需多次调用
08
//该函数会自动开启对应中断,以及屏蔽线  
09
void
Exti_Init(u8 GPIOx,u8 BITx,u8 TRIM)
10
{
11
   
u8 EXTADDR;
12
   
u8 EXTOFFSET;
13
   
EXTADDR=BITx/4;
//得到中断寄存器组的编号
14
   
EXTOFFSET=(BITx%4)*4;
15

16
   
RCC->APB2ENR|=0x01;
//使能io复用时钟
17

18
   
AFIO->EXTICR[EXTADDR]&=~(0x000F<<EXTOFFSET);
//清除原来设置!!!
19
   
AFIO->EXTICR[EXTADDR]|=GPIOx<<EXTOFFSET;
//EXTI.BITx映射到GPIOx.BITx
20
   

21
   
//自动设置
22
   
EXTI->IMR|=1<<BITx;
//  开启line BITx上的中断
23
   
EXTI->EMR|=1<<BITx;
//  开启line BITx上的事件触发 (如果不屏蔽这句,在硬件上是可以的,但是在软件仿真的时候无法进入中断!)
24
   
if
(TRIM&0x01)EXTI->FTSR|=1<<BITx;
//line BITx上事件下降沿触发
25
   
if
(TRIM&0x02)EXTI->RTSR|=1<<BITx;
//line BITx上事件上升降沿触发
26
}

使用特权

评论回复
7
工程师犹饿死|  楼主 | 2022-4-29 16:15 | 只看该作者
Library/inc/exti.h
1
#include <stm32f10x_lib.h>
2

3
void
Exti_Init(u8 GPIOx,u8 BITx,u8 TRIM);
PS: 将Library下的exti.c加入MDK的工程

使用特权

评论回复
8
工程师犹饿死|  楼主 | 2022-4-29 16:16 | 只看该作者
库函数操作
库函数操作代码:
main.c
001
#include "stm32f10x.h"
002
#include "stdio.h"
003

004

005
#define  PRINTF_ON  1
006

007
void
RCC_Configuration(
void
);
008
void
GPIO_Configuration(
void
);
009
void
USART_Configuration(
void
);
010
void
NVIC_Configuration(
void
);
011
void
EXTI_Configuration(
void
);
012

013

014

015
int
main(
void
)
016
{
017
   
RCC_Configuration();
018
   
GPIO_Configuration();
019
   
USART_Configuration();
020
   
NVIC_Configuration();
021
   
EXTI_Configuration();
022
   
while
(1);
023
}
024

025

026
void
NVIC_Configuration(
void
)
027
{
028
   
NVIC_InitTypeDef NVIC_InitStructure;
029

030
   
#ifdef   VECT_TAB_RAM
031
        
NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);
032
   
#else
033
        
NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);
034
   
#endif
035

036
   
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
037

038
   
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
039
   
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   
//优先级数字越大,优先级越小
040
   
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
041
   
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
042
   
NVIC_Init(&NVIC_InitStructure);
043

044
   
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
045
   
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
046
   
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
047
   
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
048
   
NVIC_Init(&NVIC_InitStructure);
049

050
   
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
051
   
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
052
   
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
053
   
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
054

055
   
NVIC_Init(&NVIC_InitStructure);
056
}
057

058

059

060
  

061
void
GPIO_Configuration(
void
)
062
{
063
   
GPIO_InitTypeDef GPIO_InitStructure;                                                                                                                                                                  
064
   
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
065
   
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;         
066
   
GPIO_Init(GPIOA , &GPIO_InitStructure);
067

068
   
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
069
   
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);
070
   
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource2);
071

072

073
   

074
   
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
075
   
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
076
   
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        
077
   
GPIO_Init(GPIOA , &GPIO_InitStructure);
078

079
   
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
080
   
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;         
081
   
GPIO_Init(GPIOA , &GPIO_InitStructure);
082
}
083

084
void
EXTI_Configuration(
void
)
085
{
086
   
EXTI_InitTypeDef EXTI_InitStructure;
087

088
   
EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1 | EXTI_Line2;
089
   
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
090
   
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
091
   
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
092
   
EXTI_Init(&EXTI_InitStructure);
093

094

095
}
096

097

098
void
RCC_Configuration(
void
)
099
{
100
   
/* 定义枚举类型变量 HSEStartUpStatus */
101
   
ErrorStatus HSEStartUpStatus;
102

103
   
/* 复位系统时钟设置*/
104
   
RCC_DeInit();
105
   
/* 开启HSE*/
106
   
RCC_HSEConfig(RCC_HSE_ON);
107
   
/* 等待HSE起振并稳定*/
108
   
HSEStartUpStatus = RCC_WaitForHSEStartUp();
109
   
/* 判断HSE起是否振成功,是则进入if()内部 */
110
   
if
(HSEStartUpStatus == SUCCESS)
111
   
{
112
        
/* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */
113
        
RCC_HCLKConfig(RCC_SYSCLK_Div1);
114
        
/* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */
115
        
RCC_PCLK2Config(RCC_HCLK_Div1);
116
        
/* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */
117
        
RCC_PCLK1Config(RCC_HCLK_Div2);
118
        
/* 设置FLASH延时周期数为2 */
119
        
FLASH_SetLatency(FLASH_Latency_2);
120
        
/* 使能FLASH预取缓存 */
121
        
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
122
        
/* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */
123
        
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
124
        
/* 使能PLL */
125
        
RCC_PLLCmd(ENABLE);
126
        
/* 等待PLL输出稳定 */
127
        
while
(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
128
        
/* 选择SYSCLK时钟源为PLL */
129
        
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
130
        
/* 等待PLL成为SYSCLK时钟源 */
131
        
while
(RCC_GetSYSCLKSource() != 0x08);
132
   
}
133
   
/* 打开APB2总线上的GPIOA时钟*/
134
   
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO, ENABLE);
135

136
   
//RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
137
        

138
}
139

140


141
void
USART_Configuration(
void
)
142
{
143
   
USART_InitTypeDef USART_InitStructure;
144
   
USART_ClockInitTypeDef USART_ClockInitStructure;
145

146
   
USART_ClockInitStructure.USART_Clock = USART_Clock_Disable;
147
   
USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;
148
   
USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;                                                                                                                                                     
149
   
USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;
150
   
USART_ClockInit(USART1 , &USART_ClockInitStructure);
151

152
   
USART_InitStructure.USART_BaudRate = 9600;
153
   
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
154
   
USART_InitStructure.USART_StopBits = USART_StopBits_1;
155
   
USART_InitStructure.USART_Parity = USART_Parity_No;
156
   
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
157
   
USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;
158
   
USART_Init(USART1,&USART_InitStructure);
159

160
   
USART_Cmd(USART1,ENABLE);
161
}
162

163

164
void
TIM_Configuration(
void
)
165
{
166

167

168
}
169

170
#if  PRINTF_ON
171

172
int
fputc
(
int
ch,
FILE
*f)
173
{
174
   
USART_SendData(USART1,(u8) ch);
175
   
while
(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);
176
   
return
ch;
177
}
178

179
#endif

使用特权

评论回复
9
工程师犹饿死|  楼主 | 2022-4-29 17:14 | 只看该作者
stm32f10x_it.c
01
#include "stm32f10x_it.h"
02
#include "stdio.h"
03

04
void
EXTI0_IRQHandler(
void
)
05
{
06
   
printf
(
"\r\nEXTI0 IRQHandler enter.\r\n"
);
07
   
EXTI_GenerateSWInterrupt(EXTI_Line1);
08
   
printf
(
"\r\nEXTI0 IRQHandler return.\r\n"
);
09
   
EXTI_ClearFlag(EXTI_Line0);
10
}
11

12
void
EXTI1_IRQHandler(
void
)
13
{
14
   
printf
(
"\r\nEXTI1 IRQHandler enter.\r\n"
);
15
   
EXTI_GenerateSWInterrupt(EXTI_Line2);
16
   
printf
(
"\r\nEXTI1 IRQHandler return.\r\n"
);
17
   
EXTI_ClearFlag(EXTI_Line1);
18
}
19

20
void
EXTI2_IRQHandler(
void
)
21
{
22
   
printf
(
"\r\nEXTI2 IRQHandler enter.\r\n"
);
23
   
printf
(
"\r\nEXTI2 IRQHandler return.\r\n"
);
24
   
EXTI_ClearFlag(EXTI_Line2);
25
}

使用特权

评论回复
10
qbwww| | 2022-10-2 16:14 | 只看该作者
连接到PVD输出。PVD(Programmable Votage Detector),即可编程电压监测器。作用是监视供电电压,在供电电压下降到给定的阀值以下时,产生一个中断,通知软件做紧急处理。当供电电压又恢复到给定的阀值以上时,也会产生一个中断,通知软件供电恢复

使用特权

评论回复
11
Uriah| | 2022-10-8 13:22 | 只看该作者

跟那个施密特触发器的配置有关

使用特权

评论回复
12
Bblythe| | 2022-10-8 16:21 | 只看该作者

该函数执行完后继续后续

使用特权

评论回复
13
Pulitzer| | 2022-10-8 19:20 | 只看该作者

HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高

使用特权

评论回复
14
公羊子丹| | 2023-7-1 07:24 | 只看该作者

Keil编写程序是默认的时钟为72Mhz

使用特权

评论回复
15
公羊子丹| | 2023-7-1 08:17 | 只看该作者

硬件设计和软件设计本来就是鱼和熊掌的关系,两者不可兼得

使用特权

评论回复
16
Wordsworth| | 2023-7-1 09:20 | 只看该作者

定时器输出引脚的设定

使用特权

评论回复
17
Clyde011| | 2023-7-1 10:23 | 只看该作者

A在使用自己声明的mysum之前,初始化(注册)一下该函数

使用特权

评论回复
18
万图| | 2023-7-1 12:19 | 只看该作者

紫外光复位保护电路是不行的

使用特权

评论回复
19
Uriah| | 2023-7-1 13:22 | 只看该作者

多增加过孔将此工作地线与工作地平面相连

使用特权

评论回复
20
帛灿灿| | 2023-7-1 15:18 | 只看该作者

让尽可能多的变量使用直接寻址,提高速度

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

75

主题

886

帖子

0

粉丝