STC15F104_二叉树搜索DS18B20_ROM_ID

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include "DS18B20.h"

void main()
{
unsigned char temperature[2];
unsigned char num;
//unsigned char id[4][8];

Delay500ms();
Delay500ms();
UART_INIT();
while(1)
{
// ReadTemperature(temperature, 2);
// SendByte(temperature[0]);
// SendByte(temperature[1]);
num = DS18B20_Search_Rom();
SendStr("ID=");
SendHEX(num);
SendLR();


// foreach(num);

Delay500ms();
Delay500ms();
Delay500ms();
Delay500ms();
}
}

DS18B20.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#include "uart.h"
#include "sys.h"

sbit DQ =P3^5; //数据传输线接单片机的相应的引脚

//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,并检测设备是否存在
**************************************/

void DS18B20_Reset()
{
/* 复位请求 */
DQ = 0; //送出低电平复位信号
Delay500us(); //延时至少480us
DQ = 1; //释放数据线

/* 复位响应 */
while(1==DQ); //直到总线被DS18B20拉低
while(0==DQ); //直到总线被DS18B20拉高
}


/**************************************
从DS18B20读1字节数据
**************************************/

unsigned char DS18B20_ReadByte()
{
unsigned char i = 0;
unsigned char dat = 0;
for (i=0; i<8; i++) //8位计数器
{
dat >>= 1;
DQ = 0; //开始时间片
Delay1us(); //延时等待
DQ = 1; //准备接收
Delay1us(); //接收延时
if (DQ) //读取数据
{
dat |= 0x80;
}
Delay60us(); //等待时间片结束
}
return dat;
}

/**************************************
向DS18B20写1字节数据
**************************************/

void DS18B20_WriteByte(unsigned char dat)
{
char i;
for (i=0; i<8; i++) //8位计数器
{
DQ = 0; //开始时间片
Delay1us(); //延时等待
DQ = 0X01 & dat;
Delay60us(); //等待时间片结束
DQ = 1; //恢复数据线
Delay1us(); //恢复延时
dat >>= 1; //送出数据
}
}

/* 读1位 */
bit DS18B20_read_bit()
{
bit dat = 0;

DQ = 0; //开始时间片
Delay1us(); //延时等待
DQ = 1; //准备接收
Delay1us();; //接收延时
if (DQ) //读取数据
{
dat = 1;
}
Delay60us(); //等待时间片结束
return dat;
}

/* 写1位 */
bit DS18B20_write_bit(bit dat) //
{
DQ = 0; //开始时间片
Delay1us(); //延时等待
DQ = dat;
Delay60us();; //等待时间片结束
DQ = 1; //恢复数据线
Delay1us(); //恢复延时
return dat;
}


//读温度值(低位放tempL;高位放tempH;)
char DS18B20_ReadTemperature(char *pData, int Size)
{
unsigned char TPH = 0; //存放温度值的高字节
unsigned char TPL = 0; //存放温度值的低字节

DS18B20_Reset(); //设备复位
DS18B20_WriteByte(SKIP_ROM); //跳过ROM命令
DS18B20_WriteByte(CONVERT_T); //开始转换命令
while (!DQ); //等待转换完成

DS18B20_Reset(); //设备复位
DS18B20_WriteByte(SKIP_ROM); //跳过ROM命令
DS18B20_WriteByte(READ_SCRATCHPAD); //读暂存存储器命令
TPL = DS18B20_ReadByte(); //读温度低字节
TPH = DS18B20_ReadByte(); //读温度高字节
pData[0] = (TPL >> 4) + (TPH << 4); //返回整数部分
pData[1] = ((TPL&0X08)>>3)*50+ ((TPL&0X04)>>2)*25 ;
return pData[0];
}

