• 正文
  • 相关推荐
申请入驻 产业图谱

CW32L012/F030灵眸X1智能小车——使用NRF24L01通信

16小时前
212
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

一、NRF24L01模块介绍

引脚介绍

NRF24L01所使用的通讯协议为SPI,SPI又可分为软件SPI和硬件SPI。

硬件SPI与软件SPI相比,硬件SPI是靠硬件上面的SPI控制器,所有的时钟边缘采样,时钟发生,还有时序控制,都是由硬件完成的。它降低了CPU的使用率,提高了运行速度。软件SPI就是用代码控制IO输出高低电平,模拟SPI的时序,这种方法通信速度较慢,且不可靠。

想要使用硬件SPI驱动,需要确定使用的引脚是否有SPI外设功能。可以通过用户手册146页进行查看。

当前使用的是硬件SPI接口,而NRF24L01我们需要与它发送数据也需要接收数据,故使用的是4线的SPI,使用到了时钟线SCK、主机输出从机输入线MOSI、主机输入从机输出线MISO和软件控制的片选线NSS。所以除了这些引脚需要使用硬件SPI功能的引脚外,其他引脚都可以使用开发板上其他的GPIO。这里选择使用PB13/PB14/PB15的SPI复用功能 。其他对应接入的引脚请按照你的需要。这里选择的引脚见下表。

模块在开发板上的接线为:

GND  ->GND

VCC  ->3.3V

CSN  ->PA10

CE    ->PA9

MOSI->PB15

MISO->PB14

SCK  ->PB13

IRQ  ->PB8

模块接口原理图

在我们小车主控板中,NRF24L01接口如上,注意不要插反。

二、工程代码

在NRF24L01.H文件中宏定义引脚以及寄存器

//通信引脚#define IRQ_Pin  GPIO_PIN_8#define CE_Pin   GPIO_PIN_9#define CS_Pin   GPIO_PIN_10#define SCK_Pin  GPIO_PIN_13#define MISO_Pin GPIO_PIN_14#define MOSI_Pin GPIO_PIN_15//寄存器地址代码#define CONFIG      0x00  // 配置寄存器#define EN_AA       0x01  // 自动应答功能使能寄存器#define EN_RXADDR   0x02  // 接收地址使能寄存器#define SETUP_AW    0x03  // 设置地址宽度寄存器#define SETUP_RETR  0x04  // 设置重发寄存器#define RF_CH       0x05  // 射频通道寄存器#define RF_SETUP    0x06  // 射频设置寄存器#define STATUS      0x07  // 状态寄存器#define OBSERVE_TX  0x08  // 发送观察寄存器#define CD          0x09  // 载波检测寄存器#define RX_ADDR_P0  0x0A  // 接收地址数据通道0#define RX_ADDR_P1  0x0B  // 接收地址数据通道1#define RX_ADDR_P2  0x0C  // 接收地址数据通道2#define RX_ADDR_P3  0x0D  // 接收地址数据通道3#define RX_ADDR_P4  0x0E  // 接收地址数据通道4#define RX_ADDR_P5  0x0F  // 接收地址数据通道5#define TX_ADDR     0x10  // 发送地址寄存器#define RX_PW_P0    0x11  // 接收数据通道0有效数据宽度#define RX_PW_P1    0x12  // 接收数据通道1有效数据宽度#define RX_PW_P2    0x13  // 接收数据通道2有效数据宽度#define RX_PW_P3    0x14  // 接收数据通道3有效数据宽度#define RX_PW_P4    0x15  // 接收数据通道4有效数据宽度#define RX_PW_P5    0x16  // 接收数据通道5有效数据宽度#define FIFO_STATUS 0x17  // FIFO状态寄存器#define DYNPD       0x1C  // 动态有效数据长度寄存器#define FEATURE     0x1D  // 特性寄存器//操作指令代码#define R_REGISTER    0x00  // 读寄存器命令#define W_REGISTER    0x20  // 写寄存器命令#define R_RX_PAYLOAD  0x61  // 读取接收有效数据命令#define W_TX_PAYLOAD  0xA0  // 写入发送有效数据命令#define FLUSH_TX      0xE1  // 清空发送FIFO命令#define FLUSH_RX      0xE2  // 清空接收FIFO命令#define NOP           0xFF  // 无操作命令//状态#define RX_OK         0X40#define TX_OK         0X20#define MAX_OK        0X10

