HNU小学期创新实践

创新设计报告

题目:搭载STC89C52微控制器的红外遥控小车

设计时间:2023/9/7

摘要:

  • 本设计在STC微控制器中进行红外数据解析,并完成对于步进电机的PWM控制,组成可红外遥控的小车模型实例和实际应用

关键词:

  • STC,红外遥控,步进电机

第一章:设计背景及目的

1.设计背景

​ 遥控小车是童年时的玩伴回忆,通过STC52单片机和红外接收器以及PWM控制模块,我制作了一个比较简易的红外遥控小车,但是功能比较齐全,可以进一步完善。

2.设计目的

​ 通过对该项目的编写和debug,熟悉理解单片机的运行原理,并进一步步熟悉此类电子系统的设计,实现,测试的过程,掌握相关方法和技能。

第二章:设计与实现

1.整体设计

​ C52微控制器通过4个端口输出电机状态,2个端口通过红外接收器接收红外遥控信号,再通过两个5V接口和一个GND接口分别给两个电机完成供电,整体通过四节1.5V干电池供电,实现了如下功能:小车前进、后退、转向,同时在数码管上显示当前电机运行状态:0(停止)、1(前进)、2(后退)、3(左转)、4(右转)。

​ 红外遥控信号由MP3遥控器给出,由C52微控制器进行解码和执行控制。

2.功能设计

​ 键码0x46对应小车前进状态并显示1,键码0x40对应小车停止状态并显示0,键码0x15对应小车后退状态并显示2,键码0x44对应小车左转状态并显示3,键码0x43对应小车右转状态并显示4。

3.代码实现

1.主程序
void main(void) // 主程序入口
{
	bit ExeFlag = 0; // 定义可执行位变量
	EX1 = 1;		 // 同意开启外部中断1
	IT1 = 1;		 // 设定外部中断1为低边缘触发类型
	EA = 1;
	TMOD = 0X01;
	TH0 = 0XFc; // 1ms定时
	TL0 = 0X18;
	TR0 = 1;
	ET0 = 1;
	ShowPort = LedShowData[0]; // 数码管显示数字0
	while (1)				   // 程序主循环
	{
		Delay(); // 延时
	}
}

通过相关寄存器初始化微控制器状态并进入循环等待。

2.红外解码
void IR_IN() interrupt 2 using 0 // 定义INT2外部中断函数
{
	unsigned char j, k, N = 0; // 定义临时接收变量

	EX1 = 0;	   // 关闭外部中断,防止再有信号到达
	delayms(15);   // 延时时间,进行红外消抖
	if (IRIN == 1) // 判断红外信号是否消失
	{
		EX1 = 1; // 外部中断开
		return;	 // 返回
	}

	while (!IRIN) // 等IR变为高电平,跳过9ms的前导低电平信号。
	{
		delayms(1); // 延时等待
	}

	for (j = 0; j < 4; j++) // 采集红外遥控器数据
	{
		for (k = 0; k < 8; k++) // 分次采集8位数据
		{
			while (IRIN) // 等 IR 变为低电平,跳过4.5ms的前导高电平信号。
			{
				delayms(1); // 延时等待
			}

			while (!IRIN) // 等 IR 变为高电平
			{
				delayms(1); // 延时等待
			}

			while (IRIN) // 计算IR高电平时长
			{
				delayms(1);	 // 延时等待
				N++;		 // 计数器加加
				if (N >= 30) // 判断计数器累加值
				{
					EX1 = 1; // 打开外部中断功能
					return;	 // 返回
				}
			}

			IRCOM[j] = IRCOM[j] >> 1; // 进行数据位移操作并自动补零

			if (N >= 8) // 判断数据长度
			{
				IRCOM[j] = IRCOM[j] | 0x80; // 数据最高位补1
			}
			N = 0; // 清零位数计录器
		}
	}

	if (IRCOM[2] != ~IRCOM[3]) // 判断地址码是否相同
	{
		EX1 = 1; // 打开外部中断
		return;	 // 返回
	}

	for (j = 0; j < 10; j++) // 循环进行键码解析
	{
		if (IRCOM[2] == RecvData[j]) // 进行键位对应
		{
			ControlCar(j); // 数码管显示相应数码
		}
	}

	EX1 = 1; // 外部中断开
}

