资讯详情

基于STM32红外避障小车的设计(有代码)

什么是避障车?

用红外光电传感器检测物体,即输出脉冲,输入单片机 然后控制电机驱动模块,实现壁障功能。这种避障车也叫简单的避障机器人。

各种方法: 1.红外避障 2.超声波避障

红外避障原理

基本硬件 红外发射管和接收管:分离式和集成式 在这里插入图片描述 变送电路:模拟量;数字:通过比较器输出模拟量

选择模块简介:

不怕光HJ-IR2传感器 ? 1、HJ-IR2相当于红外电子开关,检测障碍输出低电平、平 时高电平。。 ? 2.当前方有障碍物时,红外管发出的红外信号通过红外接收管接收 回来后,通过集成芯片放大,比较,输出低电平,点亮模块 上的LED发光管可以同时输出低平信号,信号可以用作单个信号 各种驱动模块用于检测和控制片机的信号输入。 ? 三、模块三线制,VCC为电原 5V,OUT为信号输出端,GND接电源 负极。 ? 4.探测距离约为1~30CM(检测距离的长度、电源电压和电流 与周围环境有关,仅供参考) ? 5、工作电压5V 工作电流 18-30ma左右。

输出2路壁障模块 :

在一般电子设计竞赛等对壁障模块功能要求不高的场合,完全可以 使用比较器输出开关量,使编程简单,易于实现; 1路壁障模块模块输出1路开关量,可连接单片机的普通输入IO 口;

2路壁障模块原理 :

根据汽车的运行情况,有以下运动方法: 如果没有被任何探头检测到,汽车直行; 当左探头检测到物体时,汽车向右转 ; 右这探头检测到物体时小车向左转 ?;如果有一定的速度要求,上述算法描述是最简单的红外壁障算法, 改进上述算法。

壁障模块安装调试步骤 :

智能车前面有两个探头,探头朝前, 铜柱可用 固定螺丝; 将中控板固定在车身上; 杜邦线正确连接中控板和探头; 控制主板连接正确; 把车放在地上,前面10CM放置物体,调整电位器, 确保探头经过物体时,LED状态不同。 若无论如何调节电位器,LED如果状态不变,应该 杜邦线接触不好,需要更换。

简单的源码分析—IO口定义

算法分析

主程序:

 #include "stm32f10x.h" #include "interface.h" #include "LCD1602.h" #include "IRCtrol.h" #include "motor.h" #include "UltrasonicCtrol.h" #include "redvoid.h"  ///全局变量定义 unsigned int speed_count=0;///占空比计数器 50次一周期 char front_left_speed_duty=SPEED_DUTY; char front_right_speed_duty=SPEED_DUTY; char behind_left_speed_duty=SPEED_DUTY; char behind_right_speed_duty=SPEED_DUTY;  unsigned char tick_5ms = 0;//5ms计数器作为主函数的基本周期 unsigned char tick_1ms = 0;//1ms作为电机的基本计数器 unsigned char tick_200ms = 0;//刷新显示

char ctrl_comm = COMM_STOP;//控制指令
char ctrl_comm_last = COMM_STOP;//上一次的指令
unsigned char continue_time=0;

int main(void)
{ 
        
	delay_init();
	GPIOCLKInit();
	UserLEDInit();
// LCD1602Init();
// IRCtrolInit();
	TIM2_Init();
	MotorInit();
	//UltraSoundInit();
	RedRayInit();
	ServoInit();

 while(1)
 { 
        	 
	 		if(tick_5ms >= 5)
		{ 
        
			tick_5ms = 0;
			tick_200ms++;
			if(tick_200ms >= 40)
			{ 
        
				tick_200ms = 0;
				LEDToggle(LED_PIN);
			}

			VoidRun();

		}
		
 }
}


串口部分:

#include "uart.h"
#include "interface.h"

//UART function
//UART1 TxD GPIOA9 RxD GPIOA10
void USART1Conf(u32 baudRate)
{ 
        
	USART_InitTypeDef USART_InitSturct;//定义串口1的初始化结构体

	GPIO_InitTypeDef GPIO_InitStruct;//定义串口对应管脚的结构体

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA , ENABLE);//打开串口管脚时钟
	//USART1_Tx_Pin Configure 
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;//输出引脚
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;//设置最高速度50MHz
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//推挽复用输出
	GPIO_Init(GPIOA , &GPIO_InitStruct);//将初始化好的结构体装入寄存器

