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

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

时间:2024-09-17 10:24:05浏览次数:14  
标签:dat 温度传感器 循迹 uint8 delay 单片机 sbit I2C nop

目录

一、主要功能

二、硬件资源

三、程序编程

四、实现现象


一、主要功能

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

仿真图:

编辑

二、硬件资源

基于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;       //电机使能端2

sbit 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;//开启定时器0
	while(Ec);//度过回响信号高电平
	TR0=0;//关闭定时器0
	result=((TH0\*256+TL0)\*0.034)/2;		// 距离cm=(时间us * 速度cm/us)/2
	return 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~960us

  while(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 delay
   DS=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 0
      i=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 variable
  temp=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;		//关闭电机1
		Motor2_EN =  0;		//关闭电机2
	}
	else 
	{
	 led=0;
	 BEEP=0;
	 Motor1_EN =  1;		//关闭电机1
	 Motor2_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;
                else
                        I2C_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);
                else
                        dat = 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);
                else
                        dat = 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通道0
        I2C_write(0x00 | chn);//写入PCF8591通道0
        I2C_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通道0
        I2C_write(0x01 | chn);//写入PCF8591通道0
        I2C_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的分享

标签:dat,温度传感器,循迹,uint8,delay,单片机,sbit,I2C,nop
From: https://blog.csdn.net/m0_74115051/article/details/142311973

相关文章

  • [proteus仿真]基于51单片机,74hs373,8255A扩展 流水灯设计
    目录一、主要功能二、硬件资源三、程序编程四、实现现象一、主要功能基于51单片机,74hs373,8255A扩展流水灯设计二、硬件资源基于KEIL5编写C++代码,PROTEUS8.15进行仿真,全部资源在页尾,提供安装包。三、程序编程#include<reg52.h>#include<intrins.h>#include......
  • 1030-基于51单片机的SPWM波(数码管)原理图、流程图、物料清单、仿真图、源代码
    1030-基于51单片机的SPWM波(数码管)原理图、流程图、物料清单、仿真图、源代码功能介绍:要求能够输出SPWM并且测量输入正弦波的频率并显示。直流电压通过DC-AC电路转为方波,搭建检测电路进行滤波和调节,得到正弦波,单片机采集该正弦波的频率,并显示。有哪些资料:1、仿真工程文......
  • 嵌入式单片机程序运行机制,从helloworld说起
    1开篇学习任何一门编程语言,都会从helloworld开始。对于一门从未接触过的语言,在短时间内我们都能用这种语言写出它的helloworld。然而,对于helloworld这个简单程序的内部运行机制,相信还有很多人都不是很清楚。helloworld这些信息是如何通显示器过显示的?cpu执行的代码和......
  • 第十一届蓝桥杯单片机省赛试题
    第十一届预赛试题目录第十一届预赛试题一、系统硬件框图二、基本功能三、显示功能(1)数据界面(2)参数界面(3)计数界面0三、按键功能四、LED指示功能五、初始状态说明六、代码示例一、系统硬件框图二、基本功能(1)使用PCF8591芯片测量AIN3通道上获取的电......
  • 51单片机-DS1302(实时时钟+可调时钟)(可参考主页上一节内容介绍)
    作者:王开心时间:2024.9.10目的:手撕51main.c#include<REGX52.H>#include"LCD1602.h"#include"DS1302.h"#include"Key.h"#include"Delay.h"#include"Timer0.h"unsignedcharKeyNum,MODE,TimeSetSelect,TimeS......
  • 单片机毕业设计——基于物联网系统的防汛监测系统 要怎么设计与实现呢 要怎么设计与实
    基于物联网的智能教室设计与实现是通过集成多个传感器和控制设备,利用云平台进行数据管理和远程监控,以实现教室环境的自动化管理。以下是根据功能需求分步骤的具体实现方案:一、系统规划与设计需求分析:确定教室需要实现的功能,如温湿度检测、风扇控制、光照检测、人体感应、设......
  • 基于单片机的水温监测系统软件设计
    基于单片机的水温监测系统软件设计1主程序框架本温度监测系统的主程序框架如图4-1所示,系统开始是单片机对各个模块进行初始化,通过按键和液晶显示两者之间的交互来实现各个功能的显示,通过按键来切换系统的功能模式,更方便用户了解整个系统的流程,最后实现对温度的监测与显示......
  • 单片机寄存器相关知识及应用(51单片机)
    在前面的STM32中我并没有直接对寄存器进行操作,而是通过固件库直接引用进行各个外设的配置和应用,现在,我开始进行寄存器的学习(51单片机)。我们先简单看一下80C51/52的微控制头文件 <REG52.h>一、字节寄存器定义定义了一系列的特殊功能寄存器,如P0、P1、P2、P3、PSW、ACC、B、......
  • 51单片机 - 蜂鸣器按键提示音代码
    作者:王开心main.c#include<REGX52.H>#include"Delay.h"#include"Key.h"#include"Nixie.h"#include"Timer0.h"#include"Buzzer.h"unsignedcharKeyNum;voidmain(){ Nixie(1,0); while(1) ......
  • 51单片机-AT24C02(IIC总线介绍及其时序编写步骤)-第一节(下一节实战)
    IIC开始通信(6大步)我以前的文章也有对基本常用的通信协议讲解,如SPIUARTIICRS232RS485CAN的讲解,可前往主页查询,(2024.9.12,晚上20:53,将AT24C02存储芯片,掉电不丢失,容量256字节)......