Arduino 旋转编码器

news2024/11/19 10:26:40

Arduino 旋转编码器

电位计
Arduino - Rotary Encoder

In this tutorial, we are going to learn how to use the incremental encoder with Arduino. In detail, we will learn:
在本教程中,我们将学习如何将增量编码器与Arduino一起使用。详细来说,我们将学习:

  • How a rotary encoder works
    旋转编码器的工作原理
  • Rotary encoder vs potentiometer
    旋转编码器与电位器区别
  • How to connect the rotary encoder to Arduino
    如何将旋转编码器连接到Arduino
  • How to program Arduino to read the direction and position from the rotary encoder WITHOUT interrupt
    如何对Arduino进行编程,使其不间断地从旋转编码器读取方向和位置
  • How to program Arduino to read the direction and position from the rotary encoder WITH interrupt
    如何对Arduino进行编程,使其从旋转编码器读取方向和位置,并带有中断

About Rotary Encoder 关于旋转编码器

A rotary encoder is an electromechanical device that converts rotational movement into an electrical signal. It measures the rotation and position of a shaft or knob. There are two main types:
旋转编码器是一种将旋转运动转换为电信号的机电设备。它测量轴或旋钮的旋转和位置。主要有两种类型:

  • Incremental encoder: which generates pulses to measure relative change
    增量编码器:产生脉冲以测量相对变化
  • Absolute encoder: which provides a unique digital code for each position, making them ideal for precise positioning even after power loss.
    绝对值编码器:为每个位置提供唯一的数字代码,即使在断电后也能实现精确定位。

This guide is about the incremental encoder.
本指南是关于增量编码器的。

Rotary Encoder Module Pinout 旋转编码器模块引脚排列

请添加图片描述

A rotary encoder module has 4 pins:
旋转编码器模块有 4 个引脚:

  • CLK pin (Output A): is the main pulse that tells us how much rotation has occurred. Whenever you turn the knob by one detent (click) in either direction, the CLK pin outputs a signal that is a completes a full cycle (LOWHIGHLOW).
    CLK 引脚(输出 A):是告诉我们发生了多少旋转的主脉冲。每当您在任一方向上转动旋钮(咔嗒一声)时,CLK 引脚都会输出一个完整的周期(低→高→低)的信号。
  • DT pin (Output B): acts like the CLK pin but outputs a signal lags behind CLK signal by 90 degrees. It helps us figure out the direction of rotation (clockwise or anticlockwise).
    DT 引脚(输出 B):其作用类似于 CLK 引脚,但输出的信号比 CLK 信号滞后 90 度。它可以帮助我们确定旋转方向(顺时针或逆时针)。
  • SW pin: is the output from the pushbutton inside the encoder. It’s normally open. If we use a pull-up resistor in this pin, the SW pin will be HIGH when the knob is not pressed, and LOW when it is pressed.
    SW引脚:是编码器内部按钮的输出。它通常开放。如果我们在此引脚中使用上拉电阻,则未按下旋钮时 SW 引脚将为高电平,按下旋钮时将为低电平。
  • VCC pin (+): needs to be connected to VCC (between 3.3 and 5 volts)
    VCC 引脚 (+):需要连接到 VCC(3.3 到 5 伏之间)
  • GND pin: needs to be connected to GND (0V)
    GND引脚:需要接GND(0V)

Rotary Encoder vs Potentiometer 旋转编码器与电位计区别

You may confuse the rotary encoder with the potentiometer. but they are distinct components. Here’s a comparison between them:
您可能会将旋转编码器与电位计混淆。但它们是不同的组成部分。以下是它们之间的比较:

  • Rotary encoder is like the modern version of potentiometer, but they can do more things.
    旋转编码器就像现代版的电位器,但它们可以做更多的事情。
  • Rotary encoder can spin around in a full circle without stopping, while potentiometer can only turn about three-quarters of the circle.
    旋转编码器可以不停地旋转一整圈,而电位器只能旋转大约四分之三的圆圈。
  • Rotary encoder outputs pulses, while potentiometer outputs the analog voltage.
    旋转编码器输出脉冲,而电位计输出模拟电压。
  • Rotary encoder is handy when you just need to figure out how much the knob has moved, not exactly where it is. Potentiometer is useful when you really need to know exactly where a knob is.
    当您只需要弄清楚旋钮移动了多少,而不是确切地知道它在哪里时,旋转编码器就很方便。当您确实需要确切知道旋钮的位置时,电位计非常有用。

