当前位置: 首页 > article >正文

wire单总线通信

 一、单总线介绍

        1-Wire(单总线)是一种由Maxim Integrated(原Dallas Semiconductor)开发的串行通信协议,它允许通过单根信号线进行数据传输,同时传输时钟和数据,实现双向通信。这种协议具有节省I/O口资源、结构简单、成本低廉、便于总线扩展和维护等优点,广泛应用于温度传感器、湿度传感器、逻辑器件、时钟芯片等多种传感器和存储器中

 二、DS18B20温度传感器

        DS18B20采用达拉斯独家的1-Wire总线协议,使用一个控制信号实现总线通信。控制线需要一个弱上拉电阻,因为所有设备都通过三态或漏极端口(DS18B20中的DQ引脚)连接到总线。在这个总线系统中,微处理器(主设备)使用每个设备唯一的64位码来标识和寻址总线上的设备。因为每个设备都有一个唯一的码,所以可以在一个总线上寻址的设备数量实际上是无限的。

        DS18B20的另一个特点是能够在没有外部电源的情况下运行。当总线为高电平时,电源通过DQ引脚通过1-Wire上拉电阻供电。高总线信号还为内部电容器(CPP)充电,然后在总线为低电平时为器件供电。这种从1-Wire总线获取电源的方法被称为“寄生电源”。作为替代方案,DS18B20

也可以由VDD上的外部电源供电

三、MEASURING TEMPERATURE(温度测量)
        DS18B20的核心功能是其直接数字温度传感器。温度传感器的分辨率可由用户配置为9、10、11或12位,分别对应0.5℃、0.25℃、0.125℃和0.0625℃的增量。上电时的默认分辨率为12位DS18B20在低功耗空闲状态下上电;要启动温度测量和A到D转换,主机必须发出转换T[44h]命令。转换后,产生的热数据存储在暂存器中的2字节温度寄存器中,DS18B20返回到空闲状态。

        温度数据在温度寄存器中存储为16位符号扩展的二进制补码。符号位(S)指示温度是正的还是负的:对于正数S=0,对于负数S=1。如果DS18B20配置为12位分辨率,温度寄存器中的所有位都将包含有效数据。

温度寄存器上电复位值为+85℃

对于11位分辨率,位0是未定义的。对于10位分辨率,位1和0是未定义的,对于9位分辨率,位2、1和0是未定义的。表2给出了12位分辨率转换的数字输出数据和相应温度读数的示例

三、DS18B20事务序列


The transaction sequence for accessing the DS18B20 is as follows:(访问DS18B20的事务顺序如下:)

  • Step 1. Initialization(初始化)
  • 1-Wire总线上的所有事务都从初始化序列开始。初始化序列由总线主站发送的复位脉冲和从站发送的存在脉冲组成。存在脉冲让总线主站知道从设备(如DS18B20)在总线上并且准备好操作
  • Step 2. ROM Command(ROM命令)
  • 总线主站检测到存在脉冲后,它可以发出ROM命令。这些命令对每个从设备的唯一64位ROM码进行操作,如果1-Wire总线上存在许多设备,则允许
  • 主站单独选择特定设备。
  • Step 3. DS18B20 Function Command(功能命令)
  • 总线主站使用ROM命令寻址它希望与之通信的DS18B20后,主站可以发出DS18B20功能命令之一。
CONVERT T [44h]       

        此命令启动单次温度转换。转换后,生成的热数据存储在暂存器中的2字节温度寄存器中,DS18B20返回低功耗空闲状态。

READ SCRATCHPAD [BEh]

        此命令允许主机读取暂存器的内容。数据传输从字节0的最低有效位开始,并继续通过暂存器,直到读取第9个字节(字节8-CRC)。如果只需要部分暂存器数据,主机可以随时发出重置以终止读取。

四、DS18B20操作时序

INITIALIZATION PROCEDURE: RESET AND PRESENCE

PULSES

        与DS18B20的所有通信都以初始化序列开始,该序列由主设备的复位脉冲和DS18B20的存在脉冲组成。当DS18B20响应复位发送存在脉冲时,它向主设备表明它在总线上并准备好操作

        在初始化序列中,总线主控器通过将1-Wire总线拉低至少480us来发送复位脉冲。然后总线主控器释放总线并进入接收模式(RX)。当总线释放时,5k上拉电阻将1-Wire总线拉高。当DS18B20检测到这种上升沿时,它等待15us到60us,然后通过将1-Wire总线拉低60us到240us来发送存在脉冲。

WRITE TIME SLOTS

        有两种类型的写入时间槽:“Write 1”时间槽和“Write 0”时间槽。总线主控器使用“Write 1”时间槽将逻辑1写入DS18B20,使用“Write0”时间槽将逻辑0写入DS18B20。所有写入时间槽的最小持续时间为60微秒,相邻写入槽之间的最小恢复时间为1微秒。两种类型的写入时间槽均由主控器将1-Wire总线拉低来启动。

        要生成一个Write 1时间槽,在将1-Wire总线拉低之后,总线主控器必须在15微秒内释放1-Wire总线。当总线被释放时,5k的上拉电阻会将总线拉高。要生成一个Write 0时间槽,在将1-Wire总线拉低之后,总线主控器必须在整个时间槽内(至少60微秒)继续将总线保持在低电平状态。

        DS18B20在主机启动写入时间槽后的15us到60us的窗口中对1-Wire总线进行采样。如果在采样窗口中总线为高电平,则向DS18B20写入1。如果总线为低电平,则向DS18B20写入0。

