本帖最后由 希岩 于 2020-5-28 13:08 编辑
DS18B20是一个常用的高精度的温度传感器。采用单总线形式进行通讯。
本次,我们通过Arduino UNO R3读取温度数据,然后通过串口打印。使用开发板上的数字口3作为DQ,Vdd连接5V。DQ和VDD之间用4.7K或者5.1k上拉电阻。
烧录程序,结果如下,代码完全贴出来了。
[mw_shl_code=arduino,true]//功能: DS18B20 温度读取,定点小数显示
//制作: 希岩 (凌晨七點半)
//时间: 2017.10.27
//端口: D3(PD3)作为单总线端口
typedef unsigned char uint08;
typedef signed char sint08;
typedef unsigned int uint16;
typedef signed int sint16;
typedef unsigned long uint32;
typedef const unsigned char cuint08;
#define DS_HIGH DDRD&=~(1<<DDD3) //作为输出
#define DS_LOW DDRD|=(1<<DDD3)
#define READ_1WIRE_BUS PIND&(1<<PIND3) //读取数据
#define FAULT 1
#define RIGHT 0
#define DS18B20_READ_ROM 0x33
#define DS18B20_MATCH_ROM 0X55
#define DS18B20_SKIP_ROM 0XCC
#define DS18B20_SEARCH_ROM 0XF0
#define DS18B20_ALARM_SEARCH_ROM 0XEC
#define DS18B20_WRITE_RAM 0X40
#define DS18B20_READ_RAM 0XBE
#define DS18B20_COPY_RAM 0X48
#define DS18B20_CONVERT_TEM 0X44
#define WDR() MCUSR &= ~(1<<WDRF) //清看门狗
uint08 DS_Data[3];
uint08 Show_Buff[7]; //显示缓冲区
uint08 Flag=0; //正负标志
//------------------------------------------------------------------
uint08 DS18B20_Init(void)
{ uint08 ret;
cli();
while(!READ_1WIRE_BUS) WDR(); //等待总线为高
DS_LOW;
delayMicroseconds(500); //至少延时480us
DS_HIGH;
delayMicroseconds(50); //延时15us-60us
if(READ_1WIRE_BUS)
ret = FAULT;
else
ret = RIGHT;
delayMicroseconds(500);
sei();
return ret;
}
//-----------------------------------------------------------------------------
//单总线读取8位数据
uint08 ds18b20_read(void)
{
uint08 data=0;
uint08 i=0;
cli();
for(i=0;i<8;i++)
{
data>>=1;
//DS_HIGH;
//while(!READ_1WIRE_BUS) WDR(); //等待总线为高
//delayMicroseconds(10);
DS_LOW;
delayMicroseconds(2); //延时>1us
DS_HIGH;
delayMicroseconds(10); // <15us
if(READ_1WIRE_BUS)
data|=0x80;
delayMicroseconds(50); //>45us
}
sei();
return data;
}
//------------------------------------------------------------
//单总线写一字节
void ds18b20_write(uint08 data)
{
uint08 i=0;
cli(); //关中断
for(i=0;i<8;i++)
{
if(data&0x01)
{
DS_LOW;
delayMicroseconds(10);//10us
DS_HIGH;
delayMicroseconds(55);//55us
}
else
{
DS_LOW;
delayMicroseconds(55);;//55us
DS_HIGH;
delayMicroseconds(10);//10us
}
data>>=1;
}
sei(); //开中断
}
//-----------------------------------------------------------------------------------
//执行转换
uint08 Ds18b20_Convert(void)
{
//发送转换命令
if(DS18B20_Init()==FAULT)
return FAULT;
ds18b20_write(DS18B20_SKIP_ROM); //忽略地址匹配,总线上只有一个器件时,或对总线所有器件操作
ds18b20_write(DS18B20_CONVERT_TEM);//开始转换命令
//等待转换完成,ds18b20默认转换精度为12位,此时最大转换时间为750ms
delayMicroseconds(1000); //延时
//读温度字节
if(DS18B20_Init()==FAULT) return FAULT;
//SCI_Send_Str("test2\n");
ds18b20_write(DS18B20_SKIP_ROM); //忽略地址匹配
ds18b20_write(DS18B20_READ_RAM); //读RAM命令
DS_Data[0]=ds18b20_read();
DS_Data[1]=ds18b20_read();
//SCI_Send_Str("test3\n");
return RIGHT;
}
//----------------------------------------------------------------------------
//根据DS18B20中读的温度字节,计算实际温度值
uint16 Get_Temperature(void)
{
uint16 u16tmp;
u16tmp=(DS_Data[1]*256)+DS_Data[0];
if((DS_Data[1]&0xf8)==0xf8) //若负温度,从补码转换(取反加一)
{
Flag=1; //负数标志
u16tmp=~u16tmp;
u16tmp++;
}
else Flag=0; // 正 符号为0
u16tmp&=0x07ff; // 确保前5位为0
//乘0.0625操作,为此本函数只适用于DS18B20 12位转换(默认)时
u16tmp=((uint32)u16tmp)*625/100; //乘6.25,即放大100倍,用于保留两位小数
// if(Flag)
// temp|=0x80; //变负数
return u16tmp;
}
//-----------------------------------------------------------------------
void Init_Port(void)
{
DDRD |=(1<<DDD3);
}
//USART发送数据--------------------------------------------------------------
void USART_Send(uint08 data)
{ while(!(UCSR0A&(1<<UDRE0))); //等待发送缓冲器为空
UDR0=data; //将数据放入缓冲器,发送数据
}
//串口发送字符串============================================================
//返回值
void SCI_Send_Str(uint08 *str)
{
uint08 *p;
p=str;
while(*p) USART_Send(*(p++)); //发送一个字符
}
//------------------------------------------------
void setup()
{
Init_Port();
Serial.begin(9600);
}
uint16 u16temp=0;
uint08 i;
void loop()
{
delay(300);
if(Ds18b20_Convert()==RIGHT)
{
u16temp=Get_Temperature();
// Serial.println(u16temp);
if(Flag)
{
Show_Buff[0]='-'; //负号
}
else
{
Show_Buff[0]=' '; //空格
}
//定点小数显示格式
Show_Buff[1]=(u16temp/1000)%10+'0';
Show_Buff[2]=(u16temp/100)%10+'0';
Show_Buff[3]='.'; // 小数点
Show_Buff[4]=(u16temp/10)%10+'0';
Show_Buff[5]=u16temp%10+'0';
Show_Buff[6]=0; //字符串结束标志
SCI_Send_Str(Show_Buff);
SCI_Send_Str("\n");
}
}[/mw_shl_code] |