You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于TinkerCad中Arduino Uno的报警系统代码问题求助

基于Arduino Uno的夜间报警系统代码修复

项目需求

  • 报警系统仅在夜间工作
  • 门/窗对应按钮被触发后,声光报警持续激活30秒
  • 需添加传感器触发阈值的可配置项

当前存在的问题

  • LCD显示屏消息重叠、频繁卡顿闪烁
  • 夜间按下按钮后,蜂鸣器与LED无法正常触发报警

变量翻译(葡萄牙语→中文)

  • botaoAtivarJanelaPin = 窗户触发按钮引脚
  • botaoAtivarPortaPin = 门触发按钮引脚
  • fotoresistorPin = 光敏电阻引脚
  • alarmeAtivado = 报警激活状态
  • sensorLuz = 光线传感器读数
  • Sistema desligado = 系统关闭
  • Sistema ligado = 系统开启
  • Janela Aberta = 窗户打开
  • Porta Aberta = 门打开

原代码

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

const int alarmePiezoPin = 3;
const int ledPin = 4;
const int botaoAtivarJanelaPin = 5;
const int botaoAtivarPortaPin = 6;
const int fotoresistorPin = A0;
const int sensorPirPin = A2;

int sensorState = LOW;
int ledState = LOW;
int alarmeAtivado = 0;
int sensorLuz = 0; //

