基于51单片机和L298N的小车制作(二)

上一篇文章讲了可以利用PWM脉冲来控制电机的转速,  并且占空比越高电机转速越快。 前面说的是利用按键来控制PWM脉冲信号的输出, 但是在实际小车中总不能一直跟着小车跑吧, 那样多没意思。 所以这次我用红外通信(遥控器)来进行对小车的控制。 外部中断0服务函数来对红外信号进行接收, 并且让小车作出相应的处理。 利用定时器T0来控制PWM脉冲信号的形成(即控制小车的转速), 我在利用定时器控制PWM脉冲形成时遇到了一个问题:我原本想的是用两个定时器来控制两个电机的转动, 但是因为优先级的原因一直没有成功, 在这里浪费了很多时间, 最后和其他人的讨论中发现用一个定时器也可以对两个电机进行控制, 让其独立的转动。 到现在 我的小车已经能准确的接收到遥控器接收的指令并按照指令进行相应的运动。 虽然在这个过程中出现了一些小插曲:比如昨天晚上51单片机烧了, 额, 连着开发板一块烧了 (捂脸), 还有实验室有多余的 (哈哈)。

到现在我的小车已经具备基本的功能了, 前进、后退、转弯等, 虽然精度很差(因为程序是自己写的), 但是也可以按照我的意愿跑了。  接下来应该会在这各个小车的基础上做一个寻迹的小车。 什么是在这个小车的基础上呢? 就是这个小车功能不会删除, 在加一个寻迹的功能; 然后可以在红外控制和寻迹之间自由切换; 想玩哪个就玩那个。 


代码如下:


也可以参见:williamgavin在51hei的帖子

/*******************************************
程序名称:红外控制小车程序
功能:可以实现小车的前进、后退、小车左右电机的转速相互独立
	  利用PWM脉冲实现对速度的分级(1级最慢, 10级最快)
单片机型号:STC89C52.    HC6800-ES V2.0
*******************************************/

# include <reg52.h>

// I/O口定义
sbit PWM1 = P2^0;
sbit PWM2 = P2^1;
sbit PWM3 = P2^2;
sbit PWM4 = P2^3;
sbit IRIN = P3^2;

typedef unsigned int u16;
typedef unsigned char u8;

u8 infrared_arr[6];
u16 TIME;			 // 外部中断0中的计时
u16 count0 = 0;			// 定时器T0中的计时
u16 count1 = 0;			// 定时器T1中的计时
u8  flag1 = 0;		// 电机1正反转的标志位
u8  flag2 = 0;		// 电机2正反转的标志位
u8  rank1;			// 电机速度等级, 一共10级
u8  rank2;			// 电机速度等级, 一共10级

//函数声明
void func(u8 choose);
void advance ();
void back();
void turn_left();
void turn_right();
void left_motor_add();
void right_motor_add();
void left_motor_less();
void right_motor_less();
void stop();

// 外部中断0、定时器中断0 初始化
void init0()
{
	EA = 1;		// 开启总中断
	EX0 = 1;	// 允许外部中断0中断
	IT0 = 1;	// 下降沿触发中断
	IRIN = 1;	// 初始化红外通信端口

	ET0 = 1;	// 定时器0中断
	TH0 = (65536 - 10) / 256;		// 赋初值, 10us
	TL0 = (65536 - 10) % 256;
	TMOD = 0x01;	// 选择方式一
	TR0 = 1;		// 打开定时器中断0

}
// i = 1时, 大概延时10us
void delay(u16 i)
{
	while (i--);
}

int main (void)
{
	init0();
	while (1);
	return 0;
}

