串口模拟 nRF24L01 无线通信
·
用USART 串口透传替代其射频收发功能,保留原数据格式和通信逻辑,仅替换底层硬件实现,适配 Proteus 虚拟仿真。

二、设计步骤(分发送端 + 接收端)
第一步:STM32CubeIDE 工程配置(发送端 / 接收端通用)
- 新建工程:选择
STM32F103R6Tx,勾选 HAL 库,创建空工程。 - 时钟配置:HSE(8MHz)→PLL 倍频 9 倍→系统时钟 72MHz,APB1 时钟 36MHz(USART1 挂载 APB2,时钟 72MHz)。
- USART1 配置:
- 模式:异步通信(Asynchronous);
- 参数:波特率 9600、数据位 8、停止位 1、校验位 None、流控 Disabled;
- 引脚:PA9(USART1_TX,复用推挽)、PA10(USART1_RX,浮空输入)。
- GPIO 配置(可选,用于指示灯):
- 发送端:PB0→GPIO_Output(发送成功指示灯);
- 接收端:PB0→GPIO_Output(接收成功指示灯)。
- 生成代码:点击 “Project→Generate Code”,生成初始化工程。
第二步:Proteus 仿真电路搭建
- 添加元件:两个 STM32F103R6、两个 LED、两个 220Ω 电阻、COMPIM(虚拟串口)、电源和 GND。
- 电路连接:
- 电源:STM32 和虚拟串口均接 3.3V/GND;
- 串口交叉连接:发送端 PA9(TX)→接收端 PA10(RX),接收端 PA9(TX)→发送端 PA10(RX);
- 指示灯:发送端 PB0→220Ω 电阻→GND,接收端同理。
- 虚拟串口配置:双击 COMPIM,波特率设为 9600,其他参数与 CubeIDE 一致,确保两节点串口参数匹配。
第三步:代码编写(发送端 + 接收端)
1. 公共头文件(comm.h,发送端 / 接收端均需添加)
c
运行
#ifndef __COMM_H
#define __COMM_H
#include "stm32f1xx_hal.h"
// 模拟nRF24L01数据帧定义(自定义,保持收发一致)
#define NRF_DATA_LEN 32 // 单次最大数据长度(同nRF24L01)
typedef struct {
uint8_t header; // 帧头(用于校验)
uint8_t data[NRF_DATA_LEN]; // 数据内容
uint8_t checksum; // 校验和(header+data求和取低8位)
} NRF_FrameTypeDef;
// 函数声明
void NRF_Sim_SendData(UART_HandleTypeDef *huart, uint8_t *data, uint8_t len);
uint8_t NRF_Sim_ReceiveData(UART_HandleTypeDef *huart, NRF_FrameTypeDef *frame);
uint8_t Calculate_Checksum(NRF_FrameTypeDef *frame);
#endif
2. 公共源文件(comm.c,发送端 / 接收端均需添加)
c
运行
#include "comm.h"
// 计算校验和
uint8_t Calculate_Checksum(NRF_FrameTypeDef *frame) {
uint8_t sum = 0;
sum += frame->header;
for (uint8_t i = 0; i < NRF_DATA_LEN; i++) {
sum += frame->data[i];
}
return sum;
}
// 模拟nRF24L01发送数据(串口透传)
void NRF_Sim_SendData(UART_HandleTypeDef *huart, uint8_t *data, uint8_t len) {
NRF_FrameTypeDef frame;
frame.header = 0xAA; // 固定帧头(可自定义)
memset(frame.data, 0, NRF_DATA_LEN); // 数据清0
memcpy(frame.data, data, len > NRF_DATA_LEN ? NRF_DATA_LEN : len); // 填充数据
frame.checksum = Calculate_Checksum(&frame); // 计算校验和
// 串口发送完整帧
HAL_UART_Transmit(huart, (uint8_t*)&frame, sizeof(NRF_FrameTypeDef), 100);
}
// 模拟nRF24L01接收数据(串口接收+校验)
uint8_t NRF_Sim_ReceiveData(UART_HandleTypeDef *huart, NRF_FrameTypeDef *frame) {
// 接收完整帧
if (HAL_UART_Receive(huart, (uint8_t*)frame, sizeof(NRF_FrameTypeDef), 500) != HAL_OK) {
return 0; // 接收超时失败
}
// 校验帧头和校验和
if (frame->header != 0xAA || frame->checksum != Calculate_Checksum(frame)) {
return 0; // 校验失败
}
return 1; // 接收成功
}
3. 发送端 main.c(核心代码)
c
运行
#include "comm.h"
extern UART_HandleTypeDef huart1;
#define LED_TX_Pin GPIO_PIN_0
#define LED_TX_GPIO_Port GPIOB
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
uint8_t send_buf[] = "STM32_NRF_Sim_Tx: Hello!"; // 待发送数据
while (1) {
// 模拟nRF24L01发送
NRF_Sim_SendData(&huart1, send_buf, sizeof(send_buf));
// 发送成功指示灯闪烁
HAL_GPIO_TogglePin(LED_TX_GPIO_Port, LED_TX_Pin);
HAL_Delay(1000); // 1秒发送一次
}
}
// GPIO初始化(CubeIDE自动生成,需确保PB0为输出)
void MX_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = LED_TX_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LED_TX_GPIO_Port, &GPIO_InitStruct);
HAL_GPIO_WritePin(LED_TX_GPIO_Port, LED_TX_Pin, GPIO_PIN_RESET);
}
4. 接收端 main.c(核心代码)
c
运行
#include "comm.h"
extern UART_HandleTypeDef huart1;
#define LED_RX_Pin GPIO_PIN_0
#define LED_RX_GPIO_Port GPIOB
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
NRF_FrameTypeDef recv_frame;
while (1) {
// 模拟nRF24L01接收
if (NRF_Sim_ReceiveData(&huart1, &recv_frame) == 1) {
// 接收成功,指示灯闪烁
HAL_GPIO_TogglePin(LED_RX_GPIO_Port, LED_RX_Pin);
// 如需打印接收数据,可添加串口打印:
// HAL_UART_Transmit(&huart1, recv_frame.data, NRF_DATA_LEN, 100);
}
HAL_Delay(10); // 轻微延时,降低CPU占用
}
}
// GPIO初始化(CubeIDE自动生成,需确保PB0为输出)
void MX_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = LED_RX_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LED_RX_GPIO_Port, &GPIO_InitStruct);
HAL_GPIO_WritePin(LED_RX_GPIO_Port, LED_RX_Pin, GPIO_PIN_RESET);
}
三、仿真与验证步骤
- 代码编译:分别编译发送端和接收端工程,生成
.hex文件。 - Proteus 加载程序:双击两个 STM32F103R6,分别导入对应
.hex文件。 - 启动仿真:点击 Proteus “运行” 按钮,观察现象:
- 发送端 LED 每 1 秒闪烁一次,说明数据正常发送;
- 接收端 LED 同步闪烁,说明数据通过串口(模拟无线)接收成功。
- 故障排查:
- 若接收失败,检查串口参数是否一致(波特率、数据位等);
- 确认串口交叉连接(TX→RX),GND 是否共地;
- 查看帧头和校验和逻辑,确保收发端一致。
更多推荐



所有评论(0)