十天学会嵌入式技术之51单片机—day-10

news2025/5/15 21:53:16

第 20 章 18B20 温度检测

20.1 18B20 概述

20.1.1 简介

18B20 是一种常用的数字温度传感器,广泛应用于环境监测、工业控制、家居自动化
和设备温度监控等领域。

20.1.2 引脚功能

18B20 引脚功能如下图所示,需要特别强调的是,18B20 采用 1-wire 总线进行通信,
数据的输入输出仅靠一个 DQ 引脚完成。
 

20.1.3 基本工作原理

20.1.4 1-wire 通信协议

20.1.4.1 概述

1-Wire 协议是一种半双工、串行通信协议,主要用于与各种低成本传感器和存储设备
进行数据交换。同 I2C 协议类似,1-Wire 也采用主从架构,一个主设备可以连接多个从设
备。如下图所示。

由于 1-wire 总线也要求各设备以开漏(Open-Drain)模式接入,因此 DQ 信号线也要
使用上拉电阻。
另外,在 1-Wire 总线中,每个从设备都有一个唯一的 64 位地址,用于设备识别和通
信,这 64 位地址是由制造商在生产设备时烧录进去的,不可更改。

20.1.4.2 初始化

1-Wire 规定,每次通信主设备都要先发送一个复位脉冲,从设备接收到该脉冲后,会
进行复位(例如:从低功耗状态恢复到正常通信状态),然后回复一个存在脉冲,主设备可
根据该存在脉冲获知从设备的健康状态。

初始化操作的时序如下。

20.1.4.3 写操作

写操作的时序如下。

20.1.4.4 读操作

读操作的时序如下。

20.1.5 18B20 通信流程

18B20 规定,主设备与其的每次通信,都要遵循以下流程。

1)初始化

主设备发送复位脉冲,从设备回复存在脉冲。
 

2)发送 ROM 命令

每个 18B20 都有一个唯一个的 64 位序列号,该序列号存储于其内部的一个 64 位的
ROM 中。在一个主设备同时连接多个 18B20 的场景下,该序列号能起到唯一标识的作用。
通过发送 ROM 命令,主设备可以获取总线上所连接的 18B20 的序列号,并根据序列号,
与特定的 18B20 进行通信。具体 ROM 命令有:
(1)搜索 ROM 命令[0xF0]
功能:识别和列出所有连接在总线上的 18B20 设备。
(2)读取 ROM 命令[0x33]
功能:在单设备连接时,主机可以使用此命令直接读取设备的 ROM 代码。
(3)匹配 ROM 命令[0x55]
功能:该命令后边会跟随一个特定的 64 位 ROM 代码,用以选择总线上特定的设备进
行通信。
(4)跳过 ROM 命令[0xCC]
功能:在单设备环境中,跳过 ROM 步骤,直接与设备通信。

3)发送功能命令

功能命令用于控制 18B20 的具体操作,向前文提到的测温命令、读取温度命令等均属
于功能命令。 常用的命令如下。
(1)温度转换[44h]
该命令的作用是启动温度测量并将温度数据转换为数字格式。接收到该命令后,
18B20 会读取其内部的温度传感元件,将测量到的温度值转换为数字信号,并存储在内部
的暂存器中,以便后续读取。完成上述操作后,18B20 会自动恢复到低功耗状态。
(2)读取暂存寄存器 [BEh]
该命令用于读取 18B20 暂存器中存储的值。该命令会返回暂存器中的全部数据,共 9
个字节,温度值保存在前两个字节,所以一般情况下,只需接收前两个字节即可。
两个字节的结构如下。

关于这两个字节,有两点需要说明:
①18B20 测温 的精 度是可选的, 有 12 位(bit0-bit11)、 11( bit1-bit11 ) 位 、10 位
(bit2-bit11)和 9 位(bit3-bit11)可选,默认 12 位。
②上述两个字节中保存的是温度值的补码。
注意:上述命令或者数据的读写操作均为低位优先。

