锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

STM32 CubeMax TCRT5000L光电对管巡线 原理与实现

时间:2023-04-26 00:07:00 光敏三极管t12d

STM32 CubeMax TCRT5000L光电管道巡线的原理和实现

1. 光电对管的原理

电子生产中使用的光电对管通常是TCRT5000系列,该系列分为TCRT5000TCRT5000L,两者的区别在于针脚的长度不同

在每个管道中包含一个红外光电二极管和一个光敏三极管,红外光电二极管不断向外发射红外线。红外线在外部环境反射后被光敏三极管吸收。光敏三极管的导通程度与吸收的红外强度成正比。因此,只要检测光敏三极管的导通程度,就知道反射红外材料的性质。一般来说,深色材料吸收更多的红外线,浅色材料反射更多的红外线。这是我们检测黑线的基本原理

由原理图可知,光敏三极管导通后输出的值是一个连续的模拟值,所以我们可以通过ADC读取模拟值并将其送入单片机进行处理,以获得非常高的灵敏度。这种做法的缺点是算法复杂。如果管道数量较多,则会对其进行处理ADC提出高要求。因此,为了简单起见,我们通常将这个模拟值发送到一个电压比较器在这种情况下,输出值只有0和1两种情况,单片机的负担会小以应付大多数场合

使用比较器的典型电路长度是目前的主流做法(仅供参考),使用多个光电将管道排成一排检测黑线

图中的三角形是电压比较器的符号,型号是LM393

典型的实物像这样,这是某宝上买的模块

如果你想现成的模块,最好看看上面有没有。电位器(直插贴片都可以),有电位器的一般可以调整比较器阈值,可测黑线的灵敏度可以调整(上面没有电位器,可能要自己换电阻…)

此时的算法编写相对简单,只要使用GPIO读取高低电平

2. CubeMax配置

以上发送的物理模块为例,共有5个光电对管,我们需要5个输入引脚。最好在这里使用输入外部中断而不是GPIO使用中断输入可以避免轮询检测,节省一些GPIO资源

因此,我们需要配置5个GPIO在配置引脚时,外部中断输入引脚,不要配置数字相同的引脚例如,作为中断输入,PA1和PB1.由于数字相同的引脚是共用的中断线,字母后引脚将覆盖字母前引脚(PB会覆盖PA),字母前引脚的中断不起作用(详见数据手册)

由于该模块检测到黑线输出较低,因此需要设置为内部上拉,上升\下降沿触发中断

最后,记得把外面中断优先级稍低,否则可能会出现中断冲突导致卡死,比如说在外部输入中断函数中调用HAL_Delay时,就会与Time base中断冲突导致卡死

其他基本配置不再重复

3. 接线

模块与STM32的接线如下

对管模块 STM32
5V 5V
GND GND
OUT1 PB0
OUT2 PB1
OUT3 PB10
OUT4 PB11
OUT5 PB12

4. 代码编写

eletube.h内容如下

#ifndef _ELETUBE_H_#define _ELETUBE_H_  #include "stm32f1xx.h"#include   //#define ETUBE_PIN_1  GPIO_PIN_0#define ETUBE_PIN_2  GPIO_PIN_1#define ETUBE_PIN_3  GPIO_PIN_10#define ETUBE_PIN_4  GPIO_PIN_11#define ETUBE_PIN_5  GPIO_PIN_12  #define ETUBE_PORT_1 GPIOB#define ETUBE_PORT_2 GPIOB#define ETUBE_PORT_3 GPIOB#define ETUBE_PORT_4 GPIOB#define ETUBE_PORT_5 GPIOB  void Etube_Check(void);///将探测情况输出   #endif

eletube.c内容如下

#include "eletube.h"  uint8_t etubeCkeck[5] = {1,1,1,1,1};//存储每个对管检测到黑线的状态,1没有检测到,0检测到  void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)//输入中断处理函数{   if(GPIO_Pin == ETUBE_PIN_1)//1号引脚   {                     if(HAL_GPIO_ReadPin(ETUBE_PORT_1,ETUBE_PIN_1)///上升沿                                         etubeCkeck[0] = 1;           if(!HAL_GPIO_ReadPin(ETUBE_PORT_1,ETUBE_PIN_1))//下降沿        {            etubeCkeck[0] = 0;              else if(GPIO_Pin == ETUBE_PIN_2)//2号引脚   {                   if(HAL_GPIO_ReadPin(ETUBE_PORT_2,ETUBE_PIN_(4)///上升沿                      etubETUBE_PIN_4))//上升沿        {            etubeCkeck[3] = 1;        }        if(!HAL_GPIO_ReadPin(ETUBE_PORT_4, ETUBE_PIN_4))//下降沿        {            etubeCkeck[3] = 0;        }    }    else if(GPIO_Pin == ETUBE_PIN_5)//4号引脚    {        if(HAL_GPIO_ReadPin(ETUBE_PORT_5, ETUBE_PIN_5))//上升沿        {            etubeCkeck[4] = 1;        }        if(!HAL_GPIO_ReadPin(ETUBE_PORT_5, ETUBE_PIN_5))//下降沿        {            etubeCkeck[4] = 0;        }    }}  void Etube_Check(void)//将探测情况输出{    uint8_t i = 0;    for(i = 0;i < 5;i++)    {        if(etubeCkeck[i] == 0) printf("0  ");        else if(etubeCkeck[i] == 1) printf("1  ");        else {};          printf("\r\n");    }}

之后在main函数里调用探测情况输出函数即可

while (1)  {    /* USER CODE END WHILE */      /* USER CODE BEGIN 3 */    Etube_Check();    HAL_Delay(500);  }

(记得自己将printf重定义)

5. 结果

输出正常,很ok

相关文章