stm32共有19个外部中断: - 线0~15:对应外部I/O口的输入中断
- 线16:连接到PVD输出。PVD(Programmable Votage Detector),即可编程电压监测器。作用是监视供电电压,在供电电压下降到给定的阀值以下时,产生一个中断,通知软件做紧急处理。当供电电压又恢复到给定的阀值以上时,也会产生一个中断,通知软件供电恢复。
- 线17:连接到RTC实时时钟产生闹钟事件。
- 线18:连接到USB唤醒事件
按下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; IMR:中断屏蔽寄存器 这个32位的寄存器只有前19位有效。当位x设置为1时,则开启这个线上的中断。 EMR:事件屏蔽寄存器 只有前19位有效。当位x设置为1时,则开启这个线上的事件触发。 RTSR/FTSR:上升沿/下降沿触发选择寄存器 只有低19位有效,当位x设置为1时,则允许这个线上上升/下降沿触发中断/事件。下降上升沿可以同时设置,则为任意电平触发。 SWIER:软件中断事件寄存器 设置IMR开启某个外部中断后,可以通过向该寄存器对应此外部中断的位x写1,产生一个软件中断,效果通外部中断触发 。 PR:挂起寄存器 当在外部中断线上发生了选择的边沿事件,该位被置’1’。在该位中写入’1’可以清除它,也可以通过改变边沿检测的极性清除。外部中断发生时,相应位置被置1,可以用于查询中断。 stm32的I/O复用外部中断只有16个,但是引脚却有112(16*7)个之多。为了让每一个I/O口都可以设置为外部中断入口,stm32使用了4个EXTICR寄存器来实现分配。 EXTICR1~4寄存器描述类似,EXTICR1如下: 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> |
12 | Usart1_Init(72,9600); //设置系统时钟和波特率 |
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); |
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 |
30 | RCC->APB2ENR|=1<<2; //使能PORTA时钟 |
32 | GPIOA->CRL&=0x0000FFFF; // PA0~3设置为浮空输入,PA4~7设置为推挽输出 |
33 | GPIOA->CRL|=0x33334444; |
38 | GPIOA -> CRH&=0xFFFFF00F; //设置USART1 的Tx(PA.9)为第二功能推挽,50MHz;Rx(PA.10)为浮空输入 |
39 | GPIOA -> CRH|=0x000008B0; |
User/stm23f10x_it.c 01 | #include "stm32f10x_it.h" |
04 | void EXTI0_IRQHandler( void ) |
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; //清除中断标志位 |
12 | void EXTI1_IRQHandler( void ) |
14 | printf ( "\r\nEXTI1 IRQHandler enter.\r\n" ); |
15 | EXTI->SWIER = 1<<2; //产生一个EXTI2上的软件中断,让此中断挂起 |
16 | printf ( "\r\nEXTI1 IRQHandler return.\r\n" ); |
20 | void EXTI2_IRQHandler( void ) |
22 | printf ( "\r\nEXTI2 IRQHandler enter.\r\n" ); |
23 | printf ( "\r\nEXTI2 IRQHandler return.\r\n" ); |
Library/src/exti.c 01 | #include <stm32f10x_lib.h> |
05 | //只针对GPIOA~G;不包括PVD,RTC和USB唤醒这三个 |
06 | //参数:GPIOx:0~6,代表GPIOA~G;BITx:需要使能的位;TRIM:触发模式,1,下升沿;2,上降沿;3,任意电平触发 |
07 | //该函数一次只能配置1个IO口,多个IO口,需多次调用 |
09 | void Exti_Init(u8 GPIOx,u8 BITx,u8 TRIM) |
13 | EXTADDR=BITx/4; //得到中断寄存器组的编号 |
16 | RCC->APB2ENR|=0x01; //使能io复用时钟 |
18 | AFIO->EXTICR[EXTADDR]&=~(0x000F<<EXTOFFSET); //清除原来设置!!! |
19 | AFIO->EXTICR[EXTADDR]|=GPIOx<<EXTOFFSET; //EXTI.BITx映射到GPIOx.BITx |
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上事件上升降沿触发 |
Library/inc/exti.h 1 | #include <stm32f10x_lib.h> |
3 | void Exti_Init(u8 GPIOx,u8 BITx,u8 TRIM); |
PS: 将Library下的exti.c加入MDK的工程 库函数操作 库函数操作代码: main.c 001 | #include "stm32f10x.h" |
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 ); |
018 | GPIO_Configuration(); |
019 | USART_Configuration(); |
020 | NVIC_Configuration(); |
021 | EXTI_Configuration(); |
026 | void NVIC_Configuration( void ) |
028 | NVIC_InitTypeDef NVIC_InitStructure; |
031 | NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0); |
033 | NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0); |
036 | NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); |
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); |
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); |
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; |
055 | NVIC_Init(&NVIC_InitStructure); |
061 | void GPIO_Configuration( void ) |
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); |
068 | GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); |
069 | GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1); |
070 | GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource2); |
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); |
079 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; |
080 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; |
081 | GPIO_Init(GPIOA , &GPIO_InitStructure); |
084 | void EXTI_Configuration( void ) |
086 | EXTI_InitTypeDef EXTI_InitStructure; |
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); |
098 | void RCC_Configuration( void ) |
100 | /* 定义枚举类型变量 HSEStartUpStatus */ |
101 | ErrorStatus HSEStartUpStatus; |
106 | RCC_HSEConfig(RCC_HSE_ON); |
108 | HSEStartUpStatus = RCC_WaitForHSEStartUp(); |
109 | /* 判断HSE起是否振成功,是则进入if()内部 */ |
110 | if (HSEStartUpStatus == SUCCESS) |
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); |
119 | FLASH_SetLatency(FLASH_Latency_2); |
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); |
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); |
133 | /* 打开APB2总线上的GPIOA时钟*/ |
134 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO, ENABLE); |
136 | //RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE); |
141 | void USART_Configuration( void ) |
143 | USART_InitTypeDef USART_InitStructure; |
144 | USART_ClockInitTypeDef USART_ClockInitStructure; |
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); |
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); |
160 | USART_Cmd(USART1,ENABLE); |
164 | void TIM_Configuration( void ) |
172 | int fputc ( int ch, FILE *f) |
174 | USART_SendData(USART1,(u8) ch); |
175 | while (USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET); |
stm32f10x_it.c 01 | #include "stm32f10x_it.h" |
04 | void EXTI0_IRQHandler( void ) |
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); |
12 | void EXTI1_IRQHandler( void ) |
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); |
20 | void EXTI2_IRQHandler( void ) |
22 | printf ( "\r\nEXTI2 IRQHandler enter.\r\n" ); |
23 | printf ( "\r\nEXTI2 IRQHandler return.\r\n" ); |
24 | EXTI_ClearFlag(EXTI_Line2); |
|