基于51单片机红外测距仪阈值报警仪表设计

这篇具有很好参考价值的文章主要介绍了基于51单片机红外测距仪阈值报警仪表设计。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

      简介

       一.系统的功能分析及体系结构设计  

       二.STC89C52单片机最小系统

       三.5V电源电路设计

       四.LCD1602液晶显示模块电路设计

       五.按键电路设计

       六.PCF8591 A/D采样电路设计

       七.GP2Y0A21YK0F红外测距传感器模块电路设计

       八.系统源程序(包含原理图,实物图焊接,源代码)

      简介

      由于红外测距是一种非接触检测技术,不受光线、被测对象颜色等的影响,较其它仪器更卫生,更耐潮湿、粉尘、高温、腐蚀气体等恶劣环境,具有少维护、不污染、高可靠、长寿命等特点。因此可广泛应用于纸业、矿业、电厂、化工业、水处理厂、污水处理厂、农业用水、环保检测、食品(酒业、饮料业、添加剂、食用油、奶制品)、防汛、水文、明渠、空间定位、公路限高等行业中。可在不同环境中进行距离准确度在线标定,可直接用于水、酒、糖、饮料等液位控制,可进行差值设定,直接显示各种液位罐的液位、料位高度。

因此,红外在空气中测距在特殊环境下有较广泛的应用。利用红外检测往往比较迅速、方便、计算简单、易于实现实时控制,并且在测量精度方面能达到工业实用的指标要求,因此为了使移动机器人能够自动躲避障碍物行走,就必须装备测距系统,以使其及时获取距障碍物的位置信息(距离和方向)。因此红外测距在移动机器人的研究上得到了广泛的应用。同时由于红外测距系统具有以上的这些优点,因此在汽车倒车雷达的研制方面也得到了广泛的应用。

 一.系统的功能分析及体系结构设计

 系统功能分析

本设计由STC89C52单片机+红外测距模块(发射与接收一体)+1602液晶显示电路+A/D采样电路-PCF8591电路+按键电路+蜂鸣器报警电路+电源电路组成。

1、通过红外测距模块检测距离(测距范围10-80cm),通过PCF8591将红外模块的模拟数值转化为数字数值,然后传给单片机处理。

2、通过1602液晶第一行实时显示距离,第二行显示设置的阈值。

3、阈值可以通过2个按键调节。

4、超过阈值后,蜂鸣器鸣叫报警。

3.1.2系统总体结构

   本系统具体框图如下图所示:

基于51单片机红外测距仪阈值报警仪表设计

二.STC89C52单片机最小系统说明:

STC89C52单片机最小系统电路由复位电路、时钟电路和电源电路。拥有这三部分电路后,单片机即可正常工作。单片机最小系统原理图如下图所示。

基于51单片机红外测距仪阈值报警仪表设计

 

三.5V电源电路设计

本系统选择5V直流电源作为系统总电源,为整个系统供电,电路简单、稳定。DC为电源的DC插座,可以直接接USB电源线,一端插在DC插座上,另外一端可以插在5V电源上,如电脑USB、充电宝、手机充电器等等。LED为红色LED灯,作为系统是否有点的指示灯,电阻为1K电阻,起到限流作用,保护LED灯,以防电流过大烧坏LED灯。SW为自锁开关,开关按下后,红灯亮,此时系统电源5V直流输出。开关再次按下后,红灯灭,此时系统电源无5V电源输出。

基于51单片机红外测距仪阈值报警仪表设计

四.LCD1602液晶显示模块电路设计

LCD显示器分为字段显示和字符显示两种。其中字段显示与LED显示相似,只要送对应的信号到相应的管脚就能显示。字符显示是根据需要显示基本字符。本设计采用的是字符型显示。系统中采用LCD1602作为显示器件输出信息。与传统的LED数码管显示器件相比,液晶显示模块具有体积小、功耗低、显示内容丰富等优点,而且不需要外加驱动电路,现在液晶显示模块已经是单片机应用设计中最常用的显示器件了。LCD1602可以显示2行16个汉字。

 LCD1602液晶模块内部的控制器共有11条控制指令,说明下表所示:

序号

指令

RS

R/W

D7

D6

D5

D4

D3

D2

D1

D0

1

清显示

0

0

0

0

0

0

0

0

0

1

2

光标返回

0

0

0

0

0

0

0

0

1

*

3

置输入模式

0

0

0

0

0

0

0

1

I/D

S

4

显示开/关控制