20.1.6 相关资料

实物图、原理图、封装

20.2 需求描述

使用 18B20 获取环境温度并将其显示在 OLED 上。

20.3 硬件设计

20.3.1 硬件原理图

20.4 软件设计

1)拷贝 OLED 相关代码

将 Dri_IIC.h、Dri_IIC.c、Int_Oled.h、Int_Oled.c 拷贝到当前项目。

2)增加延时函数

(1)Util.h

/**
* @brief 延时 10us
*
*/
void Delay10us();
/**
* @brief 延时 50us
*
*/
void Delay50us();
/**
* @brief 延时 60us
*
* @param n 倍数
*/
void Delay60us(u8 n);

(2)Util.c

void Delay60us(u8 n) //@11.0592MHz
{
    unsigned char data i;
    while (n--)
    {
        i = 25;
        while (--i);
    }
}

void Delay10us() //@11.0592MHz
{
    unsigned char data i;
    i = 2;
    while (--i);
}
void Delay50us() //@11.0592MHz
{
    unsigned char data i;
    _nop_();
    i = 20;
    while (--i);
}

3)编写 1-Wire 总线驱动

(1)Dri_1wire.h

#ifndef __DRI_1WRIE_H__
#define __DRI_1WRIE_H__
#include "Util.h"
#include <stc89c5xrc.h>
/**
* @brief 初始化
*
* @return bit 1:存在 0:不存在
*/
bit Dri_1wrie_Init();
/**
* @brief 发送一个字节
*
* @param byte 待发送字节
*/
void Dri_1wrie_SendByte(u8 byte);
/**
* @brief 接收一个字节
*
* @return u8 收到的字节
*/
u8 Dri_1wrie_ReceiveByte();
#endif /* __DRI_1WRIE_H__ */

(2)Dri_1wire.h

#include "Dri_1wrie.h"
#define DQ P44
bit Dri_1wrie_Init()
{
    bit result;
    // 主设备发送复位脉冲
    DQ = 0;
    Delay60us(8);
    DQ = 1;
    // 18B20 回复主设备
    Delay60us(1);
    result = ~DQ;
    Delay60us(7);
    return result;
}
void Dri_1wrie_SendByte(u8 byte)
{
    u8 i;
    for (i = 0; i < 8; i++) {
        // 拉低总线
        DQ = 0;
        // 从低位发送
        DQ = byte & 0x1;
        byte >>= 1;
        // 延时 60us
        Delay60us(1);
        // 释放总线
        DQ = 1;
    }
}
u8 Dri_1wrie_ReceiveByte()
{
    u8 byte = 0;
    u8 i;
    for (i = 0; i < 8; i++) {
        // 拉低总线
        DQ = 0;
        // 释放总线
        DQ = 1;
        // 延时 10us
        Delay10us();
        byte >>= 1;
        if (DQ == 1)
         {
        byte |= 0x80;
         }
        // 等待 50us
        Delay50us();
    }
    return byte;
}

4)编写 DS18B20 接口

(1)Int_DS18B20.h

#ifndef __INT_DS18B20_H__
#define __INT_DS18B20_H__
#include <STC89C5xRC.H>
#include "Util.h"
/**
* @brief 获取温度
*
* @return u8
*/
char Int_DS18B20_GetTemperature()
#endif

(2)Int_DS18B20.c

#include "Int_DS18B20.h"
#include "Dri_1wrie.h"
#include "Util.h"
char Int_DS18B20_GetTemperature()
{
    u8 ls_byte, ms_byte;
    // 初始化
    Dri_1wrie_Init();
    // 发送跳过 ROM 命令
    Dri_1wrie_SendByte(0xCC);
    // 发送测温命令
    Dri_1wrie_SendByte(0x44);
    // 初始化
    Dri_1wrie_Init();
    // 发送跳过 ROM 命令
    Dri_1wrie_SendByte(0xCC);
    // 发送读取暂存器命令
    Dri_1wrie_SendByte(0xBE);
    // 读取结果
    ls_byte = Dri_1wrie_ReceiveByte();
    ms_byte = Dri_1wrie_ReceiveByte();
    ls_byte >>= 4;
    ms_byte <<= 4;
    return ms_byte | ls_byte;
}