//USART1_Rx_Pin Configure
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;//GPIO模式悬浮输入
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;//输入引脚
  GPIO_Init(GPIOA, &GPIO_InitStruct);//将初始化好的结构体装入寄存器

//USART1 Configure 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);//时钟使能
	USART_InitSturct.USART_BaudRate = baudRate;//波特率19200
	USART_InitSturct.USART_WordLength = USART_WordLength_8b;//数据宽度8位
	USART_InitSturct.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitSturct.USART_Parity = USART_Parity_No;//无奇偶校验
	USART_InitSturct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitSturct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//使能发送与接收
	USART_Init(USART1 , &USART_InitSturct);//将初始化好的结构体装入寄存器 
	//USART1_INT Configure
	USART_ITConfig(USART1 , USART_IT_RXNE , ENABLE);//使能接收中断
// USART_ITConfig(USART1 , USART_IT_TXE , ENABLE);
	USART_Cmd(USART1 , ENABLE);//打开串口
	USART_ClearFlag(USART1 , USART_FLAG_TC);//解决第一个数据发送失败的问题
}

void PutChar(u8 Data)
{ 
        
	USART_SendData(USART1 , Data);
	while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);//等待发送完毕
}
void PutStr(char *str)//发送一个字符串
{ 
        
	while(*str != '\0')
	{ 
        
		USART_SendData(USART1 , *str++);
		while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);//等待发送完毕
	}
}

void PutNChar(u8 *buf , u16 size)
{ 
        
  u8 i;
	while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); //防止第一字节丢失
	for(i=0;i<size;i++)
	{ 
        
		 USART_SendData(USART1 , buf[i]);
		 while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);//等待发送完毕
	}
}




电机模块:

#include "motor.h"
#include "interface.h"
#include "stm32f10x.h"

//GPIO配置函数
void MotorGPIO_Configuration(void)
{ 
        		
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = FRONT_LEFT_F_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 	
	GPIO_Init(FRONT_LEFT_F_GPIO, &GPIO_InitStructure);    
	
	GPIO_InitStructure.GPIO_Pin = FRONT_LEFT_B_PIN;	
	GPIO_Init(FRONT_LEFT_B_GPIO, &GPIO_InitStructure); 
	
	GPIO_InitStructure.GPIO_Pin = FRONT_RIGHT_F_PIN;	
	GPIO_Init(FRONT_RIGHT_F_GPIO, &GPIO_InitStructure); 
	
	GPIO_InitStructure.GPIO_Pin = FRONT_RIGHT_B_PIN;	
	GPIO_Init(FRONT_RIGHT_B_GPIO, &GPIO_InitStructure); 
	
	GPIO_InitStructure.GPIO_Pin = BEHIND_LEFT_F_PIN;	
	GPIO_Init(BEHIND_LEFT_F_GPIO, &GPIO_InitStructure);  
	
	GPIO_InitStructure.GPIO_Pin = BEHIND_LEFT_B_PIN;	
	GPIO_Init(BEHIND_LEFT_B_GPIO, &GPIO_InitStructure);  
	
	GPIO_InitStructure.GPIO_Pin = BEHIND_RIGHT_F_PIN;	
	GPIO_Init(BEHIND_RIGHT_F_GPIO, &GPIO_InitStructure);  
	
	GPIO_InitStructure.GPIO_Pin = BEHIND_RIGHT_B_PIN;	
	GPIO_Init(BEHIND_RIGHT_B_GPIO, &GPIO_InitStructure);  
	
}

