基于单片机的智能清洁小车设计—控制系统设计

收藏和点赞,您的关注是我创作的动力

文章目录

    • 概要
  • 一、研究的主要内容和目标
  • 二、总体方案设计
    • 2.1智能清洁小车的硬件系统组成
    • 2.2智能清洁小车的硬件结构图
  • 三、 小车结构设计
    • 5.1基本布局和功能分析
    • 5.2小车二维及三维图
    • 小车三维图:
  • 四、 原理图
    • 程序
  • 五、 总结
  • 五、 文章目录

概要

  
如何让道路清洁更加高效,清洁效果更好,清洁成本更低,安全性更好,清洁更加环保,各大新能源汽车企业给出的答案是电动道路清洁车,这种最高时速平均在20-30km/h的小车完美地解决了以上的大部分问题。
本论文将介绍如何设计一款拥有市面上新能源清洁扫地机大部分功能的智能小车,论文一共分为三部分,是以单片机为开发基础,详细描述了我进行硬件电路设计、软件程序编写及小车关键功能部分结构设计的过程及结果。
关键词:智能小车;单片机;电机控制;扫地机;红外遥控

一、研究的主要内容和目标

  本文研究的主要内容是设计一款可以通过遥控器操控的拥有扫地吸尘洒水功能的清洁小车,我采用STC89C52芯片作整车控制的主控芯片,RZ7899作为驱动电机的驱动芯片,通过设计,小车可以做到红外遥控,控制扫刷清扫地面,控制水泵洒水并雾化控尘,控制风机高速旋转吸尘,控制舵机进行垃圾箱举升。
设计过程大致为:
(1)电机选型,估算电机需要带多少负载以及合适的电机转速,根据电机型号选择合适的驱动芯片。
(2)电路硬件设计,根据所需要的功能选择合适的芯片,然后从网上下载该芯片的芯片手册,根据芯片手册的提示和典型应用电路设计电路图并进行元器件选型并在Altium designer软件中绘制出电路原理图和PCB图。
(3)软件设计,通过KEIL软件编写程序实现对所需要功能的控制
(4)结构设计,使用Catia三维建模软件对小车底盘,扫刷,垃圾箱等关键部位进行设计。
设计目标是通过所学知识设计出一台拥有市面上出现的智能扫地车大部分功能的智能清洁小车。

二、总体方案设计

2.1智能清洁小车的硬件系统组成

本文设计的智能清洁小车硬件电路部分主要由以下几个部分构成:(1)基于STC89C52的单片机最小系统(2)行走电机驱动模块(3)扫刷电机驱动模块(4)
水泵电机驱动模块(5)吸尘风机驱动模块(6)垃圾箱举升舵机驱动模块(7)红外接收模块(8)红外遥控发射模块。这8个部分构成了小车的硬件电路,我可以通过遥控器上的按键控制小车的工作模式,来完成清扫,吸尘,倒垃圾等任务。

2.2智能清洁小车的硬件结构图

在这里插入图片描述
表2-2-1清洁小车硬件结构图

三、 小车结构设计

5.1基本布局和功能分析

本车结构是根据循迹小车的结构改进而来,小车最前头的扫刷是通过一个轴套和两个正反牙的连接轴组成,顺时针拧动轴套可以将扫刷升起,逆时针拧动可以将扫刷放下。
电池被放置在扫刷两侧,左边那一块电池组主要供应控制模块和行走、水泵、扫刷电机驱动模块。右边那一块主要供应吸尘风机。中间则放置电源电路板,最小系统板,各模块驱动板。
小车中后部是水箱和垃圾箱,水箱前放置的是水泵电机,通过水泵电机将水箱内的水抽出流经扫刷上方的雾化喷头,再流回水箱,水箱上方的是垃圾箱,垃圾箱和水箱中间放置舵机,舵机通过一个连杆机构将垃圾箱升起,倒出垃圾,这里也可以将舵机放置在垃圾箱另一侧,直接带动垃圾箱旋转180度倾倒垃圾,风机和滤尘装置放置在垃圾箱内侧后方,通过将垃圾箱内部空气抽出,造成气压差,从而吸尘。而吸尘管从垃圾箱延伸出来后,经过小车底盘连接吸盘,考虑到道路可能出现不平整的情况,这里吸盘底部可以增加两个轮子防止吸盘和道路碰撞摩擦而造成磨损。

5.2小车二维及三维图

小车二维图:
在这里插入图片描述

图5-2 1 清洁小车结构二维图

小车三维图:

在这里插入图片描述

图5-2 2 清洁小车结构三维图

四、 原理图

在这里插入图片描述

程序