5)Main.c

#include "Int_Oled.h"
#include "Int_DS18B20.h"
void main()
{
    Int_Oled_Init();
    Int_Oled_Clear();
    while (1) {
        Int_Oled_ShowNum(0, 0, Int_DS18B20_GetTemperature());
        Delay1ms(500);
    }
}

第 21 章 DS1302 时钟

21.1 DS1302 概述

21.1.1 简介

DS1302 是一个低功耗、实时时钟(RTC)芯片,如下图所示。

21.1.2 引脚功能

21.1.3 基本工作原理

21.1.4 通信协议

根据上述的工作流程可知,使用 DS1302 时,核心操作就是读写寄存器。

21.1.4.1 写操作

以下是向寄存器写入单个字节的时序图。

21.1.4.2 读操作

以下是从寄存器读取单个字节的时序图

21.1.4.3 常用寄存器

以下是各时间寄存器的地址和每位的定义。

1)中文版

2)英文版

注意:DS1302 内部有一个写保护寄存器,在向 DS1302 写入数据前需要先关闭写保护,
写完再开启写保护。

21.1.5 相关资料

实物图、原理图、封装

21.2 需求描述

将时间信息和温度信息实时地显示在 OLED 上,如下图所示。

21.3 硬件设计

21.3.1 硬件原理图

21.4 软件设计

1)拷贝 OLED 和 18B20 相关代码

2)Int_DS1302.h

#ifndef __INT_DS1302_H__
#define __INT_DS1302_H__
#include "Util.h"
#include <STC89C5xRC.H>
typedef struct
{
    u8 second;
    u8 minute;
    u8 hour;
    u8 day;
    u8 month;
    u8 year;
    u8 day_of_week;
} Struct_Date;

void Int_DS1302_Init(void);
void Int_DS1302_SetDate(Struct_Date *p_st_date);
void Int_DS1302_GetDate(Struct_Date *p_st_date);
#endif /* __INT_DS1302_H__ */

3)Int_DS1302.c