通过NEC红外通信协议格式进行红外信号解码,并搭配LUA数组完成对键码和按键显示的转换关系

uchar code LedShowData[] = {0x03, 0x9F, 0x25, 0x0D, 0x99, 0x49, 0x41, 0x1F, 0x01, 0x19}; 
						// 	0,	1,	2,	3,	4,	5,	6,	7,	8,	9

uchar code RecvData[] = {0x40, 0x46, 0x15, 0x44, 0x43, 0x19, 0x0D, 0x0E, 0x00, 0x0F};
4.电机控制
void ControlCar(unsigned char ConType) // 定义电机控制子程序
{

	stop(); // 调用停止函数

	switch (ConType)
	{
	case 1: // 前进                         
	{
		run(); // 调用前进函数
		ShowPort = LedShowData[1];
		break;
	}
	case 2:						   // 后退                              
	{
		backrun();
		ShowPort = LedShowData[2];
		break;
	}
	case 3:						   // 左转                         
	{
		leftrun();
		ShowPort = LedShowData[3]; 
		break;
	}
	case 4:						   // 右转                             
	{
		rightrun();				   // 调用小车右转函数                          
		ShowPort = LedShowData[4];
		break;					   //
	}
	case 0:						   // 停止                          
	{
		stop();					   // 调用停止函数
		ShowPort = LedShowData[0]; //
		break;					   //
								   // 退出当前选择
	}
	}
}

通过swich跳转表调用相关函数完成电机状态修改

5.电机状态修改函数
void run(void)
{
	push_val_left = 20; // 速度调节变量 0-20。。。0最小,20最大
	push_val_right = 20;
	Left_moto_go;  // 左电机往前走
	Right_moto_go; // 右电机往前走
}
// 停止函数
void stop(void)
{

	Left_moto_Stop;	 // 左电机往前走
	Right_moto_Stop; // 右电机往前走
}
// 后退函数
void backrun(void)
{
	push_val_left = 20; // 速度调节变量 0-20。。。0最小,20最大
	push_val_right = 20;
	Left_moto_back;	 // 左电机往后走
	Right_moto_back; // 右电机往后走
}

// 左转
void leftrun(void)
{
	push_val_left = 20;
	push_val_right = 20;
	Left_moto_back; // 
	Right_moto_go;	// 
}

// 右转
void rightrun(void)
{
	push_val_left = 20;
	push_val_right = 20;
	Left_moto_go; // 左电机往前走
	Right_moto_back;	 // 右电机往后
}
#define Left_moto_go        \
	{                       \
		P1_2 = 1, P1_3 = 0; \
	} // 左电机向前走
#define Left_moto_back      \
	{                       \
		P1_2 = 0, P1_3 = 1; \
	} // 左边电机向后转
#define Left_moto_Stop      \
	{                       \
		P1_2 = 0, P1_3 = 0; \
	} // 左边电机停转
#define Right_moto_go       \
	{                       \
		P1_4 = 1, P1_5 = 0; \
	} // 右边电机向前走
#define Right_moto_back     \
	{                       \
		P1_4 = 0, P1_5 = 1; \
	} // 右边电机向后走
#define Right_moto_Stop     \
	{                       \
		P1_4 = 0, P1_5 = 0; \
	} // 右边电机停转

通过宏定义和函数调用设置电机相关位的电平以控制电机状态

