基于 ATMEGA168 单片机的消毒机系统设计与实现

一、设计概述

本设计以 ATMEGA168 单片机为核心,针对公共场所 / 家庭场景的消毒需求,实现一款集定时消毒、人体感应防护、多模式消毒、状态显示 于一体的智能消毒机系统。系统支持紫外线 / 臭氧两种主流消毒方式(可按需选配),通过人体红外传感器实现 "有人即停" 的安全防护,同时提供按键设置消毒时长、蜂鸣器报警、LED 状态指示等功能,兼顾实用性与安全性。

核心功能

  1. 消毒模式控制:支持紫外线消毒、臭氧消毒、组合消毒三种模式,可通过按键切换;
  2. 定时功能:0~60 分钟可调消毒时长,到达设定时间自动停止消毒;
  3. 安全防护:人体红外感应(PIR)检测到有人时,立即停止消毒并报警,防止紫外线 / 臭氧伤害;
  4. 状态指示:LED 灯显示当前工作模式、消毒倒计时、异常状态;
  5. 报警提示:人体闯入、超时工作、设备故障时蜂鸣器报警;
  6. 手动控制:按键启停消毒、调整时长 / 模式,紧急停止按键(急停)。

二、硬件选型与电路设计

1. 核心硬件清单

模块 型号 / 规格 作用
主控单片机 ATMEGA168PA-AU(8 位 AVR) 数据处理、逻辑控制
消毒模块 紫外线灯(12V)/ 臭氧发生器(5V) 执行消毒动作
人体感应传感器 HC-SR501(PIR) 检测人体靠近
驱动模块 继电器模块(5V/2 路) 驱动紫外线灯 / 臭氧发生器
显示模块 四位数码管(共阴 / 共阳) 显示消毒时长 / 倒计时
按键 轻触按键 ×4(模式 / 加 / 减 / 启停) 手动设置参数、控制设备
蜂鸣器 无源蜂鸣器(5V) 报警提示
状态 LED 红 / 绿 / 蓝 LED×3 指示模式 / 异常状态
电源模块 220V 转 12V/5V 适配器 为系统供电
保险丝 500mA 保险丝 过流保护

2. 核心电路设计

ATMEGA168 核心资源:14 路数字 I/O、8 路 10 位 ADC、3 路定时器 / 计数器,满足系统需求。

(1)主控电路(最小系统)
  • 电源:5V 直流供电,VCC 接 5V,GND 共地;
  • 晶振:16MHz 外部晶振(XTAL1/XTAL2),搭配 22pF 电容接地,保证时钟稳定;
  • 复位:RESET 引脚接 10K 上拉电阻,并联轻触按键(按下接地),实现手动复位;
  • ISP 下载:PC0~PC3(SPI 接口),用于程序烧录。
(2)外设连接电路
外设 连接引脚(ATMEGA168) 备注
PIR 传感器 数字引脚 D2(INT0) 中断触发,有人时立即响应
紫外线继电器 数字引脚 D3 高电平吸合,驱动 12V 紫外灯
臭氧继电器 数字引脚 D4 高电平吸合,驱动 5V 臭氧发生器
数码管段选 D5~D11(a~g + 小数点) 7 段 + 小数点,共 8 路
数码管位选 A0~A3(PC0~PC3) 四位数码管独立控制
模式按键 D12 下拉电阻,按下接 5V
加键 D13 下拉电阻,按下接 5V
减键 A4(PC4) 下拉电阻,按下接 5V
启停 / 急停键 A5(PC5) 下拉电阻,按下接 5V
蜂鸣器 A6(PC6) 三极管驱动,PWM 发声
状态 LED(红) A7(PC7) 串联 220Ω 限流电阻
状态 LED(绿) D0 串联 220Ω 限流电阻
状态 LED(蓝) D1 串联 220Ω 限流电阻
(3)关键防护电路
  • 紫外线 / 臭氧继电器:触点并联 1N4007 续流二极管,防止感性负载反向电动势损坏继电器;
  • 电源输入端:串联保险丝,并联 0.1μF 滤波电容,降低电压波动;
  • PIR 传感器:输出端串联 1K 限流电阻,防止过流损坏单片机 I/O 口。

3. 电路原理图(简化框架)

plaintext

复制代码
ATMEGA168最小系统
  |-- 16MHz晶振(XTAL1/XTAL2)+ 22pF电容
  |-- RESET(上拉10K + 复位按键)
  |-- ISP下载(PC0~PC3)
  |-- D2 → HC-SR501输出(INT0中断)
  |-- D3 → 紫外线继电器控制端 → 12V紫外灯
  |-- D4 → 臭氧继电器控制端 → 5V臭氧发生器
  |-- D5~D11 → 数码管段选(a~g+dp)
  |-- PC0~PC3 → 数码管位选(四位)
  |-- D12/D13/PC4/PC5 → 模式/加/减/启停按键
  |-- PC6 → 蜂鸣器(NPN三极管驱动)
  |-- PC7/D0/D1 → 红/绿/蓝状态LED
  |-- VCC → 5V电源,GND → 共地
