STM32第七课:KQM6600空气质量传感器

文章目录

  • 需求
  • 一、KQM6600模块及接线方法
  • 二、模块配置流程
    • 1.环境
    • 2.配置时钟和IO
    • 3.配置串口初始化,使能以及中断
    • 4.中断函数
  • 三、数据处理
  • 四、关键代码
  • 总结


需求

能够在串口实时显示当前的VOC(挥发性有机化合物),甲醛和Co2浓度。
在这里插入图片描述


一、KQM6600模块及接线方法

KQM6600TAUs型空气质量检测模块,使用MEMS VOC传感器件作为检测空气中有机化合物气体(VOC)的模块。UART通信数据输出,根据VOC数据计算和等效甲醛,CO2输出。其具有体积小,功耗低,灵敏度高,响应速度快等居多优点,广泛应用在空气质量检
测及控制领域。
在这里插入图片描述
要注意该模块的电压和波特率。
在这里插入图片描述
由官方的说明书可知,只需在将该模块的(V)供电,(A)TX和(G)GND三个引脚接到板子上即可。
在这里插入图片描述
本次例程由于没有使用SD卡模块,所以选择将KQM6600模块的数据传输到UART4上,只需将该模块的A(TX)接到PC11即可。

二、模块配置流程

1.环境

1.首先要保证串口1能够将接收到的实时数据发送到串口上。
2.还要对printf进行重定向,让其能够打印到串口上。(详情见STM32第三课:串口调试)
代码如下:
usart.c

#include "usart.h"
#include "stdio.h"

void Usart1_Config()
{
	  //开时钟:GPIOA,USART1
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);
	  //配置对应的IO口 PA9(tx):复用推挽 PA10(RX):浮空输入
	    GPIO_InitTypeDef GPIO_InitStruct = {0};
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOA,&GPIO_InitStruct);
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
		GPIO_Init(GPIOA,&GPIO_InitStruct);
	  //配置串口1    8数据位,0校验位,1停止位,波特率115200
		USART_InitTypeDef USART_InitStruct = {0};//可以通过结构体类型跳转
		USART_InitStruct.USART_BaudRate = 115200;//波特率
		USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件控制流不开
		USART_InitStruct.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;//打开发送和接收
		USART_InitStruct.USART_Parity = USART_Parity_No;
		USART_InitStruct.USART_StopBits = USART_StopBits_1;
		USART_InitStruct.USART_WordLength = USART_WordLength_8b;
		USART_Init(USART1,&USART_InitStruct);
		USART_Cmd(USART1,ENABLE);
  //配置串口1的中断
	//在串口1产生接收的时候,会产生中断,我们直接去中断函数里面处理就可以了
	//选择串口1的中断原因
    USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//USART1->CR1 |= 0x1<<5;//使能串口1的接收非空中断
	NVIC_SetPriority(USART1_IRQn,7);//设置优先级0~15
	NVIC_EnableIRQ(USART1_IRQn);//使能中断通道
}

void SendData(uint8_t data)
{
	while((USART1->SR&0x01<<6)==0){}//等待上次发送完成
	USART1->DR = data;//发送数据
}

int fputc(int ch, FILE *f)
{
	//printf函数最终会跳转到这里来运行
	while((USART1->SR&0x1<<6)==0);
	//发送数据
	USART1->DR = (uint8_t)ch;
  return ch;
}


void USART1_IRQHandler(void)
{
	uint8_t data=0;
	if((USART1->SR&0x1<<5)!=0)
	{//执行该中断函数的原因有很多,所以判断一下是不是接收导致的
		//接收数据
		data = USART_ReceiveData(USART1);//读操作,同时也是清空中断标志位
		USART_SendData(USART1, data); 
	}
}

usart.h

#ifndef _USART_H_
#define _USART_H_
#include "stm32f10x.h"
#include "stdio.h"

void Usart1_Config();
void SendData(uint8_t data);
int fputc(int ch, FILE *f);


#endif
		

2.配置时钟和IO

