【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.pswp.cn/web/63129.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/63129.shtml
英文地址,請注明出處:http://en.pswp.cn/web/63129.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

《開源數據:開啟信息共享與創新的寶藏之門》

《開源數據&#xff1a;開啟信息共享與創新的寶藏之門》 一、開源數據概述&#xff08;一&#xff09;開源數據的定義&#xff08;二&#xff09;開源數據的發展歷程 二、開源數據的優勢&#xff08;一&#xff09;成本效益優勢&#xff08;二&#xff09;靈活性與可定制性&…

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 賦值…

頁面加載速度優化策略:提升用戶體驗的關鍵

文章目錄 前言一、為什么需要優化頁面加載速度&#xff1f;二、前端優化技術三、后端優化策略四、構建與部署優化五、案例研究&#xff1a;實際效果展示結語 前言 在當今快節奏的互聯網環境中&#xff0c;頁面加載速度不僅是用戶體驗的重要組成部分&#xff0c;更是影響網站性…

【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 徑…

商務禮儀學習筆記

時間,場合,地點 女士: 1. 著裝(裙裝套裝,最短不能超過膝蓋一拳,裙子形狀直通,顏色簡單不能花里胡哨,上下顏色不能超過三種,深灰深藍;上下顏色,裝飾,面料統一;絲襪不要過于花,肉色透明比較推薦) 2. 妝容和發型(經過搭理,不要毛躁; 膚色保持一致,均衡;腮紅…

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…

iOS swift開發系列--如何給swiftui內容視圖添加背景圖片顯示

我需要在swiftui項目中顯示背景圖&#xff0c;有兩種方式&#xff0c;一種是把圖片拖入asset資源中&#xff0c;另外一種是直接把圖片放在源碼目錄下。采用第一種方式&#xff0c;直接把圖片拖到資源目錄&#xff0c;但是swiftui項目沒有彈出&#xff0c; “Copy items if need…

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;需要在…

【前端知識】Javascript進階-類和繼承

文章目錄 概述一、類&#xff08;Class&#xff09;二、繼承&#xff08;Inheritance&#xff09; 三、繼承的實現方式作用一、類和作用二、繼承和作用 概述 當然可以&#xff0c;以下是對JavaScript中類和繼承的詳細介紹&#xff1a; 一、類&#xff08;Class&#xff09; 定…

前端搭建企業級項目的具體步驟?

?前端搭建企業級項目的具體步驟如下?&#xff1a; ?確定項目技術棧和規劃項目結構?&#xff1a;首先&#xff0c;確定使用的前端框架&#xff0c;如Vue.js&#xff0c;并規劃項目的目錄結構&#xff0c;包括src、components、routes、store等?。 ?準備開發環境?&#x…

Less和SCSS,哪個更好用?

前言 Less 和 SCSS 都是流行的 CSS 預處理器&#xff0c;它們的目的都是擴展 CSS 的功能&#xff0c;使樣式表更具組織性、可維護性和可重用性。雖然它們有許多相似之處&#xff0c;但在語法、特性和工作方式上也存在一些差異。 Less Less 是一種動態樣式表語言&#xff0c;…

【第三節】Git 基本操作指南

目錄 前言 一、獲取與創建項目 1.1 git init 1.2 git clone 二、基本快照操作 2.1 git add 2.2 git status 2.3 git diff 2.4 git commit 2.5 git reset HEAD 三、 文件管理 3.1 git rm 3.2 git mv 四、 總結 前言 本文將詳細介紹 Git 的基本操作&#xff0c;包括…

【Graylog】索引別名deflector的異常處理和索引分片數限制解除

索引別名deflector的異常處理 官方推薦處理步驟 Stop all Graylog nodes (OPTIONAL) If you want to keep the already ingested messages, reindex them into the Elasticsearch index with the greatest number, e. g. graylog_23 if you want to fix the deflector graylo…

PyTorch 2.0 以下版本中設置默認使用 GPU 的方法

PyTorch 2.0 以下版本中設置默認使用 GPU 的方法 在 PyTorch 2.0以下版本中&#xff0c;默認情況下仍然是使用 CPU 進行計算&#xff0c;除非明確指定使用 GPU。在 PyTorch 2.0 以下版本中&#xff0c;雖然沒有 torch.set_default_device 的便捷方法&#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 下載鏈接: …