红外发射代码
#include"reg52.h"
#include"intrins.h"
#define uchar unsigned char
#define uint unsigned int
sbit IRM_E=P3^4;					  //TO口作为红外发射口
sbit Key_UP=P2^0;					  //键码0x09
sbit Key_DOWN=P2^1;					  //键码0x16
sbit Key_LEFT=P2^2;					  //键码0x19
sbit Key_RIGHT=P2^3;				  //键码0x0d
sbit Key_STOP=P2^4;					  //键码0x0c
sbit Key_DUSTBIN_UP=P2^5;			  //启动键码0x45
sbit Key_DUSTBIN_DOWN=P2^6;			  //启动键码0x46
sbit Key_A_ONOFF=P2^7;				  //启动键码0x47,停止键码0x44
sbit Key_B_ONOFF=P0^0;				  //启动键码0x40,停止键码0x43
sbit Key_C_ONOFF=P0^1;				  //启动键码0x07,停止键码0x15
bit flag0=0;
bit flag1=0;
bit flag2=0;
bit flag3=0;
bit flag4=0;
bit flag5=0;
bit flag6=0;
bit flag7=0;
bit flag8=0;
bit flag9=0;

//延时8.77us,即1/3周期
void Delay8_77us()	//@11.0592MHz
{
	uchar i;
	i=19;
	while(--i);
}

//载波发射周期,26.3us=8.77us(发射红外光)+8.77us*2(不发射红外光)
void Send_IRM(uint i)
{
	while(i--)				//循环65535次
	{
		IRM_E=1;			//红外发射启动
		Delay8_77us();		//延时8.77us 
		IRM_E=0; 	   		//红外发射停止
		Delay8_77us();		//延时8.77us
		Delay8_77us();		//延时8.77us
	}	
}

//载波不发射周期,26.3us=8.77us*3,(不发射红外光)
void NO_Send_IRM(uint i)
{
	while(i--)				//循环65535次
	{
		IRM_E=0; 			//红外不发射
		Delay8_77us();		//延时8.77us
		Delay8_77us();		//延时8.77us,
		Delay8_77us();		//延时8.77us
	}
}

//发射数据0(NEC协议   载波发射0.56ms+载波不发射0.56ms)
void Send_NEC_0()
{
	Send_IRM(21);	 		//0.56ms=26.3us*21
	NO_Send_IRM(21); 		//0.56ms=26.3us*21
}

//发射数据1(NEC协议   载波发射0.56ms+载波不发射1.68ms)
void Send_NEC_1()
{
	Send_IRM(21);		  	 //0.56ms=26.3us*21
	NO_Send_IRM(64); 		 //1.68ms=26.3us*64
}

//按NEC编码顺序发送一帧完整数据(引导码,用户码低八位,用户码高八位,八位数据码,八位数据反码,结束码)
void Send_NEC_Message(uchar Code_Date)
{
	uint Code_User;
	uchar i;				 //定义无符号字符型i
	uint Code_User_2;		 //定义无符号整形Code_User_2
	Code_User_2=Code_User; 	 //使用临时变量,防止修改形参

//发送引导码(载波发射9ms,载波不发射4.5ms)
	Send_IRM(342);  		 //9ms=26.3*342
	NO_Send_IRM(171);  	 	 //9ms=26.3*171

//发送十六位用户码
	for(i=0;i<16;i++)		   //发送十六位用户码
	{
		if(Code_User_2&0X0001) //判断用户码是否为1
			Send_NEC_1();  	   //发射1
		else				   //否则
			Send_NEC_0();	   //发射0
		Code_User_2>>=1;	   //执行完后用户码右移一位
	}

//发送八位数据码
	Code_User_2=Code_Date;	   //Code_Date的值赋给Code_User2
	for(i=0;i<8;i++)		   //发送八位数据码
	{
		if(Code_User_2&0x01)   //判断数据码是否为1
			Send_NEC_1();	   //发射1
		else				   //否则
			Send_NEC_0();	   //发射0
		Code_User_2>>=1;	   //执行完后数据码右移一位
	}

//发送八位数据反码
	Code_User_2=(~Code_Date);
	for(i=0;i<8;i++)		   //发送八位数据反码
	{
		if(Code_User_2&0x01)   //判断数据码是否为1
			Send_NEC_1();	   //发射1
		else				   //否则
			Send_NEC_0();	   //发射0
		Code_User_2>>=1;	   //执行完后数据码右移一位
	}	

//发送结束码
	Send_NEC_0();				   //发送结束码
}

//DUSTBIN_UP按键函数(按键抬手启动消抖,按一次执行启动程序,再按一次执行停止程序)
void KeyDUSTBINUP()
{
	if(Key_DUSTBIN_UP==0&&flag0==0)		   //如果按键按下并且标志位flag0为0
	{
		flag0=1;						   //则标志位flag0置1
	}
	if(flag0==1&&Key_DUSTBIN_UP==1)		   //如果标志位flag0为1并且按键松开
	{	
		flag1=~flag1;					   //则标志位flag1取反
	}
	if(flag1==1)							   //当flag1为1时
	{
		Send_NEC_Message(0x45);			   //红外发送键码0x45
	}
	flag0=0;							   //标志位flag0清零
}	

