找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2004|回复: 0
打印 上一主题 下一主题
收起左侧

基于单片机+蓝牙的DS18B20与HCSRO4源程序与详细说明

[复制链接]
跳转到指定楼层
楼主
基于DS18B20温度传感器的HC-SR04超声波模块与温度报警的蓝牙连接
一:前言:
这个小项目算是我硬件学习的入门吧,我把其中的问题与大家分享一下,同样作为入门的一员
功能:(1)基于温度值算出声速从而计算障碍物的距离
       (2)设定额定温度,超过额定温度五次发出警告

效果图:

发送“99”后,重置                           输入合法温度值后,Distance为0是因为前方无障碍

二:项目的简单介绍
这个工程总共分为四个模块:显示模块1602;温度模块DS18B20;;超声波模块HC- SR04;
蓝牙模块HC-06;
   显示模块1602,大家应该都比较清晰,这里不做过多描述。
   附录代码:
  1. #include<reg52.h>   // 由于液晶我们这里只写不读,所以RW直接接地
  2. sbit dula = P2^;
  3. sbit wela =P2^;     // 俩锁存器,观看各自原理图是否有
  4. sbit RS = P3^;
  5. sbit LCDEN =P3^;    // RS与lcden接口
  6. void writeComm(ucharcomm)  // 写指令
  7. {
  8.     RS = 0;
  9.     P0 = comm;
  10.     LCDEN = 1;
  11.     delayMs(1);
  12.     LCDEN = 0;
  13.     delayMs(1);
  14. }
  15.                               
  16. void writeData(uchardat)   //写数据:RS=1, RW=0;
  17. {
  18.     RS = 1;
  19.     P0 = dat;
  20.     LCDEN = 1;
  21.     delayMs(1);
  22.     LCDEN = 0;
  23.     delayMs(1);
  24. }
  25. void init()
  26. {
  27.     dula = wela = 0;
  28.     writeComm(0x38);
  29.     writeComm(0x0c);
  30.     writeComm(0x06);
  31.     writeComm(0x01);
  32.    
  33. }
