基于STM32设计的城市环境监测看板(环境噪声、环境温湿度、粉尘浓度)

2023-12-21 09:17:07 浏览数 (1)

一、前言

随着城市人口规模的不断扩大和城市化进程的不断加速,城市环境污染问题越来越受到人们的关注。环境监测是评估环境污染状况、制定环保政策、维护人民身体健康的重要手段之一。传统的环境监测手段需要人工参与,成本高、效率低,不能满足大规模的实时监测需求。

本项目基于STM32设计的城市环境监测看板,实现对城市环境噪声、温湿度和粉尘浓度的实时监测和数据采集。 主控芯片采用STM32F103C8T6,具有较高的性能和稳定性,能够有效处理各种传感器采集的数据;环境噪声传感器采用ADC输出模拟信号表示环境噪声强度,能够准确测量城市环境噪声;环境温湿度传感器采用DHT11,具有高精度、快速响应和成本低廉等优点,能够准确测量城市环境的温湿度;粉尘浓度模块采用PM2.5粉尘浓度检测模块GP2Y10,能够实时快速地检测城市空气中的PM2.5粉尘浓度,为环境污染控制提供数据支持。

在本项目中,通过对不同传感器和主控芯片的选择和应用,成功设计了一款城市环境监测看板,能够实时监测和记录城市环境的噪声、温湿度和粉尘浓度等信息,为城市环保管理部门和公众提供了有力的数据支持。

二、项目整体设计思路

2.1 硬件设计思路

(1)主控芯片选择:本项目选用了STM32F103C8T6作为主控芯片,该芯片具有高性能、低功耗和丰富的外设资源,可以满足环境监测系统的要求。

(2)传感器选择:环境噪声传感器采用ADC输出模拟信号的方式来表示环境噪声强度,这里可以选择常见的电容麦克风或者MEMS麦克风作为传感器。环境温湿度传感器采用DHT11,它是一种数字式温湿度传感器,具有成本低廉、响应速度快的特点。粉尘浓度模块采用GP2Y10,它是一种激光散射式粉尘传感器,能够实时检测空气中的PM2.5粉尘浓度。

(3)连接方式:将传感器与主控芯片连接,可以通过使用模拟输入通道连接环境噪声传感器的输出,通过GPIO口连接DHT11传感器和GP2Y10传感器。

(4)电源设计:根据系统需求选择合适的电源模块,保证系统的稳定供电。

2.2 软件设计思路

(1)系统初始化:在程序开始时进行系统的初始化,包括GPIO口初始化、ADC模块初始化等。

(2)传感器数据采集:通过主控芯片的GPIO口或者ADC模块采集环境噪声、温湿度和粉尘浓度传感器的数据。对于环境噪声传感器,利用ADC模块将模拟信号转换为数字量;对于DHT11和GP2Y10传感器,直接读取其数字输出。

(3)数据处理与显示:将采集到的传感器数据进行处理,并通过LCD显示屏或者其他输出方式实时展示结果。可以设计相应的算法进行数据滤波、校正或者转换为可读格式。同时,根据不同的数据范围,可以设置合适的阈值来判断环境的状态是否达到预警水平。

(4)网络通信:通过网络模块(ESP8266)将数据传输到远程监控终端和云平台,实现远程监控和数据存储。可以使用HTTP、MQTT等协议进行数据传输,保证数据的安全性和可靠性。

(5)系统控制:设计合适的用户界面和控制方式,使用户能够方便地操作本项目。可以通过按键、触摸屏或者无线遥控等方式进行系统的开关、参数调节等操作。

三、硬件连线

(1)环境噪声传感器(模拟信号输出):

将传感器的模拟输出连接到STM32的一个ADC输入通道(PA0)。

(2)环境温湿度传感器(DHT11):

将DHT11的VCC引脚连接到STM32的3.3V电源。

将DHT11的GND引脚连接到STM32的GND引脚。

将DHT11的DATA引脚连接到STM32的一个GPIO输入引脚(PB0)。

(3)粉尘浓度模块(GP2Y10):

将GP2Y10的VCC引脚连接到STM32的3.3V电源。

将GP2Y10的GND引脚连接到STM32的GND引脚。