How Rotary Encoder Works 旋转编码器的工作原理

请添加图片描述

Inside the encoder, there’s a disc with slots connected to a pin called C, which is like a shared ground. There are two more pins, A and B.
在编码器内部,有一个圆盘,其插槽连接到一个名为 C 的引脚,就像一个共享接地。还有两个引脚,A 和 B。

  • When you twist the knob, pins A and B touch the shared ground pin C, but in a certain order depending on which way you turn the knob (clockwise or counter-clockwise).
    扭动旋钮时,A 针和 B 针会接触到共用接地针 C,但顺序有所不同,这取决于旋钮的旋转方向(顺时针或逆时针)。
  • These touches create two signals. They’re a bit different in timing because one pin touches the ground before the other. Two signals are 90 degrees out of sync with each other. This is called quadrature encoding.
    这些接触会产生两个信号。它们在时间上有点不同,因为一个引脚比另一个引脚先接地。两个信号相互不同步 90 度。这就是正交编码。
  • When you turn the knob in clockwise direction, pin A touches the ground before pin B. When you turn the knob to the counterclockwise direction, pin B touches the ground before pin A.
    当您顺时针方向转动旋钮时,引脚 A 在引脚 B 之前接触GND。当您将旋钮向逆时针方向转动时,引脚 B 在引脚 A 之前接触GND。
  • By monitoring when each pin touches or leaves the ground, we can figure out which way the knob is turning. We do this by checking what happens to pin B when pin A changes.
    通过监测每个引脚触地或离地的时间,我们就能知道旋钮在朝哪个方向转动。为此,我们要检查 A 引脚发生变化时 B 引脚的情况。

请添加图片描述

When A changes states from LOW to HIGH:
当 A 将状态从 LOW 更改为 HIGH 时:

If B is LOW, the knob is turned clockwise.
如果 B 为低电平,则顺时针转动旋钮。

  • If B is HIGH, the knob is turned counter-clockwise.
    如果 B 为 HIGH,则逆时针转动旋钮。

※ NOTE THAT: ※ 注意事项:

Pin A and B are connected to CLK and DT pins. However, depending on the manufacturers, the order may be different. The codes provided below are tested with the rotary encoder from DIYables
引脚 A 和 B 连接到 CLK 和 DT 引脚。但是,根据制造商的不同,顺序可能会有所不同。下面提供的代码是用DIYables的旋转编码器测试的

How To Program For Rotary Encoder 如何对旋转编码器进行编程

  • Check the signal from CLK pin
    检查来自 CLK 引脚的信号
  • If the state changes from LOW to HIGH, check the state of the DT pin.
    如果状态从LOW变为HIGH,请检查DT引脚的状态。
    • If the state of the DT pin is HIGH, the knob is turned in the counter-clockwise direction, increase the counter by 1
      如果 DT 引脚状态为 HIGH,则旋钮逆时针方向转动,将计数器增加 1
    • If the state of the DT pin is LOW, the knob is turned in the clockwise direction, decrease the counter by 1
      如果 DT 引脚的状态为 LOW,则旋钮顺时针方向转动,将计数器减少 1

Wiring Diagram 接线图

请添加图片描述

This image is created using Fritzing. Click to enlarge image
此图像是使用 Fritzing 创建的。点击放大图片

Arduino Code – Rotary Encoder without Interrupt Arduino代码 – 无中断旋转编码器

The below Arduino code does:
下面的Arduino代码可以:

  • Detects the direction and amount of rotation of the encoder.
    检测编码器的旋转方向和旋转量。
    • If detecting the knob turned by one detent (click) in clockwise direction, increase the counter by one.
      如果检测到旋钮按一个止动器(咔嗒声)顺时针方向转动,请将计数器增加一个。
    • If detecting the knob turned by one detent (click) in anticlockwise direction, decrease the counter by one.
      如果检测到旋钮逆时针方向转动一个咔嗒声,请将计数器减小一个。
  • Detects if the button is pressed.
    检测按钮是否被按下。