复制代码
温度模块:DS18B20模块,不过多描述,想要说一下负温度的计算与读取,网上资料也比较多一些。首先要了解,LS(低字节)的高四位 和 MS(高字节)的低四位共8个字节构成了实际的一个带符号位的字节数据可以表示18B20的温度范围。MS的高四位为符号为的扩展,当温度值为正时MS高5位全为0,温度值为负时全为1。
第一种:读取的温度为负数时,MS高五位全1,我们已经得到十六位数据value,
如果value<0x0fff,则为正,反之为负数
第二种:Hvalue&0x1f==1,为负温度,Hvalue为MS;
代码如下:
  1. sbit ds = P2^;
  2. uintdealcount=0;
  3.      // 一次计算超出额定温度的次数,初始化为0,与蓝牙模块相关,超过额定温度5次,向手机发出告警信号
  4.     Uint temp_flag     // 设置温度符号的判断符
  5. void dsInit()
  6. {

  7.     unsigned int i;
  8.     ds = 0;
  9.     i = 100;
  10.     while(i>0) i--;
  11.     ds = 1;
  12.     i = 4;
  13.     while(i>0) i--;
  14. }

  15. void dsWait()
  16. {
  17.     unsigned int i;
  18.     while(ds);
  19.     while(~ds);
  20.     i = 4;
  21.     while(i > 0)
  22.         i--;
  23. }


  24. bitreadBit()              //读一位
  25. {
  26.     unsigned int i;
  27.     bit b;
  28.     ds = 0;
  29.     i++;
  30.     ds = 1;
  31.     i++;
  32.     i++;
  33.     b = ds;
  34.     i = 8;
  35.     while(i>0) i--;
  36.     return b;
  37. }

  38. unsigned char readByte()              //读一字节
  39. {
  40.     unsigned int i;
  41.     unsigned char j, dat;
  42.     dat = 0;
  43.     for(i=0; i<8; i++)
  44.     {
  45.         j = readBit();

  46.         dat = (j << 7) | (dat >>1);
  47.     }
  48.     return dat;
  49. }


  50. voidwriteByte(unsigned char dat)
  51. {
  52.     unsigned int i;
  53.     unsigned char j;
  54.     bit b;
  55.     for(j = 0; j < 8; j++)
  56.     {
  57.         b = dat & 0x01;                          //一位一位判别0,1
  58.         dat >>= 1;                              // dat右移一位

  59.         if(b)                                    //写0,写1操作时序
  60.         {
  61.             ds = 0;
  62.             i++;
  63.             i++;
  64.             ds = 1;
  65.             i = 8;
  66.             while(i>0) i--;
  67.         }
  68.         else
  69.         {
  70.             ds = 0;
  71.             i = 8;
  72.             while(i>0) i--;
  73.             ds = 1;
  74.             i++;
  75.             i++;
  76.         }
  77.     }
  78. }



  79. intgetTmpValue()
  80. {
  81.     unsigned int tmpvalue;
  82.     int value;
  83.     float t;
  84.     unsigned char low, high;
  85.     sendReadCmd();
  86.     low = readByte();
  87.     high = readByte();
  88.     tmpvalue = high;
  89.     tmpvalue <<= 8;
  90.     tmpvalue |= low;
  91.    if(tmpvalue<0x0fff)
  92. {

  93.     value=tmpvalue;  
  94.     temp_flag=0;       //0为正

  95. }
  96. else{

  97.      value=~tmpvalue+1;
  98.      temp_flag=1;

  99. }
  100.     t = value * 0.0625;
  101.     value = t * 100 + (value > 0 ? 0.5 :-0.5);     
  102.     return value;
  103. }



  104. voidsendChangeCmd()  // 初始化
  105. {
  106.     dsInit();
  107.     dsWait();
  108.     delayMs(1);
  109.     writeByte(0xcc);
  110.     writeByte(0x44);
  111. }

  112. voidsendReadCmd()   // 读温度
  113. {
  114.     dsInit();
  115.     dsWait();
  116.     delayMs(1);
  117.     writeByte(0xcc);
  118.     writeByte(0xbe);
  119. }
复制代码