//DUSTBIN_DOWN按键函数
void KeyDUSTBINDOWN()					   
{
	if(Key_DUSTBIN_DOWN==0&&flag2==0)	   //如果按键按下并且标志位flag2为0
	{
		flag2=1;						   //则标志位flag2置1
	}
	if(flag2==1&&Key_DUSTBIN_DOWN==1)	   //如果标志位flag2为1并且按键松开
	{	
		flag3=~flag3;					   //则标志位flag3取反
	}
	if(flag3==1)							   //当flag3为1时
	{
		Send_NEC_Message(0x46);			   //红外发送键码0x47
	}	
	flag2=0;							   //标志位flag2清零
}	
//Key_A_ONOFF按键
void KeyAONOFF()					   
{
	if(Key_A_ONOFF==0&&flag4==0)		   //如果按键按下并且标志位flag4为0
	{
		flag4=1;						   //则标志位flag4置1
	}
	if(flag4==1&&Key_A_ONOFF==1)	  	   //如果标志位flag4为1并且按键松开
	{	
		flag5=~flag5;					   //则标志位flag5取反
	}
	if(flag5==1)							   //当flag5为1时
	{
		Send_NEC_Message(0x47);			   //红外发送键码0x40
	}
	 else								   //否则
	{
	 	Send_NEC_Message(0x44);			   //红外发送键码0x43
	}	
	flag4=0;							   //标志位flag4清零
}	
//Key_B_ONOFF按键
void KeyBONOFF()					   
{
	if(Key_B_ONOFF==0&&flag6==0)		   //如果按键按下并且标志位flag6为0
	{
		flag6=1;						   //则标志位flag6置1
	}
	if(flag6==1&&Key_B_ONOFF==1)	  	   //如果标志位flag6为1并且按键松开
	{	
		flag7=~flag7;					   //则标志位flag7取反
	}
	if(flag7==1)							   //当flag7为1时
	{
		Send_NEC_Message(0x40);			   //红外发送键码0x07
	}
	 else								   //否则
	{
	 	Send_NEC_Message(0x43);			   //红外发送键码0x15
	}	
	flag6=0;							   //标志位flag6清零
}
//Key_C_ONOFF按键
void KeyCONOFF()					   
{
	if(Key_C_ONOFF==0&&flag8==0)		   //如果按键按下并且标志位flag8为0
	{
		flag8=1;						   //则标志位flag8置1
	}
	if(flag8==1&&Key_C_ONOFF==1)	  	   //如果标志位flag8为1并且按键松开
	{	
		flag9=~flag9;					   //则标志位flag9取反
	}
	if(flag9==1)							   //当flag9为1时
	{
		Send_NEC_Message(0x07);			   //红外发送键码0x09
	}
	 else								   //否则
	{
	 	Send_NEC_Message(0x15);			   //红外发送键码0x16
	}	
	flag8=0;							   //标志位flag8清零
}

//Key_STOP按键
void KeySTOP()
{
	if(Key_STOP==0)							 //如果按键按下
	{
		Delay8_77us();						 //延时8.77US
		if(Key_STOP==0)						 //再次判断按键是否按下
		{
			Send_NEC_Message(0x09);			 //红外发送键码0x0c
		}			 
	}
}

//Key_UP按键
void KeyUP()
{
	if(Key_UP==0)							 //如果按键按下
	{
		Delay8_77us();						 //延时8.77US
		if(Key_UP==0)						 //再次判断按键是否按下
		{
			Send_NEC_Message(0x16);			 //红外发送键码0x0c
		}			 
	}
}
//Key_DOWN按键
void KeyDOWN()								 
{
	if(Key_DOWN==0)							 //如果按键按下
	{
		Delay8_77us();						 //延时8.77US
		if(Key_DOWN==0)						 //再次判断按键是否按下
		{
			Send_NEC_Message(0x19);			 //红外发送键码0x15
		}			 
	}
}
//Key_LEFT按键
void KeyLEFT()
{
	if(Key_LEFT==0)							 //如果按键按下
	{
		Delay8_77us();						 //延时8.77US
		if(Key_LEFT==0)						 //再次判断按键是否按下
		{
			Send_NEC_Message(0x0d);			 //红外发送键码0x09
		}			 
	}
}

//Key_RIGHT按键
void KeyRIGHT()								 
{
	if(Key_RIGHT==0)						 //如果按键按下
	{
		Delay8_77us();						 //延时8.77US
		if(Key_RIGHT==0)					 //再次判断按键是否按下
		{
			Send_NEC_Message(0x0c);			 //红外发送键码0x16
		}			 
	}
}		  

