当前位置:   article > 正文

STM32F103学习笔记(三) 外部中断(应用篇)_stm32f103如何让外部中断只触发一次

stm32f103如何让外部中断只触发一次

目录

1. 外部中断的常见应用场景

2. 外部中断的配置

3. 实例演示代码 

4. 总结

1. 外部中断的常见应用场景

        外部中断在嵌入式系统中具有广泛的应用场景,主要用于实时响应外部事件。下面介绍几种常见的应用场景:

        按键检测:外部中断常用于按键检测,例如在嵌入式系统中,我们经常需要检测按钮的按下或释放事件。通过将按钮连接到微控制器的外部中断引脚上,可以在按钮按下时触发外部中断,并在中断服务程序中处理相应的按键事件,如启动/停止操作、菜单切换等。

        传感器触发:外部中断也经常与传感器结合使用,用于实时监测外部环境的变化。例如,我们可以连接红外传感器、超声波传感器或光电传感器到外部中断引脚上,当传感器检测到特定事件(如物体接近、光线强度变化等)时,触发外部中断,从而及时处理相关事件,如报警、数据采集等。

        定时器中断扩展:外部中断与定时器结合使用,可以扩展定时器的功能。例如,我们可以利用定时器产生的定时中断来触发外部中断,从而实现定时采样、定时测量等功能。这种应用场景特别适用于需要定时执行某些任务的情况,如定时采集温湿度数据、定时发送数据等。

        外部设备触发:外部中断还常用于外部设备的触发和控制。例如,外部中断可以用于接收外部设备的触发信号,如外部传感器的报警信号、外部触发器的触发信号等,并据此执行相应的控制逻辑,如启动/停止设备、调整参数等。

        低功耗唤醒:外部中断还可用于实现低功耗唤醒功能。例如,在低功耗模式下,通过外部中断引脚接收外部事件的触发信号,可以唤醒微控制器,从而实现低功耗状态下的实时监测和响应。

2. 外部中断的配置

        配置外部中断是使用外部中断功能的关键步骤,它涉及到对外部中断引脚的配置、中断触发条件的设置以及中断服务程序的编写。以下是配置外部中断的基本步骤:

        引脚配置:首先,需要选择合适的引脚作为外部中断引脚,并将其配置为外部中断输入模式。在STM32F103系列微控制器中,每个引脚都可以作为外部中断引脚使用,需要根据具体的硬件连接和应用需求选择合适的引脚。然后,使用相应的寄存器设置将引脚配置为外部中断输入模式。

        中断触发模式设置:其次,需要根据具体的应用需求设置外部中断的触发模式。外部中断可以根据电平变化或边沿变化来触发中断,包括上升沿触发、下降沿触发、上升沿/下降沿触发等模式。在STM32F103系列微控制器中,可以通过配置外部中断触发控制寄存器来选择合适的触发模式。

        中断服务程序编写:最后,需要编写外部中断的中断服务程序。中断服务程序是一个特殊的函数,用于处理外部中断触发时的事件。在中断服务程序中,我们可以编写相应的处理逻辑,如更新状态标志、执行特定操作等。在编写中断服务程序时,需要注意保持程序的简洁高效,尽量避免使用延迟操作或阻塞式的代码,以确保系统的实时响应能力。