#include "Int_DS1302.h"
#define SCLK P37
#define IO P40
#define CE P41
#define SECOND 0x80
#define MINUTE 0x82
#define HOUR 0x84
#define DAY 0x86
#define MONTH 0x88
#define DAY_OF_WEEK 0x8A
#define YEAR 0x8C
#define WP 0x8E
void Int_DS1302_Init(void)
{
    SCLK = 0;
    IO = 0;
    CE = 0;
}
static void Int_DS1302_WriteByte(u8 byte)
{
    u8 i;
    for (i = 0; i < 8; i++) {
    IO = byte & 0x01;
    SCLK = 1;
    SCLK = 0;
    byte >>= 1;
    }
}
static u8 Int_DS1302_ReadByte()
{
    u8 i, byte = 0;
    for (i = 0; i < 8; i++) {
        byte >>= 1;
        if (IO == 1) {
            byte = byte | 0x80;
        }
        SCLK = 1;
        SCLK = 0;
    }
    return byte;
}
static void Int_DS1302_SetRegister(u8 addr, u8 byte)
{
    CE = 1;
    Int_DS1302_WriteByte(addr);
    Int_DS1302_WriteByte(byte);
    CE = 0;
}
static u8 Int_DS1302_GetRegister(u8 addr)
{
    u8 byte;
    CE = 1;
    Int_DS1302_WriteByte(addr | 1);
    byte = Int_DS1302_ReadByte();
    CE = 0;
    return byte;
}
void Int_DS1302_SetDate(Struct_Date *p_st_date)
{
    u8 temp;
    // 关闭写保护
    Int_DS1302_SetRegister(WP, 0x00);
    // 设置秒
    temp = (p_st_date->second % 10) | ((p_st_date->second / 10) << 4);
    Int_DS1302_SetRegister(SECOND, temp);
    // 设置分钟
    temp = (p_st_date->minute % 10) | ((p_st_date->minute / 10) << 4);
    Int_DS1302_SetRegister(MINUTE, temp);
    // 设置小时
    temp = (p_st_date->hour % 10) | ((p_st_date->hour / 10) << 4);
    Int_DS1302_SetRegister(HOUR, temp);
    // 设置日
    temp = (p_st_date->day % 10) | ((p_st_date->day / 10) << 4);
    Int_DS1302_SetRegister(DAY, temp);
    // 设置月
    temp = (p_st_date->month % 10) | ((p_st_date->month / 10) << 4);
    Int_DS1302_SetRegister(MONTH, temp);
    // 设置年
    temp = (p_st_date->year % 10) | ((p_st_date->year / 10) << 4);
    Int_DS1302_SetRegister(YEAR, temp);
    // 设置星期
    Int_DS1302_SetRegister(DAY_OF_WEEK, p_st_date->day_of_week % 10);
    // 开启写保护
    Int_DS1302_SetRegister(WP, 0x80);
}
void Int_DS1302_GetDate(Struct_Date *p_st_date)
{
    u8 temp;
    // 获取秒
    temp = Int_DS1302_GetRegister(SECOND);
    p_st_date->second = (temp >> 4) * 10 + (temp & 0x0F);
    temp = Int_DS1302_GetRegister(MINUTE);
    p_st_date->minute = (temp >> 4) * 10 + (temp & 0x0F);
    temp = Int_DS1302_GetRegister(HOUR);
    p_st_date->hour = (temp >> 4) * 10 + (temp & 0x0F);
    temp = Int_DS1302_GetRegister(DAY);
    p_st_date->day = (temp >> 4) * 10 + (temp & 0x0F);
    temp = Int_DS1302_GetRegister(MONTH);
    p_st_date->month = (temp >> 4) * 10 + (temp & 0x0F);
    temp = Int_DS1302_GetRegister(YEAR);
    p_st_date->year = (temp >> 4) * 10 + (temp & 0x0F);
    temp = Int_DS1302_GetRegister(DAY_OF_WEEK);
    p_st_date->day_of_week = (temp >> 4) * 10 + (temp & 0x0F);
}




4)Main.c

#include <STDIO.H>
#include "Int_DS1302.h"
#include "Int_Oled.h"
#include "Int_DS18B20.h"
code char *WEEK_NAME[] = {
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
"Sun"};