0

0

0

0

0

0

1

D

C

B

5

光标或字符移位

0

0

0

0

0

1

S/C

R/L

*

*

6

置功能

0

0

0

0

1

DL

N

F

*

*

7

置字符发生存贮器地址

0

0

0

1

字符发生存贮器地址

8

置数据存贮器地址

0

0

1

显示数据存贮器地址

9

读忙标志或地址

0

1

BF

计数器地址

10

写数到CGRA或DDRAM)

1

0

要写的数据内容

11

从CGRAM或DDRAM读数

1

1

读出的数据内容

系统中采用LCD1602作为显示器件输出信息。在本电路中电位器可以调节液晶显示的对比度即清晰度。其具体电路原理图如下图所示。

基于51单片机红外测距仪阈值报警仪表设计

 五.按键电路设计

轻触按键是按键产品下属的一款分类产品,它其实相当于是一种电子开关,只要轻轻的按下按键就可以是开关接通,松开时是开关就断开连接,实现原理主要是通过轻触按键内部的金属弹片受力弹动来实现接通和断开的。在本系统中,按键作为系统的输入,起到了人机交互的枢纽作用。按键的单片机控制引脚默认为高电平,当按键按下后,单片机的相关引脚则变成低电平。进而实现对系统的手动输入。其电路原理图如下图所示。

基于51单片机红外测距仪阈值报警仪表设计

 按键电路原理图

六.PCF8591 A/D采样电路设计

本系统选择PCF8591作为A/D采样芯片。PCF8591是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。PCF8591具有4个模拟输入、1个模拟输出和1个串行I²C总线接口。PCF8591的3个地址引脚A0, A1和A2可用于硬件地址编程,允许在同个I2C总线上接入8个PCF8591器件,而无需额外的硬件。在PCF8591器件上输入输出的地址、控制和数据信号都是通过双线双向I2C总线以串行的方式进行传输。

  • 芯片特性

(1)单独供电

(2)PCF8591的操作电压范围2.5V-6V

(3)低待机电流

(4)通过I2C总线串行输入/输出

(5)PCF8591通过3个硬件地址引脚寻址

(6)PCF8591的采样率由I2C总线速率决定

(7)个模拟输入可编程为单端型或差分输入

(8)自动增量频道选择

(9)PCF8591的模拟电压范围从VSS到VDD

(10)PCF8591内置跟踪保持电路

(11)8-bit逐次逼近A/D转换器

其具体原理图如下图所示。两个电阻为上拉电阻,让数字信号的读取更稳定。

基于51单片机红外测距仪阈值报警仪表设计

 

七.GP2Y0A21YK0F红外测距传感器模块电路设计

本系统选择GP2Y0A21YK0F红外测距传感器对距离进行检测。GP2Y0A21YK0F是测距传感器单元,是基于PSD的微距传感器,其有效测距距离在10-80cm内,有效测量角度大于40度,输出的信号为模拟电压,在0-8cm内于Juin成正比非线性关系,在10-80cm范围内成反比非线性关系,平均工号约为30mA,反应时间约为5ms,并对背景光和温度的适应性较强,由于输出信号为模拟电压,且价格低廉,因此在工程测量等方面有巨大的应用前景。由于采用三角测量方法,这个装置输出对应于电压检测输出,所以这种传感器还可用来作为接近传感器

  • 模块参数
  1. 测量距离10-80cm。
  2. 测距分辨率为1mm
  3. 电源电压为4.5V-5.5V
  4. 模拟量输出型
  5. 功耗:30mA
  6. 工作温度:-10-+60℃
  7. 存储温度:-40-+70℃
  • 使用范围
  1. 触摸式开关(卫浴设备、照明等)
  2. 节能传感器(ATM取款机、复印机、自动售货机等)
  3. 机器人、吸尘器
  4. 游乐设备(机器人、游戏机)
  5. 智能家居等等。
  • 模块接口说明
  1. 红线 接4.5V-5.5V
  2. 黑线 接GND
  3. 黄线 信号线,接单片机引脚

模块接口原理图如下图所示。

基于51单片机红外测距仪阈值报警仪表设计

传感器接口电路原理图

模块实物图如下图所示。

基于51单片机红外测距仪阈值报警仪表设计 

传感器传感器实物图

  八.系统源程序(包含原理图,实物图焊接,源代码)

基于51单片机红外测距仪阈值报警仪表设计

 程序原理图

基于51单片机红外测距仪阈值报警仪表设计

