/******本程序是基于DS5000/DS2251T单片机开发的,运行时需要有128K RAM *****/
#include <absacc.h>
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <reg5000.h>
/******************************* 参数配置 *****************************/
#define XtalFreq (11059490) // 主晶振频率
#define CntrFreq (XtalFreq/12) // 主计数器频率
#define BaudRate (38400) // 波特率
#define CntrTime (8) // 计数器的周期数
#define Ft (32768.0) // 目标晶振频率
#define FALSE 0
#define TRUE 1
sbit DQ = 0x97; // 定义DQ引脚为P1.7
/******************************* 全局变量 ********************************/
unsigned char ROM[8]; // ROM 位
unsigned char lastDiscrep = 0; // 上次差值
unsigned char doneFlag = 0; // 完成标志
unsigned char FoundROM[5][8]; // ROM 代码表
unsigned char numROMs;
unsigned char dowcrc;
unsigned char code dscrc_table[] = {
0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220,
35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98,
190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7,
219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154,
101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36,
248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185,
140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139,
87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53};
/******************************* 延时函数 ********************************
* 功能:在11.059MHz的晶振条件下调用本函数需要24μs ,然后每次计数需16μs
**************************************************************************/
void delay(int useconds) {
int s;
for (s=0; s<useconds;s++);
}
/******************************* 复位函数 *******************************
* 功能:完成单总线的复位操作。
* 复位时间为480μs,因此延时时间为(480-24)/16 = 28.5,取29μs。
* 经过70μs之后检测存在脉冲,因此延时时间为(70-24)/16 = 2.875,取3μs。
**************************************************************************/
unsigned char ow_reset(void) {
unsigned char presence;
DQ = 0; // 将 DQ 线拉低
delay(29); // 保持 480μs
DQ = 1; // DQ返回高电平
delay(3); // 等待存在脉冲
presence = DQ; // 获得存在信号
delay(25); // 等待时间隙结束
return(presence); // 返回存在信号,0 = 器件存在, 1 = 无器件
}
/****************************** 位写入函数 *******************************
* 功能:向单总线写入1位值:bitval
*************************************************************************/
void write_bit(char bitval) {
DQ = 0; // 将DQ 拉低开始写时间隙
if(bitval==1) DQ =1; // 如果写1,DQ 返回高电平
delay(5); // 在时间隙内保持电平值,
DQ = 1; // Delay函数每次循环延时16μs,因此delay(5) = 104μs
}
/**************************** 字节写入函数 *******************************
* 功能:向单总线写入一个字节值:val
*************************************************************************/
void write_byte(char val) {
unsigned char i;
unsigned char temp;
for (i=0; i<8; i++) { // 写入字节, 每次写入一位
temp = val>>i;
temp &= 0x01;
write_bit(temp);
}
delay(5);
}
/**************************** 位读取函数 ********************************
* 功能:从单总线上读取一位信号,所需延时时间为15μs,因此无法调用前面定义
* 的delay()函数,而采用一个for()循环来实现延时。
* ***********************************************************************/
unsigned char read_bit(void) {
unsigned char i;
DQ = 0; //将DQ 拉低开始读时间隙
DQ = 1; // then return high
for (i=0; i<3; i++); // 延时15μs
return(DQ); // 返回 DQ 线上的电平值
}
/**************************** 字节读取函数 *******************************
* 功能:从单总线读取一个字节的值
*************************************************************************/
unsigned char read_byte(void) {
unsigned char i;
unsigned char value = 0;
for (i=0;i<8;i++) { // 读取字节,每次读取一个字节
if(read_bit()) value|=0x01<<i; // 然后将其左移
delay(6);
}
return(value);
}
/***************************** 读取ROM代码函数 ***************************
* 功能:用于读取单总线上单个DS1820器件的ROM代码,对于多个器件需要采用
* 搜索ROM函数。
**************************************************************************/
void Read_ROMCode(void) {
int n;
char dat[9];
printf("\nReading ROM Code\n");
ow_reset();
write_byte(0x33);
for (n=0;n<8;n++){dat[n]=read_byte();}
printf("\nROMCode=%X%X%X%X\n",
dat[7],dat[6],dat[5],dat[4],dat[3],dat[2],dat[1],dat[0]);
}
/*************************** 单总线CRC函数 ******************************
* 功能:完成一次循环冗余校验,进行搜索ROM操作时应包含循环冗余校验
**************************************************************************/
unsigned char ow_crc( unsigned char x) {
dowcrc = dscrc_table[dowcrc^x];
return dowcrc;
}
/********************************* NEXT函数 ******************************
* 功能:搜索单总线上的下一个器件,如果单总线上没有其它器件则返回“假”
**************************************************************************/
unsigned char Next(void) {
unsigned char m = 1; // ROM 位索引
unsigned char n = 0; // ROM 字节索引
unsigned char k = 1;
unsigned char x = 0;
unsigned char discrepMarker = 0;
unsigned char g; // 输出位
unsigned char nxt; // 返回值
int flag;
nxt = FALSE;
dowcrc = 0;
flag = ow_reset(); // 复位单总线
if(flag||doneFlag) { // 如果没有其它器件则返回“假”
lastDiscrep = 0;
return FALSE;
}
write_byte(0xF0); // 发送搜索ROM 命令
do {
x = 0;
if(read_bit()==1) x = 2;
delay(6);
if(read_bit()==1) x |= 1;
if(x ==3) break;
else {
if(x>0)
g = x>>1;
else {
if(m<lastDiscrep) g = ((ROM[n]&k)>0);
else g = (m==lastDiscrep);
if (g==0) discrepMarker = m;
}
if(g==1) ROM[n] |= k;
else ROM[n] &= ~k;
write_bit(g);
m++;
k = k<<1;
if(k==0) {
ow_crc(ROM[n]);
n++; k++;
}
}
} while(n<8); // 循环,直到全部ROM字节0~7都完成
if(m<65||dowcrc) lastDiscrep=0;
else { // 搜索成功,置位lastDiscrep, lastOne和nxt
lastDiscrep = discrepMarker;
doneFlag = (lastDiscrep==0);
nxt = TRUE; // 表示搜索还未结束,单总线上还有其它器件
}
return nxt;
}
/********************************* FIRST函数 ******************************
* 功能: 复位当前ROM搜索状态并调用NEXT函数搜索单总线的第一个器件
**************************************************************************/
unsigned char First(void) {
lastDiscrep = 0;
doneFlag = FALSE;
return Next();
}
/********************************* 读暂存器 *******************************
* 功能:读取暂存器中9个字节的数据
**************************************************************************/
void Read_ScratchPad(void) {
int j;
char pad[10];
printf("\nReading ScratchPad Data\n");
write_byte(0xBE);
for (j=0;j<9;j++){pad[j]=read_byte();}
printf("\n ScratchPAD DATA =%X%X%X%X%X%X\n",
pad[8],pad[7],pad[6],pad[5],pad[4],pad[3],pad[2],pad[1],pad[0]);
}
//
/****************************** FIND DEVICES *****************************
* 功能:首先复位单总线以确定是否存在任何器件,如果存在则将其唤醒。然后调用
* FIRST函数跟踪冲突位,并返回到NEXT函数。NEXT函数完成鉴别单总线上每个器件
* 唯一ROM代码的大部分工作。
**************************************************************************/
void FindDevices(void) {
unsigned char m;
if(!ow_reset()) { // 如果单总线上存在器件则开始处理
if(First()) { // 至少发