本帖最后由 wang200812110 于 2013-6-5 21:08 编辑
介绍了一种基于8位
单片机STC12C5A60S2的迷宫小车系统,充分利用该芯片自带的两路PWM结合L298N芯片控制小车的运行状态;该系统采用五路红外传感器来自动检测路况,将测得信息反馈给小车控制
电路,通过软件对其行进路线进行智能调节,实现了小车自动从事先所设定的迷宫中走出;测距采用以霍尔传感器为核心的电路模块实现测距功能。采用光电对管TCR5000来检测终点位置信息,控制小车停止。同时,采用LCD12864来显示迷宫小车的距离及行走的时间。本设计结构简单,较容易实现,具有一定的智能化。
总体规划
对于走迷宫小车控制系统设计主要有三个方面:一、控制电路设计;二、传感器选择以及安放位置设计;三、程序设计。从总的方面来考虑,传感器的使用数量应该尽量少以减少单片机的信号处理量,但是又必须能使小车行驶自如。控制电路要根据选用的电机和传感器来设计,主要考虑稳定性,抗干扰性。
该迷宫小车主要可以实现的功能如下:
(1)小车基本控制:能够实现在非迷宫场地内完成直行的前进、急停,以及原地转弯和行进转弯等基本的运动方式,并能通过检测和中断电路来进行计步;
(2)红外线探测:通过红外线的探测,反馈5个信息,前方/左方近/左方远/右方近/右方远,通过调节每一个红外线发射接受器的发射和反馈的强度来使小车能最好工作;
(3)小车调试与实际运行:将程序下载到小车内,能够在迷宫(没有孤岛)中自动避障,并进行寻路,实现出迷宫的功能;能够实现遇到黑线自动停止功能。
(4)显示行驶的总时间,距离及运行时的状态,要求整个系统功耗低,性价比高。
附录.1 部分程序片段
程序1:PWM及电机模块子程序
#include
#include "delay.h"
***it R_motor3 = P4^4; //右侧电机IN1输入口 对应OUT1,注:P4SW= 0x30;设置为普通IO口
***it R_motor4 = P1^7; //右侧电机IN2输入口 对应OUT2
***it L_motor1 = P1^6; //左侧电机IN3输入口 对应OUT3
***it L_motor2 = P1^5; //左侧电机IN4输入口 对应OUT4
uchar pro_left,pro_right; //左右电机占空比数
#define pro_left 0x13 //初始PWM0占空比数
#define pro_right 0x0e //初始PWM1占空比数
extern void Pwm_Init(void) //PWM 初始化函数
{
CCON = 0;
CL = 0;
CH = 0;
CMOD = 0x00; //设置PWM时钟频率为 System频率
CCAP0L = pro_left;
CCAP0H = pro_left; //PWM0 占空比数
//0xff为0% 0x80为50%0x00为100%
CCAP1H = pro_right;
CCAP1L = pro_right; //PWM1 占空比数
CCAPM0 = CCAPM1 =0x42;//PWM0,1工作在8位无中断模式下
CR = 1; //PWM计数启动位
}
/*
* 函 数 名:Set_PWM
* 功能描述:设置PWM占空比
* 输入参数:duty:占空比0~100
*/
extern void Set_PWM(uchar duty0, uchar duty1) //PWM占空比控制函数
{
uint temp0,temp1;
if(duty0 == 0) //PWM固定输出低 占空比为0%
{
PCA_PWM0= 0x03;
temp0 = 0xff;
}
else if(duty0 == 100) //PWM固定输出高 占空比为100%
{
PCA_PWM0= 0x00;
temp0 = 0x00;
}
else
{
PCA_PWM0 =0x00;
temp0 = 256 -256*duty0/100;
}
CCAP0L = temp0;
CCAP0H = temp0;
if(duty1 == 0) //PWM固定输出低 占空比为0%
{
PCA_PWM1= 0x03;
temp1 = 0xff;
}
else if(duty1 == 100)//PWM固定输出高 占空比为100%
{
PCA_PWM1= 0x00;
temp1 = 0x00;
}
else
{
PCA_PWM1 =0x00;
temp1 = 256 -256*duty1/100;
}
CCAP1L = temp1;
CCAP1H = temp1;
}
/**************************
in1接R_motor1,in2接R_motor2
in3接L_motor3,in4接L_motor4
**************************/
extern void move_forward(void) //小车前进
{
L_motor1=1;
L_motor2=0;
R_motor3=1;
R_motor4=0;
//Set_PWM(83,84);
}
extern void move_youback(void) //小车180度调头
{
L_motor1=1;
L_motor2=0;
R_motor3=0;
R_motor4=1;
Set_PWM(100,100);
}
extern void move_zuoback(void) //小车180度调头
{
L_motor1=0;
L_motor2=1;
R_motor3=1;
R_motor4=0;
Set_PWM(100,100);
}
extern void move_left(void) //小车左转
{
Set_PWM(100,100);
L_motor1=0;
L_motor2=0;
R_motor3=1;
R_motor4=0;
}
extern void move_right(void) //小车右转
{
L_motor1=1;
L_motor2=0;
R_motor3=0;
R_motor4=0;
Set_PWM(100,100);
}
extern void move_stop(void) //小车停止
{
L_motor1=1;
L_motor2=1;
R_motor3=1;
R_motor4=1;
Set_PWM(0,0);
}
程序2:定时器及中断子程序
#include
#include"12864.h"
#include"delay.h"
ucharSqian,Sbai,Sshi,Sge,Sm; //距离转换的千位/百位/十位/个位/小数点一位,单位厘米
uchar miao,fen,shi; //定时器,时、分、秒位
int Scount = -1; //外部中断计数初始为-1
***it led = P3^7; //霍尔测距,指示灯
extern voidtimer0_int0_init(void) //定时器0初始化
{
AUXR = 0x00; //把定时器1设置为12T模式,普通51模式
TMOD=0x01; //设置定时器0工作模式1
TH0=-5000/256; //定时器装初值 5ms模式
TL0=-5000%256;
EA=1; //开总中断
ET0=1; //开定时器0中断
TR0=1; //启动定时器0
EX0 = 1; //外部中断中断允许位。1允许中断;
IT0 = 1; //下降沿触发方式。
}
void int0(void) interrupt 0 //外部中断0处理函数
{
long int Svalue; //行驶的总距离,单位为mm
Scount++; //外部中断计数
led = ~led; //每转半圈,等亮灭一次
if(Scount>0)
{
Svalue = (Scount)*104;//总距离,单位为mm
Sqian = Svalue/10000;//行驶距离千位数,cm
Sbai = Svalue%10000/1000;//行驶距离千位数,cm
Sshi = Svalue%10000%1000/100;//行驶距离千位数,cm
Sge = Svalue%10000%1000%100/10;//行驶距离千位数,cm
Sm = Svalue%10000%1000%100%10;//行驶距离千位数,cm
}
}
void timer0(void)interrupt 1//定时器0中断服务程序
{
uchar count,count1;
TH0=-50000/256;//再次装定时器初值
TL0=-50000%256;
count++; //中断次数累加
count1++;
if(count1==20) //20次50毫秒为1秒
{
write_com(0x90+3); //在12864第三行显示小车距离
Delay_Ms(50);
write_data(0x30+Sqian); //送去液晶显示千位
write_data(0x30+Sbai); //送去液晶显示百位
write_data(0x30+Sshi); //送去液晶显示十位
write_data(0x30+Sge); //送去液晶显示个位
write_data(0x2e); //送去液晶显示小数点
write_data(0x30+Sm); //送去液晶显示小数点第一位
write_sfm(0x10+1,zuozhuan);
write_sfm(0x10+3,youzhuan);
write_sfm(0x10+5,qianxing);
write_sfm(0x10+7,houzhuan);
}
if(count==20) //20次50毫秒为1秒
{
count=0;
miao++;
if(miao==60)//秒加到60则进位分钟
{
fen++;
miao=0;//同时秒数清零
if(fen==60)//分钟加到60则进位小时
{
fen=0;//同时分钟数清零
shi++;
if(shi==24)//分钟加到60则进位小时
{
shi=0;//同时分钟数清零
}
write_sfm(3,shi);//时若变化则重新写入
}
write_sfm(5,fen);//分钟若变化则重新写入
}
write_sfm(7,miao);//分钟若变化则重新写入
}
}
程序3:红外避障检测子程序
#include
#include"delay.h"
#include"pwm_motoer.h"
#include"timer_int.h"
#include"12864.h"
#include"ir_check.h"
#include"option.h"
ucharzuozhuan,youzhuan,qianxing,houzhuan;//遇到路口数分别左转,右转,前行,后转个数
***it Tcr0 = P2^0; //左侧光电开关TCR5000输出端
***it Tcr1 = P2^1; //右侧光电开关TCR5000输出端
***it zuo = P2^7; //左侧红外输出端
***it zuoled = P2^6; //左前侧红外输出端
***it zhong = P2^5; //中间红外输出端
***it youled = P2^4; //右前侧红外输出端
***it you = P2^3; //右侧红外输出端
extern voidIread(void) //红外检测处理函数
{
if((Tcr0==0)||(Tcr1==0)) //下侧光电传感器有一个检测到黑线
{ //则小车停止运行
move_stop();
Set_PWM(0,0);
//关定时器0
write_com(0x80+5);//第一行第六个位置
lcm_w_word("停止");
Delay_Ms(5000);
TR0=0;
}
if((zuo == 0)&&(zhong ==1)&&(you == 0)) //直行道行走情况
{
move_forward();
Set_PWM(83,84); //PWM控制小车直线行走参数
if((zuoled ==1)&&(youled == 0)) //偏右,右侧电机速度转快
{
move_forward();
Set_PWM(83,88);
}
if((zuoled ==0)&&(youled == 1)) //偏左,左侧电机速度转快
{
move_forward();
Set_PWM(88,84);
}
if((zuoled ==0)&&(youled == 0)) //直接行使速度
{
move_forward();
Set_PWM(83,84);
}
write_com(0x80+5);//第一行第六个位置
lcm_w_word("直行");
}
else if((zuo == 1)&&(zhong ==0)&&(you == 0)) //左转路口行走情况
{
move_forward();
Set_PWM(75,76);
if((zuoled ==0)&&(youled == 0))
{
move_left();
zuozhuan++; //左转路口数加1
Delay_Ms(500);
write_com(0x80+5);//第一行第六个位置
lcm_w_word("左转");
}
}
else if((zuo == 1)&&(zhong ==1)&&(you == 0)) //左转及前行路口行走情况
{
move_forward();
Set_PWM(75,76);
if((zuoled == 0))
{
move_left();
zuozhuan++; //左转路口数加1
Delay_Ms(450);
write_com(0x80+5);//第一行第六个位置
lcm_w_word("左转");
move_forward(); //转完之后由于左右两侧都为1,
Set_PWM(80,81); //要在转完之后加个延时100ms让小车前进一段距离在判断
Delay_Ms(200);
}
}
else if((zuo == 0)&&(zhong ==0)&&(you == 1)) //右转路口行走情况
{
move_forward();
Set_PWM(78,79);
if((zuoled ==0)&&(youled == 0))
{
move_right();
Delay_Ms(450);
youzhuan++; //右转路口数加1
write_com(0x80+5);//第一行第六个位置
lcm_w_word("右转");
move_forward(); //转完之后由于左右两侧都为1,
Set_PWM(80,81); //要在转完之后加个延时100ms让小车前进一段距离在判断
Delay_Ms(300);
}
}
else if((zuo == 0)&&(zhong ==1)&&(you == 1)) //右转及前行路口行走情况
{
Set_PWM(80,81);
Delay_Ms(300);
if((zuoled ==0)&&(youled == 0))
{
move_forward();
Set_PWM(83,84);
qianxing++; //前行路口数加1
write_com(0x80+5);//第一行第六个位置
lcm_w_word("直行");
}
}
else if((zuo == 1)&&(zhong ==0)&&(you == 1)) //T字路口行走情况
{
if((zuoled == 0)||(youled== 0))
{
move_zuoback();
Delay_Ms(280);
write_com(0x80+5);//第一行第六个位置
lcm_w_word("左转");
zuozhuan++; //左转路口数加1
move_stop();
Set_PWM(0,0);
Delay_Ms(100);
move_forward(); //转完之后由于左右两侧都为1,
Set_PWM(83,84); //要在转完之后加个延时200ms让小车前进一段距离在判断
Delay_Ms(300);
}
}
else if((zuo == 0)&&(zhong ==0)&&(zuoled == 0)&&(youled == 0)&&zhong == 0) //死胡同路,原地右后转180度迅速转弯
{
move_youback();
Delay_Ms(570);
write_com(0x80+5);//第一行第六个位置
lcm_w_word("后转180");
houzhuan++; //后转路口数加1
move_stop();
Set_PWM(0,0);
Delay_Ms(50);
}
else if((zuo == 1)&&(zhong ==1)&&(you == 1)) //十字路口行走情况
{
if((zuoled == 0)||(youled== 0))
{
move_left();
Delay_Ms(550);
write_com(0x80+5);//第一行第六个位置
lcm_w_word("左转");
zuozhuan++; //左转路口数加1
move_forward(); //转完之后由于左右两侧都为1,
Set_PWM(80,81); //要在转完后延时200ms让小车前进一段距离在判断
Delay_Ms(200);
}
}
else
{
move_forward();
Set_PWM(83,84);
write_com(0x80+5);//第一行第六个位置
lcm_w_word("直行");
}
}
33