【电子DIY作品】基于STC8H8K64U和DS18B20的温度采集和LabVIEW上位机显示

[复制链接]
查看521 | 回复7 | 2024-8-1 12:46:20 | 显示全部楼层 |阅读模式

本帖最后由 无垠的广袤 于 2024-8-2 01:12 编辑

基于STC8H8K64U和DS18B20的温度采集和LabVIEW上位机显示

通过 STC 单片机和 DS18B20 实现环境温度采集并串口显示,

/*--------- DS18B20 -----------
Function: Display temperature by UART
Board: STC8H8K64U
Main Fosc: 22.1184 MHz
Baud rate: 9600 bps
Connect: DQ --> P20
Author: Jin-Lei Li
Email: [email]lijinlei0907@163.com[/email]
Date: July 30, 2024
Ref: https://www.stcaimcu.com/forum.php?mod=viewthread&tid=323&extra=page%3D1
Ref: UART section in STC32 series datasheet
------------------------------*/

#include "STC8H.h"
#include "intrins.h"

typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long int u32;

#define MAIN_Fosc     22118400UL
#define Baudrate      9600
#define BRT           (65536 - (MAIN_Fosc/Baudrate + 2)/4)

sbit DQ = P2^0;

/*-- UART --*/
bit busy;
u8 wptr;
u8 rptr;
u8 buffer[16];
/*---------*/
bit MinusFlag;      //温度正负  0:正数  1:负数
//u16 Temper; // temperature
void GPIO_Init();
void UartInit();
void UartSend(u8 dat);
void UartSendStr(u8 *p);
void Display();
void Delay_ms(u16 ms);
/*----------- Main Program ----------------*/
void main(void)
{
    P_SW2 |= 0x80; //扩展寄存器(XFR)访问使能

    GPIO_Init();
  UartInit();
    ES = 1;
  EA = 1;
  while(1)
  {
        Display();
    Delay_ms(500);
  }
}
/*-------------- GPIO initialize ------------------*/
void GPIO_Init()
{
    P0M1 = 0x00;   P0M0 = 0x00;
  P1M1 = 0x00;   P1M0 = 0x00;
  P2M1 = 0x00;   P2M0 = 0x00;
  P3M1 = 0x00;   P3M0 = 0x00;
  P4M1 = 0x00;   P4M0 = 0x00;
  P5M1 = 0x00;   P5M0 = 0x00;
    P6M1 = 0x00;   P6M0 = 0x00;
  P7M1 = 0x00;   P7M0 = 0x00;
}
/*----------- Delay time ----------------*/
void Delay1us(void) //@22.1184MHz
{
    u8 data i;

    _nop_();
    i = 5;
    while (--i);
}

void Delay60us(void)    //@22.1184MHz
{
    u8 data i, j;

    _nop_();
    _nop_();
    i = 2;
    j = 182;
    do
    {
        while (--j);
    } while (--i);
}

void Delay480us(void)   //@22.1184MHz
{
    u8 data i, j;

    _nop_();
    i = 14;
    j = 199;
    do
    {
        while (--j);
    } while (--i);
}

void Delay_ms(u16 ms)
{
    u16 i;
  do{
      i = MAIN_Fosc / 10000;
      while(--i);
    }while(--ms);
}
/*-------------- UART Send byte ------------------*/
void UartSend(u8 dat)
{
    while (busy);
    busy = 1;
    SBUF = dat;
}
/*-------------- UART Send string ------------------*/
void UartSendStr(u8 *p)
{
    while (*p)
    {
        UartSend(*p++);
    }
}
/*-------------- UART isr ------------------*/
void UartIsr() interrupt 4
{
    if (TI)
    {
        TI = 0;
        busy = 0;
    }
    if (RI)
    {
        RI = 0;
        buffer[wptr++] = SBUF;
        wptr &= 0x0f;
    }
}
/*---------------- UART initial -----------------*/
void UartInit()
{
    SCON = 0x50;
    TMOD = 0x00;
    TL1 = BRT;
    TH1 = BRT>>8;
    TR1 = 1;
    AUXR = 0x40;
    wptr = 0x00;
    rptr = 0x00;
    busy = 0;
}
/*----------- Initialize DS18B20 ----------------*/
void Init_DS18B20(void)//初始化ds1820
{
  bit flag = 1;
  while( flag )
    {
        DQ = 0;             //输出低电平
        Delay480us();
        DQ = 1;             //输出高电平
        Delay60us();
        flag = DQ;          //读取当前电平
        Delay480us();
    }
}
void DS18b20_Write_0(void)      //写逻辑0码
{
    DQ = 0;             //输出低电平
    Delay60us();
    DQ = 1;             //输出高电平
    Delay1us();
    Delay1us();
}