首先创建一个kqm.c.h文件用来专门配置该模块
和串口1一样,只不过要注意此时是UART4,引脚为PC11。

	//开时钟 U4 PC11RX
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	 RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE);
	//配置io
	    GPIO_InitTypeDef GPIO_InitStruct = {0};
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	 	GPIO_Init(GPIOC,&GPIO_InitStruct);

3.配置串口初始化,使能以及中断

在这里插入图片描述
初始化要将波特率改为9600,然后只用打开接收就行,其他与串口1一样。
使能就不说了,改个参数就行。
中断也一样,只用改改参数。

	//配置串口  波特率9600 数据位8,校验位0,停止位1
		USART_InitTypeDef USART_InitStruct = {0};//可以通过结构体类型跳转
		USART_InitStruct.USART_BaudRate = 9600;//波特率
		USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件控制流不开
		USART_InitStruct.USART_Mode = USART_Mode_Rx;//打开接收
		USART_InitStruct.USART_Parity = USART_Parity_No;
		USART_InitStruct.USART_StopBits = USART_StopBits_1;
		USART_InitStruct.USART_WordLength = USART_WordLength_8b;
		USART_Init(UART4,&USART_InitStruct);
	//使能串口
		USART_Cmd(UART4,ENABLE);
	//配置串口4的中断(采用中断接收)
      USART_ITConfig(UART4,USART_IT_RXNE,ENABLE);//使能串口4	的接收非空中断
	  USART_ITConfig(UART4,USART_IT_IDLE,ENABLE);//总线空闲中断
	  NVIC_SetPriority(UART4_IRQn,7);//设置优先级0~15
	  NVIC_EnableIRQ(UART4_IRQn);//使能中断通道

4.中断函数

依旧是先去启动文件中找到该串口的中断函数复制过来。
然后使用USART_GetITStatus函数进行标志位判断,若为1则代表传输完成。
由于数据位为8位所以此时需要定义一个数组来存放这8位数组。
还需要定义一个参数来计数,每当存放够8位时,清0,再从头开始覆盖存入数据。此刻就完成了8位数据获取。

	uint8_t data=0;
	//判断接收中断是否发生
	if(USART_GetITStatus(UART4,USART_IT_RXNE)==SET)
	{
		data = UART4->DR;
		u4recive[u4count]=data;
		u4count++;
		u4count%=8;
		
		//USART1->DR = data;//回显
	}

为了判断该模块是否传输完数据,此时我们要使用一个新的知识:中断空闲
USART_GetITStatus(UART4,USART_IT_IDLE)
当结尾时IDLE时就代表此时判断的是中断空闲。
当中断空闲被置为1时,就代表示总线空闲,8位数据传完了,接收完毕。此时想要清理中断空闲的话,需要先读SR再读DR。
然后在设置一个标志位u4flag,将其置为1代表接收完毕。

	//触发空闲中断,表示总线空闲,接收完毕
	if(USART_GetITStatus(UART4,USART_IT_IDLE)==SET)
	{
		data = UART4->SR;//清理空闲中断,先读SR再读DR
		data = UART4->DR;
		u4flag=1;
	}

三、数据处理

先判断标志位u4flag是否为0,若为0这直接退出,不进入数据处理函数。
在这里插入图片描述
由手册可知,该模块有预热操作,为了屏蔽掉预热操作的数据,此时需要判断传输过来的8位数组,检查是否每位都为0xff,只要有一位不是就继续进行,否则向串口打印‘数据预热’。

	if(u4flag==0)
	{
		return 0;
	}
	u4flag=0;
	 for(i=1;i<7;i++)
	{
		if(u4recive[i]!=0xff)
		{
			break;
		}
	}
	if(i==7)
	{
		u4count=0;
		printf("数据预热\r\n");
		memset(u4recive,0,102);
		return 0;
	}