然后在NRF24L01.C文件中先配置SPI,随后配置NRF24L01寄存器

 

void NRF24L01_GPIO_Init(void){        RCC_APBPeriphClk_Enable1(RCC_APB1_PERIPH_SPI2,ENABLE);
        __RCC_GPIOA_CLK_ENABLE();        __RCC_GPIOB_CLK_ENABLE();
        PB13_AFx_SPI2SCK();//开启引脚复用功能        PB14_AFx_SPI2MISO();        PB15_AFx_SPI2MOSI();
        GPIO_InitTypeDef GPIO_InitStruct;         GPIO_InitStruct.IT=GPIO_IT_NONE;        GPIO_InitStruct.Mode=GPIO_MODE_OUTPUT_PP;        GPIO_InitStruct.Pins=MOSI_Pin | SCK_Pin;        GPIO_InitStruct.Speed=GPIO_SPEED_HIGH;        GPIO_Init(CW_GPIOB, &GPIO_InitStruct);
        GPIO_InitStruct.IT=GPIO_IT_NONE;        GPIO_InitStruct.Mode=GPIO_MODE_OUTPUT_PP;        GPIO_InitStruct.Pins=CS_Pin | CE_Pin;        GPIO_InitStruct.Speed=GPIO_SPEED_HIGH;        GPIO_Init(CW_GPIOA, &GPIO_InitStruct);
        GPIO_InitStruct.IT=GPIO_IT_NONE;        GPIO_InitStruct.Mode=GPIO_MODE_INPUT_PULLUP;        GPIO_InitStruct.Pins=MISO_Pin | IRQ_Pin;        GPIO_InitStruct.Speed=GPIO_SPEED_HIGH;        GPIO_Init(CW_GPIOB, &GPIO_InitStruct);
        W_CS(1);
        SPI_InitTypeDef  SPI_InitStructure; // SPI 初始化结构体        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;    // 双线全双工        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                         // 主机模式        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                     // 帧数据长度为8bit        SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                            // 时钟空闲电平为低        SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;                          // 第1个边沿采样        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                             // 片选信号由SSI寄存器控制        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;    // 波特率为PCLK的8分频        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                    // 最高有效位 MSB 收发在前        SPI_InitStructure.SPI_Speed = SPI_Speed_Low;                          // 低速SPI
        SPI_Init(CW_SPI2, &SPI_InitStructure);   // 初始化        SPI_Cmd(CW_SPI2, ENABLE);   // 使能SPI1}uint8_t SPI_SwapByte(uint8_t TxByte){        uint16_t l_Data = 0;        while(SPI_GetFlagStatus(CW_SPI2, SPI_FLAG_TXE) == RESET);  SPI_SendData(CW_SPI2, TxByte);  while(SPI_GetFlagStatus(CW_SPI2, SPI_FLAG_RXNE) == RESET);  l_Data = SPI_ReceiveData(CW_SPI2);//读取接收数据            return l_Data;                //返回}void W_Reg(uint8_t Reg,uint8_t value)//写字节{        W_CS(0);        SPI_SwapByte(Reg);        SPI_SwapByte(value);        W_CS(1);}uint8_t R_Reg(uint8_t Reg)//读字节{        uint8_t value;        W_CS(0);        SPI_SwapByte(Reg);        value=SPI_SwapByte(NOP);        W_CS(1);
        return value;}void W_Buf(uint8_t Reg, uint8_t* Buf, uint8_t Len)//连续写{        uint8_t i;        W_CS(0);        SPI_SwapByte(Reg);        for(i=0;i<Len;i++)        {                SPI_SwapByte(Buf[i]);        }        W_CS(1);}void R_Buf(uint8_t Reg, uint8_t* Buf, uint8_t Len)//连续读{        uint8_t i;        W_CS(0);        SPI_SwapByte(Reg);        for(i=0;i<Len;i++)        {                Buf[i]=SPI_SwapByte(NOP);        }        W_CS(1);}void NRF24L01_Init(void)//初始化{        NRF24L01_GPIO_Init();
        W_CE(0);        W_Buf(W_REGISTER+TX_ADDR,T_ADDR,5);        W_Buf(W_REGISTER+RX_ADDR_P0,R_ADDR,5);        W_Reg(W_REGISTER+CONFIG,0x0F);        W_Reg(W_REGISTER+EN_AA,0x01);        W_Reg(W_REGISTER+RF_CH,0x00);        W_Reg(W_REGISTER+RX_PW_P0,32);        W_Reg(W_REGISTER+EN_RXADDR,0X01);        W_Reg(W_REGISTER+SETUP_RETR,0X1A);        W_Reg(FLUSH_RX,NOP);        W_CE(1);
}void Receive(uint8_t *Buf)//数据接收{        uint8_t Status;        Status=R_Reg(R_REGISTER+STATUS);        if(Status & RX_OK)        {                R_Buf(R_RX_PAYLOAD,Buf,32);                W_Reg(FLUSH_RX,NOP);                W_Reg(W_REGISTER+STATUS,Status);                RX_Flag=1;                Delay_us(150);        }}uint8_t Send(uint8_t *Buf)//数据发送{        uint8_t Status;        W_Buf(W_TX_PAYLOAD,Buf,32);
        W_CE(0);        W_Reg(W_REGISTER+CONFIG,0x0E);        W_CE(1);
        while(R_IRQ==1);        Status=R_Reg(R_REGISTER+STATUS);        if(Status & MAX_OK)        {                W_Reg(FLUSH_TX,NOP);                W_Reg(W_REGISTER+STATUS,Status);                return MAX_OK;        }        if(Status & TX_OK)        {                W_Reg(W_REGISTER+STATUS,Status);                return TX_OK;        }}uint8_t Receive_Flag(void)//接收标志位{        if(RX_Flag==1)        {                RX_Flag=0;                return 1;        }        else{                return 0;        }}

