单片机论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1129|回复: 2
收起左侧

采集温度和测距,越限报警并传送数据给上位机

[复制链接]
1833735479 发表于 2018-5-31 14:30 | 显示全部楼层 |阅读模式
#include < reg51.h >
#include < intrins.h >
#define uchar unsigned char
#define uint   unsigned int
#define lcddata P0
sbit LCDRS=P2^0;              //液晶数据选择命令端
sbit LCDRW=P2^1;             //液晶读写命令端
sbit LCDEN=P2^2;            //液晶使能端
uchar mos0,mos1;

sbit DQ = P1^2;   //定义DS18B20端口DQ
sbit trig=P2^3;      //超声波测距模块Trig
sbit echo=P3^2;     //超声波测距模块Echo
sbit baojing=P1^0;                //baojing
sbit baojing1=P3^7;
sbit baojing2=P3^6;
sbit baojing3=P3^5;
sbit baojing4=P3^4;
sbit baojing5=P3^3;
long int distance;    //测量所得距离
uchar  juli_CS[ ] = "000.0";
uchar  juli_H[ ] = "000";
uchar  juli_L[ ] = "000";

uchar count;           //中断累加变量
sbit key_H1=P1^7;     //上限加
sbit key_H2=P1^6;     //上限减
sbit key_L1=P1^5;     //下限加
sbit key_L2=P1^4;     //下限减

long int distance1=4000;//上限值
long int        distance2=100;//下限值


bit presence;           //ds18b20 DQ被拉低 信号0允许,1禁止
uint cc,cc2;       //变量cc中保存读出的温度值
float cc1;
uchar flag;                   //flag为温度值正负标志位,“1”表示温度为复制,“0”表示为正值//flag为温度值正负标志位,“1”表示温度为复制,“0”表示为正值
void write_com(uchar com);

uchar code cdis0[ ] = {"Detection signal"};
uchar code cdis1[ ] = {"Plese wait . . ."};
uchar  cdis2[ ] = "+00.00";
uchar code cdis3[ ] = " DS18B20 ERR0R " ;
uchar code cdis4[ ] = "  Please check  " ;
uchar code table[ ]={"0123456789"}; //定义字符数组显示数字

unsigned char data   temp_data[2] = {0x00,0x00} ;  //存储16位温度

/**********************************lcd1602********************************************/

//----------------------------------
void delaylcd(uint z)
{uchar x,y;
for(x=z;x>0;x--)
  {for(y=110;y>0;y--);
  }
}

/*------------------------------------------------
                  延时函数
------------------------------------------------*/
void delayt(uint x)
{
    uchar j;
    while(x-- > 0)
    {
              for(j = 0;j < 125;j++)
        {
          ;
        }
    }
}
/*lcd1602初始化        */
/**********************************/
void lcd_init(void)
{
        write_com(0x38);                 //使用8位数据开关,显示两行,使用5*7字形
        write_com(0x0c);                //显示器开,光标关,字符不闪烁         0x0e 光标开
        write_com(0x06);           //字符不动,光标自动右移动一位
        write_com(0x01);          //清屏
}

/*写命令to lcd        */
/**********************************/
void write_com(uchar com)//写命令
{
   LCDRW=0;         //低电平为写
   LCDRS=0;         //低电平为命令选择
   LCDEN=1;
   lcddata=com;
   delaylcd(5);
   LCDEN=1;
   delaylcd(5);
   LCDEN=0;
}

/*写数据to lcd             */
/**********************************/
void write_data(uchar  date)
{
        LCDRW=0;  //低电平为写
        LCDRS=1;  //高电平为数据选择
        LCDEN=1;
        lcddata=date;
        delaylcd(5);
        LCDEN=1;
        delaylcd(5);
        LCDEN=0;
}

/*设定显示位置             */
/********************************/
void lcd_pos(uchar pos)
{                                    //第一行第几列直接写pos为几,第二行pos从0x40开始
   write_com(pos | 0x80) ;   //数据指针=80+地址变量
}

void lcd_pos1(uchar pos1)
{                                    //第?行第几列直接写pos为几,第二行pos从0x40开始
   write_com(pos1 | 0xc0) ;   //数据指针=80+地址变量
}