以上都没有问题之后,此时获取到的数组才是真正有用的数据。
在这里插入图片描述
在这里插入图片描述
由手册可知该数据的转换模式,照着做就行。记得用完将数据位和标志位都清零。

	voc=((u4recive[1]<<8)+u4recive[2])*0.11;
	ch2o = ((u4recive[3]<<8)+u4recive[4])*0.01;
	co2 = ((u4recive[5]<<8)+u4recive[6]);
	printf("VOC = %.1f PPM\r\n甲醛 = %.2f MG/M3\r\nCo2 = %.0fPPM\r\n",voc,ch2o,co2);
	u4count=0;
	memset(u4recive,0,102);
    return 0;

最后记得将处理函数添加到主函数的while(1)死循环中。
由于串口4用到了串口1输出,所以在main函数的配置应在串口1的后面。

四、关键代码

main.c

#include "stm32f10x.h"
#include "usart.h"
#include "stdio.h"
#include "delay.h"
#include "kqm.h"
#include "string.h"

int main()
{
	NVIC_SetPriorityGrouping(5);//两位抢占两位次级
    Usart1_Config(); 
    Kqm_U4Config();
    while(1)
    {	
	  	KQM_DealData();
    }
}

kqm.c

#include "stm32f10x.h"
#include "stdio.h"
#include "string.h"


float voc,ch2o,co2;
void Kqm_U4Config()
{
	//开时钟 U4 PC11RX
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	 RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE);
	//配置io
	    GPIO_InitTypeDef GPIO_InitStruct = {0};
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	 	GPIO_Init(GPIOC,&GPIO_InitStruct);
	//配置串口  波特率9600 数据位8,校验位0,停止位1
		USART_InitTypeDef USART_InitStruct = {0};//可以通过结构体类型跳转
		USART_InitStruct.USART_BaudRate = 9600;//波特率
		USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件控制流不开
		USART_InitStruct.USART_Mode = USART_Mode_Rx;//打开接收
		USART_InitStruct.USART_Parity = USART_Parity_No;
		USART_InitStruct.USART_StopBits = USART_StopBits_1;
		USART_InitStruct.USART_WordLength = USART_WordLength_8b;
		USART_Init(UART4,&USART_InitStruct);
	//使能串口
		USART_Cmd(UART4,ENABLE);
	//配置串口4的中断(采用中断接收)
      USART_ITConfig(UART4,USART_IT_RXNE,ENABLE);//使能串口4	的接收非空中断
	  USART_ITConfig(UART4,USART_IT_IDLE,ENABLE);//总线空闲中断
	  NVIC_SetPriority(UART4_IRQn,7);//设置优先级0~15
	  NVIC_EnableIRQ(UART4_IRQn);//使能中断通道
}

uint8_t u4recive[102]={0};
uint8_t u4count=0;
uint8_t u4flag=0;
uint8_t i=0;


void UART4_IRQHandler(void)
{
	uint8_t data=0;
	//判断接收中断是否发生
	if(USART_GetITStatus(UART4,USART_IT_RXNE)==SET)
	{
		data = UART4->DR;
		u4recive[u4count]=data;
		u4count++;
		u4count%=8;
		
		//USART1->DR = data;//回显
	}
	//触发空闲中断,表示总线空闲,接收完毕
	if(USART_GetITStatus(UART4,USART_IT_IDLE)==SET)
	{
		data = UART4->SR;//清理空闲中断,先读SR再读DR
		data = UART4->DR;
		u4flag=1;
	}
	
}

uint8_t KQM_DealData()
{
	if(u4flag==0)
	{
		return 0;
	}
	u4flag=0;
	 for(i=1;i<7;i++)
	{
		if(u4recive[i]!=0xff)
		{
			break;
		}
	}
	if(i==7)
	{
		u4count=0;
		printf("数据预热\r\n");
		memset(u4recive,0,102);
		return 0;
	}

	voc=((u4recive[1]<<8)+u4recive[2])*0.11;
	ch2o = ((u4recive[3]<<8)+u4recive[4])*0.01;
	co2 = ((u4recive[5]<<8)+u4recive[6]);
	printf("VOC = %.1f PPM\r\n甲醛 = %.2f MG/M3\r\nCo2 = %.0fPPM\r\n",voc,ch2o,co2);
		u4count=0;
	  memset(u4recive,0,102);
		return 0;
}

