【STM32练习】基于STM32的PM2.5环境监测系统

一.项目背景

        最近为了完成老师交付的任务,遂重制了一下小项目用STM32做一个小型的环境监测系统。

        项目整体示意框图如下:

二.器件选择

  • 单片机(STM32F103)
  • 数字温湿度模块(DHT11)
  • 液晶显示模块(0.8寸OLED)
  • 粉尘传感器模块(GP2Y10)
  • 报警模块(蜂鸣器)
  • 按键控制模块(独立按键)

        由于笔者觉得时钟模块没什么必要性,就没再加DS1302上去了。 

三.PCB绘制

        PCB推荐使用嘉立创专业版绘制,对于初学者来说简单易上手,而且这种DIY的小玩意绘制的PCB大小控制在10*10以内还可以免费打样。

        嘉立创很方便的一点是可以使用它内部自带的在线库,省去了自己画封装画元件的步骤,非常简单,但是注意要辨别这里的元件封装的正确性,因为有些元件封装是用户贡献的,所以有些地方不一定正确,各位读者如果是小白的话一定要注意辨别是否符合自己的需求!!!

        这里PCB布线也没什么好说的,很简单的几个模块,而且板子的大小很大空间完全足够布线。

四.核心代码

以下只对部分核心代码做展示。

项目文件目录

GP2Y10粉尘传感器的驱动程序

GP2Y10.h

#ifndef   __GP2Y10_H__
#define   __GP2Y10_H__#include <stdint.h>
#include <stdio.h>
#include "main.h"
#include "stm32f1xx_hal.h"
#include "driver_timer.h"
#include "driver_lcd.h"extern ADC_HandleTypeDef hadc1;#define LIMIT(x, min, max) 	( (x) < (min)  ? (min) : ( (x) > (max) ? (max) : (x) ) ) // 限幅函数
#define GP2Y10_LED_ON()	 HAL_GPIO_WritePin(GP_LED_GPIO_Port, GP_LED_Pin, GPIO_PIN_RESET) // 传感器LED灯开
#define GP2Y10_LED_OFF() HAL_GPIO_WritePin(GP_LED_GPIO_Port, GP_LED_Pin, GPIO_PIN_SET)// 传感器LED灯关#define PM25_LED_H			HAL_GPIO_WritePin(GP_LED_GPIO_Port, GP_LED_Pin, GPIO_PIN_SET);
#define PM25_LED_L			HAL_GPIO_WritePin(GP_LED_GPIO_Port, GP_LED_Pin, GPIO_PIN_RESET);#define GP2Y10_SAMP_TIME	280 // 传感器采样时间280us
#define GP2Y10_LEDON_TIME	320 // LED灯开持续时间
#define GP2Y10_PULSE_PERIOD	10000 // 传感器测量脉冲一个周期的时间#define PM25_READ_TIMES	20void GP2Y10_Init(void);
float GP2Y10_Value(void);
float Get_PM25_Average_Data(void);
void GP2Y10_Test(void);#endif

GP2Y10.c

#include "GP2Y10.h"void GP2Y10_Init(void)
{GP2Y10_LED_OFF(); // 初始化传感器LED灯为关HAL_ADC_Start(&hadc1);  //开启ADCHAL_ADC_PollForConversion(&hadc1, 50);   //等待转换完成,50为最大等待时间,单位为ms
}// 计算粉尘浓度
float GP2Y10_Value(void)
{uint16_t ADCVal;int dustVal = 0;float Voltage;PM25_LED_H;	//置1  开启内部LEDudelay(280); 	// 开启LED后的280us的等待时间ADCVal = HAL_ADC_GetValue(&hadc1);  //PA1 采样,读取AD值udelay(19);			  //延时19us,因为这里AD采样的周期为239.5,所以AD转换一次需耗时21us,19加21再加280刚好是320usPM25_LED_L;	//置0  关闭内部LEDudelay(9680);			//需要脉宽比0.32ms/10ms的PWM信号驱动传感器中的LEDVoltage = 3.3f * ADCVal / 4096.f * 2; //获得AO输出口的电压值dustVal = (0.17*Voltage-0.1)*1000;  //乘以1000单位换成ug/m3//if (dustVal < 0)dustVal = 0;            //限位//if (dustVal>500)        dustVal=500;return dustVal;
}float Get_PM25_Average_Data(void)
{float temp_val=0;uint8_t t;for(t=0;t<PM25_READ_TIMES;t++)	//#define PM25_READ_TIMES	20	定义读取次数,读这么多次,然后取平均值{temp_val+=GP2Y10_Value();	//读取ADC值mdelay(5);}temp_val/=PM25_READ_TIMES;//得到平均值return temp_val;//返回算出的ADC平均值
}void GP2Y10_Test(void)
{GP2Y10_Init();float concentration;while(1){LCD_PrintString(0,0,"CON:");concentration = GP2Y10_Value();LCD_PrintSignedVal(0,2,concentration);mdelay(1000);}
}