//根据占空比驱动电机转动
void CarMove(void)
{ 
           
	
	 BEHIND_RIGHT_EN;
	
 /* //左前轮 if(front_left_speed_duty > 0)//向前 { if(speed_count < front_left_speed_duty) { FRONT_LEFT_GO; }else { FRONT_LEFT_STOP; } } else if(front_left_speed_duty < 0)//向后 { if(speed_count < (-1)*front_left_speed_duty) { FRONT_LEFT_BACK; }else { FRONT_LEFT_STOP; } } else //停止 { FRONT_LEFT_STOP; }*/
	
		//右前轮
	if(front_right_speed_duty > 0)//向前
	{ 
        
		if(speed_count < front_right_speed_duty)
		{ 
        
			FRONT_RIGHT_GO;
		}else                //停止
		{ 
        
			FRONT_RIGHT_STOP;
		}
	}
	else if(front_right_speed_duty < 0)//向后
	{ 
        
		if(speed_count < (-1)*front_right_speed_duty)
		{ 
        
			FRONT_RIGHT_BACK;
		}else                //停止
		{ 
        
			FRONT_RIGHT_STOP;
		}
	}
	else                //停止
	{ 
        
		FRONT_RIGHT_STOP;
	}
	
	//左后轮
	if(behind_left_speed_duty > 0)//向前
	{ 
        
		if(speed_count < behind_left_speed_duty)
		{ 
        
			BEHIND_LEFT_GO;
		}	else                //停止
		{ 
        
			BEHIND_LEFT_STOP;
		}
	}
	else if(behind_left_speed_duty < 0)//向后
	{ 
        
		if(speed_count < (-1)*behind_left_speed_duty)
		{ 
        
			BEHIND_LEFT_BACK;
		}	else                //停止
		{ 
        
			BEHIND_LEFT_STOP;
		}
	}
	else                //停止
	{ 
        
		BEHIND_LEFT_STOP;
	}
	
/* //右后轮 if(behind_right_speed_duty > 0)//向前 { if(speed_count < behind_right_speed_duty) { BEHIND_RIGHT_GO; } else //停止 { BEHIND_RIGHT_STOP; } } else if(behind_right_speed_duty < 0)//向后 { if(speed_count < (-1)*behind_right_speed_duty) { BEHIND_RIGHT_BACK; } else //停止 { BEHIND_RIGHT_STOP; } } else //停止 { BEHIND_RIGHT_STOP; }*/
}

//向前
void CarGo(void)
{ 
        
	front_left_speed_duty=SPEED_DUTY;
	front_right_speed_duty=SPEED_DUTY;
	behind_left_speed_duty=SPEED_DUTY;
	behind_right_speed_duty=SPEED_DUTY;
}

//后退
void CarBack(void)
{ 
        
	front_left_speed_duty=-SPEED_DUTY;
	front_right_speed_duty=-SPEED_DUTY;
	behind_left_speed_duty=-SPEED_DUTY;
	behind_right_speed_duty=-SPEED_DUTY;
}

//向左
void CarLeft(void)
{ 
        
	front_left_speed_duty=-20;
	front_right_speed_duty=SPEED_DUTY;
	behind_left_speed_duty=-20;
	behind_right_speed_duty=SPEED_DUTY+10;//增加后轮驱动力
}

//向右
void CarRight(void)
{ 
        
	front_left_speed_duty=SPEED_DUTY;
	front_right_speed_duty=-20;
	behind_left_speed_duty=SPEED_DUTY+10;//增加后轮驱动力
	behind_right_speed_duty=-20;
}

//停止
void CarStop(void)
{ 
        
	front_left_speed_duty=0;
	front_right_speed_duty=0;
	behind_left_speed_duty=0;
	behind_right_speed_duty=0;
}

void MotorInit(void)
{ 
        
	MotorGPIO_Configuration();
	CarStop();
}


红外遥控配置:

#include "IRCtrol.h"
#include "interface.h"

unsigned char ir_rec_flag=0;//接收数据标志位 1 有新数据 0 没有
unsigned char IRCOM[4];

//use time3 realize delay systick已经在main函数中使用了,在中断中不能重复使用
void Time3Init(void)
{ 
        
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    TIM_TimeBaseStructure.TIM_Period = 1;
    TIM_TimeBaseStructure.TIM_Prescaler = (72 - 1);//72M / 72 = 1us
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Down;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
}

//1us 延时
void DelayUs(vu32 nCount)
{ 
        
  u16 TIMCounter = nCount;
  TIM_Cmd(TIM3, ENABLE);
  TIM_SetCounter(TIM3, TIMCounter);
  while (TIMCounter>1)
  { 
        
    TIMCounter = TIM_GetCounter(TIM3);
  }
  TIM_Cmd(TIM3, DISABLE);
}

//外部中断配置 红外遥控配置
void IRCtrolInit(void)
{ 
        
	GPIO_InitTypeDef  GPIO_InitStructure;
	EXTI_InitTypeDef 	EXTI_InitStructure;//定义一个外部中断相关的结构体
	NVIC_InitTypeDef NVIC_InitStructure; //定义一个中断的结构体
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO , ENABLE);
	GPIO_InitStructure.GPIO_Pin = IRIN_PIN;//配置使能GPIO管脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//配置GPIO模式,输入上拉
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置GPIO端口速度
	GPIO_Init(IRIN_GPIO , &GPIO_InitStructure);
		
	GPIO_EXTILineConfig(IRIN_PORTSOURCE , IRIN_PINSOURCE);
	EXTI_InitStructure.EXTI_Line = IRIN_EXITLINE;//将对应的GPIO口连接到中断线上
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//中断事件类型,下降沿
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//选择模式,中断型
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能该中断
	EXTI_Init(&EXTI_InitStructure);//将配置好的参数写入寄存器
			
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);	 //阶级为0,不可嵌套
	NVIC_InitStructure.NVIC_IRQChannel = 	IRIN_IRQCH;//打开PINA_8的外部中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//主优先级0,最高
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;	//子优先级,最低
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;	//使能该模块中断
	NVIC_Init(&NVIC_InitStructure);	//中断初始化,将结构体定义的数据执行
	
	Time3Init();
}