实物图实现

以下为源代码:

1602.h


------------------------------------------------*/
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include<intrins.h>

#ifndef __1602_H__
#define __1602_H__

void DispStr(unsigned char x,unsigned char y,unsigned char *ptr);
void DispNChar(unsigned char x,unsigned char y, unsigned char n,unsigned char *ptr);
void LocateXY(unsigned char x,unsigned char y);
void Disp1Char(unsigned char x,unsigned char y,unsigned char data1);
void LcdReset(void);
void LcdWriteCommand(unsigned char cmd,unsigned char chk);
void LcdWriteData( unsigned char data1 );
void WaitForEnable(void);
void LcdClear(void);

#define LCD_Init          LcdReset
#define LCD_Write_Char    Disp1Char
#define LCD_Write_String  DispStr
#define LCD_Clear         LcdClear
   
#endif

 1602.c

#include "1602.h"
#include "delay.h"
#include <intrins.h>

#define uchar unsigned char
#define uint unsigned int

#define _NOP() _nop_()
sbit RS = P2^4;   //定义端口 
sbit RW = P2^5;
sbit EN = P2^6;

#define DataPort    P0				
#define DataPIN     P0

#define CLR_RS (RS=0) 
#define SET_RS (RS=1)	
#define CLR_RW (RW=0)	
#define SET_RW (RW=1)
#define CLR_EN (EN=0)
#define SET_EN (EN=1)	

/*
	LcdReset();               //LCD1602初始化
	DelayMs(10);	
	sprintf(temp,"1111111111111111");//更新显示
	DispStr(0,0,(unsigned char *)temp);//打印显示
	sprintf(temp,"1111111111111111");//更新显示
	DispStr(0,1,(unsigned char *)temp);//打印显示
*/
/***********************************************
函数名称:DispStr
功    能:让液晶从某个位置起连续显示一个字符串
参    数:x--位置的列坐标
          y--位置的行坐标
          ptr--指向字符串存放位置的指针
返回值  :无
***********************************************/
void DispStr(uchar x,uchar y,uchar *ptr) 
{
    uchar *temp;
    uchar i,n = 0;
    
    temp = ptr;
    while(*ptr++ != '\0')   n++;    //计算字符串有效字符的个数
    
    for (i=0;i<n;i++)
    {
        Disp1Char(x++,y,temp[i]);
        if (x == 0x10)
        {
            break;
        }
    }
}

/*******************************************
函数名称:DispNchar
功    能:让液晶从某个位置起连续显示N个字符
参    数:x--位置的列坐标
          y--位置的行坐标
          n--字符个数
          ptr--指向字符存放位置的指针
返回值  :无
*******************************************
void DispNChar(uchar x,uchar y, uchar n,uchar *ptr) 
{
    uchar i;
    
    for (i=0;i<n;i++)
    {
        Disp1Char(x++,y,ptr[i]);
        if (x == 0x10)
        {
           x = 0; 
            y ^= 1;
        }
    }
}
*/
/*******************************************
函数名称:LocateXY
功    能:向液晶输入显示字符位置的坐标信息
参    数:x--位置的列坐标
          y--位置的行坐标
返回值  :无
********************************************/
void LocateXY(uchar x,uchar y) 
{
    uchar temp;

    temp = x&0x0f;
    y &= 0x01;
    if(y)   temp |= 0x40;  //如果在第2行
    temp |= 0x80;

    LcdWriteCommand(temp,1);
}

/*******************************************
函数名称:Disp1Char
功    能:在某个位置显示一个字符
参    数:x--位置的列坐标
          y--位置的行坐标
          data--显示的字符数据
返回值  :无
********************************************/
void Disp1Char(uchar x,uchar y,uchar data1) 
{
    LocateXY( x, y );			
    LcdWriteData( data1 );		
}

/*******************************************
函数名称:LcdReset
功    能:对1602液晶模块进行复位操作
参    数:无
返回值  :无
********************************************/
void LcdReset(void) 
{
//    DataDir  = 0xFF;                 //数据端口设为输出状态 
    LcdWriteCommand(0x38, 0);	    //规定的复位操作
    DelayMs(5);
    LcdWriteCommand(0x38, 0);		
    DelayMs(5);
    LcdWriteCommand(0x38, 0);
    DelayMs(5);

    LcdWriteCommand(0x38, 1);		//显示模式设置
    LcdWriteCommand(0x08, 1);		//显示关闭
    LcdWriteCommand(0x01, 1);	    //显示清屏
    LcdWriteCommand(0x06, 1);		//写字符时整体不移动
    LcdWriteCommand(0x0c, 1);		//显示开,不开游标,不闪烁
}