按键读取程序

#include "Key.h"void Key_Init(void)
{}uint8_t Key_GetValue(void)
{uint8_t value = 0;if(HAL_GPIO_ReadPin(GPIOA,KEY_A_Pin) == GPIO_PIN_SET)value = 1;if(HAL_GPIO_ReadPin(GPIOA,KEY_B_Pin) == GPIO_PIN_SET)value = 2;if(HAL_GPIO_ReadPin(GPIOA,KEY_C_Pin) == GPIO_PIN_SET)value = 3;if(HAL_GPIO_ReadPin(GPIOA,KEY_D_Pin) == GPIO_PIN_SET)value = 4;return value;
}uint8_t Key_Scan(void)
{uint8_t key_number = 0;key_number = Key_GetValue();if(key_number != 0){mdelay(20);while( Key_GetValue() != 0);mdelay(20);return key_number;}return 0;
}void Key_Test(void)
{uint8_t Key_Number = Key_Scan();if(Key_Number == 1)printf("A\n");else if(Key_Number == 2)printf("B\n");else if(Key_Number == 3)printf("C\n");else if(Key_Number == 4)printf("D\n");
}

定时程序

        这里原本用的是韦东山老师的RTOS里的非阻塞延时,但是由于笔者最终选择使用裸机完成整个功能,于是便把ms延时函数换成了HAL库的官方延时函数。

#include "driver_timer.h"
#include "stm32f1xx_hal.h"
#define CPU_FREQUENCY_MHZ    72		// STM32时钟主频void udelay(uint32_t delay)
{int last, curr, val;int temp;while (delay != 0){temp = delay > 900 ? 900 : delay;last = SysTick->VAL;curr = last - CPU_FREQUENCY_MHZ * temp;if (curr >= 0){do{val = SysTick->VAL;}while ((val < last) && (val >= curr));}else{curr += CPU_FREQUENCY_MHZ * 1000;do{val = SysTick->VAL;}while ((val <= last) || (val > curr));}delay -= temp;}
}void mdelay(int ms)
{
//    for (int i = 0; i < ms; i++)
//        udelay(1000);HAL_Delay(ms);
}

逻辑功能实现

Task.h

#ifndef   _TASK_H__
#define   _TASK_H__#include <stdint.h>
#include <stdbool.h>
#include "HeaderConfig.h"#define HUM_MAX      100
#define HUM_MIN      10
#define TEM_MAX      100
#define TEM_MIN      10
#define DUS_MAX      100
#define DUS_MIN      10void Task_Test(void);
void Device_Init(void);
void Task_Prime(void);#endif

Task.c

