Files
player/Project/Src/Drive/Source/24l01.c
2025-07-05 19:47:28 +08:00

519 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "24l01.h"
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
#ifndef BOOTLOADER
#include "rthw.h"
#define IRQ_DISABLE() rt_enter_critical()
#define IRQ_ENABLE() rt_exit_critical()
#else
#define IRQ_DISABLE() { }
#define IRQ_ENABLE() { }
#endif
/*
+--------------------------+
|GND |3V3 | |
|-----------| |
|CE |CS | |
|-----------| |
|SCK |MOSI | |
|-----------| |
|MISO |INT | |
+--------------------------+
+--------------------------+
|GND |3V3 | |
|-----------| |
|PE3 |PE4 | |
|-----------| |
|PE2 |PE6 | |
|-----------| |
|PE5 |PB6 | |
+--------------------------+
*/
// 接口函数
static void nrf24l01_dalay_us(int us)
{
#ifndef BOOTLOADER
rt_hw_us_delay(us);
#else
for(int i=0;i<30;i++);
#endif
}
static u32 nrf24l01_det_random(void)
{
static int d=0;
d++;
return d;
}
// 24L01片选信号 PE3
#define NRF24L01_CE(s) GPIO_WriteBit(GPIOE,GPIO_Pin_3,(BitAction)s)
// SPI片选信号 PE4
#define NRF24L01_CSN(s) GPIO_WriteBit(GPIOE,GPIO_Pin_4,(BitAction)s)
// IRQ主机数据输入 PB6
#define NRF24L01_IRQ() GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)
typedef struct
{
// 总中断服务函数
void (*irq)(void);
// 发送完成回调
void (*send_end_cb)(void *);
void *send_end_cb_par;
// 接收到数据回调
void (*recved_cb)(void *);
void *recved_cb_par;
}nrf_struct;
static nrf_struct g_nrf={0};
static const u8 TX_ADDRESS[TX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //发送地址
static const u8 RX_ADDRESS[RX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //发送地址
void nrf24l01_spi_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI4,ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource2, GPIO_AF_SPI4);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource5, GPIO_AF_SPI4);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource6, GPIO_AF_SPI4);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
/*!< SPI SCK pin configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOE, &GPIO_InitStructure);
/*!< SPI MOSI pin configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOE, &GPIO_InitStructure);
/*!< SPI MISO pin configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOE, &GPIO_InitStructure);
/*!< Configure sFLASH Card CS pin in output pushpull mode ********************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOE, &GPIO_InitStructure);
//失能SPI外设
SPI_Cmd(SPI4, DISABLE);
//设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
//设置SPI工作模式:设置为主SPI
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
//设置SPI的数据大小:SPI发送接收8位帧结构
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
//串行同步时钟的空闲状态为低电平
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
//串行同步时钟的第1个跳变沿上升或下降数据被采样
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
//NSS信号由硬件NSS管脚还是软件使用SSI位管理:内部NSS信号有SSI位控制
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
//定义波特率预分频的值:波特率预分频值为256
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
//CRC值计算的多项式
SPI_InitStructure.SPI_CRCPolynomial = 7;
//根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
SPI_Init(SPI4, &SPI_InitStructure);
//使能SPI外设
SPI_Cmd(SPI4, ENABLE);
}
// 软件初始化,默认进入接收模式
void nrf24l01_sort_init(void);
//初始化24L01的IO口
void nrf24l01_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOE, ENABLE);//使能GPIOB,G时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_EXTIT,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟
// GE3 片选推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOE, &GPIO_InitStructure);
// GB6 中断输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //输入
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);
EXTI_InitTypeDef EXTI_InitStruct={0};
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB,EXTI_PinSource6);
EXTI_InitStruct.EXTI_Line= EXTI_Line6;
EXTI_InitStruct.EXTI_Mode= EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger= EXTI_Trigger_Falling;
EXTI_InitStruct.EXTI_LineCmd= ENABLE;
EXTI_Init(&EXTI_InitStruct);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 针对NRF的特点初始化SPI的设置
nrf24l01_spi_init();
NRF24L01_CE(0); //使能24L01
NRF24L01_CSN(1); //SPI片选取消
nrf24l01_sort_init();
}
// 去初始化
void nrf24l01_deinit(void)
{
EXTI_InitTypeDef EXTI_InitStruct={0};
EXTI_InitStruct.EXTI_Line= EXTI_Line6;
EXTI_InitStruct.EXTI_Mode= EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger= EXTI_Trigger_Falling;
EXTI_InitStruct.EXTI_LineCmd= DISABLE;
EXTI_Init(&EXTI_InitStruct);
NRF24L01_CE(0);
}
void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line6)==SET)
{
EXTI_ClearITPendingBit(EXTI_Line6);
if(g_nrf.irq) g_nrf.irq();
}
}
u8 spi_read_write_byte(u8 txdata)
{
// 等待发送区空
while (SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_TXE) == RESET){}
// 通过外设SPIx发送一个byte 数据
SPI_I2S_SendData(SPI4, txdata);
// 等待接收完一个byte
while (SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_RXNE) == RESET){}
// 返回通过SPIx最近接收的数据
return SPI_I2S_ReceiveData(SPI4);
}
//SPI写寄存器
//reg:指定寄存器地址
//value:写入的值
u8 nrf24l01_write_reg(u8 reg,u8 value)
{
u8 status;
NRF24L01_CSN(0); //使能SPI传输
status =spi_read_write_byte(reg);//发送寄存器号
spi_read_write_byte(value); //写入寄存器的值
NRF24L01_CSN(1); //禁止SPI传输
return(status); //返回状态值
}
//读取SPI寄存器值
//reg:要读的寄存器
u8 nrf24l01_read_reg(u8 reg)
{
u8 reg_val;
NRF24L01_CSN(0); //使能SPI传输
spi_read_write_byte(reg); //发送寄存器号
reg_val=spi_read_write_byte(0XFF);//读取寄存器内容
NRF24L01_CSN(1); //禁止SPI传输
return(reg_val); //返回状态值
}
//在指定位置读出指定长度的数据
//reg:寄存器(位置)
//*pBuf:数据指针
//len:数据长度
//返回值,此次读到的状态寄存器值
u8 nrf24l01_read_buf(u8 reg,u8 *pBuf,u8 len)
{
u8 status,u8_ctr;
NRF24L01_CSN(0); //使能SPI传输
status=spi_read_write_byte(reg);//发送寄存器值(位置),并读取状态值
for(u8_ctr=0;u8_ctr<len;u8_ctr++)pBuf[u8_ctr]=spi_read_write_byte(0XFF);//读出数据
NRF24L01_CSN(1); //关闭SPI传输
return status; //返回读到的状态值
}
//在指定位置写指定长度的数据
//reg:寄存器(位置)
//*pBuf:数据指针
//len:数据长度
//返回值,此次读到的状态寄存器值
u8 nrf24l01_write_buf(u8 reg, u8 *pBuf, u8 len)
{
u8 status,u8_ctr;
NRF24L01_CSN(0); //使能SPI传输
status = spi_read_write_byte(reg);//发送寄存器值(位置),并读取状态值
for(u8_ctr=0; u8_ctr<len; u8_ctr++)spi_read_write_byte(*pBuf++); //写入数据
NRF24L01_CSN(1); //关闭SPI传输
return status; //返回读到的状态值
}
//检测24L01是否存在
//返回值:0成功;1失败
u8 nrf24l01_check(void)
{
u8 i;
u8 old[5];
nrf24l01_read_buf(TX_ADDR,old,5);
u8 buf[5]={0XA5,0XA5,0XA5,0XA5,0XA5};
nrf24l01_write_buf(NRF_WRITE_REG+TX_ADDR,buf,5);//写入5个字节的地址.
nrf24l01_read_buf(TX_ADDR,buf,5); //读出写入的地址
for(i=0;i<5;i++)if(buf[i]!=0XA5)break;
if(i!=5)return 1;//检测24L01错误
nrf24l01_write_buf(NRF_WRITE_REG+TX_ADDR,old,5);//写入5个字节的地址.
return 0; //检测到24L01
}
// 设置地址,我的,对方的
void nrf24l01_set_addr(u8 my[5],u8 dst[5])
{
//写TX节点地址
nrf24l01_write_buf(NRF_WRITE_REG+TX_ADDR,(u8*)dst,TX_ADR_WIDTH);
//设置RX节点地址,主要为了使能ACK
nrf24l01_write_buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)my,RX_ADR_WIDTH);
}
// 设置通信信道
void nrf24l01_set_chan(u8 chan)
{
//设置RF通道为chan
nrf24l01_write_reg(NRF_WRITE_REG+RF_CH,chan&0x3f);
}
// 设置接收到数据的回调函数
void nrf24l01_set_recv_cb(void(*fun)(void *t),void *t)
{
g_nrf.recved_cb=fun;
g_nrf.recved_cb_par=t;
}
// 设置发送数据完成的回调函数
void nrf24l01_set_send_cb(void(*fun)(void *t),void *t)
{
g_nrf.send_end_cb=fun;
g_nrf.send_end_cb_par=t;
}
// 设置产生中断时的回调函数
void nrf24l01_set_irq_cb(void(*fun)(void))
{
g_nrf.irq=fun;
}
// 软件初始化,默认进入接收模式
void nrf24l01_sort_init(void)
{
g_nrf.irq=nrf24l01_irq;
NRF24L01_CE(0);
//写TX节点地址
nrf24l01_write_buf(NRF_WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS,TX_ADR_WIDTH);
//设置RX节点地址,主要为了使能ACK
nrf24l01_write_buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);
//禁止自动应答
nrf24l01_write_reg(NRF_WRITE_REG+EN_AA,0x00);
//使能通道0的接收地址
nrf24l01_write_reg(NRF_WRITE_REG+EN_RXADDR,0x01);
//选择通道0的有效数据宽度
nrf24l01_write_reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
//禁止自动重发
nrf24l01_write_reg(NRF_WRITE_REG+SETUP_RETR,0x0);
//设置RF通道为40
nrf24l01_write_reg(NRF_WRITE_REG+RF_CH,40);
//设置TX发射参数,0db增益,2Mbps,低噪声增益开启
nrf24l01_write_reg(NRF_WRITE_REG+RF_SETUP,0x0f);
//接收模式0xf;发送模式0xe开启crc16
nrf24l01_write_reg(NRF_WRITE_REG+CONFIG,0x0f);
u8 sta=0;
sta=nrf24l01_read_reg(STATUS);
// 清除TX_DS或MAX_RT中断标志
nrf24l01_write_reg(NRF_WRITE_REG+STATUS,sta);
// 如果rxfifo中有数据则不会再产生接收中断这里清除RX FIFO寄存器
nrf24l01_write_reg(FLUSH_RX,0xff);
//CE为高
NRF24L01_CE(1);
}
// 发送数据
// data要发送的数据指针
// len数据长度不能超过32字节
int nrf24l01_send(void *data)
{
NRF24L01_CE(0);
//接收模式0xf;发送模式0xe开启crc16
nrf24l01_write_reg(NRF_WRITE_REG+CONFIG,0x0e);
//写数据到TX BUF 32个字节
nrf24l01_write_buf(WR_TX_PLOAD,data,TX_PLOAD_WIDTH);
NRF24L01_CE(1);
return 0;
}
// 读取接收到的数据 ,返回0成功
// buf接收数据缓冲
int nrf24l01_read(void *buf)
{
nrf24l01_read_buf(RD_RX_PLOAD,buf,RX_PLOAD_WIDTH);//读取数据
return 0;
}
// nrf的中断服务函数
void nrf24l01_irq(void)
{
u8 sta=0;
sta=nrf24l01_read_reg(STATUS); //读取状态寄存器的值
nrf24l01_write_reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
if(sta&TX_OK)//发送完成
{
//发送完成之后自动切换为接收模式
NRF24L01_CE(0);
nrf24l01_write_reg(NRF_WRITE_REG+CONFIG,0x0f);
NRF24L01_CE(1);
if(g_nrf.send_end_cb)
g_nrf.send_end_cb(g_nrf.send_end_cb_par);
}
else if(sta&RX_OK)
{
if(g_nrf.recved_cb)
g_nrf.recved_cb(g_nrf.recved_cb_par);
// 读取之后清除RX FIFO寄存器
nrf24l01_write_reg(FLUSH_RX,0xff);
}
}