|
该设计是在单片机小车为基础开发的循迹系统。小车由L298N电机驱动模块、红外循迹模块,由STC89C52RC控制芯片完成各模块之间的连接与控制。按键能传送相应命令,对小车移动进行灵活巧妙的控制。当系统启动后,通过按键来选择红外循迹的图形从而改变小车的移动方向。在自动模式下,能沿着红外循迹到地面黑线运动,能躲避障碍物。具体设计模块图如图1-1所示。
制作出来的实物图如下:
电路原理图如下:
4.1 主程序设计
在软件设计中,采用了PWM 调速、信息融合技术等,编写程序时使用了C/C++语言,实现相同功能时只需要更简单的语句,循迹模块主程序为判断语句,判断光电开关的状态,如果其中一个光电传感器未接收到反射信号(黑线或障碍物吸收了红外光线),单片机使用PWM 算法调控,通过控制电流在一个周期中的占空比,立刻调整左右轮差速实现方向调控,实现转弯循迹,如果两个光电传感器同时未接收到反射信号,单片机输出电平停止直流电机的运转,实现避障停车。通过调用各个子函数实现智能小车的功能,经实践检测程序的整体可读性较好,方便移植。
4.2 电机驱动程序
本设计采用 L298N电机驱动模块。由L298N模块各个端口的逻辑关系可知,当 ENA与ENB为 1 时,通过控制 IN1、IN2、IN3、IN4 端口电平的高低来改变电机的转向。电机方向控制逻辑表如表3-1。同时单片机还可以产生PWM波,通过调节占空比的方式来控制电机的转速。
4.3 红外循迹程序
初始化结束后,接收到循迹指令,小车前方有一对红外对管,分别置于黑线两侧,红外管相对于黑线有 2mm到 4mm的距离。当两对红外管都能探测到黑线时,汽车就会一直向前行驶。当左侧传感器无法检测到黑线时,左侧电机向前旋转,右侧电机向后旋转,利用差速原理实现车辆的向右转向,直到检测到左侧的黑线后,小车继续沿直线行驶。同样,当无法在右侧检测到黑线时,右电机向左旋转,左电机向右旋转,实现车辆的向左转向,直到在右侧检测到黑线,小车继续直线行驶。循迹流程如图3-1所示。
4.4 按键扫描程序
只要使用单片机,按键检测基本上是一定要实现的功能。按键检测要好用,最重要的是实时和去抖。初学者往往会在主循环调用按键检测程序(实时)并利用延时去抖(准确)。这种在主循环内延时的做法对整个程序非常不友好,也非常不高效。因此我们将其做成一个按键检测的模块化程序,方便调用和调试
单片机源程序如下:- #include <REGX52.H>
- #include "LCD1602.h"
- #include "Delay.h"
- #include "Timer0.h"
- #include "CCDR.h"
- #include "Key.h"
- sbit MotorA=P1^4;
- sbit MotorB=P1^5;
- sbit A01=P1^0;
- sbit A02=P1^1;
- sbit B01=P1^2;
- sbit B02=P1^3;
- unsigned char Sr=1;////半径(无限制)
- unsigned char Rr=10;////半径(1~80)
- unsigned char Counter,CompareA,CompareB; //计数值和比较值,用于输出PWM
- unsigned char KeyNum,m,
- SpeedA=13,
- SpeedB=10;
- void cwA(int a)///正
- {
- A01=0;
- A02=1;
- CompareA=a;
- }
- void ccwA(int a)///反
- {
- A01=1;
- A02=0;
- CompareA=a;
- }
-
- void cwB(int b)///反
- {
- B01=1;
- B02=0;
- CompareB=b;
- }
- void ccwB(int b)///正
- {
- B01=0;
- B02=1;
- CompareB=b;
- }
- void qian(void)
- {
- cwA(SpeedA);
- cwB(SpeedB);
- }
- void hou (void)
- {
- ccwA(SpeedA);
- ccwB(SpeedB);
- }
- void you(void)
- {
- cwA(SpeedA);
- ccwB(SpeedB);
- }
- void zuo(void)
- {
- ccwA(SpeedA);
- cwB(SpeedB);
- }
- void square()
- {
- qian();
- time(Sr);
- zuo();
- Delay(600);
- }
- void round()
- {
- cwA(SpeedA);
- cwB(SpeedB+Rr);
- }
- void main()
- {
- Timer0_Init();
- // LCD_Init(); //LCD初始化
- // LCD_ShowChar(1,1,'A'); //在1行1列显示字符A
- // LCD_ShowString(1,3,"Hello"); //在1行3列显示字符串Hello
- // LCD_ShowNum(1,9,66,2); //在1行9列显示数字66,长度为2
- // LCD_ShowSignedNum(1,12,-88,2); //在1行12列显示有符号数字-88,长度为2
- // LCD_ShowHexNum(2,1,0xA5,2); //在2行1列显示十六进制数字0xA5,长度为2
- // LCD_ShowBinNum(2,4,0xA5,8); //在2行4列显示二进制数字0xA5,长度为8
- // LCD_ShowChar(2,13,0xDF); //在2行13列显示编码为0xDF的字符
- // LCD_ShowChar(2,14,'C'); //在2行14列显示字符C
- while(1)
- {
- KeyNum=Key();
- if(KeyNum==1)
- {
- m=0;
- }
- if(KeyNum==2)
- {
- m=1;
- }
- if(m==1)
- {
- // LCD_ShowString(1,3,"square"); //在1行1列显示字符A
- square();
- }
- if(m==0)
- {
- // LCD_ShowString(1,3,"round"); //在1行1列显示字符A
- round();
- }
- }
- }
- void Timer0_Routine() interrupt 1
- {
- TL0 = 0x9C; //设置定时初值
- TH0 = 0xFF; //设置定时初值
- Counter++;
- Counter%=100; //计数值变化范围限制在0~99
- if(Counter<CompareA) //计数值小于比较值
- {
- MotorA=1; //输出1
- }
- else //计数值大于比较值
- {
- MotorA=0; //输出0
- }
- if(Counter<CompareB) //计数值小于比较值
- {
- MotorB=1; //输出1
- }
- else //计数值大于比较值
- {
- MotorB=0; //输出0
- }
- }
复制代码 原理图PCB: 无
仿真: 无
代码:
51单片机电子绘图小车.7z
(1.57 MB, 下载次数: 16)
|
-
-
视频.7z
5.85 MB, 下载次数: 4, 下载积分: 黑币 -5
评分
-
查看全部评分
|