void DS18b20_Write_1(void)      //写逻辑1码
{
    DQ = 0;             //输出低电平
    Delay1us();
    Delay1us();
    DQ = 1;             //输出高电平
    Delay60us();
}
/*----------- Read level ----------------*/
bit DS18b20_Read(void)      //读取电平
{
    bit state ;

    DQ = 0;             //输出低电平
    Delay1us();
    Delay1us();
    DQ = 1;             //输出低电平
    Delay1us();
    Delay1us();
    state = DQ;         //读取当前电平

    Delay60us();

    return  state;
}
/*----------- Write byte ----------------*/
void WriteOneChar(u8 dat)//写一个字节
{
  u8 i;
    for( i=0;i<8;i++ )      //循环八次
    {
        if( dat & 0x01 )
            DS18b20_Write_1();
        else
            DS18b20_Write_0();
        dat >>=1;
    }
}
/*----------- Read byte ----------------*/
u8 ReadOneChar(void)//读一个字节
{
    u8 i = 0;
    u8 dat = 0;
    for (i=8;i>0;i--)
    {
      DQ = 0; // 给脉冲信号
      dat >>= 1;
      DQ = 1; // 给脉冲信号
      if( DS18b20_Read() )  //如果读取到的是1,
            dat |= 0x80;
    }
    return dat;
}

/*----------- Start ----------------*/
void Start_Convert()
{
    Init_DS18B20();
    WriteOneChar(0xcc);
    WriteOneChar(0x44);
}
/*----------- Read Temperature ----------------*/
u16 Readtemp(void)
{
  u8 Low = 0;
  u8 High = 0;
  u16 Temper = 0; // temperature
  float Tt = 0;

    Start_Convert();
    while(!DQ);             //4.等待DQ变成高电平

    Init_DS18B20();
    WriteOneChar(0xCC); //跳过读序号列号的操作
    WriteOneChar(0xBE); //读取温度寄存器

    Low = ReadOneChar();   //连续读两个字节数据   //读低8位
    High = ReadOneChar();                          //读高8位

    if( High & 0XF8 )                           //有1出现就是负数
    {
        MinusFlag = 1;                          //标志位负数
        Temper = (High<<8) | Low;       //将温度换算成16位
        Temper = (~Temper) +1;          //按位取反+1
        Tt = Temper*0.0625;     //得到真实十进制温度值,因为DS18B20可以精确到0.0625度,所以读回数据的最低位代表的是0.0625度
        Temper = Tt*10 + 0.5; //放大十倍,以便保留一位小数,并四舍五入
    }
    else
    {
        MinusFlag = 0;                          //标志位正数
        Temper = (High<<8) | Low;       //将温度换算成16位
        Tt = Temper*0.0625;     //最终温度保留一位小数
        Temper = Tt*10 + 0.5;
    }
    return Temper;
}
/*----------- Display temperature ----------------*/
void Display()
{
    u16 val;
    u16 shi,ge,xiaoshu;
    val = Readtemp();
    shi = val/100+48;
    ge = val/10%10+48;
    xiaoshu = val%10+48;
    if( MinusFlag==1 ) // negtive
    {
        UartSendStr("Temperature: ");
        UartSend('-');
    UartSend(shi);
    UartSend(ge);
    UartSend('.');
    UartSend(xiaoshu);
        UartSendStr("\r\n");
    }
    else // MinusFlag==0, positive
    {
        UartSendStr("Temperature: ");
    UartSend(shi);
    UartSend(ge);
    UartSend('.');
    UartSend(xiaoshu);
        UartSendStr("\r\n");
    }
}