// 这个中断服务函数功能是接收红外数据, 选择执行的功能。
void outer0_inter() interrupt 0
{	
	u16	err;
	u8 	j, k;
	TIME = 0;
	delay(700);		// 延迟7ms	 起始码有9ms的低电平
	if (IRIN == 0)	// 确定接收到的是真的信号
	{
		err = 1000; 
		while ((err > 0) && (IRIN == 0))
		{
			// 起始码前面的低电平信号已经过去;
			delay(1);
			err -- ;
		}
		if (1 == IRIN)
		{
			// 高电平信号4.5ms的到来
			err = 500;
			while ((err > 0) && (1 == IRIN))
			{
				// 起始码完全过去
				delay(1);
				err -- ;
			}
			for (j = 0; j < 4; j++)
			{
				for (k = 0; k < 8; k++)
				{
				// 因为无论是'0', 还是 '1', 前面都有0.56ms的低电平。 
				// 所以只有当这0.56ms的低电平过去之后才好判断是'0' or '1'
					err = 60; 
					while ((0 == IRIN) && (err > 0))
					{
						delay (1); 	
						err -- ; 
					}
					// 检测高电平的时间长短, 用TIME变量存储
					err = 50;
					while ((1 == IRIN) && (err > 0))
					{
						delay (10); 	// 0.1ms,  '0' :高电平时间为0.565ms; '1' : 高电平时间为1.69ms
						TIME ++;
						err -- ;
					
						if (TIME > 30)  	// 说明不是要接收的信号
						{
							return ;
						}
					}		
					infrared_arr[j] >>= 1;
					if (TIME >= 8)  		// 将大于0.8ms的定义为 '1'
					{
						infrared_arr[j] |= 0x80;
					}
					TIME = 0;	
				}
			}
		}
		if (infrared_arr[2] != ~infrared_arr[3])
		{
			return ;
		}
		func(infrared_arr[2]);	 // 选择小车的功能
	}
}
void func(u8 choose)
{
	switch(choose)
		{
		case 0x18:			// 前进
			advance();
			break;
		case 0x52:			// 后退
			back();
			break;
		case 0x08:			//左转
			turn_left();
			break;
		case 0x5a:			//右转
			turn_right();
			break;
		case 0x0c: 			// 左边电机加速转动
			left_motor_add();
			break;
		case 0x42:			  // 左边电机减速转动
			left_motor_less();
			break;
		case 0x5e:				// 右边电机加速转动			  	
			right_motor_add();
			break;
		case 0x4a:				// 右边电机减速转动
			right_motor_less();
			break;
		case 0x1c:				// 小车停止
			stop();	
			break;
		}	
}

void T0_inter() interrupt 1
{
	TR0 = 0;
	TH0 = (65536 - 10)/256;
	TL0 = (65536 - 10)%256;
	TR0 = 1;

	count0 ++;
	if (count0 >= 100)
	{
		count0 = 0;
	}
	if (count0 < (rank1 * 10))
	{
		if (flag1 == 0)
		{
			PWM1 = 1;
			PWM2 = 0;
		}
		else
		{
			PWM1 = 0;
			PWM2 = 1;
		}
	}	
	else
	{
		PWM1 = 1;
		PWM2 = 1;
	}
	if (count0 < (rank2 * 10))
	{
		if (flag2 == 0)
		{
			PWM3 = 1;
			PWM4 = 0;
		}
		else
		{
			PWM3 = 0;
			PWM4 = 1;
		}
	}
	else
	{
		PWM3 = 1;
		PWM4 = 1;
	}
}

// 小车前进函数, 速率为最大值的一半
void advance()
{
	rank1 = 5;
	rank2 = 5;
	flag1 = 1;
	flag2 = 1;			
}
// 小车后退函数, 速率为最大值的一半
void back()
{
	rank1 = 5;
	rank2 = 5;
	flag1 = 0;
	flag2 = 0;	
}
// 小车左急转弯函数, 左边电机正转, 右边电机反转
void turn_left()
{
	flag1 = 1;
	flag2 = 0;
}
// 小车右急转弯函数, 右边电机正转, 左边电机反转
void turn_right()
{			
	flag1 = 0;
	flag2 = 1;
}
// 右边电机加速
void right_motor_add()
{	
	if (rank1 == 10)
	{
		rank1 = 5;
	} 
	rank1++;	 
}
// 右边电机加速
void right_motor_less()
{  
	if (rank1 == 0)
	{
		rank1 = 5;
	}
	rank1--;
}
// 左边电机加速
void left_motor_add()
{
	if (rank2 == 10)
	{
		rank2 = 5;
	}
	rank2++;	 
}
// 左边电机减速
void left_motor_less()
{	
	if (rank2 == 0)
	{
		rank2 = 5;
	}
	rank2--;	
}
// 小车停止函数
void stop()
{
	rank1 = 0;
	rank2 = 0;
}


  • 22
    点赞
  • 175
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值