#include "Task.h"uint8_t Prime_Mode = 0;
uint8_t Start_Mode = 0;
uint8_t Threshold_Mode = 0;//温度调节模式
bool isCollecting = false;int Humidity = 0,Temperature = 0;
float Dust_Concentration = 0;
uint8_t TemperatureMax = 30;
uint8_t TemperatureMin = 10;uint8_t DataRead_Count = 0;//数据采集计次
uint8_t Blink_Count = 0;//闪烁
uint16_t Timer_2000ms = 0;//数据采集间隔
uint16_t Timer_Blink = 0;//void Task_Test(void)
{//LCD_Test();//Key_Test();
}void Device_Init(void)
{LCD_Init();Buzzer_Init();DHT11_Init();GP2Y10_Init();Key_Init();
}void Task_Key(void)
{uint8_t Key_Number = Key_Scan();if(Prime_Mode == 2){if(Key_Number == 1){LCD_Clear();Start_Mode = 1;Prime_Mode = 0;isCollecting = false;}}else{if(Key_Number == 1){LCD_Clear();Start_Mode ^= 1;Prime_Mode = 0;isCollecting = false;}}if(Prime_Mode == 2){if(Key_Number == 2){LCD_Clear();Threshold_Mode ^= 1;}}else{if(Key_Number == 2){LCD_Clear();Prime_Mode = 1;isCollecting = false;}}//设置报警阈值if(Key_Number == 3){LCD_Clear();Prime_Mode = 2;isCollecting = false;if(Threshold_Mode == 0)//高温阈值++{++TemperatureMax;}if(Threshold_Mode == 1)//低温阈值++{++TemperatureMin;}}if(Key_Number == 4){LCD_Clear();Prime_Mode = 2;isCollecting = false;if(Threshold_Mode == 0)//高温阈值++{--TemperatureMax;}if(Threshold_Mode == 1)//低温阈值++{--TemperatureMin;}}
}void filter_and_smooth(float *data, int size, float *smoothed_data) {// 滤除0int count = 0;for (int i = 0; i < size; i++) {if (data[i] != 0) {smoothed_data[count++] = data[i];}}// 平滑曲线for (int i = 0; i < count - 2; i++) {smoothed_data[i] = (smoothed_data[i] + smoothed_data[i + 1] + smoothed_data[i + 2]) / 3.0;}
}void Task_DataCollect(void)
{//DHT11_Read(&Humidity,&Temperature);if ( DHT11_Read(&Humidity,&Temperature) !=0 ){DHT11_Init();}Dust_Concentration = Get_PM25_Average_Data();//采集粉尘浓度数据
//	printf("Humidity:%d\n",Humidity);
//	printf("Temperature:%d\n",Temperature);
//	printf("PM2.5:%f\n",Dust_Concentration);printf("%f\n",Dust_Concentration/10);
}void Task_Alarm(void)
{if(Temperature > TemperatureMax || Temperature < TemperatureMin){Buzzer_Control(ON);mdelay(20);Buzzer_Control(OFF);mdelay(20);}	
}void Task_OLED(void)
{switch(Prime_Mode){case 0:{//控制启动关机if(Start_Mode == 1)//开机{LCD_PrintString(0,0,"Welcome to:");LCD_PrintString(5,2,"System");}else//关机LCD_Clear();break;}case 1://温湿度,PM2.5浓度{if(Start_Mode == 1){if(!isCollecting){LCD_PrintString(2,3,"Collecting...");mdelay(3000);LCD_Clear();isCollecting = true;}LCD_PrintString(0,0,"Data=>");LCD_PrintString(0,2,"Humidity:");LCD_PrintSignedVal(9, 2, Humidity);LCD_PrintString(0,4,"Temperature:");LCD_PrintSignedVal(12, 4, Temperature);LCD_PrintString(0,6,"PM2.5:");LCD_PrintSignedVal(6, 6, (int)Dust_Concentration);}break;}case 2://设置报警阈值{if(Start_Mode == 1){LCD_PrintString(0,2,"High:");LCD_PrintString(0,4,"Low:");if(Threshold_Mode == 0){if(Blink_Count == 0)LCD_PrintSignedVal(6, 2, TemperatureMax);elseLCD_PrintString(6,2,"     ");LCD_PrintSignedVal(6, 4, TemperatureMin);}if(Threshold_Mode == 1){LCD_PrintSignedVal(6, 2, TemperatureMax);if(Blink_Count == 0)LCD_PrintSignedVal(6, 4, TemperatureMin);elseLCD_PrintString(6,4,"     ");}}break;}
//		case 3://出行建议
//		{
//			if(Start_Mode == 1)
//			{
//				if(Humidity > HUM_MAX)
//					LCD_PrintString(0,0,"The humidity is too high!!!");
//				else if(Humidity < HUM_MIN)
//					LCD_PrintString(0,0,"The humidity is too low!!!");
//			}
//			break;
//		}		}
}void Task_Prime(void)
{Task_Key();if(DataRead_Count == 1){Task_DataCollect();DataRead_Count = 0;}Task_Alarm();Task_OLED();
}void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM2){++Timer_2000ms;++Timer_Blink;if(Timer_2000ms >= 2000){DataRead_Count++;Timer_2000ms = 0;}if(Timer_Blink >= 650){Blink_Count ^= 1;Timer_Blink = 0;}}
}

