news 2026/9/5 23:40:30

STM32温室大棚控制系统:从传感器到执行器的嵌入式开发实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32温室大棚控制系统:从传感器到执行器的嵌入式开发实战

简介:本资源是一套基于STM32平台、采用C语言开发的温室大棚智能控制系统完整项目包,面向计算机、物联网、自动化等专业的本科生,专为课程设计、期末大作业及毕业设计实践打造。项目已通过导师评审并获99分高分,代码结构清晰、注释完整,涵盖温湿度采集、光照控制、通风执行、LCD显示与按键交互等核心功能模块,小白用户亦可编译下载后直接运行验证。压缩包共1086个文件,含570个C源文件(实现传感器驱动、PID调节、状态机逻辑等)、256个头文件(定义外设寄存器、数据结构与接口函数)、51个汇编启动文件及链接脚本,另有PDF报告、PPT答辩材料、HEX/AXF可执行镜像与Keil工程配置文件,整体大小33.74MB。目前已有123人学习下载,配套作业报告详述设计原理、硬件选型、软件流程与测试结果,是兼具工程规范性与教学适配性的高质量嵌入式实战范例。

1. 项目概述与核心价值

最近在整理过往的嵌入式项目资料,翻到了当年一个让我印象深刻的期末大作业——基于STM32的温室大棚控制系统。这不仅仅是一个简单的课程设计,它几乎涵盖了从传感器数据采集、执行器控制、人机交互到通信协议整合的完整嵌入式开发流程。对于正在学习STM32或C语言,尤其是面临期末大作业、课程设计压力的同学来说,这个项目具有极高的参考价值。它不像一些简单的流水灯或按键实验,而是将一个真实的工业控制场景微缩到了你的开发板上,让你能直观地理解嵌入式系统如何与物理世界交互。

这个系统的核心目标很明确:模拟一个智能温室环境,自动维持作物生长所需的温度、湿度和光照条件。你需要用STM32作为“大脑”,通过各类传感器(如温湿度、光照强度)感知环境,然后逻辑判断,最终驱动执行器(如加热器、加湿器、补光灯、通风扇)做出相应动作。整个过程,从硬件选型、电路设计,到软件架构、代码编写,再到最后的调试与报告撰写,是对你C语言功底、STM32外设掌握程度以及系统工程思维的一次全面检验。如果你手头正有类似的作业,或者想找一个有深度的项目来练手,那么跟着这篇分享,你不仅能拿到可运行的源码,更能理解每一行代码背后的设计逻辑和踩过的那些“坑”。

2. 系统整体设计与硬件选型解析

2.1 系统架构与核心控制逻辑

一个可靠的温室控制系统,其架构必须清晰。我们采用的是典型的“感知-决策-执行”闭环控制模式。整个系统以STM32F103C8T6(俗称“蓝桥杯”或“最小系统板”)为核心控制器,它性价比高、资源足够、社区资料丰富,非常适合学习和大作业。

系统的输入部分(感知层)主要包括:

  1. 温湿度传感器:选用DHT11或更精确的SHT20。DHT11成本低,单总线通信,编程简单;SHT20精度和稳定性更好,使用I2C接口。大作业中常用DHT11。
  2. 光照强度传感器:常用BH1750。它是数字型光照传感器,直接通过I2C接口输出光照强度值(单位勒克斯),避免了模拟传感器需要ADC采样和校准的麻烦。
  3. 土壤湿度传感器:通常使用模拟输出的模块。它将土壤湿度转化为电压信号,由STM32的ADC通道进行采样。这里需要注意,简单的电阻式传感器易腐蚀,仅供学习演示。

系统的输出部分(执行层)包括:

  1. 加热装置:用一个小功率直流加热片模拟,通过一个MOS管或继电器模块控制通断。
  2. 加湿装置:用一个5V微型雾化器模块模拟,同样通过MOS管或继电器控制。
  3. 补光灯:用高亮度LED灯条模拟,通过MOS管进行PWM调光,可以模拟不同光照强度。
  4. 通风扇:用一个直流小风扇模拟,控制方式同加热器。
  5. 液晶显示:使用0.96寸或1.3寸的OLED屏幕(SSD1306驱动,I2C接口),用于实时显示环境参数和系统状态。比LCD1602更美观、省电。

