1-wire学习笔记

1-wire是美国Dallas公司推出的一种外围串行扩展总线技术,它只使用一根信号线,即传输时钟又传输数据,并且数据传输是双向的。
1-wire单总线适用于单个主机系统,能够控制一个或多个从机设备。

1 ROM码

1-wire只需要一根信号线,为了区分信号线上的不同从机设备,厂家在生产1-wire器件时,都会在器件的ROM中编制唯一的64位序列号,通过寻址就可以把不同的器件区分开。

ROM码从最低位开始前8位是家族码,代表器件的分类编号;接着的48位是一个唯一的序列号;最后8位是前56位的CRC校验码。

2 基本时序

单总线的基本操作分别是复位读位写位,定义了基本操作后,对器件的读写操作可以通过多次调用基本操作完成。

2.1 复位

复位时序:

  1. 首先主机发出复位脉冲:拉低信号线,持续大概 $480-960\mu s$;
  2. 然后主机释放信号线,信号线被上拉电路上拉为高电平;
  3. 从机等待 $15-60\mu s$ 后,会主动发出存在脉冲:拉低信号线,持续大概 $60-240\mu s$。

2.2 读位

读位时序:

  1. 主机首先拉低信号线,并且至少维持 $1\mu s$ 的时间;
  2. 主机释放信号线,读取信号线状态,从释放到读取状态,不能超过 $15\mu s$;
  3. 读取状态后,至少 $46\mu s$ 后才能进行下一次读位。

2.3 写位

写位时序:

  1. 写”0”
    1. 主机直接将信号线拉低,持续时间大于 $60\mu s$ 小于 $120\mu s$ 即可;
  2. 写”1”
    1. 主机首先拉低信号线,并且至少维持 $1\mu s$ 的时间;
    2. 主机释放信号线,等待至少 $60\mu s$ 以供从机采样。

3 ROM命令

1-wire针对不同类型的期间规定了详细的命令,命令有两种类型。一类是ROM命令,每种命令均为8位,用来搜索、甄别从器件,实现从器件寻址或简化总线操作;另一类是器件操作的功能命令

3.1 ROM命令表

命令 功能 详细描述
[F0H] 搜索ROM指令 当系统初始化时,总线控制器通过此指令多次循环搜索ROM编码,以确认所有从机器件
[33H] 读取ROM指令 当总线上只有一个从器件时才会使用此指令,允许总线控制器直接读取从机的序列码
[55H] 匹配ROM指令 匹配ROM指令,使总线控制器在多点总线上定位一个特定的从器件
[CCH] 忽略ROM指令 忽略ROM指令,此指令允许总线控制器不必提供64位ROM码就使用功能指令
[ECH] 报警搜索指令 当总线上存在满足报警条件的从机时,该从机响应此指令

3.2 1-wire命令序列

所有单总线器件操作的流程为:

  1. 初始化(对总线上的器件进行初始化)
  2. ROM命令(指令寻找和匹配,指定待操作器件)
  3. 功能指令(进行具体操作或传输数据)

3.3 搜索算法

3.3.1 硬件基础

当向信号线写入搜索指令[F0H]后,进入搜索模式。在搜索模式中,总线上的所有从机设备都会一起向主机按位发送自己的ROM码及其补码,数据在总线上按”“逻辑组合,总线控制器在接受一位原码数据和一位补码数据后,可向总线写入一位数据,禁止对应该处ROM码为此数据的器件继续发送数据。按接受到的两位数据的不同,总线控制器可得到不同的信息:

数据 意义
00 总线上设备该位ROM码存在冲突
01 总线上设备该位ROM码均为0
10 总线上设备该位ROM码均为1
11 总线上无设备

3.3.2 算法

搜索算法采用的是二叉树型结构,搜索过程沿各分节点进行,直到找到器件的ROM码为止;后续的搜索操作沿着节点上的其它路径进行,按照同样的方式直到找到总线上的所有ROM码。

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
unsigned char romID[8];       // save romID
unsigned char lastDeviceFlag = 0;
unsigned char lastDiscrepancy = 0;


unsigned char reset() {
unsigned char ack;
...
return ack; // 0: no device; 1: exist device
}
unsigned char read_2_bit() {...} // read 2 bits data from 1-wire
void write_bit() {...} // write 1 bit data to 1-wire
void write_byte(unsigned char byteData) {...} // write 1 byte data to 1-wire

void search(unsigned char *addr) {
unsigned char bitID = 1;
unsigned char byteID = 0;
unsigned char discrepancy;
unsigned char shiftID = 1;
unsigned char read2Bit;
unsigned char writeBit;

if (!lastDeviceFlag) {
if (reset()) {
writeByte(0xf0); // write the search_comman to start
do {
read2Bit = read_2_bit();
if (read2Bit == 3)
break;
else if (read2Bit)
writeBit = read2Bit & 1;
else {
if (bitID < lastDiscrepancy)
writeBit = (romID[byteID] & shiftID) ? 1 : 0;
else
writeBit = (bitID == lastDiscrepancy);

if (writeBit == 0) discrepancy = bitID;
}

if (writeBit)
romID[byteID] |= shiftID;
else
romID[byteID] &= ~shiftID;

write_bit(writeBit);

bitID++;
shiftID <<= 1;
if (shiftID == 0) {
byteID++;
shiftID = 1;
}
} while (byteID < 8);

if (bitID > 64) {
lastDiscrepancy = discrepancy;
if (lastDiscrepancy == 0) lastDeviceFlag = 1;
unsigned char i;
for (i=0; i<8; i++) addr[i] = romID[i];
} else {
lastDiscrepancy = 0;
lastDeviceFlag = 0;
}
} else {
lastDeviceFlag = 0;
lastDiscrepancy = 0;
}
}
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!