/*******************************ds18b20*******************************************/
/*ms级别      */
void ddelay(uint ms)
{
uint i;
uchar j;
for(i=0;i<ms;i++)
   for(j=0;j<250;j++)
   {
    _nop_();          //一个机器周期,1us
           _nop_();          //适用于精度高的
        _nop_();
    _nop_();
   }
}
/*********us级延时**********/
void Delayus(uchar i)
{
  while(--i);
}
/*复位,每次读写之前都要进行复位*/
/**********************************/
bit ow_reset(void)
{

        DQ = 0; //拉低约600us
        Delayus(150);
        Delayus(150);

        DQ = 1;//产生上升沿,延时约15~60us
        Delayus(30);

        if(DQ==0) {presence=0;}         
        else presence=1;
        return(presence); //等待应答信号 0允许,1禁止
}

/*读取数据一位            */
//---------------------------------
bit Read_bit()
{
        uint i = 0;
        bit b = 0;

        DQ = 0; //产生读时隙  
        i++;         //维持低电平至少1us

        DQ = 1; //1us以上后拉高
        Delayus(2); //延时8us,DO下降沿15内ds18b20输出的数据才有效
        b = DQ; //读取数据
        Delayus(40);         //每个读时隙至少持续60us
        return(b);
}

/*读取一个字节             */
//------------------------------------
uchar Read_byte()
{
        uchar byte_read = 0;
        uchar i, j;

        for(i=0; i<8; i++)
          {
           j = Read_bit();
           byte_read = (j<<i) | byte_read; //低位读起
          }

        return(byte_read);
}

//-----------------------------------------
/*写一个字节         */
void Write_byte(uchar byte_to_write)
{
        uchar i = 0;
        uchar j = 0;
        bit write_bit = 0;

        for(j=0; j<8; j++)
          {
           write_bit =         (byte_to_write & 0x01);
            if(write_bit == 1) //写1
          {
                  DQ = 0;  //产生写时隙
                 Delayus(3);           //延时15us

                  DQ = 1;  //写1
                  Delayus(40);   //延时,写时隙不得低于60us
          }
        else
          {
                  DQ = 0;  //产生写时隙
                  Delayus(50);   //延时,保持低约60us~120us
                  DQ = 1;  
                 i++;
          }
           byte_to_write = byte_to_write >> 1;
   }
}
//-----------------------------------
/*读取温度,启动温度转换*/
/*启动温度转换*/
void start_convert()
{
        ow_reset();          // 发出复位脉冲,每次操作都从复位开始
        ddelay(1);
        Write_byte(0xcc); //skip room命令,跳过序列号命令字
        Write_byte(0x44); //启动温度转换命令
}

/*读取温度值*/
void read_tempreture()
{
        ow_reset();          // 发出复位脉冲,每次操作都从复位开始
        ddelay(1);
        Write_byte(0xcc); //skip room命令
        Write_byte(0xbe); //读取暂存器命令
        temp_data[0] = Read_byte(); //存储温度低字节值 (整数部分低四位和小数部分) 先从低字节读取
        temp_data[1] = Read_byte(); //存储温度高字节值 (其中高五位为符号位)
}
//--------------------------------------
/* Detection...显示              */
void lcd_display()
{
        uchar   m ;
        lcd_pos(0) ;                 //设置显示位置为第一行的第1个字符
      m = 0 ;
      while(cdis0[m] != '\0')
      {                          //显示字符
        write_data(cdis0[m]) ;
        m++ ;
      }
        lcd_pos1(0) ;                 //设置显示位置为第一行的第1个字符
      m = 0 ;
      while(cdis1[m] != '\0')
      {                          //显示字符
        write_data(cdis1[m]) ;
        m++ ;
      }
}


//-----------------------------------
/*   ERR0R          */
/*PLEASE   CHECK  显示    */
void Error_Menu ()
{
      uchar   m ;
      lcd_init() ;                 //初始化LCD
      lcd_pos(0) ;                 //设置显示位置为第一行的第1个字符
      m = 0 ;
      while(cdis3[m] != '\0')
      {                          
        write_data(cdis3[m]) ;           //显示字符
        m++ ;
      }

      lcd_pos(0x40) ;              //设置显示位置为第二行第1个字符
      m = 0 ;
      while(cdis4[m] != '\0')
      {
        write_data(cdis4[m]) ;       //显示字符
        m++ ;
      }
}

//------------------------------------
/*        ℃显示        */
void temp_c()
{
        lcd_pos(6);                  
    write_data(0xdf);//
        lcd_pos(7);                  
   write_data('C');
}

