历史上的今天
今天是:2024年12月16日(星期一)
2021年12月16日 | STM32 NRF24L01实现无线传输
2021-12-16 来源:eefocus
前言
STM32下NRF24L01实现无线传输
一、原理图
1.STM32F103C8T6

2.NRF24L01

NRF24L01是 nordic 的无线通信芯片,它具有以下特点:
1) 2.4G 全球开放的 ISM 频段(2.400 - 2.4835GHz),免许可证使用;
2)最高工作速率 2Mbps,高校的 GFSK 调制,抗干扰能力强;
3) 125 个可选的频道,满足多点通信和调频通信的需要;
4)内置 CRC 检错和点对多点的通信地址控制;
5)低工作电压(1.9~3.6V),待机模式下状态为 26uA;掉电模式下为 900nA;
6)可设置自动应答,确保数据可靠传输;
7)工作于EnhancedShockBurst 具有Automatic packet handling,Auto packet transaction handling ,可以实现点对点或是 1 对 6 的无线通信,速度可以达到 2M(bps),具有可选的内置包应答机制,极大的降低丢包率。
8)通过 SPI 总线与单片机进行交互,最大通信速率为10Mbps;
二、Keil代码
1.SPI_NRF2401.C
#include "Struct.h"
/******************************************************************************
宏定义
*******************************************************************************/
#define NRF_CE_GPIO GPIOC
#define NRF_CE_Pin GPIO_Pin_14
#define NRF_CSN_GPIO GPIOC
#define NRF_CSN_Pin GPIO_Pin_13
#define NRF_IRQ_GPIO GPIOC
#define NRF_IRQ_Pin GPIO_Pin_15
#define NRF_CE_H NRF_CE_GPIO ->BSRR = NRF_CE_Pin //CE高电平
#define NRF_CE_L NRF_CE_GPIO ->BRR = NRF_CE_Pin //CE低电平
#define NRF_CSN_H NRF_CSN_GPIO->BSRR = NRF_CSN_Pin //CSN高电平
#define NRF_CSN_L NRF_CSN_GPIO->BRR = NRF_CSN_Pin //CSN高电平
#define NRF_IRQ_Read NRF_IRQ_GPIO->IDR & NRF_IRQ_Pin //IRQ读数据
/******************************************************************************
变量定义
*******************************************************************************/
uint8_t NRF24L01_RXDATA[32];//nrf24l01接收到的数据
uint8_t NRF24L01_TXDATA[32];//nrf24l01需要发送的数据
static uint8_t TX_ADDRESS[5]= {0x1A,0x2A,0x3A,0x4A,0x5A};//本地地址
static uint8_t RX_ADDRESS[5]= {0x1A,0x2A,0x3A,0x4A,0x5A};//接收地址
static uint16_t Nrf_Erro=0;
/******************************************************************************
函数原型: void SPI2_Init(void)
功 能: 初始化SPI总线
*******************************************************************************/
void SPI2_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
//配置SCK,MISO,MOSI引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用功能
GPIO_Init(GPIOB, &GPIO_InitStructure);
//配置CE引脚
GPIO_InitStructure.GPIO_Pin = NRF_CE_Pin;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_Init(NRF_CE_GPIO, &GPIO_InitStructure);
//配置CSN引脚
GPIO_InitStructure.GPIO_Pin = NRF_CSN_Pin;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_Init(NRF_CSN_GPIO, &GPIO_InitStructure);
//配置IRQ引脚
GPIO_InitStructure.GPIO_Pin = NRF_IRQ_Pin;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_Init(NRF_IRQ_GPIO, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource15);
EXTI_InitStructure.EXTI_Line=EXTI_Line15;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//外部中断
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿触发
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_Init(&EXTI_InitStructure);
NRF_CSN_H; //禁止NRF器件
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //双线全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主模式
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //数据大小8位
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //时钟极性,空闲时为低
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //第1个边沿有效,上升沿为采样时刻
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由软件产生
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //8分频,9MHz
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //高位在前
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2, &SPI_InitStructure);
SPI_Cmd(SPI2, ENABLE);//使能 SPI1
// PrintString("rn SPI2 初始化完成!");
}
/******************************************************************************
函数原型: uint8_t SPI_RW(uint8_t data)
功 能: SPI总线读写
返 回 值: 返回SPI总线读取数据
*******************************************************************************/
uint8_t SPI_RW(uint8_t data)
{
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);//当SPI发送缓冲器非空时等待
SPI_I2S_SendData(SPI2, data);//通过SPI总线发送一字节数据
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);//当SPI接收缓冲器为空时等待
return SPI_I2S_ReceiveData(SPI2);
}
/******************************************************************************
函数原型: uint8_t NRF_Write_Reg(uint8_t reg, uint8_t value)
功 能: NRF写寄存器
返 回 值: NRF写寄存器返回值
*******************************************************************************/
uint8_t NRF_Write_Reg(uint8_t reg, uint8_t value)
{
uint8_t status;
NRF_CSN_L; //选通NRF器件
status = SPI_RW(reg);//写寄存器地址
SPI_RW(value); //写数据
NRF_CSN_H; //禁止NRF器件
return status;
}
/******************************************************************************
函数原型: uint8_t NRF_Read_Reg(uint8_t reg)
功 能: NRF读寄存器
返 回 值: 寄存器数据
*******************************************************************************/
uint8_t NRF_Read_Reg(uint8_t reg)
{
uint8_t reg_val;
NRF_CSN_L; //选通NRF器件
SPI_RW(reg); //写寄存器地址
reg_val = SPI_RW(0);//读取该寄存器返回数据
NRF_CSN_H; //禁止NRF器件
return reg_val;
}
/******************************************************************************
函数原型: uint8_t NRF_Write_Buf(uint8_t reg, uint8_t *pBuf, uint8_t uchars)
功 能: NRF写缓冲区
返 回 值: NRF写缓冲区返回值
*******************************************************************************/
uint8_t NRF_Write_Buf(uint8_t reg, uint8_t *pBuf, uint8_t uchars)
{
uint8_t i;
uint8_t status;
NRF_CSN_L; //选通NRF器件
status = SPI_RW(reg);//写寄存器地址
for(i=0; i SPI_RW(pBuf[i]);//写数据 } NRF_CSN_H; //禁止NRF器件 return status; } /****************************************************************************** 函数原型: uint8_t NRF_Read_Buff(uint8_t reg, uint8_t *pBuf, uint8_t uchars) 功 能: NRF读缓冲区 返 回 值: 缓冲区数据 *******************************************************************************/ uint8_t NRF_Read_Buff(uint8_t reg, uint8_t *pBuf, uint8_t uchars) { uint8_t i; uint8_t status; NRF_CSN_L; //选通NRF器件 status = SPI_RW(reg);//写寄存器地址 for(i=0; i pBuf[i] = SPI_RW(0);//读取返回数据 } NRF_CSN_H; //禁止NRF器件 return status; } /****************************************************************************** 函数原型: void NRF24L01_Check(void) 功 能: 检查NRF器件是否正常 *******************************************************************************/ void NRF24L01_Check(void) { uint8_t buf[5]; uint8_t i; //写入5个字节的地址 NRF_Write_Buf(NRF_WRITE_REG+TX_ADDR,TX_ADDRESS,5); //读出写入的地址 NRF_Read_Buff(TX_ADDR,buf,5); //比较 for(i=0;i<5;i++) { if(buf[i]!=TX_ADDRESS[i]) break; } // if(i==5) // PrintString("rn NRF24L01 初始化成功!"); // else // PrintString("rn NRF24L01 初始化失败!"); } /****************************************************************************** 函数原型: static void NRF24L01_Set_TX(void) 功 能: 将NRF24L01设置为发送模式 *******************************************************************************/ static void NRF24L01_Set_TX(void) { NRF_CE_L; NRF_Write_Reg(NRF_WRITE_REG + CONFIG,0x0E);//发送 NRF_CE_H; } /****************************************************************************** 函数原型: static void NRF24L01_Set_RX(void) 功 能: 将NRF24L01设置为接收模式 *******************************************************************************/ static void NRF24L01_Set_RX(void) { NRF_CE_L; NRF_Write_Reg(NRF_WRITE_REG + CONFIG,0x0F);//接收 NRF_CE_H; } /****************************************************************************** 函数原型: void NRF_Send_TX(uint8_t * tx_buf, uint8_t len) 功 能: NRF2401发送数据包 *******************************************************************************/ void NRF_Send_TX(uint8_t * tx_buf, uint8_t len) { NRF24L01_Set_TX(); NRF_CE_L;//进入待机模式1 NRF_Write_Buf(WR_TX_PLOAD, tx_buf, len);//装载数据 NRF_CE_H;//设置CE为高,启动发射。CE高电平持续时间最小为10us } /****************************************************************************** 函数原型: void NRF24L01_Init(uint8_t Chanal,uint8_t Mode) 功 能: NRF24L01初始化 参 数: Chanal,RF通道 *******************************************************************************/ void NRF24L01_Init(uint8_t Chanal,uint8_t Mode) { NRF_CE_L; NRF_Write_Reg(FLUSH_TX,0xff);//清空发送缓冲区 NRF_Write_Reg(FLUSH_RX,0xff);//清空接收缓冲区 NRF_Write_Buf(NRF_WRITE_REG + TX_ADDR, TX_ADDRESS,5); //写TX节点地址 NRF_Write_Buf(NRF_WRITE_REG + RX_ADDR_P0,RX_ADDRESS,5); //写RX节点地址 NRF_Write_Reg(NRF_WRITE_REG + EN_AA, 0x01); //使能通道0的自动应答 NRF_Write_Reg(NRF_WRITE_REG + EN_RXADDR, 0x01); //使能通道0的接收地址 NRF_Write_Reg(NRF_WRITE_REG + SETUP_RETR,0x1a); //设置自动重发间隔时间:500us;最大自动重发次数:10次 NRF_Write_Reg(NRF_WRITE_REG + RF_CH, Chanal); //设置RF通道为CHANAL NRF_Write_Reg(NRF_WRITE_REG + RX_PW_P0, 32); //设置通道0的有效数据宽度 NRF_Write_Reg(NRF_WRITE_REG + RF_SETUP, 0x0f); //设置TX发射参数,0db增益,2Mbps,低噪声增益开启 if(Mode==TX) NRF_Write_Reg(NRF_WRITE_REG + CONFIG,0x0E);//发送 else if(Mode==RX) NRF_Write_Reg(NRF_WRITE_REG + CONFIG,0x0F);//接收 NRF_CE_H; } /****************************************************************************** 函数原型: static void NRF24L01_Analyse(void) 功 能: 分析NRF24L01收到的数据帧 *******************************************************************************/ static void NRF24L01_Analyse(void) { uint8_t sum = 0,i; uint8_t len = NRF24L01_RXDATA[3] + 5; //uint8_t i=0; for(i=3;i if( sum!=NRF24L01_RXDATA[len] ) return; //数据校验
史海拾趣
|
目前使用动态IP能连接上无线路由并上网,请问如何设置静态IP,是用WINCE的API还是只要把IP写入到注册表指定位置,系统自己处理?如果用API,需要哪些API?如果写注册表,具体写到哪,写哪些数据? … 查看全部问答> |
|
请问是不是所有的MCU都可以用hex或者bin两种文件作为下载文件 是否大部分MCU都可以用这两种文件作为烧写文件,除了个别厂家自己搞得一些其他格式文件 还有,我如何知道这个MCU是支持哪种文件的烧写格式的? 另:除了HEX是16进制文件,BIN是二进制文件这个区别外,两者在使用上还有其他的不同吗? 望高手指点 ...… 查看全部问答> |
|
请问如何在WinCE操作系统下,在程序中得到当前的函数调用堆栈?谢谢! 开发环境 EVC,PlatformBuilder 微处理器 Renesas SH-4 … 查看全部问答> |
|
请问冯诺依曼结构与哈佛结构的区别? 通过Google查询,有人如下解释: 区别是地址空间和数据空间分开与否 冯诺依曼结构数据空间和地址空间不分开 哈佛结构数据空间和地址空间是分开的 一般DSP都是采用改进型哈佛结构,就是分开的数据空间和地址空 ...… 查看全部问答> |
|
XSCALE pxa270的dma采集图像的问题,请帮忙解答 一个9HZ的摄像头通过并口输出一个14bit灰度图像,请问如何通过Xscale PXA270 的DMA 把数据放到内存里呢??… 查看全部问答> |
|
我在使用MDK11开发STR912的片子时,常出现仿真时c语言环境下执行顺序乱跳,根本没有按照设计者的顺序执行程序,这是怎么回事?以前使用MDK的早期版本开发NXP的片子时可从来没出现过这样的问题啊。… 查看全部问答> |




