|
【基于GDF350的无线数字对讲机】2、NRF24L01的SPI通讯
[复制链接]
nRF24L01是由NORDIC生产的工作在2.4GHz~2.5GHz的ISM 频段的单片无线收发器芯片。无线收发器包括:频率发生器、增强型“SchockBurst”模式控制器、功率放大器、晶体振荡器、调制器和解调器。
它的优点如下:
(1) 2.4Ghz 全球开放ISM 频段免许可证使用
(2) 最高工作速率2Mbps,高效GFSK调制,抗干扰能力强,特别适合工业控制场合
(3) 126 频道,满足多点通信和跳频通信需要
(4) 内置硬件CRC 检错和点对多点通信地址控制
(5) 低功耗1.9 - 3.6V 工作,待机模式下状态为22uA;掉电模式下为900nA
模块及原理图如下:
今天就来用GD32F350来驱动下这个芯片,NRF24L01使用SPI通讯,GDF350提供了两个SPI接口,我们使用SPI1来连接.用到的引脚PB6,PB6,PB12,PB13,PB14,PB15.复用功能0.
连接图如下:
关于SPI总线四种工作方式科普下,我当年就对这个不清楚。
CPOL=0,串行同步时钟的空闲状态为低电平;CPOL=1,串行同步时钟的空闲状态为高电平。
CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。
NRF24L01数据手册上给的时序图如下:
从中可以看出在配置SPI时钟极性的时候,应该配置为:同步时钟空闲状态为低电平,在同步时钟的第一个跳变沿数据被采样。(SPI_CK_PL_LOW_PH_1EDGE)
- /*
- * 函数名:spi_config
- * 描述 :SPI接口初始化
- * 输入 :
- * 输出 :
- * 调用 :api接口
- */
- void spi_config(void)
- {
- spi_parameter_struct SPI_InitStructure;
- /* 使能 SPI1 相关 GPIO 的时钟 */
- rcu_periph_clock_enable(RCU_GPIOB);
- rcu_periph_clock_enable(RCU_SPI1);
- /* 配置CS pin : Pb.12 */
- /* 配置ce pin : Pb.6 */
- gpio_mode_set(GPIOB,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLUP,PIN_CS|PIN_CE);
- gpio_output_options_set(GPIOB,GPIO_OTYPE_PP,GPIO_OSPEED_2MHZ,PIN_CS|PIN_CE);
- /*配置SPI_NRF_SPI的IRQ引脚,PB7 */
- gpio_mode_set(GPIOB,GPIO_MODE_INPUT,GPIO_PUPD_NONE,PIN_IRQ);
- /* 配置 SCK MISO MOSI*/
- gpio_af_set(GPIOB,GPIO_AF_0,PIN_MISO|PIN_MOSI|PIN_SCK);
- gpio_mode_set(GPIOB,GPIO_MODE_AF,GPIO_PUPD_NONE,PIN_SCK|PIN_MISO|PIN_MOSI);
- gpio_output_options_set(GPIOB,GPIO_OTYPE_PP,GPIO_OSPEED_10MHZ,PIN_SCK|PIN_MISO|PIN_MOSI);
- /* 这是自定义的宏,用于拉高csn引脚,NRF进入空闲状态 */
- NRF_CSN_HIGH();
- /* SPI1 配置*/
- SPI_InitStructure.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
- SPI_InitStructure.device_mode = SPI_MASTER;
- SPI_InitStructure.frame_size = SPI_FRAMESIZE_8BIT;
- SPI_InitStructure.nss = SPI_NSS_SOFT;
- SPI_InitStructure.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
- SPI_InitStructure.prescale = SPI_PSC_8;
- SPI_InitStructure.endian = SPI_ENDIAN_MSB;
- spi_init(SPI1, &SPI_InitStructure);
- spi_enable(SPI1);
- }
复制代码
还有CE,CS,IRQ这个按手册上配置就是了。没有什么技术难度。关于NRF24L01的驱动代码我也发出来
- /*!
- \file nRF24L01.h
- \brief 2.4GHz High-speed wireless transceiver chip(nRF24L01) driver.
- */
- /*
- Copyright (C) 2018 sunsjw
- 2018-09-09, V1.0.0
- */
- #include "gd32f3x0.h" // Device header
- #include "nRF24L01.h"
- #include "spi_api.h"
- #include "systick.h"
- // 定义一个静态发送地址
- static uint8_t TX_ADDRESS[TX_ADR_WIDTH] = {0x34,0x43,0x10,0x10,0x01};
- static uint8_t RX_ADDRESS[RX_ADR_WIDTH] = {0x34,0x43,0x10,0x10,0x01};
- uint8_t cdVal;
- uint8_t PackLoss;
- NRF_Mode _nRFMode;
- /*
- * 函数名:nRF24L01_Init
- * 描述 :nRF24L01 初始化
- * 输入 :
- * 输出 :
- * 调用 :api接口
- */
- void nRF24L01_Init(void)
- {
- spi_config();
- _nRFMode = Unknow;
- }
- /*
- * 函数名:SPI_NRF_WriteReg
- * 描述 :用于向NRF特定的寄存器写入数据
- * 输入 :reg:NRF的命令+寄存器地址。
- dat:将要向寄存器写入的数据
- * 输出 :NRF的status寄存器的状态
- * 调用 :内部调用
- */
- uint8_t SPI_NRF_WriteReg(uint8_t reg,uint8_t dat)
- {
- uint8_t status;
- spi_ce_disable();
- /*置低CSN,使能SPI传输*/
- spi_cs_enable();
- /*发送命令及寄存器号 */
- status = spi_write(reg);
- /*向寄存器写入数据*/
- spi_write(dat);
- /*CSN拉高,完成*/
- spi_cs_disable();
- /*返回状态寄存器的值*/
- return(status);
- }
- /*
- * 函数名:SPI_NRF_ReadReg
- * 描述 :用于从NRF特定的寄存器读出数据
- * 输入 :reg:NRF的命令+寄存器地址。
- * 输出 :寄存器中的数据
- * 调用 :内部调用
- */
- uint8_t SPI_NRF_ReadReg(uint8_t reg)
- {
- uint8_t reg_val;
- spi_ce_disable();
- /*置低CSN,使能SPI传输*/
- spi_cs_enable();
- /*发送寄存器号*/
- spi_write(reg);
- /*读取寄存器的值 */
- reg_val = spi_write(NOP);
- /*CSN拉高,完成*/
- spi_cs_disable();
- return reg_val;
- }
- /*
- * 函数名:SPI_NRF_ReadBuf
- * 描述 :用于从NRF的寄存器中读出一串数据
- * 输入 :reg:NRF的命令+寄存器地址。
- pBuf:用于存储将被读出的寄存器数据的数组,外部定义
- bytes: pBuf的数据长度
- * 输出 :NRF的status寄存器的状态
- * 调用 :外部调用
- */
- uint8_t SPI_NRF_ReadBuf(uint8_t reg,uint8_t *pBuf,uint8_t bytes)
- {
- uint8_t status, byte_cnt;
- spi_ce_disable();
- /*置低CSN,使能SPI传输*/
- spi_cs_enable();
- /*发送寄存器号*/
- status = spi_write(reg);
- /*读取缓冲区数据*/
- for(byte_cnt=0; byte_cnt<bytes; byte_cnt++)
- pBuf[byte_cnt] = spi_write(NOP); //从NRF24L01读取数据
- /*CSN拉高,完成*/
- spi_cs_disable();
- return status; //返回寄存器状态值
- }
- /*
- * 函数名:SPI_NRF_WriteBuf
- * 描述 :用于向NRF的寄存器中写入一串数据
- * 输入 :reg:NRF的命令+寄存器地址。
- pBuf:存储了将要写入写寄存器数据的数组,外部定义
- bytes: pBuf的数据长度
- * 输出 :NRF的status寄存器的状态
- * 调用 :外部调用
- */
- uint8_t SPI_NRF_WriteBuf(uint8_t reg,uint8_t *pBuf,uint8_t bytes)
- {
- uint8_t status,byte_cnt;
- spi_ce_disable();
- /*置低CSN,使能SPI传输*/
- spi_cs_enable();
- /*发送寄存器号*/
- status = spi_write(reg);
- /*向缓冲区写入数据*/
- for(byte_cnt=0; byte_cnt<bytes; byte_cnt++)
- spi_write(*pBuf++); //写数据到缓冲区
- /*CSN拉高,完成*/
- spi_cs_disable();
- return (status); //返回NRF24L01的状态
- }
- /*
- * 函数名:NRF_RX_Mode
- * 描述 :配置并进入接收模式
- * 输入 :无
- * 输出 :无
- * 调用 :外部调用
- */
- void NRF_RX_Mode(void)
- {
- _nRFMode = Recv;
- spi_ce_disable();
- SPI_NRF_WriteBuf(W_REGISTER+RX_ADDR_P0,RX_ADDRESS,RX_ADR_WIDTH);//写RX节点地址
- SPI_NRF_WriteReg(W_REGISTER+EN_AA,0x01); //使能通道0的自动应答
- SPI_NRF_WriteReg(W_REGISTER+EN_RXADDR,0x01);//使能通道0的接收地址
- SPI_NRF_WriteReg(W_REGISTER+RF_CH,CHANAL); //设置RF通信频率
- SPI_NRF_WriteReg(W_REGISTER+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0的有效数据宽度
- SPI_NRF_WriteReg(W_REGISTER+RF_SETUP,0x0f); //设置TX发射参数,0db增益,2Mbps,低噪声增益开启
- SPI_NRF_WriteReg(W_REGISTER+CONFIG, 0x0f); //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式
- /*CE拉高,进入接收模式*/
- spi_ce_enable();
- }
- /*
- * 函数名:NRF_TX_Mode
- * 描述 :配置发送模式
- * 输入 :无
- * 输出 :无
- * 调用 :外部调用
- */
- void NRF_TX_Mode(void)
- {
- _nRFMode = Send;
- spi_ce_disable();
- SPI_NRF_WriteBuf(W_REGISTER+TX_ADDR,TX_ADDRESS,TX_ADR_WIDTH); //写TX节点地址
- SPI_NRF_WriteBuf(W_REGISTER+RX_ADDR_P0,RX_ADDRESS,RX_ADR_WIDTH); //设置TX节点地址,主要为了使能ACK
- SPI_NRF_WriteReg(W_REGISTER+EN_AA,0x01); //使能通道0的自动应答
- SPI_NRF_WriteReg(W_REGISTER+EN_RXADDR,0x01); //使能通道0的接收地址
- SPI_NRF_WriteReg(W_REGISTER+SETUP_RETR,0x1a);//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次
- SPI_NRF_WriteReg(W_REGISTER+RF_CH,CHANAL); //设置RF通道为CHANAL
- SPI_NRF_WriteReg(W_REGISTER+RF_SETUP,0x0f); //设置TX发射参数,0db增益,2Mbps,低噪声增益开启
- SPI_NRF_WriteReg(W_REGISTER+CONFIG,0x0e); //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,发射模式,开启所有中断
- /*CE拉高,进入发送模式*/
- spi_ce_enable();
- delay_10us(1); //CE要拉高一段时间才进入发送模式
- }
- /*
- * 函数名:NRF_Check
- * 描述 :主要用于NRF与MCU是否正常连接
- * 输入 :无
- * 输出 :SUCCESS/ERROR 连接正常/连接失败
- * 调用 :外部调用
- */
- uint8_t NRF_Check(void)
- {
- uint8_t buf[5]= {0xC2,0xC2,0xC2,0xC2,0xC2};
- uint8_t buf1[5];
- uint8_t i;
- /*写入5个字节的地址. */
- SPI_NRF_WriteBuf(W_REGISTER+TX_ADDR,buf,5);
- /*读出写入的地址 */
- SPI_NRF_ReadBuf(TX_ADDR,buf1,5);
- /*比较*/
- for(i=0; i<5; i++)
- {
- if(buf1[i]!=0xC2)
- break;
- }
- if(i==5)
- return SUCCESS ; //MCU与NRF成功连接
- else
- return ERROR ; //MCU与NRF不正常连接
- }
- /*
- * 函数名:NRF_Tx_Dat
- * 描述 :用于向NRF的发送缓冲区中写入数据
- * 输入 :txBuf:存储了将要发送的数据的数组,外部定义
- * 输出 :发送结果,成功返回TXDS,失败返回MAXRT或ERROR
- * 调用 :外部调用
- */
- uint8_t NRF_Tx_Dat(uint8_t *txbuf)
- {
- uint8_t state;
- /*ce为低,进入待机模式1*/
- spi_ce_disable();
- /*写数据到TX BUF 最大 32个字节*/
- SPI_NRF_WriteBuf(W_TX_PAYLOAD,txbuf,TX_PLOAD_WIDTH);
- /*CE为高,txbuf非空,发送数据包 */
- spi_ce_enable();
- /*等待发送完成中断 */
- while(read_IRQ() != RESET)
- {
- if(_nRFMode == Recv)
- return MODECHANGE;
- }
- /*读取状态寄存器的值 */
- state = SPI_NRF_ReadReg(STATUS);
- /*清除TX_DS或MAX_RT中断标志*/
- SPI_NRF_WriteReg(W_REGISTER+STATUS,state);
- SPI_NRF_WriteReg(FLUSH_TX,NOP); //清除TX FIFO寄存器
- /*判断中断类型*/
- if(state&MAX_RT) //达到最大重发次数
- {
- //uint8_t cdVal = NRF_Carrier_Detect();
- //PackLoss = NRF_Check_PackageLoss();
- return MAX_RT;
- }
- else if(state&TX_DS) //发送完成
- return TX_DS;
- else
- {
- cdVal = NRF_Carrier_Detect();
- return ERROR; //其他原因发送失败
- }
- }
- /*
- * 函数名:NRF_Rx_Dat
- * 描述 :用于从NRF的接收缓冲区中读出数据
- * 输入 :rxBuf:用于接收该数据的数组,外部定义
- * 输出 :接收结果,
- * 调用 :外部调用
- */
- uint8_t NRF_Rx_Dat(uint8_t *pRxbuf)
- {
- uint8_t state;
- spi_ce_enable(); //进入接收状态
- /*等待接收中断*/
- while(read_IRQ() != RESET)
- {
- if(_nRFMode == Send)
- return MODECHANGE;
- }
- //进入待机状态
- spi_ce_disable();
- /* 读取status寄存器的值 */
- state=SPI_NRF_ReadReg(STATUS);
- /* 清除中断标志*/
- SPI_NRF_WriteReg(W_REGISTER+STATUS,state);
- /*判断是否接收到数据*/
- if(state& RX_DR) //接收到数据
- {
- SPI_NRF_ReadBuf(R_RX_PAYLOAD,pRxbuf,RX_PLOAD_WIDTH);//读取数据
- SPI_NRF_WriteReg(FLUSH_RX,NOP); //清除RX FIFO寄存器
- return SUCCESS;
- }
- else
- {
- cdVal = NRF_Carrier_Detect();
- PackLoss = NRF_Check_PackageLoss();
- return ERROR; //没收到任何数据
- }
- }
- /*
- * 函数名:NRF_Check_PackageLoss
- * 描述 :nRF24l01发送检测
- * 输入 :
- * 输出 :返回值的7-4位表示数据包丢失计数,3-0位表示重发计数
- * 调用 :外部调用
- */
- uint8_t NRF_Check_PackageLoss(void)
- {
- return SPI_NRF_ReadReg(OBSERVE_TX);
- }
- /*
- * 函数名:NRF_Carrier_Detect
- * 描述 :nRF24l01载波检测
- * 输入 :
- * 输出 :返回1,通道拥挤,需要更改通信频道
- * 调用 :外部调用
- */
- uint8_t NRF_Carrier_Detect(void)
- {
- return SPI_NRF_ReadReg(CD);
- }
- /*
- * 函数名:NRF_GetStatus
- * 描述 :获取nRF24l01的状态
- * 输入 :
- * 输出 :返回nRF24l01的发送和接收状态,
- * 调用 :外部调用
- */
- NRF_Mode NRF_GetStatus(void)
- {
- return _nRFMode;
- }
- /*
- * 函数名:NRF_SetStatus
- * 描述 :设置nRF24l01的状态
- * 输入 :
- * 输出 :
- * 调用 :中断调用
- */
- void NRF_SetStatus(NRF_Mode newMode)
- {
- _nRFMode = newMode;
- }
复制代码
代码还是做了很详细的注释,有疑问的同学可以留言。
|
|