//读温度值(低位放tempL;高位放tempH;)
char DS18B20_Read_ROM_Temperature(char *pID, int IDSize, char *pData, int Size)
{
unsigned char TPH = 0; //存放温度值的高字节
unsigned char TPL = 0; //存放温度值的低字节
unsigned char i = 0;

DS18B20_Reset(); //设备复位
DS18B20_WriteByte(SKIP_ROM); //跳过ROM命令
DS18B20_WriteByte(CONVERT_T); //开始转换命令
while (!DQ); //等待转换完成

DS18B20_Reset(); //设备复位
DS18B20_WriteByte(MATH_ROM); //跳过ROM命令
for(i = 0; i < IDSize; i++) //发送8个字节的序列号
{
DS18B20_WriteByte(pID[i]);
}

DS18B20_WriteByte(READ_SCRATCHPAD); //读暂存存储器命令
TPL = DS18B20_ReadByte(); //读温度低字节
TPH = DS18B20_ReadByte(); //读温度高字节
pData[0] = (TPL >> 4) + (TPH << 4); //返回整数部分
pData[1] = ((TPL&0X08)>>3)*50+ ((TPL&0X04)>>2)*25 ;
return pData[0];
}


/* 遍历搜索单线上所连的所有18b20的序列号 */
unsigned char DS18B20_Search_Rom()
{
unsigned char i = 0;
unsigned char aByte = 0;
unsigned char num = 0;
unsigned char Stack[10];
unsigned char StackTop;
unsigned char Way;
unsigned char MarkTheWay[8]; //记住每个分支点的上一次走向

bit FirstBit;
bit SecondBit;

StackTop = 0; /* 栈的初始化 */
Stack[StackTop] = 0; /* 栈底初始化 */
num = 0;
do
{
DS18B20_Reset();
DS18B20_WriteByte(SEARCH_ROM);
i=0;
while(++i) //起始值大于栈底的0, 直到总线无响应
{
aByte >>= 1; //首先把最高位让出来, 最高位会默认补0
FirstBit = DS18B20_read_bit();
SecondBit = DS18B20_read_bit();

if(1 == FirstBit && 1 == SecondBit) //第1种情况, 总线无应答
{
num++;
break ;
}
if(0 == FirstBit && 1 == SecondBit) //第3种情况,代表0
{
aByte |= 0X00; //此语句运行无意义, 仅仅为了方便阅读理解
DS18B20_write_bit(0);
}
if(1 == FirstBit && 0 == SecondBit) //第2种情况,代表1
{
aByte |= 0X80;
DS18B20_write_bit(1);
}
if(0 == FirstBit && 0 == SecondBit) //第4种情况,既有 0 又有 1
{
if( i > Stack[StackTop]) //如果是新的冲突标记,
{
Stack[++StackTop] = i; //入栈
aByte |= 0X00; //此语句运行无意义, 仅仅为了方便阅读理解
DS18B20_write_bit(0); //向 0 方向的分支走
SetBit(MarkTheWay, sizeof(MarkTheWay), i, 0);// 记住本次在分支 i 的走向
}
else if( i == Stack[StackTop]) //说明这不是新的冲突且这是栈顶
{
StackTop--; //出栈
aByte |= 0X80;
DS18B20_write_bit(1); //向 1 方向的分支走
SetBit(MarkTheWay, sizeof(MarkTheWay), i, 1);
}

else if( i < Stack[StackTop]) //这说明这是靠近根分支的冲突
{
Way = GetBit(MarkTheWay, sizeof(MarkTheWay), i);//取出原先的走法
aByte |= (Way << 7);
DS18B20_write_bit(Way); //按照 之前 方向的分支走
}
}
if(i%8==0)
{
SendHEX(aByte);
}
if(i >= 64)
{
SendLR();
}
}
}while(Stack[StackTop] != 0);
return num;
}

sys.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include "INTRINS.H"

void Delay500us() //@11.0592MHz
{
unsigned char i, j;

i = 6;
j = 93;
do
{
while (--j);
} while (--i);
}

