基于C51的语音智能车(含循迹/跟随/避障/测速屏显/蓝牙WIFI4G控制等功能)

本文详细介绍了使用C51单片机实现智能小车的各种功能,包括PWM调速、红外循迹、超声波避障、蓝牙控制等。通过编程实现了小车的前进、后退、左右转向,并利用PWM进行速度控制。此外,还介绍了如何结合超声波模块进行避障,以及通过蓝牙接收指令进行小车的远程控制。

文章超详细,包含全部代码

本项目基于stc89c52rc。pwm控速,语音控制切换 循迹 / 跟随 / 避障 / 蓝牙WIFI控制 等模式,包含测速屏显并传给上位机等功能。

目录

文章超详细,包含全部代码

一 L9110s电机驱动模块(后改为L1298N+18650电池x2)

控制电机动起来 

二 小车动起来

1.控制小车前后左右停

2.无线射频遥控 

三 蓝牙控制小车

1.串口

2.蓝牙控制

3.点动模式蓝牙控制

四 PWM调速

测试代码

左右轮分别调速

五 红外循迹、跟随

1.红外循迹模块

2.循迹原理

3.跟随

4.红外 循迹、跟随 代码整合

六 超声波避障

转头测距

代码:

结合小车运动实现避障

更改代码:

封装函数和改进

七 小车测速及OLED屏显

进行测速实验(发现问题与改进)

开始代码优化

蓝牙调速小车:

双轮测速

 OLED显示速度

八 WIFI/4G通信

 WiFi控制小车

Wifi传输速度

4G通信

九 SU-03T语音模块

十 功能整合——全能小车

全部代码:

主函数:

定时器及其中断

串口 

红外循迹跟随

超声波避障

OLED显示

 电机驱动


基于C51的智能小车

一 L9110s电机驱动模块(后改为L1298N+18650电池x2)

接通VCC,GND 模块电源指示灯亮, 以下资料来源官方,但是不对,根据下节课实际调试

IA1输入高电平,IA1输入低电平,【OA1 OB1】电机正转;

IA1输入低电平,IA1输入高电平,【OA1 OB1】电机反转;

IA2输入高电平,IA2输入低电平,【OA2 OB2】电机正转;

IA2输入低电平,IA2输入高电平,【OA2 OB2】电机反转;

 

 和C51开发板的接线

 接线中,单片机要单独接出一条gnd连接电源

控制电机动起来 

控制轮子旋转,根据实际运行情况调整电机正反接线,保证两轮都向前

#include "reg52.h"

sbit RightA = P3^2;
sbit RightB = P3^3;

sbit LeftA = P3^4;
sbit LeftB = P3^5;

void main()
{
	LeftA = 1;
	LeftB = 0;
	
	RightA = 1;
	RightB = 0;
}

二 小车动起来

1.控制小车前后左右停

前后左右封装函数: 

void forward(){
	LeftA = 1;
	LeftB = 0;
	
	RightA = 1;
	RightB = 0;
}

void back(){
	LeftA = 0;
	LeftB = 1;
	
	RightA = 0;
	RightB = 1;
}

void left(){
	LeftA = 1;
	LeftB = 1;
	
	RightA = 1;
	RightB = 0;
}

void right(){
	LeftA = 1;
	LeftB = 0;
	
	RightA = 1;
	RightB = 1;
}

void stop(){
	LeftA = 1;
	LeftB = 1;
	
	RightA = 1;
	RightB = 1;
}

void main()
{
	while(1){
		forward();
		Delay2000ms();
		
		back();
		Delay2000ms();
		
		left();
		Delay2000ms();
		
		right();
		Delay2000ms();

        stop();
		Delay2000ms();
	}
}

2.无线射频遥控 

及其简单的IO操作,参考本人之前的文章,一看就会

(50条消息) C51:无线遥控电动车防盗器_我有在好好学习的博客-优快云博客

 点动和自锁模块都通用

#include "reg52.h"
#include "motor.h"

sbit D0 = P2^4;
sbit D1 = P2^5;
sbit D2 = P2^6;
sbit D3 = P2^7;

void main()
{
	char dirc = 0;
	while(1){
		
		if(D0)	dirc = 1;
		else if(D1)	dirc = 2;
		else if(D2)	dirc = 3;
		else if(D3)	dirc = 4;
		else	dirc = 0;
		
		switch(dirc){
			case 1:
				forward();
				break;
			
			case 2:
				back();
				break;
			
			case 3:
				left();
				break;
			
			case 4:
				right();
				break;
			
			case 0:
				stop();
				break;
		}
	}
}

三 蓝牙控制小车

后续为了不臃肿,分文件编程,参考上个c51温湿度监测系统项目最后的分文件操作:

(41条消息) 基于C51的 温湿度监测系统(及蓝牙温控风扇)_我有在好好学习的博客-优快云博客