/*------------------------------------------------
                清屏函数
------------------------------------------------*/
void LcdClear(void) 
{ 
	LcdWriteCommand(0x01,1); 
	DelayMs(5);
}

/*******************************************
函数名称:LcdWriteCommand
功    能:向液晶模块写入命令
参    数:cmd--命令,
          chk--是否判忙的标志,1:判忙,0:不判
返回值  :无
********************************************/
void LcdWriteCommand(uchar cmd,uchar chk) 
{

    if (chk) WaitForEnable();   // 检测忙信号?
    
    CLR_RS;	
    CLR_RW; 
    _NOP();

    DataPort = cmd;             //将命令字写入数据端口 
    _NOP();					
    
    SET_EN;                     //产生使能脉冲信号
    _NOP();
    _NOP();
    CLR_EN;			
}

/*******************************************
函数名称:LcdWriteData
功    能:向液晶显示的当前地址写入显示数据
参    数:data--显示字符数据
返回值  :无
********************************************/
void LcdWriteData( uchar data1 ) 
{
    WaitForEnable();        //等待液晶不忙
    SET_RS;
    CLR_RW; 

    SET_EN;
	
	_NOP();
    DataPort = data1;        //将显示数据写入数据端口
    _NOP();
                //产生使能脉冲信号
    _NOP(); 
    _NOP(); 
    CLR_EN;		
}

/*******************************************
函数名称:WaitForEnable
功    能:等待1602液晶完成内部操作
参    数:无
返回值  :无
********************************************/
void WaitForEnable(void) 
{
  	unsigned int later=0;
	DataPort=0xff;
    CLR_RS;
    SET_RW;
    _NOP();
    SET_EN; 
    _NOP();
    _NOP();
//    while((DataPIN&Busy)!=0);    
    while(((DataPIN&0x80)!=0)&&(later<1000))  //检测忙标志
    {
      DelayUs2x(2);
      later++;        
    }
    CLR_EN;
//    DataDir|=0xFF;  //将P4口切换为输出状态
}		

i2c.c

#include "i2c.h"

#define  _Nop()  _nop_()  //定义空指令
                         
bit ack;	              //应答标志位

sbit SDA=P2^0;
sbit SCL=P2^1;

#define AddWr 0x90   //写数据地址 
#define AddRd 0x91   //读数据地址

/*------------------------------------------------
                    启动总线
------------------------------------------------*/
void Start_I2c()
{
  SDA=1;   //发送起始条件的数据信号
  _Nop();
  SCL=1;
  _Nop();    //起始条件建立时间大于4.7us,延时
  _Nop();
  _Nop();
  _Nop();
  _Nop();    
  SDA=0;     //发送起始信号
  _Nop();    //起始条件锁定时间大于4μ
  _Nop();
  _Nop();
  _Nop();
  _Nop();       
  SCL=0;    //钳住I2C总线,准备发送或接收数据
  _Nop();
  _Nop();
}
/*------------------------------------------------
                    结束总线
------------------------------------------------*/
void Stop_I2c()
{
  SDA=0;    //发送结束条件的数据信号
  _Nop();   //发送结束条件的时钟信号
  SCL=1;    //结束条件建立时间大于4μ
  _Nop();
  _Nop();
  _Nop();
  _Nop();
  _Nop();
  SDA=1;    //发送I2C总线结束信号
  _Nop();
  _Nop();
  _Nop();
  _Nop();
}




/*----------------------------------------------------------------
                 字节数据传送函数               
函数原型: void  SendByte(unsigned char c);
功能:  将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
     此状态位进行操作.(不应答或非应答都使ack=0 假)     
     发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
------------------------------------------------------------------*/
void  SendByte(unsigned char c)
{
 unsigned char BitCnt;
 
 for(BitCnt=0;BitCnt<8;BitCnt++)  //要传送的数据长度为8位
    {
     if((c<<BitCnt)&0x80)SDA=1;   //判断发送位
       else  SDA=0;                
     _Nop();
     SCL=1;               //置时钟线为高,通知被控器开始接收数据位
      _Nop(); 
      _Nop();             //保证时钟高电平周期大于4μ
      _Nop();
      _Nop();
      _Nop();         
     SCL=0; 
    }
    
    _Nop();
    _Nop();
    SDA=1;               //8位发送完后释放数据线,准备接收应答位
    _Nop();
    _Nop();   
    SCL=1;
    _Nop();
    _Nop();
    _Nop();
    if(SDA==1)ack=0;     
       else ack=1;        //判断是否接收到应答信号
    SCL=0;
    _Nop();
    _Nop();
}