READ TIME SLOTS

        DS18B20只有在主控机发出读取时间槽时才能向主控机传输数据。因此,主控机必须在发出读取暂存器[BEh]或读取电源[B4h]命令后立即生成读取时间槽,以便DS18B20能够提供所请求的数据。此外,主控机可以在发出转换T[44h]或召回E2[B8h]命令后生成读取时间槽,以找出操作的状态,如DS18B20功能命令部分所述。所有读取时间槽的持续时间必须至少为60us,时间槽之间的恢复时间至少为1us。读取时间槽由主设备将1-Wire总线拉低至少1us,然后释放总线启动。

        当主机启动读取时间槽后,DS18B20将开始在总线上传输1或0。DS18B20通过将总线保持在高电平来传输1,并通过将总线拉低来传输0。当传输0时,DS18B20将在时间槽结束时释放总线,总线将被上拉电阻拉回其高空闲状态。DS18B20的输出数据在启动读取时间槽的下降沿后对15us有效。因此,主机必须释放总线,然后从时间槽开始在15us内对总线状态进行采样。

五、GPIO控制器相关操作函数接口
 

 ds18b20.h

#ifndef __DS18B20_HEAD__
#define __DS18B20_HEAD__
#include <stdio.h>
#include <stdint.h>
#include "../../include/imx6ull.h"
#include "../gpt/gpt.h"
#include "../uart/uart.h"
#define  DS18B20_LOW_LEVEL 0
#define  DS18B20_HIGH_LEVEL 1
#define DQ_OUT_MODE() (GPIO5->GDIR |= (0x1 << 2))
#define DQ_IN_MODE() (GPIO5->GDIR &= ~(0x1<<2))
extern void ds18b20_gpio_init();
extern uint_fast8_t ds18b20_read_level();
extern void ds18b20_write_bit(uint_fast8_t bit);
extern void ds18b20_write_byte(uint_fast8_t data);
extern uint_fast8_t ds18b20_read_bit();
extern uint_fast8_t ds18b20_read_byte();
extern int ds18b20_detect();
extern void ds18b20_read_roomcode();
extern void ds18b20_collect_temperature_data();
extern void test();
//输出电平状态
#define DQ_OUTPUT_LEVEL(level)   do {GPIO5->DR &=~(0x1<<2);GPIO5->DR |= (level << 2);}while (0)
#endif // !__DS18B20_HEAD__

 ds18b20.c

#include "ds18b20.h"
// 管脚的初始化
void ds18b20_gpio_init()
{
    // 管脚初始化
    //101 ALT5 — Slect mux mode: ALT5 mux port, GPIO5_IO02 of instance - gpio5
    IOMUXC_SW_MUX_CTL_PAD_GPIO5_IO02 &= ~(0xf << 0);
    IOMUXC_SW_MUX_CTL_PAD_GPIO5_IO02 |= (0x5 << 0);
}
// 读取DQ上的电平状态
uint_fast8_t ds18b20_read_level()
{
    uint_fast8_t level;
    // 从GPIO5->PSR中进行读取
    level = GPIO5->PSR & (0x1 << 2);
    return level ? 1 : 0;
}
void ds18b20_write_bit(uint_fast8_t bit)
{
    // 先拉低然后再读取数据
    /*DQ_OUT_MODE(有两种类型的写入时间槽:“Write 1”时间槽和“Write 0”时间槽。
总线主控器使用“Write 1”时间槽将逻辑1写入DS18B20,使用“Write
0”时间槽将逻辑0写入DS18B20。);*/
    if (bit)
    {
        DQ_OUT_MODE();
        DQ_OUTPUT_LEVEL(DS18B20_LOW_LEVEL);
        usgpt_deplay(5);
        DQ_IN_MODE();
        usgpt_deplay(70);
    }
    else
    {
        DQ_OUT_MODE();
        DQ_OUTPUT_LEVEL(DS18B20_LOW_LEVEL);
        usgpt_deplay(80);
        DQ_IN_MODE();
        usgpt_deplay(40);
    }
}
void ds18b20_write_byte(uint_fast8_t data)
{
    int i;
    for (i = 0; i < 8; i++)
    {
        ds18b20_write_bit((data >> i) & 1);
    }
}
uint_fast8_t ds18b20_read_bit()
{
    DQ_OUT_MODE();
    DQ_OUTPUT_LEVEL(DS18B20_LOW_LEVEL);
    usgpt_deplay(3);
    DQ_IN_MODE();
    usgpt_deplay(5);
    uint_least8_t level = ds18b20_read_level();
    usgpt_deplay(60);
    return level;
}
uint_fast8_t ds18b20_read_byte()
{
    uint_least8_t data = 0;
    int i;
    for (i = 0; i < 8; i++)
    {
        uint_least8_t bit = ds18b20_read_bit();
        if (bit)
        {
            data |= (0x1 << i);
        }
    }
    return data;
}
// 检测DS18B20温度传感器是否存在于1-Wire总线的函数ds18b20_detect()。
int ds18b20_detect()
{
    DQ_OUT_MODE();
    // 拉到低电平
    DQ_OUTPUT_LEVEL(DS18B20_LOW_LEVEL);
    usgpt_deplay(500);
    // 转换模式后自动拉高
    DQ_IN_MODE();
    usgpt_deplay(100);
    uint_fast8_t level = ds18b20_read_level();
    if (level)
    {
        uart_printf("failure\r\n");
        return -1;
    }
    else
    {
        uart_printf("success\r\n");
        usgpt_deplay(500);
        return 0;
    }
}
void test(){
    ds18b20_gpio_init();
    ds18b20_detect();
}

