📄 ds18b20.c
字号:
//-----------------------------------------------------------------
// 名称: 多点DS18B20控制程序
//-----------------------------------------------------------------
#include <pic.h>
#include <string.h>
#include <stdio.h>
#include "DS18B20.h"
#include "LM044L.h"
//温度小数位对照表(不使用该表时,还可以通过计算法得到温度小数部分)
const INT8U df_Table[] = {0,1,1,2,3,3,4,4,5,6,6,7,8,8,9,9 };
INT8U DS18B20_STATUS; //器件状态,为0时在线,否则表示被拨出或无响应
INT8U Temp_Value[2]; //存放所读取的两字节温度数据
INT8U ROMCODE[8]; //存放搜索到的64位设备ROMCODE
INT8U Level,Last_Level; //当前分支点和上次搜索的最底层分支点
INT8U DS_CNT; //搜索到的器件个数
INT8U CRC; //校验变量
bit bit_A,bit_B; //读ROMCODE的当前位原码与反码
bit bj; //临时位变量
extern INT8U LCD_Buffer[]; //液晶显示缓冲
float Temp_i,Temp_f; //温度的整数与小数部分
//-----------------------------------------------------------------
// 延时nx100ms
//-----------------------------------------------------------------
void DelayX100ms(INT8U n)
{
while (n--) __delay_ms(100);
}
//-----------------------------------------------------------------
// 从1-Wire总线读取1位
//-----------------------------------------------------------------
INT8U Read_Romcode_bit()
{
}
//-----------------------------------------------------------------
// 搜索1-Wire总线上一只器件的64位ROMCODE
// 返回0表示搜索一个ROMCODE,否则表示无器件或搜索的ROMCODE最后校验出错
//-----------------------------------------------------------------
INT8U Search_ROM1()
{
volatile INT8U i, j, k;
RESET(); //复位
if (DS18B20_STATUS) return 0; //无器件在线时返回
Write_Byte(SERACH_ROM); //发送ROM搜索命令
for (i = 0; i < 64; i++) //从0位开始索64位ROMCODE
{ bit_A = Read_Romcode_bit(); //读取第i位的原码
bit_B = Read_Romcode_bit(); //读取第i位的反码
//---------------------------------------------------------11
//读取的结果为"11"时,搜索结束,程序返回
if (bit_A == 1 && bit_B == 1) return 1;
//-----------------------------------------------------10或01
//读取的结果为"10"或"01"时,表示所有从机的此位均为"0"或"1"
//将此位保存到8字节共64位的数组ROMCODE中.
//如果为0表示所有从机此位均为"0",故发送"0"使所有从机继续通信
//如果为1表示所有从机此位均为"1",故发送"1"使所有从机继续通信
else if (bit_A != bit_B) //两位为01或10
{
}
//---------------------------------------------------------00
//读取的结果为"00"时,表示从机中此位同时有"0"与"1",在该层出现搜索分支
else if (bit_A == 0 && bit_B == 0)
{
//"="=====================================================
//当前搜索遇到的分支层位置等于前一搜索路径中最低的分支层位置
if(i == Last_Level)
{
}
//">"=====================================================
//当前搜索遇到的分支层低于前一趟搜索的最低分支层
else if (i > Last_Level)
{
}
//"<"=====================================================
//当前搜索遇到的分支层高于上一次搜索的最低分支层
//此时的“左右分支选择”决定于上一次ROMCODE搜索结果中的对应位
else if (i < Last_Level)
{
}
} //完成1位搜索------------------------------------------------
} //完成64位搜索-------------------------------------------------
//对8字(64位)ROMCODE执行CRC8校验
//CRC正确时返回0,否则返回1
}
//-----------------------------------------------------------------
// 转换并显示当前找到的器件的8字节(64位)ROMCODE
//-----------------------------------------------------------------
void Show_Romcode(INT8U r, INT8U c,INT8U *RID)
{
INT8U i; char buf[3];
for (i = 0; i < 8; i++) //读取8字节(64位)光刻码,从低字节开始读取
{ sprintf(buf,"%02X",ROMCODE[i]); //将当前字节转换为十六进制字符串
//将各字节转换后的两个十六进制字符由后向前存入RomCodeString
//各字节的两字符存入顺序依次是:(14,15)(12,13)(10,11)......(2,3)(0,1)
//上面这一行还可以改成以下两行
}
LCD_Buffer[16] = '\0';
LCD_ShowString(r,c,LCD_Buffer);//显示ROMCODE
}
//-----------------------------------------------------------------
// 搜索1-Wire上挂载的所有器件的ROMCODE
//-----------------------------------------------------------------
INT8U Search_ALL_ROM()
{
INT8U i;
DS_CNT = 0; //初始时搜索到的器件个数归0
Level = 0; //初始时设搜索分支层为0
//开始搜索第一个器件之前将64位的ROMCODE清0
for (i = 0; i < 8; i++) ROMCODE[i] = 0x00;
//开始搜索所有在线器件的ROMCODE
while(1)
{
//保存上次搜索遇到的最低分支层
Last_Level = Level;
//当前分支层暂设为0
Level = 0;
//搜索一个新的ROMCODE,未找到或出错时退出
if (Search_ROM1()) break;
//转换并显示当前找到的器件的8字节(64位)ROMCODE
Show_Romcode(2,0,ROMCODE);
//仅保存DS18B20器件的ROMCODE
//(限于EEPROM空间,本例仅最多只保存32个ROMCODE)
if (DS_CNT < 32 && ROMCODE[0] == 0x28)
{ //将所找到的器件ROMCODE写入PIC EEPROM
for (i = 0; i < 8; i++)
{ EEPROM_WRITE(DS_CNT * 8 + i,ROMCODE[i]);
while(WR);
}
__delay_ms(100); DS_CNT++; //累加所找到的总器件数
}
//显示当前找到的总器件数
sprintf(LCD_Buffer,"Found:%d",DS_CNT);
LCD_ShowString(1,0,LCD_Buffer);
//如果完成某次搜索后当前分支层仍为0则结束查找
if (Level == 0) break;
__delay_ms(100);
}
//将所搜索到的总器件数写入EEPROM 0xFF地址
EEPROM_WRITE(0xFF,DS_CNT); while(WR);
return DS_CNT; //返回所搜索到的器件总数
}
//-----------------------------------------------------------------
// 读取存放于8字节数组A中的ROMCODE的第i位(0/1)
//-----------------------------------------------------------------
INT8U Read_ROMCODE_Bit(INT8U A[],INT8U i)
{
//得出64位ROMCODE中第i位所处的字节值,及该位的掩码字节k
}
//-----------------------------------------------------------------
// 将存放于8字节数组A中的ROMCODE的第i位设为0/1
//-----------------------------------------------------------------
void Save_ROMCODE_Bit(INT8U A[],INT8U i,INT8U b)
{
//先求出64位中的第i位所在的字节在数组中的索引j
//再根据该位在此字节内8位中的位置(i % 8)再得出掩码字节k
//例如要设第3位为1,则有k = 0x01 << 3 = 0B00001000.
//相应位设为1或0
}
//-----------------------------------------------------------------
// 根据ROMCODE码读取温度数据
//-----------------------------------------------------------------
float Get_Temperature(char *rom_code)
{
float sign = 1;
RESET(); //复位
ROMCODE_Match(rom_code); //发ROMCODE匹配命令
Write_Byte(CONVERT); //温度转换命令
DelayX100ms(7); //12位分辩率转换时间为750ms
__delay_ms(50);
RESET(); //复位
ROMCODE_Match(rom_code); //发ROMCODE匹配命令
Write_Byte(READ_SCRATCHPAD); //读RAM命令
Temp_Value[0] = Read_Byte(); //读取两字节温度数据
Temp_Value[1] = Read_Byte();
//如果为负数则取反加1,并设置负数标识
//按技术手册说明,高5位为符号位,与上0xF8进行+/-判断
if ( (Temp_Value[1] & 0xF8) == 0xF8)
{
}
}
//-----------------------------------------------------------------
// 发送匹配命令,并发送64位的ROMCODE
//-----------------------------------------------------------------
void ROMCODE_Match(INT8U ROMCODE[])
{
//先发送ROM匹配命令,然后发送64位的ROMCODE
}
//-----------------------------------------------------------------
// 向1-Wire总线写1字节
//-----------------------------------------------------------------
void Write_Byte(INT8U A)
{
for (INT8U i = 0x01;i != 0x00; i <<= 1)
{
if (A & i) Write_DQ_bit(1); else Write_DQ_bit(0);
}
}
//-----------------------------------------------------------------
// 从1-Wire总线读取1字节
//-----------------------------------------------------------------
INT8U Read_Byte()
{
INT8U i,d = 0x00;
for (i = 0; i < 8; i++)
{
Read_Slot(); if (DQ == 1) d |= (1<<i); __delay_us(52);
}
return d;
}
//-----------------------------------------------------------------
// 向1-Wire总线写1位0/1
//-----------------------------------------------------------------
void Write_DQ_bit(INT8U b)
{
DQ_DIR = 0; DQ = 0; //DQ输出
if (b) { __delay_us(5); DQ_DIR = 1; __delay_us(72); }
else { __delay_us(82); DQ_DIR = 1; }
}
//-----------------------------------------------------------------
// 发送读时隙时序
//-----------------------------------------------------------------
void Read_Slot()
{
DQ_DIR = 0; DQ = 0; NOP(); NOP(); DQ_DIR = 1; NOP(); NOP();
}
//-----------------------------------------------------------------
// 1-Wire总线复位
//-----------------------------------------------------------------
void RESET()
{
}
//-----------------------------------------------------------------
// CRC8校验函数 (基于该函数可得出256字节的校验码表,改用查表法进行校验)
// 校验多项式: x^8 + x ^ 5 + x ^ 4 + 1, 去高位后倒序:0x8C
//-----------------------------------------------------------------
void CRC8(INT8U d)
{
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -