STM32智能温湿度监测系统完整代码
工程结构
project/
├── Core/
│ ├── Inc/
│ │ ├── dht22.h
│ │ ├── oled.h
│ │ ├── beep.h
│ │ └── config.h
│ └── Src/
│ ├── main.c
│ ├── dht22.c
│ ├── oled.c
│ └── beep.c
└── Drivers/
└── STM32F1xx_HAL_Driver/
1. 配置文件 config.h
#ifndef __CONFIG_H
#define __CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
#define DEBUG_MODE 1
#define SYS_CLOCK_FREQ 72000000
#define DHT22_PIN GPIO_PIN_0
#define DHT22_PORT GPIOA
#define DHT22_TIMEOUT 1000
#define OLED_I2C I2C1
#define OLED_ADDRESS 0x78
#define OLED_WIDTH 128
#define OLED_HEIGHT 64
#define BEEP_PIN GPIO_PIN_1
#define BEEP_PORT GPIOA
#define BEEP_ON_TIME 500
#define DEBUG_UART USART1
#define UART_BAUDRATE 115200
#define TEMP_ALARM_THRESHOLD 30.0f
#define HUMIDITY_ALARM_THRESHOLD 80.0f
#define SAMPLE_INTERVAL_MS 2000
typedef enum {
ERROR_NONE = 0,
ERROR_DHT22_TIMEOUT,
ERROR_DHT22_CHECKSUM,
ERROR_OLED_INIT_FAILED,
ERROR_OLED_COMM_FAILED,
ERROR_I2C_BUSY,
ERROR_I2C_ERROR
} ErrorCode_t;
#ifdef __cplusplus
}
#endif
#endif
2. DHT22 驱动文件 dht22.h
#ifndef __DHT22_H
#define __DHT22_H
#include "stm32f1xx_hal.h"
#include "config.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
float temperature;
float humidity;
uint8_t is_valid;
ErrorCode_t last_error;
uint32_t last_read_time;
} DHT22_Data_t;
void DHT22_Init(void);
ErrorCode_t DHT22_ReadData(DHT22_Data_t *data);
float DHT22_GetTemperature(void);
float DHT22_GetHumidity(void);
void DHT22_DelayMicroseconds(uint32_t us);
#ifdef __cplusplus
}
#endif
#endif
3. DHT22 驱动文件 dht22.c
#include "dht22.h"
#include <string.h>
#include <stdio.h>
static DHT22_Data_t dht22_data = {0};
static TIM_HandleTypeDef htim_delay;
static void DHT22_DelayInit(void)
{
__HAL_RCC_TIM2_CLK_ENABLE();
htim_delay.Instance = TIM2;
htim_delay.Init.Prescaler = 72 - 1;
htim_delay.Init.CounterMode = TIM_COUNTERMODE_UP;
htim_delay.Init.Period = 0xFFFFFFFF;
htim_delay.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim_delay);
HAL_TIM_Base_Start(&htim_delay);
}
void DHT22_DelayMicroseconds(uint32_t us)
{
uint32_t start = __HAL_TIM_GET_COUNTER(&htim_delay);
while ((__HAL_TIM_GET_COUNTER(&htim_delay) - start) < us);
}
void DHT22_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = DHT22_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DHT22_PORT, &GPIO_InitStruct);
DHT22_DelayInit();
HAL_GPIO_WritePin(DHT22_PORT, DHT22_PIN, GPIO_PIN_SET);
dht22_data.is_valid = 0;
dht22_data.last_error = ERROR_NONE;
#if DEBUG_MODE
printf("[DHT22] Initialized successfully\r\n");
#endif
}
ErrorCode_t DHT22_ReadData(DHT22_Data_t *data)
{
uint8_t bits[5] = {0};
uint8_t checksum = 0;
uint32_t timeout = 0;
uint8_t i, j;
if (data == NULL) {
return ERROR_DHT22_TIMEOUT;
}
HAL_GPIO_WritePin(DHT22_PORT, DHT22_PIN, GPIO_PIN_RESET);
DHT22_DelayMicroseconds(1000);
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = DHT22_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(DHT22_PORT, &GPIO_InitStruct);
DHT22_DelayMicroseconds(30);
timeout = 0;
while (HAL_GPIO_ReadPin(DHT22_PORT, DHT22_PIN) == GPIO_PIN_RESET) {
timeout++;
DHT22_DelayMicroseconds(1);
if (timeout > 100) {
dht22_data.last_error = ERROR_DHT22_TIMEOUT;
#if DEBUG_MODE
printf("[DHT22] Timeout waiting for low response\r\n");
#endif
return ERROR_DHT22_TIMEOUT;
}
}
timeout = 0;
while (HAL_GPIO_ReadPin(DHT22_PORT, DHT22_PIN) == GPIO_PIN_SET) {
timeout++;
DHT22_DelayMicroseconds(1);
if (timeout > 100) {
dht22_data.last_error = ERROR_DHT22_TIMEOUT;
return ERROR_DHT22_TIMEOUT;
}
}
for (i = 0; i < 5; i++) {
for (j = 0; j < 8; j++) {
timeout = 0;
while (HAL_GPIO_ReadPin(DHT22_PORT, DHT22_PIN) == GPIO_PIN_RESET) {
timeout++;
DHT22_DelayMicroseconds(1);
if (timeout > 100) {
dht22_data.last_error = ERROR_DHT22_TIMEOUT;
return ERROR_DHT22_TIMEOUT;
}
}
uint32_t high_time = 0;
while (HAL_GPIO_ReadPin(DHT22_PORT, DHT22_PIN) == GPIO_PIN_SET) {
high_time++;
DHT22_DelayMicroseconds(1);
if (high_time > 100) {
break;
}
}
bits[i] <<= 1;
if (high_time > 40) {
bits[i] |= 0x01;
}
}
}
checksum = bits[0] + bits[1] + bits[2] + bits[3];
if (checksum != bits[4]) {
dht22_data.last_error = ERROR_DHT22_CHECKSUM;
#if DEBUG_MODE
printf("[DHT22] Checksum error: %d != %d\r\n", checksum, bits[4]);
#endif
return ERROR_DHT22_CHECKSUM;
}
int16_t temp_raw = ((bits[2] & 0x7F) << 8) | bits[3];
int16_t hum_raw = (bits[0] << 8) | bits[1];
if (bits[2] & 0x80) {
temp_raw = -temp_raw;
}
dht22_data.temperature = temp_raw / 10.0f;
dht22_data.humidity = hum_raw / 10.0f;
dht22_data.is_valid = 1;
dht22_data.last_read_time = HAL_GetTick();
dht22_data.last_error = ERROR_NONE;
if (data != &dht22_data) {
memcpy(data, &dht22_data, sizeof(DHT22_Data_t));
}
#if DEBUG_MODE
printf("[DHT22] Read successful: Temp=%.1f°C, Hum=%.1f%%\r\n",
dht22_data.temperature, dht22_data.humidity);
#endif
return ERROR_NONE;
}
float DHT22_GetTemperature(void)
{
if (!dht22_data.is_valid) {
DHT22_ReadData(NULL);
}
return dht22_data.temperature;
}
float DHT22_GetHumidity(void)
{
if (!dht22_data.is_valid) {
DHT22_ReadData(NULL);
}
return dht22_data.humidity;
}
4. OLED 驱动文件 oled.h
#ifndef __OLED_H
#define __OLED_H
#include "stm32f1xx_hal.h"
#include "config.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define OLED_CMD_SET_CONTRAST 0x81
#define OLED_CMD_DISPLAY_ALL_ON 0xA5
#define OLED_CMD_DISPLAY_NORMAL 0xA6
#define OLED_CMD_DISPLAY_INVERSE 0xA7
#define OLED_CMD_DISPLAY_OFF 0xAE
#define OLED_CMD_DISPLAY_ON 0xAF
#define OLED_CMD_SET_MEMORY_MODE 0x20
#define OLED_CMD_SET_COL_ADDR 0x21
#define OLED_CMD_SET_PAGE_ADDR 0x22
#define OLED_CMD_SET_START_LINE 0x40
#define OLED_CMD_SET_SEG_REMAP 0xA0
#define OLED_CMD_SET_MUX_RATIO 0xA8
#define OLED_CMD_SET_COM_SCAN_DIR 0xC0
#define OLED_CMD_SET_DISPLAY_OFFSET 0xD3
#define OLED_CMD_SET_COM_PINS 0xDA
#define OLED_CMD_SET_DISPLAY_CLK 0xD5
#define OLED_CMD_SET_PRECHARGE 0xD9
#define OLED_CMD_SET_VCOMH_DESELECT 0xDB
#define OLED_CMD_SET_CHARGE_PUMP 0x8D
typedef struct {
uint8_t width;
uint8_t height;
uint8_t is_initialized;
uint8_t buffer[128 * 8];
} OLED_t;
typedef struct {
const uint8_t *data;
uint8_t width;
uint8_t height;
uint8_t first_char;
uint8_t last_char;
} FontDef_t;
ErrorCode_t OLED_Init(I2C_HandleTypeDef *hi2c);
void OLED_Clear(void);
void OLED_Update(void);
void OLED_DrawPixel(uint8_t x, uint8_t y, uint8_t color);
void OLED_DrawChar(uint8_t x, uint8_t y, char ch, FontDef_t *font, uint8_t color);
void OLED_DrawString(uint8_t x, uint8_t y, const char *str, FontDef_t *font, uint8_t color);
void OLED_DrawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t color);
void OLED_DrawRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color);
void OLED_DrawFilledRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color);
void OLED_DrawTemperature(float temp);
void OLED_DrawHumidity(float hum);
extern FontDef_t Font_6x8;
extern FontDef_t Font_7x10;
extern FontDef_t Font_11x18;
extern FontDef_t Font_16x26;
#ifdef __cplusplus
}
#endif
#endif
5. OLED 驱动文件 oled.c
#include "oled.h"
#include <string.h>
#include <stdio.h>
static I2C_HandleTypeDef *hi2c_oled = NULL;
static OLED_t oled = {0};
static const uint8_t Font6x8[][6] = {
{0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x5F,0x00,0x00,0x00},
{0x00,0x07,0x00,0x07,0x00,0x00},
{0x7C,0x12,0x11,0x12,0x7C,0x00},
{0x7F,0x49,0x49,0x49,0x36,0x00},
};
FontDef_t Font_6x8 = {
.data = (uint8_t *)Font6x8,
.width = 6,
.height = 8,
.first_char = ' ',
.last_char = '~'
};
static ErrorCode_t OLED_WriteCommand(uint8_t cmd)
{
if (hi2c_oled == NULL) {
return ERROR_OLED_INIT_FAILED;
}
uint8_t data[2] = {0x00, cmd};
if (HAL_I2C_Master_Transmit(hi2c_oled, OLED_ADDRESS, data, 2, HAL_MAX_DELAY) != HAL_OK) {
#if DEBUG_MODE
printf("[OLED] Failed to send command: 0x%02X\r\n", cmd);
#endif
return ERROR_I2C_ERROR;
}
return ERROR_NONE;
}
static ErrorCode_t OLED_WriteData(uint8_t *data, uint16_t size)
{
if (hi2c_oled == NULL || data == NULL) {
return ERROR_OLED_INIT_FAILED;
}
uint8_t buffer[size + 1];
buffer[0] = 0x40;
memcpy(&buffer[1], data, size);
if (HAL_I2C_Master_Transmit(hi2c_oled, OLED_ADDRESS, buffer, size + 1, HAL_MAX_DELAY) != HAL_OK) {
#if DEBUG_MODE
printf("[OLED] Failed to send data\r\n");
#endif
return ERROR_I2C_ERROR;
}
return ERROR_NONE;
}
ErrorCode_t OLED_Init(I2C_HandleTypeDef *hi2c)
{
if (hi2c == NULL) {
return ERROR_OLED_INIT_FAILED;
}
hi2c_oled = hi2c;
uint8_t init_cmds[] = {
OLED_CMD_DISPLAY_OFF,
OLED_CMD_SET_DISPLAY_CLK,
0x80,
OLED_CMD_SET_MUX_RATIO,
0x3F,
OLED_CMD_SET_DISPLAY_OFFSET,
0x00,
OLED_CMD_SET_START_LINE | 0x00,
OLED_CMD_SET_CHARGE_PUMP,
0x14,
OLED_CMD_SET_MEMORY_MODE,
0x00,
OLED_CMD_SET_SEG_REMAP | 0x01,
OLED_CMD_SET_COM_SCAN_DIR | 0x08,
OLED_CMD_SET_COM_PINS,
0x12,
OLED_CMD_SET_CONTRAST,
0x7F,
OLED_CMD_SET_PRECHARGE,
0xF1,
OLED_CMD_SET_VCOMH_DESELECT,
0x40,
OLED_CMD_DISPLAY_ALL_ON | 0x00,
OLED_CMD_DISPLAY_NORMAL,
OLED_CMD_DISPLAY_ON
};
for (uint16_t i = 0; i < sizeof(init_cmds); i++) {
if (OLED_WriteCommand(init_cmds[i]) != ERROR_NONE) {
return ERROR_OLED_COMM_FAILED;
}
HAL_Delay(10);
}
OLED_Clear();
OLED_Update();
oled.width = OLED_WIDTH;
oled.height = OLED_HEIGHT;
oled.is_initialized = 1;
#if DEBUG_MODE
printf("[OLED] Initialized successfully\r\n");
#endif
return ERROR_NONE;
}
void OLED_Clear(void)
{
memset(oled.buffer, 0, sizeof(oled.buffer));
}
void OLED_Update(void)
{
if (!oled.is_initialized) {
return;
}
for (uint8_t page = 0; page < 8; page++) {
OLED_WriteCommand(0xB0 + page);
OLED_WriteCommand(0x00);
OLED_WriteCommand(0x10);
OLED_WriteData(&oled.buffer[page * 128], 128);
}
}
void OLED_DrawPixel(uint8_t x, uint8_t y, uint8_t color)
{
if (x >= OLED_WIDTH || y >= OLED_HEIGHT) {
return;
}
uint16_t byte_index = x + (y / 8) * 128;
uint8_t bit_mask = 1 << (y % 8);
if (color) {
oled.buffer[byte_index] |= bit_mask;
} else {
oled.buffer[byte_index] &= ~bit_mask;
}
}
void OLED_DrawChar(uint8_t x, uint8_t y, char ch, FontDef_t *font, uint8_t color)
{
if (font == NULL || ch < font->first_char || ch > font->last_char) {
return;
}
uint16_t char_index = ch - font->first_char;
const uint8_t *char_data = &font->data[char_index * font->width];
for (uint8_t i = 0; i < font->width; i++) {
uint8_t line = char_data[i];
for (uint8_t j = 0; j < font->height; j++) {
if (line & 0x01) {
OLED_DrawPixel(x + i, y + j, color);
}
line >>= 1;
}
}
}
void OLED_DrawString(uint8_t x, uint8_t y, const char *str, FontDef_t *font, uint8_t color)
{
if (str == NULL || font == NULL) {
return;
}
uint8_t current_x = x;
while (*str) {
OLED_DrawChar(current_x, y, *str, font, color);
current_x += font->width + 1;
str++;
}
}
void OLED_DrawTemperature(float temp)
{
char buffer[32];
OLED_DrawString(10, 10, "Temperature:", &Font_6x8, 1);
snprintf(buffer, sizeof(buffer), "%.1f C", temp);
OLED_DrawString(10, 25, buffer, &Font_6x8, 1);
OLED_DrawFilledRectangle(90, 10, 4, 30, 1);
OLED_DrawRectangle(90, 10, 4, 30, 1);
OLED_DrawFilledCircle(92, 45, 6, 1);
}
void OLED_DrawHumidity(float hum)
{
char buffer[32];
OLED_DrawString(10, 45, "Humidity:", &Font_6x8, 1);
snprintf(buffer, sizeof(buffer), "%.1f %%", hum);
OLED_DrawString(10, 55, buffer, &Font_6x8, 1);
OLED_DrawFilledCircle(92, 55, 6, 1);
}
void OLED_DrawFilledRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color)
{
for (uint8_t i = 0; i < h; i++) {
for (uint8_t j = 0; j < w; j++) {
OLED_DrawPixel(x + j, y + i, color);
}
}
}
void OLED_DrawFilledCircle(uint8_t x0, uint8_t y0, uint8_t r, uint8_t color)
{
int16_t f = 1 - r;
int16_t ddF_x = 1;
int16_t ddF_y = -2 * r;
int16_t x = 0;
int16_t y = r;
OLED_DrawLine(x0 - r, y0, x0 + r, y0, color);
while (x < y) {
if (f >= 0) {
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x;
OLED_DrawLine(x0 - x, y0 + y, x0 + x, y0 + y, color);
OLED_DrawLine(x0 - x, y0 - y, x0 + x, y0 - y, color);
OLED_DrawLine(x0 - y, y0 + x, x0 + y, y0 + x, color);
OLED_DrawLine(x0 - y, y0 - x, x0 + y, y0 - x, color);
}
}
6. 蜂鸣器驱动文件 beep.h
#ifndef __BEEP_H
#define __BEEP_H
#include "stm32f1xx_hal.h"
#include "config.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
BEEP_OFF = 0,
BEEP_ON,
BEEP_BLINK
} BeepState_t;
typedef struct {
BeepState_t state;
uint32_t on_time;
uint32_t off_time;
uint32_t last_change_time;
uint8_t is_active;
} Beep_t;
void BEEP_Init(void);
void BEEP_On(void);
void BEEP_Off(void);
void BEEP_Blink(uint32_t on_time, uint32_t off_time);
void BEEP_Update(void);
void BEEP_SetAlarm(uint8_t enable);
uint8_t BEEP_IsAlarmEnabled(void);
#ifdef __cplusplus
}
#endif
#endif
7. 蜂鸣器驱动文件 beep.c
#include "beep.h"
#include "main.h"
static Beep_t beep = {0};
void BEEP_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = BEEP_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(BEEP_PORT, &GPIO_InitStruct);
BEEP_Off();
beep.state = BEEP_OFF;
beep.is_active = 0;
#if DEBUG_MODE
printf("[BEEP] Initialized successfully\r\n");
#endif
}
void BEEP_On(void)
{
HAL_GPIO_WritePin(BEEP_PORT, BEEP_PIN, GPIO_PIN_SET);
beep.state = BEEP_ON;
beep.is_active = 1;
beep.last_change_time = HAL_GetTick();
}
void BEEP_Off(void)
{
HAL_GPIO_WritePin(BEEP_PORT, BEEP_PIN, GPIO_PIN_RESET);
beep.state = BEEP_OFF;
beep.is_active = 1;
beep.last_change_time = HAL_GetTick();
}
void BEEP_Blink(uint32_t on_time, uint32_t off_time)
{
beep.state = BEEP_BLINK;
beep.on_time = on_time;
beep.off_time = off_time;
beep.last_change_time = HAL_GetTick();
beep.is_active = 1;
BEEP_On();
}
void BEEP_Update(void)
{
if (!beep.is_active) {
return;
}
uint32_t current_time = HAL_GetTick();
uint32_t elapsed = current_time - beep.last_change_time;
switch (beep.state) {
case BEEP_ON:
if (elapsed >= beep.on_time) {
BEEP_Off();
}
break;
case BEEP_OFF:
if (elapsed >= beep.off_time) {
BEEP_On();
}
break;
case BEEP_BLINK:
if (elapsed >= beep.on_time &&
HAL_GPIO_ReadPin(BEEP_PORT, BEEP_PIN) == GPIO_PIN_SET) {
BEEP_Off();
} else if (elapsed >= beep.off_time &&
HAL_GPIO_ReadPin(BEEP_PORT, BEEP_PIN) == GPIO_PIN_RESET) {
BEEP_On();
}
break;
default:
break;
}
}
void BEEP_SetAlarm(uint8_t enable)
{
if (enable) {
BEEP_Blink(BEEP_ON_TIME, BEEP_ON_TIME);
#if DEBUG_MODE
printf("[BEEP] Alarm activated\r\n");
#endif
} else {
BEEP_Off();
beep.is_active = 0;
#if DEBUG_MODE
printf("[BEEP] Alarm deactivated\r\n");
#endif
}
}
uint8_t BEEP_IsAlarmEnabled(void)
{
return beep.is_active;
}
8. 主函数文件 main.c
#include "main.h"
#include "dht22.h"
#include "oled.h"
#include "beep.h"
#include "config.h"
#include <stdio.h>
#include <string.h>
UART_HandleTypeDef huart1;
I2C_HandleTypeDef hi2c1;
TIM_HandleTypeDef htim2;
typedef struct {
float current_temperature;
float current_humidity;
uint8_t alarm_status;
uint32_t last_sample_time;
uint32_t system_uptime;
ErrorCode_t last_error;
} SystemStatus_t;
static SystemStatus_t system_status = {0};
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
Error_Handler();
}
}
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = UART_BAUDRATE;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK) {
Error_Handler();
}
#if DEBUG_MODE
printf("[UART] Initialized at %d baud\r\n", UART_BAUDRATE);
#endif
}
static void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 400000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK) {
Error_Handler();
}
#if DEBUG_MODE
printf("[I2C] Initialized at 400kHz\r\n");
#endif
}
static void GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
void System_Init(void)
{
HAL_Init();
SystemClock_Config();
GPIO_Init();
MX_USART1_UART_Init();
MX_I2C1_Init();
DHT22_Init();
if (OLED_Init(&hi2c1) != ERROR_NONE) {
printf("[ERROR] OLED initialization failed\r\n");
Error_Handler();
}
BEEP_Init();
printf("\r\n=================================\r\n");
printf("STM32 Temperature Monitor System\r\n");
printf("Version: 1.0.0\r\n");
printf("Compiled: %s %s\r\n", __DATE__, __TIME__);
printf("=================================\r\n\r\n");
printf("[SYSTEM] Initialization complete\r\n");
printf("[SYSTEM] Alarm threshold: %.1f°C\r\n", TEMP_ALARM_THRESHOLD);
}
void Sensor_Update(void)
{
uint32_t current_time = HAL_GetTick();
if (current_time - system_status.last_sample_time >= SAMPLE_INTERVAL_MS) {
DHT22_Data_t dht_data;
ErrorCode_t error = DHT22_ReadData(&dht_data);
if (error == ERROR_NONE) {
system_status.current_temperature = dht_data.temperature;
system_status.current_humidity = dht_data.humidity;
system_status.last_error = ERROR_NONE;
if (system_status.current_temperature > TEMP_ALARM_THRESHOLD) {
if (!system_status.alarm_status) {
system_status.alarm_status = 1;
BEEP_SetAlarm(1);
printf("[ALARM] Temperature exceeds threshold: %.1f°C > %.1f°C\r\n",
system_status.current_temperature, TEMP_ALARM_THRESHOLD);
}
} else {
if (system_status.alarm_status) {
system_status.alarm_status = 0;
BEEP_SetAlarm(0);
printf("[ALARM] Temperature back to normal: %.1f°C\r\n",
system_status.current_temperature);
}
}
OLED_Clear();
OLED_DrawTemperature(system_status.current_temperature);
OLED_DrawHumidity(system_status.current_humidity);
OLED_Update();
printf("[DATA] Temp=%.1f°C, Hum=%.1f%%, Alarm=%d\r\n",
system_status.current_temperature,
system_status.current_humidity,
system_status.alarm_status);
} else {
system_status.last_error = error;
printf("[ERROR] Failed to read DHT22 sensor: %d\r\n", error);
}
system_status.last_sample_time = current_time;
}
}
void System_Update(void)
{
BEEP_Update();
system_status.system_uptime = HAL_GetTick();
static uint32_t led_last_toggle = 0;
if (HAL_GetTick() - led_last_toggle > 500) {
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
led_last_toggle = HAL_GetTick();
}
}
int main(void)
{
System_Init();
printf("[MAIN] Entering main loop...\r\n");
while (1) {
Sensor_Update();
System_Update();
HAL_Delay(10);
}
}
void Error_Handler(void)
{
printf("[FATAL ERROR] System halted!\r\n");
while (1) {
BEEP_On();
HAL_Delay(100);
BEEP_Off();
HAL_Delay(100);
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
printf("Assert failed: file %s on line %d\r\n", file, (int)line);
Error_Handler();
}
#endif
9. main.h 头文件
#ifndef __MAIN_H
#define __MAIN_H
#include "stm32f1xx_hal.h"
#include <stdio.h>
void SystemClock_Config(void);
void Error_Handler(void);
void System_Init(void);
void Sensor_Update(void);
void System_Update(void);
extern UART_HandleTypeDef huart1;
extern I2C_HandleTypeDef hi2c1;
extern TIM_HandleTypeDef htim2;
#endif
10. 使用说明
硬件连接
STM32F103C8T6 (Blue Pill):
- PA0 -> DHT22 DATA
- PA1 -> Buzzer (+)
- PA9 -> USB-TX (通过CH340G)
- PA10 -> USB-RX (通过CH340G)
- PB6 -> OLED SCL
- PB7 -> OLED SDA
- PC13 -> User LED
- 3.3V -> DHT22 VCC, OLED VCC
- GND -> DHT22 GND, OLED GND, Buzzer (-)
编译和下载
- 使用STM32CubeMX生成工程框架
- 将上述文件添加到工程中
- 配置正确的包含路径
- 编译并下载到STM32
功能说明
- 数据采集:每2秒采集一次温湿度数据
- 显示:实时在OLED上显示温度和湿度
- 报警:温度超过30°C时触发蜂鸣器报警
- 通信:通过串口(115200)输出数据到上位机
- 错误处理:包含完善的错误检测和处理机制
上位机通信格式
[DATA] Temp=25.5°C, Hum=60.2%, Alarm=0
[ALARM] Temperature exceeds threshold: 31.2°C > 30.0°C
[ERROR] Failed to read DHT22 sensor: 1
扩展建议
- 添加按键:用于手动关闭报警或调整阈值
- 数据记录:添加SD卡模块存储历史数据
- 网络传输:添加ESP8266 WiFi模块上传数据到云端
- 低功耗模式:使用STM32的低功耗特性延长电池使用时间
- 多传感器:添加光照、气压等传感器