单片机学习小组
直播中

哥儿

8年用户 928经验值
擅长:嵌入式技术
私信 关注

如何去实现一种基于三路循迹模块的智能小车设计呢

红外传感器巡线的基本原理是什么?
如何去实现一种基于三路循迹模块的智能小车设计呢?

回帖(1)

刘晓英

2022-1-20 14:06:00
1.引脚定义:
GND接地,VCC供电,X1、X2、X3各自对应一对红外探头
2.实验原理:
红外传感器巡线的基本原理是利用物体的反射性质,当红外线发射到黑色上时会被黑线吸收掉,当红外线发射到不同的颜色的材料上会有不同反射到红外的接手管上,已产生不同大小的光电流,从而影响三路引脚输入电平高低。
3.注意:


  • 红外探头发出的红外光是人眼无法看到的。
  • 为了避免太阳光对红外传感器产生影响,所以我们需要在室内使用该模块。
  • 工作电压: 3.3v~5v
    remote.h


#ifndef __REMOTE_H
#define __REMOTE_H                                   


#define left GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3)
#define        mid GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2)
#define        right GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)


void remote_init(void);


void run_left(void);
void run_right(void);
void run_forth(void);
void run_back(void);
void run_stop(void);


#endif


remote.c

#include "remote.h"
#include "sys.h"


void remote_init()
{
       
          GPIO_InitTypeDef GPIO_InitStructure;
   
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //开启IO口对应的时钟
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
       
       
          GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_3;                        //PA2 PA3
          GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
          GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
          GPIO_Init(GPIOA,&GPIO_InitStructure);
       
          GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;                                                //PB0
          GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
          GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
          GPIO_Init(GPIOB,&GPIO_InitStructure);
}


void run_forth()
{
        TIM_SetCompare1(TIM4,780);
        TIM_SetCompare2(TIM4,899);
        TIM_SetCompare3(TIM4,782);
        TIM_SetCompare4(TIM4,899);       
}


void run_left()
{
        TIM_SetCompare1(TIM4,860);
        TIM_SetCompare2(TIM4,899);
        TIM_SetCompare3(TIM4,760);
        TIM_SetCompare4(TIM4,899);       
}


void run_right()
{
        TIM_SetCompare1(TIM4,760);
        TIM_SetCompare2(TIM4,899);
        TIM_SetCompare3(TIM4,860);
        TIM_SetCompare4(TIM4,899);       
}


void run_back()
{
        TIM_SetCompare1(TIM4,899);
        TIM_SetCompare2(TIM4,800);
        TIM_SetCompare3(TIM4,899);
        TIM_SetCompare4(TIM4,800);       
}


void run_stop()
{
        TIM_SetCompare1(TIM4,899);
        TIM_SetCompare2(TIM4,899);
        TIM_SetCompare3(TIM4,899);
        TIM_SetCompare4(TIM4,899);       


}
main.c

#include "sys.h"
#include "delay.h"
//#include "usart.h"
#include "led.h"
#include "oled.h"
#include "motor.h"
#include "timer.h"
#include "remote.h"
//#include "tick_ulsonic.h"            
//#include "ultrasonic.h"       


/***********************************************************************************************
本来是一个三路巡线模块,但因为模块质量问题,中间识别能力较差,故只使用左右两路,逻辑上也可以实现。
****************************************************************************************************************/


void pointleft(void); //OLED方向指示
void pointright(void);
void pointforth(void);
void pointback(void);




int main(void)
{       
        u8 i=0;
        u8 val1;
        u8 val2;
        SystemInit();
        delay_init();            //延时函数初始化          nms<=1864  
                                RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);// 或使用JTAG_Set(0X01);
                                GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
                                LED_Init();
//        uart_init(115200);
        LED_Init();                          //初始化与LED连接的硬件接口
        OLED_Init();
        pwm_init(899,0);
//        Tim3_Config();
//        ulsonic0_config();                //  ECHO PA2        TRIG PA3
//        ulsonic1_config();                //  ECHO PA13        TRIG PA14
         remote_init();
         delay_ms(1800);         delay_ms(1800);         delay_ms(1800);
         run_forth();
         while(1)                                                                                                //基于实际操作环境,在纸张内返回引脚口读取0,纸张外读取1。
         {




                 
                 val1=left;
                 val2=right;
                        switch(val1+val2)
                                 {
                                        case 2 :        run_back();pointback();        //两边跑离纸面       
                                                                break;                               
                                         
                                        case 1 :        if(val1==1)                         //一边跑离纸面
                                                                {run_right();pointright();
                                                                }                               
                                                                else{
                                                                run_left();pointleft();
                                                }
                                                                break;
                                                               
                                        case 0 :         run_forth();pointforth();                //在纸面内
                                               
                                                                break;                       
                                        default: break;
                                        }                
                                 OLED_ShowNumber(20,20,val1,1,14);
                                 OLED_ShowNumber(60,20,val2,1,14);                                       
                                        OLED_Refresh_Gram();
                 i++;
                 if(i==10)
                 {
                         LED=!LED;
                        i=0;
                 }
                 delay_ms(50);
                 
         }


}

void pointright()
{
         OLED_Clear();
        OLED_ShowString(40,10,"O");
         OLED_ShowString(60,20,"O");
         OLED_ShowString(80,30,"O");
         OLED_ShowString(60,40,"O");
         OLED_ShowString(40,50,"O");
         OLED_Refresh_Gram();
}

void pointleft()
{
                  OLED_Clear();
        OLED_ShowString(80,10,"O");
         OLED_ShowString(60,20,"O");
         OLED_ShowString(40,30,"O");
         OLED_ShowString(60,40,"O");
         OLED_ShowString(80,50,"O");
                  OLED_Refresh_Gram();
}

void pointforth()
{
                  OLED_Clear();
         OLED_ShowString(60,10,"OO");
         OLED_ShowString(50,20,"O  O");
         OLED_ShowString(40,30,"O    O");
                  OLED_Refresh_Gram();


}

void pointback()
{
                  OLED_Clear();
         OLED_ShowString(60,50,"OO");
         OLED_ShowString(50,40,"O  O");
         OLED_ShowString(40,30,"O    O");
                  OLED_Refresh_Gram();


}
该次功能实现中,三路引脚都能正常运行,但逻辑判断中只用到了左右两路,因为个人试验没有高精度要求,小车在该环境下已经能非常流畅准确的判断、运行。若使用三路引脚判断,可以实现急转弯等更高级的功能,这里不详细说明。
注:在调试中一直遇到读IO口Byte是,1和0显示不准确和不灵敏等问题,在经历了很长一段时间的不断尝试和思考后,最后从最简单的IO配置开始修改,把下拉输入改成了浮空输入模式,整个问题迎刃而解。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分