//------------------------------------
/*温度显示                       */
void temperature_display()
{
          uchar m;
          flag=0;
    ddelay(2);
    EA=0;                                //DS18B20读写数据按照严格的时序,最好不要被打断,故把所有中断关闭
    start_convert();                          //启动温度转换
    ddelay(250);
    read_tempreture();                          //读取温度
    EA=1;
   cc=temp_data[1]*256.0+temp_data[0];
    if(temp_data[1]>0xF8) {flag=1;cc=~cc+1;} else flag=0;
    cc1=cc*0.0625;
    cc2=cc1*100;
    cdis2[1]=cc2/1000+0x30;
    if(cdis2[1]==0x30)
    {cdis2[1]=0x20;}
    cdis2[2]=cc2/100%10+0x30;
    cdis2[4]=cc2%100/10+0x30;
    cdis2[5]=cc2%10+0x30;
    if(flag==1)
         cdis2[0]='-';
    else
         cdis2[0]='+';
                        lcd_pos(0) ;                 //设置显示位置为第一行的第6个字符
                     m=0;
    while(cdis2[m]!='\0')
      {                          //显示字符
                      write_data(cdis2[m]) ;
            m++;
      }                                                                  

}

/*--------------------------------------------
------------------超声波函数-----------------
-------------------------------------------*/
/*------------------------------------------------
              1602显示固定字符函数      
------------------------------------------------*/

void lcd_xianshi( )              
{   

         lcd_pos1(0);
           write_data('H');
         lcd_pos1(1);
           write_data('=');

         lcd_pos1(9);
           write_data('L');
         lcd_pos1(10);
           write_data('=');

         lcd_pos(12);
         write_data('.');
         lcd_pos(14);
         write_data('c');
         lcd_pos(15);
         write_data('m');
}


void init_t0()
{
                        PCON=0x00;  
                    SCON=0x50;

         TMOD=0x21;
                                                                                                                
         TL0=0x66;
         TH0=0xfc;              //1ms
                        TH1=0xfd;  
                   TL1=0xfd;  
                    TR1=1;
                     ET0=1;            
         EA=1;                     
}


/*------------------------------------------------
       超声波模块触发信号
------------------------------------------------*/
void trigger()
{
            trig=0;
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
                  _nop_();
      trig=1;      
}


/*------------------------------------------------
   超声波模块相应端口初始化函数
------------------------------------------------*/
void init_measuring()
{
        trig=1;
        echo=1;
        count=0;
}


/*------------------------------------------------
     超声波模块距离测试函数
------------------------------------------------*/
void measuring()
{
        uchar l;
        uint h,y;
             while(echo==0);
        TR0 = 1;
        while(echo==1);         
        TR0 = 0;
        l = TL0;
        h = TH0;
        y = (h << 8) + l;
        y = y - 0xfc66;//us部分
        distance = y + 1000 * count;//计算总时间,单位是微秒
        TL0 = 0x66;
        TH0 = 0xfc;
        delayt(30);
        distance = 3453* distance / 20000;//算出来毫米,原始为:(0.34毫米/us)*时间/2//

}


/*------------------------------------------------
       超声波模块测量结果显示函数
------------------------------------------------*/
void display(uint x)
{
        uchar bai,shi,ge,xiaoshu;
        bai=x/1000;
        shi=(x/100)%10;
        ge=(x/10)%10;
        xiaoshu=x%10;

                  juli_CS[0]=bai+0x30;
                  juli_CS[1]=shi+0x30;                  
                  juli_CS[2]=ge+0x30;
                  juli_CS[4]=xiaoshu+0x30;

        lcd_pos(9);//单位是厘米//
        write_data(table[bai]);//百位显示
                  write_data(table[shi]);//十位显示
                  write_data(table[ge]);//各位显示
             lcd_pos(13);
                   write_data(table[xiaoshu]);//小数点后一位显示

}
/*------------------------------------------
                                        延时函数1ms
-------------------------------------------*/

void delay_key(uchar m)
{

  uchar i,j;
  for(i=0;i<m;i++)
  for(j=0;j<24;j++);

}

