使用方法
对P14引脚的单总线接口
复位脉冲:微控制器拉低数据线至少 480 微秒,然后释放数据线
存在脉冲:DS18B20 在检测到复位脉冲后,会在 15-60 微秒内发出一个低电平的存在脉冲
写 0 和写 1:微控制器通过控制数据线的电平时间来写入 0 或 1
读 0 和读 1:DS18B20 通过控制数据线的电平时间来读取 0 或 1
初始化
- 复位:
- 微控制器拉低数据线至少 480 微秒,然后释放数据线
- DS18B20 检测到复位脉冲后,发出一个存在脉冲
- 跳过 ROM 指令:
- 发送 0xCC 指令跳过 ROM 操作,直接进入功能指令
- 温度转换指令:
- 发送 0x44 指令启动温度转换
- DS18B20 开始温度转换,转换时间取决于分辨率(9 位至 12 位)
- 读取温度值:
- 发送 0xBE 指令读取温度寄存器
- DS18B20 返回两个字节的温度值(低字节和高字节)
温度计算
DS18B20 返回的温度值是一个 16 位的二进制数,其中:
低字节:温度值的低 8 位
高字节:温度值的高 4 位(高字节的低 4 位)
温度值的计算公式为:
如果温度为负,返回的值是补码形式,需要进行取反加 1 操作
代码
#include <STC15F2K60S2.h>
#include <stdio.h>
#define LCD_DATA P0 // 定义LCD数据端口
sbit LCD_RS = P2^0; // RS引脚连接到P1.2
sbit LCD_RW = P2^1; // R/W引脚连接到P1.1
sbit LCD_E = P1^2; // E引脚连接到P1.0
sbit DQ = P1^4; //单总线接口
unsigned char *q;
unsigned char a[20];
float temperature;
// 延时函数
void delay(unsigned int ms) {
unsigned int i, j;
for (i = 0; i < ms; i++)
for (j = 0; j < 853; j++);
}
void LCD_Command(unsigned char cmd) {
LCD_DATA = cmd; // 将命令字节加载到数据总线
LCD_RS = 0; // 选择命令寄存器
LCD_RW = 0; // 设置为写操作
LCD_E = 1; // 使能LCD
delay(1); // 短暂延时
LCD_E = 0; // 禁止LCD
}
void LCD_Init() {
LCD_Command(0x38); // 设置显示模式
LCD_Command(0x0C); // 显示开,光标关
LCD_Command(0x06); // 文字不动,地址自动+1
LCD_Command(0x01); // 显示清屏
delay(2); // 等待LCD完成清屏
}
void LCD_DisplayString(unsigned char row, unsigned char column, unsigned char *str) {
unsigned char address;
if (row == 0)
address = 0x80 + column; // 第一行地址
else if (row == 1)
address = 0xC0 + column; // 第二行地址
LCD_Command(address); // 设置LCD地址
while (*str) { // 显示字符串
LCD_DATA = *str++;
LCD_RS = 1; // 选择数据寄存器
LCD_RW = 0; // 设置为写操作
LCD_E = 1; // 使能LCD
delay(1); // 短暂延时
LCD_E = 0; // 禁止LCD
}
}
//延迟
void Delay_OneWire(unsigned int us) {
while (us--);
}
//写
void Write_DS18B20(unsigned char dat) {
unsigned char i;
for (i = 0; i < 8; i++) {
DQ = 0; // 拉低数据线
Delay_OneWire(1); // 短暂延时
if (dat & 0x01) { // 判断当前位是否为1
DQ = 1; // 如果是1,释放数据线
Delay_OneWire(60); // 保持高电平至少60us
} else {
DQ = 0; // 如果是0,保持数据线低电平
Delay_OneWire(60); // 保持低电平至少60us
}
DQ = 1; // 释放数据线
dat >>= 1; // 移位,处理下一位
Delay_OneWire(1); // 短暂延时,确保时序
}
}
//从DS18B20读取一个字节
unsigned char Read_DS18B20(void) {
unsigned char i;
unsigned char dat = 0;
for (i = 0; i < 8; i++) {
DQ = 0; // 拉低数据线
Delay_OneWire(1); // 短暂延时,确保数据线被拉低
DQ = 1; // 释放数据线
Delay_OneWire(1); // 等待数据线稳定
if (DQ) { // 采样数据线状态
dat |= (0x01 << i); // 如果数据线为高,将对应位设置为1
}
Delay_OneWire(60); // 等待数据线恢复高电平
}
return dat;
}
//DS18B20设备初始化
bit init_ds18b20(void) {
bit initflag = 0;
DQ = 1; // 拉高数据线
Delay_OneWire(120); // 等待稳定
DQ = 0; // 拉低数据线,发送复位脉冲
Delay_OneWire(800); // 保持低电平至少480us
DQ = 1; // 释放数据线
Delay_OneWire(60); // 等待DS18B20的响应
initflag = DQ; // 读取数据线状态,检测响应信号
Delay_OneWire(40); // 确保响应信号结束
return initflag; // 返回初始化结果
}
unsigned long Temp_get(void)
{
unsigned char low,high;
unsigned int Temp;
init_ds18b20();
Write_DS18B20(0XCC);
Write_DS18B20(0X44);
Delay_OneWire(200);
init_ds18b20();
Write_DS18B20(0XCC);
Write_DS18B20(0XBE);
low=Read_DS18B20();
high=Read_DS18B20();
Temp=high&0X0F;
Temp <<= 8;
Temp |= low;
return Temp;
}
//进制转换
float Temperature_Celsius(void) {
unsigned int temp_value = Temp_get();
float temperature = (float)temp_value / 16.0;
return temperature;
}
void main() {
LCD_Init(); // 初始化LCD
while(1){
temperature = Temperature_Celsius(); // 获取温度值
sprintf(a, "%.4f", temperature); // 将float转换为字符串
q = a;
LCD_DisplayString(0,0,q);
}
}
操作视频
https://www.bilibili.com/video/BV1nUXyYYEF4?vd_source=b10b3445cdc8080c1d316e6f9a6245a0