超声波模块:HC-SR04模块
具体可以看模块说明书
附录代码,主要看注释
  1. sbit input=P1^ ;                           //Echo引脚
  2. sbit output=P1^ ;                         //Trig引脚
  3. uint count,distance;                       // distance距离,count计算多少ms
  4. void HC_prepare()                        //模块的准备工作
  5. {

  6.    output=1;                             
  7.    input=1;
  8.    count=0;
  9.    distance=0;

  10. }

  11. void trig_init()                           //Trig引脚发出触发信号              
  12. {

  13.    output=1;
  14.    delayUs();
  15.    output=0;


  16. }

  17. void measure(int temp)                //根据温度测距,算出大概的声速
  18. {
  19.    uint h,l;
  20.    uint y;
  21.    TR0=1;                         //打开定时器0
  22.    while(input)
  23.     {
  24.        ;

  25.     }
  26.    TR0=0;                         //Exho引脚返回高电平持续的时间
  27.    l=TL0;                         //低四位赋值
  28.    h=TH0;                        //高四位赋值
  29.    y=(h<<8)+l;
  30.    y=y-0xfc66;                   //减去定时期初值
  31.    distance=y+1000*count;        //得到ms
  32.    TL0=0x66;
  33.    TH0=0xfc;                    //定时器重新赋值
  34.    delayMs(10);
  35.    distance=(331.45+0.61*temp)*distance/20000;     //根据不同需求修改


  36. }


  37. void display(int v)             // v为DS18B20已经测出的value
  38. {
  39.    unsigned char b,c,d,e;
  40.    unsigned char count;
  41.    unsigned char datas[] = {0, 0, 0, 0, 0};
  42.    unsigned int tmp v;
  43. int xz_temp;                              
  44. //设置俩位数的温度(去掉小数后测量的温度)
  45.    datas[0] = tmp / 10000;                 
  46.    datas[1] = tmp % 10000 / 1000;
  47.    datas[2] = tmp % 1000 / 100;
  48.    datas[3] = tmp % 100 / 10;
  49.    datas[4] = tmp % 10;
  50.    xz_temp=10*datas[1]+datas[2];      
  51.    if(xz_temp>set_temp)
  52.        dealcount++;                  //温度大于设置的预警温度,进行一次加一
  53.    writeComm(0x80+0x40);            //液晶地址为第二行
  54.    uart_sendstr(table1);               
  55.    delayMs(15);                      //延时,可能发送不完全,可以自己调整
  56.    if (temp_flag==1)                  //判断符号位
  57.     {
  58.        writeData('-');                  //液晶写数据
  59.        uart_senddata('-');              //蓝牙发送数据,
  60.     }
  61.    else
  62.     {
  63.        writeData('+');
  64.        uart_senddata('+');
  65.     }
  66.    if(datas[0] != 0)
  67.     {
  68.        writeData('0'+datas[0]);
  69.        uart_senddata(datas[0]+0x30);
  70.     }
  71.    for(count = 1; count != 5; count++)
  72.     {
  73.        writeData('0'+datas[count]);
  74.        uart_senddata(datas[count]+0x30);     
  75.        if(count == 2)
  76.        {
  77.            writeData('.');
  78.            uart_senddata('.');
  79.        }
  80.     }
  81.    uart_senddata(0x20);
  82.    uart_senddata(0x20);                     //0x20为空,0x2e为‘.’
  83.    writeComm(0xc0+8);                    
  84.    b=distance/1000;   
  85.    c=distance/100%10;
  86.    d=distance/10%10;
  87.    e=distance%10;
  88.    uart_sendstr(table2);
  89.    delayMs(15);                           //延时
  90.    writeData('0'+b);
  91.    uart_senddata(b+0x30);
  92.    writeData('0'+c);
  93.    uart_senddata(c+0x30);
  94.    writeData('0'+d);
  95.    uart_senddata(d+0x30);
  96.    writeData('.');
  97.    uart_senddata('.');
  98.    writeData('0'+e);
  99.    uart_senddata(e+0x30);
  100.    writeData('c');
  101.    uart_senddata('c');
  102.    writeData('m');
  103.    uart_senddata('m');
  104.    delayMs(15);
  105. }
复制代码
其中要了解的基础知识点:
(1)‘\0’与‘0’   
1)’\0’,就是空字符,代表字符串结束的标志。对应的ASCLL码是0(NULL)
2)’0’,字符常量,表示字符0,对应的ASCLL码是48,也就是0x30

(2)单片机内不同进制数计算
  运算时机器都是转换为二进制计算,所以书写没有必要转换为统一的进制表达


蓝牙模块:HC-06
主要介绍见代码,AT指令集可以查使用手册
  1. void init_uart_and_HC()              // 串口与HC模块的初始化
  2. {

  3.    TMOD=0X21;                  //设置定时器模式
  4.    PCON=0X00;                  //设置电源寄存管理器
  5.    SCON=0x50;                  //串行口控制管理器
  6.     TH1=0XFD;                  
  7. TL1=0XFD;
  8. //设定9600波特率
  9.    TH0=0XFC;
  10. TL0=0X66;
  11. //对HC-SR04所用定时器赋初值

  12.    TR1=1;
  13.    ET0=1;
  14.    EA=1;
  15.    ES=1;

  16. }



  17. void uart_senddata(char dat)           //  串口发送单位数据
  18. {
  19.    ES=0;
  20.    SBUF=dat;
  21.    while(!TI);
  22.    TI=0;
  23.    ES=1;

  24. }

  25. void uart_sendstr(char *p)           //     串口发送字符串
  26. {
  27.    ES=0;
  28.    do
  29.     {

  30.        uart_senddata(*p);


  31.     }
  32.    while(*p++!='\0');
  33.    ES=1;
  34. }
  35. void delayUs()
  36. {
  37.    _nop_();
  38. }

  39. void delayMs(uint a)
  40. {
  41.    uint i, j;
  42.    for(i = a; i > 0; i--)
  43.        for(j = 110; j > 0; j--);
  44. }
