上来一张图,明确思路,程序整体裤架如下,通过单总线,单独封装一个.c文件用于单总线的操作,其实,我们可以把点c文件看成一个类操作,其属性就是我们面向对象的函数,也叫方法,操作起来方便,通过DS18B20调用封装好的单总线,实现温度的读取(用LCD1602显示出读取的温度 ),总后通过主函数调用这些模块,这就是模块化的编程,两个模块,主函数直接调用,也方便移植。
作者:Whappy
时间:2024.9.14
DS18B20实验-温度测试
第一步:模块化单总线 :OneWire.c
一共五个函数
看时序写代码
unsigned char OneWire_Init(void)
{
unsigned char AckBit;
OneWire_DQ = 1; //保证拉低之前是高电平
OneWire_DQ = 0; //拉低
Delay1ms();//延时1ms ,至少480us
OneWire_DQ = 1; //释放
Delay70us();
AckBit = OneWire_DQ; //应答位:存在的从机会拉低总线60~240us以响应主机
Delay1ms();//延时1ms ,至少480us
return AckBit;
}
void OneWire_SendBit(unsigned char Bit)
{
OneWire_DQ = 0; //拉低
Delay10us();
OneWire_DQ = Bit; //10us 将数据放到总线上
Delay50us();
OneWire_DQ = 1; //释放
}
//接收一位:即主机51读取一位:主机将总线拉低1~15us,然后释放总线,并在拉低后15us内读取总线电平(尽量贴近15us的末尾),
//读取为低电平则为接收0,读取为高电平则为接收1 ,整个时间片应大于60us
unsigned char OneWire_ReadBit(void)
{
unsigned char Bit;
OneWire_DQ = 0; //拉低
Delay5us();
OneWire_DQ = 1; //释放
Delay5us();
Bit = OneWire_DQ; //数据放到总线上,主机读
Delay50us();
return Bit;
}
//发送一个字节:连续调用8次发送一位的时序,依次发送一个字节的8位(低位在前)
void OneWire_SendByte(unsigned char Byte)
{
unsigned char i;
for(i=0; i<8; i++)
{
OneWire_SendBit(Byte & (0X01 << i));
}
}
//接收一个字节:连续调用8次接收一位的时序,依次接收一个字节的8位(低位在前)
unsigned char OneWire_ReceiveByte(void)
{
unsigned char i, Byte = 0X00;
for(i=0; i<8; i++)
{
if(OneWire_ReadBit())
{
Byte |= (0x01);
}
}
return Byte;
}
第二步:模块化 DS18B20.c:DS18B20.c :两个函数
//温度转换函数 :初始化→跳过ROM →开始温度变换
void DS18B20_ConvertTemperature(void)
{
OneWire_Init();
OneWire_SendByte(SKIP_ROM); //跳过ROM,写入一个字节数据,说我要读取温度
OneWire_SendByte(CONVERT_T); //发送一个字节,让DS18B20开始温度转化
}
//温度读取:初始化→跳过ROM →读暂存器→连续的读操作
float DS18B20_ReadTemperature(void)
{
unsigned char TLSB, TMSB;
int Temp;
float T;
OneWire_Init();//初始化
OneWire_SendByte(READ_SCRATCHPAD); //跳过ROM,写入一个字节数据,说我要读取温度
TLSB = OneWire_ReceiveByte();
TMSB = OneWire_ReceiveByte();
Temp = (TMSB<<8)| TLSB;
T = Temp/16.0;
return T;
}
第三步:主函数调用 :main.c
#include <REGX52.H>
#include "LCD1602.h"
#include "DS18B20.h"
#include "Delay.h"
float T;
void main(void)
{
DS18B20_ConvertTemperature(); //上电先转换一次温度,防止第一次读数据错误
Delay_Any(1000); //等待转换完成
//初始化
LCD_Init();
LCD_ShowString(1,1,"Temperature:");
while(1)
{
DS18B20_ConvertTemperature();
T = DS18B20_ReadTemperature();
if(T < 0)
{
LCD_ShowChar(2,1,'-');
T = -T;
}
else
LCD_ShowChar(2,1,'+');
LCD_ShowNum(2,2,T,3);
LCD_ShowChar(2,5,'.');
LCD_ShowNum(2,6,(unsigned long)(T*10000)%10000,4);
}
}
//#include <REGX52.H>
//#include "LCD1602.h"
//#include "DS18B20.h"
//#include "Delay.h"
//float T;
//void main()
//{
// DS18B20_ConvertT(); //上电先转换一次温度,防止第一次读数据错误
// Delay(1000); //等待转换完成
// LCD_Init();
// LCD_ShowString(1,1,"Temperature:");
// while(1)
// {
// DS18B20_ConvertT(); //转换温度
// T=DS18B20_ReadT(); //读取温度
// if(T<0) //如果温度小于0
// {
// LCD_ShowChar(2,1,'-'); //显示负号
// T=-T; //将温度变为正数
// }
// else //如果温度大于等于0
// {
// LCD_ShowChar(2,1,'+'); //显示正号
// }
// LCD_ShowNum(2,2,T,3); //显示温度整数部分
// LCD_ShowChar(2,5,'.'); //显示小数点
// LCD_ShowNum(2,6,(unsigned long)(T*10000)%10000,4);//显示温度小数部分
// }
//}
总代码:
OneWire.c
#include <REGX52.H>
#include "Delay.h"
sbit OneWire_DQ = P3^7; //单总线的管脚定义
//编写5个函数 初始化、写一位、读一位、写一个字节、读一个字节
//初始化:主机将总线拉低至少480us,然后释放总线,等待15~60us后,存在的从机会拉低总线60~240us以响应主机,之后从机将释放总线
unsigned char OneWire_Init(void)
{
unsigned char AckBit;
OneWire_DQ = 1; //保证拉低之前是高电平
OneWire_DQ = 0; //拉低
Delay1ms();//延时1ms ,至少480us
OneWire_DQ = 1; //释放
Delay70us();
AckBit = OneWire_DQ; //应答位:存在的从机会拉低总线60~240us以响应主机
Delay1ms();//延时1ms ,至少480us
return AckBit;
}
//写一位数据,即主机51发送一位:主机将总线拉低60~120us,然后释放总线,表示发送0;主机将总线拉低1~15us,
//然后释放总线,表示发送1。从机将在总线拉低30us后(典型值)读取电平,整个时间片应大于60us
void OneWire_SendBit(unsigned char Bit)
{
OneWire_DQ = 0; //拉低
Delay10us();
OneWire_DQ = Bit; //10us 将数据放到总线上,主机写,
Delay50us();
OneWire_DQ = 1; //释放
}
//接收一位:即主机51读取一位:主机将总线拉低1~15us,然后释放总线,并在拉低后15us内读取总线电平(尽量贴近15us的末尾),
//读取为低电平则为接收0,读取为高电平则为接收1 ,整个时间片应大于60us
unsigned char OneWire_ReadBit(void)
{
unsigned char Bit;
OneWire_DQ = 0; //拉低
Delay5us();
OneWire_DQ = 1; //释放
Delay5us();
Bit = OneWire_DQ; //数据放到总线上,主机读
Delay50us();
return Bit;
}
//发送一个字节:连续调用8次发送一位的时序,依次发送一个字节的8位(低位在前)
void OneWire_SendByte(unsigned char Byte)
{
unsigned char i;
for(i=0; i<8; i++)
{
OneWire_SendBit(Byte & (0X01 << i));
}
}
//接收一个字节:连续调用8次接收一位的时序,依次接收一个字节的8位(低位在前)
unsigned char OneWire_ReceiveByte(void)
{
unsigned char i, Byte = 0X00;
for(i=0; i<8; i++)
{
if(OneWire_ReadBit())
{
Byte |= (0x01);
}
}
return Byte;
}
DS18B20.c
#include <REGX52.H>
#include "OneWire.h"
//DS18B20 程序使用的寄存器进行红宏定义
#define SKIP_ROM 0XCC //ROM指令 跳过ROM ,相当于直接访问DS18B20
#define CONVERT_T 0X44 //功能指令 温度转换
#define READ_SCRATCHPAD 0XBE //功能指令 暂存器
//温度转换函数 :初始化→跳过ROM →开始温度变换
void DS18B20_ConvertTemperature(void)
{
OneWire_Init();
OneWire_SendByte(SKIP_ROM); //跳过ROM,写入一个字节数据,说我要读取温度
OneWire_SendByte(CONVERT_T); //发送一个字节,让DS18B20开始温度转化
}
//温度读取:初始化→跳过ROM →读暂存器→连续的读操作
float DS18B20_ReadTemperature(void)
{
unsigned char TLSB, TMSB;
int Temp;
float T;
OneWire_Init();//初始化
OneWire_SendByte(SKIP_ROM);
OneWire_SendByte(READ_SCRATCHPAD); //跳过ROM,写入一个字节数据,说我要读取温度
TLSB = OneWire_ReceiveByte();
TMSB = OneWire_ReceiveByte();
Temp = (TMSB<<8) | TLSB;
T = Temp/16.0;
return T;
}
Delay.c
#include <REGX52.H>
#include "intrins.h"
void Delay1ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
void Delay70us() //@11.0592MHz
{
unsigned char i;
_nop_();
i = 29;
while (--i);
}
void Delay_Any(unsigned int xms) //@11.0592MHz
{
unsigned char i, j;
while(xms--)
{
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
void Delay10us() //@11.0592MHz
{
unsigned char i;
i = 2;
while (--i);
}
void Delay50us() //@11.0592MHz
{
unsigned char i;
_nop_();
i = 20;
while (--i);
}
void Delay5us() //@11.0592MHz
{
}
其余代码可参考(主页51单片机内容)