kqm.h

#ifndef _KQM_H_
#define _KQM_H_
#include "stm32f10x.h"
void Kqm_U4Config();
uint8_t KQM_DealData();

#endif
		

其他代码遇上几节课一样。


总结

1.学会了KQM6600空气质量传感器模块的接线和配置。
2.学会了使用空闲中断,以及数据的获取与处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/754889.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

css 流动边框

一、背景流动边框 实现原理&#xff1a; 用背景进行旋转&#xff0c;超出我们想显示的范围则hidden&#xff0c;就有以上的效果&#xff0c;可以用after或者before元素来实现也可以。 <!DOCTYPE html> <html lang"en"><head><meta charset&qu…

【开发环境】MacBook M2安装git并拉取gitlab项目,解决gitlab出现Access Token使用无效的方法

文章目录 安装Homebrew安装git打开IDEA配置git打开IDEA拉取项目 安装Homebrew /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"在iTerm等命令行工具打开后&#xff0c;输入上面的命令 之后根据中文提示完成Homebrew的下载…

web项目打包成可以离线跑的exe软件

目录 引言打开PyCharm安装依赖创建 Web 应用运行应用程序打包成可执行文件结语注意事项 引言 在开发桌面应用程序时&#xff0c;我们经常需要将网页集成到应用程序中。Python 提供了多种方法来实现这一目标&#xff0c;其中 pywebview 是一个轻量级的库&#xff0c;它允许我们…

PyScript:在浏览器中释放Python的强大

PyScript&#xff1a;Python代码&#xff0c;直接在网页上运行。- 精选真开源&#xff0c;释放新价值。 概览 PyScript是一个创新的框架&#xff0c;它打破了传统编程环境的界限&#xff0c;允许开发者直接在浏览器中使用Python语言来创建丰富的网络应用。结合了HTML界面、Pyo…

把飞书云文档变成HTML邮件:问题挑战与解决历程

一、背景 云文档转HTML邮件 基于公司内部的飞书办公套件&#xff0c;早在去年6月&#xff0c;我们就建设了将飞书云文档转译成HTML邮件的能力&#xff0c;方便同学们在编写邮件文档和发送邮件时&#xff0c;都能有较好的体验和较高的效率。 当下问题 要被邮件客户端识别&am…

【蓝桥杯省赛真题46】python数字币统计 中小学青少年组蓝桥杯比赛 算法思维python编程省赛真题解析

目录 python数字币统计 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python数字币统计 第十四届蓝桥杯青少年组python比赛省赛真题 一、题目…

Spring Boot结合FFmpeg实现视频会议系统视频流处理与优化

在构建高效稳定的视频会议系统时,实时视频流的处理和优化是开发者面临的核心挑战之一。这不仅仅是简单的视频数据传输,更涉及到一系列复杂的技术问题,需要我们深入分析和有效解决。 高并发与实时性要求: 视频会议系统通常需要支持多人同时进行视频通话,这就意味着系统需要…

ONLYOFFICE8.1版本桌面编辑器——功能测评

一、编辑DOCX 相信大家都有写word文档的经历&#xff0c;不知道大家是不是跟我一样&#xff0c;感觉做一个word不难&#xff0c;但想做好一个word却很麻烦&#xff0c;功能太多&#xff0c;看的人眼花缭乱&#xff0c;有时候一个功能要找很久&#xff0c;甚至有的功能用一辈子都…

Matlab/simulink三段式距离/低阻抗保护

距离1段仿真波形如下所示 距离2段仿真波形如下所示 距离3段仿真波形如下所示

独立开发者系列(12)——下单与支付

做业务有个绕不开的业务逻辑&#xff0c;就是支付。这里总结一个基础的支付电商逻辑闭环流程&#xff0c;完成支付基础体系的实现。这里假定我们要实现的是一个独立的电商平台上允许用户在平台充值&#xff0c;其他的类似多多购物或者淘宝购物的流程逻辑。 数据表结构的逻辑设…