//发送按键的红外数据
void main()
{
	while(1)
		{
			KeyUP();						  //小车前进
			KeyDOWN();						  //小车后退
			KeyLEFT();						  //小车左转
			KeyRIGHT();						  //小车右转
			KeySTOP();						  //小车停止
			KeyDUSTBINUP();					  //垃圾箱升起
			KeyDUSTBINDOWN();				  //垃圾箱放下
			KeyAONOFF();					  //扫刷启动/停止
			KeyBONOFF();					  //吸尘风机启动/停止
			KeyCONOFF();					  //抑尘水泵启动/停止
		}			   
}


红外接收驱动代码
#include"reg52.h"
#include"uart.h"
#include"intrins.h"
#define u8 unsigned char;
#define u16 unsigned short;
#define u32 unsigned int;
sbit IRM_R=P3^2;				
u8 IR_CODE[5];				//定义5个8位数据,分别存放用户码、用户码反码、按键键值码、按键键值反码、验证后的键值
u8 i=0;						//定义一个无符号字符型变量i,用于循环接收四组数据
u8 j=0;						//定义一个无符号字符型变量j,用于接收一组数据中8个bit
u16 count;					//定义一个计数变量,用来循环计数设置等待超时时间
sbit MA_F1=P0^5;
sbit MA_B1=P0^6;
sbit MB_F1=P0^7;
sbit MB_B1=P2^0;
sbit MC_F1=P2^1;
sbit MC_B1=P2^2;
sbit MD_F1=P2^3;
sbit MD_B1=P2^4; 
sbit A_F1=P0^1;
sbit A_B1=P0^2;
sbit B_F1=P0^3;
sbit B_B1=P0^4;
sbit S_BRUSHA_F1=P2^5;
sbit S_BRUSHA_B1=P2^6;
sbit S_BRUSHB_F1=P2^7;
sbit S_BRUSHB_B1=P3^0;
sbit PWM0=P0^0;
u16  SERVO_PWM=500;
u8 j,k,l,m,n;
//延时函数8ms
void Delay8ms()				//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	i = 87;
	j = 12;
	do
	{
		while (--j);
	} while (--i);
}

