DS18B20 1-WIRE ROM搜索算法详解

2023-05-16

转自:http://blog.sina.com.cn/s/blog_57ad1bd20102uxxw.html

1-WIRE搜索算法详解(1)

 

0前言

美信公司(http://www.maximintegrated.com/cn)生产了许多1-Wire®器件产品,硬件电路极致简单,而相应软件就显得复杂。美信网站的《应用笔记187介绍了单线ROM搜索算法并提供了TMEX API测试程序的源代码,该算法较为复杂,而且是通用于多平台windows\JAVA等)的API,无法直接在KeilC上调试并写入单片机。本人在学习理解其算法后,适当修改源代码,并作上了详细的注释和图解,代码在KeilC环境下调试通过,并在一个挂接4DS18B20的小型1-Wire环境中测试成功,顺利获取4ROM码。现把算法分析及测试过程成文如下,其中算法部分保留了大部分AN187的内容,但作了许多修改和补充,原文可参见http://www.maximintegrated.com/cn/app-notes/index.mvp/id/187本文介绍的搜索算法及源代码,对任何现有的或将要推出的1-Wire器件都是有效的。

 

1测试环境及图示

硬件连接:4DS18B20并接,MCU为笙泉MG82G516仿真芯片(其他普通51系列都可,仿真芯片可以方便调试),软件为Keil 3

DS18B20 <wbr>1-WIRE <wbr>ROM搜索算法详解(1)

1.    4DS18B20在面包板上


DS18B20 <wbr>1-WIRE <wbr>ROM搜索算法详解(1)

2.笙泉THO65B+仿真器(可仿真51芯片)



DS18B20 <wbr>1-WIRE <wbr>ROM搜索算法详解(1)

3.Saleae Logic分析仪



DS18B20 <wbr>1-WIRE <wbr>ROM搜索算法详解(1)

 

4.全家福(开发板仅安装芯片及供电用)

 

1中,4DS18B20并接,红黄黑三线为电源、信号、地,绿色线通黄色线,接逻辑分析仪。原来逻辑分析仪从单片机端采集1-Wire信号,但实测中主机拉高电平(从机低电平)时,逻辑分析仪采集到一个尖刺脉冲,造成分析仪识别1-Wire协议失误;后将采集线接到从机端,信号正常。

2是笙泉THO65B+仿真器,USB接口,可仿真51系列,方便程序调试。该仿真器芯片型号为MPC82G516,类似于STC15F2K60S2,为1T单片机,片上64KB Flash, 60KB程序存储器, 3KB IAP存储器, 1KB ISP 引導程序空间,以及1KRAM

3为逻辑分析仪,十分小巧,支持8路信号输入,最高采样速率24M,实际一般使用16MUSB接口,附送软件。图4为开发板,本例中主要功能仅为提供CPU插座及供电,1-Wire器件连接是相当简单的。

 

 再给出一个用逻辑分析采集到的ROM搜索的全过程相关图片,有了这个分析仪,就可以十分方便地读出搜索到的ROM码,还能通过程序执行时产生“波形”分析调试代码,也可以方便的测定延时函数的时间。

DS18B20 <wbr>1-WIRE <wbr>ROM搜索算法详解(1)

 

DS18B20 <wbr>1-WIRE <wbr>ROM搜索算法详解(1)


DS18B20 <wbr>1-WIRE <wbr>ROM搜索算法详解(1)


 

2   1-Wire®器件的ROM

Maxim1-Wire®器件都带有一个64位的唯一注册码,生产时通过激光刻蚀在内部只读存储器内(ROM),用于在1-Wire网络中通过1-Wire主机对其寻址。如果1-Wire网络中从机器件数量不定且ROM码未知,则可采用搜索算法查找这些码。下表是64Bit ROM码的组成示意:
MSB表示Most Significant Bit最高有效位,LSB表示Least Significant Bit最低有效位)       

MSB                        64ROM                          LSB

8CRC

MSB              LSB

48位序列号

MSB              LSB

8位家庭码

MSB               LSB

搜索顺序是从低位到高位的,如下:

64位←——————————————————————第1

5. 64位唯一的ROM注册码

 

 DS18B20 <wbr>1-WIRE <wbr>ROM搜索算法详解(1)

 

6、通过逻辑分述仪采集到的1-Wire信号

图片说明:

1. 上图是逻辑分析仪在ROM搜索到1ROM1-Wire总线上采集到的信号,可见搜索耗时15ms

2. 因低位先传送,逻辑分析仪上显示低位在左边;

3. 信号自左到右分别为:复位R、存在脉冲、主机发搜索命令8位、从机回复64ROM码(包括家族码0x2848ROM8CRC码)

4. 分析软件识别出了1-Wire协议,在信号顶部标示了内容和数位,阅读时相当直观。

5. 将图6中家族码的部分放大如图7

DS18B20 <wbr>1-WIRE <wbr>ROM搜索算法详解(1)

 

7. 搜索过程中采集的家族码部分放大图

图片说明

1.    家族码一共为8位,图中有3通道信号,最上面第1通道从1-Wire总线采集,第2通道是“1写”程序时通过转换指定单片机引脚得到(进入该程序时置位,退出前复位);第3路为“2读”信号;均为高电平;

2.    识别8位“一写”代码可见从左到右为00010100,反过来就0010100028H

3.    如何识别1-Wire读写的时序,请参见1-Wire技术资料或DS18B20数据表资料,本文不描述。

 

 

3  1-Wire搜索协议

搜索算法采用的是二叉树型结构,搜索过程沿各分节点进行,直到找到器件的ROM码即叶子为止;后续的搜索操作沿着节点上的其它路径进行,按照同样的方式直到找到总线上的所有器件代码。本文后面提供了一个简单示例:4ROM,每个仅取4位,构造了一棵二叉树,并在此示例上推导出搜索算法的许多细节及实现。

 

搜索算法首先通过复位(reset)和在线应答脉冲(presence pulse)时隙将1-Wire总线上的所有器件复位;成功地执行该操作后,发送1 个字节的搜索命令;搜索命令使1-Wire器件准备就绪、开始进行搜索操作。

 

搜索命令分为两类:标准搜索命令(F0 hex)用来搜索连接到网络中所有器件;报警或有条件搜索命令(EC hex)只用来搜索那些处于报警状态下的器件,这种方式缩小了搜索范围,可以快速查找到所需要注意的器件。本文附带代码仅使用了标准搜索命令。

 

