首页 > 其他分享 >【硬件模块】DS18B20温度传感器

【硬件模块】DS18B20温度传感器

时间:2024-09-11 16:51:22浏览次数:13  
标签:温度传感器 DS18B20 void 总线 uint8 时序 模块 GPIO

DS18B20是只需要一根通讯线的温度传感器。

首先先看看它的通信时序,一共就仨,初始化时序,写时序,读时序。

第一个,初始化时序,我们(MCU)先拉低总线最少480us,然后释放总线(拉高)。

DS18B20收到上升沿之后会在15~60us之后把总线拉低,拉低60~240us之后再释放总线。

这样一套流程下来我们就算是初始化DS18B20了。

那我们要做的就是先把MCU用于和DS18B20通信的那个引脚设置为输出模式。然后拉低480us(可以稍微久一点,但是我试过了,480us是没问题的)后,再拉高。

接着切换引脚为输入模式(看情况,ESP32不需要,可以在一开始就配置为输入输出模式),因为DS18B20会在收到上升沿的15~60us后拉低总线,因此我们可以延时15us之后再尝试读取引脚的电平(while循环读取,直到引脚确实被拉低了),看看是否被DS18B20拉低了,也可以不延时,直接尝试读取,但是要记得while循环时间不要太久导致我们的程序卡死,可能是DS18B20那边出了问题,我们就循环读取个60us即可,60us之内没读到低电平就代表我们初始化失败。

DS18B20会在拉低电平的60~240us之后再把电平拉高,因此我们也和上一步一样,延时60us之后尝试读取引脚是否为高电平,也可以直接读取,然后while循环的时间不要超过240us。

一切顺利之后表示我们初始化成功。

接着是写时序,我们要么写‘1’要么写‘0’,我们看上图,‘0’和‘1’时序的区别就在于后半段拉高电平的时机,‘0’基本上是一直都是低电平,最后时序快结束了才拉高,而‘1’是一开始是拉低电平,后面拉高电平,拉高电平的时机大概是拉低电平后的1~15us之间。

光看时序图还有些细节我们把握不住,我们再看看文档的文字描述。

第一点,无论是写‘1’或是写‘0’,写时序都至少持续60us。

第二点,两个写周期之前需要有至少1us的恢复时间。

第三点DS18B20在初始化写时序后的15~60us这个窗口对数据线进行采样。

这边注意第三点的初始化写时序,这边的初始化并不是我们上面那个初始化时序,而是写时序的开头那个下拉总线的步骤,那个就是写时序的初始化。

因此我们进行写时序的步骤就是先把MCU的引脚改为输出模式,接着把引脚改成低电平,延时15us,然后再把要写的bit“放”在引脚上,也就是‘0’就改成低电平,‘1’就改成高电平。然后为了保证每个写时序至少是60us,因此我们延时至少45us。接着释放总线(拉高引脚),延时1us后结束写时序(因为两个写周期之间需要有至少1us的恢复时间)

写时序执行8次我们也就向DS18B20发送了一个字节了,这边需要注意的是低位先行,包括后面读取字节的时候也是先读低位。

最后是读时序,和写时序也是大差不差,我们一样是结合着文字描述看看。

读时序的持续时间和写一样至少为60us。

首先我们把引脚拉低,1us之后再释放(拉高),接着DS18B20在收到下降沿的15us之内会把传输的数据放到总线上,因此我们拉低释放总线之后就要把引脚改为输入模式。然后我们在15us之内读取引脚的电平即可。读完之后我们延时50us保证每个写时序都至少是有60us。

读时序循环8次我们也就读取了一个字节了,记得是低位先行。

接着我们就是需要给DS18B20发送指令获取到温度值了。

如果我们要跟DS18B20通信,那么必须要按照顺序遵循下面三个步骤:发送初始化时序,发送ROM操作指令,发送功能指令。两个指令轮流发完之后必须回到第一步初始化。

接下来先看看ROM操作指令有哪些。

一共是五个,但是我们最常用的就那一个。

0xCC,忽略指令。这个忽略是什么意思呢?

DS18B20通信只需要一根通信线挂载在总线上,而总线上可以挂载多个DS18B20。那么我们MCU只出一根线,怎么从多个DS18B20中指定一个为我们所用呢?