将GP2Y10的Vo引脚连接到STM32的一个ADC输入通道(PA1)。

(4)OLED显示屏(0.96寸OLED):

将OLED显示屏的SDA引脚连接到STM32的I2C总线的SDA引脚(PB7)。

将OLED显示屏的SCL引脚连接到STM32的I2C总线的SCL引脚(PB6)。

将OLED显示屏的VCC引脚连接到STM32的3.3V电源。

将OLED显示屏的GND引脚连接到STM32的GND引脚。

四、项目代码设计

4.1 主核心代码

代码语言:javascript复制
// 初始化GPIO和ADC模块
// 启用I2C总线
// 初始化OLED显示屏驱动程序

// 循环读取传感器数据并显示
while(1) {
    // 读取环境噪声传感器的模拟信号并转换为数字值
    int noise = read_adc();
  
    // 通过GPIO读取DHT11传感器的温湿度数据
    float temperature, humidity;
    read_DHT11(&temperature, &humidity);
  
    // 读取粉尘浓度的模拟电压信号并转换为PM2.5颗粒物浓度值
    float dust_level = read_GP2Y10();
  
    // 将读取的数据显示在OLED屏幕上
    oled_clear();
    oled_print_string("Noise: "   noise   "dB");
    oled_print_string("Temp: "   temperature   "C");
    oled_print_string("Humidity: "   humidity   "%");
    oled_print_string("Dust Level: "   dust_level   "ug/m^3");

    // 根据需要设置警报阈值并发出警报
    if (noise > 70 || temperature > 30 || dust_level > 50) {
        beep_alarm();
    }
  
    // 等待一段时间再进行下一次循环
    delay_ms(1000);
}

4.2 模块子函数代码

代码语言:javascript复制
#include "stm32f1xx_hal.h"
#include "ssd1306.h"

void GPIO_Init(void) {
    // 初始化GPIO引脚
    
    // 设置环境噪声传感器的模拟输入引脚为模拟输入模式
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;  // 使能GPIOA时钟
    GPIOA->CRL &= ~GPIO_CRL_MODE0;      // 复位模式寄存器中的MODE0位
    GPIOA->CRL &= ~GPIO_CRL_CNF0;       // 复位配置寄存器中的CNF0位

    // 设置DHT11的DATA引脚为上拉输入模式
    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;  // 使能GPIOB时钟
    GPIOB->CRL &= ~GPIO_CRL_MODE0;      // 复位模式寄存器中的MODE0位
    GPIOB->CRL &= ~GPIO_CRL_CNF0_0;     // 复位配置寄存器中的CNF0位
    GPIOB->CRL |= GPIO_CRL_CNF0_1;      // 设置为上拉输入模式

    // 初始化其他GPIO引脚,例如GP2Y10的Vo引脚和I2C总线的引脚等
}

void ADC_Init(void) {
    // 初始化ADC模块
    
    // 使能ADC1时钟
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; 
    
    // 配置ADC通道和采样时间
    ADC1->SMPR2 |= ADC_SMPR2_SMP0_2;   // 设置ADC通道为第0个通道,并设置采样时间为28.5个周期
    
    // 配置ADC转换模式为单次转换模式
    ADC1->CR2 &= ~ADC_CR2_CONT;        // 关闭连续转换模式,使用单次转换模式
    
    // 配置ADC转换触发源为软件触发
    ADC1->CR2 &= ~ADC_CR2_EXTSEL;      // 清除外部触发选择位
    ADC1->CR2 |= ADC_CR2_EXTSEL_0;     // 设置为软件触发模式
    
    // 使能ADC模块
    ADC1->CR2 |= ADC_CR2_ADON;
}

