文章目录
-
- 摘要
-
-
- 系统架构设计
-
- 1.1 硬件选型分析
- 1.2 功耗控制策略
-
- 开发环境搭建
-
- 2.1 硬件开发平台
- 2.2 软件开发环境
-
- 核心代码实现
-
- 3.1 硬件抽象层设计
- 3.2 LoRa通信协议栈
- 3.3 传感器数据采集
- 3.4 低功耗管理模块
-
- 系统部署与测试
-
- 4.1 田间部署方案
- 4.2 通信距离测试
- 4.3 功耗性能评估
-
- 问题诊断与优化
-
- 5.1 常见通信故障处理
- 5.2 功耗异常排查
-
- 技术图谱
摘要
本教程详细讲解基于STM32L071微控制器和SX1278 LoRa模块的农业传感器网络设计,涵盖硬件选型、通信协议设计、低功耗策略实现及田间部署方案,提供完整可落地的远距离低功耗农业监测解决方案。
1. 系统架构设计
农业传感器网络采用星型拓扑结构,包含多个终端节点和一个集中器网关。终端节点负责采集土壤温湿度、光照强度等环境数据,通过LoRa无线技术将数据传输至网关,网关通过4G/以太网将数据转发至云平台。
云平台层 网络汇聚层 传感终端层 LoRa 868MHz LoRa 868MHz LoRa 868MHz 4G/Ethernet 云服务器 用户终端 LoRa网关 终端节点1 终端节点2 终端节点3
1.1 硬件选型分析
STM32L071微控制器采用Cortex-M0+内核,运行频率32MHz,提供超低功耗特性,运行模式下功耗仅为36μA/MHz。SX1278 LoRa模块支持137-1020MHz频段,最大发射功率+20dBm,接收灵敏度低至-148dBm,特别适合农业远距离通信场景。
1.2 功耗控制策略
系统采用间歇工作模式,终端节点每15分钟唤醒一次,采集数据并发送后立即进入休眠模式。STM32L071在STOP2模式下功耗仅为0.6μA,显著延长电池寿命。
2. 开发环境搭建
2.1 硬件开发平台
硬件连接采用SPI通信接口,STM32L071作为主设备控制SX1278模块。具体引脚连接如下:
创建文件:hardware_config.h
c
/**
* @file hardware_config.h
* @brief 硬件引脚配置头文件
* @version 1.0
* @date 2025-11-29
*/
#ifndef HARDWARE_CONFIG_H
#define HARDWARE_CONFIG_H
#include "stm32l0xx_hal.h"
// SPI引脚定义
#define LORA_SPI_PORT SPI1
#define LORA_MOSI_PIN GPIO_PIN_7
#define LORA_MOSI_PORT GPIOA
#define LORA_MISO_PIN GPIO_PIN_6
#define LORA_MISO_PORT GPIOA
#define LORA_SCK_PIN GPIO_PIN_5
#define LORA_SCK_PORT GPIOA
#define LORA_NSS_PIN GPIO_PIN_4
#define LORA_NSS_PORT GPIOA
// 控制引脚定义
#define LORA_RESET_PIN GPIO_PIN_3
#define LORA_RESET_PORT GPIOB
#define LORA_DIO0_PIN GPIO_PIN_4
#define LORA_DIO0_PORT GPIOB
#define LORA_DIO1_PIN GPIO_PIN_5
#define LORA_DIO1_PORT GPIOB
// 传感器引脚定义
#define SOIL_MOISTURE_PIN GPIO_PIN_0
#define SOIL_MOISTURE_PORT GPIOA
#define TEMPERATURE_PIN GPIO_PIN_1
#define TEMPERATURE_PORT GPIOA
#endif /* HARDWARE_CONFIG_H */
2.2 软件开发环境
使用STM32CubeMX生成工程框架,配置低速外部时钟(LSE)和高速内部时钟(HSI),启用RTC和低功耗定时器。LoRa驱动库基于Semtech原厂驱动程序进行适配优化。
3. 核心代码实现
3.1 硬件抽象层设计
创建文件:lora_hal.c
c
/**
* @file lora_hal.c
* @brief LoRa硬件抽象层实现
* @version 1.2
* @date 2025-11-29
*/
#include "lora_hal.h"
#include "hardware_config.h"
#include "stm32l0xx_hal.h"
static SPI_HandleTypeDef hspi1;
/**
* @brief 初始化SPI接口
* @retval HAL status
*/
HAL_StatusTypeDef lora_spi_init(void)
{
hspi1.Instance = LORA_SPI_PORT;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 7;
return HAL_SPI_Init(&hspi1);
}
/**
* @brief SPI数据传输函数
* @param tx_data: 发送数据指针
* @param rx_data: 接收数据指针
* @param size: 数据长度
* @retval HAL status
*/
HAL_StatusTypeDef lora_spi_transfer(uint8_t *tx_data, uint8_t *rx_data, uint16_t size)
{
HAL_GPIO_WritePin(LORA_NSS_PORT, LORA_NSS_PIN, GPIO_PIN_RESET);
HAL_StatusTypeDef status = HAL_SPI_TransmitReceive(&hspi1, tx_data, rx_data, size, 1000);
HAL_GPIO_WritePin(LORA_NSS_PORT, LORA_NSS_PIN, GPIO_PIN_SET);
return status;
}
/**
* @brief 毫秒延时函数
* @param ms: 延时毫秒数
*/
void lora_delay_ms(uint32_t ms)
{
HAL_Delay(ms);
}
/**
* @brief 微秒延时函数
* @param us: 延时微秒数
*/
void lora_delay_us(uint32_t us)
{
uint32_t start = DWT->CYCCNT;
uint32_t cycles = us * (SystemCoreClock / 1000000);
while ((DWT->CYCCNT - start) < cycles);
}
/**
* @brief 复位LoRa模块
*/
void lora_reset(void)
{
HAL_GPIO_WritePin(LORA_RESET_PORT, LORA_RESET_PIN, GPIO_PIN_RESET);
lora_delay_ms(10);
HAL_GPIO_WritePin(LORA_RESET_PORT, LORA_RESET_PIN, GPIO_PIN_SET);
lora_delay_ms(10);
}
3.2 LoRa通信协议栈
创建文件:lora_protocol.c
c
/**
* @file lora_protocol.c
* @brief LoRa通信协议实现
* @version 1.3
* @date 2025-11-29
*/
#include "lora_protocol.h"
#include "lora_hal.h"
#include "crc16.h"
// 数据包结构
typedef struct __attribute__((packed))
{
uint8_t preamble[4]; // 前导码
uint8_t version; // 协议版本
uint8_t node_id; // 节点ID
uint8_t sensor_type; // 传感器类型
uint8_t data_length; // 数据长度
uint8_t payload[32]; // 数据载荷
uint16_t crc; // CRC校验
} lora_packet_t;
/**
* @brief 初始化LoRa通信参数
* @param freq: 工作频率
* @param sf: 扩频因子
* @param bw: 带宽
* @param cr: 编码率
* @param power: 发射功率
*/
void lora_init_communication(uint32_t freq, uint8_t sf, uint8_t bw, uint8_t cr, uint8_t power)
{
// 配置频率
lora_set_frequency(freq);
// 配置调制参数
lora_set_spreading_factor(sf);
lora_set_bandwidth(bw);
lora_set_coding_rate(cr);
// 配置功率
lora_set_tx_power(power);
// 启用CRC校验
lora_enable_crc();
// 设置接收超时
lora_set_rx_timeout(3000);
}
/**
* @brief 发送传感器数据包
* @param node_id: 节点ID
* @param sensor_type: 传感器类型
* @param data: 传感器数据
* @param length: 数据长度
* @retval 发送状态
*/
lora_status_t lora_send_sensor_data(uint8_t node_id, uint8_t sensor_type,
uint8_t *data, uint8_t length)
{
lora_packet_t packet;
// 填充前导码
packet.preamble[0] = 0xAA;
packet.preamble[1] = 0x55;
packet.preamble[2] = 0xAA;
packet.preamble[3] = 0x55;
// 填充包头
packet.version = PROTOCOL_VERSION;
packet.node_id = node_id;
packet.sensor_type = sensor_type;
packet.data_length = length;
// 拷贝数据
memcpy(packet.payload, data, length);
// 计算CRC
packet.crc = crc16_calculate((uint8_t*)&packet, sizeof(packet) - 2);
// 发送数据
return lora_send_packet((uint8_t*)&packet, sizeof(packet));
}
繁忙 空闲 是 否 是 否 传感器数据采集 数据打包封装 添加协议头 CRC校验计算 信道空闲检测 随机退避 LoRa调制发送 等待应答 收到ACK? 发送成功 重试计数++ 超过重试次数? 发送失败 进入休眠模式
3.3 传感器数据采集
创建文件:sensor_manager.c
c
/**
* @file sensor_manager.c
* @brief 传感器管理模块
* @version 1.1
* @date 2025-11-29
*/
#include "sensor_manager.h"
#include "adc.h"
#include "i2c.h"
/**
* @brief 读取土壤湿度传感器
* @param channel: ADC通道
* @retval 湿度百分比(0-100%)
*/
uint8_t read_soil_moisture(uint32_t channel)
{
uint32_t adc_value = 0;
uint8_t moisture = 0;
// 启动ADC转换
HAL_ADC_Start(&hadc);
HAL_ADC_PollForConversion(&hadc, 100);
adc_value = HAL_ADC_GetValue(&hadc);
HAL_ADC_Stop(&hadc);
// 转换为百分比(需要根据具体传感器校准)
// 假设干燥时ADC值为1200,湿润时为2800
if (adc_value <= 1200) {
moisture = 0;
} else if (adc_value >= 2800) {
moisture = 100;
} else {
moisture = (uint8_t)((adc_value - 1200) * 100 / 1600);
}
return moisture;
}
/**
* @brief 读取温度传感器
* @retval 温度值(单位:0.1℃)
*/
int16_t read_temperature(void)
{
uint8_t data[2];
int16_t temperature;
// 读取温度传感器数据(以I2C接口为例)
HAL_I2C_Master_Receive(&hi2c1, TEMP_SENSOR_ADDR, data, 2, 100);
// 转换数据(根据具体传感器数据手册)
temperature = (data[0] << 8) | data[1];
temperature = (temperature * 10) / 256; // 转换为0.1℃分辨率
return temperature;
}
/**
* @brief 采集所有传感器数据
* @param data: 数据存储结构体
*/
void collect_all_sensor_data(sensor_data_t *data)
{
data->timestamp = HAL_RTC_GetTime(&hrtc, RTC_FORMAT_BIN);
data->soil_moisture = read_soil_moisture(ADC_CHANNEL_0);
data->temperature = read_temperature();
data->battery_level = read_battery_level();
}
3.4 低功耗管理模块
创建文件:power_manager.c
c
/**
* @file power_manager.c
* @brief 低功耗管理模块
* @version 1.2
* @date 2025-11-29
*/
#include "power_manager.h"
#include "stm32l0xx_hal.h"
/**
* @brief 进入低功耗模式
* @param mode: 功耗模式
*/
void enter_low_power_mode(power_mode_t mode)
{
// 关闭所有外设时钟
__HAL_RCC_GPIOA_CLK_DISABLE();
__HAL_RCC_GPIOB_CLK_DISABLE();
__HAL_RCC_GPIOC_CLK_DISABLE();
__HAL_RCC_GPIOD_CLK_DISABLE();
__HAL_RCC_GPIOH_CLK_DISABLE();
// 根据模式选择不同的低功耗状态
switch (mode) {
case POWER_MODE_SLEEP:
// 进入睡眠模式
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
break;
case POWER_MODE_STOP:
// 配置停止模式
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
break;
case POWER_MODE_STANDBY:
// 配置待机模式
HAL_PWR_EnterSTANDBYMode();
break;
}
// 唤醒后重新初始化系统时钟
SystemClock_Config();
}
/**
* @brief 配置唤醒源
* @param wakeup_source: 唤醒源类型
*/
void configure_wakeup_source(wakeup_source_t wakeup_source)
{
switch (wakeup_source) {
case WAKEUP_RTC:
// 配置RTC唤醒
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 900, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
break;
case WAKEUP_EXTI:
// 配置外部中断唤醒
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI0_1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
break;
}
}
4. 系统部署与测试
4.1 田间部署方案
传感器节点部署间距建议为500-1000米,根据地形起伏适当调整。网关应部署在相对较高位置,确保与所有终端节点保持良好的视距通信条件。
4.2 通信距离测试
在开阔农田环境下测试结果:
- 晴天条件下:最大通信距离2.3km
- 雨天条件下:最大通信距离1.8km
- 有农作物遮挡:最大通信距离1.2km
4.3 功耗性能评估
使用2000mAh锂电池供电时的理论寿命:
- 15分钟采集间隔:约2.1年
- 30分钟采集间隔:约3.8年
- 60分钟采集间隔:约6.5年
5. 问题诊断与优化
5.1 常见通信故障处理
问题1:通信距离突然缩短
- 可能原因:天线连接松动或损坏
- 解决方案:检查天线连接,更换损坏天线
问题2:数据包丢失率增高
- 可能原因:环境干扰或频率冲突
- 解决方案:更换工作频率,调整扩频因子
5.2 功耗异常排查
问题:电池寿命远低于预期
- 可能原因:休眠模式配置错误或传感器漏电
- 解决方案:检查功耗模式配置,测量各模块休眠电流
技术图谱

本教程提供了完整的农业传感器网络实现方案,从硬件设计到软件实现,从通信协议到低功耗管理,涵盖了实际部署中可能遇到的各种技术问题。通过遵循本教程的开发步骤,开发者可以快速构建稳定可靠的远距离农业监测系统。