void key()
{
        key_H1=1;     //上限加
        key_H2=1;     //上限减
        key_L1=1;     //下限加
        key_L2=1;       
        if(key_H1==0)
         {
                delay_key(1);       
                if(key_H1==0)
                {
                 distance1 = distance1+10;       
                }
         }

         if(key_H2==0)
         {
                delay_key(1);       
                if(key_H2==0)
                {
                 distance1 = distance1-10;       
                }
         }
               
         if(key_L1==0)
         {
                delay_key(1);       
                if(key_L1==0)
                {
                 distance2 = distance2+10;       
                }
         }

         if(key_L2==0)
         {
                delay_key(1);       
                if(key_L2==0)
                {
                  distance2 = distance2-10;
                  if(distance2<0)
                          {
                                distance2=0;
                        }
                }
         }
}
/*-----------------------------------------------*/
/*--------------上下限显示----------------------*/
void display_H_L()
{       
        uchar H_bai,H_shi,H_ge;
        uchar L_bai,L_shi,L_ge;
        key();

        H_bai=distance1/1000;
   H_shi=(distance1/100)%10;
   H_ge=(distance1/10)%10;
        juli_H[0] = H_bai+0X30;
        juli_H[1] = H_shi+0X30;
        juli_H[2] = H_ge+0X30;


        L_bai=distance2/1000;
   L_shi=(distance2/100)%10;
   L_ge=(distance2/10)%10;
        juli_L[0] = L_bai+0X30;
        juli_L[1] = L_shi+0X30;
        juli_L[2] = L_ge+0X30;

   lcd_pos1(2);//单位是厘米//
   write_data(table[H_bai]);//百位显示
        write_data(table[H_shi]);//十位显示
        write_data(table[H_ge]);//各位显示
        write_data('c');//各位显示
        write_data('m');//各位显示


   lcd_pos1(11);//单位是厘米//
   write_data(table[L_bai]);//百位显示
        write_data(table[L_shi]);//十位显示
        write_data(table[L_ge]);//各位显示
        write_data('c');//各位显示
        write_data('m');//各位显示

}

/////////////////////////////////////////////
/*                串口                  */
////////////////////////////////////////////


void comm(uchar *parr)       //串口发送;  
{  
    do  
    {  
        SBUF=*parr++;  
        while(!TI);  
        TI=0;  
    }while(*parr!='\0');  
}  

//-------------------------------------------
/*主函数             */
void main()
{       

        baojing=0;
        baojing1=0;//由于此单片机驱动电流太小
        baojing2=0;//所以用空闲的I/O口作并联
        baojing3=0;//以提高输出电流
        baojing4=0;
        baojing5=0;
        lcd_init();                 //初始化LCD
    init_t0();          //定时器0初始化
    init_measuring();  //超声波相应端口初始化
    lcd_display(); //显示Detection
    ddelay(1000);   //显示Detection1s
    ddelay(1000);   //显示Detection1s
    ddelay(1000);   //显示Detection1s
         write_com(0x01);//清屏
    ow_reset();//DS18B20复位
         while(1)
         {       
                 comm(cdis2);
                comm("\r\n");
                comm(juli_CS);
                comm("\r\n");
                comm(juli_H);
                comm("\r\n");
                comm(juli_L);
                comm("\r\n");
                comm("\r\n");            
                 if(presence==0)
             {          
                
                 temperature_display();//温度显示
                                temp_c();//显示℃                            

             }
                   else
            {
                 Error_Menu ();//显示字符串DS18B20 ERR0R Please check
                 while(1)
                 {
                          ow_reset();//DS18B20复位
                          if(presence==0)
                                   {
                                temperature_display();//温度显示
                                   }
                 }
            }

                   lcd_xianshi( ) ;  //液晶显示特定字符
        trigger();      //触发超声波启动

        measuring();           //进行距离测量
                  display_H_L();//显示上下限
                  if(distance>distance1||distance<distance2)
                                  {
                                        baojing=1;
                                        baojing1=1;//由于此单片机驱动电流太小
                                        baojing2=1;//所以用空闲的I/O口作并联
                                        baojing3=1;//以提高输出电流
                                        baojing4=1;
                                        baojing5=1;
                                }
                  else
                                  {
                                        baojing=0;
                                        baojing1=0;//由于此单片机驱动电流太小
                                        baojing2=0;//所以用空闲的I/O口作并联
                                        baojing3=0;//以提高输出电流
                                        baojing4=0;
                                        baojing5=0;
                                }
        display(distance);    //对测量结果进行显示
        init_measuring();    //超声波相应端口初始化
         }
}
//……………………………………………中断服务函数……

void T_0()interrupt 1
{

        TL0 = 0x66;
        TH0 = 0xfc;
        count++;
       if(count==39)
       {
          TR0 =0;
          TL0 = 0x66;
          TH0 = 0xfc;
          count = 0;
       }
}


仿真原理图

仿真原理图

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

梦园心田 发表于 2019-1-22 21:02 来自手机 | 显示全部楼层
如何区分数据
1121060090 发表于 2020-1-2 01:23 | 显示全部楼层
发送数据给上位机的代码呢?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|单片机论坛 |51黑电子论坛技术交流 管理员QQ:125739409;技术交流QQ群636986012

Powered by 单片机教程网

快速回复 返回顶部 返回列表