void setup() {
 
  pinMode(alarmePiezoPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(sensorPirPin, INPUT);
  pinMode(botaoAtivarJanelaPin, INPUT_PULLUP);
  pinMode(botaoAtivarPortaPin, INPUT_PULLUP);

 
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Sistema desligado");
}

void loop() {
    sensorState = digitalRead(sensorPirPin);
    sensorLuz = analogRead(fotoresistorPin);
  
  if(sensorLuz < 500){
    alarmeAtivado = 0;
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Sistema desligado");
  } else {
    lcd.setCursor(0, 0);
    lcd.print("Sistema Ligado  ");
  }
  
  if ((digitalRead(botaoAtivarPortaPin) == LOW)) {
    alarmeAtivado = 1;
    lcd.setCursor(0, 1);
    lcd.print("PORTA ABERTA! ");
  } 

  if ((digitalRead(botaoAtivarJanelaPin) == LOW)) {
    alarmeAtivado = 1;
    lcd.setCursor(0, 1);
    lcd.print("JANELA ABERTA!");
  }
  if(sensorLuz < 500){
    if ((sensorState == HIGH) || (alarmeAtivado == 1)) {
      ativarAlarme();
    }
  }
  
  delay(100);
}

void ativarAlarme(){
    tone(alarmePiezoPin, 2000); 
    digitalWrite(ledPin, HIGH);
    delay(500);
    noTone(alarmePiezoPin);
    digitalWrite(ledPin, LOW);
}

修复后的代码

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

// 可配置常量
const int alarmePiezoPin = 3;
const int ledPin = 4;
const int botaoAtivarJanelaPin = 5;
const int botaoAtivarPortaPin = 6;
const int fotoresistorPin = A0;
const int sensorPirPin = A2;
const int LUZ_NOTURNA_LIMITE = 500; // 夜间光线阈值(可调整)
const int ALARME_DURACAO = 30000; // 报警持续时间(30秒)
const int PIR_TRIGGER_ESTADO = HIGH; // PIR传感器触发状态(可结合硬件调整)

// 状态变量
int sensorState = LOW;
int alarmeAtivado = 0;
int sensorLuz = 0;
unsigned long alarmeInicioTempo = 0;
int ultimoEstadoSistema = -1; // 记录上一次系统状态,避免重复更新LCD
int ultimoEstadoAlarme = -1; // 记录上一次报警触发状态

void setup() {
  pinMode(alarmePiezoPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(sensorPirPin, INPUT);
  pinMode(botaoAtivarJanelaPin, INPUT_PULLUP);
  pinMode(botaoAtivarPortaPin, INPUT_PULLUP);

  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Sistema desligado");
}

void loop() {
  sensorState = digitalRead(sensorPirPin);
  sensorLuz = analogRead(fotoresistorPin);
  
  // 判断是否为夜间(系统激活条件)
  int estadoSistema = (sensorLuz < LUZ_NOTURNA_LIMITE) ? 1 : 0;

  // 仅当系统状态变化时更新LCD,避免频繁闪烁
  if (estadoSistema != ultimoEstadoSistema) {
    lcd.setCursor(0, 0);
    if (estadoSistema == 1) {
      lcd.print("Sistema Ligado   "); // 补空格覆盖旧内容
    } else {
      lcd.print("Sistema desligado");
      alarmeAtivado = 0; // 白天强制关闭报警
    }
    ultimoEstadoSistema = estadoSistema;
  }

  // 检测门/窗按钮触发
  if (digitalRead(botaoAtivarPortaPin) == LOW && estadoSistema == 1) {
    alarmeAtivado = 1;
    atualizarLCDLinha1("PORTA ABERTA!   ");
  } else if (digitalRead(botaoAtivarJanelaPin) == LOW && estadoSistema == 1) {
    alarmeAtivado = 1;
    atualizarLCDLinha1("JANELA ABERTA!  ");
  } else if (alarmeAtivado == 0 && estadoSistema == 1) {
    // 无报警时清空第二行
    atualizarLCDLinha1("                ");
  }

  // 夜间触发报警逻辑
  if (estadoSistema == 1) {
    if ((sensorState == PIR_TRIGGER_ESTADO) || (alarmeAtivado == 1)) {
      if (ultimoEstadoAlarme != 1) {
        alarmeInicioTempo = millis();
        ultimoEstadoAlarme = 1;
      }
      // 持续触发报警直到30秒结束
      if (millis() - alarmeInicioTempo < ALARME_DURACAO) {
        tone(alarmePiezoPin, 2000);
        digitalWrite(ledPin, HIGH);
      } else {
        // 报警结束后重置状态
        noTone(alarmePiezoPin);
        digitalWrite(ledPin, LOW);
        alarmeAtivado = 0;
        ultimoEstadoAlarme = 0;
        atualizarLCDLinha1("                ");
      }
    } else {
      // 无触发时关闭报警
      noTone(alarmePiezoPin);
      digitalWrite(ledPin, LOW);
      ultimoEstadoAlarme = 0;
    }
  } else {
    // 白天强制关闭报警
    noTone(alarmePiezoPin);
    digitalWrite(ledPin, LOW);
    ultimoEstadoAlarme = 0;
  }

  delay(50); // 缩短延迟,提升响应速度
}

// 封装LCD第二行更新函数,避免重复代码
void atualizarLCDLinha1(String texto) {
  lcd.setCursor(0, 1);
  lcd.print(texto);
}

修复说明

  1. LCD显示问题解决

    • 新增状态变量记录上一次系统和报警状态,仅当状态变化时更新LCD,避免频繁刷新导致的闪烁
    • 打印文本时补充空格,覆盖旧内容,解决消息重叠问题
    • 封装LCD第二行更新函数,简化代码逻辑
  2. 报警触发逻辑修复

    • 修正夜间判断逻辑:原代码将sensorLuz <500判定为系统关闭,与需求完全相反,现在改为夜间(光线低于阈值)系统激活
    • 使用millis()替代delay()实现30秒报警持续,避免阻塞主循环,保证LCD和按钮响应正常
    • 完善报警状态重置逻辑,报警结束后自动恢复系统正常状态
  3. 添加可配置阈值

    • 新增LUZ_NOTURNA_LIMITE常量,可直接调整夜间光线判定阈值
    • 新增ALARME_DURACAO常量,方便修改报警持续时间
    • 新增PIR_TRIGGER_ESTADO常量,可结合硬件调整PIR传感器的触发逻辑

内容的提问来源于stack exchange,提问作者Matheus Mendonca

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 01:16:01