搜索命令发出之后,开始实际的搜索过程。首先总线上的所有从机器件同时发送ROM(也叫注册码)中的第一位(最低有效位) (参见1)与所有的1-Wire通信一样,无论是读取数据还是向从机器件写数据,都由1-Wire主机启动每一位操作。按照1-Wire协议设置特性,当所有从机器件同时应答主机时,结果相当于全部发送数据位的逻辑AND;从机发送其ROM码的第一位后,主机启动下一位操作、接着从机发送第一位数据的补码;从两次读到的数据位可以对ROM码的第一位做出几种判断(参见下表)上述二次读取1-Wire总线上当前位ROM码的正码和反码的操作,本文简述为“二读”

 

1. 检索信息位

主机读一位

从机提供当前位正码

主机再读一位

从机提供该位反码

二读后可以判断获得的信息

注意:主线读到的是各个响应从机的“线与”逻辑

0

0

连接器件的该位有01,这是一个差异位(混码位)

0

1

连接器件的该位均为0

1

0

连接器件的该位均为1

1

1

没有器件与总线相连

 

按照搜索算法的要求,“二读”后1-Wire主机必须向总线上的从机发回一个指定位,称为“一写”;如果从机器件中ROM码的当前位的值与该数据位匹配,则继续参与搜索过程;若从机器件的当前位与之不匹配,则该器件转换到休眠状态,直到下一个1-Wire复位信号到来被再次唤醒。其余63ROM码的搜索依然按照这种读两位写一位的模式进行重复操作。

 

按照这种搜索算法进行下去,最终除了一个从机器件外所有从机将进入等待状态,经过一轮检测,就可得到最后保留(未进入等待状态)器件的ROM码。在后续搜索过程中,选用不同的路径(或分支)来查找其它器件的ROM码。需要注意的是本文ROM码的数据位用第1(最低有效位)到第64 (最高有效位)表示,而不是第0位到第63位的模式;这样设置允许将差异位置计数器初始值置为0,为以后的比较提供了方便。

 

上述过程可简述为“二读一写”,“二读”结果为“00”,主机就判定这一位是“差异位”,也可称为“冲突位”“混码位”。举例来说,“二读”就相当于“老师问名”,设想学生的名字就是64ROM码,老师第1问时学生反应为:“1的不吭声,0就高喊到”;第2问时学生反过来:“0的不吭声,1的高喊到”,老师通过二次答复就可分辨:“不吭声+不吭声”表示一个学生也没有;“不吭声+到”表示大家都是1,“到+不吭声”表示大家都是0;而“到+到”收表示有01。试想,如果有01,只要有1个喊到,老师就能听到,这种合成效果就是所谓的“线与”,当然这里应称为“声与”。

 

搜索到“差异位”时,主机如何确定搜索方向(0还是1),这是本算法的核心问题,这也是典型的“二叉树遍历”算法。或许有人会提出一种“笨”算法,就是穷举64位组合,从000…000111…111遍历,有应答的从机就会被一个一个找出来,这确实是一种简单的“笨”算法,在许多地方很有用,但对于64ROM来说,假设一位的访问需要100us64位则需要6.4ms,穷举全部ROM码有264=1844亿亿,极端的遍历时间为37亿年,这确实是一种无法实现的笨办法。


下表列出了1-Wire主机和从机的搜索过程

Master

Slave

发送“复位”信号

产生“存在”脉冲

发送“搜索”命令

全体器件进入“应付搜索”状态,不断地根据主机信号作出反应

从总线读取1位“线与”

全体器件发送64ROM码的第1

从总线读取1位“线与”

全体器件发送64ROM码的第1位的反码

向总线写1位(按算法)

器件们接收此位后,凡与ROM码的第1位不符的器件进入休眠状态

64ROM码后续位

器件发后续位ROM

64ROM码后续位的反码

器件发后续位ROM码的反码

写后续各位

器件们接收此位后,凡与ROM码的当前位不符的器件进入休眠状态.

 

从上表可以看出:如果所有总线上的器件在当前位具有相同值,那么只有一条分支路径可选;总线上没有器件响应的情况是一种异常状态,可能是要查找的器件在搜寻过程中与1-Wire总线脱离。如果出现这种情况,应中止搜索,并发出1-Wire复位信号起始新的搜索过程。如果当前位既有0也有1,这种情况称为位值差异,它对在后续搜索过程中查找器件起关键作用。搜索算法指定在第一轮查询中若出现差异(数据位/补码 = 0/0),则选用‘0’路径。注意:这一点是由本文档中介绍的特定算法决定的,其它算法中或许首先选用‘1’路径。算法需要记录最后一次值差异的位置以供下一次搜索使用。

 

本文介绍的搜索算法是一个通用的程序,Maxim工程师极巧妙地设计了一些变量,只要在搜索前设置这些变量的初始值,程序就能完成不同的搜索功能,下文中会列出这些变量,但理解其奥秘需要花点时间。比如程序对最初8ROM中出现的最后一次位差异设置了一个专门的变量保持跟踪,因为64位注册码的前8位是家族码,利用此变量可以在器件的搜索过程中可以按照其家族码进行分类。运用该变量可以有选择性地跳过1-Wire器件的整个分组。如需进行选择性的搜索,可参考关于高级变量搜索的详细解释。

 

64ROM码中还包含8循环冗余校验(CRC)CRC值用于验证是否搜索到正确的ROM码。ROM码的排列如图1所示。关于CRC校验的原理,内容丰富到需要专文论述,这里不详述,可参见Maxim网站相关笔记。

 

(未完待续)

1-Wire搜索算法详解(2)

 

4 实例及算法分析

要理解算法,或制定算法,我们需要通过一个实例来解释:

 

 

        ROM示例(仅列出前4位)

ROM编号

1234……

ROM1

0011……

ROM2

1010……

ROM3

1111……

ROM4

0001……

   DS18B20 <wbr>1-WIRE <wbr>ROM搜索算法详解(2)
                                                       
84ROM的实例

 

假设1-Wire挂有4ROM如上表, 这里ROM码仅设4位,编号从14,而实际器件ROM位序号从164。右图则是按“先01”遍历顺序所构造的二叉树,可见第一次遍历得到ROM40001,第二次遍历得到ROM10011,依次类推。图中打有的位置就是分叉点,即差异位(或称为混码位)。

 

现在根据上例观察各次遍历,提炼出算法及实现细节:

