基于STM32的智能停车场系统:从传感器到物联网的完整实践

发布时间:2026/9/3 3:22:33
基于STM32的智能停车场系统:从传感器到物联网的完整实践 简介本资源是一套面向高校电子类、自动化及物联网方向本科生的毕业设计实战项目基于STM32F103VET6微控制器实现智能停车场核心功能解决传统停车场车位感知弱、状态反馈滞后、远程管理缺失等实际问题。压缩包共72个文件含30个头文件.h定义外设驱动与系统接口、27个源文件.c涵盖红外检测、GPRS短信通信、LCD显示、温湿度采集及语音控制等核心逻辑辅以Keil工程配置.uvprojx/.uvoptx、启动文件、固件库及README说明文档总大小仅304KB结构规范、模块清晰便于学习移植与二次开发。已有120人下载学习可直接用于课程设计、毕设开题与硬件验证阶段。读者可完整获取三板协同架构主板控制台指示板红外检测板的软硬件设计方案、短信定时上报与远程指令解析代码、语音播报与停车杆联动逻辑以及温湿度与车位状态的实时显示实现细节具备良好的工程参考价值与教学延展性。1. 项目概述从零到一打造一个真实的智能停车场系统最近在整理资料翻到了当年毕业设计的源码和文档一个基于STM32的智能停车场系统。现在回头看这个项目麻雀虽小五脏俱全涵盖了嵌入式开发中从传感器数据采集、通信协议、上位机交互到简单控制逻辑的完整链条。对于正在学习STM32或者准备做类似项目的同学来说这是一个非常典型的综合实践案例。它不是一个简单的点灯实验而是模拟了一个真实的应用场景如何让停车场“智能”起来自动识别车辆进出、统计车位、引导停车甚至完成计费。这个系统的核心目标很明确用最低的成本和可靠的方案解决小型停车场比如小区、商场地下车库的自动化管理问题。它不需要复杂的图像识别当然加上摄像头和OpenMV/ K210做车牌识别是更高级的玩法而是通过地磁、红外对管、超声波等常见传感器来感知车辆再结合STM32作为“大脑”进行逻辑处理最后通过显示屏、网络或串口将信息呈现给管理员和车主。如果你手头有一块STM32开发板F1、F4系列都行一些基本的传感器模块想做一个能拿得出手、写在简历里能加分的项目那么这个智能停车场的设计思路和实现细节值得你花时间深入研究一下。接下来我会把这个项目拆开揉碎从设计思路、硬件选型、软件架构到代码实现一步步讲清楚。2. 系统整体设计与核心思路拆解做一个项目最忌讳的就是拿到题目就开始埋头写代码、焊电路。我们先得想清楚这个系统到底要干什么以及怎么干最合理。2.1 核心需求与功能定义一个最基本的智能停车场需要解决以下几个问题车位状态检测实时知道哪个车位是空的哪个车位被占了。这是所有功能的基础。车辆进出管理识别有车进入或离开停车场并记录时间。这涉及到入口和出口的检测。车位引导与显示将空车位信息显示在入口的显示屏上或者通过指示灯引导车辆到具体空位。数据统计与通信将车位占用数据、车辆进出记录发送给后台管理中心上位机可能还需要支持简单的查询。基于这些需求我们可以把系统划分为几个核心模块感知层负责“看”和“听”即采集物理世界的数据。包括车位检测传感器、入口/出口车辆检测传感器。控制层系统的“大脑”基于STM32微控制器。它负责处理传感器数据、执行控制逻辑如控制道闸、指示灯、与外部设备通信。执行层负责“动手”包括道闸电机、车位指示灯、入口显示屏等。通信与交互层负责“说话”包括与上位机通信的模块如ESP8266 WiFi模块、HC-05蓝牙模块或者简单的串口以及本地的人机交互界面如OLED显示屏、按键。2.2 硬件方案选型与背后的考量硬件选型直接决定了系统的成本、稳定性和开发难度。这里的选择都是基于常见、易得、性价比高的原则。1. 主控芯片为什么是STM32STM32系列MCU资源丰富、生态完善、性价比高。对于这个项目我们不需要跑Linux虽然stm32 linux开发环境是个热门话题但这里用不上一个Cortex-M3或M4内核的芯片绰绰有余。推荐型号STM32F103C8T6蓝色药丸核心板或STM32F407VET6。F103足够应对大多数场景如果后续想加更复杂的图形界面如LVGL或网络协议F407更游刃有余。关键点芯片的GPIO数量要足够连接所有传感器和执行器UART串口最好有2-3个一个用于调试打印一个连接通信模块一个可能连接其他外设ADC通道用于模拟量传感器。2. 车位检测方案对比与选择这是项目的核心传感器选型至关重要。方案一红外对射管最便宜但易受干扰原理在车位前后安装一对红外发射管和接收管。无车时接收管收到信号有车时红外光被遮挡接收管无信号。优点成本极低电路简单。缺点对环境光敏感容易误触发比如人影走过安装要求高需要对得准。适用场景对成本极度敏感、环境光线可控的室内演示。方案二地磁传感器如HMC5883L稳定性好是目前主流原理车辆是大型金属物体会扰动地球磁场。传感器检测磁场变化从而判断是否有车停放。优点非接触式不受光线影响寿命长安装方便埋于地下或贴于地面。缺点成本比红外对管高需要I2C/SPI通信软件上需要做阈值判断和滤波算法防止误报。适用场景实际停车场项目的首选可靠性高。方案三超声波传感器如HC-SR04测距方案原理安装在车位上方测量到地面的距离。有车时距离变小。优点检测范围可控不易受相邻车位干扰。缺点成本较高安装需要一定高度复杂环境如灰尘可能影响精度。我们的选择为了平衡教学性与实用性推荐使用地磁传感器方案。它更贴近真实应用且STM32驱动I2C设备是必备技能。可以在系统中设计为支持多种传感器通过宏定义切换方便学习对比。3. 车辆进出检测通常在入口和出口处设置检测点。可以用红外对射/光电开关简单有效成本低。地感线圈真实停车场常用但需要埋设线圈制作复杂我们做实验可以用模拟开关代替其信号。RFID读卡器用于识别固定车辆实现刷卡进出。这增加了“身份识别”的维度让项目更有深度。4. 通信模块选型如何将数据发出去ESP8266 WiFi模块这是当前最热门、性价比最高的选择。通过AT指令或直接编程使用Arduino core for ESP8266或乐鑫原生SDK可以让STM32轻松连接局域网甚至将数据上报到云平台如阿里云、OneNET或本地服务器。stm32 http库的热搜也说明了网络应用的需求旺盛。HC-05/06蓝牙模块适合短距离、与手机APP通信的场景。比如做一个手机APP查看空车位、寻车。4G模块如SIM800C适用于无WiFi覆盖的户外停车场但成本和功耗较高。单纯串口如果只是连接电脑上位机直接用USB转TTL串口是最简单的。我们的选择ESP8266。它让项目具备了物联网属性学习价值更大。STM32通过串口与ESP8266通信发送AT指令配置和传输数据。5. 人机交互与执行单元显示入口总览屏可用较大的LCD屏如TFT LCD或点阵屏。每个车位上方可以用一个双色LED红/绿做指示灯。在开发调试阶段一个0.96寸的OLED显示屏SSD1306驱动I2C接口是绝佳搭档可以实时显示传感器数据、系统状态oled月薪猫stm32这个梗也说明了它的普及程度。道闸可以用一个舵机SG90模拟起落杆的动作。按键/触摸用于手动控制、设置参数等。2.3 软件架构设计如何组织你的代码面对多个传感器、通信和控制任务好的软件架构能让开发、调试和维护事半功倍。强烈不建议把所有代码都堆在main.c的while(1)里。分层与模块化设计硬件抽象层HAL/Driver这一层直接操作STM32的寄存器或调用HAL库/标准库函数实现最基础的驱动。例如i2c.c/.h: 封装I2C的读写函数。uart.c/.h: 封装串口发送、接收特别是stm32串口接收不定长数据可以用空闲中断DMA的方式高效处理。gpio.c/.h: 封装LED、按键等简单GPIO操作。设备驱动层Device基于硬件抽象层编写具体传感器/模块的驱动程序。每个设备一个独立的.c/.h文件。hmc5883l.c/.h: 地磁传感器驱动提供初始化、读取原始数据、计算磁场强度的函数。esp8266.c/.h: WiFi模块驱动封装连接WiFi、连接服务器、发送数据的AT指令流程。oled.c/.h: OLED显示屏驱动封装显示字符串、数字、图形的函数。业务逻辑层Application这是系统的核心“大脑”。它调用设备驱动层获取数据并根据预设的逻辑进行判断和控制。parking_logic.c/.h: 实现车位状态判断算法如连续采样10次地磁数据若超过8次超过阈值则判定为有车、车辆进出流程控制检测到入口信号-检查有空位-抬杆-记录车牌/时间-车位状态更新。data_manager.c/.h: 管理车位数据、车辆记录处理与上位机的通信协议如自定义串口协议或简单的JSON格式。任务调度层可选但推荐如果逻辑复杂或者需要同时处理多个实时性要求不同的任务如传感器采样必须定时进行网络通信可以稍慢引入一个简单的任务调度器或直接使用FreeRTOS是很好的选择。freertos的热搜也体现了其在复杂STM32项目中的重要性。你可以创建几个独立的任务任务1传感器数据采集与处理高优先级定时执行。任务2网络通信中优先级事件触发。任务3人机交互更新低优先级。采用这种架构你的代码会非常清晰。当你想更换一个传感器时只需修改对应的设备驱动文件想修改业务逻辑也只需在应用层调整底层驱动无需变动。3. 核心模块实现与代码细节解析有了整体设计我们深入几个最关键、最容易踩坑的模块看看具体怎么实现。3.1 地磁传感器数据采集与滤波算法以HMC5883L为例通过I2C读取其XYZ三轴的数据。但原始数据是不能直接用的噪声很大。1. 驱动实现要点// hmc5883l.c #define HMC5883L_ADDR 0x1E // I2C设备地址 uint8_t HMC5883L_Init(void) { // 配置测量模式、数据输出速率、增益等寄存器 I2C_WriteByte(HMC5883L_ADDR, CONFIG_REG_A, 0x70); // 示例配置 I2C_WriteByte(HMC5883L_ADDR, CONFIG_REG_B, 0xA0); I2C_WriteByte(HMC5883L_ADDR, MODE_REG, 0x00); // 连续测量模式 // ... 检查设备ID等初始化步骤 } void HMC5883L_ReadRawData(int16_t *mag_x, int16_t *mag_y, int16_t *mag_z) { uint8_t buf[6]; I2C_ReadBytes(HMC5883L_ADDR, DATA_REG_X_MSB, buf, 6); *mag_x (int16_t)((buf[0] 8) | buf[1]); *mag_z (int16_t)((buf[2] 8) | buf[3]); // 注意Z轴数据在Y轴之前 *mag_y (int16_t)((buf[4] 8) | buf[5]); // 根据数据表可能需要对调X和Y轴 }2. 关键数据处理与滤波读取到的是磁力计原始值我们需要计算总磁场强度或向量模并与一个“空车位基准值”进行比较。float HMC5883L_GetMagnitude(int16_t x, int16_t y, int16_t z) { // 简单的向量模计算忽略Z轴或根据安装方式调整 return sqrtf((float)(x*x y*y)); // 或加上 z*z }注意直接使用瞬时值判断会非常不稳定。必须滤波均值滤波最简单有效。连续采样N次比如20次求平均值作为本次的有效值。#define SAMPLE_SIZE 20 float filter_buffer[SAMPLE_SIZE]; uint8_t filter_index 0; float Moving_Average_Filter(float new_sample) { filter_buffer[filter_index] new_sample; filter_index (filter_index 1) % SAMPLE_SIZE; float sum 0; for(int i0; iSAMPLE_SIZE; i) { sum filter_buffer[i]; } return sum / SAMPLE_SIZE; }阈值判断与迟滞比较滤波后的磁场强度与预设的阈值比较。为了避免在阈值附近频繁抖动引入迟滞。#define THRESHOLD_HIGH 550.0 // 有车阈值 #define THRESHOLD_LOW 450.0 // 无车阈值 (THRESHOLD_LOW THRESHOLD_HIGH) typedef enum { SLOT_EMPTY 0, SLOT_OCCUPIED 1 } SlotStatus_t; SlotStatus_t last_status SLOT_EMPTY; SlotStatus_t JudgeSlotStatus(float filtered_mag) { if(last_status SLOT_EMPTY filtered_mag THRESHOLD_HIGH) { last_status SLOT_OCCUPIED; return SLOT_OCCUPIED; } else if(last_status SLOT_OCCUPIED filtered_mag THRESHOLD_LOW) { last_status SLOT_EMPTY; return SLOT_EMPTY; } return last_status; // 状态不变 }迟滞比较的原理就像电器的开关打开需要用力按下去超过高阈值关上也需要用力拉回来低于低阈值。中间的“模糊地带”保持原状态这能极大消除抖动。3. 校准与基准值获取每个安装位置的磁场环境都不同。因此系统上电后必须在空车位状态下进行一段时间的采样计算出一个动态的基准值而不是使用一个固定的阈值。float baseline_mag 0; void CalibrateBaseline(void) { float sum 0; for(int i0; i100; i) { sum HMC5883L_GetMagnitude(raw_x, raw_y, raw_z); HAL_Delay(10); } baseline_mag sum / 100; // 阈值可以设为 baseline_mag * 某个系数如1.5 THRESHOLD_HIGH baseline_mag * 1.5; THRESHOLD_LOW baseline_mag * 1.2; }3.2 STM32与ESP8266通信稳定联网的关键让STM32通过串口控制ESP8266联网并传输数据是项目从“单机”走向“物联网”的关键一步。这里陷阱很多。1. 硬件连接与初始化STM32的USART2_TX 接 ESP8266的RX。STM32的USART2_RX 接 ESP8266的TX。共地必须连接STM32的GND和ESP8266的GND。ESP8266的VCC接3.3V切勿接5V会烧毁。ESP8266的EN/CH_PD引脚接3.3V使能。初始化STM32串口时波特率通常设置为115200与ESP8266默认一致。配置好串口中断或DMA用于接收ESP8266返回的数据。2. 软件流程与AT指令处理核心是发送AT指令并解析返回的响应。必须要有超时重发和错误处理机制。// esp8266.c typedef enum { WIFI_STA_IDLE, WIFI_STA_AT_TEST, WIFI_STA_MODE_SET, WIFI_STA_CONNECTING, WIFI_STA_CONNECTED, WIFI_STA_GOT_IP, WIFI_STA_DISCONNECTED, WIFI_STA_ERROR } WifiState_t; WifiState_t wifi_state WIFI_STA_IDLE; uint8_t ESP8266_SendCmdAndWaitResp(const char* cmd, const char* expected_resp, uint32_t timeout_ms) { UART_ClearRxBuffer(); // 清空接收缓冲区 UART_SendString(cmd); // 发送AT指令记得加\r\n UART_SendString(\r\n); uint32_t start_tick HAL_GetTick(); while((HAL_GetTick() - start_tick) timeout_ms) { if(UART_RxDataAvailable()) { char* resp UART_GetRxBufferString(); if(strstr(resp, expected_resp) ! NULL) { return 1; // 成功 } if(strstr(resp, ERROR) ! NULL || strstr(resp, FAIL) ! NULL) { return 0; // 失败 } } } return 0; // 超时 } void ESP8266_ConnectToAP(const char* ssid, const char* password) { if(!ESP8266_SendCmdAndWaitResp(AT, OK, 1000)) { wifi_state WIFI_STA_ERROR; return; } if(!ESP8266_SendCmdAndWaitResp(ATCWMODE1, OK, 1000)) { // 设置为STA模式 wifi_state WIFI_STA_ERROR; return; } // 拼接连接指令 ATCWJAPSSID,PASSWORD char cmd[128]; sprintf(cmd, ATCWJAP\%s\,\%s\, ssid, password); // 连接WiFi时间较长超时设置长一些比如15秒 if(!ESP8266_SendCmdAndWaitResp(cmd, WIFI CONNECTED, 15000)) { wifi_state WIFI_STA_ERROR; return; } if(!ESP8266_SendCmdAndWaitResp(cmd, WIFI GOT IP, 5000)) { // 等待获取IP wifi_state WIFI_STA_ERROR; return; } wifi_state WIFI_STA_GOT_IP; }3. 通过TCP/UDP发送数据到服务器连接上WiFi后就可以与服务器通信了。这里以TCP连接为例。void ESP8266_SendDataToServer(const char* server_ip, uint16_t port, const char* data) { // 1. 建立TCP连接 char cmd[64]; sprintf(cmd, ATCIPSTART\TCP\,\%s\,%d, server_ip, port); if(!ESP8266_SendCmdAndWaitResp(cmd, CONNECT, 5000)) { // 处理连接失败 return; } // 2. 准备发送数据 sprintf(cmd, ATCIPSEND%d, strlen(data)); if(!ESP8266_SendCmdAndWaitResp(cmd, , 2000)) { // 等待提示符 return; } // 3. 发送实际数据 UART_SendString(data); // 等待发送完成响应 SEND OK 或 ERROR // ... (这里需要根据响应判断) // 4. 关闭连接如果是短连接 // ESP8266_SendCmdAndWaitResp(ATCIPCLOSE, CLOSED, 1000); }关键技巧处理ESP8266响应时最好使用状态机。不要用HAL_Delay干等而是在主循环或RTOS任务中根据当前wifi_state执行相应的步骤和超时判断。这样系统不会卡死。3.3 多任务管理与实时性保障即使不用RTOS我们也需要让多个“事情”看起来在同时进行。比如系统需要每隔100ms采集一次所有车位传感器数据。实时检测串口来自ESP8266或上位机的数据。每隔1秒更新一次OLED显示屏。检测入口/出口的传感器信号。1. 基于SysTick的系统时基利用STM32的SysTick定时器产生一个1ms的时基为整个系统提供时间参考。// 在SysTick中断服务函数中 volatile uint32_t system_tick 0; void SysTick_Handler(void) { system_tick; } // 获取当前系统滴答数 uint32_t GetTick(void) { return system_tick; }2. 简单任务调度器实现我们可以为每个需要定时执行的任务定义一个结构体。typedef struct { uint32_t interval; // 执行间隔 (ms) uint32_t last_run; // 上次执行的时间戳 void (*task_func)(void); // 任务函数指针 } Task_t; Task_t task_list[] { {100, 0, Sensor_Acquisition_Task}, // 100ms采集一次传感器 {1000, 0, OLED_Update_Task}, // 1s更新一次显示 {50, 0, UART_Process_Task}, // 50ms处理一次串口数据 // ... 更多任务 }; #define TASK_COUNT (sizeof(task_list)/sizeof(Task_t)) void Scheduler_Run(void) { uint32_t current_tick GetTick(); for(int i0; iTASK_COUNT; i) { if(current_tick - task_list[i].last_run task_list[i].interval) { task_list[i].task_func(); task_list[i].last_run current_tick; } } }然后在main函数的while(1)循环中不断调用Scheduler_Run()即可。这是一种协作式调度每个任务函数必须尽快执行完毕不能长时间阻塞比如不能用HAL_Delay(1000)否则会影响其他任务。3. 进阶使用FreeRTOS如果逻辑更复杂比如网络通信等待服务器响应可能阻塞或者需要任务间通信如传感器任务将数据放入队列网络任务从队列取出并发送那么使用FreeRTOS是更专业的选择。创建Sensor_Task、Network_Task、Display_Task等。使用队列xQueueCreate,xQueueSend,xQueueReceive在任务间安全传递数据。使用信号量xSemaphoreCreateBinary或事件标志组xEventGroupCreate进行任务同步。FreeRTOS提供了精确的定时器、内存管理等功能能让你的程序结构更清晰、更健壮。stm32串口空闲中断接收数据后将一帧数据通过队列发送给Network_Task去处理是非常经典的RTOS应用模式。4. 上位机设计与系统联调一个完整的系统离不开“眼睛”。上位机可以是一个简单的串口调试助手也可以是一个用C#、PythonPyQt或LabVIEW编写的图形化程序甚至是一个网页。4.1 最简单的串口协议设计对于初学者可以先从串口通信开始。定义一套简单的自定义协议让STM32定时向上位机发送数据。协议帧格式示例文本格式便于调试[START][车位1状态],[车位2状态],...,[车位N状态][总空位][总车位][END]例如[START]1,0,0,1,0,4,5[END]表示车位1有车车位2空车位3空车位4有车车位5空。总空位4个总车位5个。在STM32端使用sprintf组帧通过串口发送。 在上位机端如串口助手或自编程序解析这个字符串更新界面上的车位状态图标和数字。二进制协议效率更高但调试稍复杂。例如可以用一个字节的每一位bit来表示一个车位状态1占用0空闲后面跟着总空位和总车位的字节。4.2 基于TCP的网络通信与数据可视化使用ESP8266后数据可以通过TCP/UDP发送到网络上的服务器。服务器可以是一个运行在电脑上的Python Socket服务器 数据库如SQLite Web框架如Flask。数据流STM32 (ESP8266) - TCP -Python Socket服务器。Python服务器解析数据存入SQLite数据库记录时间、车位状态、车辆进出记录。Flask Web服务器从数据库读取数据生成网页。用户通过浏览器访问该网页实时查看停车场状态、历史记录甚至生成报表。这是一个非常经典的“嵌入式设备本地服务器Web前端”的物联网架构技术栈通用学习价值极高。4.3 联调技巧与问题定位软硬件结合的项目调试是重头戏。1. 分模块调试循序渐进第一步先让STM32的串口1连接USB转TTL到电脑能正常打印调试信息printf重定向。这是你的“眼睛”。第二步单独测试每个传感器。写一个测试程序把地磁传感器的原始值、滤波后的值、判断结果都打印出来观察是否正常。用磁铁靠近/远离看数值变化是否符合预期。第三步单独测试ESP8266。先用USB转TTL模块直接连接电脑和ESP8266用串口助手发送AT指令确保模块本身是好的能连上WiFi。然后再接入STM32进行测试。第四步测试执行机构。写程序控制LED灯、舵机看是否能按预期动作。2. 利用好调试工具串口调试助手必备。选择功能强大的如SecureCRT、MobaXterm或开源的Putty、CoolTerm。要能显示十六进制能发送文件有日志记录功能。逻辑分析仪如果时序问题复杂如I2C通信失败一个便宜的USB逻辑分析仪配合PulseView软件能帮你直观地看到波形和数据快速定位是硬件问题还是软件问题。STM32 ST-LINK Utility或STM32CubeProgrammer不仅用于烧录程序其内置的内存查看、变量实时查看Live Watch功能在调试时非常有用。3. 常见联调问题ESP8266无响应检查接线TX/RX是否交叉、波特率是否是115200、供电3.3V是否稳定电流是否足够。给ESP8266单独供电是解决很多奇怪问题的好方法。传感器数据跳动大检查电源噪声在传感器电源引脚就近加一个0.1uF的瓷片电容到地。优化软件滤波算法增加采样次数调整阈值。系统偶尔死机检查堆栈是否溢出在RTOS中尤其注意。检查中断服务函数是否执行时间过长。检查是否有数组越界、指针飞掉等内存问题。使用看门狗IWDG让系统能在死锁后自动复位。5. 项目优化与扩展思路一个基本的系统完成后可以考虑以下方向进行优化和扩展这能让你的项目脱颖而出。5.1 低功耗设计如果停车场是电池供电如太阳能低功耗至关重要。STM32低功耗模式在无车辆进出时让STM32进入停止模式Stop Mode或睡眠模式Sleep Mode此时功耗可降至微安级。通过外部中断如车辆检测传感器产生的中断来唤醒MCU。传感器间歇工作周期性地唤醒传感器进行采样而不是一直供电。ESP8266深度睡眠如果数据上报不频繁可以控制ESP8266在发送完数据后进入深度睡眠定时唤醒。5.2 引入更先进的识别技术RFID车辆识别在入口处加装RFID读卡器识别固定车辆实现自动扣费或权限管理。摄像头与车牌识别这是真正的“智能”升级。可以使用专用的车牌识别模块成本较高或者使用OpenMV、K210这类带摄像头的AIoT开发板运行轻量级的车牌识别模型。STM32通过串口与它们通信获取车牌号。k210与stm32通讯就是这个方向。蓝牙信标定位在停车场内部部署蓝牙信标Beacon车主手机APP可以结合信标信号进行粗略的室内定位和导航寻车。5.3 云平台集成将数据上传到公有云平台如阿里云物联网平台、腾讯云IoT Explorer、中国移动OneNET可以利用平台提供的设备管理、数据可视化、规则引擎、消息推送等服务快速构建一个功能完整的物联网应用无需自己搭建服务器。5.4 手机APP开发开发一个简单的手机APP可以用Android Studio或Flutter通过WiFi或4G网络从服务器获取数据实现空车位查询、预约车位、导航到车位、在线支付等功能。这构成了一个完整的用户端闭环。从一块STM32开发板开始到最终形成一个涵盖感知、控制、通信、云、端的完整物联网解决方案这个“智能停车场”项目就像一棵技能树它的每一个分支都值得你去深入探索。过程中遇到的每一个问题解决的每一个bug都会让你对嵌入式系统、对物联网有更深刻的理解。这个项目最大的价值不在于它本身的功能有多强大而在于它为你提供了一个绝佳的、贯穿多个技术领域的实践舞台。本文还有配套的精品资源点击获取