每只 DS1820 都有一个唯一的长达 64 位的编码。最前面 8 位是单线系列编码。下面 48 位是一个唯一的序列号。最后 8 位是以上 56 位的 CRC 码。

因此我们可以通过这个唯一序列号去指定DS18B20。

而忽略指令的忽略就是我们不指定DS18B20,这有两个用途,第一个就是我们总线上只挂了一个DS18B20,那么我们不指定DS18B20会更省事。第二个就是有个指令我们需要挂载在总线上的所有DS18B20去执行。

我们能忽略,那么就能匹配,0x55,匹配指令。这条匹配指令发完之后需要后接上64位的序列编码(这一步算在三个步骤中的第二步)。后续的功能指令就只会对匹配上序列编码的DS18B20生效了。

我们要匹配,首先就要先知道这64位序列编码是什么,0x33,读取指令。发完之后我们就可以接收到8byte的序列编码了。这边要注意,此时总线上只能有一个DS18B20,否则会导致多个DS18B20一起发送序列,导致数据混乱。

剩下俩命令一个是搜索,另一个是报警搜索,我没看懂咋用,就不介绍了,咱这篇文章主要还是说说怎么从DS18B20中得到温度值。

接下来看看功能指令,一共是六条,但是我们常用的就俩。

0x44,温度转换指令,发送指令后会让上一步指定的DS18B20进行温度转换,转换的结果会放在寄存器中。寄存器具体放了啥数据稍后再说。

0xBE,读寄存器,发完指令后DS18B20会把寄存器的值发过来。

0x4E,写寄存器,只能写3个byte。

0x48,拷贝寄存器,将寄存器中的3个byte(就是上面写寄存器中写的3byte)拷贝到EEPROM中,等等看下面的图就清楚了。

0xB8,召回EEPROM,也就是把EEPROM的值再整回寄存器里。

0xB4,读取电源模式,发送指令后我们再读一个bit,若是寄生电源模式,DS18B20

将拉低总线,若是外部电源模式,DS18B20 将会把总线拉高。

功能指令不少,但我们常用的就头俩,温度转换和读寄存器,寄存器是下面这样的。

一共是九个byte,如果我们只要获取温度,那么只需要接收前两个byte即可,后面七个可以不接收。

然后我们写寄存器指令能写的就是byte2~byte4一共三个byte。

其中TH和TL是掉电不丢失的,分别可以存储一个数(整型的),用作报警。如果测得的温度高于 TH 或低于 TL,报警条件成立,DS18B20 内部就会置位一个报警标识。每进行一次测温就对这个标识进行一次更新;因此,如果报警条件不成立了,在下一次温度转换后报警标识将被移去。

那么这个报警标志怎么用呢?是配合着操作指令的报警搜索指令的,总线控制器通过发出报警搜索命令(0xEC)检测总线上所有的 DS18B20 报警标识,报警标识被置位的 DS18B20 将响应这条命令。

但我们报警用的不多,重要的是byte4配置寄存器。

Byte4我们只用到了bit5和bit6,用它来设置DS18B20的精度的,默认是12bit,也就是我们通过寄存器读出的温度,每个数都代表着是0.0625℃,比如说我寄存器读出的温度数是100,那么实际表示的温度是100 * 0.0625 = 6.25℃。

9、10、11、12位的温度分辨率,分别对应着0.5℃,0.25℃,0.125℃,0.0625℃。

至此我们就可以使用DS18B20来获取采集到的温度值了。

首先先发个初始化时序,接着发送0xCC表示忽略(仅适用于总线上就一个DS18B20,换成匹配(0x55)也行),然后发送0x44让DS18B20开始温度转换,中间等待一会,最大转换时间在上面那个图里有,我们一般等个最大转换时间的2/3就行。

等待结束后我们再开始读取,三个步骤重头来一次,发送初始化时序,发送0xCC,最后发送0xBE读取寄存器,如果只要温度,那么我们接收前两个字节即可。

读取到的数据需要进一步处理,我们得到的数据实际上是一个补码,如果是正数的话那么无所谓补码原码都一样,如果是负数的话(最高位为1),那么我们需要将补码转成原码。

最后将温度数据的原码乘上0.0625(根据分辨率而定)就是我们要得到的温度(℃)了。

