STC8H开发(十一): GPIO单线驱动多个DS18B20数字温度计

目录

DS18B20

关于DS18B20的详细介绍说明已经转移到这组文章下

使用STC8H驱动DS18B20

接线

普通模式

GND  -> GND
P35  -> DQ
3.3V -> VDD

寄生供电模式

这个模式下

  • VDD和GND都要接地
  • DQ 需要用5K电阻上拉. STC8H可以通过寄存器进行设置.
  • 建议使用5V电压供电, 使用3.3V供电时, 可能会出现测温读数不更新的情况
GND  -> GND -> VDD
P35  -> DQ
5V

寄生模式下, 发起温度转换后不能查询完成情况, 如果查询, 会导致测温不成功, 读数不变, 需要等待一个合理的时间, 例如1000毫秒, 然后直接读出温度值.

代码

代码可以从GitHub或者Gitee下载

定义 IO

只需要一个Pin, 在STC8H中, 注意要将其设置为上拉, 否则读出来的全是0

#define DS18B20_DQ           P35
#define DS18B20_DQ_PULLUP()  GPIO_SetPullUp(GPIO_Port_3, GPIO_Pin_5, HAL_State_ON)
#define DS18B20_DQ_INPUT()   GPIO_P3_SetMode(GPIO_Pin_5, GPIO_Mode_Input_HIP)
#define DS18B20_DQ_OUTPUT()  GPIO_P3_SetMode(GPIO_Pin_5, GPIO_Mode_InOut_OD)
#define DS18B20_DQ_LOW()     DS18B20_DQ=RESET
#define DS18B20_DQ_HIGH()    DS18B20_DQ=SET

IO 读写

读一个bit和一个byte

__BIT DS18B20_ReadBit(void)
{
    __BIT b = RESET;

    /* Line low */
    DS18B20_DQ = RESET;
    DS18B20_DQ_OUTPUT();
    SYS_DelayUs(2);

    /* Release line */
    DS18B20_DQ_INPUT();
    SYS_DelayUs(10);

    /* Read line value */
    if (DS18B20_DQ) {
        /* Bit is HIGH */
        b = SET;
    }

    /* Wait 50us to complete 60us period */
    SYS_DelayUs(50);
    
    /* Return bit value */
    return b;
}

uint8_t DS18B20_ReadByte(void)
{
    uint8_t i = 8, byte = 0;
    while (i--) 
    {
        byte >>= 1;
        byte |= (DS18B20_ReadBit() << 7);
    }
    return byte;
}

写一个bit和一个byte

void DS18B20_WriteBit(__BIT b)
{
    if (b)
    {
        /* Set line low */
        DS18B20_DQ = RESET;
        DS18B20_DQ_OUTPUT();
        SYS_DelayUs(10);

        /* Bit high */
        DS18B20_DQ_INPUT();
        
        /* Wait for 55 us and release the line */
        SYS_DelayUs(55);
        DS18B20_DQ_INPUT();
    } 
    else 
    {
        /* Set line low */
        DS18B20_DQ = RESET;
        DS18B20_DQ_OUTPUT();
        SYS_DelayUs(65);
        
        /* Bit high */
        DS18B20_DQ_INPUT();
        
        /* Wait for 5 us and release the line */
        SYS_DelayUs(5);
        DS18B20_DQ_INPUT();
    }
}

void DS18B20_WriteByte(uint8_t byte)
{
    uint8_t i = 8;
    /* Write 8 bits */
    while (i--) 
    {
        /* LSB bit is first */
        DS18B20_WriteBit(byte & 0x01);
        byte >>= 1;
    }
}

单个 DS18B20 的场景

初始化, 注意设置上拉, 以及输入和输出模式的切换

void DS18B20_Init(void)
{
    DS18B20_DQ_PULLUP();
    DS18B20_DQ_OUTPUT();
    DS18B20_DQ = SET;
    SYS_DelayUs(1000);
    DS18B20_DQ = RESET;
    SYS_DelayUs(1000);
    DS18B20_DQ = SET;
    SYS_DelayUs(2000);
}

读取温度, 这样读出的值并非温度值, 需要根据上面的温度转换, 乘以对应的温度单元值(默认为0.0625摄氏度)

// 发起转换
DS18B20_StartAll();
// 读取总线, 当转换完成时会变为高电平
while (!DS18B20_AllDone())
{
    UART1_TxChar('.');
    SYS_Delay(1);
}

// 重置总线
DS18B20_Reset();
// 跳过ROM选择
DS18B20_WriteByte(ONEWIRE_CMD_SKIPROM);
// 写入读取暂存器指令
DS18B20_WriteByte(ONEWIRE_CMD_RSCRATCHPAD);

// 读出9个字节的数据
for (i = 0; i < 9; i++) 
{
    /* Read byte by byte */
    data[i] = DS18B20_ReadByte();
}
// 温度值位于第1和第2个字节
temperature = data[1];
temperature = temperature << 8 | data[0];

读取ROM

// 重置总线
DS18B20_Reset();
// 写入读取ROM指令, 注意这个命令不能用于连接多个设备的总线, 否则结果读数是无意义的
DS18B20_WriteByte(ONEWIRE_CMD_READROM);
// 读出数据
for (i = 0; i < 8; i++) 
{
    *buf++ = DS18B20_ReadByte();
}

多个 DS18B20 的场景

指定设备地址, 读取温度

// 重置总线
DS18B20_Reset();
// 根据地址选择设备
DS18B20_Select(addr);
// 对选中的设备, 发起转换
DS18B20_WriteByte(DS18B20_CMD_CONVERTTEMP);

// 等待转换结束

// 重置总线
DS18B20_Reset();
// 根据地址选择设备
DS18B20_Select(addr);
// 写入读取暂存器指令
DS18B20_WriteByte(ONEWIRE_CMD_RSCRATCHPAD);
// 读取数据
for (i = 0; i < 9; i++) 
{
    *buf++ = DS18B20_ReadByte();
}

参考

posted on 2022-06-04 22:59  Milton  阅读(1373)  评论(0编辑  收藏  举报

导航