void main()
{
    u8 str[17];
    u8 temperature;
    Struct_Date st_date;
    st_date.year = 23;
    st_date.month = 12;
    st_date.day = 29;
    st_date.day_of_week = 5;
    st_date.hour = 11;
    st_date.minute = 32;
    st_date.second = 00;
    // 初始化时钟并设置时间
    Int_DS1302_Init();
    Int_Oled_Init();
    Int_DS1302_SetDate(&st_date);
    Int_Oled_Clear();
    while (1) {
        Int_DS1302_GetDate(&st_date);
        temperature = Int_DS18B20_GetTemperature();
        sprintf(str, "20%02d/%02d/%02d %s",
            (int)st_date.year,
            (int)st_date.month,
            (int)st_date.day,
            WEEK_NAME[st_date.day_of_week - 1]);
    Int_Oled_ShowStr(0, 0, str);
    sprintf(str, "%02d:%02d:%02d Temp:%d",
        (int)st_date.hour,
        (int)st_date.minute,
        (int)st_date.second,
        (int)temperature);
        Int_Oled_ShowStr(0, 1, str);
        Delay1ms(50);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2376386.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】17. 多态

上一章节中我们讲了C三大特性的继承&#xff0c;这一章节我们接着来讲另一个特性——多态 1. 多态的概念 多态(polymorphism)的概念&#xff1a;通俗来说&#xff0c;就是多种形态。多态分为编译时多态(静态多态)和运行时多态(动态多态)&#xff0c;这里我们重点讲运行时多态…

家用或办公 Windows 电脑玩人工智能开源项目配备核显的必要性(含 NPU 及显卡类型补充)

一、GPU 与显卡的概念澄清 首先需要明确一个容易误解的概念&#xff1a;GPU 不等同于显卡。 显卡和GPU是两个不同的概念。 【概念区分】 在讨论图形计算领域时&#xff0c;需首先澄清一个常见误区&#xff1a;GPU&#xff08;图形处理单元&#xff09;与显卡&#xff08;视…

实现一个简单的 TCP 客户端/服务器

注意&#xff1a; TCP 三次握手建立连接建立连接后&#xff0c;TCP 提供全双工的通信服务&#xff0c;也就是在同一个连接中&#xff0c;通信双方 可以在同一时刻同时写数据&#xff0c;相对的概念叫做半双工&#xff0c;同一个连接的同一时刻&#xff0c;只能由一方来写数据T…

对抗帕金森:在疾病阴影下,如何重掌生活主动权?

帕金森病&#xff0c;一种影响全球超 1000 万人的神经退行性疾病&#xff0c;正无声地改变着患者的生活轨迹。随着大脑中多巴胺分泌减少&#xff0c;患者逐渐出现肢体震颤、肌肉僵硬、步态迟缓等症状&#xff0c;甚至连扣纽扣、端水杯这类日常动作都变得艰难。更棘手的是&#…

鸿蒙 UIAbility组件与UI的数据同步和窗口关闭

使用 EventHub 进行数据通信 Stage模型概念图 根据 Stage 模型概念图 UIAbility 先于 ArkUI Page 创建 所以&#xff0c;事件要先 .on 订阅 再 emit 发布 假如现在有页面 Page1 和他的 UIAbility // src/main/ets/page1ability/Page1Ability.ets onCreate(want: Want, laun…

Vue3学习(组合式API——计算属性computed详解)

目录 一、计算属性computed。 Vue官方提供的案例。(普通写法与计算属性写法) 使用计算属性computed重构——>简化描述响应式状态的复杂逻辑。 &#xff08;1&#xff09;计算属性computed小案例。 <1>需求说明。&#xff08;筛选原数组——>得新数组&#xff09; &…

Android Studio 模拟器配置方案

Android Studio 模拟器配置方案 1.引言2.使用Android Studio中的模拟器3.使用国产模拟器1.引言 前面介绍【React Native基础环境配置】的时候需要配置模拟器,当时直接使用了USB调试方案,但是有些时候可能不太方便连接手机调试,比如没有iPhone调不了ios。接下来说明另外两种可…

k8s中ingress-nginx介绍

1. 介绍 Ingress是一种Kubernetes资源&#xff0c;用于将外部流量路由到Kubernetes集群内的服务。与NodePort相比&#xff0c;它提供了更高级别的路由功能和负载平衡&#xff0c;可以根据HTTP请求的路径、主机名、HTTP方法等来路由流量。可以说Ingress是为了弥补NodePort在流量…

字节DeerFlow开源框架:多智能体深度研究框架,实现端到端自动化研究流程

&#x1f98c; DeerFlow DeerFlow&#xff08;Deep Exploration and Efficient Research Flow&#xff09;是一个社区驱动的深度研究框架&#xff0c;它建立在开源社区的杰出工作基础之上。目标是将语言模型与专业工具&#xff08;如网络搜索、爬虫和Python代码执行&#xff0…

算法第十八天|530. 二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先

530. 二叉搜索树的最小绝对差 题目 思路与解法 第一想法&#xff1a; 一个二叉搜索树的最小绝对差&#xff0c;从根结点看&#xff0c;它的结点与它的最小差值一定出现在 左子树的最右结点&#xff08;左子树最大值&#xff09;和右子树的最左结点&#xff08;右子树的最小值…

微服务调试问题总结

本地环境调试。 启动本地微服务&#xff0c;使用公共nacos配置。利用如apifox进行本地代码调试解决调试问题。除必要的业务微服务依赖包需要下载到本地。使用mvn clean install -DskipTests进行安装启动前选择好profile环境进行启动&#xff0c;启动前记得mvn clean清理项目。…

美SEC主席:探索比特币上市证券交易所

作者/演讲者&#xff1a;美SEC主席Paul S. Atkins 编译&#xff1a;Liam 5月12日&#xff0c;由美国SEC加密货币特别工作组发起的主题为《资产上链&#xff1a;TradFi与DeFi的交汇点》系列圆桌会议如期举行。 会议期间&#xff0c;现任美SEC主席Paul S. Atkins发表了主旨演讲。…

MySQL Join连接算法深入解析

引言 在关系型数据库中&#xff0c;Join操作是实现多表数据关联查询的关键手段&#xff0c;直接影响查询性能和资源消耗。MySQL支持多种Join算法&#xff0c;包括经典的索引嵌套循环连接&#xff08;Index Nested-Loop Join&#xff09;、块嵌套循环连接&#xff08;Block Nes…

http请求卡顿

接口有时出现卡顿&#xff0c;而且抓包显示有时tcp目标机器没有响应&#xff0c; 但nginx和java应用又没有错误日志&#xff0c;让人抓耳挠腮&#xff0c;最终还是请运维大哥帮忙&#xff0c;一顿操作后系统暂时无卡顿了&#xff0c;佩服的同时感觉疑惑到底调整了啥东…

vite+vue建立前端工程

​ 参考 开始 | Vite 官方中文文档 VUE教程地址 https://cn.vuejs.org/tutorial/#step-1 第一个工程 https://blog.csdn.net/qq_35221977/article/details/137171497 脚本 chcp 65001 echo 建立vite工程 set PRO_NAMEmy-vue-appif not exist %PRO_NAME% (call npm i…

vue使用路由技术实现登录成功后跳转到首页

文章目录 一、概述二、使用步骤安装vue-router在src/router/index.js中创建路由器&#xff0c;并导出在vue应用实例中使用router声明router-view标签&#xff0c;展示组件内容 三、配置登录成功后跳转首页四、参考资料 一、概述 路由&#xff0c;决定从起点到终点的路径的进程…

day20-线性表(链表II)

一、调试器 1.1 gdb&#xff08;调试器&#xff09; 在程序指定位置停顿 1.1.1 一般调试 gcc直接编译生成的是发布版&#xff08;Release&#xff09; gcc -g //-g调式版本&#xff0c;&#xff08;体积大&#xff0c;内部有源码&#xff09;&#xff08;DeBug&#…

HTTP 连接复用机制详解

文章目录 HTTP 连接复用机制详解为什么需要连接复用&#xff1f;连接复用的实现方式HTTP/1.1 的 Keep-AliveHTTP/2 多路复用 HTTP/1.1 的队头阻塞问题 HTTP 连接复用机制详解 HTTP 连接复用是 HTTP/1.1 及更高版本中的核心优化机制&#xff0c;旨在减少 TCP 连接建立和关闭的开…

网络协议分析 实验六 TCP和端口扫描

文章目录 实验6.1 TCP(Transfer Control Protocol)练习二 利用仿真编辑器编辑并发送TCP数据包实验6.2 UDP端口扫描实验6.3 TCP端口扫描练习一 TCP SYN扫描练习二 TCP FIN扫描 实验6.1 TCP(Transfer Control Protocol) 建立&#xff1a;syn,syn ack,ack 数据传送&#xff1a;tcp…

Spring Web MVC————入门(2)

1&#xff0c;请求 我们接下来继续讲请求的部分&#xff0c;上期将过很多了&#xff0c;我们来给请求收个尾。 还记得Cookie和Seesion吗&#xff0c;我们在HTTP讲请求和响应报文的时候讲过&#xff0c;现在再给大家讲一遍&#xff0c;我们HTTP是无状态的协议&#xff0c;这次的…