1.第一次遍历时,第1Bit1时遇到第一个差异位,按左序遍历即先01的顺序,我们选择0(称为方向0);Bit2不是差异位,算法根据“二读”后方便地选0Bit3又是差异位,再选择方向0Bit4也不是差异位。遍历结果得到ROM4。这里可得出结论1:凡遇到新的差异位,选择0

 

2.第二次遍历,按实例分析,Bit1处再选择方向0Bit20Bit3不能再选0了,改选1Bit41;得到ROM1。问题随即产生:问题1Bit1为何走0?此处确为差异位,但已不是首次经过,不能套用结论1。问题2Bit3处为何改走1?简单分析问题2可得出结论2:凡上次遍历时最后一个走0的差异位本次应走1。很明显,“上次遍历时最后一个差异位”下的左分支已经走过,这次应该往右走了。再回答问题1可以得到结论3:凡上次遍历时最后一个走0的差异位之前的差异位仍按上次遍历的老路走。这个结论比较拗口,观察实例来解释:Bit3是差异位,右分支还没走过,现在我要走Bit3下边的右分支,Bit3之前当然是按上次路线来走了。

 

3.然后是否就可以进行第三次遍历了呢?且慢,有一个重要的问题还没处理。第二次遍历前,那个“上次遍历时最后一个走0的差异位”应该Bit3,我们先设置一个变量LastDiscripancy来记住这个值,即LastDiscripancy=3;从前面的分析我们知道,这个变量的值是决定本次遍历时算法在哪个位置改道的依据,而且这个变量在本次遍历全过程中应该保持不变的,如果在该节点前或后有任意多少的差异位,均按结论1(新差异位)和结论3(老差异位)来处理。也可以理解成结论2在一次遍历中必须适用且仅适用一次,这也就是每次遍历都能找出一个新的ROM的核心所在。那么第二次遍历后,变量LastDiscripancy应该指向哪个节点呢?直接观察就可发现应该指向Bit1

 

4.那么算法中如何实现每次遍历后变量LastDiscripancy的更新呢?要知道这个指针随着每次遍历在或上或下地移动,如第一次遍历后指向Bit3,第二次后指向Bit1,第三次后指向Bit2。还有,第一次开始遍历前、第四次遍历后该变量又指向哪里呢?由于实际ROM多达64位,从机如果数据多的话,差异位也会随之增加,所以算法再引入一个变量Last_Zero,在每次遍历前设为0,即指向起始位置前,然后遍历ROM码的1-64位时,该变量始终指向最后一个走0的差异位,等到遍历完成后,将该变量的值赋给LastDiscripancy即可。这样我们再观察实例的第二次遍历,Last_Zero遍历前为0Bit1时,符合“走0的差异位”,于是Last_Zero=1,后续Bit3尽管是差异位,但不走0,所以遍历完成后,该值还是1,最后交给LastDiscripancy,自己又指向0,为第三次遍历作好准备。

 

5.第三次遍历就变得顺理成章:LastDiscripancy=1Bit1处需运用结论2,算法改走1。而且第三次遍历让Bit2成为了“最后一个走0的差异位”,第四次遍历就在此处改走1了。第四次遍历搜索到最后一个rom,但还得告诉程序结束信号,从而退出搜索。结束信号用什么判定?4ROM循环4次?当然不是,上述表图只是举例,实际总路线上挂接多少从机是未知的。答案还是利用变量LastDiscripancy来判定,开始搜索前自然有LastDiscripancy=0,但一旦进入搜索程式,每次遍历后该变量总是指向ROM码中间可能的某一位(1-64),直至遍历到最后一个从机,这时必定是所有差异位均走1,如果Last_Zero保持为初始值0,遍历过程中未作修改,遍历完成后LastDiscripancy=Last_Zero=0。以此为条件可判定搜索全部完成。

 

6.综上,当算法执行到一个差异位时,需判断区分为三种情况:首次遇到型、上次最后走0型、上次非最后走0型。可以通过二个变量的比较来表征这三种情况,即比较当前搜索的位id_bit_number和上次最后走0的位LastDiscrepancy 的大小来判别,如下表:

 

3. 搜索路径方向的确定

三种情况

当前搜索位 vs 最后走0差异位