void I2C_Init(void) {
    // 初始化I2C总线
    
    // 使能I2C1时钟
    RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
    
    // 配置I2C总线时钟频率
    I2C1->CR2 |= 36;   // 根据系统时钟频率和所需的I2C总线速率进行配置
    
    // 配置I2C总线模式和器件地址
    I2C1->CR1 &= ~I2C_CR1_SMBUS;  // 关闭SMBus模式
    I2C1->CR1 |= I2C_CR1_PE;      // 使能I2C总线
    
    // 配置I2C总线的GPIO引脚
    
    // 设置SCL引脚为开漏输出模式
    GPIOB->CRH |= GPIO_CRH_MODE6_0;
    GPIOB->CRH &= ~GPIO_CRH_MODE6_1;
    GPIOB->CRH |= GPIO_CRH_CNF6_0;
    GPIOB->CRH |= GPIO_CRH_CNF6_1;
    
    // 设置SDA引脚为开漏输出模式
    GPIOB->CRH |= GPIO_CRH_MODE7_0;
    GPIOB->CRH &= ~GPIO_CRH_MODE7_1;
    GPIOB->CRH |= GPIO_CRH_CNF7_0;
    GPIOB->CRH |= GPIO_CRH_CNF7_1;
}

void OLED_Init(void) {
    // 初始化OLED显示屏驱动程序
    
    ssd1306_Init();  // 使用 SSD1306 驱动程序进行初始化
}

void System_Init(void) {
    // 初始化系统组件
    
    HAL_Init();   // 使用HAL库进行初始化,如果没有使用HAL库,可以根据芯片厂商提供的库进行初始化
    
    GPIO_Init();  // 初始化GPIO
    ADC_Init();   // 初始化ADC模块
    I2C_Init();   // 初始化I2C总线
    OLED_Init();  // 初始化OLED显示屏驱动程序
}

4.3 OLED驱动代码

代码语言:javascript复制
#include "stm32f10x.h"
#include "OLED.h"

#define OLED_CS_GPIO    GPIOB
#define OLED_CS_PIN     GPIO_Pin_12
#define OLED_DC_GPIO    GPIOB
#define OLED_DC_PIN     GPIO_Pin_13
#define OLED_RST_GPIO   GPIOB
#define OLED_RST_PIN    GPIO_Pin_14

void Delay_ms(uint16_t time) {
    while(time--) {
        uint16_t i = 12000;  // 延时大概1ms
        while(i--);
    }
}

void GPIO_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    // CS引脚配置
    GPIO_InitStruct.GPIO_Pin = OLED_CS_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(OLED_CS_GPIO, &GPIO_InitStruct);
    
    // DC引脚配置
    GPIO_InitStruct.GPIO_Pin = OLED_DC_PIN;
    GPIO_Init(OLED_DC_GPIO, &GPIO_InitStruct);
    
    // RST引脚配置
    GPIO_InitStruct.GPIO_Pin = OLED_RST_PIN;
    GPIO_Init(OLED_RST_GPIO, &GPIO_InitStruct);
}

void SPI_Init(void) {
    SPI_InitTypeDef SPI_InitStruct;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

    // SPI总线配置
    SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;
    SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;
    SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
    SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_Init(SPI1, &SPI_InitStruct);

    SPI_Cmd(SPI1, ENABLE);
}

void OLED_WriteCmd(uint8_t cmd) {
    GPIO_ResetBits(OLED_CS_GPIO, OLED_CS_PIN);  // 片选信号拉低,开始传输数据命令
    GPIO_ResetBits(OLED_DC_GPIO, OLED_DC_PIN);  // DC信号拉低,表示发送命令
    SPI_SendData8(SPI1, cmd);                   // 发送命令
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);
    GPIO_SetBits(OLED_CS_GPIO, OLED_CS_PIN);    // 片选信号拉高,结束传输数据命令
}

void OLED_WriteData(uint8_t data) {
    GPIO_ResetBits(OLED_CS_GPIO, OLED_CS_PIN);  // 片选信号拉低,开始传输数据
    GPIO_SetBits(OLED_DC_GPIO, OLED_DC_PIN);    // DC信号拉高,表示发送数据
    SPI_SendData8(SPI1, data);                  // 发送数据
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);
    GPIO_SetBits(OLED_CS_GPIO, OLED_CS_PIN);    // 片选信号拉高,结束传输数据
}

