完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
前言
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);//写数据 } 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 = 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!=TX_ADDRESS) 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; //数据校验 if( NRF24L01_RXDATA[0] != '$' ) return; //数据校验 if( NRF24L01_RXDATA[1] != 'M' ) return; //数据校验 if( NRF24L01_RXDATA[2] != '>' ) return; //MWC发送给上位机的标志 // LEDGreen_ON; // if( NRF24L01_RXDATA[4] == MSP_FLY_DATA )//功能桢标志 // { // Battery_Fly =( (uint16_t)(NRF24L01_RXDATA[6]) << 8 ) | NRF24L01_RXDATA[5]; // THROTTLE1 = ( (uint16_t)(NRF24L01_RXDATA[8]) << 8 ) | NRF24L01_RXDATA[7]; // THROTTLE2 = ( (uint16_t)(NRF24L01_RXDATA[10]) << 8 ) | NRF24L01_RXDATA[9]; // THROTTLE3 = ( (uint16_t)(NRF24L01_RXDATA[12]) << 8 ) | NRF24L01_RXDATA[11]; // THROTTLE4 = ( (uint16_t)(NRF24L01_RXDATA[14]) << 8 ) | NRF24L01_RXDATA[13]; // pid[0].kp = NRF24L01_RXDATA[15]; // pid[0].ki = NRF24L01_RXDATA[16]; // pid[0].kd = NRF24L01_RXDATA[17]; // // pid[1].kp = NRF24L01_RXDATA[18]; // pid[1].ki = NRF24L01_RXDATA[19]; // pid[1].kd = NRF24L01_RXDATA[20]; // pid[2].kp = NRF24L01_RXDATA[21]; // pid[2].ki = NRF24L01_RXDATA[22]; // pid[2].kd = NRF24L01_RXDATA[23]; // // for(i=3;i<10;i++) // { // pid.kp=0; // pid.ki=0; // pid.kd=0; // } // } // else if( NRF24L01_RXDATA[4] == MSP_RAW_IMU || NRF24L01_RXDATA[4] == MSP_ATTITUDE )//功能桢标志 // Uart_Send(NRF24L01_RXDATA,len+1); } /****************************************************************************** 函数原型: void NRF24L01_IRQ(void) 功 能: NRF24L01中断 *******************************************************************************/ void NRF24L01_IRQ(void) { uint8_t status = NRF_Read_Reg(NRF_READ_REG + NRFRegSTATUS); if(status & (1< uint8_t rx_len = NRF_Read_Reg(R_RX_PL_WID);//收到数据长度 if(rx_len==32) { NRF_Read_Buff(RD_RX_PLOAD,NRF24L01_RXDATA,rx_len);//读取接收FIFO数据 Nrf_Erro = 0; } else { NRF_Write_Reg(FLUSH_RX,0xff);//清空接收缓冲区 } } if(status & (1< if(status & (1< NRF_Write_Reg(FLUSH_TX,0xff);//清空发送缓冲区 } } if(status & (1< NRF24L01_Set_RX();//设置Nrf2401为接收模式 } NRF_Write_Reg(NRF_WRITE_REG + NRFRegSTATUS, status);//清除中断标志位 } /****************************************************************************** 函数原型: void Nrf_Connect(void) 功 能: NRF24L01连接函数 *******************************************************************************/ void Nrf_Connect(void)//500HZ { Nrf_Erro++; if(Nrf_Erro==1) { NRF24L01_Analyse();//分析NRF24L01收到的数据帧 } if(Nrf_Erro%50==0)//0.1s未接收nrf数据 ,试图连接飞控 { NRF24L01_IRQ();//清除中断标志位 } if(Nrf_Erro>=500)//1s未接收nrf数据 ,关闭绿色LED指示灯 { // LEDGreen_OFF; Nrf_Erro = 1; // Battery_Fly = 0; } } 2.SPI_NRF24L01.h #ifndef _SPI_NRF24L01_H_ #define _SPI_NRF24L01_H_ #include "stm32f10x.h" /****************************************************************************** 宏定义 *******************************************************************************/ #define TX 1 #define RX 2 #define RX_DR 6 //接收数据中断.当接收到有效数据后置一。写‘1’清除中断。 #define TX_DS 5 //数据发送完成中断。当数据发送完成后产生中断。如果工作在自动应答模式下,只有当接收到应答信号后此位置一。写‘1’清除中断。 #define MAX_RT 4 //达到最多次重发中断。写‘1’清除中断。如果MAX_RT中断产生则必须清除后系统才能进行通讯。 #define TX_FULL 0 //TX FIFO寄存器满标志。 1:TX FIFO 寄存器满 0: TX FIFO 寄存器未满, 有可用空间。 /****************************************************************************** 全局变量声明 *******************************************************************************/ extern uint8_t NRF24L01_RXDATA[32];//nrf24l01接收到的数据 extern uint8_t NRF24L01_TXDATA[32];//nrf24l01需要发送的数据 /****************************************************************************** 全局函数声明 *******************************************************************************/ void SPI2_Init(void); void NRF24L01_IRQ(void); void NRF24L01_Check(void); void NRF24L01_Init(uint8_t Chanal,uint8_t Mode); void NRF_Send_TX(uint8_t * tx_buf, uint8_t len); void Nrf_Connect(void); uint8_t NRF_Read_Reg(uint8_t reg); uint8_t NRF_Write_Reg(uint8_t reg, uint8_t value); uint8_t NRF_Read_Buff(uint8_t reg, uint8_t *pBuf, uint8_t uchars); /****************************************************************************** NRF24L01寄存器指令 *******************************************************************************/ #define NRF_READ_REG 0x00 // 读寄存器指令 #define NRF_WRITE_REG 0x20 // 写寄存器指令 #define ACTIVATE 0x50 // follow with 0x73 to activate feature register #define R_RX_PL_WID 0x60 // 读接收缓冲区的长度 #define RD_RX_PLOAD 0x61 // 读取接收数据指令 #define WR_TX_PLOAD 0xA0 // 写待发数据指令 #define W_ACK_PAYLOAD 0xA8 // Used in RX mode. #define FLUSH_TX 0xE1 // 冲洗发送 FIFO指令 #define FLUSH_RX 0xE2 // 冲洗接收 FIFO指令 #define REUSE_TX_PL 0xE3 // 定义重复装载数据指令 #define NOP 0xFF // 保留 /****************************************************************************** NRF24L01寄存器地址 *******************************************************************************/ #define CONFIG 0x00 // 配置收发状态,CRC校验模式以及收发状态响应方式 #define EN_AA 0x01 // 自动应答功能设置 #define EN_RXADDR 0x02 // 可用信道设置 #define SETUP_AW 0x03 // 收发地址宽度设置 #define SETUP_RETR 0x04 // 自动重发功能设置 #define RF_CH 0x05 // 工作频率设置 #define RF_SETUP 0x06 // 发射速率、功耗功能设置 #define NRFRegSTATUS 0x07 // 状态寄存器 #define OBSERVE_TX 0x08 // 发送监测功能 #define CD 0x09 // 地址检测 #define RX_ADDR_P0 0x0A // 频道0接收数据地址 #define RX_ADDR_P1 0x0B // 频道1接收数据地址 #define RX_ADDR_P2 0x0C // 频道2接收数据地址 #define RX_ADDR_P3 0x0D // 频道3接收数据地址 #define RX_ADDR_P4 0x0E // 频道4接收数据地址 #define RX_ADDR_P5 0x0F // 频道5接收数据地址 #define TX_ADDR 0x10 // 发送地址寄存器 #define RX_PW_P0 0x11 // 接收频道0接收数据长度 #define RX_PW_P1 0x12 // 接收频道1接收数据长度 #define RX_PW_P2 0x13 // 接收频道2接收数据长度 #define RX_PW_P3 0x14 // 接收频道3接收数据长度 #define RX_PW_P4 0x15 // 接收频道4接收数据长度 #define RX_PW_P5 0x16 // 接收频道5接收数据长度 #define FIFO_STATUS 0x17 // FIFO栈入栈出状态寄存器设置 #define DYNPD 0x1C // per pipe DPL control #define FEATURE 0x1D // “Feature” register address #endif 3.Struct.h #ifndef _STRUCT_H_ #define _STRUCT_H_ #include "stm32f10x.h" #include "Led.h" #include "SPI_NRF24L01.h" #include "Uart.h" #endif 4.main.c #include "Struct.h" int main(void) { SPI2_Init(); //SPI2初始化 NRF24L01_Init(35,TX);//2401选择35通道,发送模式 NRF24L01_Check();//检测2401是否正常 PrintString("rn HEELO QST! rn"); } 总结 以上就是今天要讲的内容,本文仅仅简单介绍了基于STM32F103C8T6在Keil下编程实现NRF24L01实现无线传输的原理图和代码。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1777 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1621 浏览 1 评论
1080 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
728 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1678 浏览 2 评论
1938浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
731浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
570浏览 3评论
595浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
554浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 04:49 , Processed in 0.914701 second(s), Total 78, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号