路径(变量:search_direction

结论2:上轮最后差异位

Id_bit_number=LastDiscripancy

1

结论3:非最后差异位

Id_bit_number < LastDiscripancy

同上次 (来自存储的最近ROM)

结论1:新遇差异位

Id_bit_number > LastDiscripancy

0

其中变量Id_bit_number表示当前搜索位,每一次遍历时从164步进;

变量search_direction表示当前节点经过二读及判断后确定的搜索方向,是0还是1

其他变量说明请参见流程图中附文。

 

 

5  流程图:

9列出了对一个从器件进行搜索的流程图;注意:流程图附文中列出了涉及到的一些关键变量,并进行了说明,在本文描述内容、流程图及源代码中也将用到这些名称的变量。

其他说明:

1 该流程最终被代码表达成一个函数,可以执行对一个器件的搜索;

2 当主机复位后未收到从机的存在脉冲、最后设备变量LastDeviceFlat=1、二读后均为1这三种情况,函数执行初始化变量后返回False

3 红色虚线框中流程,是针对差异位的处理,分3种情况走不同分支,该部分是本算法的精华;

4 红色虚线框中最下面的二个绿色背景框,是对家族码的处理,适用于多类型器件混合网络的指定处理,如单类器件组网,可以跳过此部分;

5 图中各指令框边上列出了部分变量、变量比较、变量赋值表达式,以方便后续理解代码;

程序每步搜索确定的ROM码将存入数组变量ROM_no[]中,流程图中“同上次”框中将调用此数组变量的值,获取上轮遍历时该位值。

DS18B20 <wbr>1-WIRE <wbr>ROM搜索算法详解(2)

 DS18B20 <wbr>1-WIRE <wbr>ROM搜索算法详解(2)

 

  

6 实现

上述流程图算法实际上是一个通用的函数,可实现一次从机ROM码的搜索,在附录代码中即为OWSearch()函数,执行一次该函数,可以有以下几种结果:

1.复位信号发出后,未收到任何应答信号,表明无器件挂接或硬件电路故障,函数返回False退出;

2.上轮搜索中程序判断为最后一个器件,本次执行函数也是返回False退出;

3.在某位“二读”时出现“11”的信号,这是执行中出现的异常,函数也是返回False退出;

4.首次或再次进入此函数,信号也正常,函数将搜索到总线上的第一个器件ROM码;

在上述4种结果中,第1和第3是异常后退出,第2是器件搜索完毕后结束退出。第4是首次执行搜索和再次执行搜索这二种情况,可以表述后下面二个函数:First和Next,二个函数通过对LastDiscrepancyLastFamilyDiscrepancyLastDeviceFlagROM_NO值的处理,利用同一流程实现了两个不同类型的搜索操作;这两个操作是搜索1-Wire器件ROM码的基础,本文附后列出了全部代码,可供测试。

First  

FIRST’操作是搜索1-Wire总线上的第一个从机器件。该操作是通过将LastDiscrepancy、LastFamilyDiscrepancy和LastDeviceFlag置零,然后进行搜索完成的。最后ROM码从ROM_NO寄存器中读出。若1-Wire总线上没有器件,复位序列就检测不到应答脉冲,搜索过程中止。

Next

‘NEXT’操作是搜索1-Wire总线上的下一个从机器件;一般情况下,此搜索操作是在‘FIRST’操作之后或上一次‘NEXT’操作之后进行;保持上次搜索后这些值的状态不变、执行又一次搜索即可实现‘NEXT’操作。之后从ROM_NO寄存器中来读出新一个ROM码。若前一次搜索到的是1-Wire上的最后一个器件,则返回一个无效标记FALSE,并且把状态设置成下一次调用搜索算法时将是‘FIRST’操作的状态。

        MaximAN187应用笔记图3 (a, b, c)例举了三个器件的搜索过程,为简单起见该示例中的ROM码只有2位。具体过程有二个图和一个表。与本文中的示例也大同小异,所以本文不再列出。有兴趣的可直接阅读AN187应用笔记。




7 高级变量搜索

3种利用同一组状态变量LastDiscrepancyLastFamilyDiscrepancyLastDeviceFlagROM_NO实现的高级变量搜索算法,这几种高级搜索算法允许来指定作为搜索目标或需要跳过搜索的器件的类型(家族码)以及验证某类型的器件是否在线(参见4)

如果理解了算法原理及各个变量的作用,不难理解“高级变量搜索”的三种功能。本文附带代码为简便起见,删除了这些内容,读者如感兴趣可直接访问AN187应用笔记。

 

Verify

‘VERIFY’操作用来检验已知ROM码的器件是否连接在1-Wire总线上,通过提供ROM码并对该码进行目标搜索就可确定此器件是否在线。首先,将ROM_NO寄存器值设置为已知的ROM码值,然后将LastDiscrepancyLastDeviceFlag标志位分别设置为64 (40h)0 进行搜索操作,然后读ROM_NO的输出结果;如果搜索成功并且ROM_NO中存储的仍是要搜索器件的ROM码值,那么此器件就在1-Wire总线上。

 

Target Setup

‘TARGET SETUP’操作就是用预置搜索状态的方式首先查找一个特殊的家族类型,每个1-Wire器件都有一个字节的家族码内嵌在ROM码中(参见图1),主机可以通过家族码来识别器件所具有的特性和功能。若1-Wire总线上有多片器件时,通常是将搜索目标首先定位在需注意的器件类型上。为了将一个特殊的家族作为搜索目标,需要将所希望的家族码字节放到ROM_NO寄存器的第一个字节中,并且将ROM_NO寄存器的复位状态置零,然后将LastDiscrepancy设置为64 (40h);把LastDeviceFlagLastFamilyDiscrepancy设置为0。在执行下一次搜索算法时就能找出所期望的产品类型的第一个器件;并将此值存入ROM_NO寄存器。需要注意的是如果1-Wire总线上没有挂接所期望的产品类型的器件,就会找出另一类型的器件,所以每次搜索完成后,都要对ROM_NO寄存器中存储的结果进行校验。

 

Family Skip Setup

‘FAMILY SKIP SETUP’操作用来设置搜索状态以便跳过搜索到的指定家族中的所有器件,此操作只有在一个搜索过程结束后才能使用。通过把LastFamilyDiscrepancy复制到LastDiscrepancy,并清除LastDeviceFlag即可实现该操作;在下一搜索过程就会找到指定家族中的下一个器件。如果当前家族码分组是搜索过程中的最后一组,那么搜索过程结束并将LastDeviceFlag置位。

 

要注意的是,FamilySkipSetupTargetSetup函数实际上并没有进行搜索操作,它们只不过是用来设置搜索寄存器,以便在下一次执行‘NEXT’操作时能跳过或找到所期望的类型。

4. 搜索变量状态的设置

功能函数

LastDiscrepancy

LastFamily- Discrepancy

LastDeviceFlag

ROM_NO

FIRST

0

0

0

搜索结果

NEXT

保持原值

保持原值

保持原值

保持搜索结果

VERIFY

64

0

0

验证与预设相同

TARGET SETUP

64

0

0

仅设家族码,其他为0

FAMILY SKIP SETUP

复制于LastFamilyDiscrepancy

0

0

保持原值

 

8 结论

本文提供的搜索算法可以找出任意给定的1-Wire器件组中独一无二的ROM码,这是保证多点1-Wire总线应用的关键,已知ROM码后就可以对逐一选定的某个1-Wire器件来进行操作。本文还对一些变量搜索算法做了详细论述,这些变量搜索算法能够查找或跳过特定类型的1-Wire器件。

或许Maxim觉得1-Wire 器件的软件开销让人望而生畏,因此设计了专用芯片DS2480B系列,可以实现串口到1-Wire线路的驱动,包括与本文档中相同的搜索算法,详细资料请参阅DS2480B数据资料和应用笔记192;以及DS2490 芯片,实现USB口到1-Wire桥接,也可实现了整个搜索过程;还有一款I2C桥接1-Wire的芯片。使用这些芯片,无须编写复杂算法,只需向芯片发送命令即可实现多种控制,其最大优点是芯片中集成了1-Wire操作控制的硬件,省却了1-Wire复杂的时序控制,因而其他编程可使用高级语言来编写,甚至直接使用Maxim提供的平台软件在PC上开发1-Wire应用系统。

9 附录

《详解3》中将给出了实现搜索过程的例程,并给出了‘C’程序代码,需要注意的是,Maxim并没有给出“复位、读写总线”等低级1-Wire函数C代码,而是提示我们可以调用TMEX API实现,考虑到本程序在51系列平台上独立调试,代码中提供了这些函数。关于TMEX API和其它一些1-Wire API的详细资料请参考应用笔记155

另须注意:低级1-Wire函数对时序控制有极高要求,其延时代码必须确保符合读写时序,本文程序在1T单片机MPC82G516调试通过,如改用其他1T单片机或12T单片机,必须对延时函数重新调试参数,以获得1-Wire规定时序。另:代码在实测中也适用于“寄生供电”,即不给从机连接VCC电源,代码也可正常工作。关于“寄生供电”的详细信息,请参见Maxim其他应用笔记。

 

(介绍完,代码待续)

1-Wire搜索算法详解(3)

 

C代码:

#include
#include 

sbit DQ=P0^7;  //1-wire总线
sbit K1=P0^6;  //标志变量,用于观察进出某段代码所用时间
sbit P_Read=P0^5; //
sbit P_Write=P0^4; //

// definitions
#define FALSE 0
#define TRUE  1

//几个延时函数,供一线低级操作时调用
//如果改用不同的MPU,如12T,则必须修改这几个函数,确保时间符合协议要求
void Delay480us();  //@12.000MHz
void Delay410us();  //@12.000MHz
void Delay3_88us(unsigned char i);

//一线低级操作函数
bit  OWReset();       //复位
void OWWriteBit(bit bit_value);  //写一位
bit  OWReadBit();     //读一位
void OWWriteByte(unsigned char byte_value); //写一个字节
//

//搜索函数
bit  OWSearch();  //算法核心函数,完成一次ROM搜索过程
bit  OWFirst();   //调用OWSearch完成第一次搜索
bit  OWNext();   //调用OWSearch完成下一次搜索
unsigned char docrc8(unsigned char value); //执行CRC校验

//全局搜索变量
unsigned char ROM_NO[8];  //数组,存放本次搜索到的ROM码(8个字节)
char LastDiscrepancy;  //每轮搜索后指向最后一个走0的差异位
char LastFamilyDiscrepancy; //指向家族码(前8位)中最后一个走0的差异位
bit LastDeviceFlag;   //搜到最后一个ROM后,程序通过判别将该变量置1,下轮搜索时即会结束退出
unsigned char crc8;    //CRC校验变量
 


//--------------------------------------------------------------------------
//    在单总线上搜索第一个器件
// 返回TRUE: 找到, 存入ROM_NO缓冲;FALSE:无设备
// 先将初始化3个变量,然后调用OWSearch算法进行搜索
//--------------------------------------------------------------------------
bit OWFirst()
{
   LastDiscrepancy = 0;
   LastDeviceFlag = FALSE;
   LastFamilyDiscrepancy = 0;
   return OWSearch();
}

//--------------------------------------------------------------------------
//    在单总线上搜索下一个器件
// 返回TRUE: 找到, 存入ROM_NO缓冲;FALSE:无设备,结束搜索
// 在前一轮搜索的基础上(3个变量均在前一轮搜索中有明确的值),再执行一轮搜索
//--------------------------------------------------------------------------
bit OWNext()
{
   return OWSearch();
}

 

 

 

//--------------------------------------------------------------------------
//     单总线搜索算法,利用了一些状态变量,这是算法的核心程序,代码也较长
//     返回TRUE: 找到, 存入ROM_NO缓冲;FALSE:无设备,结束搜索
//--------------------------------------------------------------------------
bit OWSearch()
{
   char id_bit_number;    //指示当前搜索ROM位(取值范围为1-64)
     //下面三个状态变量含义:
  //last_zero:  指针,记录一次搜索(ROM1-64位)最后一位往0走的混码点编号
  //search_direction:搜索某一位时选择的搜索方向(0或1),也是“一写”的bit位值
  //rom_byte_number: ROM字节序号,作为ROM_no[]数组的下标,取值为1—8
   char last_zero, rom_byte_number, search_result;

   bit id_bit, cmp_id_bit,search_direction; //二读(正码、反码)、及一写(决定二叉搜索方向)
   unsigned char rom_byte_mask ; //ROM字节掩码,

   // 初始化本次搜索变量
   id_bit_number = 1;
   last_zero = 0;
   rom_byte_number = 0;
   rom_byte_mask = 1;
   search_result = 0;
   crc8 = 0;

// ------------------------------------------------------------------
//1。是否搜索完成(已到最后一个设备)?
//-------------------------------------------------------------------
   if (!LastDeviceFlag)  // LastDeviceFlag由上轮搜索确定是否为最后器件,当然首次进入前必须置False
   {
      if (OWReset())    //复位总线
      {
         LastDiscrepancy = 0;  //复位几个搜索变量
         LastDeviceFlag = FALSE;
         LastFamilyDiscrepancy = 0;
         return FALSE;    //如果无应答,返回F,退出本轮搜索程序
      }

      OWWriteByte(0xF0);   //发送ROM搜索命令F0H
   Delay3_88us(60);

//=====================================================================
// 开始循环处理1-64位ROM,每位必须进行“二读”后进行判断,确定搜索路径
// 然后按选定的路径进行“一写”,直至完成全部位的搜索,这样一次循环
// 可以完成一轮搜索,找到其中一个ROM码。
//=====================================================================
      do        //逐位读写搜索,1-64位循环
      {
         id_bit = OWReadBit();   //二读:先读正码、再读反码
         cmp_id_bit = OWReadBit();

         if (id_bit  && cmp_id_bit)  //二读11,则无器件退出程序
            break;
         else       //二读不为11,则需分二种情况
         {
            //*********************************************
   // 第一种情况:01或10,直接可明确搜索方向
            if (id_bit != cmp_id_bit)
               search_direction = id_bit;  // 记下搜索方向search_direction的值待“一写”

   //*********************************************
            else
            {
               // 否则就是第二种情况:遇到了混码点,需分三种可能分析:
               // 1。当前位未到达上轮搜索的“最末走0混码点”(由LastDiscrepancy存储)
      //    说明当前经历的是一个老的混码点,判别特征为当前位在(小于)LastDiscrepancy前
      //    不管上次走的是0还是1,只需按上次走的路即可,该值需从ROM_NO中的当前位获取
               if (id_bit_number < LastDiscrepancy)
                  search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0);
      // 从
              
      else
               // 2。当前位正好为上轮标记的最末的混码点,这个混码点也就是上次走0的点
      //    那么这次就需要走1
      // 3。除去上二种可能,那就是第3种可能: 这是一个新的混码点,
      //    id_bit_number>LastDiscrepancy
      //。。然而下一条语句巧妙地将上二种可能合在一起处理,看不懂我也没办法了
                  search_direction = (id_bit_number == LastDiscrepancy);
   
   //************************************************

            // 确定了混码点的路径方向还没完事,还需要更新一个指针:last_zero
   // 这个指针每搜索完一位后(注意是一bit不是一轮)总是指向新的混码点
   // 凡遇到新的混码点,我们按算法都是先走0,所以凡遇走0的混码点必须更新此指针
               if (search_direction == 0)
               {
                  last_zero = id_bit_number;

                  // 下面二条是程序的高级功能了:64位ROM中的前8位是器件的家族代码,
      // 用LastFamilyDiscrepancy这个指针来记录前8位ROM中的最末一个混码点
      // 可用于在多类型器件的单线网络中对家族分组进行操作
                  if (last_zero < 9)
                     LastFamilyDiscrepancy = last_zero;
               }
            }

            // 确定了要搜索的方向search_direction,该值即ROM中当前位的值,需要写入ROM
            // 然而64位ROM需分8个字节存入ROM_NO[],程序使用了一个掩码字节rom_byte_mask
   // 以最低位为例:该字节值为00000001,如记录1则二字节或,写0则与反掩码
            if (search_direction == 1)
               ROM_NO[rom_byte_number] |= rom_byte_mask;
            else
               ROM_NO[rom_byte_number] &= ~rom_byte_mask;

            // 关键的一步操作终于到来了:一写
            OWWriteBit(search_direction);

            // 一个位的操作终于完成,但还需做些工作,以准备下一位的操作:
            // 包括:位变量id_bit_number指向下一位;字节掩码左移一位
            id_bit_number++;
            rom_byte_mask <<= 1;

            // 如果够8位一字节了,则对该字节计算CRC处理、更新字节号变量、重设掩码
            if (rom_byte_mask == 0)
            {
                docrc8(ROM_NO[rom_byte_number]);  // CRC计算原理参考其他文章
                rom_byte_number++;
                rom_byte_mask = 1;
            }
         }
      }
      while(rom_byte_number < 8);  // ROM bytes编号为 0-7
   //流程图中描述从1到64的位循环,本代码中是利用rom_byte_number<8来判断的
   //至此,终于完成8个字节共64位的循环处理

 //=================================================================================
 
      // 一轮搜索成功,找到的一个ROM码也校验OK,则还要处理二个变量
      if (!((id_bit_number < 65) || (crc8 != 0)))
      {
         // 一轮搜索结束后,变量last_zero指向了本轮中最后一个走0的混码位
   // 然后再把此变量保存在LastDiscrepancy中,用于下一轮的判断
   // 当然,last_zero在下轮初始为0,搜索是该变量是不断变动的
        LastDiscrepancy = last_zero;

         // 如果这个指针为0,说明全部搜索结束,再也没有新ROM号器件了
         if (LastDiscrepancy == 0)
            LastDeviceFlag = TRUE;  //设置结束标志
        
         search_result = TRUE;  //返回搜索成功
      }
   }

// ------------------------------------------------------------------
//搜索完成,如果搜索不成功包括搜索到了但CRC错误,复位状态变量到首次搜索的状态。
//-------------------------------------------------------------------
   if (!search_result || !ROM_NO[0])
   {
      LastDiscrepancy = 0;
      LastDeviceFlag = FALSE;
      LastFamilyDiscrepancy = 0;
      search_result = FALSE;
   }
   return search_result;
}

