tags: [source-summary] type: source source: "尚硅谷嵌入式技术之STM32单片机(高级篇)V2.0.1 — LoRa章节 + 配套代码13~14" author: "尚硅谷研究院" date: 2026-07-15
用生活理解:LoRa 就像"对讲机里的长跑冠军"——说话速度很慢(50bps),但声音能传出几公里,而且电池用几年不换。适合田野里的温度传感器每隔一小时报一次数。LoRa 是在水下吹气泡——气泡(信号)虽然升得慢,但能飘很远。
LPWAN = Low Power Wide Area Network(低功耗广域网),是 IoT 中连接远距离、低功耗设备的无线技术。
| 技术 | 频段 | 速率 | 优点 | 缺点 |
|---|---|---|---|---|
| LoRa | 470~510MHz(CN) / 868MHz(EU) / 915MHz(US) | 0.3~50Kbps | 私有化部署、成本低 | 速率低 |
| NB-IoT | 运营商授权频段 | ~250Kbps | 覆盖广、运营商维护 | 需 SIM 卡、有月费 |
| Sigfox | 868/915MHz | ~100bps | 超低功耗 | 速率极低、依赖 Sigfox 网络 |
| LTE-M | 运营商授权频段 | ~1Mbps | 速率较高 | 模组贵、功耗较高 |
LoRa 使用CSS(Chirp Spread Spectrum,啁啾扩频)调制。普通无线信号像"喊话"(功率集中在一小段频率),LoRa 像"吹口哨从低到高再从高到低"(信号散布在宽频带上)。
| 参数 | 可取值范围 | 说明 | 对性能的影响 |
|---|---|---|---|
| SF (扩频因子) | 6~12 | 每个 Chirp 符号代表的位数 | SF↑ → 灵敏度↑ → 速率↓ |
| BW (带宽) | 125 / 250 / 500 KHz | 调制信号的频率宽度 | BW↑ → 速率↑ → 灵敏度↓ |
| CR (编码率) | 4/5 ~ 4/8 | 前向纠错(FEC)冗余度 | CR↑ → 抗干扰↑ → 冗余↑ |
典型参数速查表:
| SF | BW(KHz) | 速率(bps) | 灵敏度(dBm) | 参考距离 |
|---|---|---|---|---|
| 7 | 125 | ~5470 | -123 | ~2km |
| 9 | 125 | ~1460 | -129 | ~3km |
| 12 | 125 | ~290 | -137 | ~5km |
| 12 | 250 | ~580 | -134 | ~3.5km |
SF12 + BW125 是最常见的高灵敏度配置,适合需要最远距离但数据量很少的场景。
CAD 是 LoRa 的一个特殊功能——在极低功耗下周期性监听空中是否有 LoRa 信号。如果检测到信号,唤醒 MCU 接收;无信号则快速返回休眠。
CAD 的意义:普通 LoRa 接收模式下,接收机须持续打开(功耗 ~10mA),而 CAD 的监听功耗极低(~5μA)。
LoRa 网络采用星型拓扑:
┌─→ 节点1 (SF12, 上报温度)
│
┌──────┐ ├─→ 节点2 (SF9, 上报湿度) ┌──────────┐
│ 网关 │←┼─→ 节点3 (SF7, 上报位移) ───→│ 云服务器 │
│(接收) │ └─→ ... │(数据存储)│
└──────┘ └──────────┘
↓
STM32(处理数据)
项目路径:stm32/13_lora_node_hal(节点)、stm32/14_lora_gateway_hal(网关)
实际代码使用 LLCC68 芯片 SPI 驱动 API,通过 SPI 配置 LoRa 射频参数并收发数据,而非 AT 指令。
文件:stm32/13_lora_node_hal/Core/Src/main.c(节点端)
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "lora.h"
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
// 定义全局变量,按键标志位,以及计数值
uint8_t isKeyed;
uint32_t count;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
// MX_SPI1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf("尚硅谷LoRa通讯实验:普通节点...\n");
LoRa_Init();
// 进入接收模式
LoRa_EnterRxMode();
// 定义接收缓冲区和长度
uint8_t rxBuff[256];
uint16_t rxLen;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
LoRa_RecvData(rxBuff, &rxLen);
if (rxLen > 0)
{
printf("收到数据:data: %.*s\n", rxLen, rxBuff);
// 清空长度
rxLen = 0;
}
if (isKeyed)
{
printf("按键按下!\n");
// 准备发送数据,拼接上按键次数
uint8_t msg[100] = {0};
sprintf((char *)msg, "一个普通LoRa节点,准备开始发送数据... %d", ++count);
LoRa_SendData(msg, strlen((char *)msg));
isKeyed = 0; // 清除标志位
// 再次进入接收模式
LoRa_EnterRxMode();
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == KEY_Pin)
{
// 延时消抖
HAL_Delay(100);
if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin))
{
isKeyed = 1;
}
}
}
/* USER CODE END 4 */
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
文件:stm32/14_lora_gateway_hal/Core/Src/main.c(网关端)
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "lora.h"
/* USER CODE END Includes */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
// MX_SPI1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf("尚硅谷LoRa通讯实验:网关节点...\n");
LoRa_Init();
// 进入接收模式
LoRa_EnterRxMode();
// 定义接收缓冲区和长度
uint8_t rxBuff[256];
uint16_t rxLen;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
LoRa_RecvData(rxBuff, &rxLen);
if (rxLen > 0)
{
printf("收到数据:data: %.*s\n", rxLen, rxBuff);
// 清空长度
rxLen = 0;
// 发送回复消息
uint8_t *msg = "网关已经收到你的数据,收到请回复...";
LoRa_SendData(msg, strlen((char *)msg));
// 再次进入接收模式
LoRa_EnterRxMode();
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
| 参数 | AT 指令 | 说明 |
|---|---|---|
| 工作模式 | AT+MODE=0 |
0=透传, 1=定点传 |
| 本机地址 | AT+ADDR=1 |
1~65535 |
| 目标地址 | AT+SEND=addr,len,data |
定点模式时指定 |
| 中心频率 | AT+BAND=470000000 |
单位 Hz(470~510MHz) |
| 扩频因子 | AT+SF=12 |
6~12 |
| 带宽 | AT+BW=125 |
125/250/500 KHz |
| 编码率 | AT+CR=1 |
1=4/5, 2=4/6, 3=4/7, 4=4/8 |
| 发射功率 | AT+POWER=20 |
0~20dBm |
| CAD 使能 | AT+CAD=1 |
0=关, 1=开(低功耗监听) |