文章目录
需求
使用ADC将MQ2模块检测到的烟雾浓度模拟量转化为数字量。
最后,将实时检测的结果显示在串口上。
一、MQ-2 气体传感器
特点
广泛的探测范围,高灵敏度,快速响应恢复,优异的稳定性,寿命长以及简单的驱动电路。
应用
可用于家庭和工厂的气体泄漏监测装置, 适宜于液化气、丁烷、丙烷、甲烷、酒精、氢气、烟雾等的探测。
电路及引脚
二、实现流程
由于该模块的实现流程和ADC光照采集几乎一样,下面使用库函数的方式来编写。
1.开时钟,分频,配IO
该模块使用的引脚为PC1/ADC123_IN11,所以接下来我们要配置PC1。
烟雾检测模块是获得一个模拟量,所以接引脚模式配置为模拟输入。
代码如下:
c
//开时钟ADC1和PC
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC|RCC_APB2Periph_ADC1,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//配置GPIO口
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//MQ2
GPIO_Init(GPIOC, &GPIO_InitStructure);
2.配置ADC的工作模式
和光照检测一样,直接改成库函数就行。
代码如下(示例):
c
ADC_InitTypeDef ADC_InitStruct={0}; //
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;//ADC独立模式
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//选择软件SWSTART位触发
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;//连续还是单次模式
ADC_InitStruct.ADC_ScanConvMode = DISABLE;//关闭扫描
ADC_InitStruct.ADC_NbrOfChannel = 1;
ADC_Init(ADC1,&ADC_InitStruct);
ADC_Cmd(ADC1, ENABLE);
3.配置通道
这里使用库函数编写就很简单了,直接一个函数就解决了。
输入参数 1 ADCx:x 可以是 1 或者 2 来选择 ADC 外设 ADC1 或 ADC2
输入参数 2 ADC_Channel:被设置的 ADC 通道
输入参数 3 Rank:规则组采样顺序。取值范围 1 到 16。
输入参数 4 ADC_SampleTime:指定 ADC 通道的采样时间值
c
ADC_RegularChannelConfig(ADC1, ADC_Channel_11,1, ADC_SampleTime_239Cycles5);
4.复位,AD校准
没什么好说的,该部分可有可无,想严谨点的话就加上。
c
ADC_ResetCalibration(ADC1);//复位
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);//AD校准
while(ADC_GetCalibrationStatus(ADC1));
5.数值的获取
依旧是先转换一次,再while等待转换完成,最后读取打印。
c
void Get_Smoke_Value()
{
uint16_t Smoke=0;
//让规则通道转换一次
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
//ADC1->CR2 |= 0x01<<22;
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == 0)//判断寄存器的位2是不是等于1,是0就等待转换完成
{}
Smoke = ADC_GetConversionValue(ADC1); //读规则组通道数据寄存器
printf("烟雾浓度参数 = %d \r\n",Smoke);
return;
}
需求实现
关键代码如下:
main.c
c
#include "stm32f10x.h"
#include "usart.h"
#include "stdio.h"
#include "delay.h"
#include "string.h"
#include "pwm.h"
#include "adc.h"
int main()
{
NVIC_SetPriorityGrouping(5);//两位抢占两位次级
Usart1_Config();
SysTick_Config(72000);
RGBpwm_Config();
uint8_t cai_count=0;
uint16_t cont=0;
Adc_Config();
while(1)
{
if(ledcnt[0]>=ledcnt[1]){//过去500ms
ledcnt[0]=0;
Get_Smoke_Value();
}
}
return 0;
}
adc.c
c
#include "ADC.h"
//库函数
void Adc_Config(void)
{
//开时钟ADC1和PC,PA
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC|RCC_APB2Periph_ADC1,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//配置GPIO口
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//MQ2
GPIO_Init(GPIOC, &GPIO_InitStructure);
//配置ADC1
ADC_InitTypeDef ADC_InitStruct={0}; //
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;//ADC独立模式
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//选择软件SWSTART位触发
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;//连续还是单次模式
ADC_InitStruct.ADC_ScanConvMode = DISABLE;//关闭扫描
ADC_InitStruct.ADC_NbrOfChannel = 1;
ADC_Init(ADC1,&ADC_InitStruct);
ADC_Cmd(ADC1, ENABLE);
//配置通道
ADC_RegularChannelConfig(ADC1, ADC_Channel_11,1, ADC_SampleTime_239Cycles5);
//校准
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
void Get_Smoke_Value()
{
uint16_t Smoke=0;
//让规则通道转换一次
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
//ADC1->CR2 |= 0x01<<22;
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == 0)//判断寄存器的位2是不是等于1,是0就等待转换完成
{}
Smoke = ADC_GetConversionValue(ADC1); //读规则组通道数据寄存器
printf("烟雾浓度参数 = %d \r\n",Smoke);
return;
}
adc.h
c
#ifndef _ADC_H_
#define _ADC_H_
#include "stm32f10x.h"
#include "stdio.h"
void Get_Smoke_Value();
void Adc_Config(void);
#endif
总结
大致流程和ADC光照采集差别不大,照着一步一步做就能实现。