MQ使用烟雾传感器
ADC的使用
转换电压和浓度
使用定时器
ADC的使用
利用mq2传感器检测气体,无非是利用传感器内部的电路和材料在不同的气体环境下具有不同的电阻值,通过收集电阻电压来检测相应气体浓度的变化。然后我们就可以用了ADC收集外部传感器的电压值,ADC将连续变量的模拟信号转换为离散的数字信号。ADC有些人不懂可以去详细了解一下,大佬们写得很好。 接下来是代码部分: 首先对io配置口,然后对ADC配置模式。
void Adc_Init()///初始化函数 {
GPIO_InitTypeDef GPIO_Initstructre; ADC_InitTypeDef ADC_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOARCC_APB2Periph_ADC1,ENABLE);//使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能io口 GPIO_Initstructre.GPIO_Mode=GPIO_Mode_AIN; GPIO_Initstructre.GPIO_Pin=GPIO_Pin_1; GPIO_Initstructre.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_Initstructre); GPIO_SetBits(GPIOA,GPIO_Pin_1); RCC_ADCCLKConfig(RCC_PCLK2_Div6);//保证不超过14M ADC_DeInit(ADC1);//复位ADC1 ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;//不能连续扫描 ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//数据右对齐 ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;///软件触发 ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;//独立模式 ADC_InitStruct.ADC_NbrOfChannel = 1; ADC_InitStruct.ADC_ScanConvMode = DISABLE;//不使用扫描模式 ADC_Init(ADC1,&ADC_InitStruct); ADC_Cmd(ADC1,ENABLE);//使能指定ADC1 ADC_ResetCalibration(ADC1);//使能复位校准
while(ADC_GetResetCalibrationStatus(ADC1));//等待复位校准结束
ADC_StartCalibration(ADC1);//开启AD校准
while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
}
然后是ADC电压采集的相关函数
u16 Get_Adc(u8 ch)
{
ADC_RegularChannelConfig(ADC1,ch,1,ADC_SampleTime_239Cycles5);//ADC1,通道1,配置采集周期
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件复位
while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));//状态发生改变
return ADC_GetConversionValue(ADC1);//返回值
}
利用上一个函数的返回值进一步进行数据计算
u16 Get_Adc_Average(u8 ch,u8 times)//两个入口参数,通道,取平均值的次数
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ch);
delay_ms(5);
}
return temp_val/times;
}
然后是对气体PPM的转换
void MQ2_cumlate(float RS)
{
R0 = RS / pow(CAL_PPM / 613.9f, 1 / -2.074f);
}
float MQ2_GetPPM(void)
{
u16 adcx;
adcx=Get_Adc_Average(ADC_Channel_1,30);//ADC1,取30次的平均值
float Vrl = 3.3f * adcx / 4096.f;//3.3v的参考电压,4096份
Vrl = ( (float)( (int)( (Vrl+0.005)*100 ) ) )/100;
float RS = (3.3f - Vrl) / Vrl * RL;
if(times<6) // 获取系统执行时间,3s前进行校准,用到了定时器
{
R0 = RS / pow(CAL_PPM / 613.9f, 1 / -2.074f);//校准R0
}
float ppm = 613.9f * pow(RS/R0, -2.074f);
return ppm;
}
接下来是定时器部分的代码,这一部分主要是为了上方用到的校准
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitSture;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//定时器3,时钟
TIM_TimeBaseInitSture.TIM_Period = arr;//自动装载值
TIM_TimeBaseInitSture.TIM_Prescaler = psc;//预分频系数
TIM_TimeBaseInitSture.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitSture.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitSture);//定时器3
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);//定时器3,更新中断,使能
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
TIM_Cmd(TIM3,ENABLE);
}
void TIM3_IRQHandler(void)//中断函数,0.5秒中断一次
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update) != RESET)//判断状态
{
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//清除中断待处理位
times++;
}
}
最后我们可以通过串口助手,或者显示屏幕将数据进行显示,MQ系列的传感器主要就是ADC和相应的浓度转换。
电压值转化部分参考了以下博主的代码😁
https://blog.csdn.net/qq_41422043/article/details/89138213?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-7&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-7
若有错误,请大家指出。😉😉😉