/*

 * Created by ArduinoGetStarted.com
   *
 * This example code is in the public domain
   *
 * Tutorial page: https://arduinogetstarted.com/tutorials/arduino-rotary-encoder
   */

#include <ezButton.h>  // the library to use for SW pin

#define CLK_PIN 2
#define DT_PIN 3
#define SW_PIN 4

#define DIRECTION_CW 0   // clockwise direction
#define DIRECTION_CCW 1  // counter-clockwise direction

int counter = 0;
int direction = DIRECTION_CW;
int CLK_state;
int prev_CLK_state;

ezButton button(SW_PIN);  // create ezButton object that attach to pin 4

void setup() {
  Serial.begin(9600);

  // configure encoder pins as inputs
  pinMode(CLK_PIN, INPUT);
  pinMode(DT_PIN, INPUT);
  button.setDebounceTime(50);  // set debounce time to 50 milliseconds

  // read the initial state of the rotary encoder's CLK pin
  prev_CLK_state = digitalRead(CLK_PIN);
}

void loop() {
  button.loop();  // MUST call the loop() function first

  // read the current state of the rotary encoder's CLK pin
  CLK_state = digitalRead(CLK_PIN);

  // If the state of CLK is changed, then pulse occurred
  // React to only the rising edge (from LOW to HIGH) to avoid double count
  if (CLK_state != prev_CLK_state && CLK_state == HIGH) {
    // if the DT state is HIGH
    // the encoder is rotating in counter-clockwise direction => decrease the counter
    if (digitalRead(DT_PIN) == HIGH) {
      counter--;
      direction = DIRECTION_CCW;
    } else {
      // the encoder is rotating in clockwise direction => increase the counter
      counter++;
      direction = DIRECTION_CW;
    }

​    Serial.print("DIRECTION: ");
​    if (direction == DIRECTION_CW)
​      Serial.print("Clockwise");
​    else
​      Serial.print("Counter-clockwise");

​    Serial.print(" | COUNTER: ");
​    Serial.println(counter);
  }

  // save last CLK state
  prev_CLK_state = CLK_state;

  if (button.isPressed()) {
    Serial.println("The button is pressed");
  }
}

To simplify the code for button debouncing, the ezButton library is used.
为了简化按钮去抖动的代码,使用了 ezButton 库。

Quick Steps 快速步骤
  • Install ezButton library on Arduino IDE. See How To
    在Arduino IDE上安装ezButton库。了解操作方法
  • Copy the above code and open with Arduino IDE
    复制上面的代码并使用Arduino IDE打开
  • Click Upload button on Arduino IDE to upload code to Arduino
    单击Arduino IDE上的“上传”按钮,将代码上传到Arduino
  • Turn the knob in clockwise, then anticlockwise
    顺时针转动旋钮,然后逆时针转动
  • Press the knob 按下旋钮
  • See the result on Serial Monitor.
    在串行监视器上查看结果。

Arduino Code – Rotary Encoder with Interrupt Arduino代码 – 带中断的旋转编码器

In the previous example code, we use the polling method, which continuously check the pin’s state. This has two disadvantages:
在前面的示例代码中,我们使用轮询方法,该方法持续检查引脚的状态。这有两个缺点:

  • Waste Arduino resource 浪费Arduino资源
  • Some counter may be missed if another code takes long time to excecute.
    如果另一个代码需要很长时间才能完成,则可能会错过某些计数器。

One approach to handle this is by using interrupts. Interrupts eliminate the need for constant checking of a particular event. This allows the Arduino to carry out other tasks without overlooking an event.
处理此问题的一种方法是使用中断。中断消除了对特定事件进行持续检查的需要。这允许Arduino在不忽略事件的情况下执行其他任务。

Here’s an example of how to read a rotary encoder with interrupts.
下面是一个示例,说明如何读取带有中断的旋转编码器。

/*

 * Created by ArduinoGetStarted.com
   *
 * This example code is in the public domain
   *
 * Tutorial page: https://arduinogetstarted.com/tutorials/arduino-rotary-encoder
   */

#include <ezButton.h>  // the library to use for SW pin

#define CLK_PIN 2
#define DT_PIN 3
#define SW_PIN 4

#define DIRECTION_CW 0   // clockwise direction
#define DIRECTION_CCW 1  // counter-clockwise direction