完整代码在下面,大家也不用跟私信跟我要工程文件,下面贴出来的基本上就是全部了,自己创个工程,把下面代码往main.c里一贴,最多因为环境不同有些小问题改改就可以了。

大家也可以关注我同名公众号“折途想要敲代码”,回复关键词“DS18B20”领取相关的文档资料(没有代码)

完整代码(ESP32(ESP-IDF)&STM32&ESP8266(Arduino))

这边附上ESP32的代码(ESP-IDF)。

#include <stdio.h>
#include <unistd.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define DS18B20_GPIO GPIO_NUM_9

// 初始化DS18B20的通信引脚
void DS18B20_init(void) {
    gpio_config_t gpio_initer = {
        .intr_type = GPIO_INTR_DISABLE,     // 不中断
        .mode = GPIO_MODE_INPUT_OUTPUT_OD,  // 输入输出模式,要开漏模式
        .pin_bit_mask = ((uint32_t)1 << DS18B20_GPIO),  // 指定GPIO
        .pull_down_en = GPIO_PULLDOWN_DISABLE,          // 不加下拉电阻
        .pull_up_en = GPIO_PULLUP_ENABLE                // 加上上拉电阻
    };
    gpio_config(&gpio_initer);
}

// 封装一下操作DS18B20的引脚
void DS18B20_SetDQ(uint8_t val) {
    gpio_set_level(DS18B20_GPIO, val);
}
uint8_t DS18B20_GetDQ(void) {
    return gpio_get_level(DS18B20_GPIO);
}
// 写一个Byte
void DS18B20_WriteByte(uint8_t data) {
    for (uint8_t i = 0; i < 8; ++i) {
        DS18B20_SetDQ(0);  // 先拉低15us
        usleep(15);

        DS18B20_SetDQ(data & 0x01);  // 将bit放置总线60us
        usleep(60);

        DS18B20_SetDQ(1);  // 释放总线
        usleep(1);         // 每个bit发完等待1us
        data >>= 1;
    }
}
// 读取一个Byte
uint8_t DS18B20_ReadByte(void) {
    uint8_t res = 0x00;
    for (uint8_t i = 0; i < 8; ++i) {
        DS18B20_SetDQ(0);  // 拉低总线1us后释放表示开始接收
        usleep(1);
        DS18B20_SetDQ(1);

        usleep(10);  // 等待10us后读取(15us之内)
        if (DS18B20_GetDQ() == 1)
            res |= (0x01 << i);

        usleep(50);
    }
    return res;
}
// 初始化时序
bool DS18B20_InitSlot(void) {
    DS18B20_SetDQ(0);  // 拉低总线最少480us
    usleep(480);
    DS18B20_SetDQ(1);  // 释放

    usleep(15);
    uint8_t waitTime = 0;
    while ((DS18B20_GetDQ() != 0) && (waitTime <= 45)) {  // 等待DS18B20拉低总线
        waitTime++;
        usleep(1);
    }
    if (waitTime > 45)
        return false;

    waitTime = 0;
    while ((DS18B20_GetDQ() != 1) &&
           (waitTime <= 240)) {  // 等待DS18B20释放总线
        waitTime++;
        usleep(1);
    }
    if (waitTime > 240 || waitTime < 60)
        return false;
    return true;
}
// 打印64位序列编码(要改为获取的话修改一下即可)
void DS18B20_PrintCode(void) {
    if (!DS18B20_InitSlot())
        return;
    uint8_t code[8];
    DS18B20_WriteByte(0x33);  // 读取指令
    for (uint i = 0; i < 8; ++i) {
        code[i] = DS18B20_ReadByte();
    }
    printf("code is : ");
    for (uint i = 0; i < 8; ++i) {
        printf("%02x ", code[i]);
    }
    printf("\r\n");
}
// 获取温度
float DS18B20_GetTemperture(void) {
    uint16_t temp;
    uint8_t Hdata, Ldata;

    if (!DS18B20_InitSlot())
        return 0;
    DS18B20_WriteByte(0xCC);  // 忽视指令
    DS18B20_WriteByte(0x44);  // 温度转换指令

    DS18B20_SetDQ(1);  // 拉高总线后等待500ms
    vTaskDelay(500 / portTICK_PERIOD_MS);

    if (!DS18B20_InitSlot())
        return 0;
    DS18B20_WriteByte(0xCC);
    DS18B20_WriteByte(0xBE);  // 读取寄存器指令
    Ldata = DS18B20_ReadByte();
    Hdata = DS18B20_ReadByte();
    temp = Hdata;
    temp = (temp << 8) | Ldata;
    return temp * 0.0625;  // 12位分辨率,每个数表示0.0625.
}

