当前位置:   article > 正文

江科大stm32视频学习笔记——中断的应用:对射式红外传感器计次&旋转编码器计次_江科大stm32配件 对射式红外传感器

江科大stm32配件 对射式红外传感器

目录

一、中断系统的结构框图及硬件介绍

1.1 外部中断结构

1.2 硬件介绍

 二、对射式红外传感器计次

2.1 硬件连接图

2.2 代码 

CountSensor.c

main.c

2.3 bug调试 

三、旋转编码器计次

3.1 硬件连接图 

3.2 代码 

Encoder.c 

main.c

3.3 bug调试


一、中断系统的结构框图及硬件介绍

1.1 外部中断结构

GPIO:(A-G)有多个分组,每组有16个引脚

AFIO:只有一组线到EXTI,AFIO在中间充当数据选择器

EXTI:用来检测其配置的引脚电平变化,并将信息发送到NVIC

NVIC:配置中断优先级,根据优先级顺序传至CPU进行处理

1.2 硬件介绍

 二、对射式红外传感器计次

2.1 硬件连接图

2.2 代码 

  • CountSensor.c

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

  1. #include "stm32f10x.h"                  // Device header
  2.  
  3. uint16_t CountSensor_Count;
  4.  
  5. void CountSensor_Init(void)
  6. {
  7.     //开启外设时钟,EXTI和NVIC自动开启,无需设置
  8.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  9.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
  10.     
  11. //配置GPIO
  12.     GPIO_InitTypeDef GPIO_InitStructure;
  13.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  14.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
  15.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  16.     GPIO_Init(GPIOB, &GPIO_InitStructure);
  17.     
  18.     //配置AFIO的数据选择器,选择想要的中断引脚
  19.     GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
  20.     
  21. //配置EXTI
  22.     EXTI_InitTypeDef EXTI_InitStructure;
  23.     EXTI_InitStructure.EXTI_Line = EXTI_Line14; //配置EXTI第14条线路
  24.     EXTI_InitStructure.EXTI_LineCmd = ENABLE; //开启中断
  25.     EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //设置为中断模式
  26.     EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
  27.     EXTI_Init(&EXTI_InitStructure);
  28.     
  29.     //配置NVIC(分组方式整个工程只能用一种)
  30.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //优先级分组
  31.     NVIC_InitTypeDef NVIC_InitStructure;
  32.     NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //指定中断请求通道
  33.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断请求通道
  34.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //NVIC抢占优先级
  35.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //NVIC响应优先级
  36.     NVIC_Init(&NVIC_InitStructure);
  37. }
  38. //也可以通过在主程序中声明外部变量将值传至主程序
  39. uint16_t CountSensor_Get(void)
  40. {
  41.     return CountSensor_Count;
  42. }
  43.  
  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 "OLED.h"
  3. #include "CountSensor.h"
  4. int main()
  5. {
  6. OLED_Init();
  7. OLED_ShowString(1, 1, "Count:"); // 显示一个字符串
  8. CountSensor_Init();
  9. while(1)
  10. {
  11. OLED_ShowNum(1, 7, CountSensor_Get(), 5);
  12. }
  13. }

2.3 bug调试 

  • 现象:计数器乱跳
  • 归因:触发时抖动造成
  • 解决方案:再次判断引脚电平,上升沿触发判据为1,下降沿触发判据为0,双边触发无需再次判断。实测仍不够稳定,在此基础上,两次判断之间加1ms延时,实测稳定。
  • 后续测试:在强光直射环境、使用镊子,纸张等不同遮挡介质,更改GPIO_Mode_IPU、GPIO_Mode_IPD模式对稳定性均无影响。

三、旋转编码器计次

3.1 硬件连接图 