void OLED_Init(void) {
    GPIO_Init();
    SPI_Init();
    
    GPIO_SetBits(OLED_RST_GPIO, OLED_RST_PIN);  // OLED复位
    Delay_ms(100);
    GPIO_ResetBits(OLED_RST_GPIO, OLED_RST_PIN);
    Delay_ms(100);
    GPIO_SetBits(OLED_RST_GPIO, OLED_RST_PIN);

    OLED_WriteCmd(0xAE);  // 关闭OLED显示屏
    OLED_WriteCmd(0x20);  // 设置内存地址模式:水平地址模式
    OLED_WriteCmd(0x10);  // 设置高四位地址
    OLED_WriteCmd(0xb0);  // 设置起始行为0
    OLED_WriteCmd(0xc8);  // 设置扫描方向:从上到下
    OLED_WriteCmd(0x00);  // 设置低八位地址
    OLED_WriteCmd(0x10);  // 设置高四位地址
    OLED_WriteCmd(0x40);  // 设置起始列为0
    OLED_WriteCmd(0x81);  // 设置对比度控制
    OLED_WriteCmd(0xff);  // 对比度值(0-255)
    OLED_WriteCmd(0xa1);  // 设置段重映射
    OLED_WriteCmd(0xa6);  // 设置正常/反相显示模式:正常显示
    OLED_WriteCmd(0xa8);  // 设置多路复用比率
    OLED_WriteCmd(0x3F);  // 值越大,亮度越大
    OLED_WriteCmd(0xa4);  // 设置全局显示:开启显示
    OLED_WriteCmd(0xd3);  // 设置显示偏移
    OLED_WriteCmd(0x00);  // 不偏移
    OLED_WriteCmd(0xd5);  // 设置频率分区
    OLED_WriteCmd(0xf0);  // 频率分区
    OLED_WriteCmd(0xd9);  // 设置预充电周期
    OLED_WriteCmd(0x22);  // 值越大,亮度越弱
    OLED_WriteCmd(0xda);  // 设置COM硬件扫描方式
    OLED_WriteCmd(0x12);  // 按列扫描
    OLED_WriteCmd(0xdb);  // 设置VCOMH电压倍率
    OLED_WriteCmd(0x20);  // 1.00*VCC
    OLED_WriteCmd(0x8d);  // 设置充电泵开关
    OLED_WriteCmd(0x14);  // 开启充电泵
    OLED_WriteCmd(0xaf);  // 开启OLED显示屏
}

void OLED_Puts(uint8_t x, uint8_t y, char *str) {
    uint8_t i = 0;
    while(str[i] != '') {
        OLED_SetCursor(x   i * 6, y);
        for(uint8_t j = 0; j < 6; j  ) {
            OLED_WriteData(Font_6x8[(str[i] - 32) * 6   j]);
        }
        i  ;
    }
}

int OLED(void) {
    OLED_Init();
    OLED_Clear();
}

五、总结

城市环境监测看板,基于STM32F103C8T6主控芯片以及环境噪声、温湿度和粉尘浓度传感器的数据采集,实现了对城市环境的实时监测。该系统能够准确获取环境噪声强度、温湿度和粉尘浓度等信息,为城市规划和环境保护提供了重要的参考数据。

通过使用ADC来采集环境噪声传感器输出的模拟信号,再结合处理算法,系统能够精确测量环境中的噪声水平。而DHT11温湿度传感器则提供了准确的温度和湿度数据,帮助了解城市环境的舒适度和变化情况。另外,利用PM2.5粉尘浓度检测模块GP2Y10,可以得到城市空气中细颗粒物的浓度信息,从而评估空气质量状况。

这个城市环境监测看板不仅能够及时获取环境数据,还具备数据显示和报警功能。通过LCD显示屏,可以直观地查看当前环境的噪声、温湿度和粉尘浓度数值,以及相应的报警状态。当某项数据超过设定的阈值时,看板将发出警报提示,提醒人们采取相应的措施。

这个项目的设计和实现为城市规划和环境保护提供了重要的技术支持。通过实时监测城市环境的噪声、温湿度和粉尘浓度等指标,可以评估城市生活质量、改善城市环境,从而创建更加宜居、健康的城市环境。此外,该系统还可以应用于智能交通管理、工业区域监测等领域,提高城市安全性和环境可持续发展水平。

随着物联网和智慧城市的发展,城市环境监测看板有着广阔的应用前景。通过不断的技术创新和数据分析,可以更好地了解城市环境与人类生活的关系,为构建宜居、绿色、可持续发展的城市做出积极的贡献。

0 人点赞