void Delay1us() //@11.0592MHz
{
_nop_();
}

void Delay60us() //@11.0592MHz
{
unsigned char i, j;

_nop_();
_nop_();
i = 1;
j = 161;
do
{
while (--j);
} while (--i);
}

void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;

i = 22;
j = 3;
k = 227;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}

void SetBit(unsigned char* pData, unsigned int DataSize, unsigned int bits, unsigned int flag)
{
unsigned char Magic;
Magic = 1 << (bits % 8);
if (flag)
{
pData[bits/8] |= Magic;
}
else
{
pData[bits/8] &= ~Magic;
}
}

bit GetBit(unsigned char* pData, unsigned int DataSize, unsigned int bits)
{
return 0x01 & (pData[bits/8] >> (bits%8));
}

uart.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#include "reg51.h"

//#define BAUD 0xF400 // 1200bps @ 11.0592MHz
//#define BAUD 0xFA00 // 2400bps @ 11.0592MHz
//#define BAUD 0xFD00 // 4800bps @ 11.0592MHz
#define BAUD 0xFE80 // 9600bps @ 11.0592MHz
//#define BAUD 0xFF40 //19200bps @ 11.0592MHz
//#define BAUD 0xFFA0 //38400bps @ 11.0592MHz


sfr AUXR = 0x8E;
sbit RXB = P3^0;
sbit TXB = P3^1;

typedef bit BOOL;
typedef unsigned char BYTE;
typedef unsigned int WORD;

BYTE TBUF,RBUF;
BYTE TDAT,RDAT;
BYTE TCNT,RCNT;
BYTE TBIT,RBIT;
BOOL TING,RING;
BOOL TEND,REND;

void UART_INIT();

BYTE t, r;
BYTE buf[16];

//-----------------------------------------
//Timer interrupt routine for UART

void tm0() interrupt 1
{
if (RING)
{
if (--RCNT == 0)
{
RCNT = 3; //reset send baudrate counter
if (--RBIT == 0)
{
RBUF = RDAT; //save the data to RBUF
RING = 0; //stop receive
REND = 1; //set receive completed flag
}
else
{
RDAT >>= 1;
if (RXB)
RDAT |= 0x80; //shift RX data to RX buffer
}
}
}
else if (!RXB)
{
RING = 1; //set start receive flag
RCNT = 4; //initial receive baudrate counter
RBIT = 9; //initial receive bit number (8 data bits + 1 stop bit)
}

if (--TCNT == 0)
{
TCNT = 3; //reset send baudrate counter
if (TING) //judge whether sending
{
if (TBIT == 0)
{
TXB = 0; //send start bit
TDAT = TBUF; //load data from TBUF to TDAT
TBIT = 9; //initial send bit number (8 data bits + 1 stop bit)
}
else
{
TDAT >>= 1; //shift data to CY
if (--TBIT == 0)
{
TXB = 1;
TING = 0; //stop send
TEND = 1; //set send completed flag
}
else
{
TXB = CY; //write CY to TX port
}
}
}
}
}

void UART_INIT()
{
TMOD = 0x00; //timer0 in 16-bit auto reload mode
AUXR = 0x80; //timer0 working at 1T mode
TL0 = BAUD;
TH0 = BAUD>>8; //initial timer0 and set reload value
TR0 = 1; //tiemr0 start running
ET0 = 1; //enable timer0 interrupt
PT0 = 1; //improve timer0 interrupt priority
EA = 1; //open global interrupt switch

TING = 0;
RING = 0;
TEND = 1;
REND = 0;
TCNT = 0;
RCNT = 0;
}

void SendByte(char aByte)
{
while(!TEND);
TEND = 0;
TBUF = aByte;
TING = 1;
}
char RecvByte()
{
while(!REND);
REND = 0;
return RBUF;
}