/*----------------------------------------------------------------
                 字节数据传送函数               
函数原型: unsigned char  RcvByte();
功能:  用来接收从器件传来的数据,并判断总线错误(不发应答信号),
     发完后请用应答函数。  
------------------------------------------------------------------*/	
unsigned char  RcvByte()
{
  unsigned char retc;
  unsigned char BitCnt;
  
  retc=0; 
  SDA=1;             //置数据线为输入方式
  for(BitCnt=0;BitCnt<8;BitCnt++)
      {
        _Nop();           
        SCL=0;       //置时钟线为低,准备接收数据位
        _Nop();
        _Nop();      //时钟低电平周期大于4.7us
        _Nop();
        _Nop();
        _Nop();
        SCL=1;       //置时钟线为高使数据线上数据有效
        _Nop();
        _Nop();
        retc=retc<<1;
        if(SDA==1)retc=retc+1; //读数据位,接收的数据位放入retc中
        _Nop();
        _Nop(); 
      }
  SCL=0;    
  _Nop();
  _Nop();
  return(retc);
}



/*----------------------------------------------------------------
                     应答子函数
原型:  void Ack_I2c(void);
 
----------------------------------------------------------------*/
/*void Ack_I2c(void)
{
  
  SDA=0;     
  _Nop();
  _Nop();
  _Nop();      
  SCL=1;
  _Nop();
  _Nop();              //时钟低电平周期大于4μ
  _Nop();
  _Nop();
  _Nop();  
  SCL=0;               //清时钟线,钳住I2C总线以便继续接收
  _Nop();
  _Nop();    
}*/
/*----------------------------------------------------------------
                     非应答子函数
原型:  void NoAck_I2c(void);
 
----------------------------------------------------------------*/
void NoAck_I2c(void)
{
  
  SDA=1;
  _Nop();
  _Nop();
  _Nop();      
  SCL=1;
  _Nop();
  _Nop();              //时钟低电平周期大于4μ
  _Nop();
  _Nop();
  _Nop();  
  SCL=0;                //清时钟线,钳住I2C总线以便继续接收
  _Nop();
  _Nop();    
}

/*------------------------------------------------
             读AD转值程序
输入参数 Chl 表示需要转换的通道,范围从0-3
返回值范围0-255
------------------------------------------------*/
unsigned char ReadADC(unsigned char Chl)
 {
   unsigned char Val;
   Start_I2c();               //启动总线
   SendByte(AddWr);             //发送器件地址
     if(ack==0)return(0);
   SendByte(0x40|Chl);            //发送器件子地址
     if(ack==0)return(0);
   Start_I2c();
   SendByte(AddWr+1);
      if(ack==0)return(0);
   Val=RcvByte();
   NoAck_I2c();                 //发送非应位
   Stop_I2c();                  //结束总线
  return(Val);
 }




/*----------------------------------------------------------------
                    向无子地址器件发送字节数据函数               
函数原型: bit  ISendByte(unsigned char sla,ucahr c);  
功能:     从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla.
           如果返回1表示操作成功,否则操作有误。
注意:    使用前必须已结束总线。
----------------------------------------------------------------*/
/*bit ISendByte(unsigned char sla,unsigned char c)
{
   Start_I2c();               //启动总线
   SendByte(sla);             //发送器件地址
     if(ack==0)return(0);
   SendByte(c);               //发送数据
     if(ack==0)return(0);
  Stop_I2c();                 //结束总线
  return(1);
}
*/

