200 lines
3.8 KiB
C
200 lines
3.8 KiB
C
/********************************************************
|
||
*
|
||
* @file ds18b20.c
|
||
* @brief ds18b20驱动
|
||
* @author Mculover666
|
||
* @date 2020/08/29
|
||
* @note 此驱动中us级延时使用DWT
|
||
*
|
||
********************************************************/
|
||
|
||
#include "ds18b20.h"
|
||
#include <stdio.h>
|
||
|
||
/**
|
||
* @brief 发送复位信号
|
||
* @param none
|
||
* @retval none
|
||
*/
|
||
static void DS18B20_Send_Reset_Single(void)
|
||
{
|
||
DS18B20_OutPut_Mode();
|
||
|
||
/* 拉低总线 480 - 960 us*/
|
||
DS18B20_Out(0);
|
||
DS18B20_Delay_us(750);
|
||
|
||
/* 释放总线 15 - 60 us */
|
||
DS18B20_Out(1);
|
||
DS18B20_Delay_us(15);
|
||
}
|
||
|
||
/**
|
||
* @brief 检测DS18B20存在脉冲
|
||
* @param none
|
||
* @retval 0 DS18B20设备正常
|
||
* @retval 1 DS18B20设备响应复位信号失败
|
||
* @retval 2 DS18B20设备释放总线失败
|
||
*/
|
||
static uint8_t DS18B20_Check_Ready_Single(void)
|
||
{
|
||
uint8_t cnt = 0;
|
||
|
||
/* 1.检测存在脉冲 */
|
||
DS18B20_InPut_Mode();
|
||
|
||
//等待DS18B20 拉低总线 (60~240 us 响应复位信号)
|
||
while (DS18B20_In() && cnt < 240) {
|
||
DS18B20_Delay_us(1);
|
||
cnt++;
|
||
}
|
||
|
||
if (cnt > 240) {
|
||
return 1;
|
||
}
|
||
|
||
/* 2.检测DS18B20是否释放总线 */
|
||
cnt = 0;
|
||
DS18B20_InPut_Mode();
|
||
|
||
//判断DS18B20是否释放总线(60~240 us 响应复位信号之后会释放总线)
|
||
while ((!DS18B20_In()) && cnt<240) {
|
||
DS18B20_Delay_us(1);
|
||
cnt++;
|
||
}
|
||
|
||
if (cnt > 240) {
|
||
return 2;
|
||
} else {
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 检测DS18B20设备是否正常
|
||
* @param none
|
||
* @retval 0 DS18B20设备正常
|
||
* @retval 1 DS18B20设备响应复位信号失败
|
||
* @retval 2 DS18B20设备释放总线失败
|
||
*/
|
||
static uint8_t DS18B20_Check_Device(void)
|
||
{
|
||
/*1.主机发送复位信号*/
|
||
DS18B20_Send_Reset_Single();
|
||
|
||
/*2.检测存在脉冲*/
|
||
return DS18B20_Check_Ready_Single();
|
||
}
|
||
/**
|
||
* @brief DS18B20初始化
|
||
* @param none
|
||
* @retval none
|
||
*/
|
||
void DS18B20_Init(void)
|
||
{
|
||
/* 1.DS18B20控制引脚初始化 */
|
||
//在main函数中已经初始化,不需要再次重复。
|
||
|
||
/*2.检测DS18B20设备是否正常*/
|
||
switch (DS18B20_Check_Device()) {
|
||
case 0:
|
||
printf("DS18B20_Init OK!\n");
|
||
break;
|
||
case 1:
|
||
printf("DS18B20设备响应复位信号失败!\n");
|
||
break;
|
||
case 2:
|
||
printf("DS18B20设备释放总线失败!\n");
|
||
break;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 向DS18B20写一个字节
|
||
* @param cmd 要写入的字节
|
||
* @retval none
|
||
*/
|
||
static uint8_t DS18B20_Write_Byte(uint8_t cmd)
|
||
{
|
||
uint8_t i = 0;
|
||
|
||
/* 1. 设置总线为输出模式 */
|
||
DS18B20_OutPut_Mode();
|
||
|
||
/* 2. 发送数据,低位在前 */
|
||
for (i = 0; i < 8; i++) {
|
||
DS18B20_Out(0);
|
||
DS18B20_Delay_us(2);
|
||
DS18B20_Out(cmd & 0x01);
|
||
DS18B20_Delay_us(60);
|
||
DS18B20_Out(1);
|
||
cmd >>= 1;
|
||
DS18B20_Delay_us(2);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 从DS18B20读一个字节
|
||
* @param none
|
||
* @retval 读取到的一个字节数据
|
||
*/
|
||
uint8_t DS18B20_Read_Byte(void)
|
||
{
|
||
uint8_t i = 0;
|
||
uint8_t data = 0;
|
||
|
||
/* 读取数据 */
|
||
for (i =0; i < 8; i++) {
|
||
DS18B20_OutPut_Mode();
|
||
DS18B20_Out(0);
|
||
DS18B20_Delay_us(2);
|
||
DS18B20_Out(1);
|
||
|
||
DS18B20_InPut_Mode();
|
||
DS18B20_Delay_us(10);
|
||
data >>= 1 ;
|
||
if (DS18B20_In()) {
|
||
data |= 0x80;
|
||
}
|
||
|
||
DS18B20_Delay_us(60);
|
||
DS18B20_Out(1);
|
||
}
|
||
|
||
return data;
|
||
}
|
||
|
||
/**
|
||
* @brief 从DS18B20读取一次数据
|
||
* @param none
|
||
* @retval 读取到的温度数据
|
||
* @note 适用于总线上只有一个DS18B20的情况
|
||
*/
|
||
uint16_t DS18B20_Read_Temperature(void)
|
||
{
|
||
uint16_t temp = 0;
|
||
uint8_t temp_H, temp_L;
|
||
|
||
DS18B20_Check_Device();
|
||
|
||
DS18B20_Write_Byte(0xCC); //跳过ROM序列检测
|
||
DS18B20_Write_Byte(0x44); //启动一次温度转换
|
||
|
||
//等待温度转换完成
|
||
while (DS18B20_Read_Byte() != 0xFF);
|
||
|
||
DS18B20_Check_Device(); //必须,不能省略
|
||
|
||
DS18B20_Write_Byte(0xCC); //跳过ROM序列检测
|
||
DS18B20_Write_Byte(0xBE); //读取温度
|
||
|
||
temp_L = DS18B20_Read_Byte(); //读取的温度低位数据
|
||
temp_H = DS18B20_Read_Byte(); //读取的温度高位数据
|
||
temp = temp_L | (temp_H << 8); //合成温度
|
||
|
||
return temp;
|
||
|
||
}
|