//延时函数10us
void Delay10us()		//@11.0592MHz
{
	unsigned char i;

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

//延时函数100us
void Delay100us()		//@11.0592MHz
{
	unsigned char i, j;

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

//延时函数300ms
void Delay300ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	_nop_();
	i = 13;
	j = 156;
	k = 83;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

//红外接收初始化函数
void IR_INIT()
{
	IT0=1;						//下降沿触发
	EX0=1;						//允许外部中断
	EA=1;						//开启总中断
	IRM_R=1;					//初始化端口为高电平
}

//串口初始化函数
void Uart_Init()
{
    TMOD = 0x20;		// T1设置为8位自动重装载定时器			
    SCON = 0x40;		// 串口工作在模式1:8位UART波特率可变,且禁止接收
    TH1 = 0xE6;			// 波特率为2400且波特率加倍时的定时器设置值。
    TL1 = TH1;			
    PCON = 0x80;		// 设置为波特率加倍
	EA = 1;				// 开总中断
	ES = 1;			    // 开串口中断
	TR1 = 1;		    // 定时器1开启计数
}

//串口发送1字节
void Uart_SendByte(int c)
{	
    SBUF = c;											  //通过串口寄出数据
    while (!TI);										  //查询T1标志位,等待八位数据发送完毕
    TI = 0;												  //当八位数据发送完毕,中断标志位清零
}

//中断处理函数
void IRISR() interrupt 0
{
//判断引导码											  //如果接收到红外信号,首先接收到的是引导码
	Delay8ms();											  //引导码低电平一共9ms,先延时8ms
														  
	if(IRM_R==0)										  //判断是不是低电平,如果是低电平,则继续判断,如果不是,则是干扰
		{
			count=200;									  //给超时检测count赋值200(由于之前延时了8ms,引导码低电平还剩1ms(100*10us=1ms))
			while((IRM_R==0)&&(count>0))				  //当红外接收引脚为低电平且count大于0时(如果循环100次后IRM_R变为1跳出循环,则继续判断)
			{											  //(如果将200次循环完,低电平一共持续10ms,超时,该信号不是引导码)
				Delay10us();							  //延时10us(间隔10us检测一次)
				count--;								  //每循环一次,count值减一
			}
		
		if(IRM_R==1)									  //判断IRM_R是不是高电平(引导码高电平一共4.5ms)
		{
			count=500;									  //给超时检测count赋值500(500*10us=5ms)
			while((IRM_R==1)&&(count>0))				  //当红外接收引脚为高电平且count大于0时(如果循环450次后IRM_R变为0跳出循环,则该信号为引导码)
			{											  //(如果将500次循环完,高电平一共持续5ms,超时,该信号不是引导码)
				Delay10us();							  //延时10us(间隔10us检测一次)
				count--;								  //每循环一次,count值减一
			}
//接收用户码和数据码		
			for(i=0;i<4;i++)							  //接收四个字节(十六位用户码,八位数据码,八位数据反码) 
			{											  
				for(j=0;j<8;j++)						  //接收八位数据
				{
					count=60;							  //count赋值60(60*10us=0.6ms)
					while((IRM_R==0)&&(count>0))		  //载波发射(低电平)0.56ms,循环56次后跳出循环
					{
						Delay10us();
						count--;
					}
					count=0;
					while(IRM_R==1)						  //判断载波不发射(高电平)持续时间,
					{									  //若为0.56ms,则接收0,若为1.68ms,则接收1
						Delay100us();					  //延时0.1ms
						count++;						  //理论上count为17,接收1,count为6,接收0				
					}
					IR_CODE[i]>>=1;						  //右移一位(数据从低位往高位传输)
					if(count>=11)						  //判断count为17还是6,(168us-56us)/100us=11
					{
						IR_CODE[i]=0x80;				  //将数组放置最高位
					}
				}
			}

		}												  
		if(IR_CODE[2]==~IR_CODE[3])						  //判断按键数据码和数据反码是否相等
		{
			IR_CODE[4]=IR_CODE[2];						  //如果相等,则将按键数据码跟新到IR_CODE[4]
			return;										  //跳出子函数
		}
	}
}

//小车直走
void go_straight()			
{
	MA_F1=1;						  //根据RZ7899芯片手册,
	MA_B1=0;						  //F1=1,B1=0电机正转
	MB_F1=1;						  //F1=0,B1=1电机反转
	MB_B1=0;						  //F1=0,B1=0电机悬空
	MC_F1=1;						  //F1=1,B1=1电机制动
	MC_B1=0;						  //所以小车直走就是四个电机全部正转
	MD_F1=1;
	MD_B1=0;
} 

//小车后退
void back_off()
{
	MA_F1=0;						  //小车后退是四个电机全部反转
	MA_B1=1;
	MB_F1=0;
	MB_B1=1;
	MC_F1=0;
	MC_B1=1;
	MD_F1=0;
	MD_B1=1;	
} 

//小车左转
void turn_left()
{
	MA_F1=0;						  //小车左转是右边电机正转,左边电机悬空
	MA_B1=0;
	MB_F1=0;
	MB_B1=0;
	MC_F1=1;
	MC_B1=0;
	MD_F1=1;
	MD_B1=0;	
} 

//小车右转
void turn_right()
{
	MA_F1=1;							//小车右转是左边电机正转,右边电机悬空
	MA_B1=0;
	MB_F1=1;
	MB_B1=0;
	MC_F1=0;
	MC_B1=0;
	MD_F1=0;
	MD_B1=0;	
}

//小车刹车
void brake()
{
	MA_F1=1;							   //刹车是四个电机制动
	MA_B1=1;
	MB_F1=1;
	MB_B1=1;
	MC_F1=1;
	MC_B1=1;
	MD_F1=1;
	MD_B1=1;	
}

//吸尘风机工作/停止
void A_ON()									
{
	A_F1=1;
	A_B1=0;		
}

void A_OFF()
{
	B_F1=1;
	B_B1=1;
}   

//水泵电机工作/停止
void B_ON()
{
	B_F1=1;
	B_B1=0;
}

void B_OFF()
{
	B_F1=1;
	B_B1=1;
}

//扫刷电机工作/停止
void S_BRUSH_ON()
{											 //扫刷是将垃圾清扫到中间
	S_BRUSHA_F1=1;							 //所以要一个正转一个反转
	S_BRUSHA_B1=0;
	S_BRUSHB_F1=0;
	S_BRUSHA_B1=1;	
}

void  S_BRUSH_OFF()
{
	S_BRUSHA_F1=1;
	S_BRUSHA_B1=1;
	S_BRUSHB_F1=1;
	S_BRUSHA_B1=1;		
}

//垃圾箱举升舵机升起/降下

//ms延时函数
void Delayms(unsigned char ms)		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);
}

//定时器清零
void Timer0_INIT()
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x00;			//设置定时初值
	TH0 = 0x00;			//设置定时初值
	TF0 = 0;			//清除TF0标志
	TR0 = 1;			//定时器0开始计时
	ET0 = 1;			//开定时器0中断
}