核心控制逻辑是一个简单的阈值判断:

  • 温度控制:低于设定下限,开启加热器;高于设定上限,开启通风扇;在区间内,两者都关闭。
  • 湿度控制:低于设定下限,开启加湿器;高于设定上限,开启通风扇(辅助除湿)。
  • 光照控制:低于设定下限,开启补光灯,并通过PWM调节亮度至目标值。

注意:在实际工业场景中,会采用PID等更复杂的控制算法来避免执行器频繁启停(“振荡”)。但在大作业中,简单的阈值控制足以清晰展示逻辑,且易于实现和理解。

2.2 关键硬件电路设计要点

硬件连接是项目的基础,这里有几个容易出错的点需要特别注意:

  1. 电源管理:STM32核心板是3.3V逻辑电平。而DHT11、继电器模块、雾化器、风扇等通常是5V供电。务必确保3.3V和5V的电源隔离。可以使用独立的5V电源适配器为执行器部分供电,STM32的GPIO输出信号通过光耦或电平转换模块去控制5V侧的MOS管或继电器。最忌讳直接将5V设备接到STM32的GPIO上,会烧毁芯片。
  2. 传感器接口
    • DHT11:单总线协议,只需一个GPIO口。时序要求严格,微秒级延时必须准确。建议使用SysTick定时器或定时器中断来产生精确延时,而不是简单的for循环延时。
    • BH1750:I2C接口(PB6-SCL, PB7-SDA)。需要正确配置STM32的I2C硬件外设或模拟I2C时序。上拉电阻(通常4.7K)必不可少。
    • ADC土壤湿度:注意ADC的参考电压(通常是3.3V)。传感器的模拟输出范围可能不是0-3.3V,可能需要分压电路。采样时建议多次采样取平均,并做软件滤波(如滑动平均)。
  3. 执行器驱动
    • MOS管选择:驱动风扇、加热片等小电流设备,可以用常见的IRF540N(N沟道)。GPIO输出高电平(3.3V)通过一个限流电阻连接到MOS管的栅极(G),漏极(D)接负载到电源正,源极(S)接电源负。务必在负载(如电机、继电器线圈)两端并联一个续流二极管,防止断电时产生的反向电动势击穿MOS管。
    • 继电器隔离:如果负载功率较大(如真实加热棒),强烈建议使用继电器模块。继电器模块自带了光耦隔离和驱动电路,直接用STM32的GPIO输出3.3V即可控制,安全方便。

3. 软件架构与核心模块代码实现

3.1 工程结构与外设初始化

一个好的软件架构能让代码清晰易维护。建议采用模块化编程,将不同功能分离到独立的.c/.h文件对中。

Project/ ├── Core/ │ ├── main.c │ ├── stm32f1xx_it.c │ └── ... ├── Drivers/ │ ├── STM32F1xx_HAL_Driver/ │ └── ... ├── Src/ │ ├── bsp_dht11.c/h // DHT11驱动 │ ├── bsp_bh1750.c/h // BH1750驱动 │ ├── bsp_oled.c/h // OLED驱动 │ ├── bsp_adc.c/h // ADC采样(土壤湿度) │ ├── bsp_pwm.c/h // PWM输出(补光灯) │ ├── bsp_gpio.c/h // GPIO控制(加热、加湿、风扇) │ ├── control_logic.c/h // 核心控制逻辑 │ └── system.c/h // 系统初始化、延时函数等 └── Inc/ └── ...

main.c中,初始化顺序至关重要:

int main(void) { HAL_Init(); // HAL库初始化 SystemClock_Config(); // 系统时钟配置,通常使用外部晶振8MHz,倍频到72MHz MX_GPIO_Init(); MX_ADC1_Init(); // 初始化ADC,用于土壤湿度 MX_I2C1_Init(); // 初始化I2C,用于BH1750和OLED MX_TIM2_Init(); // 初始化定时器,用于PWM输出和精准延时 OLED_Init(); // 初始化OLED显示 DHT11_Init(); // 初始化DHT11 GPIO // ... 其他初始化 // 显示开机界面 OLED_ShowString(0, 0, "GreenHouse Sys", 16); HAL_Delay(1000); OLED_Clear(); while (1) { // 1. 数据采集 read_sensor_data(); // 2. 控制逻辑判断 control_logic_process(); // 3. 更新显示 update_display(); // 4. 延时,控制循环周期(如2秒一次) HAL_Delay(2000); } }

3.2 传感器数据采集驱动详解

DHT11驱动要点: DHT11的通信时序是难点。它采用单总线,主机(STM32)先发起起始信号(拉低至少18ms后拉高20-40us),然后等待从机响应。之后是40位数据(16位湿度整数+16位温度整数+8位校验和)的传输,每一位都以50us左右的低电平起始,高电平的持续时间决定数据位是0(26-28us)还是1(70us)。

// 关键代码片段:读取一位数据 uint8_t DHT11_Read_Bit(void) { while(DHT11_IO_READ() == GPIO_PIN_RESET); // 等待低电平起始信号结束 delay_us(40); // 延时40us后检测电平 if(DHT11_IO_READ() == GPIO_PIN_SET) { while(DHT11_IO_READ() == GPIO_PIN_SET); // 等待高电平结束 return 1; } else { return 0; } }

实操心得:这里的delay_us必须非常精确。使用SysTick定时器或通用定时器来实现微秒延时函数比软件循环更可靠。另外,读取完40位数据后,一定要校验和(前四个字节相加的低8位等于校验和字节),数据无效则丢弃,避免显示乱码。

BH1750驱动要点: BH1750通过I2C发送指令字。常用的是连续高分辨率模式(指令0x10)。发送测量指令后,需要等待测量完成(典型时间120ms),再读取两个字节的数据。

float BH1750_Read_Lux(void) { uint8_t buf[2]; uint16_t lux_raw = 0; float lux = 0.0; // 发送测量指令(0x10) HAL_I2C_Master_Transmit(&hi2c1, BH1750_ADDR_WRITE, (uint8_t*)&cmd_measure, 1, HAL_MAX_DELAY); HAL_Delay(180); // 等待测量完成,留有余量 // 读取数据 HAL_I2C_Master_Receive(&hi2c1, BH1750_ADDR_READ, buf, 2, HAL_MAX_DELAY); lux_raw = (buf[0] << 8) | buf[1]; lux = lux_raw / 1.2; // 根据手册,分辨率1.2 lx/计数 return lux; }

ADC采样与滤波: 对于土壤湿度这类变化缓慢的模拟量,软件滤波能有效去除毛刺。

#define ADC_FILTER_LEN 10 uint32_t soil_moisture_filter(void) { static uint32_t adc_buf[ADC_FILTER_LEN] = {0}; static uint8_t buf_index = 0; uint32_t sum = 0; uint8_t i; // 读取当前ADC值 HAL_ADC_Start(&hadc1); HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY); adc_buf[buf_index] = HAL_ADC_GetValue(&hadc1); buf_index = (buf_index + 1) % ADC_FILTER_LEN; // 计算滑动平均值 for(i = 0; i < ADC_FILTER_LEN; i++) { sum += adc_buf[i]; } return sum / ADC_FILTER_LEN; }

得到ADC平均值后,可以映射为湿度百分比。注意,这个百分比是相对值,需要根据传感器在空气中和在水中的读数进行校准。

3.3 核心控制逻辑实现

控制逻辑模块是系统的大脑,它根据采集到的数据和用户设定的阈值,决定执行器的动作。

// control_logic.c typedef struct { float temp_set_low; float temp_set_high; float humi_set_low; float humi_set_high; uint16_t light_set_low; } Control_Threshold_t; typedef struct { float temperature; float humidity; uint16_t light_intensity; uint16_t soil_moisture; uint8_t heater_status; uint8_t humidifier_status; uint8_t fan_status; uint8_t light_status; uint16_t light_pwm_duty; // PWM占空比 0-100 } System_Status_t; void control_logic_process(System_Status_t *status, Control_Threshold_t *th) { // 温度控制 if (status->temperature < th->temp_set_low) { status->heater_status = 1; status->fan_status = 0; // 加热时通常不开风扇 } else if (status->temperature > th->temp_set_high) { status->heater_status = 0; status->fan_status = 1; // 过热时开启风扇通风降温 } else { status->heater_status = 0; status->fan_status = 0; } // 湿度控制 if (status->humidity < th->humi_set_low) { status->humidifier_status = 1; } else if (status->humidity > th->humi_set_high) { status->humidifier_status = 0; // 湿度过高时,如果风扇没因温度开启,可以开启辅助除湿 if (status->fan_status == 0) { status->fan_status = 2; // 用一个特殊状态表示因湿度高开启 } } else { status->humidifier_status = 0; } // 光照控制 if (status->light_intensity < th->light_set_low) { status->light_status = 1; // 简单的PWM调节:假设目标光照是设定值,当前光照越低,PWM越大 // 这里简化处理,直接给一个固定补偿值 status->light_pwm_duty = 70; // 设置PWM占空比为70% } else { status->light_status = 0; status->light_pwm_duty = 0; } // 根据状态字,实际控制GPIO和PWM输出 HAL_GPIO_WritePin(HEATER_GPIO_Port, HEATER_Pin, status->heater_status ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(HUMIDIFIER_GPIO_Port, HUMIDIFIER_Pin, status->humidifier_status ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(FAN_GPIO_Port, FAN_Pin, (status->fan_status > 0) ? GPIO_PIN_SET : GPIO_PIN_RESET); // 设置PWM占空比 __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, (status->light_pwm_duty * 100) / 100); // 假设ARR=100 }

这个逻辑清晰易懂,但存在一个问题:当温度和湿度阈值同时触发风扇开启和关闭时,逻辑会有冲突。在实际编写时,需要定义更优先级的规则,例如温度优先于湿度。

3.4 OLED显示界面设计

OLED显示是系统状态的窗口,信息需要清晰、直观。我们可以设计多页显示或滚动显示。

// bsp_oled.c 中的显示函数 void update_display(System_Status_t *status) { char str_buf[20]; OLED_Clear(); // 第一行:温度 sprintf(str_buf, "Temp:%2.1fC", status->temperature); OLED_ShowString(0, 0, str_buf, 12); // 第二行:湿度 sprintf(str_buf, "Humi:%2.1f%%", status->humidity); OLED_ShowString(0, 2, str_buf, 12); // 第三行:光照 sprintf(str_buf, "Light:%4dLx", status->light_intensity); OLED_ShowString(0, 4, str_buf, 12); // 第四行:土壤湿度 & 状态图标 sprintf(str_buf, "Soil:%3d%%", status->soil_moisture); OLED_ShowString(0, 6, str_buf, 12); // 在屏幕右侧显示执行器状态图标 // 加热器图标 if(status->heater_status) OLED_ShowChar(90, 0, 'H', 12, 1); // 加湿器图标 if(status->humidifier_status) OLED_ShowChar(90, 2, 'W', 12, 1); // 风扇图标 if(status->fan_status) OLED_ShowChar(90, 4, 'F', 12, 1); // 补光灯图标 if(status->light_status) OLED_ShowChar(90, 6, 'L', 12, 1); }

为了更丰富,可以增加一个页面显示设定阈值,或者通过按键切换显示页面。

4. 系统调试与功能扩展思路

4.1 调试过程中常见问题与解决方案

在实现这个系统的过程中,几乎每个初学者都会遇到一些典型问题。这里我把它整理成一个速查表,方便你快速定位:

问题现象可能原因排查步骤与解决方案
DHT11读取数据始终为0或2551. 时序不准确。
2. 上拉电阻未接或阻值不对(通常4.7K-10K)。
3. 电源电压不稳。
4. 传感器损坏。
1. 用逻辑分析仪或示波器抓取总线时序,检查起始信号和位读取时间。
2. 确保数据线有上拉电阻到3.3V。
3. 给DHT11的VCC和GND并联一个100uF电容稳压。
4. 更换传感器。
BH1750读取失败(HAL_I2C返回错误)1. I2C引脚配置错误(PB6/PB7)。
2. 上拉电阻缺失。
3. 从机地址错误(BH1750地址为0x23或0x5C)。
4. 测量等待时间不足。
1. 检查CubeMX中I2C配置,确认引脚复用正确。
2. SCL和SDA线必须接4.7K上拉电阻到3.3V。
3. 尝试两个地址(通常写地址0x46,读地址0x47)。
4. 发送测量命令后,至少延时120ms再读取。
OLED屏幕不显示或花屏1. I2C地址错误(通常0x78或0x7A)。
2. 初始化序列不正确。
3. 电源问题。
4. 对比度设置不当。
1. 用I2C扫描程序确认OLED的7位地址(通常是0x3C)。
2. 严格按照SSD1306数据手册的初始化流程编写代码。
3. 确保OLED模块供电稳定(3.3V或5V,视模块而定)。
4. 在初始化代码中发送设置对比度的命令(0x81, 0x7F)。
继电器或MOS管控制不动作1. GPIO输出模式配置错误(应推挽输出)。
2. 驱动电流不足。
3. 负载端电源未接通。
4. 未接续流二极管(对感性负载)。
1. 用万用表测量控制引脚电平,确认输出高低变化。
2. STM32 GPIO驱动能力有限,驱动大功率MOS管可能需要三极管扩流。
3. 检查执行器(风扇、加热片)的供电回路是否完整。
4. 在直流电机或继电器线圈两端并联一个1N4007二极管。
ADC采样值跳动剧烈1. 模拟电源噪声大。
2. 参考电压不稳。
3. 传感器信号受干扰。
1. 在STM32的VDDA和VSSA引脚附近加滤波电容(通常0.1uF和10uF并联)。
2. 确保VREF+稳定(如果独立引出)。
3. 对模拟输入信号加RC低通滤波(如1K电阻串联,0.1uF电容对地)。
4. 软件上采用多次采样取平均+滑动滤波。
系统运行一段时间后死机1. 看门狗未启用或未及时喂狗。
2. 堆栈溢出。
3. 中断服务程序处理时间过长。
4. 电源电压跌落。
1. 启用独立看门狗(IWDG),在主循环中定期喂狗。
2. 在启动文件(startup_stm32f103xe.s)中适当增大堆栈(Stack_Size)和堆(Heap_Size)。
3. 中断中只做标记,复杂处理放到主循环。
4. 检查电源带载能力,MCU电源引脚加去耦电容。

4.2 项目功能扩展与优化建议

完成基础功能后,你可以尝试以下扩展,让项目脱颖而出,在答辩或作业评分中获得高分:

  1. 增加人机交互(HMI)

    • 按键输入:增加几个按键,用于手动设置温度、湿度、光照的阈值。配合OLED菜单,实现参数的查看和修改。这需要你设计一个简单的菜单状态机。
    • 旋转编码器:用旋转编码器来调节数值,比按键更直观。需要处理编码器的正反转和按键中断。
  2. 数据记录与存储

    • EEPROM存储:使用STM32内部的Flash模拟EEPROM(或外接AT24Cxx芯片),将用户设定的阈值保存起来,掉电不丢失。HAL库提供了HAL_FLASHEx_DATAEEPROM_Write函数。
    • SD卡存储:通过SPI接口连接SD卡模块,将历史温湿度数据以CSV格式写入文件,便于后期在电脑上分析。可以配合FatFs文件系统。
  3. 远程监控与控制

    • 蓝牙模块(HC-05/06):通过串口连接蓝牙模块,手机APP(如串口调试助手或自己写的App)可以实时接收传感器数据并发送控制指令。这是性价比最高的无线方案。
    • Wi-Fi模块(ESP8266):通过AT指令控制ESP8266连接路由器,将数据上报到云平台(如OneNET、阿里云)或自己搭建的TCP服务器,实现网页远程监控。难度稍大,但更实用。
  4. 改进控制算法

    • 防震荡处理:在阈值控制中加入“回差”(Hysteresis)。例如,温度低于20度开启加热,但直到高于22度才关闭加热,这样避免在20度附近频繁开关。
    • 简易PID控制:对于补光灯的PWM调光,可以尝试实现一个简单的PID控制器,让光照强度能更稳定地维持在设定值附近,而不是简单的开关。
  5. 低功耗设计(适用于电池供电场景):

    • 使用STM32的休眠模式(Stop Mode),定时唤醒(通过RTC)进行数据采集和控制,其他时间休眠,大幅降低系统功耗。
    • 在休眠期间,关闭不必要的外设时钟(如ADC、I2C)。

4.3 作业报告撰写核心要点

一份优秀的作业报告和源码同等重要。报告不仅仅是代码的罗列,更是你设计思路和解决问题能力的体现。结构可以参考以下大纲:

  1. 摘要:用200-300字简述项目背景、实现功能、采用的技术和最终成果。
  2. 系统总体设计:包含系统框图、工作原理文字描述、硬件选型理由(为什么用STM32F103?为什么用DHT11?)。
  3. 硬件电路设计:给出核心部分的电路原理图(可以用立创EDA等工具绘制),并分模块讲解(电源、MCU最小系统、传感器接口、执行器驱动电路)。
  4. 软件设计:这是重点。
    • 软件流程图:主程序流程图、各子模块(如数据采集、控制逻辑)流程图。
    • 程序模块结构:展示你的.c/.h文件组织。
    • 关键代码分析:挑选2-3个最核心的函数(如DHT11读取、控制逻辑函数)进行详细注释和说明。
  5. 系统调试与测试
    • 测试环境:描述你是怎么测试的(例如,用吹风机模拟升温,用湿布靠近传感器模拟加湿)。
    • 测试数据:制作表格,记录在不同环境条件下,系统的输入(传感器值)和输出(执行器动作)是否符合预期。
    • 问题与解决:将你调试过程中遇到的主要问题(如前面提到的DHT11读取失败)和解决方法写进去,这是报告的亮点。
  6. 总结与展望:总结项目的完成情况、学到了什么、有哪些不足。对上述“功能扩展”部分的想法可以写在这里作为展望。
  7. 附录:完整的源代码(可以只贴关键部分,全部源码以附件形式)、元器件清单、参考文献。

记住,报告图文并茂,逻辑清晰,展现出你严谨的工程态度。这个基于STM32的温室大棚控制系统项目,从硬件到软件,从调试到报告,完整地走一遍,你对嵌入式系统的理解一定会上升一个实实在在的台阶。它不仅仅是为了交作业,更是为你后续更复杂的项目打下坚实的基础。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 23:40:15

SOTA实时语音转写模型落地前,先搞懂验证方法和避坑要点

Muse Voice Transcribe 是 MSL 发布的第一个实时音频感知模型&#xff0c;按照官方消息&#xff0c;它从今天开始逐步推出&#xff0c;定位是 SOTA。SOTA 这个词最近在模型圈热度很高&#xff0c;但严格说它不是一个能直接照搬的结论&#xff1a;模型在某个公开测试集上 SOTA&a…

作者头像 李华
网站建设 2026/9/5 23:38:47

基于Newmark-β迭代求解双线性单自由度结构动力响应

简介&#xff1a;本资源是一份面向本科及硕士阶段结构动力学教学与自学的MATLAB基础教程&#xff0c;聚焦双线性单自由度&#xff08;SDOF&#xff09;体系在地震激励下的非线性响应求解问题&#xff0c;采用Newmark-β法进行迭代数值积分。资源提供完整可运行的MATLAB实现方案…

作者头像 李华
网站建设 2026/9/5 23:36:40

Ultimate Vocal Remover 5.6 从零上手:完整跑通第一次人声提取

Ultimate Vocal Remover 5.6 从零上手&#xff1a;完整跑通第一次人声提取 【免费下载链接】ultimatevocalremovergui GUI for a Vocal Remover that uses Deep Neural Networks. 项目地址: https://gitcode.com/GitHub_Trending/ul/ultimatevocalremovergui Ultimate …

作者头像 李华
网站建设 2026/9/5 23:34:24

企业级WMS系统全解:Java实现、核心架构与高并发实战

简介&#xff1a;这是一套基于Java开发的商用级WMS物流仓储管理系统源码&#xff0c;面向第三方物流、自营仓储等企业及Java全栈开发者&#xff0c;旨在降低信息化实施成本并支持定制化扩展。系统采用SpringMVCHibernateMinidaoEasyUIRedisEhcache等主流技术栈&#xff0c;完整…

作者头像 李华