void app_main(void) {
    DS18B20_init();
    DS18B20_PrintCode();
    float tempertrue = 0.0;
    while (1) {
        tempertrue = DS18B20_GetTemperture();
        printf("tempertrue is %f\r\n", tempertrue);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

STM32的代码。

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
 
 
#define DS18B20_DQ GPIO_Pin_0
 
void Z_DS18B20_Output(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    GPIO_InitTypeDef itd;
    itd.GPIO_Mode=GPIO_Mode_Out_PP;    //推挽输出
    itd.GPIO_Pin=DS18B20_DQ; 
    itd.GPIO_Speed=GPIO_Speed_50MHz;                   
    GPIO_Init(GPIOA,&itd);
}
 
void Z_DS18B20_Input(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    GPIO_InitTypeDef itd;
    itd.GPIO_Mode=GPIO_Mode_IPU;        //上拉输入    
    itd.GPIO_Pin=DS18B20_DQ; 
    itd.GPIO_Speed=GPIO_Speed_50MHz;                   
    GPIO_Init(GPIOA,&itd);
}
 
void Z_DS18B20_SetDQ(BitAction val){
    GPIO_WriteBit(GPIOA,DS18B20_DQ,val);
}
 
uint8_t Z_DS18B20_GetDQ(void){
    return GPIO_ReadInputDataBit(GPIOA,DS18B20_DQ);
}
 
void Z_DS18B20_WriteByte(uint8_t data){
    Z_DS18B20_Output();
    for(uint8_t i=0;i<8;++i){
        Z_DS18B20_SetDQ(0);     //拉低总线15us
        Delay_us(15);
        
        Z_DS18B20_SetDQ(data&0x01); //将数据从低位开始放到总线上60us
        Delay_us(60);
        
        Z_DS18B20_SetDQ(1);     //释放总线后延时1us
        Delay_us(1);
        data>>=1;
    }
}
 
 
uint8_t Z_DS18B20_ReadBit(void){
    uint8_t res=0;
    Z_DS18B20_Output();
    Z_DS18B20_SetDQ(0);     //拉低总线1us后释放表示开始读取字节
    Delay_us(1);
    Z_DS18B20_SetDQ(1);
    
    Z_DS18B20_Input();
    Delay_us(10);           //等待10us(在15us之内)后读取总线
    res=Z_DS18B20_GetDQ();
    
    Delay_us(50);           //延时50us以保证每个时序至少有60us.
    return res;
}
 
uint8_t DS18B20_Read_Byte(void){
  uint8_t res=0x00;
  for(uint8_t i=0;i<8;++i){
    if(Z_DS18B20_ReadBit()==1) res|=(0x01<<i);
  }
  return res;
}
 
uint8_t Z_DS18B20_Init(void){
    Z_DS18B20_Output();
    Z_DS18B20_SetDQ(0);     //复位
    Delay_us(480);
    Z_DS18B20_SetDQ(1);
    Delay_us(15);
    
    uint8_t waitTime=0;
    Z_DS18B20_Input();
    while(Z_DS18B20_GetDQ() && waitTime<=45){   //等待从机拉低总线
        waitTime++;
        Delay_us(1);
    }
    if(waitTime>45) return 1;
    
    waitTime=0;
    while(!Z_DS18B20_GetDQ() && waitTime<=240){ //等待从机松开总线
        waitTime++;
        Delay_us(1);
    }
    if(waitTime>240||waitTime<60) return 1;
    return 0;
}
 
float Z_DS18B20_GetTemperture(void){
	uint16_t temp;
	uint8_t Hdata,Ldata;
    
    Z_DS18B20_Init();
    Z_DS18B20_WriteByte(0xCC);
    Z_DS18B20_WriteByte(0x44);  //温度转换指令
    Z_DS18B20_Init();
	Z_DS18B20_WriteByte(0xCC);   
	Z_DS18B20_WriteByte(0xBE);  //读取寄存器指令  
	Ldata=DS18B20_Read_Byte();     
	Hdata=DS18B20_Read_Byte();    
	temp=Hdata;
	temp=(temp<<8)|Ldata;
	return temp*0.0625;    
}
 
int main(void){
    OLED_Init();
    while(1){
        OLED_ShowNum(1,1,Z_DS18B20_GetTemperture(),3);
        OLED_ShowNum(1,5,(int)(Z_DS18B20_GetTemperture()*100)%100,2);
        Delay_ms(300);
    }
}
 

 ESP8266(Arduino)

#define DS18B20_DQ_GPIO D2
 
void DS18B20_Input_Init(void){
  pinMode(DS18B20_DQ_GPIO, INPUT_PULLUP);
}
 
void DS18B20_Output_Init(void){
  pinMode(DS18B20_DQ_GPIO, OUTPUT);
}
 
void DS18B20_Reset(void)	   
{                 
  DS18B20_Output_Init();
	digitalWrite(DS18B20_DQ_GPIO,LOW);
	delayMicroseconds(750);
	digitalWrite(DS18B20_DQ_GPIO, HIGH);
	delayMicroseconds(15);
}
 
uint8_t DS18B20_Check(void){
  uint8_t waitTime=0;
  DS18B20_Input_Init();
  while(digitalRead(DS18B20_DQ_GPIO) && waitTime<200){
    waitTime++;
    delayMicroseconds(1);
  }
  if(waitTime>=200) return 1;
  else waitTime=0;
 
  while((0==digitalRead(DS18B20_DQ_GPIO)) && waitTime<240){
    waitTime++;
    delayMicroseconds(1);
  }
  if(waitTime>=240) return 1;
  return 0;
}
 
 
uint8_t DS18B20_Read_Bit(void){
  uint8_t res=0;
  DS18B20_Output_Init();
  digitalWrite(DS18B20_DQ_GPIO, LOW);
  delayMicroseconds(2);
  digitalWrite(DS18B20_DQ_GPIO, HIGH);
  DS18B20_Input_Init();
  delayMicroseconds(12);
  res=digitalRead(DS18B20_DQ_GPIO);
  delayMicroseconds(50);
  return res;
}
 
uint8_t DS18B20_Read_Byte(void){
  uint8_t res=0x00;
  for(uint8_t i=0;i<8;++i){
    if(DS18B20_Read_Bit()==1) res|=(0x01<<i);
  }
  return res;
}
 
void DS18B20_Write_Byte(uint8_t data){
  DS18B20_Output_Init();
  for(uint8_t i=0;i<8;++i){
    if(data&0x01==1){
      digitalWrite(DS18B20_DQ_GPIO,LOW);
      delayMicroseconds(2);
      digitalWrite(DS18B20_DQ_GPIO, HIGH);
      delayMicroseconds(60);
    }else{
      digitalWrite(DS18B20_DQ_GPIO,LOW);
      delayMicroseconds(60);
      digitalWrite(DS18B20_DQ_GPIO, HIGH);
      delayMicroseconds(2);
    }
    data>>=1;
  }
}
 
void DS18B20_Start(void){
  DS18B20_Reset();
  DS18B20_Check();
  DS18B20_Write_Byte(0xCC);
  DS18B20_Write_Byte(0x44);
}
 	 
uint8_t DS18B20_Init(void){
  DS18B20_Output_Init();
 	DS18B20_Reset();
	return DS18B20_Check();
}  
 
 
float DS18B20_GetTemperture(void){
	uint16_t temp;
	uint8_t a,b;
	float value;
	
	DS18B20_Start();                  
	DS18B20_Reset();
	DS18B20_Check();	 
	DS18B20_Write_Byte(0xCC);// skip rom
	DS18B20_Write_Byte(0xBE);// convert	    
	a=DS18B20_Read_Byte(); // LSB   
	b=DS18B20_Read_Byte(); // MSB   
	temp=b;
	temp=(temp<<8)+a;
	if((temp&0xF800)==0xF800){
		temp=(~temp)+1;
		value=temp*(-0.0625);
	}else{
		value=temp*0.0625;	
	}
	return value;    
}
 
 
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.println("Hello, STM32!");
  pinMode(D1, OUTPUT);
  digitalWrite(D1, HIGH);
  DS18B20_Init();  
}
int count=0;
void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(D1, !digitalRead(D1));
  delay(1000); // this speeds up the simulation
  Serial.println(DS18B20_GetTemperture());
}