/*----------------------------------------------------------------
                    向有子地址器件发送多字节数据函数               
函数原型: bit  ISendStr(unsigned char sla,unsigned char suba,ucahr *s,unsigned char no);  
功能:     从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件
          地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。
           如果返回1表示操作成功,否则操作有误。
注意:    使用前必须已结束总线。
----------------------------------------------------------------*/
/*bit ISendStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no)
{
   unsigned char i;
 for(i=0;i<no;i++)
    { 
   Start_I2c();               //启动总线
   SendByte(sla);             //发送器件地址
     if(ack==0)return(0);
   SendByte(suba);            //发送器件子地址
     if(ack==0)return(0); 
 
     SendByte(*s);            //发送数据
       if(ack==0)return(0);
     Stop_I2c();                  //结束总线
	 DelayMs(1);               //必须延时等待芯片内部自动处理数据完毕
	 s++;
	 suba++;
    } 
  return(1);
}
*/
/*----------------------------------------------------------------
                    向无子地址器件读字节数据函数               
函数原型: bit  IRcvByte(unsigned char sla,ucahr *c);  
功能:     从启动总线到发送地址,读数据,结束总线的全过程,从器件地
          址sla,返回值在c.
           如果返回1表示操作成功,否则操作有误。
注意:    使用前必须已结束总线。
----------------------------------------------------------------*/
/*bit IRcvByte(unsigned char sla,unsigned char *c)
{
   Start_I2c();                //启动总线
   SendByte(sla+1);            //发送器件地址
     if(ack==0)return(0);
   *c=RcvByte();               //读取数据
     NoAck_I2c();              //发送非就答位
     Stop_I2c();               //结束总线
  return(1);
}

*/
/*----------------------------------------------------------------
                    向有子地址器件读取多字节数据函数               
函数原型: bit  ISendStr(unsigned char sla,unsigned char suba,ucahr *s,unsigned char no);  
功能:     从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件
          地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。
           如果返回1表示操作成功,否则操作有误。
注意:    使用前必须已结束总线。
----------------------------------------------------------------*/
/*bit IRcvStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no)
{
   unsigned char i;

   Start_I2c();               //启动总线
   SendByte(sla);             //发送器件地址
     if(ack==0)return(0);
   SendByte(suba);            //发送器件子地址
     if(ack==0)return(0);

   Start_I2c();
   SendByte(sla+1);
      if(ack==0)return(0);

  for(i=0;i<no-1;i++)
    { 
     *s=RcvByte();              //发送数据
      Ack_I2c();                //发送就答位 
     s++;
    } 
   *s=RcvByte();
    NoAck_I2c();                 //发送非应位
    Stop_I2c();                    //结束总线
  return(1);
}
*/

i2c.h

 #ifndef __I2C_H__
#define __I2C_H__  
              
#include <reg52.h>          //头文件的包含
#include <intrins.h>

#define  _Nop()  _nop_()        //定义空指令

void Start_I2c();
void Stop_I2c();
void  SendByte(unsigned char c);
unsigned char  RcvByte();

void Ack_I2c(void);
void NoAck_I2c(void);
bit ISendByte(unsigned char sla,unsigned char c);
bit ISendStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no);
bit IRcvByte(unsigned char sla,unsigned char *c);
bit IRcvStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no);

unsigned char ReadADC(unsigned char Chl);

#endif

main.c

#include<reg52.h> //包含头文件
#include<stdio.h>
#include<math.h>
#include "1602.h"
#include "delay.h"
#include "i2c.h"

sbit Buzzer =P1^0;	//引脚定义
sbit Key1 =P1^1;
sbit Key2 =P1^2;

char dis0[16];			   //打印数组初始化
char dis1[16];
unsigned long time_20ms=0;		   //定时器计数

float Volt=0.0;		  	//检测电压
unsigned int BatCap=80;			  //容量初始化
float Shijul= 0,midval ;	//实际距离
unsigned int Setjul= 25 ;	//测量距离
unsigned int DisFlag = 0,rekey=0 ;	//更新显示

void Init_Timer0(void);		   //函数声明
void UART_Init(void);
void uartSendStr(unsigned char *s,unsigned char length);
void uartSendByte(unsigned char dat);

