准备工作
1)控制芯片:
因为刚学完51基础课,这里直接用51学习板(STC89C52RC)。
2)车身:
可直接在某宝购买,一般直接配备(亚克力车身、电机、轮胎、固定螺钉)。
3)L298N电机驱动模块:
L298N可驱动模块 电机正反转,可直接向单片机供电(L298N接入12V)。
输出 A/B: 分别接 左/右 电机 (电机接法如上图所示)
通道A/B使能: 拔下帽子就可以了PWM调速电机
逻辑输入: IN1/2 控制 输出A 端 电机的正反转
IN3/4 控制 输出B 端 电机的正反转
电机的正反转 与 电机和输出A/B接线有关,接线后应先调试判断方向是否正确。如果方向不对,电机和输出应该是正确的A/B的接线换序
接线:按上图接线输出A/B 连接电机,逻辑输入接单片机I/O口
4)红外循迹模块
推荐使用TCR5000循环模块(单个循环模块可根据自身实际情况调整扫描位置)
循迹原理:利用红外线对不同颜色有不同的反射特性。传感器的红外发射二极管在汽车行驶过程中不断发射红外光。当红外光遇到白色地面时,会发生漫反射,红外接收管接收反射光;如果遇到黑线,红外光被吸收,红外管无法接收信号。 通过2路循迹传感器模块收集的红外对管信号LM339比较器后输出高或低电平,实现信号检测。
接线:(A0可以不接)D00输出信号接单片机I/O口
注:一些制造商设置红外管无法接收信号 输出高电平,有的厂家设置红外管接收信号 输出低电平。因此,接线后必须进行调试(输出高电平)
5)电源
强烈建议用 12V锂电池以前用过9个V虽然碱性电池的电压是9V但电流严重不足。
所以12可以直接使用V2000ma锂电池左右 可直接驱动L298N而且还可以通过L298N直接给单片机供电,锂电池也可以 重复充电。
功能介绍
根据TCR使用单片机的5000循环模块的工作原理I/O口接收TCR5000循迹模块发出的信号,当单片机I/O接收到低电平/高电时,口表示检测到轨道(黑线),然后给予L298N逻辑输入脚信号,让电机做出相应的动作。
汽车转弯可以通过一侧轮胎转向另一侧,但这样汽车移动角度很大,一般不推荐;另一种方法是通过一侧轮胎转向另一侧,使汽车移动角度更小,甚至在原地转动。
源码(仅供参考)
主函数(使用模块化编程,补充后续头文件)
#include <REGX52.H> #include "trac.h" #include "pwm.h" int main () { Timer0_PWM_Init(); P0=0XFF; while(1) { Trac(); } }
PWM函数
#include <REGX52.H> sbit ENA=P2^0; //ENA使然口 sbit ENB=P2^5; //ENB使然口 unsigned char compare_ENA,compare_ENB;//PWM比较值 unsigned char count_ENA,count_ENB; //PWM计数值 /*********************************************************************************** * @brief 定时器0初始化 * @param * @retval */ void Timer0_PWM_Init(void) //100微秒@11.0592MHz { TMOD &= 0xF0; //设置定时器模式 TMOD |= 0x01; //设置定时器模式 TL0 = 0xA4; ///设定时初值 TH0 = 0xFF; ///设定时初值 TF0 = 0; //清除TF0标志 TR0 = 1; ///定时器0开始计时 ET0=1; EA=1; } /*********************************************************************************** * @brief PWM对比值赋值函数 * @param * @retval */ void PWM_Compare( unsigned char Date1,Date2) { compare_ENA=Date1; compare_ENB=Date2; } /*********************************************************************************** * @brief 定时器0执行函数 * @param * @retval */ void Timer0_PWM_Run(void) interrupt 1 { // TL0 = 0xA4; ///设定时初值 // TH0 = 0xFF; ///设定时初值 TL0 = 0xE9; ///设定时初值 TH0 = 0xFF; ///设定时初值 count_ENA ; count_ENA%=100; //控制范围0~99 if(count_ENA<compare_ENA) { ENA=1; } else if(count_ENA>compare_ENA) { ENA=0; } count_ENB ; count_ENB%=100; //控制范围0~99 if(count_ENB<compare_ENB) { ENB=1; } else if(count_ENB>compare_ENB) { ENB=0; } }
循迹函数
#include <REGX52.H> #include "pwm.h" /*********************************************************************************** * @brief 红外管从左到右返回信号脚 */ sbit IR_1=P0^3; sbit IR_2=P0^4; sbit IR_3=P0^5; sbit IR_4=P0^6; /*********************************************************************************** * @brief L298N信号输出 10正转 01反转 */ sbit IN1=P2^1; sbit IN2=P2^2; sbit IN3=P2^3; sbit IN4=P2^4; /*********************************************************************************** * @brief 控制车轮旋转方向 10正转 01反转 * @param a,b,,c,d * @retval */ void L298N_Init(unsigned char a,b,c,d) { IN1=a; IN2=b; IN3=c; IN4=d; } /*********************************************************************************** * @brief 跟踪模块执行函数 * @param 无 * @retval 无 */ void Trac() { if(IR_1==0 && IR_2==0 && IR_3==1 && IR_4==0) //中间检测到黑线,此时小车位置中间偏右
{
PWM_Compare( 20,20); //左右轮都为20%
L298N_Init(1,0,1,0); //左右轮都正传
}
else if(IR_1==1 && IR_2==0 && IR_3==0 && IR_4==0 ) //最左边检测到黑线
{
PWM_Compare( 30,40); //左轮为30% 右轮为40%
L298N_Init(0,1,1,0); //左轮反传 右轮正转
}
else if(IR_1==0 && IR_2==1 && IR_3==0 && IR_4==0 ) //中间检测到黑线,此时小车位置中间偏左
{
PWM_Compare( 23,23); //左轮为23% 右轮为23%
L298N_Init(1,0,1,0); //左轮正传 右轮正转
}
else if(IR_1==0 && IR_2==0 && IR_3==0 && IR_4==1 ) //最右边检测到黑线
{
PWM_Compare( 40,30); //左轮为40% 右轮为30%
L298N_Init(1,0,0,1); //左轮正传 右轮反转
}
else if(IR_1==0 && IR_2==0 && IR_3==0 && IR_4==0 ) //未检测到黑线
{
PWM_Compare( 0,0);
L298N_Init(0,0,0,0); //轮胎不运动
}
else if(IR_1==1 && IR_2==1 && IR_3==1 && IR_4==1 ) //四路都检测到黑线
{
PWM_Compare( 0,0);
L298N_Init(0,0,0,0); //轮胎不运动
}
else if(IR_1==0 && IR_2==1 && IR_3==1 && IR_4==0 ) //中间两路检测到黑线
{
PWM_Compare( 17,17); //左轮为17% 右轮为17%
L298N_Init(1,0,1,0); //左轮正传 右轮正转
}
}