测试采用4个DS18B20挂在6m长得网线上面,使用的是5V供电,4.7K上拉,STM32驱动,
程序实现ROM搜索并分别读取每一个DS18B20的温度.
/*************************************************************************************************************
* 文件名: ds18b20.c
* 功能: STM32 DS18B20驱动
* 作者: cp1300@139.com
* 创建时间: 2012年9月17日22:45
* 最后修改时间:2012年9月17日
* 详细: 需要延时函数支持
* 注意延时精度尽可能的高
* 读取的时候不要长时间的被中断,因为1wire对时间要求很严格
*************************************************************************************************************/
#include "system.h"
#include "delay.h"
#include "ds18b20.h"
//PC1
#define DS18B20_OUT PBout(15)
#define DS18B20_IN PBin(15)
//DS18B20使用的是GPIOE0
#define Set18b20IOout() GPIOx_Init(GPIOB,BIT15,OUT_PP,SPEED_10M); //设置DS18B20 IO为输出,
#define Set18b20IOin() GPIOx_Init(GPIOB,BIT15,IN_IPU,0); //设置DS18B20 IO为上拉输入,
#define Read18b20IO() ((DS18B20_IN) ? 1 : 0) //读取DS18B20 IO
#define Write18b20IO(x) (DS18B20_OUT = x) //写DS18B20 IO
/*************************************************************************************************************************
*函数 : bool DS18B20_Reset(void)
*功能 : 复位DS18B20
*参数 : 无
*返回 : TRUE:成功;FALSE:失败
*依赖 : 底层宏定义
*作者 : cp1300@139.com
*时间 : 20120917
*最后修改时间: 20120917
*说明 :无
*************************************************************************************************************************/
bool DS18B20_Reset(void)
{
u8 i = 0;
Set18b20IOout(); //主机端口推挽输出模式
Write18b20IO(1);
Delay_US(1);
Write18b20IO(0); //拉低总线480us~240us
Delay_US(500); //>480US延时
Write18b20IO(1);
Delay_US(2); //复位完成
Set18b20IOin(); //主机端口浮空输入模式
while(Read18b20IO()) //等待低电平应答信号
{
i ++;
Delay_US(1);
if(i > 100)
{
uart_printf("DS18B20 error!\r\n");
return FALSE; //等待超时,初始化失败,返回FALSE;
}
}
Delay_US(250); //跳过回复信号
return TRUE; //检测到DS18B20,并且初始化成功
}
/*************************************************************************************************************************
*函数 : __inline u8 DS18B20_ReadBit(void)
*功能 : 读取DS18B20 1bit数据
*参数 : 无
*返回 : 数据,最低位有效
*依赖 : 底层宏定义
*作者 : cp1300@139.com
*时间 : 20130402
*最后修改时间: 20130402
*说明 :无
*************************************************************************************************************************/
__inline u8 DS18B20_ReadBit(void)
{
u8 data = 0;
Set18b20IOout(); //主机端口推挽输出模式
Write18b20IO(0); //拉低总线10-15us
Delay_US(12);
Write18b20IO(1); //释放总线
Set18b20IOin(); //主机端口浮空输入模式
Delay_US(10);
if(Read18b20IO()) //读取数据,读取后大约延时40-45us
data = 0x01;
Delay_US(40);
return data;
}
/*************************************************************************************************************************
*函数 : u8 DS18B20_ReadData(void)
*功能 : 读取DS18B20数据
*参数 : 无
*返回 : 数据
*依赖 : 底层宏定义
*作者 : cp1300@139.com
*时间 : 20120917
*最后修改时间: 20120917
*说明 :无
*************************************************************************************************************************/
u8 DS18B20_ReadData(void)
{
u8 i,data = 0;
for(i = 0;i < 8;i ++)
{
data >>= 1;
if(DS18B20_ReadBit())
data |= 0x80;
}
return data;
}
/*************************************************************************************************************************
*函数 : __inline void DS18B20_WriteBit(u8 bit)
*功能 : 向DS18B20写一位数据
*参数 : 数据,只发送最低位
*返回 : 无
*依赖 : 底层宏定义
*作者 : cp1300@139.com
*时间 : 20130402
*最后修改时间: 20130402
*说明 :无
*************************************************************************************************************************/
__inline void DS18B20_WriteBit(u8 bit)
{
Set18b20IOout(); //主机端口推挽输出模式
Write18b20IO(0); //拉低总线10-15us
Delay_US(12);
Write18b20IO(bit & 0x01); //写入数据位,保持20-45us
Delay_US(30);
Write18b20IO(1); //释放总线
Delay_US(5);
}
/*************************************************************************************************************************
*函数 : void DS18B20_WriteData(u8 data)
*功能 : 向DS18B20写数据
*参数 : 数据
*返回 : 无
*依赖 : 底层宏定义
*作者 : cp1300@139.com
*时间 : 20120917
*最后修改时间: 20120917
*说明 :无
*************************************************************************************************************************/
void DS18B20_WriteData(u8 data)
{
u8 i;
for(i = 0;i < 8;i ++)
{
DS18B20_WriteBit(data);
data >>= 1;
}
}
/*************************************************************************************************************************
*函数 : s16 DS18B20_ReadTemper(void)
*功能 : 读取DS18B20温度
*参数 : 无
*返回 : 温度值
*依赖 : 底层宏定义
*作者 : cp1300@139.com
*时间 : 20120917
*最后修改时间: 20120917
*说明 :温度值扩大了100倍,温度值是个有符号数.
*************************************************************************************************************************/
s16 DS18B20_ReadTemper(void)
{
u8 th, tl;
s16 data;
if(DS18B20_Reset() == FALSE)
{
return 0xffff; //返回错误
}
DS18B20_WriteData(0xcc); //跳过读序列号
DS18B20_WriteData(0x44); //启动温度转换
DS18B20_Reset();
DS18B20_WriteData(0xcc); //跳过读序列号
DS18B20_WriteData(0xbe); //读取温度
tl = DS18B20_ReadData(); //读取低八位
th = DS18B20_ReadData(); //读取高八位
data = th;
data <<= 8;
data |= tl;
data *= 6.25; //温度值扩大100倍,精确到2位小数
return data;
}
/*************************************************************************************************************************
*函数 : __inline u8 DS18B20_Read2Bit(void)
*功能 : 读取DS18B20 2bit数据
*参数 : 无
*返回 : 数据
*依赖 : 底层宏定义
*作者 : cp1300@139.com
*时间 : 20120917
*最后修改时间: 20120917
*说明 :无
*************************************************************************************************************************/
u8 DS18B20_Read2Bit(void)
{
u8 i,data = 0;
for(i = 0;i < 2;i ++)
{
data <<= 1;
if(DS18B20_ReadBit())
data |= 1;
}
return data;
}
//
//以下代码为多DS18B20相关
#define MAXNUM 4 //定义最多有4个 DS18B20
/*************************************************************************************************************************
*函数 : u8 DS18B20_SearchROM(u8 (*pID)[8],u8 Num)
*功能 : 搜索DS18B20 ROM
*参数 : pID:DS18B20 ID缓冲区指针
Num:DS18B20数目,必须事先知道
*返回 : 搜索到的DS18B20数目
*依赖 : 底层宏定义
*作者 : cp1300@139.com
*时间 : 2013-04-17
*最后修改时间 : 2013-04-17
*说明 : 程序必须事先知道DS18B20数目,搜索的数目只会小于这个数目
代码移植于互联网
*************************************************************************************************************************/
u8 DS18B20_SearchROM(u8 (*pID)[8],u8 Num)
{
unsigned char k,l,chongtuwei,m,n;
unsigned char zhan[(MAXNUM)];
unsigned char ss[64];
u8 num = 0;
l=0;
do
{
DS18B20_Reset();
DS18B20_WriteData(0xf0);
for(m=0;m<8;m++)
{
unsigned char s=0;
for(n=0;n<8;n++)
{
k=DS18B20_Read2Bit();//读两位数据
k=k&0x03;
s>>=1;
if(k==0x01)//01读到的数据为0 写0 此位为0的器件响应
{
DS18B20_WriteBit (0);
ss[(m*8+n)]=0;
}
else if(k==0x02)//读到的数据为1 写1 此位为1的器件响应
{
s=s|0x80;
DS18B20_WriteBit (1);
ss[(m*8+n)]=1;
}
else if(k==0x00)//读到的数据为00 有冲突位 判断冲突位
{ //如果冲突位大于栈顶写0 小于栈顶写以前数据 等于栈顶写1
chongtuwei=m*8+n+1;
if(chongtuwei>zhan[l])
{
DS18B20_WriteBit (0);
ss[(m*8+n)]=0;
zhan[++l]=chongtuwei;
}
else if(chongtuwei<zhan[l])
{
s=s|((ss[(m*8+n)]&0x01)<<7);
DS18B20_WriteBit (ss[(m*8+n)]);
}
else if(chongtuwei==zhan[l])
{
s=s|0x80;
DS18B20_WriteBit (1);
ss[(m*8+n)]=1;
l=l-1;
}
}
else
{
return num; //搜索完成,//返回搜索到的个数
}
}
pID[num][m]=s;
}
num=num+1;
}
while(zhan[l]!=0&&(num<MAXNUM));
return num; //返回搜索到的个数
}
/*************************************************************************************************************************
*函数 : s16 DS18B20_ReadDesignateTemper(u8 pID[8])
*功能 : 读取指定ID的DS18B20温度
*参数 : pID:DS18B20 ID,必须事先知道,如果不知道请启动ROM搜索
*返回 : 温度值
*依赖 : 底层宏定义
*作者 : cp1300@139.com
*时间 : 2013-04-17
*最后修改时间 : 2013-04-17
*说明 : 温度值扩大了100倍,温度值是个有符号数.
*************************************************************************************************************************/
s16 DS18B20_ReadDesignateTemper(u8 pID[8])
{
u8 th, tl;
s16 data;
if(DS18B20_Reset() == FALSE)
{
return 0xffff; //返回错误
}
DS18B20_WriteData(0xcc); //跳过读序列号
DS18B20_WriteData(0x44); //启动温度转换
DS18B20_Reset();
DS18B20_WriteData(0x55); //发送序列号匹配命令
for(data = 0;data < 8;data ++) //发送8byte的序列号
{
DS18B20_WriteData(pID[data]);
}
Delay_US(10);
DS18B20_WriteData(0xbe); //读取温度
tl = DS18B20_ReadData(); //读取低八位
th = DS18B20_ReadData(); //读取高八位
data = th;
data <<= 8;
data |= tl;
data *= 6.25; //温度值扩大100倍,精确到2位小数
return data;
}
#ifndef DS18B20_H_
#define DS18B20_H_
//DS18B20指令
typedef enum
{
SEARCH_ROM = 0xf0, //搜索ROM指令
READ_ROM = 0x33, //读取ROM指令
MATH_ROM = 0x55, //匹配ROM指令
SKIP_ROM = 0xcc, //忽略ROM指令
ALARM_SEARCH = 0xec, //报警索索指令
CONVERT_T = 0x44, //温度转换指令
WRITE_SCRATCHPAD = 0x4e, //写暂存器指令
READ_SCRATCHPAD = 0xbe, //读取暂存器指令
COPY_SCRATCHPAD = 0x48, //拷贝暂存器指令
RECALL_E2 = 0xb8, //召回EEPROM指令
READ_POWER_SUPPLY = 0xb4, //读取电源模式指令
} DS18B20_CMD;
//DS18B20 ROM编码
typedef struct
{
u8 DS18B20_CODE; //DS18B20单总线编码:0x19
u8 SN_1; //序列号第1字节
u8 SN_2; //序列号第2字节
u8 SN_3; //序列号第3字节
u8 SN_4; //序列号第4字节
u8 SN_5; //序列号第5字节
u8 SN_6; //序列号第6字节
u8 crc8; //CRC8校验码
} DS18B20_ROM_CODE;
#define DS18B20_Init() (DeviceClockEnable(DEV_GPIOB,ENABLE)) //使能GPIOB时钟
s16 DS18B20_ReadTemper(void); //读取DS18B20温度
void DS18B20_WriteData(u8 data);
u8 DS18B20_SearchROM(u8 (*pID)[8],u8 Num); //搜索ROM;
s16 DS18B20_ReadDesignateTemper(u8 pID[8]); //读取指定ID的DS18B20温度
#endif /*DS18B20_H_*/
#define DS18B20_NUM 4
u8 ID_Buff[DS18B20_NUM][8];
int main(void)
{
OS_CPU_SR cpu_sr;
s16 temp;
u8 buff[16];
u8 i,j,num;
SYSTEM_ClockInit(9); //初始化系统时钟72MHz
JTAG_Set(SWD_ENABLE); //只开启SWD调试模式
DevInit();
uart_printf("start system ...\r\n\r\n");
num = DS18B20_SearchROM(ID_Buff,DS18B20_NUM);
uart_printf("总线上实际挂载DS18B20数量: %d\r\n",DS18B20_NUM);
uart_printf("搜索到的DS18B20数量: %d\r\n",num);
for(i = 0;i < num;i ++)
{
uart_printf("\r\n DS18B20 No%d ID: ",i);
for(j = 0;j < 8;j ++)
{
uart_printf("%02X ",ID_Buff[i][j]);
}
}
i = 0;
while(1)
{
LED1 = ~LED1;
Delay_MS(1000);
temp = DS18B20_ReadDesignateTemper(ID_Buff[i ++]);
uart_printf("\r\n DS18B20 No%d Temp:%d ",i,temp);
if(i == 4)
{
i = 0;
uart_printf("\r\n");
}
}
}
结果