3. 实例演示代码 

        总结了开启所有外部中断的函数,通过简单的配置函数参数即可选定开启的外部中断通道

  1. void EXITX_Tnit(GPIO_TypeDef* GPIOX,uint16_t PIN)
  2. {
  3. /*开启时钟*/
  4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO时钟
  5. /*GPIO初始化*/
  6. if(GPIOX == GPIOA) gpio_init(RCC_APB2Periph_GPIOA,GPIO_Mode_IPU,GPIOA,PIN);
  7. if(GPIOX == GPIOB) gpio_init(RCC_APB2Periph_GPIOB,GPIO_Mode_IPU,GPIOB,PIN);
  8. if(GPIOX == GPIOC) gpio_init(RCC_APB2Periph_GPIOC,GPIO_Mode_IPU,GPIOC,PIN);
  9. if(GPIOX == GPIOA) GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GetPinSource(PIN));//将外部中断的N号线映射到GPIO
  10. if(GPIOX == GPIOB) GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GetPinSource(PIN));
  11. if(GPIOX == GPIOC) GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GetPinSource(PIN));
  12. /*EXTI初始化*/
  13. EXTI_InitTypeDef EXTI_InitStructure; //定义结构体变量
  14. EXTI_InitStructure.EXTI_Line = (uint32_t)PIN; //选择配置外部中断的14号线
  15. EXTI_InitStructure.EXTI_LineCmd = ENABLE; //指定外部中断线使能
  16. EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //指定外部中断线为中断模式
  17. EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //指定外部中断线为下降沿触发
  18. EXTI_Init(&EXTI_InitStructure); //将结构体变量交给EXTI_Init,配置EXTI外设
  19. /*NVIC配置*/
  20. NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量
  21. if(PIN == 0x0001) NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //选择配置NVIC的EXTI0线
  22. if(PIN == 0x0002) NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; //选择配置NVIC的EXTI1线
  23. if(PIN == 0x0004) NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //选择配置NVIC的EXTI2线
  24. if(PIN == 0x0008) NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //选择配置NVIC的EXTI3线
  25. if(PIN == 0x0010) NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; //选择配置NVIC的EXTI4线
  26. if((PIN & 0x03E0) != 0x0000) NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //选择配置NVIC的EXTI9_5线
  27. if((PIN & 0xFC00) != 0x0000) NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //选择配置NVIC的EXTI15_10线
  28. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC线路使能
  29. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定NVIC线路的抢占优先级为1
  30. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC线路的响应优先级为1
  31. NVIC_Init(&NVIC_InitStructure); //将结构体变量交给NVIC_Init,配置NVIC外设
  32. }

以下PIN口转换通道函数配合使用

  1. uint8_t GetPinSource(uint16_t pin)
  2. {
  3. if (pin == GPIO_Pin_0) return GPIO_PinSource0;
  4. if (pin == GPIO_Pin_1) return GPIO_PinSource1;
  5. if (pin == GPIO_Pin_2) return GPIO_PinSource2;
  6. if (pin == GPIO_Pin_3) return GPIO_PinSource3;
  7. if (pin == GPIO_Pin_4) return GPIO_PinSource4;
  8. if (pin == GPIO_Pin_5) return GPIO_PinSource5;
  9. if (pin == GPIO_Pin_6) return GPIO_PinSource6;
  10. if (pin == GPIO_Pin_7) return GPIO_PinSource7;
  11. if (pin == GPIO_Pin_8) return GPIO_PinSource8;
  12. if (pin == GPIO_Pin_9) return GPIO_PinSource9;
  13. if (pin == GPIO_Pin_10) return GPIO_PinSource10;
  14. if (pin == GPIO_Pin_11) return GPIO_PinSource11;
  15. if (pin == GPIO_Pin_12) return GPIO_PinSource12;
  16. if (pin == GPIO_Pin_13) return GPIO_PinSource13;
  17. if (pin == GPIO_Pin_14) return GPIO_PinSource14;
  18. if (pin == GPIO_Pin_15) return GPIO_PinSource15;
  19. return 0xFF;
  20. }

