10、外部中断实验

1、外部中断概述。

STM32F10X共有68个可屏蔽中断通道,16个可编程优先级(使用了4位中断优先级)。

互联型产品有20个事件/中断检测器。

其他产品有19个事件/中断检测器。

16个GPIO连接到EXIT0到EXIT15(16个中断线)。

EXIT16连接到PVD事件。

EXIT17连接到RTC闹钟事件。

EXIT18连接到USB唤醒事件。

EXIT19连接到以太网唤醒事件(只适用于互联型产品)。

2、寄存器。

 

10、外部中断实验_第1张图片

10、外部中断实验_第2张图片

IMR 中断可屏蔽寄存器,interrupt mast register。

EMR 事件可屏蔽寄存器,event masmast register。

RTSR 上升沿触发选择寄存器,rising trigger selection register。

FTSR 下降沿触发选择寄存器,falling trigger selection register。

SWIER 软件中断事件寄存器,software interrupt event register。

PR 挂起寄存器,pending register。

3、外部中断一般步骤。

①初始化IO口为输入。

RCC_APB2PeirphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

GPIO_Init(GPIOB,&GPIO_InitStrucure);

②开启AFIO时钟。

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

③设置IO与中断线映射关系。

GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource2);

④初始化线上中断,设置触发条件等。

EXTI_Init(&EXTI_InitStructure);

⑤配置中断分组(NVIC),并使能中断。

NVIC_Init(&NVIC_InitStructure);

⑥编写中断服务函数。

EXTI0_IRQHandler();

16个外部外部中断线共有6个中断处理函数,分别是EXTI0、EXTI1、EXTI2、EXTI3、EXTI4、EXTI9_5、EXTI15_10。

4、函数讲解。

①IO口与中断线映射。操作AFIO(复用功能IO)的EXTICR寄存器。

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
{
  uint32_t tmp = 0x00;
  /* 判断参数,portsource外部中断端口,pinsource引脚号 */
  assert_param(IS_GPIO_EXTI_PORT_SOURCE(GPIO_PortSource));
  assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource));
  
  //引脚号取低两位,乘以4,0x0F左移指定位数。乘以4时因为一个pin的控制占EXTICR的4bit
  tmp = ((uint32_t)0x0F) << (0x04 * (GPIO_PinSource & (uint8_t)0x03));    
  
  //EXTICR共有4个对应Pin0-Pin15,清零引脚号对应的寄存器位置
  AFIO->EXTICR[GPIO_PinSource >> 0x02] &= ~tmp;    

  //引脚号对应的寄存器位置设置为外部中断端口,即设置为GPIOA.B.C.D.E.F.G其中的一个
  AFIO->EXTICR[GPIO_PinSource >> 0x02] |= 
  (((uint32_t)GPIO_PortSource) << (0x04 * (GPIO_PinSource & (uint8_t)0x03)));
	
}

②初始化外部中断参数。caoI操作断屏蔽、EMR事件屏蔽、RTSR上升沿触发、FTSR下降沿触发。

void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)
{
  uint32_t tmp = 0;

  /* 检查参数,MODE模式中断或事件,TRIGGER触发上升沿或下降沿,LINE中断线号,STATE状态使能与否 */
  assert_param(IS_EXTI_MODE(EXTI_InitStruct->EXTI_Mode));
  assert_param(IS_EXTI_TRIGGER(EXTI_InitStruct->EXTI_Trigger));
  assert_param(IS_EXTI_LINE(EXTI_InitStruct->EXTI_Line));  
  assert_param(IS_FUNCTIONAL_STATE(EXTI_InitStruct->EXTI_LineCmd));

  tmp = (uint32_t)EXTI_BASE;    //tmp赋值外部中断基地址   
     
  if (EXTI_InitStruct->EXTI_LineCmd != DISABLE)    //中断使能
  {
    /* 清零中断屏蔽对应中断线和事件屏蔽对应中断线 */
    EXTI->IMR &= ~EXTI_InitStruct->EXTI_Line;    //中断屏蔽清零
    EXTI->EMR &= ~EXTI_InitStruct->EXTI_Line;    //事件屏蔽清零
    
    tmp += EXTI_InitStruct->EXTI_Mode;    //通过模式选择是中断屏蔽寄存器还是事件屏蔽寄存器

    *(__IO uint32_t *) tmp |= EXTI_InitStruct->EXTI_Line;    //选择的的寄存器执行对应屏蔽线的置位

    /* 清零上升沿选择对应中断线和下降沿选择对应中断线 */
    EXTI->RTSR &= ~EXTI_InitStruct->EXTI_Line;    //上升沿触发寄存器清零对应中断线
    EXTI->FTSR &= ~EXTI_InitStruct->EXTI_Line;    //下降沿触发寄存器清零对应中断线
    
    /* 选择触发方式 */
    if (EXTI_InitStruct->EXTI_Trigger == EXTI_Trigger_Rising_Falling)    //上升沿和下降沿同时触发
    {
      /* 设置上升沿触发对应中断线和下降沿触发对应中断线 */
      EXTI->RTSR |= EXTI_InitStruct->EXTI_Line;    //置位中断线对应的上升沿触发寄存器
      EXTI->FTSR |= EXTI_InitStruct->EXTI_Line;    //置位中断线对应的下降沿触发寄存器
    }
    else
    {
      tmp = (uint32_t)EXTI_BASE;    //tmp赋值外部中断基地址
      tmp += EXTI_InitStruct->EXTI_Trigger;    //通过触发边沿选择上升沿触发寄存器还是下降沿触发寄存器

      *(__IO uint32_t *) tmp |= EXTI_InitStruct->EXTI_Line;    //选择的边沿触进行使能
    }
  }
  else    //中断失能
  {
    tmp += EXTI_InitStruct->EXTI_Mode;    //模式选择中断屏蔽寄存器或者事件屏蔽寄存器

    *(__IO uint32_t *) tmp &= ~EXTI_InitStruct->EXTI_Line;    //对应的中断线,1取反为0,与0进行清零
  }
}

