【Proteus单片机仿真】基于51单片机的循迹小车避障+气体传感器和温度传感器系统

目录

一、主要功能

二、硬件资源

三、程序编程

四、实现现象


一、主要功能

开机即两个直流电机运转,然后三个气体传感器,如果超过阈值,即蜂鸣器报警;
超声波传感器,如果检测到障碍,电机停止;
温度传感器,超过阈值,电机停止,蜂鸣器报警,点亮一个灯;
循迹模拟,与电机联动;

仿真图:

编辑

二、硬件资源

基于KEIL5编写C++代码,PROTEUS8.15进行仿真,全部资源在页尾,提供安装包。

1、51单片机

2、超声波模块

3、烟雾传感器

4、一氧化碳传感器

5、二氧化碳传感器

6、DS18B20温度传感器

7、灯光报警模块

8、PCF8591电机模块

9、LCD1602显示模块

10、L298N电机模块

三、程序编程

/*全部代码资源在页尾*/
#include <REGX52.H>
#include<intrins.h>
#include<stdio.h>
#include "Delay.h"
#include "LCD1602.h"
#define uchar unsigned char
#define uint unsigned  int
typedef unsigned char u8;
typedef unsigned int  u16;
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef unsigned long uint32;
sbit led = P3^5;			  //LED灯引脚
sbit BEEP = P3^6;			  //蜂鸣器引脚
sbit DS=P3^7;                 //DS18B20温度传感器
sbit Motor1_IN1 = P3^3;	      //电机IN1口
sbit Motor1_IN2 = P3^4;
sbit Motor1_EN =  P3^2;       //电机使能端1
sbit Motor2_IN1 = P2^4;	      //电机IN2口
sbit Motor2_IN2 = P2^5;
sbit Motor2_EN =  P2^7;       //电机使能端2sbit CS=P1^0;        //51单片机引脚设置
sbit CLK=P1^1;
sbit DIO=P1^2;
sbit CS1=P1^3;       //51单片机引脚设置
sbit CLK1=P1^4;
sbit DIO1=P1^2;
sbit CS2=P1^5;       //51单片机引脚设置
sbit CLK2=P1^6;
sbit DIO2=P1^2;
sbit Tr=P3^0;//触发信号
sbit Ec=P3^1;//回响信号
sbit I2C_SCL=P2^0;//pcf8591
sbit I2C_SDA=P2^1;uchar Recv_Buffer\[4\];
uint Voltage\[\]={'0','0','0','0'};
bit bdata IIC_ERROR;unsigned char count;
unsigned int distance;
static uint temp;
static float ftemp = 0.0f;//温度转变
uint temp;
static unsigned char num;
static int maxnumber=100,difference;
unsigned int Read_value(void);//读值函数
uint8 AD_value = 0;//AD值
uint8 AD_value1 = 0;//AD值void tmpchange();
uint tmp();
void beep_warning(uint);
void Delay10us(void);//10us延时函数
uint8 get\_ADC\_vaule(uint8 chn);
uint8 get\_ADC\_vaule1(uint8 chn);void Time0_Init()          //定时器初始化
{TMOD = 0x01;TH0 = 0x00;TL0 = 0x00;TR0 = 0;//先关闭定时器0
}void Time0_Int() interrupt 1 //中断程序
{TH0  = 0xfe;             //重新赋值TL0  = 0x33;
}unsigned int Read_value()
{uint result;Tr=1;//触发引脚发出11us的触发信号(至少10us)Delay10us();Tr=0;while(!Ec);//度过回响信号的低电平TR0=1;//开启定时器0while(Ec);//度过回响信号高电平TR0=0;//关闭定时器0result=((TH0\*256+TL0)\*0.034)/2;		// 距离cm=(时间us * 速度cm/us)/2return result + 2;	//+2修正补偿	
}uchar get\_AD\_Res()          //ADC0832启动读取函数
{uchar i, data1=0, data2=0;CS=0;CLK=0;DIO=1;\_nop\_();CLK=1;\_nop\_();CLK=0;DIO=1;\_nop\_(); CLK=1;\_nop\_();CLK=0;DIO=0;\_nop\_();CLK=1;\_nop\_();CLK=0;DIO=1;\_nop\_(); for(i=0; i<8; i++){CLK=1;\_nop\_();CLK=0;\_nop\_();data1=(data1<<1)|(uchar)DIO; }for(i=0; i<8; i++){data2=data2|(uchar)DIO<<i;CLK=1;\_nop\_();CLK=0;\_nop\_();}CS=1;return(data1 == data2)?data1:0;
}uchar get\_AD\_Res1()          //ADC0832启动读取函数
{uchar i, data1=0, data2=0;CS1=0;CLK1=0;DIO1=1;\_nop\_();CLK1=1;\_nop\_();CLK1=0;DIO1=1;\_nop\_(); CLK1=1;\_nop\_();CLK1=0;DIO1=0;\_nop\_();CLK1=1;\_nop\_();CLK1=0;DIO1=1;\_nop\_(); for(i=0; i<8; i++){CLK1=1;\_nop\_();CLK1=0;\_nop\_();data1=(data1<<1)|(uchar)DIO1; }for(i=0; i<8; i++){data2=data2|(uchar)DIO1<<i;CLK1=1;\_nop\_();CLK1=0;\_nop\_();}CS1=1;return(data1 == data2)?data1:0;
}uchar get\_AD\_Res2()          //ADC0832启动读取函数
{uchar i, data1=0, data2=0;CS2=0;CLK2=0;DIO2=1;\_nop\_();CLK2=1;\_nop\_();CLK2=0;DIO2=1;\_nop\_(); CLK2=1;\_nop\_();CLK2=0;DIO2=0;\_nop\_();CLK2=1;\_nop\_();CLK2=0;DIO2=1;\_nop\_(); for(i=0; i<8; i++){CLK2=1;\_nop\_();CLK2=0;\_nop\_();data1=(data1<<1)|(uchar)DIO2; }for(i=0; i<8; i++){data2=data2|(uchar)DIO2<<i;CLK2=1;\_nop\_();CLK2=0;\_nop\_();}CS2=1;return(data1 == data2)?data1:0;
}void dsreset(void)            //发出命令
{uint i;DS=0;		              i=103;				   //将总线拉低480us~960uswhile(i>0)i--;DS=1;					   //然后拉高总线,若DS18B20做出反应会将在15us~60us后将总线拉低i=4;					   //15us~60us等待while(i>0)i--;//while(DS);
}
bit tmpreadbit(void)          //读取数据
{uint i;bit dat;DS=0;i++;          //i++ for delayDS=1;i++;i++;dat=DS;i=8;while(i>0)i--;return (dat);
}
uchar tmpread(void)           //读取数据
{uchar i,j,dat;dat=0;for(i=1;i<=8;i++){j=tmpreadbit();dat=(j<<7)|(dat>>1);   //读出的数据最低位在最前面,这样刚好一个字节在DAT里}return(dat);
}
void tmpwritebyte(uchar dat)  //传输数据给DS18B20
{uint i;uchar j;bit testb;for(j=1;j<=8;j++){testb=dat&0x01;dat=dat>>1;if(testb)     //write 1{DS=0;i++;i++;DS=1;i=8;while(i>0)i--;}else{DS=0;       //write 0i=8;while(i>0)i--;DS=1;i++;i++;}}
}
void tmpchange(void)          //DS18B20开始工作
{dsreset();Delay(1);tmpwritebyte(0xcc);  tmpwritebyte(0x44);  
}					  
uint tmp()                    //获得温度
{float tt;uchar a,b;dsreset();Delay(1);tmpwritebyte(0xcc);tmpwritebyte(0xbe);a=tmpread();//低八位b=tmpread();//高八位temp=b;temp<<=8;             //two byte  compose a int variabletemp=temp|a;tt=temp*0.0625; //算出来的是测到的温度,数值可到小数点后两位temp=tt*10+0.5; //为了显示温度后的小数点后一位并作出四舍五入,因为取值运算不能取小数点后的数return temp;
}void beep_warning(uint ftemp) //温度传感器蜂鸣器警报并且电机转动
{if(ftemp>40){Beep();		 //蜂鸣器报警led=1;Motor1_EN =  0;		//关闭电机1Motor2_EN =  0;		//关闭电机2}else {led=0;BEEP=0;Motor1_EN =  1;		//关闭电机1Motor2_EN =  1;		//关闭电机2}
}void I2C_delay()//I2C延时函数
{\_nop\_();\_nop\_();\_nop\_();\_nop\_();
}void I2C_start()//I2C起始信号
{I2C_SDA = 1;I2C_SCL = 1;I2C_delay();I2C_SDA = 0;I2C_delay();I2C_SCL = 0;I2C_delay();
}void I2C_stop()//I2C停止信号
{I2C_SDA = 0;I2C_SCL = 0;I2C_delay();I2C_SCL = 1;I2C_delay();I2C_SDA = 1;I2C_delay();
}bit I2C_write(uint8 dat)//I2C写一个字节
{bit ack = 0;uint8 mask = 0;for(mask=0x80;mask!=0;mask>>=1){if((mask&dat) == 0)I2C_SDA = 0;elseI2C_SDA = 1;I2C_delay();I2C_SCL = 1;I2C_delay();I2C_SCL = 0;I2C_delay();}I2C_SDA = 1;I2C_delay();I2C_SCL = 1;I2C_delay();ack = I2C_SDA;I2C_delay();I2C_SCL = 0;I2C_delay();return (~ack);        
}uint8 I2C\_read\_ACK()//I2C读一个字节,并发送应答位
{uint8 dat = 0;uint8 mask = 0;I2C_SDA = 1;for(mask=0x80;mask!=0;mask>>=1){if(I2C_SDA == 0)dat = dat & (~mask);elsedat = dat | mask;I2C_delay();I2C_SCL = 1;I2C_delay();I2C_SCL = 0;I2C_delay();}I2C_SDA = 0;I2C_delay();I2C_SCL = 1;I2C_delay();I2C_SCL = 0;I2C_delay();return dat;
}uint8 I2C\_read\_NACK()//I2C读一个字节,并发送非应答位
{uint8 dat = 0;uint8 mask = 0;I2C_SDA = 1;for(mask=0x80;mask!=0;mask>>=1){if(I2C_SDA == 0)dat = dat & (~mask);elsedat = dat | mask;I2C_delay();I2C_SCL = 1;I2C_delay();I2C_SCL = 0;I2C_delay();}I2C_SDA = 1;I2C_delay();I2C_SCL = 1;I2C_delay();I2C_SCL = 0;I2C_delay();return dat;
}uint8 get\_ADC\_vaule(uint8 chn)//获取AD值
{uint8 value = 0;I2C_start();//I2C起始信号if(!I2C_write(0X90))//写入PCF8591地址及读写选择位为写{I2C_stop();return 0;}
//        I2C_write(0X40 | chn);//写入PCF8591通道0I2C_write(0x00 | chn);//写入PCF8591通道0I2C_start();//I2C起始信号I2C_write(0x48<<1 | 0x01);I2C\_read\_ACK();//提供转换所需的时钟信号value = I2C\_read\_NACK();//读取上一次转换的结果I2C_stop();//I2C结束信号return value;
}
uint8 get\_ADC\_vaule1(uint8 chn)//获取AD值
{uint8 value = 0;I2C_start();//I2C起始信号if(!I2C_write(0X90))//写入PCF8591地址及读写选择位为写{I2C_stop();return 0;}
//        I2C_write(0X40 | chn);//写入PCF8591通道0I2C_write(0x01 | chn);//写入PCF8591通道0I2C_start();//I2C起始信号I2C_write(0x48<<1 | 0x01);I2C\_read\_ACK();//提供转换所需的时钟信号value = I2C\_read\_NACK();//读取上一次转换的结果I2C_stop();//I2C结束信号return value;
}
void main()					  //主函数
{	uchar u,U,R,u1,U1,R1,u2,U2,R2;Tr=0;//出发引脚首先拉低
//    led=0;				//灯关掉
//	BEEP=0;			    //蜂鸣器关掉LCD_Init();         //显示屏初始化Time0_Init();
//	Motor1_EN =  1;
//    Motor1_IN1 = 1;	      //电机IN口
//    Motor1_IN2 = 0;
//	Motor2_EN =  1;
//	Motor2_IN1 = 1;	      //电机IN口
//    Motor2_IN2 = 0;while(1){
//	   AD\_value = get\_ADC_vaule(0);//读取通道0的AD值   左电机
//	   AD\_value1 = get\_ADC_vaule1(0);//读取通道0的AD值  右电机
//	   difference=AD\_value-AD\_value1;  //差值等于左电机减去右电机
//	   if(difference>50)
//	   {
//	     Motor1_EN =  0;//左电机停止
//	   }
//	   else if(difference<(-50))
//	   {
//	     Motor2_EN =  0;//右电机停止
//	   }
//	   LCD\_ShowNum(2,10,AD\_value,3); //第一行显示温度
//	   LCD\_ShowNum(2,14,AD\_value1,3); //第一行显示温度
//		u=get\_AD\_Res();
//		U=(250*u)/128;    //二氧化碳
//		R=200*U/250;
//		u1=get\_AD\_Res1();
//		U1=(250*u1)/128;    //烟雾
//		R1=200*U1/250;
//		u2=get\_AD\_Res2();
//		U2=(250*u2)/128;    //一氧化碳
//		R2=200*U2/250;
//		tmpchange();        //让18b20开始转换温度
//	    temp = tmp();       //读取温度
//	    ftemp = temp/10.0f; //转换温度distance = Read_value();//读值distance-=1;LCD_ShowNum(2,5,distance,3); //第一行显示温度
//		if(R>maxnumber||R1>maxnumber||R2>maxnumber)
//		{
//		 Beep();
//		}
//		else
//		{
//		 BEEP=0;
//		}
//	   if(distance<50)
//	   {
//	     Motor1_EN =  0;
//		 Motor2_EN =  0;
//		 Motor1_IN1 = 0;	      //电机IN口
//         Motor1_IN2 = 0;
//		 Motor2_IN1 = 0;	      //电机IN口
//         Motor2_IN2 = 0;
//	   }
//	   else if(ftemp<=40)
//	   {
//	     Motor1_EN =  1;
//		 Motor2_EN =  1;
//		 Motor1_IN1 = 1;	      //电机IN口
//         Motor1_IN2 = 0;
//		 Motor2_IN1 = 1;	      //电机IN口
//         Motor2_IN2 = 0;
//	   }
//	   LCD_ShowNum(1,1,R,3); //第一行显示温度	  
//	   LCD_ShowNum(1,5,R1,3); //第一行显示温度
//	   LCD_ShowNum(1,9,R2,3); //第一行显示温度
//	   LCD_ShowNum(2,1,ftemp,3); //第一行显示温度
//	   LCD_ShowNum(2,5,distance,3); //第一行显示温度
//	   beep_warning(ftemp); //温度超出报警,舵机转动	}
}void Delay10us()
{TL0=0xF5;TH0=0xFF;TR0=1;while (TF0==0);TR0=0;TF0=0;
}

四、实现现象

具体动态效果看B站演示视频:

基于51单片机的循迹小车避障转弯加气体传感器_哔哩哔哩_bilibili

全部资料(源程序、仿真文件、安装包、演示视频):

链接:https://pan.baidu.com/s/1B1k9zD7gyX8sjBVFUNlCxg 
提取码:r7wo 
–来自百度网盘超级会员V4的分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/147306.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习02-pytorch-06-张量的形状操作

在 PyTorch 中&#xff0c;张量的形状操作是非常重要的&#xff0c;可以让你灵活地调整和处理张量的维度和数据结构。以下是一些常用的张量形状函数及其用法&#xff0c;带有详细解释和举例说明&#xff1a; 1. reshape() 功能: 改变张量的形状&#xff0c;但不改变数据的顺序…

[Redis][List]详细讲解

目录 0.前言1.常用命令1.LPUSH / RPUSH2.LPUSHX / RPUSHX3.LRANGE4.LPOP / RPOP5.LINDEX6.LINSERT7.LLEN8.LREM9.LTRIM10.LSET 2.阻塞版本命令0.是什么&#xff1f;1.BLPOP / BRPOP 3.内部编码(旧版本&#xff0c;仅供参考)1.ziplist(压缩链表)2.linkedlist(链表)3.quicklist(快…

TK72A12N1 N沟道功率MOSFET 工业控制领域的高性能功率开关

TK72A12N1产品特性&#xff1a; 漏源电压&#xff08;Vdss&#xff09;&#xff1a;120V&#xff0c;这意味着该器件在正常工作时&#xff0c;漏极和源极之间所能承受的最大电压为 120V。如果超过这个电压&#xff0c;可能会导致器件损坏。 漏极电流&#xff08;Id&#xff0…

基于SpringBoot和Vue框架的医保管理系统的设计与实现

文未可获取一份本项目的java源码和数据库参考。 1.研究的主要内容与方法 &#xff08;1&#xff09;主要内容 医保管理系统采用B/S模式进行开发&#xff0c;采用Springboot框架、VUE技术、Idea为环境、MySQL为数据库开发。主要功能有&#xff1a;个人资料管理、投保用户管理、…

C++ 把字符串转换成整数 (atoi) - 力扣(LeetCode)

点击链接即可查看&#xff1a;LCR 192. 把字符串转换成整数 (atoi) - 力扣&#xff08;LeetCode&#xff09; 一、题目 请你来实现一个 myAtoi(string s) 函数&#xff0c;使其能将字符串转换成一个 32 位有符号整数&#xff08;类似 C/C 中的 atoi 函数&#xff09;。 函数 my…

剩余参数运算符的babel转义配置

记一次生产构建的报错 uncaught syntaxerror: unexpected token ... 背景 在处理展示markdown文本功能&#xff0c;并且其中的代码高亮功能时&#xff0c;引入了两个第三发的依赖包marked 和 highlight.js &#xff0c;本地功能调试正常之后&#xff0c;一如即往的没有build…

基于51单片机的汽车倒车防撞报警器系统

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 本课题基于微控制器控制器&#xff0c; 设计一款汽车倒车防撞报警器系统。 要求&#xff1a; 要求&#xff1a;1.配有距离&#xff0c; 用于把车和障碍物之间的距离信号送入控制器。 2.配有报警系…

【漏洞复现】金斗云 HKMP download 任意文件读取漏洞

免责声明&#xff1a; 本文内容旨在提供有关特定漏洞或安全漏洞的信息&#xff0c;以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步&#xff0c;并非出于任何恶意目的。阅读者应该明白&#xff0c;在利用本文提到的漏洞信息或进行相关测…

[产品管理-32]:NPDP新产品开发 - 30 - 文化、团队与领导力 - 领导力与团队的可持续发展

目录 一、团队领导的领导力 1.1 领导力 1、领导力的定义 2、领导力的重要性 3、领导力的构成要素 4、如何提升领导力 1.2 情商 二、虚拟团队 1、团队定义与特征 2、团队优势 3、团队挑战与应对策略 三、可持续发展 四、团队管理和领导力中的度量指标 4.1 激励创新…

SpringBoot环境配置(Spring Boot Profile)

一、介绍 在Spring Boot中&#xff0c;spring.profiles 配置用于定义不同环境下的配置文件。这使得应用可以在不同的环境中使用不同的配置&#xff0c;比如开发环境、测试环境和生产环境等。这种方式可以避免在代码中硬编码配置信息&#xff0c;并且能够更灵活地管理应用的环境…

深度学习02-pytorch-04-张量的运算函数

在 PyTorch 中&#xff0c;张量&#xff08;tensor&#xff09;运算是核心操作之一&#xff0c;PyTorch 提供了丰富的函数来进行张量运算&#xff0c;包括数学运算、线性代数、索引操作等。以下是常见的张量运算函数及其用途&#xff1a; 1. 基本数学运算 加法运算&#xff1a…

Linux常用命令 笔记

Linux常用指令 查看命令ls 列出指定路径下的文件和目录cd 切换目录绝对路径相对路径 pwd 查看当前路径的绝对路径touch 创建空文件cat 显示文件内容echo 显示内容 & 写入文件vim 文本编辑器打开文件编辑文件保存退出 mkdir 创建目录rm 删除文件&目录删除文件删除目录 定…

TMS320F28335的RS232 通信实验

TMS320F28335 内部含有非常多的通信接口,其中串口是通信接口中应用 非常广泛之一,开发板上集成了一个 RS232 模块,其中串口就是接在 F28335 芯 片的 SCIA 接口。 F28335 通过 SCIA 实现与 PC 机对话,F28335 的 SCIA 收到 PC 机发来的数据后 原封不动的返回给 PC 机显示,定…

【JVM原理】运行时数据区(内存结构)

JVM &#xff08;Java Virtual Machine&#xff09;原理 文章目录 四、运行时数据区&#xff08;内存结构&#xff09;4-1 线程私有区域程序计数器&#xff08;program counter Register&#xff09;本地方法栈&#xff08;Native Method Stacks&#xff09;Java 虚拟机栈&…

【可变模板参数】

文章目录 可变参数模板的概念可变参数模板的定义方式参数包的展开方式递归展开参数包逗号表达式展开参数包 STL容器中的emplace相关接口函数 可变参数模板的概念 可变参数模板是C11新增的最强大的特性之一&#xff0c;它对参数高度泛化&#xff0c;能够让我们创建可以接受可变…

C++ | Leetcode C++题解之第423题从英文中重建数字

题目&#xff1a; 题解&#xff1a; class Solution { public:string originalDigits(string s) {unordered_map<char, int> c;for (char ch: s) {c[ch];}vector<int> cnt(10);cnt[0] c[z];cnt[2] c[w];cnt[4] c[u];cnt[6] c[x];cnt[8] c[g];cnt[3] c[h] - …

C++初阶学习——模版进阶

1. 非类型模板参数 模板参数分类类型形参与非类型形参。 类型形参即&#xff1a;出现在模板参数列表中&#xff0c;跟在class或者typename之类的参数类型名称。 非类型形参&#xff0c;就是用一个常量作为类(函数)模板的一个参数&#xff0c;在类(函数)模板中可将该参数当成…

GroupMamba: Parameter-Efficient and Accurate Group Visual State Space Model

GroupMamba: Parameter-Efficient and Accurate Group Visual State Space Model 1.介绍2.相关工作3.方法3.1预备知识3.2整体架构3.3调制组Mamba层3.3.1视觉单一选择性扫描&#xff08;Visual Single Selective Scan&#xff0c;简称VSSS&#xff09;块3.3.2分组Mamba操作3.3.3…

Vue 计算属性(computed)的使用和优化

前言 Vue 的计算属性&#xff08;computed&#xff09;是 Vue.js 中非常重要的一个概念。它允许你在 Vue 组件中定义一些计算逻辑&#xff0c;这些逻辑会依赖于 Vue 的响应式数据&#xff0c;并且具有缓存机制&#xff0c;只有在依赖数据发生改变时才会重新计算&#xff0c;从…

蓝桥杯—STM32G431RBT6(ADC数模转换,从原理到应用)

一、什么是ADC&#xff1f; ADC&#xff08;Analog-to-Digital Converter&#xff09;即模数转换器。它是一种将模拟信号转换为数字信号的电子器件。在电子系统中&#xff0c;ADC 起着至关重要的作用&#xff0c;它能将连续变化的模拟量&#xff08;如电压、电流等&#xff09;…