创新设计报告
题目:搭载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口。
第三章:总结
本设计的目标是实现一个能实现基本移动的红外遥控小车模型,并最终完成了基本设计目标,由于时间关系,还有很多待完善部分留待以后完成,功能尚不完整。
通过本次创新设计作业,我熟悉了单片机的运行原理,实现了基于单片机完成一个简单的实用项目的制作,进一步加强了相关的设计,调试,测试等基本方法和技能。也在实现过程中熟悉了单片机的用途和应用方法。