// 定义小车驱动模块输入IO口
sbit L293D_IN1 = P1 ^ 2;
sbit L293D_IN2 = P1 ^ 3;
sbit L293D_IN3 = P1 ^ 4;
sbit L293D_IN4 = P1 ^ 5;
sbit L293D_EN1 = P1 ^ 6;
sbit L293D_EN2 = P1 ^ 7;

为PWM控制模块定义小车IO口,其中P16和P17为使能口,通过跳线帽赋为1。

6.PWM调速模块
/*调节push_val_left的值改变电机转速,占空比            */
void pwm_out_left_moto(void)
{
	if (Left_moto_stop)
	{
		if (pwm_val_left <= push_val_left)
		{
			Left_moto_pwm = 1;
		}
		else
		{
			Left_moto_pwm = 0;
		}
		if (pwm_val_left >= 20)
			pwm_val_left = 0;
	}
	else
	{
		Left_moto_pwm = 0;
	}
}
/******************************************************************/
/*                    右电机调速                                  */
void pwm_out_right_moto(void)
{
	if (Right_moto_stop)
	{
		if (pwm_val_right <= push_val_right)
		{
			Right_moto_pwm = 1;
		}
		else
		{
			Right_moto_pwm = 0;
		}
		if (pwm_val_right >= 20)
			pwm_val_right = 0;
	}
	else
	{
		Right_moto_pwm = 0;
	}
}

通过对pwm_val_left和pwm_val_right分别于push_val_left和push_val_right进行对比完成PWM调速,push_val_left和push_val_right由调整电机状态时给定。

7.定时器更新PWM
void timer0() interrupt 1 using 2
{
	TH0 = 0XFc; // 1Ms定时
	TL0 = 0X18;
	time++;
	pwm_val_left++;
	pwm_val_right++;
	pwm_out_left_moto();
	pwm_out_right_moto();
}

搭配上述的调速函数,完成PWM调速

8.剩余延时函数及宏定义
uchar IRCOM[7];
unsigned char RunFlag = 0; // 定义运行标志位
bit EnableLight = 0;	   // 定义指示灯使能位

/*************状态指示灯定义*************/
sbit S1 = P3 ^ 2; // 定义S1按键端口
sbit S2 = P3 ^ 4; // 定义S2按键端口

/*************红外探头端口定义***********/
sbit M1A = P1 ^ 2; // 定义电机1正向端口
sbit M1B = P1 ^ 3; // 定义电机1反向端口
sbit M2A = P1 ^ 4; // 定义电机2正向端口
sbit M2B = P1 ^ 5; // 定义电机2反向端口

sbit IRIN = P3 ^ 3; // 定义红外接收端口
/*********红外接收端口的定义*************/
#define ShowPort P0 // 定义数码管显示端口

extern void ControlCar(uchar CarType); // 声明小车控制子程序

void delayms(unsigned char x) // 0.14mS延时程序
{
	unsigned char i; // 定义临时变量
	while (x--)		 // 延时时间循环
	{
		for (i = 0; i < 13; i++)
		{
		} // 14mS延时
	}
}

void Delay1ms(unsigned int i)
{
	unsigned char j, k;
	do
	{
		j = 10;
		do
		{
			k = 50;
			do
			{
				_nop_();
			} while (--k);
		} while (--j);
	} while (--i);
}
void Delay() // 定义延时子程序
{
	uint DelayTime = 30000; // 定义延时时间变量
	while (DelayTime--)
		;	// 开始进行延时循环
	return; // 子程序返回
}

P12、P13、P14、P15为电机状态控制IO口。

第三章:总结

​ 本设计的目标是实现一个能实现基本移动的红外遥控小车模型,并最终完成了基本设计目标,由于时间关系,还有很多待完善部分留待以后完成,功能尚不完整。

​ 通过本次创新设计作业,我熟悉了单片机的运行原理,实现了基于单片机完成一个简单的实用项目的制作,进一步加强了相关的设计,调试,测试等基本方法和技能。也在实现过程中熟悉了单片机的用途和应用方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值