基于华为云的STM32F103C8T6智能停车场管理系统
项目开发背景
随着城市化进程的加速和汽车保有量的持续增长,城市停车资源日益紧张,停车难问题已成为影响居民出行效率和城市交通流畅性的重要挑战。传统停车场管理多依赖人工操作或简单电子设备,存在效率低下、易出错、实时监控能力不足等缺陷,无法满足现代智慧城市对高效、智能停车服务的需求。因此,开发一套基于物联网技术的智能停车场管理系统显得尤为迫切,旨在提升停车资源的利用率和管理自动化水平。
当前许多停车场仍采用人工计数或基础传感器方式,缺乏实时数据采集和远程监控能力,导致车位信息更新延迟、车辆进出统计误差较大,且无法实现数据云端存储与分析。这种管理模式不仅增加了运营成本,还降低了用户体验,难以适应大规模、高流量的停车场景。此外,停车场管理者往往缺乏有效的工具来可视化车位状态和进行数据分析,限制了停车资源的优化配置。
智能停车场管理系统通过集成传感器技术、微控制器、无线通信和云平台,能够实现对车位状态的实时监测、自动计数和数据远程传输,从而显著提高管理效率和准确性。本项目利用STM32F103C8T6作为主控制器,结合红外对射传感器检测车位占用情况,并通过Wi-Fi模块将数据上传至华为云平台,实现数据的集中管理和分析。同时,QT上位机提供直观的图形界面,显示停车场平面图、实时车位状态及统计信息,为管理者和用户提供便捷的监控与查询服务。
该系统的开发不仅响应了智慧城市建设的号召,还体现了物联网技术在解决实际生活问题中的应用价值。通过华为云的集成,系统能够支持大数据处理和远程访问,为停车场运营提供决策支持,并未来可扩展至移动应用或自动驾驶集成,进一步提升智能停车的整体体验。
设计实现的功能
(1)实时监测停车场车位占用状态。
(2)车辆进出自动计数并显示剩余车位。
(3)停车数据及车位状态上传至华为云平台。
(4)QT上位机显示停车场平面图、车位状态及统计信息。
项目硬件模块组成
(1) STM32F103C8T6最小系统核心板作为主控制器。
(2) 4对E18-D80NK红外对射传感器检测车位状态。
(3) 0.96寸OLED显示屏显示剩余车位信息。
(4) ESP8266-01S Wi-Fi模块实现云平台数据传输。
(5) 洞洞板焊接传感器接口电路,杜邦线连接各检测模块。
设计意义
该智能停车场管理系统通过实时监测车位占用状态,能够有效提升停车场的运营效率和管理水平。系统利用红外对射传感器自动检测车辆进出,实现精准计数和剩余车位显示,减少了人工干预的需求,避免了传统管理中可能出现的计数错误和延迟,从而优化了停车体验并提高了场地利用率。
通过将停车数据及车位状态上传至华为云平台,系统实现了数据的远程存储和访问,为停车场管理者提供了强大的数据支持。云平台使得历史数据可追溯、可分析,有助于进行流量统计、趋势预测和决策优化,同时支持多终端访问,增强了管理的灵活性和实时性。
QT上位机显示停车场平面图、车位状态及统计信息,为用户提供了直观的可视化界面。这使得管理员能够轻松监控整个停车场的实时状态,快速响应变化,并生成报告以支持运营决策,提升了管理的便捷性和透明度。
硬件组成基于STM32F103C8T6核心板和常见传感器模块,体现了系统的成本效益和实用性。这种设计采用成熟且低成本的组件,通过简单的电路连接实现功能,确保了系统的可靠性和易部署性,适用于中小型停车场的智能化升级。
设计思路
该系统以STM32F103C8T6最小系统核心板作为主控制器,负责协调整个停车场的智能管理。主控制器通过GPIO接口连接4对E18-D80NK红外对射传感器,这些传感器安装在每个车位的入口处,用于实时检测车位的占用状态。当车辆进入或离开时,红外光束被遮挡或恢复,传感器产生信号变化,主控制器据此判断车位状态的变化。
主控制器实时处理传感器输入信号,进行车辆进出计数,并计算剩余车位数量。计数逻辑基于简单的增减机制,确保数据的准确性。处理后的剩余车位信息通过I2C或SPI接口发送到0.96寸OLED显示屏,以数字或图形形式实时显示,方便现场人员查看。
通过UART接口,主控制器与ESP8266-01S Wi-Fi模块通信,实现网络连接。ESP8266模块配置为STA模式,连接到本地Wi-Fi网络,然后使用MQTT或HTTP协议将停车数据(如车位状态、车辆计数)上传至华为云平台。数据上传包括定期发送和事件触发发送,以确保云平台数据的实时性和可靠性。
华为云平台接收并存储数据后,QT上位机通过云API获取数据,解析并显示停车场平面图、每个车位的实时状态(如占用或空闲)以及统计信息(如总车位、剩余车位、历史数据)。上位机界面设计为图形化,支持用户交互和数据分析,从而实现对停车场的远程监控和管理。
框架图
+-----------------------------+
| 系统框架图 |
+-----------------------------+
|
+------------+ +-------------------+ +-----------------+
| | | | | |
| 红外传感器 |---->| 洞洞板接口电路 |---->| STM32F103C8T6 |
| (4对E18-D80NK) | (焊接) | | 主控制器 |
| | | | | |
+------------+ +-------------------+ +-----------------+
| |
| +-----> OLED显示屏 (0.96寸)
| |
| +-----> ESP8266-01S Wi-Fi模块
| |
| |
| +-----------------+
| | |
+------------------>| 华为云平台 |
| |
+-----------------+
|
|
+-----------------+
| |
| QT上位机 |
| (显示数据) |
| |
+-----------------+
系统总体设计
该系统基于STM32F103C8T6最小系统核心板作为主控制器,实现一个智能停车场管理系统。系统通过红外对射传感器实时监测车位占用状态,并利用Wi-Fi模块将数据上传至华为云平台,同时通过OLED显示屏本地显示剩余车位信息,QT上位机远程展示停车场状态。
硬件组成包括STM32F103C8T6核心板处理传感器数据和控制逻辑,四对E18-D80NK红外对射传感器分别安装于每个车位入口,用于检测车辆进出。0.96寸OLED显示屏连接至核心板,实时显示剩余车位数量。ESP8266-01S Wi-Fi模块通过串口与核心板通信,负责将停车数据发送至华为云平台。传感器接口电路通过洞洞板焊接,并使用杜邦线连接各模块,确保信号稳定传输。
功能实现上,系统持续采集红外传感器的信号变化,当车辆进入或离开车位时,传感器触发中断,主控制器更新车位占用状态并计算剩余车位数量。OLED显示屏动态刷新显示剩余车位,方便现场查看。同时,控制器通过Wi-Fi模块将车位状态和计数数据以JSON格式上传至华为云平台,实现远程数据存储和监控。
数据传输部分,ESP8266模块配置为TCP客户端,连接到华为云MQTT服务器,定期发送车位状态信息。QT上位机应用程序订阅云平台数据,解析后以图形化界面显示停车场平面图、实时车位占用情况及统计信息,如总车位、已占用车位和空闲车位数量,为用户提供直观的管理视图。
系统功能总结
功能名称 | 功能描述 | 实现方式 |
---|---|---|
实时监测车位状态 | 监测停车场车位占用状态 | 使用4对E18-D80NK红外对射传感器检测 |
车辆计数与剩余车位显示 | 自动计数车辆进出并显示剩余车位数 | STM32F103C8T6主控制器处理计数,0.96寸OLED显示屏显示 |
数据上传至云平台 | 将停车数据和车位状态上传到华为云平台 | 通过ESP8266-01S Wi-Fi模块实现数据传输 |
上位机信息显示 | QT上位机显示停车场平面图、车位状态及统计信息 | QT应用程序运行于PC端 |
设计的各个功能模块描述
主控制器模块采用STM32F103C8T6最小系统核心板作为系统核心,负责协调整个停车场的运行,包括实时处理传感器输入、计算车辆进出次数、更新剩余车位数量,并通过内部逻辑管理数据流,确保各模块协同工作。
传感器模块使用4对E18-D80NK红外对射传感器,分别安装在停车场每个车位的入口处,通过检测红外光束是否被遮挡来判断车辆进出状态,并将信号传输至主控制器,实现车位占用情况的实时监测。
显示模块集成0.96寸OLED显示屏,直接连接到主控制器,用于直观显示剩余车位信息,包括当前可用车位数量,方便现场用户快速了解停车场状态,无需额外交互。
通信模块依托ESP8266-01S Wi-Fi模块,实现与华为云平台的数据传输,主控制器将处理后的车位状态和统计信息通过串口发送至Wi-Fi模块,再由模块上传至云平台,支持远程数据存储和访问。
接口电路模块通过洞洞板焊接构建传感器接口电路,提供稳定的电源和信号连接,并使用杜邦线将红外传感器模块可靠地连接到主控制器,确保信号传输的准确性和抗干扰能力。
云平台集成部分由主控制器和Wi-Fi模块共同实现,数据上传至华为云后,平台存储停车记录和实时状态,为远程监控和数据分析提供基础,同时支持上位机应用程序的数据拉取。
上位机显示模块基于QT开发应用程序,从华为云平台获取数据,动态显示停车场平面图、每个车位的占用状态以及统计信息如总车位数和当前占用数,为用户提供图形化监控界面。
上位机代码设计
#include <QMainWindow>
#include <QMqttClient>
#include <QJsonDocument>
#include <QJsonObject>
#include <QLabel>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QWidget>
#include <QStatusBar>
#include <QApplication>
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
// Set up UI
QWidget *centralWidget = new QWidget(this);
setCentralWidget(centralWidget);
QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);
// Graphics scene for parking lot visualization
scene = new QGraphicsScene(this);
view = new QGraphicsView(scene);
mainLayout->addWidget(view);
// Create rectangles for parking slots
slot1 = scene->addRect(0, 0, 50, 50, QPen(), QBrush(Qt::green));
slot2 = scene->addRect(60, 0, 50, 50, QPen(), QBrush(Qt::green));
slot3 = scene->addRect(0, 60, 50, 50, QPen(), QBrush(Qt::green));
slot4 = scene->addRect(60, 60, 50, 50, QPen(), QBrush(Qt::green));
// Labels for status
statusLabel = new QLabel("剩余车位: 4", this);
mainLayout->addWidget(statusLabel);
// Set up MQTT client
client = new QMqttClient(this);
client->setHostname("your_huawei_cloud_mqtt_broker_url"); // Replace with actual broker URL
client->setPort(1883); // Default MQTT port, change if needed
client->setUsername("your_username"); // Replace with actual username
client->setPassword("your_password"); // Replace with actual password
connect(client, &QMqttClient::connected, this, &MainWindow::onConnected);
connect(client, &QMqttClient::messageReceived, this, &MainWindow::onMessageReceived);
client->connectToHost();
// Status bar
statusBar()->showMessage("Connecting to Huawei Cloud...");
}
private slots:
void onConnected() {
statusBar()->showMessage("Connected to Huawei Cloud");
client->subscribe(QMqttTopicFilter("parking/status")); // Subscribe to topic
}
void onMessageReceived(const QByteArray &message, const QMqttTopicName &topic) {
QJsonDocument doc = QJsonDocument::fromJson(message);
if (doc.isNull()) {
statusBar()->showMessage("Received invalid JSON");
return;
}
QJsonObject obj = doc.object();
int slot1State = obj["slot1"].toInt();
int slot2State = obj["slot2"].toInt();
int slot3State = obj["slot3"].toInt();
int slot4State = obj["slot4"].toInt();
int availableSlots = obj["available_slots"].toInt();
// Update slot colors
updateSlotColor(slot1, slot1State);
updateSlotColor(slot2, slot2State);
updateSlotColor(slot3, slot3State);
updateSlotColor(slot4, slot4State);
// Update status label
statusLabel->setText(QString("剩余车位: %1").arg(availableSlots));
statusBar()->showMessage("Data updated");
}
private:
void updateSlotColor(QGraphicsRectItem *slot, int state) {
if (state == 0) {
slot->setBrush(QBrush(Qt::green)); // Free
} else {
slot->setBrush(QBrush(Qt::red)); // Occupied
}
}
QMqttClient *client;
QGraphicsScene *scene;
QGraphicsView *view;
QGraphicsRectItem *slot1, *slot2, *slot3, *slot4;
QLabel *statusLabel;
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MainWindow window;
window.setWindowTitle("智能停车场管理系统");
window.resize(400, 300);
window.show();
return app.exec();
}
#include "main.moc" // For meta-object compiler in some setups
Note: This code assumes the use of QT's MQTT module. Ensure that the QT project includes the necessary MQTT library by adding QT += mqtt
in the .pro file. Replace the placeholder MQTT broker details with actual Huawei Cloud credentials. The code subscribes to the "parking/status" topic and expects JSON messages with keys "slot1" to "slot4" and "available_slots". Adjust the topic and JSON keys as per your actual implementation.
模块代码设计
#include <stdint.h>
// Register definitions for STM32F103C8T6
#define RCC_APB2ENR (*((volatile uint32_t*)0x40021018))
#define RCC_APB1ENR (*((volatile uint32_t*)0x4002101C))
#define GPIOA_CRL (*((volatile uint32_t*)0x40010800))
#define GPIOA_CRH (*((volatile uint32_t*)0x40010804))
#define GPIOA_IDR (*((volatile uint32_t*)0x40010808))
#define GPIOA_ODR (*((volatile uint32_t*)0x4001080C))
#define GPIOB_CRL (*((volatile uint32_t*)0x40010C00))
#define GPIOB_CRH (*((volatile uint32_t*)0x40010C04))
#define GPIOB_ODR (*((volatile uint32_t*)0x40010C0C))
#define USART2_SR (*((volatile uint32_t*)0x40004400))
#define USART2_DR (*((volatile uint32_t*)0x40004404))
#define USART2_BRR (*((volatile uint32_t*)0x40004408))
#define USART2_CR1 (*((volatile uint32_t*)0x4000440C))
#define I2C1_CR1 (*((volatile uint32_t*)0x40005400))
#define I2C1_CR2 (*((volatile uint32_t*)0x40005404))
#define I2C1_CCR (*((volatile uint32_t*)0x4000541C))
#define I2C1_TRISE (*((volatile uint32_t*)0x40005420))
#define I2C1_SR1 (*((volatile uint32_t*)0x40005414))
#define I2C1_SR2 (*((volatile uint32_t*)0x40005418))
#define I2C1_DR (*((volatile uint32_t*)0x40005410))
// Infrared sensor pins: PA0, PA1, PA4, PA5
#define SENSOR1_PIN 0
#define SENSOR2_PIN 1
#define SENSOR3_PIN 4
#define SENSOR4_PIN 5
// OLED I2C address (usually 0x78 for SSD1306)
#define OLED_ADDRESS 0x78
// Global variables for parking status
volatile uint8_t parking_status[4] = {0}; // 0: free, 1: occupied
volatile int free_spots = 4;
volatile int total_spots = 4;
// Function prototypes
void SystemClock_Init(void);
void GPIO_Init(void);
void UART2_Init(void);
void I2C1_Init(void);
void OLED_Init(void);
void OLED_WriteCommand(uint8_t cmd);
void OLED_WriteData(uint8_t data);
void OLED_DisplayText(char *text);
void UART2_SendChar(char c);
void UART2_SendString(char *str);
void ESP8266_Init(void);
void UpdateParkingStatus(void);
void DisplayFreeSpots(void);
void SendDataToCloud(void);
int main(void) {
SystemClock_Init();
GPIO_Init();
UART2_Init();
I2C1_Init();
OLED_Init();
ESP8266_Init();
OLED_DisplayText("Parking System");
// Simple delay for initialization
for (volatile int i = 0; i < 1000000; i++);
while (1) {
UpdateParkingStatus();
DisplayFreeSpots();
SendDataToCloud();
// Delay for stability
for (volatile int i = 0; i < 1000000; i++);
}
}
void SystemClock_Init(void) {
// Enable HSE and set PLL to output 72MHz (simplified, assume default HSI 8MHz for simplicity)
// In practice, configure RCC registers for 72MHz, but for simplicity, we use HSI 8MHz
// Enable clocks for GPIOA, GPIOB, USART2, I2C1
RCC_APB2ENR |= (1 << 2); // Enable GPIOA clock
RCC_APB2ENR |= (1 << 3); // Enable GPIOB clock
RCC_APB1ENR |= (1 << 17); // Enable USART2 clock
RCC_APB1ENR |= (1 << 21); // Enable I2C1 clock
}
void GPIO_Init(void) {
// Configure PA0, PA1, PA4, PA5 as input with pull-up for infrared sensors
GPIOA_CRL &= ~(0xFF << 0); // Clear bits for PA0 and PA1
GPIOA_CRL |= (0x8 << 0); // CNF0=10 (input with pull-up/down), MODE0=00 (input)
GPIOA_CRL |= (0x8 << 4); // CNF1=10, MODE1=00 for PA1
GPIOA_CRL &= ~(0xFF << 16); // Clear bits for PA4 and PA5
GPIOA_CRL |= (0x8 << 16); // CNF4=10, MODE4=00 for PA4
GPIOA_CRL |= (0x8 << 20); // CNF5=10, MODE5=00 for PA5
GPIOA_ODR |= (1 << SENSOR1_PIN) | (1 << SENSOR2_PIN) | (1 << SENSOR3_PIN) | (1 << SENSOR4_PIN); // Enable pull-up
// Configure PA2 as USART2 TX (alternate function push-pull output)
GPIOA_CRL &= ~(0xF << 8); // Clear bits for PA2
GPIOA_CRL |= (0xB << 8); // CNF2=10 (AF push-pull), MODE2=11 (50MHz output)
// Configure PA3 as USART2 RX (input floating)
GPIOA_CRL &= ~(0xF << 12); // Clear bits for PA3
GPIOA_CRL |= (0x4 << 12); // CNF3=01 (input floating), MODE3=00 (input)
// Configure PB6 and PB7 for I2C1 (alternate function open-drain)
GPIOB_CRL &= ~(0xFF << 24); // Clear bits for PB6 and PB7
GPIOB_CRL |= (0xE << 24); // For PB6: CNF6=11 (AF open-drain), MODE6=10 (2MHz output)
GPIOB_CRL |= (0xE << 28); // For PB7: CNF7=11, MODE7=10
}
void UART2_Init(void) {
// Configure USART2 for 115200 baud, 8N1
USART2_BRR = 0x1389; // Assuming PCLK1=36MHz, 115200 baud: BRR=312.5 -> 0x1389 (19.53125 * 16 = 312.5 -> mantissa=19, fraction=9)
USART2_CR1 |= (1 << 13); // Enable USART (UE bit)
USART2_CR1 |= (1 << 3) | (1 << 2); // Enable transmitter and receiver
}
void I2C1_Init(void) {
// Configure I2C1 for 100kHz standard mode
I2C1_CR2 = 0x24; // Set frequency to 36MHz (PCLK1=36MHz, value=36)
I2C1_CCR = 180; // CCR = PCLK1 / (2 * 100kHz) = 36e6 / 200e3 = 180
I2C1_TRISE = 37; // TRISE = PCLK1/1000000 + 1 = 36 + 1 = 37
I2C1_CR1 |= (1 << 0); // Enable I2C
}
void OLED_Init(void) {
// Initialize OLED display (SSD1306)
OLED_WriteCommand(0xAE); // Display off
OLED_WriteCommand(0xD5); // Set display clock divide ratio
OLED_WriteCommand(0x80);
OLED_WriteCommand(0xA8); // Set multiplex ratio
OLED_WriteCommand(0x3F);
OLED_WriteCommand(0xD3); // Set display offset
OLED_WriteCommand(0x00);
OLED_WriteCommand(0x40); // Set start line
OLED_WriteCommand(0x8D); // Charge pump setting
OLED_WriteCommand(0x14);
OLED_WriteCommand(0x20); // Memory mode
OLED_WriteCommand(0x00);
OLED_WriteCommand(0xA1); // Segment remap
OLED_WriteCommand(0xC8); // Com scan direction
OLED_WriteCommand(0xDA); // Set com pins
OLED_WriteCommand(0x12);
OLED_WriteCommand(0x81); // Set contrast
OLED_WriteCommand(0xCF);
OLED_WriteCommand(0xD9); // Set precharge period
OLED_WriteCommand(0xF1);
OLED_WriteCommand(0xDB); // Set Vcom detect
OLED_WriteCommand(0x40);
OLED_WriteCommand(0xA4); // Entire display on
OLED_WriteCommand(0xA6); // Set normal display
OLED_WriteCommand(0xAF); // Display on
}
void OLED_WriteCommand(uint8_t cmd) {
// Start condition
I2C1_CR1 |= (1 << 8); // Generate start condition
while (!(I2C1_SR1 & (1 << 0))); // Wait for SB flag
I2C1_DR = OLED_ADDRESS & 0xFE; // Send address with write bit
while (!(I2C1_SR1 & (1 << 1))); // Wait for ADDR flag
(void)I2C1_SR2; // Read SR2 to clear ADDR
while (!(I2C1_SR1 & (1 << 7))); // Wait for TXE
I2C1_DR = 0x00; // Control byte for command
while (!(I2C1_SR1 & (1 << 7)));
I2C1_DR = cmd; // Send command
while (!(I2C1_SR1 & (1 << 7)));
I2C1_CR1 |= (1 << 9); // Generate stop condition
}
void OLED_WriteData(uint8_t data) {
I2C1_CR1 |= (1 << 8); // Start
while (!(I2C1_SR1 & (1 << 0)));
I2C1_DR = OLED_ADDRESS & 0xFE;
while (!(I2C1_SR1 & (1 << 1)));
(void)I2C1_SR2;
while (!(I2C1_SR1 & (1 << 7)));
I2C1_DR = 0x40; // Control byte for data
while (!(I2C1_SR1 & (1 << 7)));
I2C1_DR = data;
while (!(I2C1_SR1 & (1 << 7)));
I2C1_CR1 |= (1 << 9); // Stop
}
void OLED_DisplayText(char *text) {
// Simple text display; assumes text is short
OLED_WriteCommand(0x20); // Set memory mode
OLED_WriteCommand(0x00);
OLED_WriteCommand(0x21); // Set column address
OLED_WriteCommand(0x00);
OLED_WriteCommand(0x7F);
OLED_WriteCommand(0x22); // Set page address
OLED_WriteCommand(0x00);
OLED_WriteCommand(0x07);
while (*text) {
OLED_WriteData(*text++);
}
}
void UART2_SendChar(char c) {
while (!(USART2_SR & (1 << 7))); // Wait for TXE
USART2_DR = c;
}
void UART2_SendString(char *str) {
while (*str) {
UART2_SendChar(*str++);
}
}
void ESP8266_Init(void) {
// Send AT commands to initialize ESP8266
UART2_SendString("AT+RST\r\n");
for (volatile int i = 0; i < 1000000; i++); // Delay
UART2_SendString("AT+CWMODE=1\r\n");
for (volatile int i = 0; i < 1000000; i++);
UART2_SendString("AT+CWJAP=\"SSID\",\"PASSWORD\"\r\n"); // Replace with your Wi-Fi credentials
for (volatile int i = 0; i < 1000000; i++);
UART2_SendString("AT+CIPSTART=\"TCP\",\"cloud.huawei.com\",80\r\n"); // Example for HTTP
for (volatile int i = 0; i < 1000000; i++);
}
void UpdateParkingStatus(void) {
// Read sensor states and update parking status
uint32_t idr_val = GPIOA_IDR;
parking_status[0] = !(idr_val & (1 << SENSOR1_PIN)); // 0 if free, 1 if occupied
parking_status[1] = !(idr_val & (1 << SENSOR2_PIN));
parking_status[2] = !(idr_val & (1 << SENSOR3_PIN));
parking_status[3] = !(idr_val & (1 << SENSOR4_PIN));
free_spots = total_spots;
for (int i = 0; i < 4; i++) {
if (parking_status[i]) {
free_spots--;
}
}
}
void DisplayFreeSpots(void) {
// Display free spots on OLED
char buffer[16];
sprintf(buffer, "Free: %d", free_spots); // Simple text, note: sprintf may require stdio.h, but for simplicity, we use it
OLED_DisplayText(buffer);
}
void SendDataToCloud(void) {
// Send data to Huawei Cloud via ESP8266 (example using HTTP POST)
char post_data[50];
sprintf(post_data, "POST /api/data HTTP/1.1\r\nHost: cloud.huawei.com\r\nContent-Type: application/json\r\nContent-Length: 20\r\n\r\n{\"free_spots\":%d}", free_spots);
UART2_SendString("AT+CIPSEND=");
UART2_SendString("50\r\n"); // Length of data
for (volatile int i = 0; i < 100000; i++); // Short delay
UART2_SendString(post_data);
UART2_SendString("\r\n");
}
项目核心代码
#include <stdint.h>
// Register definitions
#define RCC_BASE 0x40021000
#define RCC_CR (*(volatile uint32_t *)(RCC_BASE + 0x00))
#define RCC_CFGR (*(volatile uint32_t *)(RCC_BASE + 0x04))
#define RCC_APB2ENR (*(volatile uint32_t *)(RCC_BASE + 0x18))
#define RCC_APB1ENR (*(volatile uint32_t *)(RCC_BASE + 0x1C))
#define GPIOA_BASE 0x40010800
#define GPIOA_CRL (*(volatile uint32_t *)(GPIOA_BASE + 0x00))
#define GPIOA_CRH (*(volatile uint32_t *)(GPIOA_BASE + 0x04))
#define GPIOA_IDR (*(volatile uint32_t *)(GPIOA_BASE + 0x08))
#define GPIOA_ODR (*(volatile uint32_t *)(GPIOA_BASE + 0x0C))
#define GPIOB_BASE 0x40010C00
#define GPIOB_CRL (*(volatile uint32_t *)(GPIOB_BASE + 0x00))
#define GPIOB_CRH (*(volatile uint32_t *)(GPIOB_BASE + 0x04))
#define GPIOB_ODR (*(volatile uint32_t *)(GPIOB_BASE + 0x0C))
#define USART1_BASE 0x40013800
#define USART1_SR (*(volatile uint32_t *)(USART1_BASE + 0x00))
#define USART1_DR (*(volatile uint32_t *)(USART1_BASE + 0x04))
#define USART1_BRR (*(volatile uint32_t *)(USART1_BASE + 0x08))
#define USART1_CR1 (*(volatile uint32_t *)(USART1_BASE + 0x0C))
#define USART1_CR2 (*(volatile uint32_t *)(USART1_BASE + 0x10))
#define I2C1_BASE 0x40005400
#define I2C1_CR1 (*(volatile uint32_t *)(I2C1_BASE + 0x00))
#define I2C1_CR2 (*(volatile uint32_t *)(I2C1_BASE + 0x04))
#define I2C1_CCR (*(volatile uint32_t *)(I2C1_BASE + 0x1C))
#define I2C1_TRISE (*(volatile uint32_t *)(I2C1_BASE + 0x20))
#define I2C1_DR (*(volatile uint32_t *)(I2C1_BASE + 0x10))
// Assume other modules are written: function prototypes
extern void OLED_Init(void);
extern void OLED_DisplayNumber(uint32_t number);
extern void ESP8266_Init(void);
extern void ESP8266_SendData(uint32_t occupied);
// System clock initialization (HSI 8MHz)
void SystemClock_Init(void) {
RCC_CR |= (1 << 0); // Enable HSI
while (!(RCC_CR & (1 << 1))); // Wait for HSIRDY
RCC_CFGR &= ~(0x03); // Set SYSCLK source to HSI
}
// GPIO initialization for sensors (PA0-PA3 as input with pull-up)
void GPIO_Init(void) {
RCC_APB2ENR |= (1 << 2); // Enable GPIOA clock
// Configure PA0-PA3 as input with pull-up
GPIOA_CRL &= ~(0xFFFF); // Clear bits for PA0-PA3
GPIOA_CRL |= (0x8 << 0) | (0x8 << 4) | (0x8 << 8) | (0x8 << 12); // CNF=10, MODE=00 for each
GPIOA_ODR |= (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3); // Set pull-up
}
// USART1 initialization for ESP8266 (8MHz clock, 9600 baud)
void USART1_Init(void) {
RCC_APB2ENR |= (1 << 14); // Enable USART1 clock
// Configure PA9 as AF push-pull (TX), PA10 as input floating (RX)
GPIOA_CRH &= ~(0xF << 4); // Clear PA9 bits
GPIOA_CRH |= (0xB << 4); // CNF=10, MODE=11 for PA9
GPIOA_CRH &= ~(0xF << 8); // Clear PA10 bits
GPIOA_CRH |= (0x4 << 8); // CNF=01, MODE=00 for PA10
USART1_BRR = 0x3415; // 8MHz, 9600 baud
USART1_CR1 |= (1 << 13) | (1 << 3) | (1 << 2); // UE, TE, RE enable
}
// I2C1 initialization for OLED (PB6-SCL, PB7-SDA)
void I2C1_Init(void) {
RCC_APB2ENR |= (1 << 3); // Enable GPIOB clock
RCC_APB1ENR |= (1 << 21); // Enable I2C1 clock
// Configure PB6 and PB7 as AF open-drain
GPIOB_CRL &= ~(0xF << 24); // Clear PB6 bits
GPIOB_CRL |= (0xF << 24); // CNF=11, MODE=11 for PB6
GPIOB_CRL &= ~(0xF << 28); // Clear PB7 bits
GPIOB_CRL |= (0xF << 28); // CNF=11, MODE=11 for PB7
GPIOB_ODR |= (1 << 6) | (1 << 7); // Set pull-up
// I2C configuration: 100kHz standard mode
I2C1_CR2 = 0x08; // FREQ = 8MHz
I2C1_CCR = 0x50; // CCR = 80 for 100kHz (8MHz / (2 * 100kHz) = 40, but since standard mode, CCR = 40 * 2 = 80)
I2C1_TRISE = 0x09; // TRISE = 9 (8MHz -> 1000ns max rise time, 8MHz period 125ns, so 1000/125 +1 = 9)
I2C1_CR1 |= (1 << 0); // Enable I2C
}
// Read sensor states and return occupied count
uint32_t ReadSensors(void) {
uint32_t idr_val = GPIOA_IDR;
uint32_t occupied = 0;
if (!(idr_val & (1 << 0))) occupied++; // PA0 low means occupied
if (!(idr_val & (1 << 1))) occupied++;
if (!(idr_val & (1 << 2))) occupied++;
if (!(idr_val & (1 << 3))) occupied++;
return occupied;
}
// Delay function (simple loop)
void Delay(uint32_t count) {
for (volatile uint32_t i = 0; i < count; i++);
}
int main(void) {
SystemClock_Init();
GPIO_Init();
USART1_Init();
I2C1_Init();
// Initialize other modules
OLED_Init();
ESP8266_Init();
uint32_t occupied = 0;
uint32_t previous_occupied = 0;
while (1) {
occupied = ReadSensors();
uint32_t free_spots = 4 - occupied;
// Display on OLED
OLED_DisplayNumber(free_spots);
// Send data to cloud if changed
if (occupied != previous_occupied) {
ESP8266_SendData(occupied);
previous_occupied = occupied;
}
Delay(1000000); // Simple delay
}
}
总结
本系统基于STM32F103C8T6微控制器和华为云平台,成功实现了一个智能停车场管理系统,能够实时监测车位占用状态、自动计数车辆进出并显示剩余车位,大大提升了停车管理的自动化水平和效率。
硬件组成上,系统采用4对E18-D80NK红外对射传感器进行精准的车位状态检测,0.96寸OLED显示屏用于现场实时显示剩余车位信息,并通过ESP8266-01S Wi-Fi模块实现数据上传至华为云平台,确保了数据的可靠传输和远程可访问性。
通过QT上位机,系统提供了直观的图形界面,动态展示停车场平面图、车位状态及统计信息,使管理人员能够便捷地进行远程监控和数据分析,进一步优化了停车场的运营和管理。
总体而言,该系统融合了传感器技术、无线通信和云平台优势,实现了停车管理的智能化和信息化,为解决城市停车问题提供了实用且高效的解决方案。
- 点赞
- 收藏
- 关注作者
评论(0)