220V→12V适配器 → 12V紫外灯 + 12V转5V模块 → 单片机/传感器供电

三、软件设计

1. 开发环境与核心资源

  • 开发环境:Atmel Studio 7.0(或 Arduino IDE,需安装 ATMEGA168 支持);
  • 编程语言:C 语言(AVR-GCC 编译器);
  • 核心资源:
    • 定时器:Timer0(8 位)实现 1ms 系统时钟,Timer1(16 位)实现倒计时;
    • 外部中断:INT0(D2)响应 PIR 人体感应;
    • GPIO:数字 I/O 控制继电器、按键、LED;
    • SPI:可选扩展(本设计暂未使用)。

2. 程序架构

plaintext

复制代码
主程序流程:
1. 初始化:
   a. 端口初始化(I/O方向、上拉/下拉);
   b. 定时器初始化(1ms中断、倒计时计时);
   c. 外部中断初始化(INT0下降沿触发,PIR检测);
   d. 数码管/LED初始化(默认显示00:00,绿灯常亮);
   e. 变量初始化(默认模式:紫外线,时长:15分钟,状态:待机)。
2. 主循环:
   a. 按键扫描:检测模式/加/减/启停键,更新消毒模式/时长;
   b. 状态机处理:
      - 待机状态:响应按键,修改参数,数码管显示设定时长;
      - 运行状态:启动继电器,数码管倒计时,检测剩余时间;
      - 报警状态:人体闯入/故障,停止消毒,蜂鸣器报警,红灯闪烁;
   c. 倒计时更新:每秒刷新数码管显示;
   d. 状态LED更新:不同模式对应不同LED颜色(紫外-蓝,臭氧-绿,组合-紫);
3. 中断服务函数:
   a. INT0中断(PIR触发):立即停止消毒,进入报警状态;
   b. 定时器中断:1ms计时,实现秒级倒计时、按键消抖。

3. 核心代码示例(AVR C)

c

运行

复制代码
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

// 引脚定义
#define PIR_PIN     PD2    // INT0,PIR传感器
#define UV_RELAY    PD3    // 紫外线继电器
#define OZONE_RELAY PD4    // 臭氧继电器
#define BUZZER      PC6    // 蜂鸣器
// 数码管段选(a~g+dp):D5~D11对应PORTD5~D7 + PORTB0~B3
#define SEG_PORT_D  PORTD
#define SEG_PORT_B  PORTB
// 数码管位选:PC0~PC3
#define BIT_PORT    PORTC
// 按键引脚
#define KEY_MODE    PD12   // 模式键
#define KEY_ADD     PD13   // 加键
#define KEY_SUB     PC4    // 减键
#define KEY_START   PC5    // 启停键

// 全局变量
typedef enum {
  MODE_STANDBY,    // 待机
  MODE_UV,         // 紫外线消毒
  MODE_OZONE,      // 臭氧消毒
  MODE_COMBO,      // 组合消毒
  MODE_ALARM       // 报警
} WorkMode;

WorkMode currentMode = MODE_STANDBY;
uint16_t setTime = 15;    // 默认消毒时长(分钟)
uint16_t remainTime = 0;  // 剩余时间(秒)
bool isRunning = false;   // 运行状态
bool pirDetect = false;   // 人体感应标志

// 数码管段码表(共阴,0~9,带小数点)
uint8_t segCode[16] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};

// 延时函数(简易)
void delay_ms(uint16_t ms) {
  while(ms--) _delay_ms(1);
}

// 端口初始化
void port_init() {
  // 输出端口:继电器、蜂鸣器、数码管、LED
  DDRD |= (1<<UV_RELAY)|(1<<OZONE_RELAY)|0xF8; // D3-D4输出,D5-D7输出(段选)
  DDRB |= 0x0F; // B0-B3输出(段选)
  DDRC |= (1<<BUZZER)|0xFF; // PC0-PC7输出(位选+蜂鸣器+LED)
  // 输入端口:PIR、按键(上拉电阻)
  DDRD &= ~((1<<PIR_PIN)|(1<<KEY_MODE)|(1<<KEY_ADD));
  DDRC &= ~((1<<KEY_SUB)|(1<<KEY_START));
  PORTD |= (1<<PIR_PIN)|(1<<KEY_MODE)|(1<<KEY_ADD); // 上拉
  PORTC |= (1<<KEY_SUB)|(1<<KEY_START);             // 上拉
}