// 读取ds18b20的room码
void ds18b20_read_roomcode()
{
    // 管脚初始化
    ds18b20_gpio_init();
    int ret;
    // 检测i_write是否存在
    ret = ds18b20_detect();
    if (ret == -1)
    {
        return;
    }
    ds18b20_write_byte(0x33);
    uint_fast8_t id[8];
    int i;
    for (i = 0; i < 8; i++)
    {
        *(id + i) = ds18b20_read_byte();
    }
    // family code
    uart_printf("family code:%4x\r\n", *id);
    // serial number
    int i1;
    uart_printf("serial number:");
    for (i1 = 1; i1 < 7; i1++)
    {
        uart_printf("CRC:%4x\r\n", *(id + 7));
    }
}
// 采集温度
void ds18b20_collect_temperature_data()
{
    while (1)
    {
        // 管脚初始化
        ds18b20_gpio_init();
        int ret1;
        ret1 = ds18b20_detect();
        if (ret1 == -1)
        {
            return;
        }
        ds18b20_write_byte(0xcc);
        ds18b20_write_byte(0x44);
        sgpt_deplay(1);
        // 读取温度值
        ds18b20_gpio_init();
        int ret;
        ret = ds18b20_detect();
        if (ret == -1)
        {
            return;
        }
        // 主机可以通过发出SNIP ROM[CCH]命令后
        ds18b20_write_byte(0xcc);
        ds18b20_write_byte(0xBE);
        // 读取温度值
        uint_fast8_t temperature_lsb = ds18b20_read_byte();
        uint_fast8_t temperature_msb = ds18b20_read_byte();
        uart_printf("low:%x,high:%x\r\n", temperature_lsb, temperature_msb);
        // 温度转换
        // 先处理整数的情况
        uint_fast8_t integer_part = (temperature_msb << 4) | (temperature_lsb >> 4);
        // 处理符号位
        uint_fast8_t signal = integer_part & (0x1 << 7);
        if (signal)
        {
            integer_part = ~integer_part;
        }
        // 处理小数部分
        uint_fast8_t decimal_part = temperature_lsb & 0xf;
        if (signal)
        {
            decimal_part = ((~decimal_part) & 0xf) + 1;
        }
        // 扩大了1000倍
        decimal_part *= 625;
        // 打印温度
        if (signal)
        {
        }
        else
        {
            uart_printf("temperature:%d.%d\r\n", integer_part, decimal_part);
        }
    }
}

 

  • 这是本人的学习笔记不是获利的工具,小作者会一直写下去,希望大家能多多监督
  • 文章会每攒够两篇进行更新发布(受平台原因,也是希望能让更多的人看见)
  • 感谢各位的阅读希望我的文章会对诸君有所帮助

http://www.kler.cn/a/461811.html

相关文章:

  • 使用 httputils + chronicle-bytes 实现金融级 java rpc
  • cka考试-02-节点维护
  • 高频java面试题
  • IDEA2023.1修改默认Maven配置
  • C语言面的向对象编程(OOP)
  • 前端编码技巧与规范
  • MySQL数据库笔记——多版本并发控制MVCC
  • 基于Java+Springboot+Vue开发的旅游景区管理系统,实习作品
  • LeetCode -Hot100 - 42. 接雨水
  • HTML5 评分星级组件
  • 【Pytorch实用教程】循环神经网络中使用dropout需要注意的问题
  • [江科大STM32] 第五集快速建立STM32工程模板——笔记
  • Spring-kafka快速Demo示例
  • css实现图片填充文字
  • MySQL数据库——多版本并发控制MVCC
  • Linux基础指令(下)
  • Oracle 的网络配置文件详解
  • 基于通用优化软件GAMS的数学建模和优化分析实践技术应用
  • 2 秒杀系统架构
  • Jenkins管理多版本python环境
  • 云效流水线使用Node构建部署前端web项目
  • 深入浅出:AWT事件监听器及其应用
  • git仓库上传
  • Spring Bean required a single bean, but 2 were found,发现多个 Bean
  • 深入浅出:事件监听中的适配器模式
  • 微信小程序调用 WebAssembly 烹饪指南