当前位置: 首页 > news >正文

避障小车—51单片机

一、小车底盘组装

根据视频的安装步骤安装

二、 电机模块开发

2.1 L9110s概述

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

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

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

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

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

2.1.1 与C51单片机解法

2.2 让小车动起来

代码看网盘资料,因为分文件编写,不好贴近来,只放核心部分代码

#include "reg52.h"
#include "intrins.h"// 左轮
sbit RightCon1A = P3^2;
sbit RightCon1B = P3^3;// 右轮
sbit LeftCon1A = P3^4;
sbit LeftCon1B = P3^5;void Delay1000ms()		//@11.0592MHz
{unsigned char i, j, k;_nop_();i = 8;j = 1;k = 243;do{do{while (--k);} while (--j);} while (--i);
}void goForward()  //前进
{LeftCon1A = 0;LeftCon1B = 1;RightCon1A = 0;RightCon1B = 1;
}void goRight()    //  右转弯
{LeftCon1A = 0;LeftCon1B = 1;RightCon1A = 0;RightCon1B = 0;
}void goLeft()     //  左转弯
{LeftCon1A = 0;LeftCon1B = 0;RightCon1A = 0;RightCon1B = 1;
}void goBack()  // 倒退
{LeftCon1A = 1;LeftCon1B = 0;RightCon1A = 1;RightCon1B = 0;
}void main()
{while(1){goForward();       	 //	前进Delay1000ms();Delay1000ms();goBack();			//  倒退Delay1000ms();Delay1000ms();goLeft();           //  左转弯Delay1000ms();Delay1000ms();goRight();          //  右转弯Delay1000ms();Delay1000ms();}
}
2.2.1 串口控制小车方向

1. 串口分文件编程进行代码整合——具体过程看课程,主要考验C语言功底和代码调试能力,通过现象来改代码

2. 接入蓝牙模块,通过蓝牙控制小车,实现6.6.1的课程需求,蓝牙透传太容易了。

3. 添加点动控制,如果APP支持按下一直发数据,松开就停止发数据(蓝牙调试助手的自定义按键不能实现),就能实现前进按键按下后小车一直往前走的功能

#include "reg52.h"
#include "motor.h"
#include "string.h"
#include "delay.h"
sbit D5 = P3^7;
#define SIZE 12sfr AUXR = 0x8E;
char buffer[SIZE];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;//开启串口中断
}//M1qian  M2 hou M3 zuo  M4 you
void Uart_Handler() interrupt 4
{static int i = 0;//静态变量,被初始化一次char tmp;if(RI)//中断处理函数中,对于接收中断的响应{RI = 0;//清除接收中断标志位tmp = SBUF;if(tmp == 'M'){i = 0;}buffer[i++] = tmp;//灯控指令if(buffer[0] == 'M'){switch(buffer[1]){case '1':goForward();Delay10ms();break;case '2':goBack();Delay10ms();break;case '3':goLeft();Delay10ms();break;case '4':goRight();Delay10ms();break;default:stop();break;}}if(i == 12) {memset(buffer, '\0', SIZE);i = 0;}}}
2.3 如何进行小车PWM调速

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

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

#include "motor.h"
#include "reg52.h"char speed;
char cnt = 0;void Time0Init()
{//1. 配置定时器0工作模式位16位计时TMOD = 0x01;//2. 给初值,定一个0.5出来TL0=0x33;TH0=0xFE;//3. 开始计时TR0 = 1;TF0 = 0;//4. 打开定时器0中断ET0 = 1;//5. 打开总中断EAEA = 1;
}void Time0Handler() interrupt 1
{cnt++;  //统计爆表的次数. cnt=1的时候,报表了1//重新给初值TL0=0x33;TH0=0xFE;//控制PWM波if(cnt < speed){//前进goForward();}else{//停止stop();}if(cnt == 40){//爆表40次,经过了20mscnt = 0;  //当40次表示20ms,重新让cnt从0开始,计算下一次的20ms}}extern char speed;void main()
{Time0Init();//UartInit();while(1){speed = 10;//10份单位时间全速运行,30份停止,所以慢,20ms是40份的500usDelay1000ms();Delay1000ms();speed = 20;Delay1000ms();Delay1000ms();speed = 40;Delay1000ms();Delay1000ms();}
}
2.3.1 PWM方式实现小车转向

原理: 左轮定时器0调速,右轮定时器1调速,那么左转就是右轮速度大于左轮!

开发:有手就行

#include "motor.h"
#include "reg52.h"char speedLeft;
char cntLeft = 0;char speedRight;
char cntRight = 0;void Time1Init()
{//1. 配置定时器1工作模式位16位计时TMOD &= 0x0F;TMOD |= 0x1 << 4;//2. 给初值,定一个0.5出来TL1=0x33;TH1=0xFE;//3. 开始计时TR1 = 1;TF1 = 0;//4. 打开定时器1中断ET1 = 1;//5. 打开总中断EAEA = 1;
}void Time0Init()
{//1. 配置定时器0工作模式位16位计时TMOD = 0x01;//2. 给初值,定一个0.5出来TL0=0x33;TH0=0xFE;//3. 开始计时TR0 = 1;TF0 = 0;//4. 打开定时器0中断ET0 = 1;//5. 打开总中断EAEA = 1;
}void Time1Handler() interrupt 3
{cntRight++;  //统计爆表的次数. cnt=1的时候,报表了1//重新给初值TL1=0x33;TH1=0xFE;//控制PWM波if(cntRight < speedRight){//右前进goForwardRight();}else{//停止stopRight();}if(cntRight == 40){//爆表40次,经过了20mscntRight = 0;  //当100次表示1s,重新让cnt从0开始,计算下一次的1s}}void Time0Handler() interrupt 1
{cntLeft++;  //统计爆表的次数. cnt=1的时候,报表了1//重新给初值TL0=0x33;TH0=0xFE;//控制PWM波if(cntLeft < speedLeft){//左前进goForwardLeft();}else{//停止stopLeft();}if(cntLeft == 40){//爆表40次,经过了20mscntLeft = 0;  //当100次表示1s,重新让cnt从0开始,计算下一次的1s}}extern char speedLeft;
extern char speedRight;void main()
{Time0Init();Time1Init();//UartInit();while(1){speedLeft = 10;//10份单位时间全速运行,30份停止,所以慢,20ms是40份的500usspeedRight = 40;Delay1000ms();Delay1000ms();speedLeft = 40;speedRight = 10;Delay1000ms();Delay1000ms();}
}
2.4 循迹小车
2.4.1 循迹模块使用

TCRT5000传感器的红外发射二极管不断发射红外线

当发射出的红外线没有被反射回来或被反射回来但强度不够大时,

红外接收管一直处于关断状态,此时模块的输出端为高电平,指示二极管一直处于熄灭状态

被检测物体出现在检测范围内时,红外线被反射回来且强度足够大,红外接收管饱和,

此时模块的输出端为低电平,指示二极管被点亮

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

  • 接线方式
    • VCC:接电源正极(3-5V)
    • GND:接电源负极
    • DO:TTL开关信号输出0、1
    • AO:模拟信号输出(不同距离输出不同的电压,此脚一般可以不接)

6.3.2 循迹小车原理

由于黑色具有较强的吸收能力,当循迹模块发射的红外线照射到黑线时,红外线将会被黑线吸收,导致

循迹模块上光敏三极管处于关闭状态,此时模块上一个LED熄灭。在没有检测到黑线时,模块上两个LED

常亮

总结就是一句话,有感应到黑线,D0输出高电平 ,灭灯

循迹模块安装在小车车头两侧下方小车两个模块都能反射回来红外,输出低电平,灯亮,直走

上方小车左模块遇到黑线,红外被吸收,左模块输出高电平,右模块输出低电平,左转,反之右转

  • 代码实现
#include "motor.h"
#include "delay.h"
#include "reg52.h"sbit leftSensor = P2^7;
sbit rightSensor = P2^6;void main()
{//下方小车两个模块都能反射回来红外,输出低电平,灯亮,直走//上方小车左模块遇到黑线,红外被吸收,左模块输出高电平,右模块输出低电平,左转,反之右转while(1){if(leftSensor == 0 && rightSensor == 0){goForward();  // q前进}if(leftSensor == 1 && rightSensor == 0){goLeft();          // 左转}if(leftSensor == 0 && rightSensor == 1){goRight(); 			// 右转}if(leftSensor == 1 && rightSensor == 1){//停stop();           }}
}

修改BUG

防止小车跑车赛道

#include "motor.h"
#include "delay.h"
#include "uart.h"
#include "time.h"
#include "reg52.h"
extern char speedLeft;
extern char speedRight;sbit leftSensor = P2^7;
sbit rightSensor = P2^6;void main()
{Time0Init();    //  中断器Time1Init();//UartInit();while(1){if(leftSensor == 0 && rightSensor == 0){speedLeft = 32;speedRight = 40;}if(leftSensor == 1 && rightSensor == 0){speedLeft = 12;//10份单位时间全速运行,30份停止,所以慢,20ms是40份的500usspeedRight = 40;}if(leftSensor == 0 && rightSensor == 1){speedLeft = 32;speedRight = 20;}if(leftSensor == 1 && rightSensor == 1){//停speedLeft = 0;speedRight = 0;}}
}
2.5 跟随小车/壁障小车
2.5.1 红外壁障模块分析

原理和寻线是一样的,寻线红外观朝下,跟随朝前

6.4.2 跟随小车的原理

左边跟随模块能返回红外,输出低电平,右边不能返回,输出高电平,说明物体在左边,需要左转

右边跟随模块能返回红外,输出低电平,左边不能返回,输出高电平,说明物体在右边,需要右转

6.4.3 跟随小车开发和调试

有手就行,哈哈

  • 代码实现
#include "motor.h"
#include "delay.h"
#include "reg52.h"//sbit leftSensor = P2^7;
//sbit rightSensor = P2^6;sbit leftSensor = P2^5;
sbit rightSensor = P2^4;void main()
{while(1){if(leftSensor == 0 && rightSensor == 0){goForward();}if(leftSensor == 1 && rightSensor == 0){goRight();}if(leftSensor == 0 && rightSensor == 1){goLeft();}if(leftSensor == 1 && rightSensor == 1){//停stop();}}
}
6.4.4 超声波避障小车
1. 超声波代码模块

超声波测距模块是用来测量距离的一种产品,通过发送和收超声波,利用时间差和声音传播速度, 计算出模块到前方障碍物的距离。

    • 怎么让它发送波

Trig ,给Trig端口至少10us的高电平

    • 怎么知道它开始发了

Echo信号,由低电平跳转到高电平,表示开始发送波

    • 怎么知道接收了返回波

Echo,由高电平跳转回低电平,表示波回来了

    • 怎么算时间

Echo引脚维持高电平的时间!

波发出去的那一下,开始启动定时器

波回来的拿一下,我们开始停止定时器,计算出中间经过多少时间

    • 怎么算距离

距离 = 速度 (340m/s)* 时间/2

  • 超声波的时序图

  • 代码实现
#include "reg52.h"
#include "delay.h"sbit Trig     = P1^3;
sbit Echo     = P1^2;void Time1Init()
{	TMOD &= 0x0F;		//设置定时器模式TMOD |= 0x10;TH1 = 0;TL1 = 0;//设置定时器0工作模式1,初始值设定0开始数数,不着急启动定时器
}void startHC()
{Trig = 0;Trig = 1;Delay10us();Trig = 0;
}double get_distance()
{double time;//定时器数据清零,以便下一次测距TH1 = 0;TL1 = 0;//1. Trig ,给Trig端口至少10us的高电平startHC();//2. echo由低电平跳转到高电平,表示开始发送波while(Echo == 0);//波发出去的那一下,开始启动定时器TR1 = 1;//3. 由高电平跳转回低电平,表示波回来了while(Echo == 1);//波回来的那一下,我们开始停止定时器TR1 = 0;//4. 计算出中间经过多少时间time = (TH1 * 256 + TL1)*1.085;//us为单位//5. 距离 = 速度 (340m/s)* 时间/2return  (time * 0.017);
}

2. sg90舵机代码模块
  • 怎么控制舵机

向黄色信号线“灌入”PWM信号。

PWM波的频率不能太高,大约50HZ,即周期=1/频率=1/50=0.02s,20ms左右

数据:

0.5ms-------------0度; 2.5% 对应函数中占空比为250

1.0ms------------45度; 5.0% 对应函数中占空比为500

1.5ms------------90度; 7.5% 对应函数中占空比为750

2.0ms-----------135度; 10.0% 对应函数中占空比为1000

2.5ms-----------180度; 12.5% 对应函数中占空比为1250

定时器需要定时20ms, 关心的单位0.5ms, 40个的0.5ms,初值0.5m cnt++

1s = 10ms * 100

20ms = 0.5ms * 40

  • 编程实现

#include "reg52.h"
#include "delay.h"sbit sg90_con = P1^1;int jd;
int cnt = 0;void Time0Init()
{//1. 配置定时器0工作模式位16位计时TMOD &= 0xF0;		//设置定时器模式TMOD |= 0x01;//2. 给初值,定一个0.5出来TL0=0x33;TH0=0xFE;//3. 开始计时TR0 = 1;TF0 = 0;//4. 打开定时器0中断ET0 = 1;//5. 打开总中断EAEA = 1;
}void sgMiddle()
{//中间位置jd = 3; //90度 1.5ms高电平cnt = 0;
}void sgLeft()
{//左边位置jd = 5; //135度 1.5ms高电平cnt = 0;
}void sgRight()
{//右边位置jd = 1; //0度cnt = 0;
}void Time0Handler() interrupt 1
{cnt++;  //统计爆表的次数. cnt=1的时候,报表了1//重新给初值TL0=0x33;TH0=0xFE;//控制PWM波if(cnt < jd){sg90_con = 1;}else{sg90_con = 0;}if(cnt == 40){//爆表40次,经过了20mscnt = 0;  //当100次表示1s,重新让cnt从0开始,计算下一次的1ssg90_con = 1;}}
3. mian函数组合调用
#include "reg52.h"
#include "hc04.h"
#include "delay.h"
#include "sg90.h"void main()
{Time0Init();Time1Init();//舵机的初始位置sgMiddle();Delay300ms();Delay300ms();while(1){sgLeft();    //  左摇头Delay440ms();sgMiddle();   // 回正Delay430ms();sgRight();   //  右摇头Delay420ms();sgMiddle();  // 回正Delay450ms();}
}
4. 测距摇头实现
#include "reg52.h"
#include "hc04.h"
#include "delay.h"
#include "sg90.h"#define MIDDLE 0
#define LEFT 1
#define RIGHT 2void main()
{char dir;   // 方向变量double disMiddle;  // 中间距离double disLeft;		// 左间距离double disRight;	// 右间距离Time0Init();Time1Init();//舵机的初始位置sgMiddle();Delay300ms();Delay300ms();dir = MIDDLE;while(1){if(dir != MIDDLE){    // 保持测完左右间距之后,回到中间值sgMiddle();dir = MIDDLE;Delay300ms();}disMiddle = get_distance();     // 超声波测距if(disMiddle > 35){  // 如果中间的距离大于了35cm;就前进//前进}else								// 如果前方的距离小于了35cm;就停止{ 		//停止//测左边距离sgLeft();Delay300ms();disLeft = get_distance();sgMiddle();    //  测中间距离Delay300ms();sgRight();   //  测右间距离dir = RIGHT;Delay300ms();disRight = get_distance();}}
}

main函数先调用两个定时器(超声波与sg90舵机定时器);22行至25行代码。将超声波模块保持正前方向之后,进入while循环语句,先进入第一个if语句判断超声波方向,如果超声波方向不在正中间,将其回正之后,将超声波测量的距离,赋值给第二个if语句,进去判断,如何距离大于35cm,小车前进,如果距离不大于35,超声波通过sg90舵机,进行左右测距,测出35cm内无障碍之后,进行前进。

  • 下面是加上电机驱动的代码,让小车跑起来
#include "reg52.h"  // 包含寄存器定义头文件
#include "hc04.h"   // 包含超声波传感器(HC-SR04)头文件
#include "delay.h"  // 包含延时函数头文件
#include "sg90.h"   // 包含舵机(SG90)头文件
#include "motor.h"  // 包含电机控制头文件#define MIDDLE 0   // 定义舵机的中间位置为 0
#define LEFT 1     // 定义舵机的左边位置为 1
#define RIGHT 2    // 定义舵机的右边位置为 2void main()
{char dir;  // 定义舵机的当前方向变量double disMiddle;  // 定义前方的距离变量double disLeft;    // 定义左方的距离变量double disRight;   // 定义右方的距离变量Time0Init();  // 初始化定时器0Time1Init();  // 初始化定时器1// 舵机的初始位置设为中间位置sgMiddle();Delay300ms();  // 延时300毫秒Delay300ms();  // 再延时300毫秒dir = MIDDLE;  // 将舵机方向变量设置为中间位置while(1){  // 无限循环,控制主逻辑if(dir != MIDDLE){  // 如果当前方向不是中间sgMiddle();  // 将舵机调整到中间位置dir = MIDDLE;  // 更新方向变量为中间Delay300ms();  // 延时300毫秒}disMiddle = get_distance();  // 获取前方距离if(disMiddle > 35){  // 如果前方距离大于35goForward();  // 向前移动}else if(disMiddle < 10){  // 如果前方距离小于10goBack();  // 向后移动Delay150ms();  // 延时150毫秒stop();  // 停止移动}else{// 停止移动stop();// 测量左边的距离sgLeft();Delay300ms();  // 延时300毫秒disLeft = get_distance();  // 获取左边距离sgMiddle();  // 将舵机回到中间位置Delay300ms();  // 延时300毫秒sgRight();  // 将舵机转向右边dir = RIGHT;  // 更新方向变量为右边Delay300ms();  // 延时300毫秒disRight = get_distance();  // 获取右边距离if(disLeft < disRight){  // 如果左边距离小于右边距离goRight();  // 向右移动Delay150ms();  // 延时150毫秒stop();  // 停止移动}if(disRight < disLeft){  // 如果右边距离小于左边距离goLeft();  // 向左移动Delay150ms();  // 延时150毫秒stop();  // 停止移动}}}
}

大家在实际操作中,可根据现场实际情况进行对代码测距的修改。

关于相关代码,si信我即可。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 大数据技术体系架构
  • 为何家用无线路由器不能实现PROFINET通信?
  • EasyExcel 文件导出:表头与内容样式简单设置
  • 【Tools】什么是基座模型
  • 机械学习—零基础学习日志(Python做数据分析02)
  • ✨机器学习笔记(三)—— 多元线性回归、特征缩放、Scikit-Learn(未完待续)
  • 大腾智能出席龙华云创中心启动与鸿蒙园揭牌仪式
  • 《花100块做个摸鱼小网站! 》第六篇—将小网站部署到云服务器上
  • 【前端面试】Webpack、Rollup 和 Gulp 构建工具了解
  • 收藏:B站相当精彩的关于向量数据库的2个视频
  • 《数据结构(C语言版)第二版》第八章-排序(8.3-交换排序、8.4-选择排序)
  • [数据集][图像分类]熊分类数据集309张5类别黑熊泰迪北极熊等
  • 动手学深度学习(pytorch)学习记录25-汇聚层(池化层)[学习记录]
  • AIGC与数据分析融合,引领商业智能新变革(TOP企业实践)
  • iOS——GCD再学习
  • C++类的相互关联
  • CentOS从零开始部署Nodejs项目
  • emacs初体验
  • Javascripit类型转换比较那点事儿,双等号(==)
  • opencv python Meanshift 和 Camshift
  • php ci框架整合银盛支付
  • Redash本地开发环境搭建
  • 阿里云应用高可用服务公测发布
  • 当SetTimeout遇到了字符串
  • 工程优化暨babel升级小记
  • 关键词挖掘技术哪家强(一)基于node.js技术开发一个关键字查询工具
  • 规范化安全开发 KOA 手脚架
  • 听说你叫Java(二)–Servlet请求
  • 优化 Vue 项目编译文件大小
  • mysql面试题分组并合并列
  • 没有任何编程基础可以直接学习python语言吗?学会后能够做什么? ...
  • ###C语言程序设计-----C语言学习(3)#
  • #预处理和函数的对比以及条件编译
  • $(this) 和 this 关键字在 jQuery 中有何不同?
  • $.ajax中的eval及dataType
  • (2024.6.23)最新版MAVEN的安装和配置教程(超详细)
  • (4) openssl rsa/pkey(查看私钥、从私钥中提取公钥、查看公钥)
  • (C#)获取字符编码的类
  • (el-Transfer)操作(不使用 ts):Element-plus 中 Select 组件动态设置 options 值需求的解决过程
  • (Python) SOAP Web Service (HTTP POST)
  • (翻译)Entity Framework技巧系列之七 - Tip 26 – 28
  • (一)、python程序--模拟电脑鼠走迷宫
  • *Django中的Ajax 纯js的书写样式1
  • .net 4.0发布后不能正常显示图片问题
  • .net core 外观者设计模式 实现,多种支付选择
  • .net6+aspose.words导出word并转pdf
  • .NET程序员迈向卓越的必由之路
  • .NET使用HttpClient以multipart/form-data形式post上传文件及其相关参数
  • .Net中间语言BeforeFieldInit
  • @font-face 用字体画图标
  • []常用AT命令解释()
  • [2017][note]基于空间交叉相位调制的两个连续波在few layer铋Bi中的全光switch——
  • [AIGC] Kong:一个强大的 API 网关和服务平台
  • [BUUCTF NewStarCTF 2023 公开赛道] week4 crypto/pwn
  • [C++] sqlite3_get_table 的使用