//=====================================================================
   至此,OWSearch函数结束。函数实现的是一轮搜索,如成功,可得到一个ROM码
//=======================================================================


//=====================================================================
// 1-Wire函数调用所需的延时函数,注意不同MCU下须重调参数
//=====================================================================

void Delay480us()  //@12.000MHz
{
 unsigned char i, j;
 i = 2;
 j = 90;
 do
 {
  while (--j);
 } while (--i);
}

void Delay410us()  //@12.000MHz
{
 unsigned char i, j;
 i = 2;
 j = 40;
 do
 {
  while (--j);
 } while (--i);
}


void Delay3_88us(unsigned char i)  //@12.000MHz  只能3-80us
{
 //i*=3;
 i-=1;
 while (--i);
}
  


//=====================================================================
//  一线函数:复位、读一位、写一位、写一字节
//=====================================================================
bit OWReset()
{
        bit result;
  unsigned char i;
        DQ=0;    // 拉低总线启动复位信号
        Delay480us();  
        DQ=1;    // Releases the bus
  i=53;   //延时70us
  while(--i);
        result = DQ;  // 采样总线上从机存在信号
        Delay410us();  //
        return result;  //
}

//-----------------------------------------------------------------------------
void OWWriteBit(bit dat)  //写一位函数
 //
{
  unsigned char i;
  P_Write=1;     //写函数执行的标志变量,用于调试
        if (dat)    //写1
        {
                DQ=0;    // Drives DQ low
                i=4;     // 延时6us
u
    while(--i);
                DQ=1;    // 释放总线
                i=38;     // 延时54us,不要看i的值,实测为54us
    while(--i);  //
        }
        else     //写0
        {
                DQ=0;    //
    i=35;     // 延时60
    while(--i);
                DQ=1;    // 释放总线
    i=7;   // 延时10
    while(--i);
        }
  P_Write=0;
}

