测试采用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"); } } }
结果