445 lines
12 KiB
C
445 lines
12 KiB
C
#include "24l01.h"
|
||
#include "stdio.h"
|
||
#include "stdlib.h"
|
||
#include "stm32f4xx.h"
|
||
#include "string.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 uint32_t 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 uint8_t TX_ADDRESS[TX_ADR_WIDTH] = {
|
||
0x34, 0x43, 0x10, 0x10, 0x01
|
||
}; // 发送地址
|
||
static const uint8_t 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();
|
||
}
|
||
}
|
||
|
||
uint8_t spi_read_write_byte(uint8_t 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:写入的值
|
||
uint8_t nrf24l01_write_reg(uint8_t reg, uint8_t value) {
|
||
uint8_t status;
|
||
NRF24L01_CSN(0); // 使能SPI传输
|
||
status = spi_read_write_byte(reg); // 发送寄存器号
|
||
spi_read_write_byte(value); // 写入寄存器的值
|
||
NRF24L01_CSN(1); // 禁止SPI传输
|
||
return (status); // 返回状态值
|
||
}
|
||
|
||
// 读取SPI寄存器值
|
||
// reg:要读的寄存器
|
||
uint8_t nrf24l01_read_reg(uint8_t reg) {
|
||
uint8_t 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:数据长度
|
||
// 返回值,此次读到的状态寄存器值
|
||
uint8_t nrf24l01_read_buf(uint8_t reg, uint8_t *pBuf, uint8_t len) {
|
||
uint8_t 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:数据长度
|
||
// 返回值,此次读到的状态寄存器值
|
||
uint8_t nrf24l01_write_buf(uint8_t reg, uint8_t *pBuf, uint8_t len) {
|
||
uint8_t 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,失败
|
||
uint8_t nrf24l01_check(void) {
|
||
uint8_t i;
|
||
uint8_t old[5];
|
||
nrf24l01_read_buf(TX_ADDR, old, 5);
|
||
|
||
uint8_t 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(uint8_t my[5], uint8_t dst[5]) {
|
||
// 写TX节点地址
|
||
nrf24l01_write_buf(NRF_WRITE_REG + TX_ADDR, (uint8_t *)dst, TX_ADR_WIDTH);
|
||
|
||
// 设置RX节点地址,主要为了使能ACK
|
||
nrf24l01_write_buf(NRF_WRITE_REG + RX_ADDR_P0, (uint8_t *)my, RX_ADR_WIDTH);
|
||
}
|
||
|
||
// 设置通信信道
|
||
void nrf24l01_set_chan(uint8_t 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, (uint8_t *)TX_ADDRESS,
|
||
TX_ADR_WIDTH);
|
||
|
||
// 设置RX节点地址,主要为了使能ACK
|
||
nrf24l01_write_buf(NRF_WRITE_REG + RX_ADDR_P0, (uint8_t *)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);
|
||
|
||
uint8_t 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) {
|
||
uint8_t 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);
|
||
}
|
||
}
|