之前做的时候苟了一周编出来的程序
QX-A51小车跟随前方障碍物运动
s2控制小车前进后退左转右转
s3跟踪
s4光敏
功能蛮全的,跟踪不是特别灵敏,跟小车硬件有关,可以再调整。
单片机源程序如下:
- #include <reg52.h>
- #include <intrins.h>
- #include <C:\Users\Administrator\Desktop\QXA51.h>
- unsigned char pwm_left_val =180;//左电机占空比值 取值范围0-170,0最快
- unsigned char pwm_right_val = 175;//右电机占空比值取值范围0-170 ,0最快
- unsigned char pwm_t;//周期
- #define MAIN_Fosc 11059200UL //宏定义主时钟HZ
- #define PCF8591_ADDR 0x90 //PCF8591地址
- #define DACOUT_EN 0x40 //DAC输出使能
- typedef unsigned char INT8U;
- typedef unsigned char uchar;
- typedef unsigned int INT16U;
- typedef unsigned int uint;
- sbit SDA = P2^0; //I2C串行数据
- sbit SCL = P2^1; //I2C串行时钟
- sbit we = P2^7; //位定义数码管位选锁存器接口
- sbit du = P2^6; //位定义数码管位选锁存器接口
- sbit LED0 = P1^0;
- sbit LED1 = P1^1;
- sbit LED2 = P1^2;
- sbit LED3 = P1^3;
- sbit LED4 = P1^4;
- sbit LED5 = P1^5;
- sbit LED6 = P1^6;
- sbit LED7 = P1^7;//led流水灯
- uchar code leddata[]={
- 0x3F, //"0"
- 0x06, //"1"
- 0x5B, //"2"
- 0x4F, //"3"
- 0x66, //"4"
- 0x6D, //"5"
- 0x7D, //"6"
- 0x07, //"7"
- 0x7F, //"8"
- 0x6F, //"9"
- 0x00, //熄灭
- 0x00 //自定义
- }; //数码管段选表
- uchar AD_Value; //存储AD转换回的数字量
- uint i=0,a=0,b=0,c=0;
- void Delay_Ms(INT16U ms)
- {
- INT16U i;
- do{
- i = MAIN_Fosc / 96000;
- while(--i); //96T per loop
- }while(--ms);
- }
- void Delay5us()
- {
- #if MAIN_Fosc == 11059200
- _nop_();
- #elif MAIN_Fosc == 12000000
- _nop_();
- #elif MAIN_Fosc == 22118400
- _nop_(); _nop_(); _nop_();
- #endif
- }
- /*====================================
- 函数:I2C_init()
- 描述:I2C总线初始化
- ====================================*/
- void I2C_init()
- {
- SDA = 1; //数据总线高
- _nop_();
- SCL = 1; //时钟总线高
- _nop_();
- }
- /*====================================
- 函数:I2C_Start()
- 描述:I2C起始信号
- ====================================*/
- void I2C_Start()
- {
- SCL = 1;
- _nop_();
- SDA = 1;
- Delay5us();
- SDA = 0;
- Delay5us();
- }
- /*====================================
- 函数:I2C_Stop()
- 描述:I2C停止信号
- ====================================*/
- void I2C_Stop()
- {
- SDA = 0;
- _nop_();
- SCL = 1;
- Delay5us();
- SDA = 1;
- Delay5us();
- }
- /*====================================
- 函数:Master_ACK(bit i)
- 参数:i 为0时发送非应答 为1时发送应答
- 描述:I2C主机发送应答
- ====================================*/
- void Master_ACK(bit i)
- {
- SCL = 0; // 拉低时钟总线允许SDA数据总线上的数据变化
- _nop_(); // 让总线稳定
- if (i) //如果i = 1 那么拉低数据总线 表示主机应答
- {
- SDA = 0;
- }
- else
- {
- SDA = 1; //发送非应答
- }
- _nop_();//让总线稳定
- SCL = 1;//拉高时钟总线 让从机从SDA线上读走 主机的应答信号
- _nop_();
- SCL = 0;//拉低时钟总线, 占用总线继续通信
- _nop_();
- SDA = 1;//释放SDA数据总线。
- _nop_();
- }
- /*====================================
- 函数:Test_ACK()
- 返回:0为非应答 1为应答
- 描述:I2C检测从机应答
- ====================================*/
- bit Test_ACK() // 检测从机应答
- {
- SCL = 1;//时钟总线为高电平期间可以读取从机应答信号
- Delay5us();
- if (SDA)
- {
- SCL = 0;
- I2C_Stop();
- return(0);
- }
- else
- {
- SCL = 0;
- return(1);
- }
- }
- /*====================================
- 函数:I2C_send_byte(uchar byte)
- 参数:byte 要发送的字节
- 描述:I2C发送一个字节
- ====================================*/
- void I2C_send_byte(uchar byte)
- {
- uchar i;
- for(i = 0 ; i < 8 ; i++)
- {
- SCL = 0;
- _nop_();
- if (byte & 0x80) //
- {
- SDA = 1;
- _nop_();
- }
- else
- {
- SDA = 0;
- _nop_();
- }
- SCL = 1;
- _nop_();
- byte <<= 1;
- }
- SCL = 0;
- _nop_();
- SDA = 1;
- _nop_();
- }
- /*====================================
- 函数:I2C_read_byte()
- 返回:读取的字节
- 描述:I2C读一个字节
- ====================================*/
- uchar I2C_read_byte()
- {
- uchar i, dat;
- SCL = 0 ;
- _nop_();
- SDA = 1;
- _nop_();
- for(i = 0 ; i < 8 ; i++)
- {
- SCL = 1;
- _nop_();
- dat <<= 1;
- if (SDA)
- {
- dat |= 0x01;
- }
- _nop_();
- SCL = 0;
- _nop_();
- }
- return(dat);
- }
- /*DAC输出*/
- bit DAC_OUT(uchar DAT)
- {
- I2C_Start();
- I2C_send_byte(PCF8591_ADDR+0);
- if (!Test_ACK())
- {
- return(0);
- }
- I2C_send_byte(DACOUT_EN); //DA输出使能
- if (!Test_ACK())
- {
- return(0);
- }
- I2C_send_byte(DAT);
- if (!Test_ACK())
- {
- return(0);
- }
- I2C_Stop();
- return(1);
- }
- /*读AD数据*/
- bit ADC_Read(uchar CON)
- {
- I2C_Start();
- I2C_send_byte(PCF8591_ADDR+0);
- if (!Test_ACK())
- {
- return(0);
- }
- I2C_send_byte(CON);
- Master_ACK(0);
- I2C_Start();
- I2C_send_byte(PCF8591_ADDR+1);
- if (!Test_ACK())
- {
- return(0);
- }
- AD_Value = I2C_read_byte();
- Master_ACK(0);
- I2C_Stop();
- return(1);
- }
- /*小车前进*/
- void forward()
- {
- left_motor_en; //左电机使能
- right_motor_en;//右电机使能
- left_motor_go; //左电机前进
- right_motor_go; //右电机前进
- }
- /*小车后退*/
- void backward()
- {
- left_motor_en; //左电机使能
- right_motor_en;//右电机使能
- left_motor_back; //左电机后退
- right_motor_back; //右电机后退
- }
- /*小车左转*/
- void left()
- {
- left_motor_stops; //左电机停止
- right_motor_en;//右电机使能
- right_motor_go; //右电机前进
- }
- /*小车右转*/
- void right()
- {
- right_motor_stops;//右电机停止
- left_motor_en; //左电机使能
- left_motor_go; //左电机前进
- }
- /*小车停止*/
- void stop()
- {
- right_motor_stops;//右电机停止
- left_motor_stops; //左电机停止
- }
- void timer0() interrupt 1
- {
- pwm_t++;//周期计时加
- if(pwm_t == 255)
- pwm_t = EN1 = EN2 = 0;
- if(pwm_left_val == pwm_t)//左电机占空比
- EN1 = 1;
- if(pwm_right_val == pwm_t)//右电机占空比
- EN2 = 1;
- }
- void main()
- {
- unsigned char j;
- for(;;)
- {
- while(1)
- {
- if(key_s2 == 0)//判断S2是否按下
- {
- Delay_Ms(5);//软件消抖
- if(key_s2 == 0)
- {
- while(!key_s2);//松手检测
- beep = 0;
- Delay_Ms(1000);
- beep = 1;
-
- TMOD |= 0x02;//8位自动重装模块
- TH0 = 220;
- TL0 = 220;//11.0592M晶振下占空比最大比值是256,输出100HZ
- TR0 = 1;//启动定时器0
- ET0 = 1;//允许定时器0中断
- EA = 1;
-
- forward();//小车前进
- Delay_Ms(1000);//毫秒级延时
-
- stop();//小车停止
- Delay_Ms(1000);//毫秒级延时
-
- backward();//小车后退
- beep = 0;//蜂鸣器鸣叫
- Delay_Ms(1000);//毫秒级延时
-
- stop();//小车停止
- beep = 1;//蜂鸣器停止鸣叫
- Delay_Ms(1000);//毫秒级延时
-
- left(); // 小车左转
- beep = 0;//蜂鸣器鸣叫
- Delay_Ms(1000);//毫秒级延时
-
- stop();//小车停止
- beep = 1;//蜂鸣器停止鸣叫
- Delay_Ms(1000);//毫秒级延时
-
- right();// 小车右转延时
- beep = 0;//蜂鸣器鸣叫
- Delay_Ms(1000);//毫秒级延时
-
- stop();//小车停止
- beep=1;//蜂鸣器停止鸣叫
- Delay_Ms(1000);//毫秒级延时
- }
- }
- if(key_s3 == 0)//判断S3是否按下
- {
- Delay_Ms(5);//软件消抖
- if(key_s3 == 0)
- {
- while(!key_s3);//松手检测
- beep = 0;//蜂鸣器鸣叫
- Delay_Ms(1000);//毫秒级延时
- beep = 1;//蜂鸣器停止鸣叫
- TMOD |= 0x02;//8位自动重装模块
- TH0 = 220;
- TL0 = 220;//11.0592M晶振下占空比最大比值是256,输出100HZ
- TR0 = 1;//启动定时器0
- ET0 = 1;//允许定时器0中断
- EA = 1;
- I2C_init();
- while(1)
- {
- if (ADC_Read(0x00))
- if (DAC_OUT(AD_Value))
- if (AD_Value > 150) {stop(); }
- else {forward(); }
- Delay_Ms(5);
- }
- }
- }
- if(key_s4 == 0)// 实时检测S3按键是否被按下
- {
- Delay_Ms(5);//软件消抖
- if(key_s4 == 0)//再检测S3是否被按下
- {
- while(!key_s4);//松手检测
- beep = 0; //使能有源蜂鸣器
- Delay_Ms(1000);//200毫秒延时
- beep = 1; //关闭有源蜂鸣器
- TMOD |= 0x02;//8位自动重装模块
- TH0 = 220;
- TL0 = 220;//11.0592M晶振下占空比最大比值是256,输出100HZ
- TR0 = 1;//启动定时器0
- ET0 = 1;//允许定时器0中断
- EA = 1;//总中断允许
-
- while(1)
- {
- we = 1;//打开位选
- P0 = 0xfe;//,注意数码管的排序,P0.0对应连接的是左边第一位数码管
- we = 0; //关闭位选
- du = 1; //打开段选
- P0 = leddata[b];
- du = 0; //关闭段选
- Delay_Ms(1);
-
- we = 1;//打开位选
- P0 = 0xfd;//,注意数码管的排序,P0.0对应连接的是左边第一位数码管
- we = 0; //关闭位选
- du = 1; //打开段选
- P0 = leddata[i];
- du = 0; //关闭段选
- Delay_Ms(1);
-
- if(left_led2 == 1 && right_led2 == 1)//为0 识别障碍物 为1没有识别到障碍物
- { stop();
- }
-
- if(left_led2 == 0 && right_led2 == 0)//左右识别到障碍物,前进跟随
- {
- forward();
- for(c=0;c<=27000;c++)
- {
- if(c==27000)
- { j++;
- a++;}
- }
- }
- if(left_led2 == 1 && right_led2 == 0)//小车右侧识别到障碍物,右转跟随
- {
- right();
- for(c=0;c<=27000;c++)
- {
- if(c==27000)
- { j++;
- a++;}
- }
- }
-
- if(left_led2 == 0 && right_led2 == 1)//小车左侧识别到障碍物,左转跟随
- {
- left();
- for(c=0;c<=27000;c++)
- {
- if(c==27000)
- { j++;
- a++;}
- }
- }
-
- if(j==10) //当数值为10时,清零
- {
- j=0;
- b++;
- }
- if(b==9)
- { b=0;}
- if(a==90)
- {
- a=0;
- j=0;
- b=0;
- }
- }
- }
- }
- }
- break;
- }
- }
复制代码
所有资料51hei提供下载:
程序.rar
(35.83 KB, 下载次数: 16)
|