volatile int counter = 0;
volatile int direction = DIRECTION_CW;
volatile unsigned long last_time;  // for debouncing
int prev_counter;

ezButton button(SW_PIN);  // create ezButton object that attach to pin 4

void setup() {
  Serial.begin(9600);

  // configure encoder pins as inputs
  pinMode(CLK_PIN, INPUT);
  pinMode(DT_PIN, INPUT);
  button.setDebounceTime(50);  // set debounce time to 50 milliseconds

  // use interrupt for CLK pin is enough
  // call ISR_encoderChange() when CLK pin changes from LOW to HIGH
  attachInterrupt(digitalPinToInterrupt(CLK_PIN), ISR_encoderChange, RISING);
}

void loop() {
  button.loop();  // MUST call the loop() function first

  if (prev_counter != counter) {
    Serial.print("DIRECTION: ");
    if (direction == DIRECTION_CW)
      Serial.print("Clockwise");
    else
      Serial.print("Counter-clockwise");

​    Serial.print(" | COUNTER: ");
​    Serial.println(counter);

​    prev_counter = counter;
  }

  if (button.isPressed()) {
    Serial.println("The button is pressed");
  }

  // TO DO: your other work here
}

void ISR_encoderChange() {
  if ((millis() - last_time) < 50)  // debounce time is 50ms
    return;

  if (digitalRead(DT_PIN) == HIGH) {
    // the encoder is rotating in counter-clockwise direction => decrease the counter
    counter--;
    direction = DIRECTION_CCW;
  } else {
    // the encoder is rotating in clockwise direction => increase the counter
    counter++;
    direction = DIRECTION_CW;
  }

  last_time = millis();
}

Now, As you twist the knob, you’ll notice information appearing on the Serial Monitor, much like what you saw in the earlier code.
现在,当您转动旋钮时,您会注意到串行监视器上出现的信息,与您在前面的代码中看到的非常相似。

※ NOTE THAT: ※ 注意事项:

  • If you use the interrupt, you need to connect the encoder’s CLK pin to an Arduino pin that can handle interrupts. But remember, not all Arduino pins can do this. For example, on the Arduino Uno, only pins 2 and 3 can work with interrupts.
    如果使用中断,则需要将编码器的 CLK 引脚连接到可以处理中断的 Arduino 引脚。但请记住,并非所有Arduino引脚都可以做到这一点。例如,在 Arduino Uno 上,只有引脚 2 和 3 可以使用中断。
  • You might come across tutorials on other websites that use two interrupts for a single encoder, but this is unnecessary and wasteful. Just one interrupt is sufficient.
    您可能会在其他网站上遇到对单个编码器使用两个中断的教程,但这是不必要的和浪费的。只需一次中断就足够了。
  • It’s important to use the volatile keyword for global variables used in the interrupt. Neglecting this could lead to unexpected issues.
    对中断中使用的全局变量使用 volatile 关键字非常重要。忽视这一点可能会导致意想不到的问题
  • Keep the code within the interrupt as straightforward as you can. Avoid using Serial.print() or Serial.println() inside the interrupt.
    在中断中保持代码尽可能简单明了。避免在中断中使用 Serial.print() 或 Serial.println()

Arduino Rotary Encoder Application Arduino旋转编码器应用

With Rotary Encoder, we can do the following applications but not limit:
使用旋转编码器,我们可以执行以下应用,但不限于:

  • Arduino - Rotary Encoder controls Position of Sevo Motor
    Arduino - 旋转编码器控制 Sevo 电机的位置
  • Arduino - Rotary Encoder controls Brightness of LED
    Arduino - 旋转编码器控制 LED 亮度
  • Arduino - Rotary Encoder controls Speed of Stepper Motor
    Arduino - 旋转编码器控制步进电机的速度

示例1

在这里插入图片描述


/*
 * Created by ArduinoGetStarted.com
 *
 * This example code is in the public domain
 *
 * Tutorial page: https://arduinogetstarted.com/tutorials/arduino-rotary-encoder-led
 */

#include <Servo.h>

#define CLK_PIN 2
#define DT_PIN 3
#define SW_PIN 4
#define LED_PIN 9

#define DIRECTION_CW 0   // clockwise direction
#define DIRECTION_CCW 1  // counter-clockwise direction

