#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); } }