锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

基于STM32采集CO2(MH-Z19C)传感器数据

时间:2022-11-12 05:00:00 zg2传感器如何维护06丝印z19三极管

本文主要记录使用情况STM32的USART2串口采集CO2通过传感器数据和传感器数据USART串口使用串口调试助手显示CO2数值。
一、实验设备
正点原子STM32MINI魏盛科技开发板CO2(MH-Z19C)传感器。
二、硬件连接
STM32的USART1(PA9-TX,PA10-RX)通过CH340芯片与计算机连接,USART2的接收端PA3-RX连接MH-Z19C的发送端TX,USART2的发送端PA2-TX连接MH-Z19C的接收端RX。特别注意,如果串口接收数据错误,您使用的串口与其他功能没有冲突。
三、CO2传感器控制原理
首先通过STM32主控芯片向Sensor发送读取气浓度指令:FF 01 86 00 00 00 00 00 79,
接到指令后,传感器返回值为:FF 86 HIGH LOW — — — — 校验和。
USART中断函数主要负责传感器返回数据的存储和处理。
四、USART2.C程序

#include "sys.h" #include "usart.h"  //  //如果使用ucos,包括下面的头文件. #if SYSTEM_SUPPORT_OS #include "includes.h" //ucos 使用  #endif  支持///添加以下代码printf不需要选择函数use MicroLIB  #if 1 #pragma import(__use_no_semihosting)  ////标准库所需的支持函数  struct __FILE  { 
          int handle;   };   FILE __stdout;        //定义_sys_exit()避免使用半主机模式  void _sys_exit(int x)  { 
          x = x;  }  //重定义fputc函数  int fputc(int ch, FILE *f) { 
               while(((USART1->SR&0X40)==0)|((USART2->SR&0X40)==0));///循环发送,直到发送完成      USART1->DR = (u8) ch;    USART2->DR = (u8) ch;          return ch; } #endif    #if EN_USART1_RX| EN_USART2_RX|EN_UART5_RX //如果能够接收 /串口1pan> //注意,读取USARTx->SR能避免莫名其妙的错误  u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节. //接收状态 //bit15, 接收完成标志 //bit14, 接收到0x0d //bit13~0, 接收到的有效字节数目 u16 USART_RX_STA=0; //接收状态标记  u16 PM25; u16 CO2; void uart_init(u32 bound) //初始化串口1和串口2,函数的参数是波特率 { 
         GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; //串口1设置 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟 //USART1_TX GPIOA.9 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9 //USART1_RX GPIOA.10初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  //Usart1 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器 //USART 初始化设置 USART_InitStructure.USART_BaudRate = bound;//串口波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式 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_Rx | USART_Mode_Tx; //收发模式 USART_Init(USART1, &USART_InitStructure); //初始化串口1 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断 USART_Cmd(USART1, ENABLE); //使能串口1  串口2设置--用于USART2采集炜盛PM2.5(ZH03B)传感器 //RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); //使能USART2, //RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟 // //USART2_TX GPIOA.2 // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2 // GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 // GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.2 // //USART2_RX GPIOA.3初始化 // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA.3 // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入 // GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.3  // //Usart2 NVIC 配置 // NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3 // NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3 // NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 // NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器 // //USART 初始化设置 // USART_InitStructure.USART_BaudRate = bound;//串口波特率 // USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式 // 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_Rx | USART_Mode_Tx; //收发模式 // USART_Init(USART2, &USART_InitStructure); //初始化串口2 // USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断 // USART_Cmd(USART2, ENABLE); //使能串口2  //串口2设置--用于USART2采集炜盛MH-Z19C二氧化碳传感器(我用的正点原子STM32MINI开发板,其他串口被占用) RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); //使能USART2, RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟 //USART2_TX GPIOA.2 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.2 //USART2_RX GPIOA.3初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA.3 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.3  //Usart2 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器 //USART 初始化设置 USART_InitStructure.USART_BaudRate = bound;//串口波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式 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_Rx | USART_Mode_Tx; //收发模式 USART_Init(USART2, &USART_InitStructure); //初始化串口2 USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断 USART_Cmd(USART2, ENABLE); //使能串口2  } void USART1_IRQHandler(void) //串口1中断服务程序 { 
         u8 Res; #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS. OSIntEnter(); #endif if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾) { 
         Res =USART_ReceiveData(USART1); //读取接收到的数据 if((USART_RX_STA&0x8000)==0)//接收未完成 { 
         if(USART_RX_STA&0x4000)//接收到了0x0d { 
         if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始 else USART_RX_STA|=0x8000; //接收完成了  } else //还没收到0X0D { 
         if(Res==0x0d)USART_RX_STA|=0x4000; else { 
         USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; USART_RX_STA++; if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收  } } } } #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS. OSIntExit(); #endif } //该段代码作用是采集并处理炜盛PM2.5(ZH03B)传感器数据 //void USART2_IRQHandler(void) //串口2中断服务程序 // { 
         // u8 Res; //  //#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS. // OSIntEnter();  //#endif // static char start=0; // if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收中断 // { 
         // Res =USART_ReceiveData(USART2); //读取接收到的数据 // //USART_SendData(USART1,Res); // if(Res == 0x42) //如果接收的第一位数据是0X42(这个是查看传感器的手册得知的) // { 
         // USART_RX_STA = 0; //让数组索引值从0开始 // start = 1; //这个变量是来确定第二位是否接收到了0X4D(这个也是查看传感器的手册得知的) // } // if(start == 1) // { 
         // USART_RX_BUF[USART_RX_STA] = Res ; //把接收到的数据存到数组里面 // USART_RX_STA++; // if(USART_RX_STA >= 24 && (USART_RX_BUF[1]==0x4d)) // { 
         // //USART_SendData(USART1,USART_RX_BUF[12]*256+USART_RX_BUF[13]); // PM25=USART_RX_BUF[12]*256+USART_RX_BUF[13]; // printf("PM2.5:%d\n",PM25); // start = 0; // USART_RX_STA=0;//重新开始接收  // USART_RX_BUF[0] = 0; // } // }  // } //  //#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS. // OSIntExit();  //#endif //  // }  //该段代码作用是采集并处理炜盛MH-Z19C二氧化碳传感器数据 void USART2_IRQHandler(void) //串口2中断服务程序 { 
         u8 Res; #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS. OSIntEnter(); #endif static char start=0; if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收中断 { 
         Res =USART_ReceiveData(USART2); //读取接收到的数据 //USART_SendData(USART1,Res); if(Res == 0xFF) //如果接收的第一位数据是0XFF(这个是查看传感器的手册得知的) { 
         USART_RX_STA = 0; //让数组索引值从0开始 start = 1; //这个变量是来确定第二位是否接收到了0X86(这个也是查看传感器的手册得知的) } if(start == 1) { 
         USART_RX_BUF[USART_RX_STA] = Res ; //把接收到的数据存到数组里面 USART_RX_STA++; if(USART_RX_STA >= 9 && (USART_RX_BUF[1]==0x86)) { 
         //USART_SendData(USART1,USART_RX_BUF[12]*256+USART_RX_BUF[13]); CO2=USART_RX_BUF[2]*256+USART_RX_BUF[3]; printf("CO2:%dppm\n",CO2); start = 0; USART_RX_STA=0;//重新开始接收  USART_RX_BUF[0] = 0; } } } #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS. OSIntExit(); #endif } #endif  五 USART2.h程序 #ifndef __USART_H #define __USART_H #include "stdio.h"  #include "sys.h"  #define USART_REC_LEN 200 //定义最大接收字节数 200 #define EN_USART1_RX 1 //使能(1)/禁止(0)串口1接收 #define EN_USART2_RX 1 //使能(1)/禁止(0)串口2接收 extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符  extern u16 USART_RX_STA; //接收状态标记  //如果想串口中断接收,请不要注释以下宏定义 void uart_init(u32 bound); #endif 六 CO2.c程序 ```c #include "CO2.h" //发送读取指令 //const u16 CO2_SPAN_SET[9]={0xFF,0x01,0x99,0x00,0x00,0x00,0x13,0x88,0x8F};//此处为设置CO2量程,参考MH-Z19B数据手册,而MH-Z19C手册里并没有设置量程的指令,该处代码慎用。 const u16 CO2_WORK_CMD[9]={ 
        0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79}; //void CO2_SPAN(void) //{ 
         // int i; // for(i = 0; i < 9; i++)  // {  // USART_ClearFlag(USART2,USART_FLAG_TC); // USART_SendData(USART2,CO2_SPAN_SET[i]);  // while(USART_GetFlagStatus(USART2, USART_FLAG_TC)==RESET);  // }  //  //} void CO2_WORK(void) { 
         int i; for(i = 0; i < 9; i++) { 
         USART_ClearFlag(USART2,USART_FLAG_TC); USART_SendData(USART2,CO2_WORK_CMD[i]); while(USART_GetFlagStatus(USART2, USART_FLAG_TC)==RESET); } } 七、CO2.h程序、 ```c #ifndef __CO2_H #define __CO2_H #include "stdio.h"  #include "sys.h"  #include "usart.h" //extern void CO2_SPAN(void); extern void CO2_WORK(void); #endif 八、main.c程序(功能:当检测到CO2>1500ppm时,LED1点亮,否则LED1熄灭,LED0只是个闪烁灯而已) ```c #include "led.h" #include "delay.h" #include "sys.h" #include "usart.h" #include "stdio.h" #include "CO2.h" extern u16 CO2; int main(void) { 
         delay_init(); //延时函数初始化  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2  uart_init(9600); //串口初始化为9600 LED_Init(); //初始化与LED连接的硬件接口 while(1) { 
         // CO2_SPAN(); CO2_WORK(); if(CO2>1500) { 
         LED1=0; } else { 
         LED1=1; } LED0=!LED0; delay_ms(250); } } 九、实验结果 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20201222235531335.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzUzNjM3NTg2,size_16,color_FFFFFF,t_70#pic_center) 十、楼主是一名单片机爱好者,欢迎大家留言交流。 走钢丝的猴书于2020.12.2223:42 
锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章