
简介这是一份面向51单片机初学者与嵌入式系统爱好者的燃气检测Proteus仿真设计资源以智能气表LCD流量控制场景为切入点完整演示了从传感器信号采集、ADC转换、浓度判断到LED/蜂鸣器报警输出的典型流程也适合电子竞赛或课程设计参考。压缩包共33个文件约289KB主要包含Proteus仿真工程dsn、C语言源程序c/h、编译生成的hex、调试辅助的lst/m51/obj及Keil工程文件uvproj/uvopt基本覆盖了从源代码编写、编译烧录到仿真验证的完整工具链目录中还可看到“LCD流量控制”“脉冲”“智能气表”等设计模块。目前已有173人学习下载适合希望快速理解51单片机燃气检测系统工作原理、掌握Proteus硬件仿真调试方法的读者。通过查看源程序与仿真文件能够直观学习传感器数据采集逻辑、阈值比较与报警控制实现并结合示例工程练习Keil与Proteus的联调操作对提升嵌入式系统设计能力有明显帮助。1. 燃气检测仿真卡在哪Proteus模型和单片机程序的配对做燃气检测类课程设计时大部分人不是被C语言难住的而是被“仿真做不出来”卡住。标题里的四个要素要分开看51单片机是控制核心燃气检测是传感端需求Proteus是交付载体源程序和仿真文件是评分直接看的对象。这类设计放到Proteus里跑真正的技术难点在于传感器模型缺失、AD转换时序对不上、报警逻辑没法直观验证。网上能搜到的教程大多只给一份源码但实际把hex文件烧进仿真图后数码管乱码、EOC不翻转、读数恒为0xFF的情况比比皆是。这篇文章按一个可复现的完整方案来讲MQ-2传感器怎么等效进ProteusADC0809怎么和51单片机握手报警阈值怎么调最后怎么把源程序与仿真文件整理成一套能交差的工程。2. 燃气检测与51单片机之间为什么要插一个ADC08092.1 MQ-2气敏传感器的输出特性曲线燃气检测最常见的传感器型号是MQ-2。它的核心是二氧化锡半导体材料内部带一根加热丝通电后把敏感层加热到工作温度。清洁空气中敏感层表面吸附氧分子载流子浓度低等效电阻很高当甲烷、丙烷、液化气等还原性气体出现在传感器表面时氧解吸释放电子材料电导率上升等效电阻RS明显下降。典型接法是把传感器和负载电阻RL串联分压Uout VCC x RL / (RS RL)洁净空气中RS约为几十千欧Uout接近0V浓度升高时RS降到几千欧Uout上升。这个输出是模拟电压范围大概在0到4V之间跟浓度是非线性曲线。51单片机内部没有ADC所以要么外接ADC芯片采样电压值要么用比较器把它变成高低电平触发报警。做分级浓度显示时ADC方案明显更合适。2.2 三种信号接入51单片机的方式对比比较器方案用LM393把Uout和电位器设定的阈值电压比较输出数字电平直接进IO口。成本最低但只能告诉你“有没有超标”给不出浓度趋势。ADC0832方案串行接口ADC占用2根IO速度快但Proteus里调试SPI时序对新手不友好。ADC0809方案8路模拟输入8位并行输出接口直观Proteus元件库里自带模型网上可参考的例程最多。本设计选ADC0809理由很简单Proteus仿真里并行接口的引脚状态一目了然适合边仿真边理解转换时序。8位分辨率在5V基准下每个LSB约19.5mV对应MQ-2的输出范围做三档浓度划分完全够用。2.3 MQ-2在Proteus元件库里的等效替代在Proteus元件库里搜“MQ-2”通常找不到可直接用的气体传感器模型。这不是你的库缺元件而是这类半导体气敏传感器本身没有仿真模型。常见的等效做法是用电位器POT-HG充当可变分压器手动调节输出电压模拟气体浓度变化。更接近真实特性一点的做法是保留分压结构把一个普通电阻作为RL另一个电位器作为RS电位器调小时Uout升高和MQ-2的电阻下降趋势一致。参数推荐值说明加热电压VH5V直流仿真中直接接电源检测回路电压VC5V直流与单片机共地负载电阻RL4.7k到10k可调决定Uout静态工作点电位器(模拟RS)10k调节范围覆盖清洁空气到泄漏状态ADC参考电压VCC5VVREF接VCCVREF-接地实际做硬件时RL的选择要参考MQ-2数据手册里的灵敏度曲线仿真阶段用电位器手调浓度不需要精确匹配电阻值。这里要注意电位器三个引脚别接错中间抽头输出到ADC0809的IN0其余两端分别接VCC和GND。2.4 ADC0809和51单片机的引脚对接规划我比较常用的分配方式是把P1口整个作为ADC0809的数据总线通道选择用P2的低三位控制信号走P3口信号接单片机引脚D0-D7P1.0-P1.7A/B/C通道选择P2.0-P2.2STARTP3.0OEP3.1EOCP3.2蜂鸣器P3.3LCD数据口P0.0-P0.7LCD控制口P2.3-P2.5LED指示P3.5-P3.7这样分配的好处是数据总线独占一个口写代码时直接用P1 ADC_DATA读取时序不容易错位。ADC0809的CLK时钟信号可以用Proteus里的DCLOCK信号源直接供给也可以让51单片机的定时器T0产生方波两种方式都行细节放在下一章程序里说。3. 51单片机源程序怎么写ADC0809驱动与三级报警逻辑3.1 用定时器T0给ADC0809提供CLKADC0809工作时必须有时钟信号典型范围10kHz到1.2MHz。Proteus仿真里最简单的方式是放一个DCLOCK时钟源频率设为500kHz输出端接到ADC0809的CLK引脚。如果手上没有DCLOCK或者老师要求“纯单片机电路”就用定时器T0工作在方式2把机器周期分频后从P3.4引脚送出去。以12MHz晶振为例机器周期是1usT0输出500kHz方波的初始化代码如下void Timer0_Init(void) { TMOD 0xF0; // 保留T1的配置 TMOD | 0x02; // T0方式28位自动重装 TH0 0xFE; // 初值产生500kHz方波 TL0 0xFE; ET0 1; // 开T0中断 TR0 1; // 启动T0 } void Timer0_ISR(void) interrupt 1 { // 方式2自动重装不需要重新赋初值 // 对P3.4取反即可得到方波 T0_PIN !T0_PIN; }使用定时器输出时钟时ADC0809的CLK引脚直接连P3.4不需要外部信号源。但要注意方式2重装后第一次进中断的时间比后续周期多一个机器周期仿真中这个误差可以忽略。我一般更推荐DCLOCK方案程序少一个中断源后续调EOC时序时变量更少。3.2 ADC0809转换时序的代码实现ADC0809的转换流程是拉低START设置通道地址拉高START再拉低START触发转换等待EOC由低变高表示转换完成最后拉高OE读取数据。驱动函数如下unsigned char ADC0809_Read(unsigned char ch) { unsigned char val; ADC_A ch 0x01; // 通道选择低三位有效 ADC_B (ch 1) 0x01; ADC_C (ch 2) 0x01; START 0; _nop_(); START 1; // 启动脉冲上升沿 _nop_(); START 0; // 下降沿开始转换 while (EOC 0); // 等待转换结束EOC变高 OE 1; // 打开输出使能 _nop_(); val ADC_DATA; // P1口读取8位转换结果 OE 0; // 关闭输出使能 return val; }这里有个关键细节EOC信号在转换过程中保持低电平转换完成后变为高电平所以while(EOC 0)可以可靠等待。读取数据时OE为高电平期间ADC0809把内部8位锁存器推送到数据总线上单片机直接从P1口取数。最后一次OE必须拉低否则下一次转换时数据总线一直被占用。3.3 连续采样加均值滤波燃气传感器输出有波动单片机上电瞬间ADC读数也会跳变直接拿单次采样值做阈值判断容易出现误报警。我一般做8次连续采样取平均值unsigned char ADC_Read_Filter(void) { unsigned char i; unsigned int sum 0; for (i 0; i 8; i) { sum ADC0809_Read(0); // 固定采样IN0通道 } return (unsigned char)(sum 3); // 右移3位相当于除以8 }滤波之后再做阈值判断稳定性和源程序的健壮性都会好一些。这里选择的IN0通道对应电位器抽头Proteus里调节电位器时ADC值会连续变化。3.4 三档报警阈值与执行动作我一般把8位ADC值按浓度分成三档正常状态绿灯常亮预警状态黄灯慢闪、蜂鸣器间歇鸣叫报警状态红灯快闪、蜂鸣器连续响。阈值变量用宏定义方便课程设计答辩时临时改参数#define TH_WARN 80 // 0.8V左右根据VREF5V换算 #define TH_ALARM 160 // 1.6V左右视为泄漏报警 void Alarm_Handle(unsigned char conc) { if (conc TH_WARN) // 安全区 { LED_SAFE 1; LED_WARN 0; LED_ALARM 0; BEEP 0; } else if (conc TH_ALARM) // 预警区 { LED_SAFE 0; LED_WARN !LED_WARN; // 慢闪效果 LED_ALARM 0; BEEP (millis % 500 100); // 每500ms响100ms } else // 报警区 { LED_SAFE 0; LED_WARN 0; LED_ALARM 1; BEEP 1; // 持续报警 } }这里LED指示灯用了LED_WARN !LED_WARN产生闪烁效果实际源程序里要配合延时或定时器中断让主循环周期稳定。阈值换算逻辑是5V对应ADC值255所以0.8V对应2550.8/540 不对80对应0.8V 阈值向下取整。我这段代码里的注释“0.8V左右”如果按2550.8/540.8其实TH_WARN80对应1.57V。需要修正。重新计算VREF5V8位ADCLSB19.6mV。浓度分级对应电压正常Uout 0.6V对应ADC值31预警0.6V-1.5V对应ADC值31-76报警1.5V对应ADC值76为了演示效果好把阈值放宽一点TH_WARN60约1.18VTH_ALARM120约2.35V。这个分级在仿真里配合电位器好操作不至于滑几度就报警。实际产品阈值要按MQ-2在目标气体浓度下的输出电压标定仿真阶段阈值的主要作用是演示逻辑。主循环里每50ms读一次浓度并刷新状态void main(void) { unsigned char concentration; LCD_Init(); // 1602初始化 Timer0_Init(); // 若用定时器输出CLK则调用 while (1) { concentration ADC_Read_Filter(); // 8次均值 LCD_Show_Concentration(concentration); Alarm_Handle(concentration); Delay50ms(); } }LCD1602的驱动代码属于标准外设源程序里直接复用平时写好的显示驱动函数即可本节不再重复贴完整代码重点在ADC和报警逻辑的配合。4. Proteus仿真文件搭建元件摆放、连线和hex加载4.1 元器件清单与Proteus元件库搜索关键词Proteus 8 Professional的元件库里搜索关键词和实际元件不完全同名列一份常用对照表方便直接查元件Proteus里的搜索关键词数量单片机AT89C51 或 AT89C521ADC转换器ADC08091气敏传感器替代POT-HG电位器1液晶屏LM016L字符液晶1排阻RESPACK-81蜂鸣器BUZZER1LEDLED-RED / LED-YELLOW / LED-GREEN各1晶振CRYSTAL12MHz1电容CAP 30pF x2CAP-ELEC 10uF各2、1电阻RES 100R / 10k若干POT-HG在Proteus元件库里的名称就是POT-HG也可以用RES可变电阻替代。注意数码管在这个设计里不用显示功能交给LM016L液晶评分时显示实时浓度更直观。4.2 仿真原理图连线顺序先把AT89C51放中间P1口整体向右引出8根线给ADC0809的D0-D7。ADC0809的IN0接电位器中间抽头电位器两端分别接5V和GND这样旋转电位器就能模拟燃气浓度从低到高。ADC0809的VREF接5VVREF-接地CLK引脚接一个DCLOCK信号源频率设500kHz。单片机P0口接RESPACK-8排阻排阻另一端接VCC用于上拉P0口。P0口再接LM016L的D0-D7P2.3接RSP2.4接RWP2.5接E。蜂鸣器一端接VCC另一端串一个100欧限流电阻接P3.3。三个LED分别接P3.5、P3.6、P3.7注意LED的正极接单片机引脚负极接GND这样引脚输出高电平时LED点亮逻辑和代码一致。STOP我上面3.4里LED_SAFE1点亮那LED接法要匹配LED正极接P3.5负极接GND输出1时点亮。代码里正常状态下LED_SAFE1符合。4.3 Keil源程序编译与hex烧录步骤Keil uVision5里建立新工程时芯片型号选Atmel下的AT89C52勾选生成hex文件。编译通过后在Proteus里双击AT89C51元件弹窗里找到Program File项点击文件夹图标选择Keil Output目录下的.hex文件。晶振频率要同步设置如果原理图上用的是12MHz晶振单片机属性里的Clock Frequency默认是12MHz这里能对应上就正常。仿真文件组织我习惯分三个目录“Proteus工程”放.pdsprj文件“Source”放Keil工程和.c文件“Doc”放课程设计说明书。答辩时老师要源程序和仿真文件直接整目录拷走就能跑比单独丢一个hex文件规范得多。4.4 初次仿真验证的观察点点击右下角的Play按钮后第一眼应该看ADC0809的EOC引脚波形。EOC从低到高跳变一次代表一次转换完成。如果EOC纹丝不动优先检查CLK信号。然后在LCD屏上应该看到字符显示“GAS: 001”之类的浓度值调节电位器POT-HG时数值连续变化超过阈值后LED和蜂鸣器状态切换。拧电位器的时候一只手按住键盘上的A键可以快速增加阻值按住D键减小每次按一下变化1%。要快速滑到报警区间直接按住A键不放几秒钟就能看到浓度从20跳到140报警灯亮起。这个操作手感比拿鼠标拖电位器方便很多。5. 仿真调试ADC0809的EOC不翻转和读数恒定怎么办5.1 EOC一直为低电平的检查路径EOC是ADC0809的转换结束信号仿真中这个引脚如果始终不跳高按下面顺序排查检查CLK引脚是否有方波输入。用示波器探针点CLK没有波形说明DCLOCK频率设置不对或者引脚没连上。检查START脉冲是否真的送达。单片机的P3.0如果初始化时默认输出高电平需要先在程序里给START0再进入转换流程。我的源程序里每次读ADC前都会把START拉低避免悬空电平干扰。检查程序是否跑起来了在Keil里全速运行Proteus里看P1.0引脚有没有电平变化。如果整个程序卡在某个while循环里EOC自然不会有反应。5.2 读数恒为0xFF或0x00的典型原因读数恒为0xFF大概率是P1口外部没有拉低信号的驱动能力问题。Proteus里P0口是开漏结构但P1口有内部上拉如果数据总线悬空读回的值是所有位为1也就是0xFF。把ADC0809的D0-D7全部接到P1口如果某根线没连上该位就保持高电平。另一种情况是OE没拉高就开始读数据数据总线上是高阻状态。读数恒为0通常是ADC0809的VREF上下限问题。VREF和VREF-不能悬空VREF接VCC后电位器抽头电压才能被正确量化。还有检查IN0通道选择A/B/C三根线都接低电平选择IN0如果C引脚悬空被上拉成高电平实际采样的可能就是IN4通道而IN4没接任何东西读数要么0要么跳变。5.3 用Proteus虚拟示波器看ADC时序Proteus里有简易示波器点右边的工具栏找到“VSINE”不是我指的是Virtual Instruments面板里的“OSCILLOSCOPE”。把示波器的A通道接EOCB通道接CLK运行仿真后可以看到两路波形。正常情况是CLK连续方波转换期间EOC为低转换结束后EOC拉高形成一个周期性的负脉冲。这个波形图上能直接判断START脉冲宽度是否太短。如果EOC的负脉冲宽度远远大于一个CLK周期说明START没有正确触发转换程序里需要在START1之后加几个_nop_()让脉冲宽度不小于2个CLK周期。5.4 仿真专属的“浓度”调节技巧用鼠标左键点一下POT-HG然后按键盘A或D键微调阻值。A增加D减少每按一次变化1%。想快速跳变就长按A不放。如果老师演示时要求看到“浓度上升导致报警”的连贯过程先把电位器调到10%再演示长按A键画面里液晶数值连续上涨这是答辩时最直观的效果。POT-HG两端的接法决定旋转方向对应浓度增大还是减小如果反过来把电位器上下两个固定端交换即可。6. 进阶串口上报浓度和继电器联动排气扇上面的方案已经能覆盖燃气检测报警的全部流程但课程设计要想拉开分差通常加两个功能一是串口把浓度值发到Proteus虚拟终端二是继电器联动排风扇。先说串口51单片机的UART引脚是P3.0和P3.1波特率用4800或9600初始化时把SCON置为0x50定时器T1做波特率发生器void UART_Init(void) { SCON 0x50; // 串口方式1允许接收 TMOD 0x0F; TMOD | 0x20; // T1方式2 TH1 0xFA; // 9600波特率12MHz晶振 TL1 0xFA; TR1 1; TI 0; } void UART_SendByte(unsigned char dat) { SBUF dat; while (TI 0); TI 0; }Proteus里放置VIRTUAL TERMINALRX引脚接单片机的TXD引脚TX接RXD两个设备交叉相连并共地。程序里在每次更新浓度值后把ADC值转换成十六进制字符发送虚拟终端窗口里就能看到数据滚动输出。继电器联动排气扇的可做性更强在Proteus元件库里放一个RELAY模型线圈一端接VCC另一端接NPN三极管的集电极发射极接地基极串电阻接P2.6。代码里阈值越过TH_ALARM时给P2.6置1继电器吸合常开触点接一个直流电机模拟排风扇转动。注意如果在Proteus里直接放RELAY线圈两端要并联一个反向二极管否则断电瞬间的感生电动势会让模型报错。很多教程原型图里没画这个二极管仿真也能跑但实际硬件电路里必须有。最后给你一个答辩现场的演示脚本开机先展示安全状态LCD显示浓度值小于60绿色LED亮按住A键把电位器阻值拉高LCD数值跳到130以上红色LED亮蜂鸣器持续响继电器吸合电机开始转松开A键慢慢调回去系统自动恢复到安全状态。整个过程不需要重新烧写程序单靠源程序里的阈值宏定义和Proteus工程文件就能完整展示闭环逻辑。把这套源程序和仿真文件按第四章的分类文件夹整理好拷到U盘里就能直接打开运行。本文还有配套的精品资源点击获取