int counter = 0;
int direction = DIRECTION_CW;
int CLK_state;
int prev_CLK_state;
int brightness = 125;  // middle value

void setup() {
  Serial.begin(9600);

  // configure encoder pins as inputs
  pinMode(CLK_PIN, INPUT);
  pinMode(DT_PIN, INPUT);

  // read the initial state of the rotary encoder's CLK pin
  prev_CLK_state = digitalRead(CLK_PIN);
  pinMode(LED_PIN, OUTPUT);
}

void loop() {

  // read the current state of the rotary encoder's CLK pin
  CLK_state = digitalRead(CLK_PIN);

  // If the state of CLK is changed, then pulse occurred
  // React to only the rising edge (from LOW to HIGH) to avoid double count
  if (CLK_state != prev_CLK_state && CLK_state == HIGH) {
    // if the DT state is HIGH
    // the encoder is rotating in counter-clockwise direction => decrease the counter
    if (digitalRead(DT_PIN) == HIGH) {
      direction = DIRECTION_CCW;
      counter--;
      brightness -= 10;  // you can change this value
    } else {
      // the encoder is rotating in clockwise direction => increase the counter
      direction = DIRECTION_CW;
      counter++;
      brightness += 10;  // you can change this value
    }

    if (brightness < 0)
      brightness = 0;
    else if (brightness > 255)
      brightness = 255;

    // sets the brightness of LED according to the counter
    analogWrite(LED_PIN, brightness);

    Serial.print("COUNTER: ");
    Serial.print(counter);
    Serial.print(" | BRIGHTNESS: ");
    Serial.println(brightness);
  }

  // save last CLK state
  prev_CLK_state = CLK_state;
}

示例2

在这里插入图片描述

/*
 * Created by ArduinoGetStarted.com
 *
 * This example code is in the public domain
 *
 * Tutorial page: https://arduinogetstarted.com/tutorials/arduino-rotary-encoder-servo-motor
 */

#include <Servo.h>

#define CLK_PIN 2
#define DT_PIN 3
#define SW_PIN 4
#define SERVO_PIN 9

#define DIRECTION_CW 0   // clockwise direction
#define DIRECTION_CCW 1  // counter-clockwise direction

int counter = 0;
int direction = DIRECTION_CW;
int CLK_state;
int prev_CLK_state;

Servo servo;  // create servo object to control a servo

void setup() {
  Serial.begin(9600);

  // configure encoder pins as inputs
  pinMode(CLK_PIN, INPUT);
  pinMode(DT_PIN, INPUT);

  // read the initial state of the rotary encoder's CLK pin
  prev_CLK_state = digitalRead(CLK_PIN);
  servo.attach(SERVO_PIN);  // attaches the servo on pin 9 to the servo object
  servo.write(0);
}

void loop() {

  // read the current state of the rotary encoder's CLK pin
  CLK_state = digitalRead(CLK_PIN);

  // If the state of CLK is changed, then pulse occurred
  // React to only the rising edge (from LOW to HIGH) to avoid double count
  if (CLK_state != prev_CLK_state && CLK_state == HIGH) {
    // if the DT state is HIGH
    // the encoder is rotating in counter-clockwise direction => decrease the counter
    if (digitalRead(DT_PIN) == HIGH) {
      counter--;
      direction = DIRECTION_CCW;
    } else {
      // the encoder is rotating in clockwise direction => increase the counter
      counter++;
      direction = DIRECTION_CW;
    }

    Serial.print("DIRECTION: ");
    if (direction == DIRECTION_CW)
      Serial.print("Clockwise");
    else
      Serial.print("Counter-clockwise");

    Serial.print(" | COUNTER: ");
    Serial.println(counter);

    if (counter < 0)
      counter = 0;
    else if (counter > 180)
      counter = 180;

    // sets the servo angle according to the counter
    servo.write(counter);
  }

  // save last CLK state
  prev_CLK_state = CLK_state;
}

Video Tutorial 视频教程

We are considering to make the video tutorials. If you think the video tutorials are essential, please subscribe to our YouTube channel to give us motivation for making the videos.
我们正在考虑制作视频教程。如果您认为视频教程是必不可少的,请订阅我们的 YouTube 频道,为我们制作视频提供动力。

Function References

  • pinMode()

  • digitalRead()

  • Serial