1.串口

添加串口功能,用蓝牙进行控制,参考上面文章。

接收字符 f b l r s ,使得电机 前 后 左 右 停 。

main.c

#include "reg52.h"
#include "delay.h"
#include "motor.h"
#include "uart.h"

void main()
{
    //串口初始化
	UartInit();
	
	while(1){
		//给电机控制函数传入获得的串口指令
		motor_ON(get_Uart());
		
	}
}

motor.c中的函数

void motor_ON(char dir)
{
	switch(dir){
		case 'f':
			forward();
			break;
		
		case 'b':
			back();
			break;
		
		case 'l':
			left();
			break;
		
		case 'r':
			right();
			break;
		
		case 's':
			stop();
			break;
	}
}

uart.c

默认电机状态为停        motor_dirc = 's'

#include "reg52.h"
 
sfr AUXR = 0x8E;
 
char motor_dirc = 's';
 
//串口部分代码
void UartInit(void)		//9600bps@11.0592MHz
{
	AUXR = 0x01;
	SCON = 0x50; //配置串口工作方式1,REN使能接收
	
	TMOD &= 0x0F;
	TMOD |= 0x20;//定时器1工作方式位8位自动重装
	
	TH1 = 0xFD;
	TL1 = 0xFD;//9600波特率的初值
	
	TR1 = 1;//启动定时器
	
	EA = 1;//开启总中断
	ES = 1;//开启串口中断
}
 
//发送字符
void sendByte(char data_msg)
{
	SBUF = data_msg;
	while(!TI);
	TI = 0;
}
 
//发送字符串
void sendString(char* str)
{
	while( *str != '\0'){
		sendByte(*str);
		str++;
	}
}

//调取蓝牙命令内容
char get_Uart(){
	return motor_dirc;
}
 
//蓝牙指令接收(中断)
void UART_HANDLER() interrupt 4
{
	char cmd;
	
	if(RI)//中断处理函数中,对于接收中断的响应
	{
		RI = 0;//清除接收中断标志位
		
		cmd = SBUF;//接收命令
		
		motor_dirc = cmd;
		
		sendString("收到串口指令,改变状态\r\n");
	}
}

2.蓝牙控制

给串口连接上蓝牙模块。

 使用蓝牙串口助手,自定义设置好按键对应发送的字符,向设备发送命令。

最终实现了蓝牙控制小车方向。

3.点动模式蓝牙控制

蓝牙助手改为长按模式0.2s发一次指令

重点在于串口中断。

接收到指令也运动0.2s

//蓝牙指令接收(中断)
void UART_HANDLER() interrupt 4
{
	char cmd;
	
	if(RI)//中断处理函数中,对于接收中断的响应
	{
		RI = 0;//清除接收中断标志位
		
		cmd = SBUF;//接收命令
		
		motor_dirc = cmd;
		
		switch(motor_dirc){
			case 'f':
				forward();
				sendString("向前\r\n");
				break;
			
			case 'b':
				back();
				sendString("向后\r\n");
				break;
			
			case 'l':
				left();
				sendString("向左\r\n");
				break;
			
			case 'r':
				right();
				sendString("向右\r\n");
				break;
			
			case 's':
				stop();
				sendString("停止\r\n");
				break;
		}
	}
    //每次收到数据运动0.2秒
	Delay200ms();
}

main.c        没收到指令就保持停滞状态。 

void main()
{
  //串口初始化
	UartInit();
	
	while(1){
		//没收到指令就不动
		stop();
	}
}

四 PWM调速

参考本人之前的文章

(45条消息) C51:PWM+舵机角度控制_我有在好好学习的博客-优快云博客

原理: 全速前进是 LeftA = 0; LeftB = 1; 完全停止是 LeftA = 0;LeftB = 0; 那么单位时间内,比如20ms, 有15ms是全速前进,5ms是完全停止,速度就会比5ms全速前进,15ms完全停止获得的功率多,相应的速度更快!

开发:借用PWM的舵机控制代码

测试代码

#include "reg52.h"
#include "intrins.h"

sbit RightA = P3^2;
sbit RightB = P3^3;

sbit LeftA = P3^4;
sbit LeftB = P3^5;

int speed;//0~40

int cnt;

void Time0Init()//500微秒
{
//1. 配置定时器0工作模式位16位计时
	TMOD = 0x01;
	
//2. 给初值,定一个10ms出来
	TL0 = 0x33;		//设置定时初值
	TH0 = 0xFE;		//设置定时初值
	
//3. 开始计时,定时器"数数"
	TR0 = 1;
	TF0 = 0;
	
//4. 打开定时器0中断
	ET0 = 1;
	
//5. 打开总中断EA
	EA = 1;
}