/******************************************************************************* * 函 数 名 :DelayIr * 函数功能 :0.14MS 延时 * 输 入 :无 * 输 出 :无 *******************************************************************************/
void DelayIr(unsigned char x)  
{ 
        
  while(x--)
 { 
        
  DelayUs(140);
 }
}

void IRIntIsr(void)
{ 
        
  unsigned char j,k,N=0;
	 DelayIr(15);
	 if (IRIN==1) 
     { 
         
	   return;
	  } 
		 continue_time = 40;//连发信号,表示指令持续 40*5 = 200ms 无指令停车
                           //确认IR信号出现
  while (!IRIN)            //等IR变为高电平,跳过9ms的前导低电平信号。
    { 
        DelayIr(1);}

 for (j=0;j<4;j++)         //收集四组数据
 { 
         
  for (k=0;k<8;k++)        //每组数据有8位
  { 
        
   while (IRIN)            //等 IR 变为低电平,跳过4.5ms的前导高电平信号。
     { 
        DelayIr(1);}
    while (!IRIN)          //等 IR 变为高电平
     { 
        DelayIr(1);}
     while (IRIN)           //计算IR高电平时长
      { 
        
    DelayIr(1);
    N++;           
    if (N>=30)
	 { 
         
	 return;}                  //0.14ms计数过长自动离开。
      }                        //高电平计数完毕 
     IRCOM[j]=IRCOM[j] >> 1;                  //数据最高位补“0”
     if (N>=8) { 
        IRCOM[j] = IRCOM[j] | 0x80;}  //数据最高位补“1”
     N=0;
  }//end for k
 }//end for j
   
	k = ~IRCOM[3];
   if (IRCOM[2] != k)
   { 
         
     return; }
	 
		 //指令转换
		 
		 switch(IRCOM[2])
		 { 
        
			 case 0x46: ctrl_comm = COMM_UP;break;
			 case 0x15: ctrl_comm = COMM_DOWN;break;
			 case 0x44: ctrl_comm = COMM_LEFT;break;
			 case 0x43: ctrl_comm = COMM_RIGHT;break;
			 case 0x40: ctrl_comm = COMM_STOP;break;
			 default :  return;
		 }
		 ir_rec_flag = 1;
	
}

红外避障模块:

#include "redvoid.h"
#include "interface.h"
#include "motor.h"

extern char ctrl_comm;

//获取红外避障模块状态
char GetVoidStatus(void)
{ 
        
	char left=0,right=0;
	char count;
	if(VOID_L_IO == BARRIER_Y)
	{ 
        
		count = 2;
		while(--count)//10ms 采集2次均要采集到前面障碍物信息,滤波
		{ 
        
			if(VOID_L_IO == BARRIER_N)
				break;
			Delayms(1);
		}
		if(count == 0) left = 1;
	}
	
	if(VOID_R_IO == BARRIER_Y)
	{ 
        
		count = 2;
		while(--count)//10ms 采集2次均要采集到前面障碍物信息,滤波
		{ 
        
			if(VOID_R_IO == BARRIER_N)
				break;
			Delayms(1);
		}
		if(count == 0) right = 2;
	}
	
	return left + right;
}

//延时的同时检测红外,一旦发生障碍物,就停止并跳出延时
void DelayCheck(int ms)
{ 
        
	while(ms--)
	{ 
        
		Delayms(1);
		if(VOID_NONE != GetVoidStatus())
		{ 
        
			CarStop();
			return;
		}
	}
}

//红外避障处理
//处理方式:左边检测到 后退500ms 右转500ms
// 右边检测到 后退500ms 左转500ms
// 两边检测到 后退700ms 右转500ms
// 没检测到 直行
void VoidRun(void)
{ 
        
	char status;
	status = GetVoidStatus();
	
	switch(status)
	{ 
        
		case VOID_LEFT: 
			ctrl_comm = COMM_RIGHT;CarBack 

标签: 50cm红外避障传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台