单片机智能小车
项目完整效果:
自制超强功能单片机智能小车
mc6c遥控器控制
/*
I/O -> P3^2(INT0)
*/
#include<reg52.h>
#include<intrins.h>
#define SIGNAL_THRESHOLD 1382 //1382
#define ERROR_RANGE 10 //184
sbit signal=P3^2;
sbit IN1=P1^0;
sbit IN2=P1^1;
sbit IN3=P1^2;
sbit IN4=P1^3;
unsigned int signal_time;
void init_Timer0(void);
void Timer0_process(void);
void init_Interrupt0(void);
void Interrupt0_process(void);
void forward(void);
void backward(void);
void stop(void);
void main(void)
{
init_Timer0();
init_Interrupt0();
while(1)
{
if(signal==0)
TR0=1;
if((signal_time<SIGNAL_THRESHOLD+ERROR_RANGE)&&(signal_time>SIGNAL_THRESHOLD-ERROR_RANGE))
{
stop();
}
else
{
signal_time>SIGNAL_THRESHOLD+ERROR_RANGE? forward() : backward();
}
}
}
void init_Timer0(void)
{
TMOD=0x09;
TH0=0x00;
TL0=0x00;
ET0=1;
//TR0=1;
}
void init_Interrupt0(void)
{
EA=1;
EX0=1;
IT0=1;// ²»È·¶¨
}
void Timer0_process(void) interrupt 1
{
TH0=0x00;
TL0=0x00;
//TR0=1;
}
void Interrupt0_process(void) interrupt 0
{
signal_time=0;
signal_time|=TH0;
signal_time<<=8;
signal_time|=TL0;
TH0=0x00;
TL0=0x00;
}
void forward(void)
{
IN1=0;
IN2=1;
IN3=0;
IN4=0;
}
void backward(void)
{
IN1=1;
IN2=0;
IN3=0;
IN4=1;
}
void stop(void)
{
IN1=1;
IN2=1;
IN3=1;
IN4=1;
}
红外协议控制
#include<reg52.h>
#include<intrins.h>
sbit IN1=P1^0;
sbit IN2=P1^1;
sbit IN3=P1^2;
sbit IN4=P1^3;
sbit servo_port=P2^7;
#define INITIAL_angle 15
#define BIAS_ANGLE 2
#define LEFT_ANGLE INITIAL_angle-BIAS_ANGLE
#define RIGHT_ANGLE INITIAL_angle+BIAS_ANGLE
unsigned char status_flag;//0x00=forward,0x01=backward,0x02=left,0x03=right,0x04=brake
unsigned char irtime;
bit irpro_ok,ir_ok;
unsigned char IRcode[4],IRdata[33];
void servo(unsigned char t); //5<=t<=25 %200
void delay_servo(unsigned char _100us_count); //error=-0.173611111111us
void delay(void); //error = -0.000000000018us
void backward(void);
void forward(void);
void left(void);
void right(void);
void brake(void);
void TIME0init(void);
void EX0init();
void TIME0_interrupt(void);
void EX0_interrupt(void);
void Ir_work(void);
void Ircodepro(void);
void initial_status_test(void);
void main(void)
{
EX0init();
TIME0init();
initial_status_test();
while(1)
{
if(ir_ok)
{
Ircodepro();
ir_ok=0;
}
if(irpro_ok)
{
Ir_work();
irpro_ok=0;
}
}
}
void initial_status_test(void)
{
servo(INITIAL_angle); //¶æ»ú¹éλ
servo(INITIAL_angle); //¶æ»ú¹éλ
forward();
delay();
delay();
brake();
backward();
delay();
delay();
brake();
}
void TIME0init(void)
{
TMOD=0x02;
TH0=0x00;
TL0=0x00;
ET0=1;
TR0=1;
}
void EX0init()
{
IT0=1;
EX0=1;
EA=1;
}
void TIME0_interrupt(void) interrupt 1 using 1
{
irtime++;
}
void EX0_interrupt(void) interrupt 0
{
static unsigned char i;
static bit startflag;
if(startflag)
{
if(irtime>40&&irtime<60)
i=0;
IRdata[i]=irtime;
irtime=0;
i++;
if(i==33)
{
ir_ok=1;
startflag=0;
}
}
else
{
irtime=0;
startflag=1;
}
}
void Ir_work(void)
{
if (IRcode[0]==0x00&&IRcode[1]==0xFF)
{
switch(IRcode[2])//0x00FF
{
//up
case 0x18:
{
switch (status_flag)
{
case 0x01:brake();forward();break;
case 0x04:forward();break;
default:servo(INITIAL_angle);forward();
}
break;
}
//<-
case 0x08:
{
switch (status_flag)
{
case 0x00:left();forward();break;
case 0x01:left();backward();break;
default:left();
}
break;
}
//OK
case 0x1C:
{
brake();break;
}
//->
case 0x5A:
{
switch (status_flag)
{
case 0x00:right();forward();break;
case 0x01:right();backward();break;
default:right();
}
break;
}
//down
case 0x52:
{
switch (status_flag)
{
case 0x00:brake();backward();break;
case 0x04:backward();break;
default:servo(INITIAL_angle);backward();
}
break;
}
default:break;
}
}
}
void Ircodepro(void)
{
unsigned char i, j, k;
unsigned char cord,value;
k=1;
for(i=0;i<4;i++) //¡ä|¨¤¨ª4??¡Á??¨²
{
for(j=1;j<=8;j++) //¡ä|¨¤¨ª1??¡Á??¨²8??
{
cord=IRdata[k];
if(cord>7)
value|=0x80;
if(j<8)
{
value>>=1;
}
k++;
}
IRcode[i]=value;
value=0;
}
irpro_ok=1;
}
void servo(unsigned char t) //5<=t<=25 %200
{
unsigned char i;
for(i=5;i>0;i--)
{
servo_port=1;
delay_servo(t);
servo_port=0;
delay_servo(200-t);
}
}
//0.1ms
void delay_servo(unsigned char _100us_count) //error=-0.173611111111us
{
unsigned char a,b;
while(_100us_count)
{
for(b=1;b>0;b--)
for(a=43;a>0;a--);
_100us_count--;
}
}
//80ms
void delay(void) //error = -0.000000000018us
{
unsigned char a,b,c;
for(c=75;c>0;c--)
for(b=196;b>0;b--)
for(a=1;a>0;a--);
}
void forward(void)
{
status_flag=0x00;
IN1=1;
IN2=0;
IN3=0;
IN4=1;
//delay();
}
void backward(void)
{
status_flag=0x01;
IN1=0;
IN2=1;
IN3=1;
IN4=0;
//delay();
}
void left(void)
{
status_flag=0x02;
servo(LEFT_ANGLE);
}
void right(void)
{
status_flag=0x03;
servo(RIGHT_ANGLE);
}
void brake(void)
{
status_flag=0x04;
IN1=1;//control
IN2=1;
IN3=1;
IN4=1;
//delay();
}
蓝牙协议控制
蓝牙串口助手app下载:我的Github主页
#include<reg52.h>
#include<intrins.h>
sbit IN1=P1^0;
sbit IN2=P1^1;
sbit IN3=P1^2;
sbit IN4=P1^3;
sbit servo_port=P2^7;
#define INITIAL_angle 15
#define BIAS_ANGLE 2
#define LEFT_ANGLE INITIAL_angle-BIAS_ANGLE
#define RIGHT_ANGLE INITIAL_angle+BIAS_ANGLE
unsigned char status_flag;//0x00=forward,0x01=backward,0x02=left,0x03=right,0x04=brake
unsigned char irtime;
bit irpro_ok,ir_ok;
unsigned char IRcode[4],IRdata[33];
void servo(unsigned char t); //5<=t<=25 %200
void delay_servo(unsigned char _100us_count); //error=-0.173611111111us
void delay(void); //error = -0.000000000018us
void backward(void);
void forward(void);
void left(void);
void right(void);
void brake(void);
void TIME0init(void);
void EX0init();
void TIME0_interrupt(void);
void EX0_interrupt(void);
void Ir_work(void);
void Ircodepro(void);
void initial_status_test(void);
void main(void)
{
EX0init();
TIME0init();
initial_status_test();
while(1)
{
if(ir_ok)
{
Ircodepro();
ir_ok=0;
}
if(irpro_ok)
{
Ir_work();
irpro_ok=0;
}
}
}
void initial_status_test(void)
{
servo(INITIAL_angle); //???ú1é??
servo(INITIAL_angle); //???ú1é??
forward();
delay();
delay();
brake();
backward();
delay();
delay();
brake();
}
void TIME0init(void)
{
TMOD=0x02;
TH0=0x00;
TL0=0x00;
ET0=1;
TR0=1;
}
void EX0init()
{
IT0=1;
EX0=1;
EA=1;
}
void TIME0_interrupt(void) interrupt 1 using 1
{
irtime++;
}
void EX0_interrupt(void) interrupt 0
{
static unsigned char i;
static bit startflag;
if(startflag)
{
if(irtime>40&&irtime<60)
i=0;
IRdata[i]=irtime;
irtime=0;
i++;
if(i==33)
{
ir_ok=1;
startflag=0;
}
}
else
{
irtime=0;
startflag=1;
}
}
void Ir_work(void)
{
if (IRcode[0]==0x00&&IRcode[1]==0xFF)
{
switch(IRcode[2])//0x00FF
{
//up
case 0x18:
{
switch (status_flag)
{
case 0x01:brake();forward();break;
case 0x04:forward();break;
default:servo(INITIAL_angle);forward();
}
break;
}
//<-
case 0x08:
{
switch (status_flag)
{
case 0x00:left();forward();break;
case 0x01:left();backward();break;
default:left();
}
break;
}
//OK
case 0x1C:
{
brake();break;
}
//->
case 0x5A:
{
switch (status_flag)
{
case 0x00:right();forward();break;
case 0x01:right();backward();break;
default:right();
}
break;
}
//down
case 0x52:
{
switch (status_flag)
{
case 0x00:brake();backward();break;
case 0x04:backward();break;
default:servo(INITIAL_angle);backward();
}
break;
}
default:break;
}
}
}
void Ircodepro(void)
{
unsigned char i, j, k;
unsigned char cord,value;
k=1;
for(i=0;i<4;i++) //??|¨¤¨a4???á??¨2
{
for(j=1;j<=8;j++) //??|¨¤¨a1???á??¨28??
{
cord=IRdata[k];
if(cord>7)
value|=0x80;
if(j<8)
{
value>>=1;
}
k++;
}
IRcode[i]=value;
value=0;
}
irpro_ok=1;
}
void servo(unsigned char t) //5<=t<=25 %200
{
unsigned char i;
for(i=5;i>0;i--)
{
servo_port=1;
delay_servo(t);
servo_port=0;
delay_servo(200-t);
}
}
//0.1ms
void delay_servo(unsigned char _100us_count) //error=-0.173611111111us
{
unsigned char a,b;
while(_100us_count)
{
for(b=1;b>0;b--)
for(a=43;a>0;a--);
_100us_count--;
}
}
//80ms
void delay(void) //error = -0.000000000018us
{
unsigned char a,b,c;
for(c=75;c>0;c--)
for(b=196;b>0;b--)
for(a=1;a>0;a--);
}
void forward(void)
{
status_flag=0x00;
IN1=1;
IN2=0;
IN3=0;
IN4=1;
//delay();
}
void backward(void)
{
status_flag=0x01;
IN1=0;
IN2=1;
IN3=1;
IN4=0;
//delay();
}
void left(void)
{
status_flag=0x02;
servo(LEFT_ANGLE);
}
void right(void)
{
status_flag=0x03;
servo(RIGHT_ANGLE);
}
void brake(void)
{
status_flag=0x04;
IN1=1;//control
IN2=1;
IN3=1;
IN4=1;
//delay();
}
超声波测距自动避障行驶
//INT0->P3.2<-ECHO TRIG->P1.4
#include<reg52.h>
#include <intrins.h>
#define STRAIGHT_DISTANCE_SETTING 30 //正前方测距的临界距离
#define ROUND_DISTANCE_SETTING 15 //左右方测距的临界距离
#define INITIAL_angle 14 //舵机初始位置
#define BIAS_ANGLE 5 //舵机左右偏置
#define LEFT_ANGLE INITIAL_angle+BIAS_ANGLE
#define RIGHT_ANGLE INITIAL_angle-BIAS_ANGLE
sbit servo_port=P2^7; //舵机IO口
sbit ECHO=P3^2; //接超声波输出信号
sbit TRIG=P1^4; //超声波触发信号
sbit IN1=P1^0; //motor A ->Right
sbit IN2=P1^1;
sbit IN3=P1^2; //motor B ->Left
sbit IN4=P1^3;
unsigned char time_H,time_L;
int distance,time,left_distance,right_distance;
void delay(void);
void forward(void);
void backward(void);
void left(void);
void right(void);
void brake(void);
void compute_distance(void);
void DELAY100ms(void);
void DELAY15us(void);
void detect_distance(void);
void initTIMER0(void);
void servo(unsigned char t);
void delay_servo(unsigned char _100us_count);
void detect_left_distance(void);
void detect_right_distance(void);
void main(void)
{
initTIMER0();
servo(INITIAL_angle); //舵机归位
while(1)
{
detect_distance();
while(distance < STRAIGHT_DISTANCE_SETTING)
{
brake();
backward();
brake();
detect_left_distance(); //舵机左方测距
left_distance=distance;
detect_right_distance(); //舵机右方测距
right_distance=distance;
servo(INITIAL_angle); //舵机归位
if((left_distance>ROUND_DISTANCE_SETTING)||(right_distance>ROUND_DISTANCE_SETTING))
{
left_distance>right_distance? left() : right();
}
else
{
backward();
brake();
brake();
left();
}
detect_distance();
}
forward();
}
}
void servo(unsigned char t) //5<=t<=25 %200
{
unsigned char i;
for(i=25;i>0;i--)
{
servo_port=1;
delay_servo(t);
servo_port=0;
delay_servo(200-t);
}
}
//0.1ms
void delay_servo(unsigned char _100us_count) //error=-0.173611111111us
{
unsigned char a,b;
while(_100us_count)
{
for(b=1;b>0;b--)
for(a=89;a>0;a--);
_100us_count--;
}
}
void detect_distance(void) //(cm)
{
EX0=1;
TR0=1;
TRIG=1;
DELAY15us();
TRIG=0;
DELAY100ms();
EX0=0;
compute_distance();
}
void detect_left_distance(void) //(cm)
{
servo(LEFT_ANGLE);
EX0=1;
TR0=1;
TRIG=1;
DELAY15us();
TRIG=0;
servo(LEFT_ANGLE);
servo(LEFT_ANGLE);
EX0=0;
compute_distance();
}
void detect_right_distance(void) //(cm)
{
servo(RIGHT_ANGLE);
EX0=1;
TR0=1;
TRIG=1;
DELAY15us();
TRIG=0;
servo(RIGHT_ANGLE);
servo(RIGHT_ANGLE);
EX0=0;
compute_distance();
}
void INTER0_process(void) interrupt 0
{
TR0=0;
time_H=TH0;
time_L=TL0;
TH0=0;
TL0=0;
}
void initTIMER0(void)
{
TMOD=0x09;
TH0=0x00;
TL0=0x00;
EA=1;
IT0=1;
}
void DELAY15us(void) //误差 0us
{
unsigned char d;
for(d=12;d>0;d--);
}
void DELAY100ms(void)
{
unsigned char a,b,c;
for(c=131;c>0;c--)
for(b=156;b>0;b--)
for(a=3;a>0;a--);
}
void compute_distance(void)
{
time=0;
time|=time_H;
time<<=8;
time|=time_L;
distance=time*0.0093;
}
//40ms
void delay(void) //误差 -0.000000000009us
{
unsigned char a,b,c;
for(c=75;c>0;c--)
for(b=196;b>0;b--)
for(a=1;a>0;a--);
}
void forward(void) //前进
{
IN1=1;//control
IN2=0;
IN3=1;
IN4=0;
delay();
}
void backward(void) //后退
{
IN1=0;//control
IN2=1;
IN3=0;
IN4=1;
delay();
delay();
delay();
delay();
}
void left(void) //左转
{
IN1=1;//control
IN2=0;
IN3=0;
IN4=1;
delay();
delay();
delay();
brake();
}
void right(void) //右转
{
IN1=0;//control
IN2=1;
IN3=1;
IN4=0;
delay();
delay();
delay();
brake();
}
void brake(void) //制动
{
IN1=1;//control
IN2=1;
IN3=1;
IN4=1;
delay();
delay();
delay();
}
蓝牙协议控制小车机械臂
/************************************************************
servo1 右 40-120 right
servo2 左 0-50 left
servo3 底座 0-180 bottom
servo4 上爪 100-125 up
************************************************************/
#include<reg52.h>
#include <intrins.h>
#include <stdio.h>
#include <math.h>
typedef unsigned char uchar;
typedef unsigned int uint;
sbit scl=P3^6; //时钟输入线
sbit sda=P3^7; //数据输入/输出端
#define PCA9685_adrr 0x80// 1+A5+A4+A3+A2+A1+A0+w/r
#define PCA9685_SUBADR1 0x2
#define PCA9685_SUBADR2 0x3
#define PCA9685_SUBADR3 0x4
#define PCA9685_MODE1 0x00
#define PCA9685_PRESCALE 0xFE
#define LED0_ON_L 0x06
#define LED0_ON_H 0x07
#define LED0_OFF_L 0x08
#define LED0_OFF_H 0x09
#define ALLLED_ON_L 0xFA
#define ALLLED_ON_H 0xFB
#define ALLLED_OFF_L 0xFC
#define ALLLED_OFF_H 0xFD
unsigned char remote_command[7]; //包头(0xA5)+原数据+校验和(1B)+包尾(0x5A)
unsigned char data_index=0;
bit command_flag;
void delayms(uint z);
void delayus();
void init();
void start();
void stop();
void ACK();
void write_byte(uchar byte);
uchar PCA9685_read(uchar address);
uchar read_byte();
void PCA9685_write(uchar address,uchar date);
void reset(void) ;
void setPWMFreq(float freq);
void servo_control(uchar num, uchar angle);
void command_process(void);
void init_bluetooth_timer0(void);
void bluetooth_interrupt_process(void);
void begin(void);
void servo_angle(void);
uchar servo1=90;
uchar servo2=90;
uchar servo3=90;
uchar servo4=90;
/*---------------------------------------------------------------
主函数
----------------------------------------------------------------*/
void main()
{
init();
begin();
setPWMFreq(50);
init_bluetooth_timer0();
servo_angle();
while(1)
{
if(command_flag)
{
command_process();
servo_angle();
}
}
}
void servo_angle(void)
{
servo_control(0,servo1);
delayms(2);
servo_control(1,servo2);
delayms(2);
servo_control(2,servo3);
delayms(2);
servo_control(3,servo4);
}
void command_process(void)
{
if(remote_command[0]==0xA5)
{
servo1=remote_command[1]+90;
servo2=remote_command[2]+90;
servo3=remote_command[3]+90;
servo4=remote_command[4]+90;
}
command_flag=0;
}
void init_bluetooth_timer0(void)
{
TMOD=0x20;
TH1=253;
TL1=TH1;
SCON=0x50;
TR1=1;
EA=1;
ES=1;
}
void bluetooth_interrupt_process(void) interrupt 4
{
if(RI)
{
remote_command[data_index]=SBUF;
data_index++;
if(data_index==7)
{
data_index=0;
command_flag=1;
}
RI=0;
}
}
/**********************函数的声明*********************************/
/*---------------------------------------------------------------
毫秒延时函数
----------------------------------------------------------------*/
void delayms(uint z)
{
unsigned char a,b;
while(z)
{
for(b=102;b>0;b--)
for(a=3;a>0;a--);
z--;
}
}
/*---------------------------------------------------------------
IIC总线所需的通用函数
----------------------------------------------------------------*/
/*---------------------------------------------------------------
微妙级别延时函数 大于4.7us
----------------------------------------------------------------*/
void delayus()
{
_nop_(); //if Keil,require use intrins.h
_nop_(); //if Keil,require use intrins.h
}
/*---------------------------------------------------------------
IIC总线初始化函数
----------------------------------------------------------------*/
void init()
{
sda=1; //sda scl使用前总是被拉高
delayus();
scl=1;
delayus();
}
/*---------------------------------------------------------------
IIC总线启动信号函数
----------------------------------------------------------------*/
void start()
{
sda=1;
delayus();
scl=1; //scl拉高时 sda突然来个低电平 就启动了IIC总线
delayus();
sda=0;
delayus();
scl=0;
delayus();
}
/*---------------------------------------------------------------
IIC总线停止信号函数
----------------------------------------------------------------*/
void stop()
{
sda=0;
delayus();
scl=1; //scl拉高时 sda突然来个高电平 就停止了IIC总线
delayus();
sda=1;
delayus();
}
/*---------------------------------------------------------------
IIC总线应答信号函数
----------------------------------------------------------------*/
void ACK()
{
uint i;
scl=1;
delayus();
while((sda=1)&&(i<255))
i++;
scl=0;
delayus();
}
/*---------------------------------------------------------------
写一个字节,无返回值,需输入一个字节值
----------------------------------------------------------------*/
void write_byte(uchar byte)
{
uchar i,temp;
temp=byte;
for(i=0;i<8;i++)
{
temp=temp<<1;
scl=0;
delayus();
sda=CY;
delayus();
scl=1;
delayus();
}
scl=0;
delayus();
sda=1;
delayus();
}
/*---------------------------------------------------------------
读一个字节函数,有返回值
----------------------------------------------------------------*/
uchar read_byte()
{
uchar i,j,k;
scl=0;
delayus();
sda=1;
delayus();
for(i=0;i<8;i++)
{
delayus();
scl=1;
delayus();
if(sda==1)
{
j=1;
}
else j=0;
k=(k<< 1)|j;
scl=0;
}
delayus();
return k;
}
/*---------------------------------------------------------------
有关PCA9685模块的函数
----------------------------------------------------------------*/
/*---------------------------------------------------------------
向PCA9685里写地址,数据
----------------------------------------------------------------*/
void PCA9685_write(uchar address,uchar date)
{
start();
write_byte(PCA9685_adrr); //PCA9685的片选地址
ACK();
write_byte(address); //写地址控制字节
ACK();
write_byte(date); //写数据
ACK();
stop();
}
/*---------------------------------------------------------------
从PCA9685里的地址值中读数据(有返回值)
----------------------------------------------------------------*/
uchar PCA9685_read(uchar address)
{
uchar date;
start();
write_byte(PCA9685_adrr); //PCA9685的片选地址
ACK();
write_byte(address);
ACK();
start();
write_byte(PCA9685_adrr|0x01); //地址的第八位控制数据流方向,就是写或读
ACK();
date=read_byte();
stop();
return date;
}
/*---------------------------------------------------------------
PCA9685复位
----------------------------------------------------------------*/
void reset(void)
{
PCA9685_write(PCA9685_MODE1,0x0);
}
void begin(void)
{
reset();
}
/*---------------------------------------------------------------
PCA9685修改频率函数
----------------------------------------------------------------*/
void setPWMFreq(float freq)
{
uint prescale,oldmode,newmode;
float prescaleval;
freq *= 0.92; // Correct for overshoot in the frequency setting
prescaleval = 25000000;
prescaleval /= 4096;
prescaleval /= freq;
prescaleval -= 1;
prescale = floor(prescaleval + 0.5);
oldmode = PCA9685_read(PCA9685_MODE1);
newmode = (oldmode&0x7F) | 0x10; // sleep
PCA9685_write(PCA9685_MODE1, newmode); // go to sleep
PCA9685_write(PCA9685_PRESCALE, prescale); // set the prescaler
PCA9685_write(PCA9685_MODE1, oldmode);
delayms(2);
PCA9685_write(PCA9685_MODE1, oldmode | 0xa1);
}
/*---------------------------------------------------------------
PCA9685修改角度函数
num:舵机PWM输出引脚0~15,on:PWM上升计数值0~4096,off:PWM下降计数值0~4096
一个PWM周期分成4096份,由0开始+1计数,计到on时跳变为高电平,继续计数到off时
跳变为低电平,直到计满4096重新开始。所以当on不等于0时可作延时,当on等于0时,
off/4096的值就是PWM的占空比。
----------------------------------------------------------------*/
void servo_control(uchar num, uchar angle)
{
uint off = 102.4+2.275555556*angle;
PCA9685_write(LED0_ON_L+4*num,0);
PCA9685_write(LED0_ON_H+4*num,0);
PCA9685_write(LED0_OFF_L+4*num,off);
PCA9685_write(LED0_OFF_H+4*num,off>>8);
}