搭建Renesas R7FA8D1BHECBD-BTB的开发调试环境(DAP-LINK: N32G45XVL-STB)

目录 概述 1 软硬件 1.1 软硬件环境信息 1.2 开发板信息 1.3 调试器信息 2 FSP和KEIL产生测试项目 2.1 FSP生成项目 2.2 Keil中配置 3 硬件连接框图 4 一个测试案例 4.1 功能介绍 4.2 定时器函数 5 测试 搭建Renesas R7FA8D1BHECBD-BTB的开发调试环境&#xff08…

【漏洞复现】I doc view——任意文件读取

声明&#xff1a;本文档或演示材料仅供教育和教学目的使用&#xff0c;任何个人或组织使用本文档中的信息进行非法活动&#xff0c;均与本文档的作者或发布者无关。 文章目录 漏洞描述漏洞复现测试工具 漏洞描述 I doc view 在线文档预览是一个用于查看、编辑、管理文档的工具…

LabVIEW材料样本结构缺陷检测

本文介绍了一种基于LabVIEW的实验室振动特性分析测试装置&#xff0c;通过分析振动特性来检测结构缺陷。文章详细描述了具体案例、硬件型号、工作原理、软件功能以及注意事项。 硬件型号 振动传感器&#xff1a;PCB Piezotronics 352C33加速度计 数据采集卡&#xff1a;NI PXI…

天气网站爬虫及可视化

摘要&#xff1a;随着互联网的快速发展&#xff0c;人们对天气信息的需求也越来越高。本论文基于Python语言&#xff0c;设计并实现了一个天气网站爬虫及可视化系统。该系统通过网络爬虫技术从多个天气网站上获取实时的天气数据&#xff0c;并将数据进行清洗和存储。同时&#…

Windows下activemq集群配置(broker-network)

1.activemq版本信息 activemq&#xff1a;apache-activemq-5.18.4 2.activemq架构 3.activemq集群配置 activemq集群配置基于Networks of Brokers 这种HA方案的优点&#xff1a;是占用的节点数更少(只需要2个节点),而且2个broker都可以响应消息的接收与发送。不足&#xff…

下载旧版本vscode及扩展,离线下载远程linux服务器插件

背景 工作的内网没有网络&#xff0c;无法使用网络来下载插件和vscode软件&#xff0c;且有远程linux服务器需求&#xff0c;linux服务器中lib相关库比较旧且无法更新&#xff0c;所以需要选择一个旧版本的vscode&#xff0c;相应插件也需要选择旧版本的 旧版本vscode下载 没…

JavaWeb——MySQL:事务的简单学习

前面学习完了数据库增删查改的SQL语言&#xff0c;约束&#xff0c;数据库设计&#xff0c;以及多表查询&#xff0c;再学完事务就达到初级工程师的水平了。 6. 事务 6.1 概念 事务类似于编程语言的方法&#xff0c;包含一组SQL指令。 事务是不可分割的&#xff1b; 该指令步…

高中数学:复数-三角表示式

一、定义 辐角主值 二、复数乘除运算的三角表示及其几何意义 乘法 复数乘法的几何意义 除法 练习 解

机器学习 笔记

什么是机器学习 Machine Learning 约等于 Look for a function. 学习路线 监督学习&#xff1a; 回归Regression&#xff1a;指模型预估的输出是数值Classification&#xff1a;指模型预估的输出是类别&#xff0c;二分类的输出是或否会告诉机器正确的答案是什么 半监督学习…

xlsx插件简介

1. xlsx插件 1.1. 常用属性和方法 1.1.1. 创建新的工作簿1.1.2. 从数组生成工作表1.1.3. 添加工作表到工作簿1.1.4. 从HTML表格创建工作表1.1.5. 读取Excel文件1.1.6. 导出Excel文件1.1.7. 设置单元格样式 2. vue中如何使用xlsx 2.1. vue-xlsx的特点2.2. 常用属性和方法 2.2.1…