// 定时器初始化(1ms中断)
void timer_init() {
  TCCR0A = (1<<WGM01); // CTC模式
  TCCR0B = (1<<CS01)|(1<<CS00); // 64分频,16MHz→250KHz
  OCR0A = 249; // 250KHz / 250 = 1KHz → 1ms中断
  TIMSK0 = (1<<OCIE0A); // 使能比较匹配中断
  sei(); // 开启全局中断
}

// 外部中断初始化(INT0,PIR触发)
void interrupt_init() {
  EICRA = (1<<ISC01)|(1<<ISC00); // 上升沿触发(PIR检测到人时输出高电平)
  EIMSK = (1<<INT0); // 使能INT0中断
}

// 数码管显示函数(显示分钟:秒,如15→0015,5分30秒→0530)
void display(uint16_t time) {
  uint8_t min = time / 60;
  uint8_t sec = time % 60;
  uint8_t num[4] = {min/10, min%10, sec/10, sec%10};
  
  for(uint8_t i=0; i<4; i++) {
    // 段选输出
    SEG_PORT_D = (segCode[num[i]] & 0xE0) | (SEG_PORT_D & 0x1F); // D5-D7
    SEG_PORT_B = (segCode[num[i]] & 0x1F) | (SEG_PORT_B & 0xE0); // B0-B3
    // 位选输出(仅当前位亮)
    BIT_PORT &= ~0x0F;
    BIT_PORT |= (1<<i);
    delay_ms(1); // 消影延时
  }
  BIT_PORT &= ~0x0F; // 关闭所有位
}

// 按键扫描函数
void key_scan() {
  // 模式键
  if(!(PIND & (1<<KEY_MODE))) {
    delay_ms(20); // 消抖
    if(!(PIND & (1<<KEY_MODE))) {
      switch(currentMode) {
        case MODE_STANDBY: currentMode = MODE_UV; break;
        case MODE_UV: currentMode = MODE_OZONE; break;
        case MODE_OZONE: currentMode = MODE_COMBO; break;
        case MODE_COMBO: currentMode = MODE_STANDBY; break;
        default: currentMode = MODE_STANDBY;
      }
      while(!(PIND & (1<<KEY_MODE))); // 等待释放
    }
  }
  
  // 加键(时长+1分钟,最大60)
  if(!(PIND & (1<<KEY_ADD)) && currentMode == MODE_STANDBY) {
    delay_ms(20);
    if(!(PIND & (1<<KEY_ADD))) {
      setTime = (setTime + 1) % 61;
      if(setTime == 0) setTime = 1;
      while(!(PIND & (1<<KEY_ADD)));
    }
  }
  
  // 减键(时长-1分钟,最小1)
  if(!(PINC & (1<<KEY_SUB)) && currentMode == MODE_STANDBY) {
    delay_ms(20);
    if(!(PINC & (1<<KEY_SUB))) {
      setTime = (setTime - 1) % 61;
      if(setTime == 0) setTime = 60;
      while(!(PINC & (1<<KEY_SUB)));
    }
  }
  
  // 启停键
  if(!(PINC & (1<<KEY_START))) {
    delay_ms(20);
    if(!(PINC & (1<<KEY_START))) {
      isRunning = !isRunning;
      if(isRunning) {
        remainTime = setTime * 60; // 转换为秒
        // 根据模式启动继电器
        switch(currentMode) {
          case MODE_UV: PORTD |= (1<<UV_RELAY); break;
          case MODE_OZONE: PORTD |= (1<<OZONE_RELAY); break;
          case MODE_COMBO: PORTD |= (1<<UV_RELAY)|(1<<OZONE_RELAY); break;
          default: isRunning = false;
        }
      } else {
        // 停止所有继电器
        PORTD &= ~((1<<UV_RELAY)|(1<<OZONE_RELAY));
        remainTime = 0;
      }
      while(!(PINC & (1<<KEY_START)));
    }
  }
}

// 报警函数(蜂鸣器响+红灯闪烁)
void alarm() {
  PORTC |= (1<<PC7); // 红灯亮
  PORTC ^= (1<<BUZZER); // 蜂鸣器翻转
  delay_ms(200);
  PORTC &= ~(1<<PC7); // 红灯灭
  delay_ms(200);
}

// 外部中断服务函数(PIR检测到人)
ISR(INT0_vect) {
  if(isRunning) {
    currentMode = MODE_ALARM;
    isRunning = false;
    PORTD &= ~((1<<UV_RELAY)|(1<<OZONE_RELAY)); // 停止消毒
    pirDetect = true;
  }
}