标签:温度传感器,DS18B20,void,总线,uint8,时序,模块,GPIO
From: https://blog.csdn.net/m0_63235356/article/details/140664469

相关文章

  • logging模块用于记录日志的标准库
    日志级别是监控和调试软件系统的关键组成部分,它们帮助开发者和运维人员区分不同严重程度的信息,从而更有效地响应和解决问题。以下是日志级别的详细说明及如何在Python中使用它们的示例。日志级别分类日志级别按严重程度从低到高排序如下:DEBUG:用于记录详细的调试信息,通常在开......
  • Nuxt Kit 的使用指南:模块创建与管理
    title:NuxtKit的使用指南:模块创建与管理date:2024/9/11updated:2024/9/11author:cmdragonexcerpt:摘要:本文是关于NuxtKit的使用指南,重点介绍了如何使用defineNuxtModule创建自定义模块及installModule函数以编程方式安装模块,以增强Nuxt3应用的功能性、可维护性和......
  • PointNet++改进策略 :模块改进 | SWA| PVT,融入Transformer的点云与体素的模块同时提升
    目录介绍PVT原理PVT的核心思想和结构PVT模块结构体素分支点分支代码实现论文题目:PVT:Point-VoxelTransformerforPointCloudLearning发布期刊:InternationalJournalofIntelligentSystems通讯地址:杭州电子科技大学&伦敦大学学院代码地址:https://github.com/......
  • PointNet++改进策略 :模块改进 | x-Conv | PointCNN, 结合局部结构与全局排列提升模型性
    目录前言PointCNN实现细节1.XXX-Conv操作输入输出步骤2.PointCNN网络架构层级卷积分类与分割任务......
  • 解决python封装Logging模块后,log位置显示错误的问题
    引入今天由于项目需要,要将logging库二次封装成一个类,以实现一些自定义的功能。我将二次封装了一个logService类,然后在其中同样也实现info,warn,error等日志函数。额外加了一个将日志存入数据库的功能。大概是像下面这样子:但是在封装的过程中,出现了一个问题:log中,不能正确显......
  • opencv学习:模板匹配和argparse 模块的代码实现及优缺点
    模板匹配模板匹配算法(TemplateMatchingAlgorithm),这是一种在图像处理和计算机视觉领域常用的方法,用于在一个大图像中寻找一个小模板图像的位置。模板匹配算法通过滑动窗口的方式在目标图像上移动模板图像,并计算模板图像与目标图像的局部区域之间的相似度。算法步骤读取图......
  • ColchisFM 新模块发布 | ColchisFM-Python开发接口功能模块
    Python作为目前最流行的一种高级编程语言,‌以其易读性和易用性而闻名。‌特别在人工智能和数学计算上,有着天然的优势和丰富的开源算法库。ColchisFM在地质模型构建方面具有智能化、矢量化、可见即可得的特点。自动化建立地层格架,处理复杂正/逆断层、地层尖灭、地层超覆、削截、......
  • dotenv模块引入失败
    一、背景项目中需要加入环境变量到进程中,例如数据库连接地址、ETCD数据等使用dotenv,读取特定的配置文件进行数据的写入。代码如下:importdotenvfrom'dotenv';dotenv.config({path:'./config/.env',});该代码在其他项目使用过,应该是可以跑通的二、现象项目启动的时......
  • 鸿蒙OS模块化开发实战:独立路由与解耦策略
    前言在现代软件开发中,模块化设计是提高项目可维护性和可扩展性的关键。鸿蒙OS以其先进的架构设计,为开发者提供了强大的模块化开发工具。本文将深入探讨如何在鸿蒙OS中实现模块的独立路由配置,以降低模块间的耦合度,实现单模块的独立运行和开发。一、架构设计概述一个清晰的......
  • NLTK英文文本分词的常用模块
    目录1.断句模块:2.分词模块:3.去除文本中的除标点符号:4.去除停用词:5.词频提取与词频绘图: 5.1词频的提取5.2画出词频5.3画出出现频率最高的三个词 6.单词搜索1.断句模块:importnltkfromnltk.tokenizeimportsent_tokenize#英文断句模块#要断句的文本parag......