void main (void)
{     
	unsigned char midvolt;

	Init_Timer0();        //定时器0初始化
	UART_Init();
	             
	LCD_Init();           //初始化液晶
	DelayMs(20);          //延时有助于稳定
	LCD_Clear(); 

	sprintf(dis0,"Now:Err cm 1-80",Shijul);//打印电池容量值
	LCD_Write_String(0,0,dis0);//显示第一行
	sprintf(dis1,"Set:%2d cm     ",Setjul);//打印电压值			
	LCD_Write_String(0,1,dis1);//显示第二

	uartSendStr("reday ok!!",10);
	while (1)         //主循环
	{
		if(DisFlag ==1)
		{
			DisFlag =0 ;
			midvolt=ReadADC(0);				//ad转换采集
	
			Volt=(float)midvolt*5.10/255;		//计算出电压 *5.10为参考电压 手机适配器
													
			if((Volt<0.42)||(Volt>3.13))   //超出测量范围
			{
				sprintf(dis0,"Now:%4.1f",Volt);//打印显示内容
				Buzzer = 1;
				uartSendStr("ddddddd") ;
			}
			else	//正常范围
			{
				Shijul=26.527*pow(Volt,-1.225)+0.1;	  //模拟曲线获取 根据手册来 光电型号GP2Y0A21YK0F  测量范围10-80cm	 0.1位匹配
				midval =  Shijul;
				sprintf(dis0,"Now:%4.1fcm 1-80",Shijul);//打印实际值
				if(midval>Setjul)  //实际值和设置值对比
				{Buzzer = 0;}
				else
				{Buzzer = 1;}		
			}
			LCD_Write_String(0,0,dis0);//显示第一行
	
//			sprintf(dis1,"Set:%2d cm %4.2f",Setjul,Volt);//打印电压值
			sprintf(dis1,"Set:%2d cm     ",Setjul);//打印电压值			
			LCD_Write_String(0,1,dis1);//显示第二行
		}
		if((Key1==0)||(Key2==0)) //检测按键是否按下
		{
		  	if(rekey==0)		//防止重复
			{
				DelayMs(10);//延时去抖动
			 	if(Key1==0)	   //按键1
				{
					rekey =1;
					if(Setjul>10)  //设置值--
					{
						Setjul--;
					}
				}
				else if(Key2==0)  //按键2
				{
					rekey =1;
					if(Setjul<80)	   //设置值++
					{
						Setjul++;
					}
				}
			
			}
		}
		else
		{rekey =0;}	//防止重复

	}
}


void Init_Timer0(void)
{
	TMOD |= 0x01;	  //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响		     
	TH0=(65536-20000)/256;		  //重新赋值 20ms
	TL0=(65536-20000)%256;
	EA=1;            //总中断打开
	ET0=1;           //定时器中断打开
	TR0=1;           //定时器开关打开
}

void Timer0_isr(void) interrupt 1 
{
	TH0=(65536-20000)/256;		  //重新赋值 20ms
	TL0=(65536-20000)%256;
	
	time_20ms++;
	if(time_20ms%30==0)	  //定时显示
	{
		DisFlag = 1;
	}
}


void UART_Init(void)
{
    SCON  = 0x50;		        // SCON: 模式 1, 8-bit UART, 使能接收  
    TMOD |= 0x20;               // TMOD: timer 1, mode 2, 8-bit 重装
    TH1   = 0xFD;               // TH1:  重装值 9600 波特率 晶振 11.0592MHz
	TL1 = TH1;  
    TR1   = 1;                  // TR1:  timer 1 打开                         
    EA    = 1;                  //打开总中断
    ES    = 1;                  //打开串口中断
}

void uartSendByte(unsigned char dat)
{
	unsigned char time_out;
	time_out=0x00;
	SBUF = dat;			  //将数据放入SBUF中
	while((!TI)&&(time_out<100))  //检测是否发送出去
	{time_out++;DelayUs2x(10);}	//未发送出去 进行短暂延时
	TI = 0;						//清除ti标志
}

void uartSendStr(unsigned char *s,unsigned char length)
{
	unsigned char NUM;
	NUM=0x00;
	while(NUM<length)	//发送长度对比
	{
		uartSendByte(*s);  //放松单字节数据
		s++;		  //指针++
		NUM++;		  //下一个++
  	 }
}

void UART_SER (void) interrupt 4 	//串行中断服务程序
{
	if(RI)                        //判断是接收中断产生
	{
		RI=0;                      //标志位清零
	}
	if(TI)  //如果是发送标志位,清零
	TI=0;
} 






最后附上自己总结的一些话~

在这个红外测距仪的实现过程中,我是以各个模块独立化的形式展现出来的,原因在于我想让大家从入门开始就建立起建工程的意识,从硬件原理图再到代码的编译实现,逐步拆开去理解每个模块的代码实现过程。相信大家看完能有一个清晰的认识和对单片机的理解。

~如有不足,请补充,谢谢!文章来源地址https://www.toymoban.com/news/detail-468527.html

