1 Star 0 Fork 2

zzsj / ds18b20

forked from sjzc-qwz / ds18b20 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
ds18b20.c 9.78 KB
一键复制 编辑 原始数据 按行查看 历史
Nixsawe 提交于 2022-01-09 16:03 . 修正部分注释内容
/**
* ds18b20.c - DS18B20 功能封装
* by Nixsawe
* 2022-1-5 ~ 2022-1-9
*
* 不支持寄生电源模式
*/
#include "ds18b20.h"
/*---------- 基本方法 ----------*/
// 传入 0 时延时 12 周期
// 基准延时 (11 + 6 * n) 个周期
// 11.0592MHz 晶振下 9216 个周期相当于 10ms
void delay(unsigned char n)
{
while(n --);
}
// 进行 CRC8 校验
// 返回计算得到的校验和,若最后一个字节的内容为校验和,则校验通过后本函数应返回 0
unsigned char crc8_check(unsigned char * bytes, unsigned char n)
{
unsigned char i, j, crc = 0;
for(i = 0; i < n; i ++)
{
crc ^= bytes[i];
for(j = 0; j < 8; j ++)
{
if(crc & 1)
{
crc = (crc >> 1) ^ 0x8C;
}
else
{
crc >>= 1;
}
}
}
return crc;
}
// 等待操作完成
// 某些操作提供进度指示,可以用这样的方法进行等待
unsigned char ds18b20_wait_finish(int wait_ms)
{
// 不断读 1 位数据,直到读到 1,或者超时返回
// 每一个循环约 1ms
do
{
// 延时约 936us
delay(142);
// 读操作大约 60us
if(ds18b20_read_bit())
{
// 转换完毕
return 1;
}
} while(-- wait_ms);
return 0;
}
// 将 DS18B20 复位
// 执行每个新的操作前,都需要一步复位操作
// 如果线上有设备存在(初始化成功),则返回 1,否则返回 0
unsigned char ds18b20_reset()
{
unsigned char ack;
// 拉低电平
DS18B20_DATA_IO = 0;
// 持续至少 480us
delay(72);
// 释放引脚
DS18B20_DATA_IO = 1;
// 等待 15us~60us
delay(5); // 约 44.5us
// 检测存在性
// 如果设备响应,这条线将在该时间段被拉低
ack = !DS18B20_DATA_IO;
delay(67);
return ack;
}
// 在总线上写 1 位数据
void ds18b20_write_bit(unsigned char dat)
{
// 拉低电平
DS18B20_DATA_IO = 0;
// 等待约 1us
_nop_();
if(dat & 1)
{
// 拉高/释放电平
DS18B20_DATA_IO = 1;
}
// 等待约 60us
delay(8); // 约 64us
// 拉高/释放电平
DS18B20_DATA_IO = 1;
}
// 在总线上读 1 位数据
unsigned char ds18b20_read_bit()
{
unsigned char dat;
// 拉低电平
DS18B20_DATA_IO = 0;
// 等待约 1us
_nop_();
// 释放电平
DS18B20_DATA_IO = 1;
// 读取电平
dat = !!DS18B20_DATA_IO;
// 等待约 60us
delay(7); // 约 57.5us
return dat;
}
// 写字节,先传输低位
void ds18b20_write_byte(unsigned char dat)
{
unsigned char i;
for(i = 0; i < 8; i ++)
{
ds18b20_write_bit(dat & 1);
dat >>= 1;
}
}
// 读字节,先传输低位
unsigned char ds18b20_read_byte()
{
unsigned char dat = 0, i;
for(i = 0; i < 8; i ++)
{
dat >>= 1;
if(ds18b20_read_bit())
dat |= 0x80;
}
return dat;
}
/*---------- ROM 命令 ----------*/
// 通过二分法学习/搜索总线上的设备 ROM 列表 (TODO)
// unsigned char ds18b20_search_rom()
// {}
// 获取总线上下一个设备的 ROM 编码 (TODO)
// unsigned char ds18b20_search_next()
// {}
// 使用 ROM 命令读 64 位的 ROM 编码
// 当总线上仅有一个设备时,读取设备的 ROM 编码
// 有多个设备时会导致冲突
// 读取的数据校验成功时返回 1,否则返回 0
unsigned char ds18b20_read_rom(DS18B20_ROM_CODE * rom)
{
unsigned char i;
// 写 Read ROM 命令
ds18b20_write_byte(DS18B20_CMD_READ_ROM);
// 读 64 位(8 字节)的 ROM 编码
for(i = 0; i < 8; i ++)
{
// 按字节读
rom -> rom_code[i] = ds18b20_read_byte();
}
// 对数据进行 CRC 校验,并返回校验结果
return !crc8_check(rom -> rom_code, 8);
}
// 根据 ROM 编码匹配设备
// 这个命令执行后,只有 ROM 编码完全匹配的设备会响应后续操作
void ds18b20_match_rom(DS18B20_ROM_CODE * rom)
{
unsigned char i;
// 写 Match ROM 命令
ds18b20_write_byte(DS18B20_CMD_MATCH_ROM);
// 写 64 位(8 字节)的 ROM 编码
for(i = 0; i < 8; i ++)
{
// 按字节写
ds18b20_write_byte(rom -> rom_code[i]);
}
}
// 跳过 ROM 匹配
// 这个命令执行后,所有设备都会同步响应后续操作
// 有些命令是可以多设备同时进行的,比如可让总线上所有设备同时地执行温度转换命令
void ds18b20_skip_rom()
{
// 写 Skip ROM 命令
ds18b20_write_byte(DS18B20_CMD_SKIP_ROM);
}
// 报警 ROM 搜索
// Alarm Search
// TODO
/*---------- 功能命令 ----------*/
// 进行温度转换
// 通知设备进行温度转换,设备将进行温度采样并结果存储在暂存器的温度寄存器中
// 温度转换的时间与采样精度(分辨率位数)有关
// 9-bit: <93.75ms
// 10-bit: <187.5ms
// 11-bit: <375ms
// 12-bit: <750ms
// 本方法在命令发出后立即返回,不等待命令执行完毕
void ds18b20_convert()
{
// 写 Convert T 命令
ds18b20_write_byte(DS18B20_CMD_CONVERT_T);
}
// 进行温度转换
// 同上,但本方法将等待温度转换操作结束后返回
// 当转换完成时,返回 1,转换超时则返回 0
unsigned char ds18b20_convert_sync()
{
// 写 Convert T 命令
ds18b20_write_byte(DS18B20_CMD_CONVERT_T);
// 等待操作完成,超时时间根据最大转换时间估计
return ds18b20_wait_finish(751);
}
// 写暂存器 (Scratchpad)
// 向设备的暂存器的 TH、TL 寄存器以及配置 (configuration) 寄存器写数据
void ds18b20_write_pad(DS18B20_TEMP_T th, DS18B20_TEMP_T tl, unsigned char cfg)
{
// 写 Write Scratchpad 命令
ds18b20_write_byte(DS18B20_CMD_WRITE_PAD);
// 写 TH 字节
ds18b20_write_byte(th);
// 写 TL 字节
ds18b20_write_byte(tl);
// 写 config 字节
ds18b20_write_byte(cfg);
}
// 读暂存器
// 读 9 字节暂存器数据,并进行 CRC 校验
// 校验通过,代表读取成功,返回 1,否则返回 0
unsigned char ds18b20_read_pad(DS18B20_SCRATCHPAD_PAD * pad)
{
unsigned char i;
// 写 Read Scratchpad 命令
ds18b20_write_byte(DS18B20_CMD_READ_PAD);
// 读 9 个字节的暂存器数据
for(i = 0; i < 9; i ++)
{
// 按字节读
pad -> pad_bytes[i] = ds18b20_read_byte();
}
// 对数据进行 CRC 校验,并返回校验结果
return !crc8_check(pad -> pad_bytes, 9);
}
// 向 EEPROM 写入暂存数据
// 将暂存器的 TH、TL 寄存器以及配置寄存器内容复制到 EEPROM 中
// 复制过程可能持续 10ms (从寄生电源要求复制期间 10ms 高电平推测得来)
// 本方法在命令发出后立即返回,不等待命令执行完毕
void ds18b20_copy_pad()
{
// 写 Copy Scratchpad 命令
ds18b20_write_byte(DS18B20_CMD_COPY_PAD);
}
// 向 EEPROM 写入暂存数据
// 同上,但本方法将等待复制操作结束后返回
// 当复制完成时,返回 1,超时则返回 0
unsigned char ds18b20_copy_pad_sync()
{
// 写 Copy Scratchpad 命令
ds18b20_write_byte(DS18B20_CMD_COPY_PAD);
// 等待操作完成,超时时间根据最大复制时间估计
return ds18b20_wait_finish(11);
}
// 从 EEPROM 中重新加载数据
// 从 EEPROM 中重新读取 TH、TL 寄存器内容以及配置寄存器内容
// 本方法在命令发出后立即返回,不等待命令执行完毕
void ds18b20_recall_ee()
{
// 写 Recall EE 命令
ds18b20_write_byte(DS18B20_CMD_RECALL_EE);
}
// 从 EEPROM 中重新加载数据
// 同上,但本方法将等待操作结束后返回
// 当操作完成时,返回 1,超时则返回 0
unsigned char ds18b20_recall_ee_sync()
{
// 写 Recall EE 命令
ds18b20_write_byte(DS18B20_CMD_RECALL_EE);
// 等待操作完成,超时时间同 ds18b20_copy_pad_sync 的超时(因为不知道操作要多久)
return ds18b20_wait_finish(11);
}
// 读供电状态
// 若设备工作于寄生电源下,将返回 0,若工作于外部电源,将返回 1
unsigned char ds18b20_read_power()
{
// 写 Read Power Supply 命令
ds18b20_write_byte(DS18B20_CMD_READ_POWER);
// 读 1 位数据并返回
return ds18b20_read_bit();
}
/*---------- 常用方法封装 ----------*/
// 初始化总线上所有设备
unsigned char ds18b20_init(DS18B20_TEMP_T th, DS18B20_TEMP_T tl, unsigned char bits)
{
// 复位并检测存在
if(!ds18b20_reset())
return 0;
// 跳过 ROM 搜索,向所有 ROM 设备发送指令
ds18b20_skip_rom();
// 写暂存器
ds18b20_write_pad(th, tl, DS18B20_CONFIG_RESOLUTION(bits));
return 1;
}
// 读取温度值,将结果通过指针写回变量
// 读取成功时返回 1,否则返回 0
// 【无复位、搜索操作】
unsigned char ds18b20_read_temp_bytes(DS18B20_TEMP_T * high, DS18B20_TEMP_T * low)
{
DS18B20_SCRATCHPAD_PAD pad;
// 读暂存器
if(!ds18b20_read_pad(&pad))
return 0;
// 如果指针有效,则将结果写到指针所指的变量
if(high)
{
* high = pad.pad_data.temp_high;
}
if(low)
{
* low = pad.pad_data.temp_low;
}
return 1;
}
// 读取用户字节,将结果通过指针写回变量
// 读取成功时返回 1,否则返回 0
// 在不使用温度报警功能时,TH 和 TL 寄存器可被用于存储两字节的用户数据
// 【无复位、搜索操作】
unsigned char ds18b20_read_user_bytes(unsigned char * byte1, unsigned char * byte2)
{
DS18B20_SCRATCHPAD_PAD pad;
// 读暂存器
if(!ds18b20_read_pad(&pad))
return 0;
// 如果指针有效,则将结果写到指针所指的变量
if(byte1)
{
* byte1 = pad.pad_data.th;
}
if(byte2)
{
* byte2 = pad.pad_data.tl;
}
return 1;
}
// 读取温度整数值
// 读取成功时返回温度的整数值,否则返回 DS18B20_INVALID_TEMP_INT
// 【无复位、搜索操作】
signed int ds18b20_read_int_temp()
{
DS18B20_TEMP_T high, low;
// 读温度字节值
if(ds18b20_read_temp_bytes(&high, &low))
{
// 解析整数部分
return DS18B20_TEMP_INT(high, low);
}
return DS18B20_INVALID_TEMP_INT;
}
// 读取温度浮点值
// 读取成功时返回温度的浮点数值,否则返回 DS18B20_INVALID_TEMP_FLOAT
// 【无复位、搜索操作】
float ds18b20_read_float_temp()
{
DS18B20_TEMP_T high, low;
// 读温度字节值
if(ds18b20_read_temp_bytes(&high, &low))
{
// 解析整个数据
return DS18B20_TEMP_FLOAT(high, low);
}
return DS18B20_INVALID_TEMP_FLOAT;
}
C
1
https://gitee.com/zzsj_run/ds18b20.git
git@gitee.com:zzsj_run/ds18b20.git
zzsj_run
ds18b20
ds18b20
master

搜索帮助