3.2 代码 

  • Encoder.c 

  1. #include "stm32f10x.h" // Device header
  2. int16_t Encoder_Count;
  3. void Encoder_Init(void)
  4. {
  5. // 开启所需要使用的外设的时钟,EXTI和NVIC的时钟自动开启
  6. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  7. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
  8. // 配置GPIO
  9. GPIO_InitTypeDef GPIO_InitStructure;
  10. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  11. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
  12. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  13. GPIO_Init(GPIOB, &GPIO_InitStructure);
  14. // 配置AFIO
  15. GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0); // 将AFIO的第0个数据选择器拨到GPIOB上
  16. GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1); // 将AFIO的第1个数据选择器拨到GPIOB上
  17. // 配置EXTI(将EXTI的第0和1条线路配置为中断触发模式)
  18. EXTI_InitTypeDef EXTI_InitStructure; // 定义结构体变量
  19. EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1; // EXTI对应的输入线路,该变量可以时EXTI_Linex的任意组合
  20. EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 是否开启中断
  21. EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // EXTI配置为中断触发模式
  22. EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发
  23. EXTI_Init(&EXTI_InitStructure);
  24. // 配置NVIC(分组方式整个芯片只能用同一种)
  25. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // NVIC中断优先级分组
  26. // 对两个通道都进行优先级设置
  27. NVIC_InitTypeDef NVIC_InitStructure; // 这个变量可以重复使用
  28. NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
  29. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 指定中断通道是使能还是失能
  30. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // NVIC配置抢占优先级
  31. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // NVIC配置响应优先级
  32. NVIC_Init(&NVIC_InitStructure);
  33. NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
  34. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 指定中断通道是使能还是失能
  35. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // NVIC配置抢占优先级
  36. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; // NVIC配置响应优先级
  37. NVIC_Init(&NVIC_InitStructure);
  38. }
  39. int16_t Encoder_Get(void)
  40. {
  41. // return Encoder_Count;
  42. // 这里也可不不直接返回Encoder_Count,选择返回Encoder_Count的变化量
  43. int16_t Temp;
  44. Temp = Encoder_Count;
  45. Encoder_Count = 0;
  46. return Temp;
  47. }
  48. void EXTI0_IRQHandler(void)
  49. {
  50. if (EXTI_GetITStatus(EXTI_Line0) == SET) // 检查EXTI_Line0的中断标志位是否为1
  51. {
  52. if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0) // 检查PB0是否稳定在0,方式数字乱跳
  53. {
  54. if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0) // 反转(A的下降沿时B为低电平)
  55. {
  56. Encoder_Count --;
  57. }
  58. }
  59. EXTI_ClearITPendingBit(EXTI_Line0); // 清除EXTI_Line0的中断标志位
  60. }
  61. }
  62. void EXTI1_IRQHandler(void)
  63. {
  64. if (EXTI_GetITStatus(EXTI_Line1) == SET) // 检查EXTI_Line1的中断标志位是否为1
  65. {
  66. if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0) // 检查PB1是否稳定在0,方式数字乱跳
  67. {
  68. if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0) // 正转(B的下降沿时A为低电平)
  69. {
  70. Encoder_Count ++;
  71. }
  72. }
  73. EXTI_ClearITPendingBit(EXTI_Line1); // 清除EXTI_Line1的中断标志位
  74. }
  75. }
  • main.c

  1. #include "stm32f10x.h" // Device header
  2. #include "OLED.h"
  3. #include "Encoder.h"
  4. int16_t Num = 0;
  5. int main()
  6. {
  7. OLED_Init();
  8. OLED_ShowString(1, 1, "Num:"); // 显示一个字符串
  9. Encoder_Init();
  10. while(1)
  11. {
  12. Num += Encoder_Get();
  13. OLED_ShowSignedNum(1, 5, Num, 5);
  14. }
  15. }

3.3 bug调试

现象:计数器乱跳,非线性

归因:实测结论为连接性问题,旋转编码器直接插在面包板上,旋转旋钮时,易造成抖动。

解决方案:将旋转编码器引脚全部改用杜邦线接出来,实测结果稳定,一圈计数20。

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

闽ICP备14008679号