//给定时器赋值产生中断
 void Timer0_Value(unsigned int pwm)
{
	unsigned short value;
	value=0xffff-pwm;							//因为定时器是TH0,TL0都要全部计数到0xFF后在计1个数就会产生中断,所以要想产生
												//pwm毫秒的中断,那么TH0,TL0就应该赋值(0xFFFF-pwm)
	TR0 = 0;
	TL0=value;									//16位数据给8位数据赋值默认将16位数据的低八位直接赋给八位数据
    TH0=value>>8;								//将16位数据右移8位,也就是将高8位移到低八位,再赋值给8位数据	
	TR0 = 1;									//定时器启动
}
//中断处理函数
void Timer0_isr() interrupt 1 using 1
{
	static u16 i = 1;								//定义一个静态变量,每次调用函数时保持上一次所赋的值							
	switch(i)
	{
		case 1:
			PWM0=1;						 			//PWM控制管脚高电平			                                 
			Timer0_Value(SERVO_PWM);				//给定时器0赋值,计数SERVO_PWM个脉冲后产生中断,下次中断会进入下一个case语句
			break;
		case 2:
			PWM0=0;									//PWM控制管脚低电平		
			Timer0_Value(20000-SERVO_PWM);			//高脉冲结束后剩下的时间(20000-SERVO_PWM)全是低电平了, 
			i = 0;									//20000个脉冲正好为一个周期20毫秒
			break;	 
	}
	i++;
}

//垃圾箱升起
void DUSTBIN_UP()
{
	Timer0_INIT();	//定时器0初始化
	EA = 1;			//开总中断
		SERVO_PWM = 500;		//脉冲宽度在500微秒,对应0°
		Delayms(500);				//延时0.5秒
		SERVO_PWM = 1000;		//脉冲宽度在1000微秒,对应45°
		Delayms(500);
		SERVO_PWM = 1500;		//脉冲宽度在1000微秒,对应90°
		Delayms(500);
		SERVO_PWM = 2000;		//脉冲宽度在1000微秒,对应135°
		Delayms(500);
		SERVO_PWM = 2500;		//脉冲宽度在1000微秒,对应180°
		Delayms(500);
}

//垃圾箱降下
void DUSTBIN_DOWN()
{
	Timer0_INIT();	//定时器0初始化
	EA = 1;			//开总中断
		SERVO_PWM = 2500;		//脉冲宽度在500微秒,对应180°
		Delayms(500);				//延时0.5秒
		SERVO_PWM = 2000;		//脉冲宽度在1000微秒,对应135°
		Delayms(500);
		SERVO_PWM = 1500;		//脉冲宽度在1000微秒,对应90°
		Delayms(500);
		SERVO_PWM = 1000;		//脉冲宽度在1000微秒,对应45°
		Delayms(500);
		SERVO_PWM = 500;		//脉冲宽度在1000微秒,对应0°
		Delayms(500);
}

void main(void)
{
	IR_INIT();
	Uart_Init();
	while (1)
	{		
		Uart_SendByte();
		Delay300ms();

//小车行走
		switch(j)
		{
			case 1:	IR_CODE[4]=0x09;			
				go_straight();
				break;
			case 2: IR_CODE[4]=0x16;
				back_off();
				break;
			case 3: IR_CODE[4]=0x19;
				turn_left();
				break;
			case 4: IR_CODE[4]=0x0d;
				turn_right();
				break;
			case 5: IR_CODE[4]=0x0c;
				brake();
				break;
		 default: j=0;
		 		break;
		}

//垃圾箱升降
		switch(k)
		{
			case 1: IR_CODE[4]=0x45;
				DUSTBIN_UP();
				break;
			case 2: IR_CODE[4]=0x46;
				DUSTBIN_DOWN();
				break;
		default: k=0;
				break; 		
		}

//吸尘器工作
		switch(l)
		{
			case 1: IR_CODE[4]=0x47;
				A_ON();
				break;
	   		case 2: IR_CODE[4]=0x44;
				A_OFF();
				break;
		default: l=0;
				break;
		}

//洒水器工作
		switch(n)
		{
			case 1: IR_CODE[4]=0x40;
				B_ON();
				break;
			case 2: IR_CODE[4]=0x43;		
				B_OFF();
				break;
		 default: n=0;
				break;
		}	

//扫刷工作
		switch(m)
		{
			case 1: IR_CODE[4]=0x07;			
				S_BRUSH_ON();
				break;
			case 2: IR_CODE[4]=0x15;
				S_BRUSH_OFF();
				break;
		default: m=0;
				break;
		}	
	}		
}			
			
			
			
			
	




五、 总结

  第一个难点在于电机选型上,由于一开始设计整车的结构还没有确定,我无法判断需要多少扭矩及多少转速的电机,于是我在淘宝上买了一个智能小车模型,用卷尺量出模型的大致尺寸并加以修改,然后在三维软件里画出模型并赋予材料估算重量,再根据我实习时的经验,参考公司的新能源清洁车绘制了一个大概的小车结构,再结合网上的智能小车实验案例,进而估算出本设计需要的电机扭矩、转速和电压。