void SendData(char* pData, int len)
{
int i;
for(i=0; i<len; i++)
{
SendByte(pData[i]);
}
}
void SendHEX(unsigned char Data)
{
unsigned char highByte = (Data >> 4);
unsigned char lowByte = (Data & 0X0F);

highByte += 0x30;
if (highByte > 0x39)
{
SendByte(highByte + 0x07);
}
else
{
SendByte(highByte);
}

lowByte += 0x30;
if (lowByte > 0x39)
{
SendByte(lowByte + 0x07);
}
else
{
SendByte(lowByte);
}
}



void SendLR()
{
SendByte('\r');
SendByte('\n');
}

void SendStr(char* pData)
{
int i = 0;;
while(pData[i] != '\0')
{
SendByte(pData[i++]);
}
}





//void main()
//{
// char aByte;
// UART_INIT();

// while (1)
// { //user's function
// aByte = RecvByte();
// SendByte(aByte);
// }
//}

STARTUP.A51

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
$NOMOD51
;------------------------------------------------------------------------------
; This file is part of the C51 Compiler package
; Copyright (c) 1988-2005 Keil Elektronik GmbH and Keil Software, Inc.
; Version 8.01
;
; *** <<< Use Configuration Wizard in Context Menu >>> ***
;------------------------------------------------------------------------------
; STARTUP.A51: This code is executed after processor reset.
;
; To translate this file use A51 with the following invocation:
;
; A51 STARTUP.A51
;
; To link the modified STARTUP.OBJ file to your application use the following
; Lx51 invocation:
;
; Lx51 your object file list, STARTUP.OBJ controls
;
;------------------------------------------------------------------------------
;
; User-defined <h> Power-On Initialization of Memory
;
; With the following EQU statements the initialization of memory
; at processor reset can be defined:
;
; <o> IDATALEN: IDATA memory size <0x0-0x100>
; <i> Note: The absolute start-address of IDATA memory is always 0
; <i> The IDATA space overlaps physically the DATA and BIT areas.
IDATALEN EQU 80H
;
; <o> XDATASTART: XDATA memory start address <0x0-0xFFFF>
; <i> The absolute start address of XDATA memory
XDATASTART EQU 0
;
; <o> XDATALEN: XDATA memory size <0x0-0xFFFF>
; <i> The length of XDATA memory in bytes.
XDATALEN EQU 0
;
; <o> PDATASTART: PDATA memory start address <0x0-0xFFFF>
; <i> The absolute start address of PDATA memory
PDATASTART EQU 0H
;
; <o> PDATALEN: PDATA memory size <0x0-0xFF>
; <i> The length of PDATA memory in bytes.
PDATALEN EQU 0H
;
;</h>
;------------------------------------------------------------------------------
;
;<h> Reentrant Stack Initialization
;
; The following EQU statements define the stack pointer for reentrant
; functions and initialized it:
;
; <h> Stack Space for reentrant functions in the SMALL model.
; <q> IBPSTACK: Enable SMALL model reentrant stack
; <i> Stack space for reentrant functions in the SMALL model.
IBPSTACK EQU 0 ; set to 1 if small reentrant is used.
; <o> IBPSTACKTOP: End address of SMALL model stack <0x0-0xFF>
; <i> Set the top of the stack to the highest location.
IBPSTACKTOP EQU 0xFF +1 ; default 0FFH+1
; </h>
;
; <h> Stack Space for reentrant functions in the LARGE model.
; <q> XBPSTACK: Enable LARGE model reentrant stack
; <i> Stack space for reentrant functions in the LARGE model.
XBPSTACK EQU 0 ; set to 1 if large reentrant is used.
; <o> XBPSTACKTOP: End address of LARGE model stack <0x0-0xFFFF>
; <i> Set the top of the stack to the highest location.
XBPSTACKTOP EQU 0xFFFF +1 ; default 0FFFFH+1
; </h>
;
; <h> Stack Space for reentrant functions in the COMPACT model.
; <q> PBPSTACK: Enable COMPACT model reentrant stack
; <i> Stack space for reentrant functions in the COMPACT model.
PBPSTACK EQU 0 ; set to 1 if compact reentrant is used.
;
; <o> PBPSTACKTOP: End address of COMPACT model stack <0x0-0xFFFF>
; <i> Set the top of the stack to the highest location.
PBPSTACKTOP EQU 0xFF +1 ; default 0FFH+1
; </h>
;</h>
;------------------------------------------------------------------------------
;
; Memory Page for Using the Compact Model with 64 KByte xdata RAM
; <e>Compact Model Page Definition
;
; <i>Define the XDATA page used for PDATA variables.
; <i>PPAGE must conform with the PPAGE set in the linker invocation.
;
; Enable pdata memory page initalization
PPAGEENABLE EQU 0 ; set to 1 if pdata object are used.
;
; <o> PPAGE number <0x0-0xFF>
; <i> uppermost 256-byte address of the page used for PDATA variables.
PPAGE EQU 0
;
; <o> SFR address which supplies uppermost address byte <0x0-0xFF>
; <i> most 8051 variants use P2 as uppermost address byte
PPAGE_SFR DATA 0A0H
;
; </e>
;------------------------------------------------------------------------------

