• stm32学习笔记:中断的应用:对射式红外传感器计次&旋转编码器计次


    相关API介绍

    EXT配置API(stm32f10x exti.h)

    NVIC 配置API (misc.h)

     初始化的中断的步骤

        第一步:配置RCC时钟,把涉及外设的时钟都打开
        第二步:配置GPIO,设置为输入模式
        第三步:配置AFIO,选择某个GPIO口连接到EXTI(边缘检测及控制器)
        第四步:配置EXTI(不需要开启时钟,原因不详),选择边沿触发方式和触发响应方式
        边沿触发方式:上升沿、下降沿、或者双边沿,触发响应方式:中断响应和事件响应
        第五步:配置NVIC(内核的外设,不需要开启时钟),给中断选择一个合适的优先级

     

     对射式红外传感器计次

    CountSensor.h

    1. #ifndef __COUNT_SENEOR_H
    2. #define __COUNT_SENEOR_H
    3. extern void CountSensor_Init(void);
    4. extern uint16_t CountSensor_Get(void);
    5. #endif
    CountSensor.c
    1. #include "stm32f10x.h" // Device header
    2. uint16_t CountSensor_Count;
    3. void CountSensor_Init(void)
    4. {
    5. //第一步:配置RCC时钟,把涉及外设的时钟都打开
    6. //第二步:配置GPIO,设置为输入模式
    7. //第三步:配置AFIO,选择某个GPIO口连接到EXTI(边缘检测及控制器)
    8. //第四步:配置EXTI(不需要开启时钟,原因不详),选择边沿触发方式和触发响应方式
    9. //边沿触发方式:上升沿、下降沿、或者双边沿,触发响应方式:中断响应和事件响应
    10. //第五步:配置NVIC(内核的外设,不需要开启时钟),给中断选择一个合适的优先级
    11. //对射式红外传感器:B14
    12. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    13. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    14. GPIO_InitTypeDef GPIO_InitStructure;
    15. //参考手册中文版中,第八章GPIO有说明说明外设设置什么格式
    16. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入,默认为高电平
    17. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
    18. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    19. GPIO_Init(GPIOB, &GPIO_InitStructure);
    20. //配置AFIO的数据选择器,选择想要的中断引脚
    21. GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
    22. EXTI_InitTypeDef EXTI_InitStructure;
    23. EXTI_InitStructure.EXTI_Line = EXTI_Line14;
    24. EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    25. EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断模式(而不是事件响应)
    26. //三种,上升沿,下降沿,上升沿+下降沿
    27. EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
    28. EXTI_Init(&EXTI_InitStructure);
    29. //5种分组方式选择其中的一种
    30. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    31. NVIC_InitTypeDef NVIC_InitStructure;
    32. //在stm32f10x.h中选择,该芯片是MD中等密度的,锁选择STM32F10X_MD即可
    33. //stm32的EXTI10到EXTI15都是合并到EXTI15_10_IRQn通道的
    34. NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;//指定通道
    35. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    36. //在misc文件中查找NVIC_Priority_Table,查的分组2的抢占优先级和响应优先级的取值范围均为0-3
    37. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    38. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    39. NVIC_Init(&NVIC_InitStructure);
    40. }
    41. uint16_t CountSensor_Get(void)
    42. {
    43. return CountSensor_Count;//全局变量
    44. }
    45. //中断函数不需要申明,因为不需要调用,是直接申明的
    46. //中断函数都是无参,无返回值
    47. void EXTI15_10_IRQHandler(void) //中断函数的名字都是固定的
    48. {
    49. //因为10-15通道都可以进来,故要判断是不是想要的14通道进来
    50. if (EXTI_GetITStatus(EXTI_Line14) == SET)
    51. {
    52. /*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
    53. if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0)
    54. {
    55. CountSensor_Count ++;
    56. }
    57. //中断程序结束后,一定要再调用一下清楚中断标志位的函数,
    58. //只有中断标志位置1,程序就会跳转到中断函数
    59. //如果不清除中断标志位,就会一直申请中断,
    60. //这样程序就会不断响应中断,执行中断函数,程序就会卡死在中断函数中
    61. EXTI_ClearITPendingBit(EXTI_Line14);
    62. }
    63. }

     main.c

    1. #include "stm32f10x.h" // Device header
    2. #include "Delay.h"
    3. #include "OLED.h"
    4. #include "CountSensor.h"
    5. int main(void)
    6. {
    7. OLED_Init();
    8. CountSensor_Init();
    9. //从第一行,第一列开始写
    10. OLED_ShowString(1, 1, "Count:");
    11. while (1)
    12. {
    13. //从第一行第7列开始写
    14. OLED_ShowNum(1, 7, CountSensor_Get(), 5);
    15. }
    16. }

     旋转编码器计次

    Encoder.c

    如果把A相的下降沿用作触发中断,在中断时刻读取B相的电平
    则正转是高电平,反转是低电平
    正转时,A相先出现下降沿,所以刚开始动,就进中断了
    反转后,A相先出现下降沿,转到位了,才进入中断

    故该实验:A、B相都触发中断
    正转:B相下降沿、A相低电平
    反转:A相下降沿、B相低电平
    这样保证正转和反转都是转到位,才执行数字加减的操作

    1. #include "stm32f10x.h" // Device header
    2. #include "Delay.h"
    3. int16_t EncoderCount = 0;
    4. void Encoder_Init(void)
    5. {
    6. // 配置RCC, 将涉及到的外设全部打开, 不打开时钟外设无法工作
    7. // EXTI 和 NVIC 的时钟是一直打开的, 不需要再开启时钟了, 因为 NVIC 是内核的外设
    8. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 开启 GPIOB 的时钟
    9. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 开启 AFIO 的时钟
    10. // 配置 GPIO_Pin_B0 | GPIO_Pin_B1, 设置端口为输入模式
    11. GPIO_InitTypeDef GPIO_InitStructure;
    12. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉、下拉、浮空输入均可
    13. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
    14. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    15. GPIO_Init(GPIOB, &GPIO_InitStructure);
    16. // 配置 AFIO, 选择我们用的 GPIO 到后面的 EXTI
    17. GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0); // PB0 -> EXTI0
    18. GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1); // PB1 -> EXTI1
    19. // 配置 EXTI: 将EXTI的第0、1个线路配置为中断模式、下降沿触发、然后开启中断
    20. EXTI_InitTypeDef EXTI_InitStruct;
    21. EXTI_InitStruct.EXTI_Line = EXTI_Line0 | EXTI_Line1; // 选择PB0 所在的第0个线路、选择 PB1 所在的第1个线路
    22. EXTI_InitStruct.EXTI_LineCmd = ENABLE; // 开启中断
    23. EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; // 中断模式 或 事件模式
    24. EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发
    25. EXTI_Init(&EXTI_InitStruct);
    26. // 配置 NVIC, 给 EXTI0 中断选择一个合适的优先级, 最终外部中断信号就能进入 CPU 了
    27. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 2位抢占, 2位响应, 整个工程需要设置成一致的.
    28. NVIC_InitTypeDef NVIC_InitStruct;
    29. NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; // 选择进入 NVIC 的通道
    30. NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; // 通道使能
    31. NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级: 0~3
    32. NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; // 响应优先级: 0~3
    33. NVIC_Init(&NVIC_InitStruct);
    34. // 配置 NVIC, 给 中断选择一个合适的优先级, 最终外部中断信号就能进入 CPU 了
    35. NVIC_InitStruct.NVIC_IRQChannel = EXTI1_IRQn;
    36. NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; // 通道使能
    37. NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级: 0~3
    38. NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; // 响应优先级: 0~3
    39. NVIC_Init(&NVIC_InitStruct);
    40. }
    41. void EXTI0_IRQHandler(void)
    42. {
    43. ITStatus res = EXTI_GetITStatus(EXTI_Line0); // 判断是否是 EXIT0
    44. if(SET == res)
    45. {
    46. // 抖动延时下
    47. Delay_ms(3);
    48. if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0 && GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0) // 正转
    49. {
    50. EncoderCount--;
    51. }
    52. EXTI_ClearITPendingBit(EXTI_Line0); // 清除中断标志位
    53. }
    54. }
    55. void EXTI1_IRQHandler(void)
    56. {
    57. ITStatus res = EXTI_GetITStatus(EXTI_Line1); // 判断是否是 EXIT1
    58. if(SET == res)
    59. {
    60. // 抖动延时下
    61. Delay_ms(3);
    62. if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0 && GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0) // 反转
    63. {
    64. EncoderCount++;
    65. }
    66. EXTI_ClearITPendingBit(EXTI_Line1); // 清除中断标志位
    67. }
    68. }
    69. int16_t Encoder_Get(void)
    70. {
    71. int16_t Temp = EncoderCount;
    72. EncoderCount = 0;
    73. return Temp;
    74. }

     Encoder.h

    1. #ifndef __ENCODER_H
    2. #define __ENCODER_H
    3. extern void Encoder_Init(void);
    4. extern int16_t Encoder_Get(void);
    5. #endif

    main.c

    1. #include "stm32f10x.h" // Device header
    2. #include "Delay.h"
    3. #include "oled.h"
    4. #include "encoder.h"
    5. static int16_t Num = 0;
    6. int main(void)
    7. {
    8. OLED_Init();
    9. Encoder_Init();
    10. OLED_ShowString(1, 1, "Num:");
    11. while(1)
    12. {
    13. Num += Encoder_Get();
    14. OLED_ShowSignedNum(1, 5, Num, 5);
    15. }
    16. }

  • 相关阅读:
    Stable Diffusion XL搭建
    Scala基础【正则表达式、框架式开发原则】
    聊聊操作系统中 进程 and 线程中哪些事??
    掷骰子的多线程应用程序1(复现《Qt C++6.0》)
    Flink
    在SPDK中使能E810网卡ADQ特性
    小知识· Zigbee 简介
    解决ios向mac复制文字不成功的一种方法
    Arduino IDE + Esp32 Cam + 实现视频流 + 开发环境部署
    MVP 聚技站|.NET C# 系列(六):调试 C# 控制台应用程序
  • 原文地址:https://blog.csdn.net/hmh520i/article/details/133799412