简介:一份基于Atmel SAM L21 J18B低功耗单片机的嵌入式植物浇水控制应用工程,面向智能农业、物联网及嵌入式系统学习者,适合需要实现土壤湿度监测、自动灌溉和远程监控的开发者参考。资源以zip压缩包形式提供,整体约38.06MB,压缩包内文件清单未在下载页单独展示;工程围绕MATLAB数据分析与微控制器协同工作,涵盖ADC采样、传感器数据处理、RTC定时控制、RTOS任务调度及低功耗电源管理等多个设计环节。目前已有45人浏览学习,既可作为课程设计、电子竞赛的完整参考项目,也可用作产品原型开发的切入点。借助包内内容,读者可理解从硬件选型、电路布局到嵌入式程序编写,再到MATLAB算法建立与联调的完整流程,并可据此扩展湿度预测模型、无线通信控制等功能,形成更智能的浇水方案。
1. 办公室绿植的无人值守方案:低功耗单片机该选谁
办公室窗台上的绿植,周末两天没人浇水,周一回来叶子就蔫了。真正的难点不是让水泵转起来,而是让电池撑过整个夏天。基于 ATSAML21J18B 单片机开发板的嵌入式植物浇水控制应用,解决的就是这个组合问题:先用低功耗 Cortex-M0+ 采集土壤湿度,再用状态机决策水泵启停,最后让系统大部分时间睡在微安级电流里。
ATSAML21J18B 属于 Microchip SAM L21 系列,48MHz 主频、256KB Flash、32KB SRAM,待机功耗约 4µA。开发板和应用落到工程上,就是一张外设连接表、一套可抄的 C 状态机代码,以及一组实测的浇水参数,三者配合才能做到「平时不耗电、该浇才浇」。
谁适合用这个方案:做过单片机点亮 LED、想往低功耗方向深入的嵌入式工程师,以及做智能家居、小型农业监测、需要省电采样策略的从业者。示例代码以 ATSAML21J18B 的 HAL 为准,不绑定具体开发板型号。
2. ATSAML21J18B 开发板的选型理由与最小硬件连接
2.1 为什么选这颗单片机:待机功耗是植物浇水应用的第一指标
植物浇水是典型的慢变系统,土壤湿度一天内的变化不超过几十个百分点,采样周期取 5 分钟完全够用。这意味着单片机 99% 的时间都在空闲状态,决定续航的不是主频而是待机电流。SAM L21 系列在 48MHz 活动模式下电流约 35µA/MHz,进入 Standby 后配合 RTC 保持计时,整机电流约 3.9µA,两节 AA 电池可以跑一年以上。
| 单片机 | 内核 | 典型待机电流 | 适合场景 |
|---|---|---|---|
| ATSAML21J18B | Cortex-M0+ | 3.9µA | 电池供电传感节点、本方案 |
| STM32L431 | Cortex-M4 | 3.4µA | 需要 DSP、浮点运算 |
| ESP32 | Xtensa LX6 | 10µA 以上 | 需要 Wi-Fi、云端联动 |
从外设角度看,这颗芯片自带 12 位 ADC、两组 SERCOM(可配置为 UART/I2C/SPI)、RTC 和看门狗,植物浇水应用需要的模块全部内置,不需要再挂额外芯片。选它能省掉「低功耗单片机 + 外部前端」的组合,把传感、决策、驱动三件事放在一颗芯片上完成,BOM 和调试链路都更短。
2.2 外设分配表:土壤湿度、水泵驱动与调试串口的引脚规划
开发板引出引脚有限,接线前先做一张分配表,比边接边试可靠得多。以下是一套常见的规划,传感器、执行器和人机接口互不冲突:
| 外设 | 引脚 | 复用功能 | 说明 |
|---|---|---|---|
| 土壤湿度传感器 | PA02 | AIN0 | 12 位 ADC 输入,接传感器模拟输出 |
| 水泵 MOS 管驱动 | PB10 | GPIO 输出 | 经 AO3400 驱动 3.3V 微型水泵 |
| UART 调试 | PA10 / PA11 | SERCOM3 | 115200-8-N-1,打印湿度与状态 |
| OLED 显示(可选) | PA16 / PA17 | SERCOM1 I2C | 显示湿度百分比与电池电压 |
传感器输出端到 PA02 之间串一个 1kΩ 电阻,再并联 100nF 电容,滤掉电源纹波带来的读数抖动。水泵不要用 GPIO 直接驱动,3.3V 单片机引脚输出电流有限,接一个 N-MOS(AO3400)用 PB10 控制栅极,泵由电池正极供电。调试串口留在开发板上还有个好处:量产前跳掉,仅保留 PA02 和 PB10 两根信号线进主控,整机故障率会明显下降。
2.3 最小工程:Microchip Studio 下的裸机框架
这类应用不建议上 RTOS,任务只有「采样、决策、浇水、计时」四个,裸机状态机更好排查。开发环境用 Microchip Studio 或 MPLAB X,新建工程时用 Atmel START 生成初始化代码,把 ADC0、RTC、SERCOM3、WDT 勾上,生成后入口就是 atmel_start_init。主函数只做两件事:初始化,然后进入由 RTC 唤醒的主循环。
#include <atmel_start.h> #include <hal_adc_sync.h> #include <hal_gpio.h> #define PUMP_PIN PIN_PB10 volatile uint8_t wakeup_flag = 0; void RTC_0_Handler(void) { wakeup_flag = 1; /* RTC 定时唤醒,置位后主循环处理 */ RTC_0_rtc_clear_interrupt(); } int main(void) { atmel_start_init(); /* 时钟、GPIO、ADC、RTC、WDT 初始化 */ gpio_set_pin_direction(PUMP_PIN, GPIO_DIRECTION_OUT); gpio_set_pin_level(PUMP_PIN, false); /* 上电默认关泵,防止误喷 */ while (1) { if (wakeup_flag) { wakeup_flag = 0; watering_poll(); /* 采样湿度并按状态机决策 */ } sleep_mode_enter(); /* 进入 Standby,见第 4 章 */ } }atmel_start_init 由 Atmel START 生成,负责把时钟配置到 48MHz、使能需要用到的外设和中断。PUMP_PIN 对应数据手册上的 PB10,上电先拉低是安全设计,否则复位瞬间水泵可能因为引脚浮空而误转。watering_poll 的实现放在第 3 章。sleep_mode_enter 不是标准库函数,是我们在第 4.2 节封装的 Standby 进入函数。Microchip 官方例程库和不少嵌入式开源项目都提供 SAM L21 的 low-power 例程,对着烧录一遍就能确认这套框架的基本形态。
3. ATSAML21J18B 的土壤湿度采样与浇水控制状态机实现
3.1 电容式湿度传感器的 ADC 采样与均值滤波参数
市面常见的土壤湿度传感器分两类。电阻式靠两根金属探针测土壤导电率,便宜,但直流极化会让探针几个月内氧化,读数漂移明显;电容式用 PCB 铜箔做极板,测介电常数,不与土壤金属离子直接接触,寿命长。对无人值守的浇水控制应用,电容式是更稳的选择。电容式传感器输出 0~3.3V 模拟电压,干燥时电压偏高(约 2.6V),湿润时偏低(约 1.2V),正好落在 ATSAML21J18B 的 12 位 ADC 量程内。
ADC 采样不能只读一次。传感器输出经过输出电阻和滤波电容形成一阶低通,单次读数的噪声通常在 ±30 counts,直接用于阈值判断会出现干湿抖动。常见做法是每个采样点读 8 次、间隔 10ms,取平均作为有效值:
static uint16_t read_soil_moisture(void) { uint16_t raw = 0; uint32_t sum = 0; uint8_t i; for (i = 0; i < 8; i++) { adc_sync_read_channel(&ADC_0, 0, (uint8_t *)&raw, 2); sum += raw; delay_ms(10); /* 等传感器输出进入平稳区 */ } return (uint16_t)(sum / 8); }adc_sync_read_channel 是 SAM L21 HAL 的同步读接口,第三个参数是输出缓冲区,第四个参数是字节数,12 位结果占 2 字节。8 次采样合计约 80ms,只在唤醒后执行一次,对整机待机电流影响很小。如果传感器线缆超过 20cm,把间隔提到 20ms、滤波电容从 100nF 加大到 1µF,读数会平滑很多,代价是响应变慢,但对分钟级系统无所谓。
3.2 浇水决策状态机:双阈值迟滞与二次确认
判断「该不该浇水」最忌讳单阈值:湿度在阈值附近波动时,水泵会频繁启停。解决方案是双阈值迟滞——低于 THRESH_DRY 判定干燥,高于 THRESH_WET 判定湿润,两个阈值之间留 600 counts 左右的死区。另一个工程习惯是二次确认:第一次采到干燥后不立即浇水,等下一个采样周期再确认一次,拦截掉传感器被叶片遮住或探头悬空造成的假读数。
typedef enum { ST_IDLE, ST_CONFIRM, ST_PUMPING, ST_COOLDOWN } state_t; state_t state = ST_IDLE; uint8_t dry_confirm = 0; uint32_t pump_start_ms = 0; void watering_poll(void) { uint16_t m = read_soil_moisture(); switch (state) { case ST_IDLE: if (m < THRESH_DRY) { /* 第一次干燥,进入确认态 */ state = ST_CONFIRM; dry_confirm = 1; } break; case ST_CONFIRM: if (m < THRESH_DRY) { /* 第二个周期仍干燥,开始浇水 */ gpio_set_pin_level(PUMP_PIN, true); pump_start_ms = now_ms(); state = ST_PUMPING; } else { dry_confirm = 0; /* 湿度回升,撤销浇水决定 */ state = ST_IDLE; } break; case ST_PUMPING: if (now_ms() - pump_start_ms >= PUMP_ON_MS) { gpio_set_pin_level(PUMP_PIN, false); state = ST_COOLDOWN; /* 进入抑制期,等水分扩散 */ } break; case ST_COOLDOWN: /* 状态不变,由 RTC 计时到期后统一切回 ST_IDLE */ break; } }状态切换的关键在 ST_CONFIRM:它把「一次干燥采样」和「两次干燥采样」区分开,拦截掉大部分瞬时干扰。ST_PUMPING 里 PUMP_ON_MS 是硬上限,即使传感器失效、读数一直偏低,水泵最多转 30 秒就停,不会出现淹花盆的故障。now_ms 是 SysTick 中断里累加的 uint32 毫秒计数,溢出周期约 49.7 天,对这个应用足够。ST_COOLDOWN 的状态切换放在 RTC 中断回调里做,不在 watering_poll 里延时等待。
提示:ST_COOLDOWN 在 WDT 复位后会丢失。把上次浇水时刻写入 RTC 或 Flash 备份区,复位后重新核算抑制期,否则刚浇完水系统重启,下一轮采样又会判定干燥。
3.3 浇水时长与复检逻辑的参数表
参数标定按「花盆大小、基质类型、泵流量」三个变量折算。以口径 15cm、装填泥炭土的花盆为例,微型隔膜泵流量约 300mL/min,浇透需要 120~180mL 水,对应泵运行 30 秒左右。节奏参数常见设定如下:
| 参数 | 推荐值 | 设定依据 |
|---|---|---|
| THRESH_DRY | 1800(12 位 ADC 码值) | 泥炭土完全干燥时的实测中值 |
| THRESH_WET | 1200 | 浇透后静置 10 分钟的读数 |
| PUMP_ON_MS | 30000 | 目标浇水量 ÷ 泵流量 |
| COOLDOWN_MS | 3600000 | 浇水后 1 小时内不重复启动 |
| SAMPLE_PERIOD | 300000 | 5 分钟唤醒一次采样 |
两个阈值不是固定的。同一块泥炭土,压实前后干湿读数差 300 counts;换成椰糠基质整体偏低。正确标定方式是先把传感器埋入正常湿度土壤,用串口连续打印读数,取 24 小时内干湿极值的 20% 与 80% 分位当阈值,第 5 章给出具体步骤。
4. 嵌入式低功耗调度:RTC 唤醒与看门狗恢复
4.1 用 RTC 周期中断代替 delay 定时采样
主循环里不能用 delay 等 5 分钟,那样单片机停在活动模式,电流会到毫安级。SAM L21 的 RTC 支持周期中断,由外部 32.768kHz 晶振或内部 OSC32K 提供计数时钟,配置好周期后自动唤醒。下面是 Atmel START 生成的代码里修改周期值的示意,接口名称在不同 HAL 版本有差异,逻辑不变:
static void rtc_arm(uint32_t seconds) { struct rtc_module *rtc = &RTC_0; rtc_disable(rtc); /* 改配置前必须先失能 */ rtc_set_period(rtc, RTC_PERIOD_CYC32_CPRD, seconds); rtc_enable(rtc); }rtc_set_period 的第三参数是秒数换算后的计数周期值。RTC 使能后每隔 SAMPLE_PERIOD 触发一次中断,中断服务函数里只置位 wakeup_flag 就返回,不采样、不驱动泵,把中断上下文控制在 1µs 量级。采样任务放主循环做,避免长时间占用中断导致其他外设中断丢失。SAMPLE_PERIOD 换算成的周期值超过 16 位时要确认 HAL 内部用的是 32 位周期寄存器,SAM L21 支持这个模式,但代码里要显式声明。
4.2 进入 Standby 的封装与唤醒后的外设恢复
ATSAML21J18B 的 Standby 模式由 PM 的 SLEEPCFG 寄存器控制,置位后执行 WFI 指令进入。进入前要把 ADC、SERCOM 逐个关掉,否则外设时钟仍维持,实际睡眠电流会比数据手册值高出一截。常见封装如下:
void sleep_mode_enter(void) { adc_sync_disable(&ADC_0); /* 关 ADC,省掉采样电路静态电流 */ PM->SLEEPCFG.bit.SLEEPMODE = PM_SLEEPCFG_SLEEPMODE_STANDBY_Val; __WFI(); /* 唤醒后按数据手册建议重新使能外设 */ adc_sync_enable(&ADC_0); }SLEEPMODE 的具体枚举值由头文件里的 PM_SLEEPCFG_SLEEPMODE_STANDBY_Val 宏给出,不同型号编码不一样。唤醒后外设时钟不是自动恢复的,Atmel START 生成的初始化是一次性的,所以 WFI 之后要立即重新使能 ADC,并在下一次采样前等约 1ms 让内部参考源建立——直接采样会拿到前几次转换的残留值。想验证睡眠电流是否达标,用万用表串入电池供电回路,读数应该落在 4~10µA 之间,如果高出几个数量级,多半是有外设没关干净。
注意:SLEEPMODE 的枚举编码在 SAM D21 与 SAM L21 上不同,移植到其他系列以前务必对照数据手册的 PM 章节。
4.3 看门狗兜底与复位后的安全状态
状态机再严谨,也挡不住寄存器被干扰跳飞。给整个系统加看门狗,超时自动复位,是出厂前的必备步骤。SAM L21 的 WDT 配置如下:
void wdt_init(void) { WDT->CTRLA.bit.ENABLE = 0; /* 写配置前先失能 */ WDT->CONFIG.reg = WDT_CONFIG_PER(0xA); /* 超时约 8 秒,以手册表为准 */ WDT->CTRLA.bit.ENABLE = 1; }WDT_CONFIG_PER 的参数与超时秒数的对应关系在不同系列上不一样,0xA 在 SAM L21 上对应 8 秒级别,量产前以数据手册的 WDT 超时表为准。主循环每轮喂一次狗,喂狗放在进入睡眠之前,保证「唤醒 → 处理 → 睡眠」的完整循环里狗不会被饿死。如果程序在浇水过程中卡死,WDT 复位后 main 从头执行,上电默认关泵的动作保证复位瞬间泵一定是停止状态,不会带着卡死前的高电平继续转。
5. 植物浇水控制应用的阈值校准与整机验证
5.1 用串口打印湿度曲线标定双阈值
开发板接上串口,每 30 秒打印一次采样值:
printf("moisture=%u\r\n", read_soil_moisture());花盆浇透后静置到表层发白,整个过程记录 24 小时,得到干燥极值和湿润极值,按 (max - min) × 20% 与 × 80% 算出 THRESH_DRY 和 THRESH_WET,写回参数表再跑一天,观察状态切换是否符合预期。注意串口波特率要与开发板电路匹配,115200 下输出量很小,不会对低功耗测试造成干扰。
5.2 三个常见误用与对应处理
- 探头埋太浅:读数受表层蒸发影响大,湿度曲线剧烈抖动,加大死区到 800 counts 依然误触发,把探头埋到 5cm 以下即可解决。
- 浇水后立即复检:水会顺着传感器外壳流下,造成「刚浇完就很湿」的假信号,复检必须等 COOLDOWN 到期后再做。
- 供电电压变化:传感器输出是比例式的,电池从 3.7V 掉到 3.2V,同一湿度下的 ADC 码值会偏高,软件里用 VCC / 4095 换算成百分比再比较。
5.3 交付前的验证清单与复位保护
| 验证项 | 方法 | 通过标准 |
|---|---|---|
| 待机电流 | 万用表串入电池供电回路 | 睡眠状态下 ≤ 10µA |
| WDT 复位恢复 | 浇水时强制重启 | 复位后泵必须处于关断状态 |
| 连续运行 | 无人值守跑 48 小时,串口记录全部事件 | 浇水次数与预期一致,无一次误动作 |
跑完 48 小时后,如果日志与实际浇水次数对不上,优先检查 COOLDOWN 状态有没有被复位清掉——这是裸机状态机最容易丢的一个状态。把上次浇水的时间戳存在 RTC 的计时寄存器里,设备启动时先读回来核算剩余抑制期,再决定是否允许进 ST_CONFIRM。这个复位保护比任何阈值标定都重要。
本文还有配套的精品资源,点击获取