到了这里,关于基于51单片机红外测距仪阈值报警仪表设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于51单片机设计的红外遥控器

    遥控器是现代生活中必不可少的电子产品之一,目前市面上的遥控器种类繁多,应用范围广泛。而 NEC 红外遥控器协议则是目前应用最为广泛的一种协议之一,几乎所有的电视、空调等家用电器都支持该协议。 本项目是基于 51 单片机设计支持 NEC 协议的红外遥控器,实现接收

    2024年02月09日
    浏览(43)
  • 48、基于51单片机红外遥控智能温控风扇系统设计

        本设计为一种温控风扇系统,具有灵敏的温度感测和显示功能,系统STC89C52单片机作为控制平台对风扇转速进行控制。可由用户设置高、低温度值,测得温度值在高低温度之间时打开风扇弱风档,当温度升高超过所设定的温度时自动切换到大风档,当温度小于所设定的温

    2024年02月04日
    浏览(47)
  • 32、基于51单片机红外智能垃圾桶系统设计

    随着现代化进程的日益推进,科技越来越发达,人们的生活水平也提高了,城市化程度越来越高,与此同时也带了许多问题,生活垃圾越来越多垃圾设施却不够完善。无论是在公共场合还是家庭厨房的垃圾大都是没有盖或者有盖但需要人用手打开的,比如夏天的家庭厨房没有

    2023年04月14日
    浏览(53)
  • 基于51单片机的红外密码锁设计[proteus仿真]

    密码锁检测系统这个题目算是课程设计和毕业设计中常见的题目了,本期是一个基于51单片机的红外密码锁设计 需要的源文件和程序的小伙伴可以关注公众号【阿目分享嵌入式】,赞赏任意文章 2¥,私信阿目【112基于51单片机的红外密码锁设计】即可获取(看到消息会第一时

    2024年02月21日
    浏览(53)
  • 超声波测距模块HC-SR04详解(基于51单片机)

    本篇文章是个人整理的包含超声波测距模块HC-SR04的基本介绍与基本工作原理以及分别通过LCD1602、数码管和串口显示距离的实例讲解与代码的笔记,部分内容来自《HC-SR04超声波测距模块说明书》,代码使用模块化编辑,部分模块来自江科大自化协的51单片机教学视频。 希望大

    2023年04月16日
    浏览(48)
  • 63、基于51单片机红外遥控人体感应自动门控制系统设计

    毕设帮助、开题指导、技术解答(有偿)见文末。 目录 摘要 一、硬件方案 二、设计功能 三、实物图 四、原理图 五、PCB图 六、Protues仿真 七、程序 部分代码 八、资料包括 伴随着电气技术的发展,电气控制控制技术已经成熟,针对电子自动门进行研究。基于8051内核的单片

    2024年02月03日
    浏览(44)
  • 45、基于51单片机智能台灯红外坐姿定时提醒人体检测光照系统设计

    社会在不断进步,人类在不断追求,市场在不断变化,高科技应用含量决定着产品发展的新趋势和前景,智能化技术在电子产品领域的应用意义深远。随着电子产品的快速发展,家用电器也越来越偏向智能化,已经应用于实际中的有智能洗衣机,智能电饭锅,智能电磁炉等,

    2023年04月21日
    浏览(44)
  • FPGA一键测距仪之超声波模块篇

    FPGA一键测距仪之数码管篇 FPGA一键测距仪之[按键+控制+蜂鸣器]篇 FPGA一键测距仪之终篇 第一个FPGA小项目:基于BASYS3的超声波一键测距仪 本篇会对超声波测距模块进行详细的讲解,包括测距原理、各模块的时序图构思以及代码实现。 所用到的软件工具: Vivado 2019.1 Modelsim SE

    2024年02月02日
    浏览(47)
  • 38、基于51单片机红外热释电人体感应蓝牙防盗报警器系统设计

    随着现在社会的发展,时代进步,高新技术的快速融入,人们的生活发生了巨大的改变,人们置购了大量高新技术的产品,许多高科技产品的使用越来越成为家庭生活的主旋律,因此人们对自己所处环境的安全要求就越来越高,特别是家居安全,不得不时刻留意不速之客的光

    2024年02月03日
    浏览(60)
  • 104、基于51单片机智能风扇pwm调速红外遥控无线遥控风扇温控风扇系统设计

    毕设帮助、开题指导、技术解答(有偿)见文末。 目录 摘要 一、硬件方案 二、设计功能 三、实物图 四、原理图 五、Protues仿真 六、流程图 七、程序源码 八、资料包括 随着气温的逐渐上升,风扇的需求量也逐渐扩大。传统风扇不能根据外界温度的变化对风扇转速快慢进行

    2024年02月15日
    浏览(67)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包