超声波避障小车,红外遥控小车上下左右运动仿真
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- #include <reg52.h> //51头文件
- #include <intrins.h> //包含nop等系统函数
- #define uchar unsigned char
- #define uint unsigned int
- /*红外*/
- #define JINGZHEN 12
- #define TIME0TH ((65536-100*JINGZHEN/12)&0xff00)>>8 //12M晶振机械周期0.25us,100us,红外遥控
- #define TIME0TL ((65536-100*JINGZHEN/12)&0xff)
- unsigned char count0 = 50;
- unsigned char count1 = 0;
- sbit EN = P2^5;
- uint IrCount=0,Show=0,Cont=0;
- uchar IRDATBUF[32];
- uchar IrDat[5]={0,0,0,0,0};
- uchar IrStart=0,IrDatCount=0;
- code uchar BitMsk[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,};
- /*电机驱动IO定义*/
- sbit IN1 = P1^2; //为1 左电机反转
- sbit IN2 = P1^3; //为1 左电机正转
- sbit IN3 = P1^6; //为1 右电机正转
- sbit IN4 = P1^7; //为1 右电机反转
- sbit EN1 = P1^4; //为1 左电机使能
- sbit EN2 = P1^5; //为1 右电机使能
- /*按键定义*/
- sbit key_s2 = P3^0;
- sbit beep = P2^3;//蜂鸣器
- sbit RX = P2^0;//ECHO超声波模块回响端
- sbit TX = P2^1;//TRIG超声波模块触发端
- sbit LCM_RW = P3^6; //定义LCD引脚
- sbit LCM_RS = P3^5;
- sbit LCM_E = P3^4;
- sbit servorControl =P2^7; //舵机的控制引脚
- #define lcddata P0 //定义液晶屏数据口
- #define Busy 0x80 //用于检测LCM状态字中的Busy标识
- #define left_motor_en EN1 = 1 //左电机使能
- #define right_motor_en EN2 = 1 //右电机使能
- #define left_motor_stops IN1 = 0, IN2 = 0//左电机停止
- #define right_motor_stops IN3 = 0, IN4 = 0//右电机停止
- #define left_motor_go IN1 = 0, IN2 = 1//左电机正传
- #define left_motor_back IN1 = 1, IN2 = 0//左电机反转
- #define right_motor_go IN3 = 1, IN4 = 0//右电机正传
- #define right_motor_back IN3 = 0, IN4 = 1//右电机反转
- unsigned char pwm_left_val = 38;//左电机占空比值 取值范围0-80,0最快
- unsigned char pwm_right_val = 44;//右电机
- unsigned char pwm_t;//周期
- unsigned int time = 0;//传输时间
- unsigned long S = 0;//距离
- bit flag = 0;//超出测量范围标志位
- bit flag1=0;//舵机模块计数标志
- uchar control=5; //控制舵机转角
- uchar servorTime=0; //控制舵机脉冲占空比
- uchar lFlag=0;//左方向是否有障碍的标志
- uchar rFlag=0;//右方向是否有障碍的标志
- uint ldistance=0,rdistance=0;//左右边长度
- unsigned char code tishi[] ="the distance is:";//LCD1602显示格式
- unsigned char code ASCII[13] = "0123456789.cm";
- unsigned char code table[]=" howfar:000.0cm";
- unsigned char code table1[]=" Out of range ";
- unsigned char disbuff[4] = { 0,0,0,0};//距离显示缓存
-
- bit flagg=0; //切换正常避障模式和遥控模式
- void delay(unsigned int z)//毫秒级延时
- {
- unsigned int x,y;
- for(x = z; x > 0; x--)
- for(y = 114; y > 0 ; y--);
- }
- void Delay10us(unsigned char i) //10us延时函数 启动超声波模块时使用
- {
- unsigned char j;
- do{
- j = 10;
- do{
- _nop_();
- }while(--j);
- }while(--i);
- }
-
- /************************************LCD1602液晶屏驱动函数************************************************/
- /******************读状态**********************/
- unsigned char readstatus(void)
- {
- lcddata = 0xFF;
- LCM_RS = 0;
- Delay10us(1);
- LCM_RW = 1;
- Delay10us(1);
- do{
- LCM_E = 0;
- Delay10us(1);
- LCM_E = 0;
- Delay10us(1);
- LCM_E = 1;
- Delay10us(1);
- }
- while (lcddata & Busy); //检测忙信号
- return(lcddata);
- }
- /****************写数据************************/
- void writedata(unsigned char datas)
- {
- readstatus(); //检测忙
- lcddata = datas;
- LCM_RS = 1;
- Delay10us(1);
- LCM_RW = 0;
- Delay10us(1);
- LCM_E = 0; //若晶振速度太高可以在这后加小的延时
- Delay10us(1);
- LCM_E = 0; //延时
- Delay10us(1);
- LCM_E = 1;
- Delay10us(1);
- }
- /***************写指令*************************/
- void writecom(unsigned char WCLCM,BuysC) //BuysC为0时忽略忙检测
- {
- if (BuysC) readstatus(); //根据需要检测忙
- lcddata = WCLCM;
- LCM_RS = 0;
- Delay10us(1);
- LCM_RW = 0;
- Delay10us(1);
- LCM_E = 0;
- Delay10us(1);
- LCM_E = 0;
- Delay10us(1);
- LCM_E = 1;
- Delay10us(1);
- }
- /*******************初始化******************/
- void lcdinition(void)
- {
- lcddata = 0;
- writecom(0x38,0); //三次显示模式设置,不检测忙信号
- delay(5);
- writecom(0x38,0);
- delay(5);
- writecom(0x38,0);
- delay(5);
- writecom(0x38,1); //显示模式设置,开始要求每次检测忙信号
- writecom(0x08,1); //关闭显示
- writecom(0x01,1); //显示清屏
- writecom(0x06,1); // 显示光标移动设置
- writecom(0x0c,1); // 显示开及光标设置
- }
- /*******************按指定位置显示一个字符*****/
- void DisplayOneChar(unsigned char x, unsigned char y, unsigned char data2)
- {
- y &= 0x1;
- x&= 0xF; //限制X不能大于15,Y不能大于1
- if (y) x |= 0x40; //当要显示第二行时地址码+0x40;
- x |= 0x80; //算出指令码
- writecom(x, 1); //发命令字
- writedata(data2); //发数据
- }
- /******************按指定位置显示一串字符*******/
- void DisplayListChar(unsigned char x, unsigned char y, unsigned char code *DData)
- {
- unsigned char ListLength;
- ListLength = 0;
- y &= 0x1;
- x &= 0xF; //不能大于15,y不能大于1
- while (DData[ListLength]>0x19) //若到达字串尾则退出
- {
- if (x <= 0xF) //坐标应小于0xF
- {
- DisplayOneChar(x, y, DData[ListLength]); //显示单个字符
- ListLength++;
- x++;
- }
- }
- }
- /***************************************************************************/
-
- /*小车前进*/
- void forward(uint m)
- {
- left_motor_go; //左电机前进
- right_motor_go; //右电机前进
- delay(m);
- }
- /*PWM控制使能 小车后退*/
- void backward(uint m)
- {
- left_motor_back; //左电机后退
- right_motor_back; //右电机后退
- delay(m);
- }
- /*小车停止*/
- void stop(uint m)
- {
- right_motor_stops;//右电机停止
- left_motor_stops; //左电机停止
- delay(m);
- }
- /*小车左转*/
- void left_rapidly(uint m)
- {
- left_motor_back;
- right_motor_go;
- delay(m);
- }
- /*小车右转*/
- void right_rapidly(uint m)
- {
- right_motor_back;
- left_motor_go;
- delay(m);
- }
- /*判断S2是否被按下*/
- void keyscan()
- {
- for(;;) //死循环
- {
- if(key_s2 == 0)// 实时检测S2按键是否被按下
- {
- delay(5); //软件消抖
- if(key_s2 == 0)//再检测S2是否被按下
- {
- while(!key_s2);//松手检测
- beep = 0; //使能有源蜂鸣器
- delay(200);//200毫秒延时
- beep = 1; //关闭有源蜂鸣器
- break; //退出FOR死循环
- }
- }
- }
- }
- /*LCD显示所测结果*/
- void xianshi( )
- {
- if((S>=4000)||flag==1) //超出测量范围
- {
- flag=0;
- DisplayListChar(0, 1, table1);
- }
- else
- {
- disbuff[0]=S/1000; //距离数值千位
- disbuff[1]=S%1000/100;//距离数值百位
- disbuff[2]=S%100/10;//距离数值十位
- disbuff[3]=S%10; //距离数值个位
- DisplayListChar(0, 1, table);
- DisplayOneChar(9, 1, ASCII[disbuff[0]]);
- DisplayOneChar(10, 1, ASCII[disbuff[1]]);
- DisplayOneChar(11, 1, ASCII[disbuff[2]]);
- DisplayOneChar(12, 1, ASCII[10]);
- DisplayOneChar(13, 1, ASCII[disbuff[3]]);
- DisplayOneChar(14, 1, ASCII[11]);
- DisplayOneChar(15, 1, ASCII[12]);
- }
- }
- void qidongceju() //启动超声波模块
- {
- TX=1; //启动一次模块
- Delay10us(2); //延时20us
- TX=0;
- }
- /*计算超声波所测距离并显示*/
- uint ceju()
- {
- TH0=0;
- TL0=0;
- qidongceju();
- while(!RX); //当RX(ECHO信号回响)为零时等待
- TR0=1; //开启计数
- while(RX); //当RX为1计数并等待
- TR0=0; //关闭计数
- time=TH0*256+TL0;
- S=(float)(time*1.085)*0.16; //单位为MM
- if(S<=400)
- return 1; //距离小于400mm时返回1
- else
- return 0;
- }
- void duoji(uchar m) //舵机转向定义
- {
- control=m;
- servorTime=0;
- flag1=1;
- delay(100);
- flag1=0;
- delay(100); //延时,降低转向速度
- }
- /*超声波避障*/
- void avoid()
- {
- if(S < 400)//设置避障距离 ,单位毫米 刹车距离
- {
- beep = 0;//使能蜂鸣器
- stop();//停车
- do{
- xianshi();
- duoji(18); //使舵机向左摆动
- lFlag=ceju();
- xianshi();
- ldistance=S;
- duoji(8); //使舵机向右摆动
- rFlag=ceju();
- xianshi();
- rdistance=S;
- duoji(13);//控制舵机使超声波模块正对前方
- backward(200);
- if(rdistance>ldistance)
- {
- right_rapidly(10);
- }
- if(ldistance>rdistance)
- {
- left_rapidly(10);
- }
- }while(lFlag==1&&rFlag==1);//当前方、左右侧都有障碍物
- if(lFlag==0&&rFlag==1) //左侧没有障碍物,右侧有
- {
- left_rapidly(80);
- }
- else if(rFlag==0&&lFlag==1)//右侧没有障碍物,左侧有
- {
- right_rapidly(80);
- }
- else if(rFlag==0&&lFlag==0)//两侧都没有障碍物,默认向前走
- {
- forward();
- }
- }
- else{
- forward();
- beep=1;
- }
- }
- void inition1()
- {
- TMOD = 0x21;//定时器1工作模式2,8位自动重装;
- TH0 = 0;//定时器0工作模式1,16位定时用于产生PWM,T0用测ECH0脉冲长度
- TL0 = 0;//T0,16位定时计数用于记录ECHO高电平时间
- ET0 = 1;
- TH1 = 155;
- TL1 = 155; //100HZ T1
- ET1 = 1;
- TR1 = 1;
- EA = 1;
- }
- void inition2()
- {
- TMOD |= 0x011;
- TH0 = TIME0TH;
- TL0 = TIME0TL;
- ET0=1;
- TR0=1;
- ET1=1;
- TR1=1;
- IT0 = 1; //下降沿
- EX0 = 1;
- EA=1;
- }
- void scan()
- {
- if(Show==1)
- {
- Show=0;
- Cont=0;
- switch (IrDat[3])
- {
- case 0x12://go
- forward(1);
- break;
- case 0x0b://back
- backward(1);
- break;
- case 0x1a://right
- right_rapidly(1);
- break;
- case 0x1e://left
- right_rapidly(1);
- break;
-
- }
- }
- }
- void main()
- {
- lcdinition();
- delay(5);
- DisplayListChar(0, 0, tishi);//1602第一行显示tishi数组内容
- DisplayListChar(0, 1, table);//1602第二行显示table数组内容
- keyscan();//等待按下S2启动小车
- TX = 0;
- if(flagg==0)
- inition1();
- else
- {
- inition2();
- }
- while(1)
- {
- if(flagg==0){
- duoji(13);//控制舵机使超声波模块正对前方
- ceju();
- xianshi();
- avoid(); }
- else
- {
- scan();
- }
- }
- }
- /*定时器1中断输出PWM信号*/
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
Keil代码与Proteus8.13仿真下载:
红外超声波舵机避障小车仿真和代码.zip
(145.18 KB, 下载次数: 90)
|