③中断标志获取和中断标志清零。操作IMR中断屏蔽、PR挂起。

标志获取EXTI_GetFlagStatus(),只需要操作PR即可。

ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)
{
  ITStatus bitstatus = RESET;
  uint32_t enablestatus = 0;
  /* 判断参数exti_line为中断线 */
  assert_param(IS_GET_EXTI_LINE(EXTI_Line));
  
  enablestatus =  EXTI->IMR & EXTI_Line;    //取中断线对应中断屏蔽位
  //挂起寄存器置位和中断屏蔽位置位,则此中断使能
  if (((EXTI->PR & EXTI_Line) != (uint32_t)RESET) && (enablestatus != (uint32_t)RESET))    
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  return bitstatus;
}

void EXTI_ClearITPendingBit(uint32_t EXTI_Line)
{
  /* 确定参数,exti_line为中断线 */
  assert_param(IS_EXTI_LINE(EXTI_Line));
  
  EXTI->PR = EXTI_Line;    //挂起寄存器置位进行挂起寄存器的清零
}

5、外部中断实验操作。

①外部中断初始化函数。

void EXTIX_Init(void)
{
	EXTI_InitTypeDef EXTI_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	KEY_Init();    //GPIO初始化
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);    //外部中断需要使能AFIO时钟
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);    //GPIOE.2外部中断
	EXTI_InitStructure.EXTI_Line = EXTI_Line2;    //中断线2
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;    //中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;    //上升沿
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;    //中断使能
	EXTI_Init(&EXTI_InitStructure);    //外部中断参数初始化
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);    //GPIOE.3外部中断
	EXTI_InitStructure.EXTI_Line = EXTI_Line3;    //中断线3,其他参数同中断线2
	EXTI_Init(&EXTI_InitStructure);    //外部中断参数初始化
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);    //GPIOE.4外部中断
	EXTI_InitStructure.EXTI_Line = EXTI_Line4;    //中断线4,其他参数同中断线2
	EXTI_Init(&EXTI_InitStructure);    //外部中断参数初始化
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);    //GPIOA.0外部中断
	EXTI_InitStructure.EXTI_Line = EXTI_Line0;    //中断线0
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;    //上升沿,其他参数同中断线2
	EXTI_Init(&EXTI_InitStructure);    //外部中断参数初始化
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;    //外部中断0优先级设置
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;    //外部中断2优先级设置
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;    //外部中断3优先级设置
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;    //外部中断4优先级设置
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

②中断处理函数。

//外部中断0服务函数
void EXTI0_IRQHandler(void)
{
	delay_ms(10);
	if(WK_UP==1)    //WK_UP按下
	{
		BEEP = !BEEP;
	}
	EXTI_ClearITPendingBit(EXTI_Line0);    //清零中断标志
}

//外部中断2服务函数
void EXTI2_IRQHandler(void)
{
	delay_ms(10);
	if(KEY2==0)    //KEY2按下
	{
		LED0 = !LED0;
		LED1 = !LED1;
	}
	EXTI_ClearITPendingBit(EXTI_Line2);    //清零中断标志
}

//外部中断3服务函数
void EXTI3_IRQHandler(void)
{
	delay_ms(10);
	if(KEY1==0)    //KEY1按下
	{
		LED1 = !LED1;
	}
	EXTI_ClearITPendingBit(EXTI_Line3);    //清零中断标志
}

//外部中断4服务函数
void EXTI4_IRQHandler(void)
{
	delay_ms(10);
	if(KEY0==0)    //KEY0按下
	{
		LED0 = !LED0;
	}
	EXTI_ClearITPendingBit(EXTI_Line4);    //清零中断标志
}

③主函数。

int main()
{
	delay_init();
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	uart_init(115200);
	LED_Init();
	BEEP_Init();
	KEY_Init();
	EXTIX_Init();
	
	while(1)
	{
		printf("hello world!\r\n");
		delay_ms(1000);
	}
}

 

你可能感兴趣的:(STM32)