See Also

  • Arduino - Rotary Encoder LED
  • Arduino - Rotary Encoder - Servo Motor

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1863775.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

iptables(11)target(SNAT、DNAT、MASQUERADE、REDIRECT)

简介 前面我们已经介绍了ACCEPT、DROP、REJECT、LOG,这篇文章我们介绍SNAT、DNAT、MASQUERADE、REDIRECT,这几个参数的定义我们在上篇文章中都有介绍,我这里再列出回顾一下 DNAT(目标地址转换)和 SNAT(源地址转换) 原理:修改数据包的源或目标 IP 地址。通常用于 NAT(…

Maven高级理解属性

属性 在这一章节内容中&#xff0c;我们将学习两个内容&#xff0c;分别是 属性版本管理 属性中会继续解决分模块开发项目存在的问题&#xff0c;版本管理主要是认识下当前主流的版本定义方式。 4.1 属性 4.1.1 问题分析 讲解内容之前&#xff0c;我们还是先来分析问题: …

Games101 透视投影矩阵推导

目录 齐次坐标 透视投影 透视投影的四棱锥体挤压为正交投影的长方体 变换规定 转换过程 观察1 观察2 关于任意一点挤压后向哪里移动的问题&#xff0c;简单推导了一下 齐次坐标 如下&#xff0c;(x, y, z, 1) 表示空间中的xyz点&#xff0c;让它每个分量乘以k&#…

MySQL 基础概念

MySQL逻辑架构 MySQL 服务器逻辑架构图 最上层的服务并不是MySQL所独有的&#xff0c;大多数基于网络的客户端/服务器的工具或者服务都有类似的架构&#xff0c;比如连接管理、授权认证、安全等等。 大多数MySQL的核心服务都在第二层&#xff0c;包括查询解析、分析、优化、…

空间的维度

空间的维度----中科院科学智慧火花 当今世界科学前沿&#xff0c;最具有挑战性和最激动人心的理论&#xff0c;莫过于弦理论&#xff0c;他不仅仅融合了相对论和量子理论&#xff0c;甚至被认为是终极理论。弦理论最核心的内容就是多维空间。由于时间和空间概念必然要写进物理…

Echarts 图表添加点击事件跳转页面,但只有图表部分点击才会跳转页面,坐标轴,区域缩放等点击不跳转。

默认的点击事件是这样的&#xff1a; myChart.on(click, function (param) {console.log(param) }) 这个事件需要点击具体图形才会触发&#xff0c;例如我上面的图&#xff0c;想选择a柱子&#xff0c;就需要明确点击到柱体才行&#xff0c;明显不符合正常的预期&#xff0c;正…

FullCalendar日历组件集成实战(16)

背景 有一些应用系统或应用功能&#xff0c;如日程管理、任务管理需要使用到日历组件。虽然Element Plus也提供了日历组件&#xff0c;但功能比较简单&#xff0c;用来做数据展现勉强可用。但如果需要进行复杂的数据展示&#xff0c;以及互动操作如通过点击添加事件&#xff0…

【Linux】Wmware Esxi磁盘扩容

目录 一、概述 1.1 磁盘分区概念 1.2 LVM概念 二、扩容步骤 二、报错 一、概述 1.1 磁盘分区概念 在 Linux 中&#xff0c;每一个硬件设备都映射到一个系统的文件&#xff0c;对于硬盘、光驱等 IDE 或 SCSI 设备也不例外。Linux把各种 IDE 设备分配了一个由 hd 前缀组成的文…

使用VBA隐藏图表中的系列

Excel中很多图表相关的操作&#xff0c;并不能通过录制宏得到代码&#xff0c;这个场景中&#xff0c;如下希望开发代码实现自动化&#xff0c;就会无从下手&#xff0c;其实只要找到相关的属性和方法&#xff0c;代码可能并不复杂。 Excel的线图如下所示&#xff0c;其中有三…

每日一学(面试考题)

1、ConCurrentHashMap为什么不允许key为null&#xff1f; 底层 putVal方法 中 如果key || value为空 抛出空指针异常 其实是为了避免在多线程并发场景下的歧义问题 在获取key 返回结果为null 无法判断是 put&#xff08;k&#xff0c;v&#xff09;的时候 value本身是n…

Python+Pytest+Allure+Yaml接口自动化测试框架详解

PythonPytestAllureYaml接口自动化测试框架详解 编撰人&#xff1a;CesareCheung 更新时间&#xff1a;2024.06.20 一、技术栈 PythonPytestAllureYaml 版本要求&#xff1a;Python3.7.0,Pytest7.4.4,Allure2.18.1,PyYaml6.0 二、环境配置 1、安装python3.7&#xff0c;并配置…

探索ONLYOFFICE桌面编辑器8.1:更强大的办公软件(新功能全新详解)

引入 时间到达2024年&#xff0c;办公软件已经成为不可或缺的的一部分。想到办公软件不知道大家首先想到那些产品 office 亦或是 WPS&#xff0c;但一个前者需要购买才能使用完整服务&#xff0c;一个漫天的弹广告不充会员什么都用不了。那难道世面上就没有一块正在好用无广告的…

一天跌20%,近500只下跌,低价可转债为何不香了?

6月以来&#xff0c;Wind可转债低价指数累计下跌7.3%&#xff0c;大幅跑输中价、高价转债。分析认为&#xff0c;市场调整的底层逻辑在于投资者对风险的重新评估和流动性的紧缩&#xff0c;宏观经济的波动和政策环境的不确定性、市场结构性的变化均对低价可转债市场产生了冲击。…

【 IM 服务】IM 翻译服务介绍

融云控制台 IM 翻译功能入口&#xff1a;IM 翻译 融云即时通讯业务提供 IM 翻译 插件&#xff0c;可为 IMLib 与 IMKit SDK 快速接入外部翻译服务&#xff0c;由融云服务端负责对接外部翻译服务供应商的鉴权、API 调用、账号管理、计费等流程。 提示&#xff1a; 1、该插件仅支…

COMSOL - 一个点光源是否总能照亮整个房间?

20 世纪 50 年代&#xff0c;数学家恩斯特施特劳斯&#xff08;Ernst Straus&#xff09;提出了一个有趣的问题&#xff1a;在一个侧壁由理想反射镜构成的任意形状的空房间里&#xff0c;一个点光源是否总能照亮整个房间&#xff1f;诺贝尔奖获得者罗杰彭罗斯&#xff08;Roger…

背包模型——AcWing 423. 采药

背包模型 定义 背包模型是一种常见的算法问题模型&#xff0c;它主要涉及将一些物品放入一个容量有限的背包中&#xff0c;以达到某种最优目标&#xff0c;如最大化价值或最小化重量等。 运用情况 常用于资源分配、项目选择、货物装载等实际问题中。例如&#xff0c;在选择…

一次性掌握openlayers和cesium两个地图开发框架

又到一年毕业季&#xff0c;选择就业的同学&#xff0c;如果还没拿到offer&#xff0c;就要开始准备秋招了。 如果想找webgis相关的岗位&#xff0c;可以通过招聘信息&#xff0c;了解到企业的具体要求。其中&#xff0c;openlayers和cesium有多重要就不用我多说了。 掌握这两…

AI对职场的整顿

普通人离AI还有几年缓冲区&#xff0c;但早点做准备总是好的 AI淘汰的始终是跟不上时代的人。 现在很多公司都有AI培训&#xff0c;不仅GPT&#xff0c;还有Midjourney、Stable DIffusion等一系列AI工具。 像我们公司虽然今年招的少&#xff0c;但也会对新招的应届生统一进行…

VSCode运行前端项目-页面404

背景&#xff1a; 通过VSCode运行前端本地项目&#xff0c;运行成功后打开本地链接&#xff1a;http://1x.xxx.x.xxx:9803/ &#xff0c;发现打开的页面重定向到404&#xff1a;http//1xx.xxx.x.xxx:9803/404&#xff1b; 并且控制台出现&#xff1a;Failed to load resource: …

邮件自动推送技术如何实现?有哪些优劣势?

邮件自动推送怎么设置&#xff1f;如何评估邮件自动推送的效果&#xff1f; 邮件自动推送是一种高效的电子邮件营销和通信技术&#xff0c;它能够根据预设条件自动发送邮件给特定的收件人。AokSend将深入探讨邮件自动推送技术的实现原理和注意事项。 邮件自动推送&#xff1a…