第二个难点是芯片选型和元器件选型,市面上主流的电机驱动芯片是L298N和ULN2003A,考虑到ULN2003A不适合驱动直流电机,而L298N外部电路相对复杂,所以我选择了更为简单的RZ7899作为电机驱动芯片。元器件选型应该算是我在设计过程中最难解决的问题了,一些描述详细的芯片手册还好,会给出典型应用电路和元件选型参考,但还是会遇到一些元器件需要自己来计算和判断参数,我的解决办法是去淘宝和立创商城里,搜索自己需要的元器件,再根据卖家或商城中给出的参数和元器件手册来选择。
第三个难点是PCB绘制,一开始我是根据元件手册给出的尺寸自己绘制元件库,工作量非常巨大,但因为疫情无法制作实物,我就改成去淘宝上买现成的二维三维封装库了,这导致本设计的部分元器件并不是按照电路设计中BOM表给出的封装来画的,如果要制作出实物,还是要按照元件尺寸重新绘制。

五、 文章目录

目 录
1 绪论 6
1.1 研究背景及意义 6
1.1.1 研究背景 6
1.1.2 本设计的目的、意义 6
1.2 国内外研究现状 7
1.3智能清扫车的发展趋势 7
1.4 研究的主要内容和目标 8
1.5 本章小结 8
2总体方案设计 9
2.1智能清洁小车的硬件系统组成 9
2.2智能清洁小车的硬件结构图 9
2.3智能清洁小车的电机选型 10
2.4本章小结 11
3 硬件电路设计 12
3.1单片机最小系统板设计 12
3.2锂电池平衡充电电路 16
3.3过放保护电路 21
3.4线性稳压电路 24
3.5行走电机、扫刷电机、水泵电机驱动电路 28
3.6吸尘风机驱动电路 32
3.7垃圾箱举升舵机驱动电路 35
3.8红外接收电路 40
3.9红外发送遥控电路 42
3.10本章总结 47
4.软件编程设计 48
4.1基本思路 48
4.2红外发射程序设计 48
4.3红外接收驱动程序设计 48
4.4本章总结 49
5.小车结构设计 50
5.1基本布局和功能分析 50
5.2小车二维及三维图 51
5.3本章小结 52
6.结束语 53
6.1结论 53
6.11设计总结和难点 53
6.1.2设计创新点 54
6.13设计的不足点 54
参考文献 55
致谢 55
附录A:系统原理图 56
附录B:程序代码 57
红外发射代码 57
红外接收驱动代码 66

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/110013.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JAVA反射机制及动态代理

反射机制 反射机制是什么 1、Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息&#xff0c;从而操作类或对象的属性和方法。本质是JVM得到class对象之后&#xff0c; 再通过class对象进行反编译&#xff0c;从而获取对象的各种信息。 2、Java属于先编译再运行的…

gurobi 安装/license激活 记录

前言&#xff1a;花了好久&#xff0c;被嫌弃惹ww&#xff0c;记录一下踩过的坑 至于为何没安装gurobi也能跑一段时间&#xff0c;直到显示需要license激活&#xff0c;还是未解之迷&#xff0c;需要教教。 首先这是官方给的gurobi license激活教程 我们一步步来复现吧&#…

Go命令行参数操作:os.Args、flag包

Go命令行参数操作&#xff1a;os.Args、flag包 最近在写项目时&#xff0c;需要用到命令行传入的参数&#xff0c;正好借此机会整理一下。 1 os.Args&#xff1a;程序运行时&#xff0c;携带的参数&#xff08;包含exe本身&#xff09; package mainimport ("fmt"&q…

cola架构:有限状态机(FSM)源码分析

目录 0. cola状态机简述 1.cola状态机使用实例 2.cola状态机源码解析 2.1 语义模型源码 2.1.1 Condition和Action接口 2.1.2 State 2.1.3 Transition接口 2.1.4 StateMachine接口 2.2 Builder模式 2.2.1 StateMachine Builder模式 2.2.2 ExternalTransitionBuilder-…

Spring中Bean的完整生命周期!(Bean实例化的流程,Spring后处理器,循环依赖解释及解决方法)附案例演示

Bean实例化的基本流程 加载xml配置文件&#xff0c;解析获取配置中的每个的信息&#xff0c;封装成一个个的BeanDefinition对象将BeanDefinition存储在一个名为beanDefinitionMap的Map<String,BeanDefinition>中ApplicationContext底层遍历beanDefinitionMap&#xff0c…

解决计算机msvcp120.dll文件丢失的5种方法,亲测有效

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp120.dll丢失”。这个错误提示可能会给我们带来很大的困扰&#xff0c;影响我们的正常使用。本文将详细介绍msvcp120.dll丢失的原因、解决方法以及预防措施&#xff0c;帮助大家更好地…

3D LUT 滤镜 shader 源码分析

最近在做滤镜相关的渲染学习&#xff0c;目前大部分 LUT 滤镜代码实现都是参考由 GPUImage 提供的 LookupFilter 的逻辑&#xff0c;整个代码实现不多。参考网上的博文也有各种解释&#xff0c;参考了大量博文之后终于理解了&#xff0c;所以自己重新整理了一份&#xff0c;方便…

