KQM6600空气质量传感器
目录
查找资料
-
找相应的资料,看资料
-
1、看引脚(看接线图)

-- 可以看出只有kqm向单片机发送数据,所以单片机编写代码只用写接收函数
- 2、然后看数据的输出格式

-- 可以看出数据输出的数据位数是8位,但是传输数据是10位,因为还有起始位和停止位
-- 已知数据1是voc,数据2是pcho(甲醛),数据3是co2,都是16进制数的形式,所以需要转换成10进制数,并且单位都不同,还要进行换算。


编程
1、初始化(时钟、IO、外设、中断、其他)
- 1、配置时钟(A端口和UART4(外设自身也有时钟))
-- 这里注意串口4的名字有点特殊,是UART4,没有S。
cs
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE); //看数据手册在哪条线上 - APB1 //注意串口名字
-- 注意看数据手册,该外设在那条线上,这里明显是在APB1线上,所以用RCC_APB1PeriphClockCmd,至于为什么用串口4,是因为在这个单片机上其他的串口被别的外设使用了,所以只能用串口4,
而根据原理图可以看出串口4连接在单片机上的引脚是PC10和PC11,所以需要配置这两个引脚


- 2、配置IO口
-- PC10是TX,PC11是RX,所以配置PC10为复用推挽输出,PC11为浮空输入
cs
//IO PC10,PC11
GPIO_InitTypeDef GPIO_InitStructure = {0}; //定义结构体变量,并且将结构体变量赋初值
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOC, &GPIO_InitStructure);
- 3、配置外设
-- 将外设名字改为串口4即可
cs
USART_InitTypeDef USART_InitStructure = {0};
USART_InitStructure.USART_BaudRate = 9600; //波特率 常用的是4800 9600 115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位长度
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位长度
USART_InitStructure.USART_Parity = USART_Parity_No; //奇偶校验(这里写不使用)
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制失能(不使用硬件流控制)
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//模式
USART_Init(UART4, &USART_InitStructure);
USART_Cmd(UART4,ENABLE);//开启串口 //使能或者失能 UART4 外设(一般外设都要写这个)
- 4、配置中断
-- 配置中断,不仅要开启中断通道,还要使能中断源
cs
//使能中断源 //串口有10个,用哪一个就要开哪一个中断源
USART_ITConfig(UART4,USART_IT_RXNE,ENABLE);
//中断
NVIC_InitTypeDef NVIC_InitStructure = {0};
NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn; //中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能(使能哪个中断通道,就要写哪个(必须写)中断服务函数)
NVIC_Init(&NVIC_InitStructure);
2、中断服务函数
- 因为这里单片机只用接收数据,所以只写接收函数即可,而接收数据用中断来接收
cs
//中断服务函数
void UART4_IRQHandler()
{
//判断接收中断是否发生
if(USART_GetITStatus(UART4, USART_IT_RXNE) == SET)
{
//处理中断:保存数据
kqm.rxbuff[kqm.rxlen++] = USART_ReceiveData(UART4);
if(kqm.rxlen == 8)
kqm.rxflag = 1;
kqm.rxlen %= 10;//对10求余,他就一直会小于10
//清理终端
USART_ClearITPendingBit(UART4,USART_IT_RXNE);
}
}
3、数据解析函数



cs
//数据解析函数
void data_parsing(void)//解析
{
if(kqm.rxflag == 1 )
{
//错误判断
if(kqm.rxlen != 8 )//异常情况
{
goto AAA;
}
//预热
if(kqm.rxbuff[1] == 0xff && kqm.rxbuff[2] == 0xff && \
kqm.rxbuff[3] == 0xff && kqm.rxbuff[4] == 0xff && \
kqm.rxbuff[5] == 0xff && kqm.rxbuff[6] == 0xff)//S数据的高位和低位
{
printf("当前模式处在预热模式\r\n");
goto AAA;
}
uint8_t check = kqm.rxbuff[0]+kqm.rxbuff[1]+kqm.rxbuff[2]+kqm.rxbuff[3]+kqm.rxbuff[4]+kqm.rxbuff[5]+kqm.rxbuff[6];
if(check !=kqm.rxbuff[7])
{
printf("校验错误\r\n");
goto AAA;
}
//解析数据
kqm.voc = (kqm.rxbuff[1]<<8|kqm.rxbuff[2])*0.1;//两个8位数合成1个16位
kqm.hcho = (kqm.rxbuff[3]<<8|kqm.rxbuff[4])*0.01;
kqm.co2 = (kqm.rxbuff[5]<<8|kqm.rxbuff[6])*1;
printf("voc:%.2fPPM\r\n",kqm.voc);
printf("hcho:%.2fmg/m3\r\n",kqm.hcho);
printf("co2:%.2fPPM\r\n",kqm.co2);
AAA:
memset(kqm.rxbuff,0,10);
kqm.rxlen = 0;
kqm.rxflag = 0;
}
}
kqm6600.h
-- 这里选择定义一个结构体来存取数据
cs
#ifndef _KQM6600_H_
#define _KQM6600_H_
#include "stdio.h"
#include "STM32f10x.h"
void kqm6600_init(void);
typedef struct {
uint8_t rxbuff[10];//接收缓冲区
uint8_t rxlen;//接收计数值
uint8_t rxflag;
float voc;//空气质量
float co2;//二氧化碳
float hcho;//甲醛
}KQM;
void data_parsing(void);
#endif
硬件连接

- G是GND
- V是VCC
- A是PC11

安装ST-LINK驱动
-- 在文件夹中找到安装包

-- 安装完毕,会有这个图标

-- 点击魔法棒


-- 连接下载器
-- 程序编译没错误后,点击下载

实验结果
- mian.c
cs
int main()
{
relay_on();
Delay_nms(100);
relay_off();
relay_init();
kqm6600_init();
SysTick_Config(72000);
while(1)
{
if(kqmtime >= 500)
{
kqmtime =0 ;
data_parsing();
if(kqm.voc >= 7)
{
relay_on();
Delay_nms(100);
relay_off();
}
//printf("1\r\n");
}
}
}

补充:
- 注:数据解析函数可以参考这个框架
//数据解析函数 //1、判断数据是否接收完毕 //2、错误判断(预热、校验。。。) //3、解析数据 //4、清除接收缓冲区
- 注:每次收到一个字节就会触发一次中断,而不是收到8个数据才会触发