Files
player/Project/Src/Drive/Source/24l01.c

519 lines
13 KiB
C
Raw Normal View History

2025-06-27 00:32:57 +08:00
#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);
}
}