后面进一步想要实现温度的实时监测和数据记录保存,因此编写了 LabVIEW 程序,修改了部分单片机程序代码。经过实验验证,该项目可以实现 LabVIEW 上位机对 MCU 发送指令,MCU 通过 DS18B20 温度传感器获取环境温度,并通过串口将数据反馈给上位机,上位机实时记录数据,并将日期和各个时刻的温度数据保存至文件。

LabVIEW上位机前面板设置如图所示 img

程序面板如下图所示 img img

需要注意的是单片机发送字符串给上位机、上位机接收均是一位一位传递,因此需要考虑判定截止符号,并将字符串转化为一定精度的数值才能显示到 LabVIEW 图表。

实物连接如下图所示 img

LabVIEW和程序代码见附件

效果展示视频已上传至B站 https://www.bilibili.com/video/BV194vqekEzY/ .

项目说明

该项目起初是由于实验室缺少环境温度监控,而精密的光学仪器和材料对温度又十分敏感,因此想要制作一款实验室使用的远程温度监控系统。实验所需材料为一线制 DS18B20 高精度温度传感器、STC8H8K64U 开发板、STC 程序下载器。上位机使用最新版 LabVIEW 编程,上位机通过串口通信发送指令到 MCU,单片机读取传感器数据并回传给上位机,上位机实时保存时间和对应的温度数据。

项目分析

该项目相较于市场上常见的智能温度计的优点为可极大程度地提高信息获取的自由度,即使用者可以自定义采集数据的频率和精度,并实时查看监控保存数据,避免因上传至云端造成的信息泄露的风险。

此外,该项目的不足之处是未实现无线远程控制和数据上传功能,缺少封装,不便于携带和转移,采集数据较少。因此后续可结合安信可ESP8266等带有WiFi功能的开发板,实现远程数据读取和操控。

MCU开发者和爱好者
回复

使用道具 举报

爱笑 | 2024-8-1 13:56:10 | 显示全部楼层
不错不错!
用心做好保姆工作
回复

使用道具 举报

无垠的广袤 | 2024-8-2 01:16:05 | 显示全部楼层

感谢鼓励,展示视频已上传至B站,后面会进一步优化该项目,如增加湿度传感器、光照度传感器等获取更多环境信息;增加数据自动上传至云端服务器功能,增加APP或小程序访问实时数据功能等,敬请期待哦
MCU开发者和爱好者
回复 支持 反对

使用道具 举报

bzhou830 | 2024-8-2 08:43:34 | 显示全部楼层
STC的板子哪里搞到的
选择去发光,而不是被照亮
回复 支持 反对

使用道具 举报

无垠的广袤 | 2024-8-2 13:47:52 | 显示全部楼层
bzhou830 发表于 2024-8-2 08:43
STC的板子哪里搞到的

图片中绿色的板子是STC官方提供的【开天斧】开发板,MCU为STC8H8K64U,视频中的开发板是我自己设计的PCB,MCU也是STC8H8K64U,支持USB下载,项目工程见https://oshwhub.com/lijinlei0907/stc8h-ws2812-color-control-board
MCU开发者和爱好者
回复 支持 反对

使用道具 举报

bzhou830 | 2024-8-2 14:02:00 | 显示全部楼层
无垠的广袤 发表于 2024-8-2 13:47
图片中绿色的板子是STC官方提供的【开天斧】开发板,MCU为STC8H8K64U,视频中的开发板是我自己设计的PCB ...

厉害,学习下
选择去发光,而不是被照亮
回复 支持 反对

使用道具 举报

iiv | 2024-8-3 08:55:19 | 显示全部楼层
很棒
回复

使用道具 举报

WT_0213 | 2024-8-3 09:33:32 | 显示全部楼层
厉害
回复

使用道具 举报

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

本版积分规则