// 定时器中断服务函数(1ms)
ISR(TIMER0_COMPA_vect) {
  static uint16_t cnt = 0;
  cnt++;
  if(cnt >= 1000) { // 1秒
    cnt = 0;
    if(isRunning && remainTime > 0) {
      remainTime--;
      // 倒计时结束
      if(remainTime == 0) {
        isRunning = false;
        PORTD &= ~((1<<UV_RELAY)|(1<<OZONE_RELAY));
        currentMode = MODE_STANDBY;
      }
    }
  }
}

// 主函数
int main(void) {
  port_init();
  timer_init();
  interrupt_init();
  
  while(1) {
    key_scan(); // 按键扫描
    
    switch(currentMode) {
      case MODE_STANDBY:
        PORTC |= (1<<PC0); // 绿灯亮
        display(setTime * 60); // 显示设定时长
        break;
      case MODE_UV:
        PORTC |= (1<<PC1); // 蓝灯亮
        if(isRunning) display(remainTime);
        else display(setTime * 60);
        break;
      case MODE_OZONE:
        PORTC |= (1<<PC2); // 绿灯亮
        if(isRunning) display(remainTime);
        else display(setTime * 60);
        break;
      case MODE_COMBO:
        PORTC |= (1<<PC1)|(1<<PC2); // 蓝+绿=紫灯亮
        if(isRunning) display(remainTime);
        else display(setTime * 60);
        break;
      case MODE_ALARM:
        alarm(); // 报警
        pirDetect = false;
        currentMode = MODE_STANDBY;
        break;
      default:
        currentMode = MODE_STANDBY;
    }
    
    // 清除LED(避免叠加)
    PORTC &= ~((1<<PC0)|(1<<PC1)|(1<<PC2));
  }
}

四、系统调试与优化

1. 硬件调试

  • 最小系统调试:烧录测试程序,验证晶振、复位、ISP 下载功能正常;
  • 传感器调试:用手靠近 PIR 传感器,检测 INT0 中断是否触发,确保 "有人即停";
  • 继电器调试:测试继电器吸合 / 断开是否正常,紫外灯 / 臭氧发生器能否可靠启停;
  • 数码管调试:校准显示精度,消除重影(增加消影延时),确保倒计时准确;
  • 电源调试:测试满载时电压稳定性,避免水泵 / 紫外灯启动时电压跌落。

2. 软件优化

  • 按键消抖:增加 20ms 消抖延时,避免误触发;
  • 倒计时精度:采用 16 位定时器(Timer1)替代 8 位定时器,提升计时准确性;
  • 异常处理:增加继电器粘连检测(通过反馈引脚),防止设备失控;
  • 低功耗优化:待机时关闭定时器以外的外设,降低功耗;
  • 报警逻辑:区分 "人体闯入" 和 "时长结束" 报警(不同蜂鸣频率)。

3. 安全验证

  • 人体感应响应时间:≤100ms,确保及时停止消毒;
  • 急停按键:按下后立即切断所有继电器,优先级最高;
  • 过流保护:保险丝在短路时及时熔断,防止火灾隐患;
  • 绝缘处理:220V/12V 电路隔离,避免触电风险。

五、功能扩展建议

  1. 蓝牙 / 红外遥控:增加 HC-05 蓝牙模块,支持手机 APP 远程设置时长 / 模式;
  2. 消毒记录存储:外接 AT24C02 EEPROM,记录每次消毒时长、时间;
  3. 环境适配:增加温湿度传感器(DHT11),根据湿度自动调整臭氧消毒时长;
  4. 语音提示:增加 SYN6288 语音模块,播报 "消毒开始 / 结束 / 有人闯入";
  5. 联网功能:替换为 ATMEGA168+ESP8266 组合,接入物联网平台,远程监控设备状态。

六、总结

本设计基于 ATMEGA168 单片机实现了消毒机的核心功能,硬件电路简洁可靠,软件逻辑兼顾实用性与安全性。通过人体感应防护、定时控制、多模式切换等设计,满足不同场景的消毒需求;同时具备易扩展、低成本的特点,可适配家庭、办公室、医院等多种场所的消毒应用。调试过程中需重点关注安全防护逻辑,确保紫外线 / 臭氧不会对人体造成伤害。

相关推荐
brave and determined10 天前
传感器学习(day04):红外感知:从经典热释电开关到智能时代的隐形慧眼
嵌入式硬件·算法·传感器·红外·嵌入式设计·红外矩阵·人体红外
CC呢5 个月前
基于单片机智能消毒柜设计
stm32·单片机·嵌入式硬件·消毒柜
岚叶2 年前
AVR 单片机 调试环境 JTAG MKII
单片机·avr·mkii
chinjinyu2 年前
ATtiny88初体验(七):TWI
oled·attiny88·avr·ssd1306·i2c/twi