; Standard SFR Symbols
ACC DATA 0E0H
B DATA 0F0H
SP DATA 81H
DPL DATA 82H
DPH DATA 83H

NAME ?C_STARTUP


?C_C51STARTUP SEGMENT CODE
?STACK SEGMENT IDATA

RSEG ?STACK
DS 1

EXTRN CODE (?C_START)
PUBLIC ?C_STARTUP

CSEG AT 0
?C_STARTUP: LJMP STARTUP1

RSEG ?C_C51STARTUP

STARTUP1:

IF IDATALEN <> 0
MOV R0,#IDATALEN - 1
CLR A
IDATALOOP: MOV @R0,A
DJNZ R0,IDATALOOP
ENDIF

IF XDATALEN <> 0
MOV DPTR,#XDATASTART
MOV R7,#LOW (XDATALEN)
IF (LOW (XDATALEN)) <> 0
MOV R6,#(HIGH (XDATALEN)) +1
ELSE
MOV R6,#HIGH (XDATALEN)
ENDIF
CLR A
XDATALOOP: MOVX @DPTR,A
INC DPTR
DJNZ R7,XDATALOOP
DJNZ R6,XDATALOOP
ENDIF

IF PPAGEENABLE <> 0
MOV PPAGE_SFR,#PPAGE
ENDIF

IF PDATALEN <> 0
MOV R0,#LOW (PDATASTART)
MOV R7,#LOW (PDATALEN)
CLR A
PDATALOOP: MOVX @R0,A
INC R0
DJNZ R7,PDATALOOP
ENDIF

IF IBPSTACK <> 0
EXTRN DATA (?C_IBP)

MOV ?C_IBP,#LOW IBPSTACKTOP
ENDIF

IF XBPSTACK <> 0
EXTRN DATA (?C_XBP)

MOV ?C_XBP,#HIGH XBPSTACKTOP
MOV ?C_XBP+1,#LOW XBPSTACKTOP
ENDIF

IF PBPSTACK <> 0
EXTRN DATA (?C_PBP)
MOV ?C_PBP,#LOW PBPSTACKTOP
ENDIF

MOV SP,#?STACK-1

; This code is required if you use L51_BANK.A51 with Banking Mode 4
;<h> Code Banking
; <q> Select Bank 0 for L51_BANK.A51 Mode 4
#if 0
; <i> Initialize bank mechanism to code bank 0 when using L51_BANK.A51 with Banking Mode 4.
EXTRN CODE (?B_SWITCH0)
CALL ?B_SWITCH0 ; init bank mechanism to code bank 0
#endif
;</h>
LJMP ?C_START

END