提问人:Muhammad Dawood Ahmed 提问时间:11/11/2023 最后编辑:CliffordMuhammad Dawood Ahmed 更新时间:11/11/2023 访问量:32
故障输入 ESP32 显示
fault input ESP32 showing
问:
我正在使用电容式传感器检测物体。传感器需要 24V 才能运行,但 ESP32 在 2.2 至 3.6V 下运行。传感器的输入也将是 24V。 所以我不能直接将传感器连接到 ESP32,它会损坏我的 ESP32。为此,我使用了 Relay,我将 Sensor 与 Relay 连接,并将 Relay 与 ESP32 连接。
传感器的输出线和传感器的负极线与继电器线圈连接。
我使用 25pin 作为 ESP32 的输出和 34pin 的输入。
25pin连接到继电器12端口,该端口与4端口常闭,与8端口常开,34pin连接到8端口。
当传感器检测到某些东西时,传感器灯亮起。 ESP32 的 LED 亮起,并在串行监视器上打印“检测到”,传感器灯、LED 保持亮起并持续打印“检测到”,直到物体与传感器接触。
但是当有物体时,传感器的灯保持关闭状态。但有时 LED 会亮起,“检测到”即使没有物体,也会开始在串行监视器上打印。 另外,如果我从继电器(34端口)上取下输入引脚(8pin)。有时它打印“检测到”并且 LED 也亮起。
首先,我宣布引脚为数字引脚,现在我声明引脚为模拟引脚。
但结果仍然相同,但现在我通过将 10 传感器的输入相加并将总和除以 10 来归档数据。这效果很好,但有时仍然会出现同样的问题。我想我已经清除了 ESP32 的缓冲区来解决这个问题。我不知道如何清除缓冲区。还是使用 millis()?
代码如下:
const int input=34;
const int output=25;
const int led=2;
void setup()
{
pinMode(input,INPUT);
pinMode(output,OUTPUT);
pinMode(led,2);
Serial.begin(300);
digitalWrite(output,HIGH);
}
void loop()
{
int detect=0;
for(int i=0;i<10;i++)
{
detect+=analogRead(input);
}
detect=detect/10;
if(detect>4000)
{
Serial.println("Detected");
digitalWrite(led,HIGH);
detect=0;
}
else
{
Serial.println("Not Detected");
digitalWrite(led,LOW);
detect=0;
}
}
答:
本网站无法确定您的硬件是否正确,但继电器是数字状态开关,高电平或低电平。因此,通过模拟输入读取它几乎没有意义。
您之前没有使用数字输入的尝试更令人感兴趣,但是您在这两种情况下遇到的问题几乎可以肯定是由于开关反弹造成的。既然您提到了继电器线圈,很明显您没有使用固态继电器,因此它会受到开关反弹的影响。
开关弹跳是机电触点的一个问题,当触点打开或关闭时,电压会在短时间内变化。交换机反弹状态更改的时间和轮询交换机可能会导致读取不正确的状态 - 尤其是在实施状态更改检测时。
要解决此问题,您的软件必须实现“去抖动”算法。一个简单的方法是对任何状态变化进行时间戳,然后在经过足够长的时间后接受状态,任何开关反弹都已稳定下来(通常 20-30 毫秒就足够了)。
例如:
void loop()
{
// Debounce time in milliseconds
static const int DEBOUNCE_MS = 30 ;
// Initial state
static int proximity_detect_state = digitalRead( input ) ;
// Debounce timestamp and state
static unsigned long state_change_timestamp = 0;
static bool debouncing = false ;
// Get input state and time
int input_state = digitalRead( input ) ;
int now = millis() ;
// Debounce input...
if( input_state != proximity_detect_state )
{
// State changed, timestamp it.
state_change_timestamp = now ;
debouncing = true ;
}
else if( debouncing &&
now - state_change_timestamp > DEBOUNCE_MS )
{
// Steady state for debounce period, accept it as a new state
proximity_detect_state = input_state ;
debouncing = false ;
}
// On change of debounced state...
// Force state change of first iteration
static int previous_proximity_detect_state = proximity_detect_state == 0 ? 1 : 0 ;
if( proximity_detect_state != previous_proximity_detect_state )
{
previous_proximity_detect_state = proximity_detect_state ;
if( proximity_detect_state != 0 )
{
Serial.println( "Detected" ) ;
digitalWrite(led,HIGH);
}
else
{
Serial.println("Not Detected");
digitalWrite(led,LOW);
}
}
}
以上部分仅用于防止串口连续输出。重复设置 LED 状态是良性的,因此不需要串行输出,您可以简单地拥有:// On change of debounced state...
previous_proximity_detect_state
digitalWrite( led, proximity_detect_state ? HIGH : LOW ) ;
代替整个块。
如果不需要严格的确定性实时确定性响应,则更简单的解决方案是以略高于开关反弹时间的间隔轮询输入状态。例如:
void loop()
{
static const int POLL_INTERVAL_MS = 100 ;
// Initial state and time
static int proximity_detect_state = digitalRead( input ) ;
static unsigned long poll_timestamp = millis() ;
// Get current time
int now = millis() ;
// If time to poll input...
if( now - millis() >= POLL_INTERVAL_MS )
{
proximity_detect_state = digitalRead( input ) ;
}
digitalWrite( led, proximity_detect_state ? HIGH : LOW ) ;
}
比较两种解决方案,在第一种解决方案中,状态变化检测在事件发生后 30 毫秒确定性地发生。任何抖动都归结为继电器的物理反弹持续时间。而在第二秒中,检测发生在实际事件发生后 0 到 100 毫秒之间的任何时间。显然,您可以减少轮询间隔,但它将保持可变,在某些情况下,您可能需要更具确定性的东西。
当然,另一种解决方案是使用固态继电器而不是机电继电器。但这并不在本网站上的真正范围之内。它在EMC、功耗和耐用性方面也具有其他优势。
评论