三、实验现象

在发送端main函数中写入如下代码

int main(void){        uint8_t Buf[32]={0x00,0x67,0x68,0x69,0x70},num=0;        OLED_Init();//初始化        NRF24L01_Init();        OLED_ShowString(1,1,"Send ok");        while(1)        {                num++;                Buf[0]=num;                Send(Buf);                Delay_s(1);        }}

在接收端main函数中写入如下代码

int main(void){        uint8_t Buf[32]={0};        OLED_Init();//初始化        NRF24L01_Init();        OLED_ShowString(1,1,"Receive ok");        while(1)        {                Receive(Buf);                if(Receive_Flag()==1)                {                        OLED_ShowNum(3,1,Buf[0],3);                        OLED_ShowHexNum(2,4,Buf[1],2);                        OLED_ShowHexNum(2,7,Buf[2],2);                        OLED_ShowHexNum(2,10,Buf[3],2);                        OLED_ShowHexNum(2,13,Buf[4],2);                }        }}

然后现象如下

发送端发送四个十六进制数据以及一个递增的十进制数据,OLED屏幕显示 Send ok

接收端第一行显示Receive OK,第二行显示接收到的固定十六进制数据,第三行显示接收到的十进制数据


扫码加入QQ群,3群| 610403240

相关推荐

登录即可解锁
  • 海量技术文章
  • 设计资源下载
  • 产业链客户资源
  • 写文章/发需求
立即登录

以开放、共享、互助为理念,致力于构建武汉芯源半导体CW32系列MCU生态社区。无论是嵌入式MCU小自还是想要攻破技术难题的工程师,亦或是需求解决方案的产品经理都可在CW32生态社区汲取营养、共同成长。