ESP32移植Openharmony外设篇(8)MQ-3酒精检测传感器
MQ-3酒精检测
模块简介
应用场景
MQ3是MQ传感器系列中最常用的传感器之一。它是金属氧化物半导体(MOS)类型的传感器。金属氧化物传感器也被称为化学电阻在暴露于醇,因为感测基于所述感测材料的电阻的变化。因此,通过将其放置在简单的分压器网络中,可以检测到酒精浓度。
MQ3酒精传感器可在5V直流电压下工作,功耗约800mW。它可以检测25至500 ppm范围内的酒精浓度。
1 ppm等于多少?
在测量气体时,术语“浓度”用来描述空气中气体的体积含量。两种最常见的度量单位是百万分之一和浓度百分比。
百万分之一(缩写为ppm)是一种气体与另一种气体的比率。例如,500ppm的酒精意味着如果您可以计算一百万个气体分子,则其中500个是酒精,而999500个分子则是其他一些气体。
产品规格
工作电压 | 5伏 |
负载电阻 | 200KΩ |
加热器电阻 | 33Ω±5% |
加热消耗 | <800MW |
感应电阻 | 1MΩ– 8MΩ |
浓度范围 | 25 – 500 ppm |
预热时间 | 不少于24小时 |
工作原理
当在高温下加热SnO2半导体层时,氧吸附在表面上。在干净的空气中,来自二氧化锡导带的电子被氧分子吸引。这在SnO2颗粒的表面正下方形成电子耗尽层,并形成势垒。结果,SnO2膜变得高电阻并且防止电流流动。
但是,在存在酒精的情况下,吸附的氧的表面密度会随着与酒精的反应而降低;这降低了潜在的障碍。然后,电子释放到二氧化锡中,使电流自由流过传感器。
原理图
参考代码
BUILD.gn
# Copyright (c) 2022 Hunan OpenValley Digital Industry Development Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//kernel/liteos_m/liteos.gni")
module_name = get_path_info(rebase_path("."), "name")
kernel_module(module_name){
sources = [
"adc_jj_example.c",
]
include_dirs = [
"//drivers/hdf_core/framework/include/platform/",
"//drivers/hdf_core/framework/include/utils/",
"//drivers/hdf_core/framework/support/platform/include/adc",
"//drivers/hdf_core/adapter/khdf/liteos_m/osal/include/",
"//drivers/hdf_core/framework/include/core/",
"//drivers/hdf_core/framework/include/osal/",
"//drivers/hdf_core/interfaces/inner_api/utils",
"//device/soc/esp/esp32/components/driver/include",
"//device/soc/esp/esp32/components/esp_adc_cal/include",
"//device/soc/esp/esp32/components/driver/esp32/include",
]
}
adc_jj_example.c
/*
* Copyright (c) 2022 Hunan OpenValley Digital Industry Development Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include "cmsis_os2.h"
#include "ohos_run.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "esp_adc_cal.h"
#define SYS_DELAY_TICKS 200
#define TASK_STACK_SIZE 4096
#define TASK_PRIO 25
#define DEFAULT_VREF 3300 // 默认参考电压,单位mV
static esp_adc_cal_characteristics_t *adc_chars;
#define myADC_heat_sensitive_channel ADC_CHANNEL_9 // 通道9 酒精传感器Ao输出
#define AD_Value1_Channnel myADC_heat_sensitive_channel // 重新定义一个, 为例后续更好的更改
#define width ADC_WIDTH_BIT_12 // ADC分辨率 12位
#define atten ADC_ATTEN_DB_11 // ADC衰减 11 dB 衰减,输入电压范围为 0-3.3V。
#define unit ADC_UNIT_2 // ADC2
#define NO_OF_SAMPLES 128 // 采样次数, 目的: 多次采样, 滤波
/**
* @description: ADC初始化
* @return {无}
*/
void myADC_Init()
{
adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t)); // 分配内存
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, width, DEFAULT_VREF, adc_chars);
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP)
{
printf("eFuse Two Point: %d\n", val_type);
}
else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF)
{
printf("eFuse Vref: %d\n", val_type);
}
else
{
printf("Default Vref: %d\n", val_type);
}
// 配置ADC2通道
adc2_config_channel_atten((adc2_channel_t)AD_Value1_Channnel, atten);
}
/**
* @description: 获取传感器的AD值和电压值
* @param {int16_t} *AD_Value1 第一个传感器的AD值的地址
* @param {float*} Voltage1 第一个传感器的电压值的地址
* @return {*}
*/
void myADC_GetAdAndVoltage_Value(int16_t *AD_Value1, float *Voltage1)
{
uint32_t adc_reading1 = 0;
for (int i = 0; i < NO_OF_SAMPLES; i++)
{ // 多次采样, 滤波
int raw;
if (adc2_get_raw((adc2_channel_t)AD_Value1_Channnel, width, &raw) == ESP_OK)
{
adc_reading1 += raw; // 采集电压值
}
}
adc_reading1 /= NO_OF_SAMPLES; // 得到滤波后的数据
// esp_adc_cal_raw_to_voltage返回的是mV, 想得到单位V, 除以1000
*AD_Value1 = (int16_t)adc_reading1; // 转换为int16_t类型
*Voltage1 = esp_adc_cal_raw_to_voltage(adc_reading1, adc_chars) / 1000.0; // 获取电压值
}
int16_t light_AdVal;
float light_Voltage;
static void gpio_test(void)
{
myADC_Init();
while (1)
{
myADC_GetAdAndVoltage_Value(&light_AdVal, &light_Voltage);
printf("gz adc cal: %d\t gz v: %.2f \n", light_AdVal, light_Voltage);
sleep(2); // 延时
}
}
static void gpio_example_task(void)
{
osThreadAttr_t attr;
int g_taskID;
attr.name = "adc_test";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = TASK_STACK_SIZE;
attr.priority = TASK_PRIO;
g_taskID = osThreadNew((osThreadFunc_t)gpio_test, NULL, &attr);
if (g_taskID == NULL)
{
printf("Failed to create Test GPIO thread!\n");
}
}
OHOS_APP_RUN(gpio_example_task);
注意这里的酒精模块使用到的模数转换器是ESP32的adc2,当使用adc2时不能使用WIFI功能,如果需要使用WIFI可以修改所连接的GPIO口,具体可以参考:GPIO & RTC GPIO - ESP32 - — ESP-IDF 编程指南 v5.2.4 文档
编译并烧录
在源码根目录下使用hb工具对写好的代码进行编译
选择mini级系统
同理 产品选择esp公司下的esp32
选择完毕后在源码根目录下执行hb build -f 进行编译
编译完成后会有如下界面,并且编译后的代码固件位于:out\esp32\esp32
实验现象
按下ESP32开发板上的EN键,即可观察到实验现象:
从模块的工作原理来看,随着酒精的浓度上升,吸附氧的表面密度会随着酒精与酒精反应而降低,从而降低势垒。 这样,电子被释放到二氧化锡中,允许电流自由流过传感器。电压应该变大才对,可这里为什么电压反而变小了呢?
实际上这要从原理图来解释:
MQ3传感器(U8)与一个运算放大器(LM393,U9A)相连。传感器的输出通过电阻R46和电容C32进行滤波后,连接到运算放大器的反相输入端。运算放大器的同相输入端通过电阻R47接地。
当空气中没有酒精时,传感器的电阻较高,因此流过R46的电流较小,导致运算放大器反相输入端的电压较低。此时,运算放大器的输出为高电平,红灯D16亮起。
当空气中存在酒精时,传感器的电阻降低,流过R46的电流增大,导致运算放大器反相输入端的电压升高。如果这个电压超过运算放大器同相输入端的电压(即地电位),运算放大器的输出将变为低电平,红灯D16熄灭。
因此,读取到对应的ADC引脚的电压会变低,这实际上是指运算放大器的输出电压变低,而不是传感器本身的电压变低。这是因为传感器电阻的降低导致了运算放大器反相输入端电压的升高,进而使运算放大器的输出电压变低。
总结来说,当MQ3酒精传感器检测到酒精时,其电阻降低,导致运算放大器反相输入端电压升高,从而使运算放大器输出电压变低,最终表现为ADC读取的电压变低!