五.最终效果

实物

功能演示 

基于STM32的PM2.5监测系统

六.总结

        通过本项目的实践,不仅实现了基础功能监测,还为未来更复杂的项目打下了坚实的基础。希望读者通过该项目,也能够掌握模块化开发的思路,逐步进阶!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ReactPress最佳实践—搭建导航网站实战

Github项目地址&#xff1a;https://github.com/fecommunity/easy-blog 欢迎Star。 近期&#xff0c;阮一峰在科技爱好者周刊第 325 期中推荐了一款开源工具——ReactPress&#xff0c;ReactPress一个基于 Next.js 的博客和 CMS 系统&#xff0c;可查看 demo站点。&#xff08;…

2024,大模型杀进“决赛圈”

Henry Chesbrough在著作《通过技术创新盈利势在必行》中&#xff0c;曾提出过一个创新的“漏斗模型”。开放式创新一开始鼓励百花齐放&#xff0c;但最终只有10%的技术能够通过这个漏斗&#xff0c;成功抵达目标市场target market&#xff0c;进入到商业化与产业化的下一个阶段…

STM8单片机学习笔记·GPIO的片上外设寄存器

目录 前言 IC基本定义 三极管基础知识 单片机引脚电路作用 STM8GPIO工作模式 GPIO外设寄存器 寄存器含义用法 CR1&#xff1a;Control Register 1 CR2&#xff1a;Control Register 2 ODR&#xff1a;Output Data Register IDR&#xff1a;Input Data Register 赋值…

【CSS in Depth 2 精译_081】 13.1:CSS 渐变效果(下)——CSS 径向渐变(13.1.3)+ CSS 锥形渐变(13.1.4)

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第四部分 视觉增强技术 ✔️【第 13 章 渐变、阴影与混合模式】 ✔️ 13.1 渐变 ✔️ 13.1.1 使用多个颜色节点&#xff08;上&#xff09;13.1.2 颜色插值方法&#xff08;中&#xff09;13.1.3 径…

ubuntu 用 ss-tproxy的最终网络结构

1、包含了AD广告域名筛选 2、Ss-tproxy 国内国外地址分类 3、chinadns-ng解析 4、透明网关 更多细节看之前博客 ubuntu 用ss-TPROXY实现透明代理&#xff0c;基于TPROXY的透明TCP/UDP代理,在 Linux 2.6.28 后进入官方内核。ubuntu 用 ss-tproxy的内置 DNS 前挂上 AdGuardHome…

BUUCTF Pwn [HarekazeCTF2019]baby_rop2 题解

下载 得到两个文件 checksec 64位 拖入IDA64 查看main函数 看到给了个libc说明这题是ret2libc题 这里的打印函数是printf 所以利用printf函数的plt输出真实地址got 但printf的got好像不行 所以换成了read的got 因为这是64位程序 所以用寄存器传参&#xff1b;又因为printf得…

语音识别失败 chrome下获取浏览器录音功能,因为安全性问题,需要在localhost或127.0.0.1或https下才能获取权限

环境&#xff1a; Win10专业版 谷歌浏览器 版本 131.0.6778.140&#xff08;正式版本&#xff09; &#xff08;64 位&#xff09; 问题描述&#xff1a; 局域网web语音识别出现识别失败 chrome控制台出现下获取浏览器录音功能&#xff0c;因为安全性问题&#xff0c;需要在…

【一本通】输入两个不同的数,通过指针对两个数进行相加和相乘

【一本通】输入两个不同的数&#xff0c;通过指针对两个数进行相加和相乘 C语言代码C代码Java代码 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 输入两个不同的数&#xff0c;通过指针对两个数进行相加和相乘&#xff0c;并输出。 输入 …

X.game解析柚子币提升速效双向利好和年中历史新低原因

柚子币最新消息&#xff0c;币安宣布将于2024年9月25日21:00左右暂停柚子币网络上的代币存取业务&#xff0c;以全力支持即将到来的柚子币网络升级和硬分叉&#xff0c;这一消息为柚子币的未来发展增添了新的期待和变数。 除了速度的提升&#xff0c;Spring1.0还带来了诸多技术…

redis集群安装部署 redis三主三从集群