复制代码
主函数:
  1. #include <reg52.H>
  2. #include <intrins.H>
  3. #define uchar unsigned char
  4. #define uint unsigned int
  5. uchar flag=0,mode;                 //flag表示输入合法,mode表示发出指令
  6. uchar b[]="ERROR";                 //超出额定温度五次
  7. uchar c[]="OKreset";                //输入“99”后发送
  8. uchar receive_com[2];              //接收字符组
  9. uchar index=0;                    //接收字符组的索引
  10. uchar init_temp[]="Set yourtemp:";
  11. uchar table1[]="temp:  ";
  12. uchar table2[]="Distance:";
  13. int set_temp;
  14. void main()
  15. {
  16.    int temp;
  17.    init();
  18.    init_uart_and_HC();
  19.    writeComm(0x80);
  20.    sendChangeCmd();
  21.    if(flag==0)
  22.     {
  23.        uart_sendstr(init_temp);
  24.        while(!mode)  
  25.        {
  26.            ;                                 
  27. //   表示人为有响应,只有蓝牙接收到数据才会启动
  28.        }
  29.     }
  30.    while(flag==1)                    //  输入合法的温度执行
  31.     {
  32.        writeString(table1,7);
  33.        writeString(table2,9);
  34.        HC_prepare();
  35.        temp=getTmpValue();
  36.        trig_init();
  37.        while(input==0)
  38.        {
  39.            ;
  40.        }
  41.        measure(temp);
  42.        display(temp);
  43.        uart_senddata('\r');
  44.        uart_senddata('\n');
  45.        if(dealcount==5)
  46.        {
  47.            uart_sendstr(b);
  48.            BEEP();                    //延时2.5s,这里可以自己修改
  49.            dealcount=0;
  50.        }
  51.        sendChangeCmd();
  52.        HC_prepare();


  53.     }
  54. mode=0;                 //若跳出while循环,说明接收到了,重置信号
  55. dealcount=0;            // 将超出额定温度的计数置0

  56. }




  57. void t0() interrupt 1
  58. {
  59.    TL0 = 0x66;
  60.    TH0 = 0xfc;
  61.    count++;               //溢出为1ms
  62.    if(count == 18)//超声波回声脉宽最多18ms
  63.     {
  64.        TR0 =0;
  65.        TL0 = 0x66;
  66.        TH0 = 0xfc;
  67.        count = 0;
  68.     }

  69. }

  70. void ser() interrupt 4
  71. {

  72.    RI=0;
  73.    receive_com[index]=SBUF;     
  74.    index++;
  75.   if(index==2)                      //整点温度值输入,当为2位时进入执行
  76.     {
  77.        index=0;                    //重置index

  78.        set_temp=(receive_com[0]-0x30)*10+receive_com[1]-0x30;   
  79. //将字符计算为整数值
  80.        if(set_temp==99)            //99为重置值
  81.        {

  82.            flag=0;               
  83.            uart_sendstr(&c);
  84.            uart_senddata('\r');
  85.            uart_senddata('\n');
  86. //发送回车换行
  87.        }
  88.        if(set_temp!=99)                //正常输入时
  89.        {
  90.            uart_sendstr(receive_com);
  91.            uart_senddata('\r');
  92.            uart_senddata('\n');
  93.            flag=1;                   //置flag为1

  94.        }


  95.        mode=1;                   //mode置1,表示有输入,表示人为响应
  96.     }


  97. }
复制代码

整体思想:
(1)     mode,flag为主要参数,mode决定是否进入运行,是否响应
(2)     对输送数据的发送接收要清晰

可以改进的几点:
(1)     设定温度可以到小数点后俩位,提高精确度,只需要加一个判断小数点的函数
(2)     可以将功能提高一些,比如判断距离或其他

评分

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

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

Powered by 单片机教程网

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