//-----------------------------------------------------------------------------
bit OWReadBit()     //读一位
{
        bit result;
  unsigned char i;
     P_Read=1;    // 时间隙6+9+55
        DQ=0;      // Drives DQ low
        i=8;   //6
  while(--i);
        DQ=1;      // 释放
        i=6;   //9
  while(--i);
        result = DQ;    // 取样总线
        i=32;   //45
  while(--i);     //
    P_Read=0;
        return result;
}

//-----------------------------------------------------------------------------
void OWWriteByte(unsigned char dat) //写一字节
{
        char loop;
        for (loop = 0; loop < 8; loop++) //低位先传
        {
                OWWriteBit(dat & 0x01);
                dat >>= 1;     //右移
         }
}

//-----------------------------------------------------------------------------
char OWReadByte(void)  //读一字节,本例中并未用到
{
        char loop, result=0;
        for (loop = 0; loop < 8; loop++)
        {
          result >>= 1;
            if (OWReadBit())
             result |= 0x80;
        }
        return result;
}

//  CRC计算用表
static unsigned char 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};
  

//--------------------------------------------------------------------------
//迭代计算CRC,返回当前CRC值
unsigned char docrc8(unsigned char value)
{
   // 详见应用笔记AN27
   crc8 = dscrc_table[crc8 ^ value];   //^表示按位异或
   return crc8;
}