selenium工作原理和反爬分析

一、 Selenium Selenium是最广泛使用的开源Web UI(用户界面)自动化测试套件之一&#xff0c;支持并行测试执行。Selenium通过使用特定于每种语言的驱动程序支持各种编程语言。Selenium支持的语言包括C#&#xff0c;Java&#xff0c;Perl&#xff0c;PHP&#xff0c;Python和Ru…

Linux——Linux权限

Linux权限 前言一、shell命令以及运行原理二、Linux权限的概念Linux权限管理文件访问者的分类&#xff08;人&#xff09;文件类型和访问权限&#xff08;事物属性&#xff09;文件权限值的表示方法文件访问权限的相关设置方法 file指令目录的权限粘滞位 总结 前言 linux的学习…

基本微信小程序的体检预约小程序

项目介绍 我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;体检预约系统小程序被用户普遍使用&#xff0c;为方便用户…

LabVIEW开发基于图像处理的车牌检测系统

LabVIEW开发基于图像处理的车牌检测系统 自动车牌识别的一般步骤是图像采集、去除噪声的预处理、车牌定位、字符分割和字符识别。结果主要取决于所采集图像的质量。在不同照明条件下获得的图像具有不同的结果。在要使用的预处理技术中&#xff0c;必须将彩色图像转换为灰度&am…

【PyQt学习篇 · ⑧】:QWidget - 窗口特定操作

文章目录 图标标题不透明度窗口状态最大化和最小化窗口标志案例 图标 setWindowIcon(QIcon("resource/header_icon.png"))&#xff1a;该函数用于设置QWidget的窗口图标。可以为窗口设置一个图标&#xff0c;以显示在窗口标题栏、任务栏或窗口管理器中。 windowIcon…

识别flink的反压源头

背景 flink中最常见的问题就是反压&#xff0c;这种情况下我们要正确的识别导致反压的真正的源头&#xff0c;本文就简单看下如何正确识别反压的源头 反压的源头 首先我们必须意识到现实中轻微的反压是没有必要去优化的&#xff0c;因为这种情况下是由于偶尔的流量峰值,Task…

Linux 音频驱动实验

目录 音频接口简介为何需要音频编解码芯片&#xff1f;WM8960 简介I2S 总线接口I.MX6ULL SAI 简介 硬件原理图分析音频驱动使能修改设备树使能内核的WM8960 驱动alsa-lib 移植alsa-utils 移植 声卡设置与测试amixer 使用方法音乐播放测试MIC 录音测试LINE IN 录音测试 开机自动…

论文范文:论基于架构的软件设计方法及应用

注意:范文只适用于帮助大家打开写作思路,并不能作为素材直接用于平时练习、考试中。考试中直接使用范文的素材,会有被认定为雷同卷的风险。 摘要: 2022年4月,本人所在单位计划研发生态集装箱管理控制平台项目。该平台主要用于与现有公司生态集装箱产品做对接,达到远程控制…

【Leetcode】【简单】13. 罗马数字转整数

力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能&#xff0c;轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/roman-to-integer/description/ …

用图说话——流程图进阶

目录 一、基本流程图 二、时序流程图 一、基本流程图 经常阅读歪果仁绘制的流程图&#xff0c;感觉比较规范&#xff0c;自己在工作中也尝试用他们思维来绘图&#xff0c;这是一个小栗子&#xff1a; 二、时序流程图 在进行Detail设计过程中&#xff0c;一般的绘图软件显得…

【Xilinx Kintex-7 Virtex-7 LVDS bank电压】

各种介绍很多&#xff0c;也都写的似乎很长很详细&#xff0c;但有错误。 详细的查阅Xilinx 论坛 43989 核心 总结一下就是Xilinx 7serious 的FPGA ,你如果要配置成LVDS,这的LVDS是正儿八经的那种&#xff0c;那么FPGA 这块你只需要记住两点就可以。 第一&#xff0c;假如你…

开放式耳机推荐排行榜、开放式耳机性价比推荐

随着无线耳机越来越普及&#xff0c;人们对于耳机的要求也越来越高。传统的入耳式耳机虽然音质好&#xff0c;但是长时间佩戴容易引起耳部不适&#xff0c;甚至可能导致听力损失。为此大家都开始选择入手舒适、安全的开放式耳机&#xff0c;现在耳机市场&#xff0c;各种品牌、…

脚本木马编写

PHP小马编写 小马用waf扫描&#xff0c;没扫描出来有风险。 小马过waf之后用echo $_SERVER[DOCUMENT_ROOT]获得当前运行脚本所在的文档根目录。&#xff0c;然后在上传大马工具。 $_SERVER&#xff0c;参考&#xff1a;PHP $_SERVER详解 小马编写二次加密 现在是可以被安全…
最新文章