中断服务函数(可将触发条件后所需执行的代码替换进去)

  1. void EXTI0_IRQHandler(void)
  2. {
  3. cnt++; //计数值自增一次
  4. EXTI_ClearITPendingBit(EXTI_Line0); //清除外部中断0号线的中断标志位
  5. }
  6. void EXTI1_IRQHandler(void)
  7. {
  8. cnt++; //计数值自增一次
  9. EXTI_ClearITPendingBit(EXTI_Line1); //清除外部中断1号线的中断标志位
  10. }
  11. void EXTI2_IRQHandler(void)
  12. {
  13. cnt++; //计数值自增一次
  14. EXTI_ClearITPendingBit(EXTI_Line2); //清除外部中断2号线的中断标志位
  15. }
  16. void EXTI3_IRQHandler(void)
  17. {
  18. cnt++; //计数值自增一次
  19. EXTI_ClearITPendingBit(EXTI_Line3); //清除外部中断3号线的中断标志位
  20. }
  21. void EXTI4_IRQHandler(void)
  22. {
  23. cnt++; //计数值自增一次
  24. EXTI_ClearITPendingBit(EXTI_Line4); //清除外部中断4号线的中断标志位
  25. }
  26. void EXTI9_5_IRQHandler(void)
  27. {
  28. if (EXTI_GetITStatus(EXTI_Line5) == SET) //判断是否是外部中断5号线触发的中断
  29. {
  30. cnt++; //计数值自增一次
  31. EXTI_ClearITPendingBit(EXTI_Line5); //清除外部中断5号线的中断标志位
  32. }
  33. if (EXTI_GetITStatus(EXTI_Line6) == SET) //判断是否是外部中断6号线触发的中断
  34. {
  35. cnt++; //计数值自增一次
  36. EXTI_ClearITPendingBit(EXTI_Line6); //清除外部中断6号线的中断标志位
  37. }
  38. if (EXTI_GetITStatus(EXTI_Line7) == SET) //判断是否是外部中断7号线触发的中断
  39. {
  40. cnt++; //计数值自增一次
  41. EXTI_ClearITPendingBit(EXTI_Line7); //清除外部中断7号线的中断标志位
  42. }
  43. if (EXTI_GetITStatus(EXTI_Line8) == SET) //判断是否是外部中断8号线触发的中断
  44. {
  45. cnt++; //计数值自增一次
  46. EXTI_ClearITPendingBit(EXTI_Line8); //清除外部中断8号线的中断标志位
  47. }
  48. if (EXTI_GetITStatus(EXTI_Line9) == SET) //判断是否是外部中断9号线触发的中断
  49. {
  50. cnt++; //计数值自增一次
  51. EXTI_ClearITPendingBit(EXTI_Line9); //清除外部中断9号线的中断标志位
  52. }
  53. }
  54. void EXTI15_10_IRQHandler(void)
  55. {
  56. if (EXTI_GetITStatus(EXTI_Line10) == SET) //判断是否是外部中断10号线触发的中断
  57. {
  58. cnt++; //计数值自增一次
  59. EXTI_ClearITPendingBit(EXTI_Line10); //清除外部中断10号线的中断标志位
  60. }
  61. if (EXTI_GetITStatus(EXTI_Line11) == SET) //判断是否是外部中断11号线触发的中断
  62. {
  63. cnt++; //计数值自增一次
  64. EXTI_ClearITPendingBit(EXTI_Line11); //清除外部中断11号线的中断标志位
  65. }
  66. if (EXTI_GetITStatus(EXTI_Line12) == SET) //判断是否是外部中断12号线触发的中断
  67. {
  68. cnt++; //计数值自增一次
  69. EXTI_ClearITPendingBit(EXTI_Line12); //清除外部中断12号线的中断标志位
  70. }
  71. if (EXTI_GetITStatus(EXTI_Line13) == SET) //判断是否是外部中断13号线触发的中断
  72. {
  73. cnt++; //计数值自增一次
  74. EXTI_ClearITPendingBit(EXTI_Line13); //清除外部中断13号线的中断标志位
  75. }
  76. if (EXTI_GetITStatus(EXTI_Line14) == SET) //判断是否是外部中断14号线触发的中断
  77. {
  78. cnt++; //计数值自增一次
  79. EXTI_ClearITPendingBit(EXTI_Line14); //清除外部中断14号线的中断标志位
  80. }
  81. if (EXTI_GetITStatus(EXTI_Line15) == SET) //判断是否是外部中断15号线触发的中断
  82. {
  83. cnt++; //计数值自增一次
  84. EXTI_ClearITPendingBit(EXTI_Line15); //清除外部中断15号线的中断标志位
  85. }
  86. }

主函数开启初始化

EXITX_Tnit(GPIOX,GPIO_Pin_X);

        注意!!相同的PIN口不能一起使用,例如PA0与PB0,都是共享的外部中断通道0,故同时只能使用一个PIN口,防止程序逻辑错误的情况

4. 总结

        通过这篇学习笔记,我对外部中断的基础配置进行了学习。在整个学习过程中,我努力从多个通道的配置去理解外部中断的应用逻辑,并在撰写笔记的过程中,尽可能详细地呈现出来。然而,我也意识到在某些方面可能存在不足和错误,并希望通过后续的学习和实践来不断改进和完善。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/479303
推荐阅读
相关标签
  

闽ICP备14008679号