void Delay2000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 15;
	j = 2;
	k = 235;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void forward(){
	LeftA = 1;
	LeftB = 0;
	
	RightA = 1;
	RightB = 0;
}

void stop(){
	LeftA = 1;
	LeftB = 1;
	
	RightA = 1;
	RightB = 1;
}

void main()
{
	speed = 40;
	cnt = 0;
	
	Time0Init();
	
	Delay2000ms();
	
	while(1){
		speed = 40;//快
		Delay2000ms();
		
		speed = 30;//中
		Delay2000ms();
		
		speed = 20;//慢
		Delay2000ms();
		
		speed = 10;//跑不动
		Delay2000ms();

    speed = 0;//停
		Delay2000ms();
	}
}

void Time0Handler() interrupt 1
{
	cnt++; //统计爆表的次数
	
//重新给初值
	TL0 = 0x33;		//设置定时初值
	TH0 = 0xFE;		//设置定时初值
//按照给定速度参数跑
	if(cnt < speed){
		forward();
	}else{
		stop();
	}
	
	if(cnt == 40){//爆表40次,经过了20ms
		
	cnt = 0; //计算下一次的20ms
	stop();
	}
}

根据speed的大小测试对车速的影响,设置合适的速度

左右轮分别调速

 整合起来,分别通过两个 speed_Right、speed_Left 参数数值实现左右轮调速:

void PWM_Right(){
	RightA = 1;
	RightB = 0;
}

void PWM_Left(){
	LeftA = 1;
	LeftB = 0;
}

void PWM_STOP_Right(){
	RightA = 1;
	RightB = 1;
}

void PWM_STOP_Left(){
	LeftA = 1;
	LeftB = 1;
}
#include "reg52.h"
#include "motor.h"

int speed_Right = 40;//0~40

int cnt_Right =0;

int speed_Left = 40;//0~40

int cnt_Left =0;

//定时器0
void Time0Init()//500微秒
{
	
//1. 配置定时器0工作模式位16位计时
	TMOD = 0x01;
	
//2. 给初值,定一个10ms出来
	TL0 = 0x33;		//设置定时初值
	TH0 = 0xFE;		//设置定时初值
	
//3. 开始计时,定时器"数数"
	TR0 = 1;
	TF0 = 0;
	
//4. 打开定时器0中断
	ET0 = 1;
	
//5. 打开总中断EA
	EA = 1;
}

//定时器1
void Time1Init()//500微秒
{
	
	//1. 配置定时器1工作模式位16位计时
	TMOD &= 0x0F;
	TMOD |= 0x1 << 4;
	
//2. 给初值,定一个10ms出来
	TL1 = 0x33;		//设置定时初值
	TH1 = 0xFE;		//设置定时初值
	
//3. 开始计时,定时器"数数"
	TR1 = 1;
	TF1 = 0;
	
//4. 打开定时器0中断
	ET1 = 1;
	
//5. 打开总中断EA
	EA = 1;
}

//右轮调速
void Time0Handler() interrupt 1
{
	cnt_Right++; //统计爆表的次数
	
//重新给初值
	TL0 = 0x33;		//设置定时初值
	TH0 = 0xFE;		//设置定时初值
	
//按照给定速度参数跑
	if(cnt_Right < speed_Right){
		PWM_Right();
	}else{
		PWM_STOP_Right();
	}
	if(cnt_Right == 40){//爆表40次,经过了20ms
		
	cnt_Right = 0; //计算下一次的20ms
	//stop();
	}
}

//左轮调速
void Time1Handler() interrupt 3
{
	cnt_Left++; //统计爆表的次数
	
//重新给初值
	TL1 = 0x33;		//设置定时初值
	TH1 = 0xFE;		//设置定时初值
	
//按照给定速度参数跑
	if(cnt_Left < speed_Left){
		PWM_Left();
	}else{
		PWM_STOP_Left();
	}
	if(cnt_Left == 40){//爆表40次,经过了20ms
		
	cnt_Left = 0; //计算下一次的20ms
	}
}
#include "reg52.h"
#include "delay.h"
#include "motor.h"
#include "uart.h"
#include "pwm.h"

extern char motor_dirc;

void main()
{
  //串口初始化
	UartInit();
	//定时器开启
	Time0Init();
	Time1Init();
	
	while(1){
		motor_dirc = SBUF;
	}
}

五 红外循迹、跟随

1.红外循迹模块

TCRT5000传感器的红外发射二极管不断发射红外线
当发射出的红外线没有被反射回来或被反射回来但强度不够大时,
红外接收管一直处于关断状态,此时模块的输出端为高电平,指示二极管一直处于熄灭状态
被检测物体出现在检测范围内时,红外线被反射回来且强度足够大,红外接收管饱和,
此时模块的输出端为低电平,指示二极管被点亮

 总结就是一句话,没反射回来,D0输出高电平,灭灯

评论 44
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值