在学习完51单片机以后,想着做一个小项目,于是便有了这辆51遥控小车,话不多说,先看实物图
遥控器
遥控车
楼主看了很多51小车的帖子,但一直没有找到心仪的,所以楼主便一边摸索一边组装了这辆小车,因为楼主没有焊接的地方,所以这辆车完全靠杜邦线和胶带连接,对新手很友好。
硬件部分
51单片机最小系统板*2
HC05兼容版*2
AMS1117降压模块*2
TBFNG6612电机驱动模块*1
MP2307降压模块*1
7.4V18650电池*1
PDD成品玩具车架*1
以及电池盒及干电池和杜邦线若干,和四个独立按键
软件部分
遥控器端
/*遥控器部分*/
#include <at89c51RC2.h>
#include "UART.H"
// 按键引脚定义
sbit KEY1 = P2^0; // 前进按键
sbit KEY2 = P2^1; // 后退按键
sbit KEY3 = P3^2; // 左转按键
sbit KEY4 = P3^3; // 右转按键
// 用于标记按键是否按下
bit key1_pressed = 0;
bit key2_pressed = 0;
bit key3_pressed = 0;
bit key4_pressed = 0;
// 记录前进状态(是否正在前进)
bit moving_forward = 0;
// 记录后退状态(是否正在后退)
bit moving_backward = 0;
void main()
{
Uart1_Init(); // 初始化串口
IT0 = 1; // 设置 INT0 为下降沿触发
IT1 = 1; // 设置 INT1 为下降沿触发
EX0 = 1; // 启用外部中断 0
EX1 = 1; // 启用外部中断 1
EA = 1; // 启用总中断
while(1)
{
// 处理前进和后退按键
if (KEY1 == 0 && !key1_pressed) { // 前进按键按下
UART_SendChar('F');
key1_pressed = 1; // 标记为按下
moving_forward = 1; // 记录电机正在前进
moving_backward = 0; // 停止后退
} else if (KEY1 == 1 && key1_pressed) { // 前进按键松开
key1_pressed = 0; // 重置标记
if (!key2_pressed) { // 只有当没有后退命令时才停止
UART_SendChar('S');
moving_forward = 0; // 电机停止
}
}
if (KEY2 == 0 && !key2_pressed) { // 后退按键按下
UART_SendChar('B');
key2_pressed = 1; // 标记为按下
moving_forward = 0; // 停止前进
moving_backward = 1; // 记录电机正在后退
} else if (KEY2 == 1 && key2_pressed) { // 后退按键松开
key2_pressed = 0; // 重置标记
if (!key1_pressed) { // 只有当没有前进命令时才停止
UART_SendChar('S');
moving_backward = 0; // 电机停止
}
}
}
}
void INT0_ISR(void) interrupt 0 {
if (KEY3 == 0 && !key3_pressed) { // 左转按键按下
UART_SendChar('L'); // 启动转向
key3_pressed = 1; // 标记为按下
}
while (KEY3 == 0); // 等待按键松开
key3_pressed = 0; // 松开时重置标记
// 如果前进键或后退键还在按下,则继续前进或后退
if (moving_forward) {
UART_SendChar('F'); // 继续前进
} else if (moving_backward) {
UART_SendChar('B'); // 继续后退
} else {
UART_SendChar('S'); // 否则停止电机
}
}
void INT1_ISR(void) interrupt 2 {
if (KEY4 == 0 && !key4_pressed) { // 右转按键按下
UART_SendChar('R'); // 启动转向
key4_pressed = 1; // 标记为按下
}
while (KEY4 == 0); // 等待按键松开
key4_pressed = 0; // 松开时重置标记
// 如果前进键或后退键还在按下,则继续前进或后退
if (moving_forward) {
UART_SendChar('F'); // 继续前进
} else if (moving_backward) {
UART_SendChar('B'); // 继续后退
} else {
UART_SendChar('S'); // 否则停止电机
}
}
遥控车端
/*遥控车*/
#include <at89c51RC2.h>
#include "Timer0.h"
// 电机控制引脚定义
sbit STBY = P2^4; // 待机控制引脚
sbit PWMA = P2^5; // 电机 A 的 PWM 控制引脚
sbit AIN1 = P2^6; // 电机 A 的方向控制引脚 1
sbit AIN2 = P2^7; // 电机 A 的方向控制引脚 2
sbit BIN1 = P1^0; // 电机 B 的方向控制引脚 1
sbit BIN2 = P1^1; // 电机 B 的方向控制引脚 2
sbit PWMB = P1^2; // 电机 B 的 PWM 控制引脚
unsigned char motor1_active = 0; // 电机1是否处于活动状态
void Uart1_Init(void) //9600bps@11.0592MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
AUXR &= 0xBF; //定时器时钟12T模式
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xFD; //设置定时初始值
TH1 = 0xFD; //设置定时重载值
ET1 = 0; //禁止定时器中断
TR1 = 1; //定时器1开始计时
}
char UART_ReceiveChar(void) {
while (!RI); // 等待接收数据完成
RI = 0; // 清除接收标志
return SBUF; // 返回接收到的数据
}
// 电机控制函数
void MotorControl(char command) {
// 先关闭所有电机
AIN1 = 0;
AIN2 = 0;
BIN1 = 0;
BIN2 = 0;
PWMA = 0;
PWMB = 0;
STBY = 1; // 保持 STBY 为高电平,使能电机驱动
switch (command) {
case 'F': // 前进
AIN1 = 1;
AIN2 = 0;
PWMA = 1; // 设置 PWM 为高电平
break;
case 'B': // 后退
AIN1 = 0;
AIN2 = 1;
PWMA = 1; // 设置 PWM 为高电平
break;
case 'L': // 左转
BIN1 = 1;
BIN2 = 0;
PWMB = 1; // 设置 PWM 为高电平
break;
case 'R': // 右转
BIN1 = 0;
BIN2 = 1;
PWMB = 1; // 设置 PWM 为高电平
break;
case 'S': // 停止
AIN1 = 0;
AIN2 = 0;
BIN1 = 0;
BIN2 = 0;
PWMA = 0;
PWMB = 0;
break;
default:
// 无效命令,不做任何操作
break;
}
}
void main()
{
char command;
Uart1_Init(); // 初始化串口
while(1)
{
command = UART_ReceiveChar(); // 接收来自单片机A的指令
MotorControl(command); // 根据接收到的指令控制电机
}
}
详细程序部分请见:shanzhonglong/51-bluetooth-remote-control-car-: 51单片机遥控小车,适合像我一样的初学者
Proteus仿真
大家可参考仿真进行实物连接
目前存在的问题
因为楼主买的是成品车架,前桥和后驱都是各一个成品130玩具电机 ,并且因为51单片机的单线程,小车没法同时执行前进和转向命令,只能调用中断来执行小幅度的转向 ,所以实际跑起来很怪,在这里求助各位大佬有没有更好的解决方案 。
因为是第一次分享文章,有不对的地方还请多多见谅,最后希望大家共同进步。