//主函数,
void main()
{
   bit rslt;
   K1=0;   //这三个位用于观察“二读一写”
   P_Read=0;
   P_Write=0;

   rslt = OWFirst();  //搜索第一个ROM
   while (rslt)   //如果搜索成功,继续搜索下一个
   {
      rslt = OWNext();
   }
   while(1);
}


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

DS18B20 1-WIRE ROM搜索算法详解 的相关文章

  • 问题:使用NoSQLBooster连接MongoDB报错:reports maximum wire version 0...

    前言 问题解决 使用NoSQLBooster连接MongoDB报错 xff1a reports maximum wire version 0 but this version of the Node js Driver requires a
  • MAME打开ROM报错解决办法

    问 olds100 34 西游释厄传 特别版 版本 100 第 1 套 34 运行报错如何解决 xff1f 答 经过我的研究olds100 zip这个游戏是一个特别版本 它依赖两个文件才可以正常运行 分别是 xff1a olds zip x
  • Duplicate Net Names Wire Net......

    这是本人使用Altium Designer软件绘制原理图文件 xff0c 进行工程编译 xff08 Compile xff09 时遇到的问题 一 问题分析 xff1a Duplicate Net Names 中文意思就是 xff1a 网络名
  • cd rom是计算机的,CD-ROM是什么意思,CD-ROM是什么意思

    CD ROM是什么意思 CD ROM是什么意思以下文字资料是由 历史新知网www lishixinzhi com 小编为大家搜集整理后发布的内容 xff0c 让我们赶快一起来看一下吧 xff01 关于CD ROM的意思 xff0c 计算机专
  • DFS搜索算法详解

    深度优先搜索 一条道走到黑 DFS其实叫深度优先搜索算法 xff0c 起始它只是一种搜索的方法思路 xff0c 并没有固定的算法格式 让我们通过一个社交图的例子来看 我们拿到一个社交关系无向图 xff1a 通过无向图可以得到邻接矩阵 用1表
  • ROM、SDRAM、RAM、DRAM、SRAM、FLASH 的区别

    ROM 和 RAM 指的都是半导体存储器 xff0c ROM 是 Read Only Memory 的缩写 xff0c RAM是 Random Access Memory的缩写 ROM 在系统体质供电的时候仍然可以保存数据 xff0c 而R
  • 温度传感器DS18B20-第2季第1部分-朱有鹏-专题视频课程

    温度传感器DS18B20 第2季第1部分 1700人已学习 课程介绍 本课程是 朱有鹏老师单片机完全学习系列课程 第2季第1个课程 xff0c 主要讲解单片机系统中常用的温度传感器DS18B20 本课程的目标是让大家进一步掌握时序的分析和编
  • mame新版ROM下载网站推荐

    网站地址 https www retroroms info index php 中文插件安装 浏览器插件 https www tampermonkey net UP主自己写的脚本 已经失效 https gitee com lxyoucan
  • ESP32S2(12K)-DS18B20数码管显示温度

    一 物料清单 NODEMCU 32 S2 ESP32 12K 四段数码管 共阴 DS18B20 VCC DQ GND Arduino IDE 2 0 3 二 实现方法及效果图 2 1 引用库 include lt OneWire h gt
  • 硬件MSB最高位优先、LSB最低位优先的CRC计算原理详细解释和程序,正算反算成功等效,DS18B20和HTU31D传感器CRC

    wxleasyland 64 139 com 2022 7 以前写过 我学习CRC32 CRC16 CRC原理和算法的总结 xff08 与WINRAR结果一致 xff09 长篇 经过十几年又忘记了 这次碰到DS18B20进行CRC校验 xf
  • (转)ds18b20时序说明

    ds18b20时序说明 新手在DS18B20读写过程中要犯很多错误 老衲普度众生 xff0c 简要说明它怎么用 1 过程1 2是初始化过程 xff0c 每次读取都要初始化 xff0c 否则18b20处于待机状态 xff0c 无法成功读取 过
  • 蓝桥杯模块练习之温度传感器DS18B20

    蓝桥杯单片机比赛系列4温度传感器DS18B20 温度传感器DS18B20原理相关电路onewire总线几个需要知道的暂存器和命令 代码解释修改代码自写代码 实现代码 温度传感器DS18B20原理 相关电路 DS18B20遵循onewire总
  • RAM、ROM、SRAM、DRAM、SSRAM、SDRAM、FLASH、EEPROM的区别

    RAM Random Access Memory 随机存储器 存储单元的内容可按需随意取出或存入 且存取的速度与存储单元的位置无关的存储器 这种存储器在断电时将丢失其存储内容 故主要用于存储短时间使用的程序 按照存储信息的不同 随机存储器又
  • 基于51单片机的DS18B20测温程序与仿真图

    一 基础介绍 时序介绍就暂不介绍 可以网上搜集资料 二 proteus仿真图 三 程序代码 include
  • 在Arduino中使用DS18B20温度传感器(基于OneWire和DallasTemperature库)

    文章目录 目的 快速使用 相关库引入 使用步骤 使用演示 演示一 演示二 演示三 相关库说明 OneWire库 DallasTemperature库 总结 目的 DS18B20是常用的温度传感器 功能够用 使用简单 本文将用Arduino第
  • 【Verilog】ROM & RAM

    文章目录 RAM ROM ROM 只读存储器 概念 源代码 testbench 仿真波形 RAM 随机访问内存 概念 源代码与testbench 仿真波形 RAM ROM ROM 只读存储器 概念 ROM内部的数据是在ROM制造工序中 在工
  • 【分享】ROM厂商刷机工具合集

    1 MTK刷机 SP Flash Tool下载地址 SP Flash Tool v5 1924 Download SmartPhone Flash Tool MTKClient 下载地址 Releases notmyst33d mtkcli
  • DS18B20温度传感器模块介绍及与USART HMI通信

    一 DS18B20温度传感器 DS18B20是常用的数字温度传感器 其输出的是数字信号 具有体积小 硬件开销低 抗干扰能力强 精度高的特点 DS18B20数字温度传感器接线方便 封装成后可应用于多种场合 如管道式 螺纹式 磁铁吸附式 不锈钢
  • FPGA学习笔记_ROM核调用与调试

    FPGA学习笔记 ROM核调用与调试 1 ROM存储器IP核的使用 2 创建 mif文件 3 In system memory content editor内存查看工具的使用 4 Signal tapII工具使用 5 Verilog 代码
  • linux下如何挂载android的img文件? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 最近 我对android rom感兴趣 我想更改和重建它们 所以 我在我的 XOOM 上做了一些测试