redis集群安装部署 redis三主三从集群 1、下载redis2、安装redis集群 三主三从3、配置redis开机自启动3.1、建立启动脚本3.2、复制多份redis启动脚本给集群使用3.3、添加可执行权限3.4、配置开机自启动 1、下载redis 本次redis安装部署选择当前最新的稳定版本7.4.1 下载链接: …

数据结构,链表的简单使用

任意位置删除&#xff1a; void Any_Del(LinkListPtr h,int a)//任意删 {if(NULLh||a>h->len){printf("删除失败");}LinkListPtr ph;for(int i0;i<a-1;i){pp->next;}LinkListPtr p2p;p2p2->next;p->nextp->next->next;free(p2);p2NULL;h-&g…

Servlet容器来扫描指定包中的类 找到带有WebServlet注解的类

项目框架如上图 myweb下边三个类 package com.qcby.tomcat.myweb;import com.qcby.tomcat.webServlet.WebServlet;WebServlet(urlPatterns {"MyFirstServlet"}) public class MyFirstServlet {}package com.qcby.tomcat.myweb;import com.qcby.tomcat.webServlet.W…

两数之和(Hash表)

优质博文&#xff1a;IT-BLOG-CN 一、题目 给定一个整数数组nums和一个整数目标值target&#xff0c;请你在该数组中找出"和"为目标值target的那两个整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元…

C++8--赋值运算符重载

1.运算符重载 C引入运算符的目的是为了增强代码的可读性。运算符重载是具有特殊函数名的函数&#xff0c;也具有其返回值类型&#xff0c;函数名字以及参数列表&#xff0c;其返回值类型与参数列表与普通的函数相似。 函数名字为&#xff1a;关键字operator后面接需要重载的运算…

pyfink1.20版本下实现消费kafka中数据并实时计算

1、环境 JDK版本&#xff1a;1.8.0_412python版本&#xff1a;3.10.6apache-flink版本&#xff1a;1.20.0flink版本&#xff1a;1.20kafka版本&#xff1a;kafka_2.12-3.1.1flink-sql-connector-kafka版本&#xff1a;3.3.0-1.202、执行python-flink脚本 从kafka的demo获取消…

数据结构速成

1. 数据结构与算法 2. 顺序表 3. 链表 4. 栈与队列 5. 串 6. 树与二叉树&#xff08;1&#xff09; 7. 树与二叉树&#xff08;2&#xff09; 8. 图 9. 图的应用 10. 查找 11. 排序&#xff08;1&#xff09; 12. 排序&#xff08;2&#xff09;

从源码层级深入探索 Spring AMQP 如何在 Spring Boot 中实现 RabbitMQ 集成——消费者如何进行消费

本章节主要从底层源码探索Spring Boot中RabbitMQ如何进行消费&#xff0c;至于RabbitMQ是如何使用如何生产消息&#xff0c;本章不做过多介绍&#xff0c;感兴趣的小伙伴可以参考&#xff1a;从源码层级深入探索 Spring AMQP 如何在 Spring Boot 中实现 RabbitMQ 集成——生产者…

计算机视觉中的边缘检测算法

摘要&#xff1a; 本文全面深入地探讨了计算机视觉中的边缘检测算法。首先阐述了边缘检测的重要性及其在计算机视觉领域的基础地位&#xff0c;随后详细介绍了经典的边缘检测算法&#xff0c;包括基于梯度的 Sobel 算子算法、Canny 边缘检测算法等&#xff0c;深入剖析了它们的…

Unix 和 Windows 的有趣比较

Unix 和 Windows NT 比较 来源于这两本书&#xff0c;把两本书对照来读&#xff0c;发现很多有意思的地方&#xff1a; 《Unix 传奇》 https://book.douban.com/subject/35292726/ 《观止 微软创建NT和未来的夺命狂奔 》 Showstopper!: The Breakneck Race to Create Windows…

SSM 垃圾分类系统——高效分类的科技保障

第五章 系统功能实现 5.1管理员登录 管理员登录&#xff0c;通过填写用户名、密码、角色等信息&#xff0c;输入完成后选择登录即可进入垃圾分类系统&#xff0c;如图5-1所示。 图5-1管理员登录界面图 5.2管理员功能实现 5.2.1 用户管理 管理员对用户管理进行填写账号、姓名、…