基于51单片机的循迹小车(循迹、超声波测距)

目录

前言

一、硬件准备

二、模块介绍

1.电机驱动模块

2.红外循迹模块

3.超声波测距模块

三、代码部分(仅供参考)


前言

在大学期间,通过实验室考核做的51循迹小车(循迹超声波测距),有很多的不足,主要记录自己的学习过程(含代码

一、硬件准备

1.51单片机

2.小车底板(亚克力板)

3.两个前轮子、电机、一个万向轮(买小车的时候都配有)

4.若干不同高度铜柱、若干杜邦线、面包板

5.超声波

6.电源模块(建议12V可充电锂电池

7.红外循迹模块

8.L298N

二、模块介绍

1.电机驱动模块

控制引脚

  • IN1 & IN2 电机驱动器A的输入引脚,控制电机A转动及旋转角度
    • IN1输入高电平HIGH,IN2输入低电平LOW,对应电机A正转
    • IN1输入低电平LOW,IN2输入高电平HIGH,对应电机A反转
    • IN1、IN2同时输入高电平HIGH或低电平LOW,对应电机A停止转动
    • 调速就是改变IN1、IN2高电平的占空比(需拔掉ENA处跳帽)
  • IN3 & IN4 电机驱动器B的输入引脚,控制电机B转动及旋转角度
    • IN3输入高电平HIGH,IN4输入低电平LOW,对应电机B正转
    • IN3输入低电平LOW,IN4输入高电平HIGH,对应电机B反转
    • IN3、IN4同时输入高电平HIGH或低电平LOW,对应电机B停止转动
    • 调速就是改变IN3、IN4高电平的占空比(需拔掉ENB处跳帽)

输出引脚

  • OUT1 & OUT2 电机驱动器A的输出引脚,接直流电机A或步进电机的A+和A-
  • OUT3 & OUT4 电机驱动器B的输出引脚,接直流电机B或步进电机的B+和B-

调速控制引脚(不用时跳帽不要拔)

  • ENA 电机A调速开关引脚,拔掉跳帽,使用PWM对电机A调速,插上电机A高速运行
  • ENB 电机B调速开关引脚,拔掉跳帽,使用PWM对电机B调速,插上电机B高速运行

L298N工作逻辑IO口输入方式(高电平→1,低电平→0)

直流电机

旋转方式

IN1

IN2

IN3

IN4

PWM调速信号

ENA

ENB

M1

正转

1

0

/

/

1

/

反转

0

1

/

/

1

/

停止

0

0

/

/

1

/

M2

正转

/

/

1

0

/

1

反转

/

/

0

1

/

1

停止

/

/

0

0

/

1

2.红外循迹模块

本次用到的红外循迹模块的传感器为TCRT5000,检测反射距离为1mm~25mm,可转动突出的正方形中间的电位器调节灵敏度,输出形式为0 和 1

 

引脚

  • VCC:3.3V~5V(接单片机的VCC / 3.3V / 5V)
  • GND:接地(接单片机GND)
  • DO:TTL电平输出(接单片机IO口)
  • AO:模拟信号输出(此引脚可不接)

工作原理

  • TCRT5000是一种红外线传感器,它可以检测物体是否在其检测范围内。它的工作原理是利用红外线的反射来检测物体的存在。
  • TCRT5000由发射管和接收管组成。发射管发射出红外线,接收管接收反射回来的红外线。
  • 当有物体进入检测范围时,它会反射红外线,接收管会接收到反射回来的红外线信号。这个信号会被放大并转换成数字信号,然后被传输到控制器或处理器中进行处理。

由于黑色是不反射红外线的,故传感器检测到黑线时,输出高电平,开关指示灯亮(传感器接电后电源指示灯常亮)。

当调试时发现小车经过黑线而循迹模块开关指示灯不亮时可调节循迹模块离地面的距离或调节传感器灵敏度

3.超声波测距模块

此模块用到了 HC-SR04 ,HC-SR04超声波测距模块是一种基于超声波测距原理的传感器,可以通过发送超声波脉冲并接收其回波来计算目标与传感器之间的距离。测距范围为2cm~400cm,精度为3mm,工作电压为5V,工作电流为15mA。

HC-SR04 完整规格:

工作电压直流5V
工作电流15mA
运行频率40KHz
最大范围4m
最小范围2cm
测距精度3mm
测量角度15°
触发输入信号10µS TTL脉冲
尺寸45 x 20 x 15mm

引脚

  • VCC:电源线(接单片机5V
  • GND:接地(接单片机GND)
  • Trig:触发引脚,触发测距(接单片机IO口)
  • Echo:回波引脚,传回时间差(接单片机IO口)

超声波时序图

 工作原理:首先给Trig引脚提供一个10us以上(可20us)的高电平触发脉冲(放在中断函数里) –> 模块内部将发射8个40KHz的脉冲并检测回波 –> 如果Echo引脚为电平,启动定时器 –> 当Echo引脚为电平时,关闭定时器 –> 计算计时器时间间隔 –> 根据公式计算距离

PS:计算距离公式:s = t * 0.034 / 2 (单位为厘米

三、代码部分(仅供参考)

#include <REGX52.H>
#include <intrins.h>

sbit IN1=P1^0;   //单片机的IO口
sbit IN2=P1^1;
sbit IN3=P1^3;
sbit IN4=P1^2;
sbit D1=P1^4;
sbit D2=P1^5;
sbit D3=P1^6;
sbit D4=P1^7;
sbit ENA=P2^5;   //l298n左使能端口
sbit ENB=P2^4;   //l298n右使能端口
sbit Trig=P2^0;
sbit Echo=P2^1;

//pwm:脉冲宽度调制
//占空比:一个脉冲周期内,高电平时间/整个周期时间
unsigned int PWMR=0,PWML=0,pwm_t=0; 
				//右轮占空比
				//左轮占空比
				//设定的比较值
				
/************************超声波模块****************************/
unsigned long distance;
unsigned long s;
unsigned int t=0;
unsigned int counter=0;
bit flag=0; //中断溢出标志
/*bit:标志位,只能0/1

/************************数码管显示****************************/
unsigned char NixieTable[]={0X3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F};
//定义数码管显示码0、1、2、3、4、5、6、7、8、9
unsigned char dis_LED[4]={0,0,0,0};


void Timer0_Init(void)		//500us@11.0592MHz
{		
	TMOD = 0x11;	//定时器0和定时器1工作方式为1
	TL1 = 0xf8;				//定时2ms
	TH1 = 0x30;	
	ET0=1;      //允许T0中断
	ET1 = 1;	//允许T1中断
	TR1 = 1;	//打开定时器1
	EA = 1;		//打开总中断
	TMOD |= 0x11;		//设置定时器0和1模式1
	TL0 = (65536-100)%256;		//设置定时初始值
	TH0 = (65536-100)/256;		
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;
	EA = 1; 
	PT0=1;
}

void Timer2_Isr(void) interrupt 5
{
	TF2 = 0;      //清除TF2标志
	flag=1;       //溢出标志
}

void Timer2_Init(void)		//2毫秒@12.000MHz
{
	T2MOD = 0;				//清零T2MOD寄存器
	T2CON = 0;				//清零T2CON寄存器
	//设置定时初始值
	TL2 = 0;				//清零TL2寄存器
	TH2 = 0;				//清零TH2寄存器
	RCAP2L = 0x30;			//设置RCAP2L寄存器为0x30
	RCAP2H = 0xF8;			//设置RCAP2H寄存器为0xF8
	TR2 = 1;				//启动定时器2
	ET2 = 1;				//允许定时器2中断
}


/************************延时函数***********************/
void Delayms(unsigned int xms)		
{
	while(xms--){
		unsigned char i, j;

		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}

/************************延时20us***********************/
void Delay20us()		//@11.0592MHz
{
	unsigned char i;

	_nop_();
	i = 6;
	while (--i);
}


void RightMotoForward()  //右轮向前
{
	IN3=1; 
	IN4=0;}
void RightMotoBack()     //右轮向后
{
	IN3=0; 
	IN4=1;}
void LeftMotoBack()      //左轮向后
{
	IN1=0; 
	IN2=1;}
void LeftMotoForward()   //左轮向前
{
	IN1=1; 
	IN2=0;}
void RightMotoStop()     //右轮停下
{
	IN3=0; 
	IN4=0;}
void LeftMotoStop()      //左轮停下
{
	IN1=0; 
	IN2=0;}

void CarGo()    //左右轮都向前
{RightMotoForward();LeftMotoForward();}

void CarBack()  //左右轮都向后
{RightMotoBack();LeftMotoBack();}
	
void CarRight()  //向右转
{RightMotoStop();LeftMotoForward();}
	
void CarLeft() //向左转
{LeftMotoStop();RightMotoForward();}

void CarStop()  //停下
{RightMotoStop();LeftMotoStop();}

void Track()   //  灭1黑   亮0     检测到黑线为灭1   
{
	
	if(D1==0&&D2==0&&D3==0&&D4==0) 	//小车停下  未检测到黑线
		{
			Delayms(50);
			if(D1==0&&D2==0&&D3==0&&D4==0) 	//小车停下  未检测到黑线
		{
			PWML=30;          //左电机初始转速
			PWMR=30;        //右电机初始转速
			CarGo();
			Delayms(10);
		}
			CarStop();
		}
		
	if(D2==1&&D3==1) {
		//小车两边都感应到黑线 小车直行 全灭都为1
		//Delayms(100);
		if(D2==1&&D3==1) {
			PWML=30;          //左电机初始转速
			PWMR=30;          //右电机初始转速
			CarGo();
		}
		Delayms(10);
	}
				
	if(D1==0&&D2==0&&D3==1&&D4==0)  //小车右边扫描到黑线 小车偏左 向右移动 
		{
			PWML=30;          //左电机初始转速
			PWMR=30;        //右电机初始转速
			CarRight();
			Delayms(10);
			if(D1==0&&D2==0&&D3==0&&D4==0){
					PWML=30;          
					PWMR=30;          
					CarGo();
					Delayms(10);
				if(D1==0&&D2==0&&D3==0&&D4==0){
						PWML=30;          //左电机初始转速
						PWMR=35;         //右电机初始转速
						CarRight();
						Delayms(10);
				}
			}
		}
		
	if(D1==0&&D2==1&&D3==0&&D4==0) //小车左边扫描到黑线 小车偏右 小车应该向左移动     
		{
			PWML=35;          //左电机初始转速
			PWMR=30;           //右电机初始转速
			CarLeft();
			Delayms(10);
			if(D1==0&&D2==0&&D3==0&&D4==0){
					PWML=30;          
					PWMR=30;          
					CarGo();
					Delayms(10);
				if(D1==0&&D2==0&&D3==0&&D4==0){
						PWML=35;          //左电机初始转速
						PWMR=30;           //右电机初始转速
						CarLeft();
						Delayms(10);
				}
			}
		}
		
	if(D1==0&&D2==0&&D3==0&&D4==1){
		PWML=30;          //左电机初始转速
		PWMR=35;        //右电机初始转速
		CarRight();
		Delayms(50);
		if(D1==0&&D2==0&&D3==0&&D4==0){
				PWML=30;          
				PWMR=30;          
				CarGo();
				Delayms(10);
			if(D1==0&&D2==0&&D3==0&&D4==0){
					PWML=30;          //左电机初始转速
					PWMR=35;         //右电机初始转速
					CarRight();
					Delayms(10);
			}
		}
	}
	
	if(D1==1&&D2==0&&D3==0&&D4==0){
		PWML=35;          //左电机初始转速
		PWMR=30;           //右电机初始转速
		CarLeft();
		Delayms(50);
		if(D1==0&&D2==0&&D3==0&&D4==0){
				PWML=30;          
				PWMR=30;          
				CarGo();
				Delayms(10);
			if(D1==0&&D2==0&&D3==0&&D4==0){
					PWML=35;          //左电机初始转速
					PWMR=30;           //右电机初始转速
					CarLeft();
					Delayms(10);
			}
		}
	}
		
	if((D1==1&&D2==1&&D3==0&&D4==0) || (D1==1&&D2==1&&D3==1&&D4==0)) //直角左拐
		{
			PWML=20;          //左电机初始转速
			PWMR=20;          //右电机初始转速
			CarGo();
			Delayms(100);
			if(D1==0&&D2==0&&D3==0&&D4==0){
				CarStop();
				Delayms(100);
				PWML=30;          //左电机初始转速
				PWMR=25;           //右电机初始转速
				CarLeft();         //原地左拐
				Delayms(100);
			}
		}
		
	if((D1==0&&D2==0&&D3==1&&D4==1) || (D1==0&&D2==1&&D3==1&&D4==1))  //直角右拐
		{
			PWML=20;          //左电机初始转速
			PWMR=20;           //右电机初始转速
			CarGo();
			Delayms(100);
			if(D1==0&&D2==0&&D3==0&&D4==0){
				CarStop();
				Delayms(100);
				PWML=25;          //左电机初始转速
				PWMR=30;           //右电机初始转速
				CarRight();        //原地右拐
				Delayms(100);
			}
		}
		
//	if((D1==1&&D2==0&&D3==0&&D4==0)||(D1==1&&D2==0&&D3==1&&D4==0)||(D1==1&&D2==1&&D3==1&&D4==0)||(D1==1&&D2==1&&D3==0&&D4==0))  //锐角左拐
//		{
//			PWML=10;          //左电机初始转速
//			PWMR=10;   		  //右电机初始转速
//			CarGo();
//			Delayms(2000);
//			if(D1==0&&D2==0&&D3==0&&D4==0){
//				CarStop();
//				Delayms(2000);
//				PWML=5;          //左电机初始转速
//				PWMR=0;           //右电机初始转速
//				CarLeft();
//			}
//			Delayms(2000);
//		}
//		
//	if((D1==0&&D2==0&&D3==0&&D4==1)||(D1==0&&D2==1&&D3==0&&D4==1)||(D1==0&&D2==1&&D3==1&&D4==1)||(D1==0&&D2==0&&D3==1&&D4==1))  //锐角左拐
//	{
//		PWML=15;          //左电机初始转速
//		PWMR=15;           //右电机初始转速
//		Cargo();
//		Delayms(2000);
//		if(D1==0&&D2==0&&D3==0&&D4==0){
//			CarStop();
//			Delayms(2000);
//			PWML=5;          //左电机初始转速
//			PWMR=15;           //右电机初始转速
//			CarRight();
//		}
//		Delayms(2000);
//	}
//	
	
//	
//	if(D1==0&&D2==1&&D3==1&&D4==0){
//		if(D1==1){
//			CarLeft();
//		}
//		if(D4==1){
//			CarRight();
//		}
//	}
}

void chaoshengbo(){
	//定义超声波避障最小距离
	while(!Echo);  
	TR2=1;  
	while(Echo);  
	TR2=0;
	distance=200;   //20cm
	
	t=TH2*256+TL2;
	TH2=0;
	TL2=0;
	
	s=(long)(t*0.17);  //算出为毫米mm
	
	if(s<=(long)distance){
		CarStop();
	}
	if((s>=4000) || (flag==1))    //超出测距范围显示“----”
		{
		flag=0;
		dis_LED[0]=0X40;
		dis_LED[1]=0X40;
		dis_LED[2]=0X40;
		dis_LED[3]=0X40;
	}else{
		dis_LED[0]=NixieTable[s%10/1];       //个位
		dis_LED[1]=NixieTable[s%100/10];     //十位
		dis_LED[2]=NixieTable[s%1000/100];   //百位
		dis_LED[3]=NixieTable[s%10000/1000]; //千位
	}
}

void Nixie(){
	unsigned int i;
	unsigned int j;
	for(i=0;i<4;i++){
		switch(i){
			case 0:P2_4=0;P2_3=0;P2_2=0;break;  //LED1亮
			case 1:P2_4=0;P2_3=0;P2_2=1;break;  //LED2亮
			case 2:P2_4=0;P2_3=1;P2_2=0;break;  //LED3亮
			case 3:P2_4=0;P2_3=1;P2_2=1;break;  //LED4亮
		}
		if(i==1){
			P0=dis_LED[i]+0x80;   //加小数点
		}else{
			P0=dis_LED[i];
		}
		j=10;          //扫描间隔时间设定
		while(j--);
		P0=0x00;       //消隐
	}
}


void Timer0_Isr(void) interrupt 1      //T0中断用来计数器溢出 超出测距范围
{
	//重新赋初值
	TH0=(64536-100)/256;	
	//TH0 = 0xFF;
	TL0=(64536-100)%256+1;	 //有1微秒误差
  //TL0 = 0xA4;
		pwm_t++;
	if(pwm_t<PWML){
			ENA=1;
		}
	else{
			ENA=0;  //电机停止
			
		}
	if(pwm_t<PWMR){
			ENB=1;
		}
	else{
			ENB=0;  //电机停止
		}
	
	if(pwm_t>=100)  //一个周期
		{
			pwm_t=0;
		}
}

void Timer1_Isr(void) interrupt 3     //T1中断扫描数码管和计200ms启动模块
{
	TH1=0XF8;          //定时2ms
	TL1=0X30;
	Nixie();
	counter++;
	if(counter>=100){
		counter=0;
		Trig=1;
		Delay20us();
		Trig=0;
	}
}


void main()
{
	//定时器初始化
	Timer0_Init();
	Timer2_Init();
	while(1)
	{
		CarGo();	
		Track();		//	循迹函数	
		chaoshengbo();  //超声波函数
		
	}
}

循迹小车,随着电力电子器件的发展,PWM电压型逆变器在交流变频调速、UPS、电能质量控制器、轻型直流输电换流器等电力电子装置中得到了越来越广泛的应用。PWM电压型逆变器直流侧所需的理想无脉动直流电压源通常通过整流加上大直流电容滤波获得。大直流滤波电容的使用,给装置带来占用空间大、成本高及严重影响电能质量方面的问题。因此,研究如何减小甚至去除逆变器直流侧电容,以及解决因其产生的低次谐波和相关问题,具有十分重要的理论意义和实用价值。本文在综述了国内外在PWM电压型逆变器及各种抑制谐波PWM技术的基础上,对目前工程中应用最广泛的SPWM电压型逆变器的主电路及谐波消除调制技术和相关问题进行了深入研究。50年代末晶闸管标志着电力电子半导体期间的开端。电力电子器件经历了40多年的发展历程[1-2],特别是近30多年内更是得到了迅猛的发展[3,4]。以Th(SCR)为代表的半控型器件是第一代电力电子器件[5],其主要用于可控整流装置,若用于可控的逆变器,因其无法自行关断,须配置强迫换流电路,致使装置复杂化。CR)为代表的半控型器件是第一代电力电子器件[5],其主要用于可控整流装置,若用于可控的逆变器,因其无法自行关断,须配置强迫换流电路,致使装置复杂化。CR)为代表的半控型器件是第一代电力电子器件[5],其主要用于可控整流装置,若用于可控的逆变器,因其无法自行关断,须配置强迫换流电路,致使装置复杂化。CR)为代表的半控型器件是第一代电力电子器件[5],其主要用于可控整流装置,若用于可控的逆变器,因其无法自行关断,须配置强迫换流电路,致使装置复杂化。CR)为代表的半控型器件是第一代电力电子器件[5],其主要用于可控整流装置,若用于可控的逆变器,因其无法自行关断,须配置强迫换流电路,致使装置复杂化。CR)为代表的半控型器件是第一代电力电子器件[5],其主要用于可控整流装置,若用于可控的逆变器,因其无法自行关断,须配置强迫换流电路,致使装置复杂化。CR)为代表的半控型器件是第一代电力电子器件[5],其主要用于可控整流装置,若用于可控的逆变器,因其无法自行关断,须配置强迫换流电路,致使装置复杂化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值