随机推荐

  • Ubuntu更新sudo apt update库报错

    sudo apt update报错 evyn 64 ubuntu sudo apt update E 文件 list 第 1 行的记录格式有误 etc apt sources list d ros latest list Suite E 无
  • 孤立森林(Isolation Forest)从原理到实践

    异常检测 离群点是在给定数据集中 xff0c 与其他数据点显著不同的数据点 异常检测是找出数据中离群点 和大多数数据点显著不同的数据点 的过程 离群点 真实世界中的大型数据集的模式可能非常复杂 xff0c 很难通过查看数据就发现其模式 这就
  • 一个C++程序员的学习经历

    正在上网的时候有这个念头的 xff0c 所以急急忙忙找了一些学习编程的高人的感想 xff1a 我开始学VC时就是自己一个人在啃 xff0c 也没什么人指导 xff0c 当时没有条件上网 xff0c 资料特别少 xff0c 在书店里随便买本书
  • Mac mini 2018 win10 外接显卡终极教程

    Mac mini 2018 win10 外接N卡应该算是最简单了 但是有些小问题 xff0c 比如说总是需要插拔雷电3的线材 xff0c 对于强迫症或者偏执来说总是感觉不爽 一种解决方案是用refind 启动方法 xff0c 将refind
  • Layui上传系列之二(多文件分块上传优化实现)

    接下来 xff0c 就要实现layui的uploader分块上传了 xff0c 在官网上没有提到分块上传 xff0c 倒是有一个多文件选择后 xff0c 显示文件列表的例子 目录 现状分析 我的做法 功能优化 上代码了 现状分析 对于我们能
  • tigervnc+noVNC远程使用RViz

    写在前面 遇到了远程桌面访问ubuntu系统并使用RViz的需要 xff0c 试了常用的vnc4server xff0c 在没有外接显示器的情况下 xff0c vnc4server需要虚拟一个显示器出来 xff0c 虚拟显示器可以使用Xvf
  • VINS-Mono融合轮式编码器和GPS(三):后端优化

    VINS Mono融合轮式编码器和GPS xff08 三 xff09 xff1a 后端优化 开篇介绍理论目标函数IMU约束1 残差2 优化变量3 Jacobian4 协方差 实践配合代码查看 开篇 项目地址VINS GPS Wheel xf
  • ROS-Gazebo (一):关于Gazebo无法加载模型,长时间卡在开始界面的问题解决方法

    在使用ROS Gazebo的过程中首先遇到的问题就是长时间加载不出模型 来 通常的解决方法是 从官方模型库下载号所有的基本模型 然后解压到 gazebo models文件夹里面就可以了 具体的下载地址和详细的操作方式可以 百度或者谷歌 34
  • 用SST89E516RD自制51单片机仿真器

    原文网址 xff1a http www1 eccn com tech06 te074653 asp 用SST89E516RD自制51单片机仿真器 文 xff0f 吴汉清 单片机实验和开发中最重要的一个环节就是程序的调试 xff0c 在业余条
  • Latex (一) 安装和环境变量的设置

    一 安装 Tex有很多不同的版本 xff0c 很多人喜欢用ctex xff0c 但是最推荐是官方版本Texlive 搜了很多资料 xff0c 一般windows的话 xff0c 可以将Tex live 43 Tex studio作为标配 x
  • KITTI 数据集 参数—— tracking devkit中的rotation_y和alpha角

    根据devkit中的readme txt和cs overview pdf的描述以及根据通过对数据集做的小实验总结的 xff0c 如果过有错误的地方欢迎指正 61 61 61 61 61 61 61 61 61 61 61 61 61 61
  • 拯救者Y7000P 安装Ubuntu16.04问题解决

    先列一下问题 xff1a 1 wifi开不来了 xff1b 2 触摸板没法用 3 休眠后打不开 目前1 3 xff0c 解决了 xff0c 但是2依然没法解决 xff0c 不过问题不大 xff0c 大不了用鼠标 首先 xff0c 问题的原因
  • VSCode python调试库代码以及添加相关扩展支持opencv

    调试python 代码的时候可以再launch json 文件中添加 justMycode 34 false 来调试安装的包的代码 由于opencv 底层调用的C xff0c 所以如果要在代码提示中正确提示可能要安装额外插件 xff1a 比
  • vscode python包的引用一些问题

    个人使用vscode碰到的一些python包的引用问题以及尝试解决的一些办法 xff0c 可能只适用我自己的情况 项目目录大概如下 xff1a lib是根目录下的一个文件夹 xff0c 里面每个文件夹都是一个python 包 xff0c 都
  • MATLAB 矩阵的化简rref()函数

    在用MATLAB求解线性方程组的时候 xff0c 可以使用 rref 函数对矩阵进行化简 xff0c 从而很方便直观的得到原方程的解 xff0c 举一个简单的例子 xff1a 解下列线性方程组 则用MATLAB的rref函数解上述方程组的代
  • MATLAB求符号函数的函数值的方法

    在MATLAB中定义函数的方法有许多种 xff0c 比较常用的一种是定义符号变量 x 和 y 举一个简单的例子 xff1a 对函数 y 61 x 2 用上述方法的MATLAB语言如下 xff1a syms x y y 61 x 2 要想画出
  • C++寻找数组最大值和最小值

    寻找数组中的最大最小值 include lt iostream gt using namespace std include lt algorithm gt int main int n cin gt gt n int p 61 new i
  • Excel如何同时查找多个数据

    在使用多个excel表的时候 xff0c 有时需要在一个表中查找另一个表中的某些信息 xff0c 怎样能一步到位 xff0c 将所有要查找的信息一次找出来而不是一个个的Ctrl 43 F xff1f 这是前几天帮辅导员老师统计新生的数据时遇
  • python tkinter 全部组件(widget)及事件类型(event)一览

    对于一个简单的GUI程序设计来说 xff0c 我觉得无非就是三个要素 xff0c widget xff08 部件 xff09 xff0c layout xff08 布局 xff09 xff0c event xff08 事件的响应 xff09
  • DS18B20 1-WIRE ROM搜索算法详解

    转自 xff1a http blog sina com cn s blog 57ad1bd20102uxxw html 1 WIRE 搜索算法详解 xff08 1 xff09 0 前言 美信公司 xff08 http www maximin