使用STM32F030F4P6的SPI协议和NRF24L01模块进行通讯 实现无线数据的收发

单片机这块纯属个人业余爱好, 有很多不足的地方还请大家多多指教, 代码中有些命名不规范的地方还请大家多多包涵.

本文只实现无线模块的简单的点亮(能收发一个字节数据), 一直想diy一个无线遥控的小车, 就要使用到无线模块, 找了好久发现NRF24L01(下面简称NRF)是最便宜的一款无线模块(除过WiFi和蓝牙模块), 就买了几个, 由于stm32f103涨价, 就选择了便宜的stm32f030, 网上找了很多资料对于stm32f030的资料很少, 他和stm32f103代码大同小异, 就试着在stm32f103代码的基础上修改一下, 就是不能通讯, 只能发送成功, 不能接收到数据, 搁置了好久最后从新选择了一块 HC-12 的无线通讯模块, 这个模块比较贵首次购买一套(收发两个模块)比较便宜, 空旷视野最远通讯距离1公里(没有实测量过), 他使用的是串口通讯, 写好代码烧录进去后可以通讯, 最后成功diy了无线遥控小车, 利用HC-12感觉大材小用了, 最后闲来无事就又琢磨一下这个NRF模块, 终于可以相互通讯了, 也不知道哪里出问题了, 唯一不同的是, 之前的是在网上找的资料上修修改改, 没有使用中断, 只使用了while循环进行检测, 这次重头开始编写的时候使用了中断, 在调试了一下就可以通讯.

遇到的一些问题:

1.原理图上PA4 是SPI1的片选spi1_nss的复用, 配置的时候把PA4也配置成了复用模式, 发现不能成功, 需要配置成输出模式解决了问题

2.NRF的IRQ脚配置中断的时候需要配置为下降沿触发

3.stm32板子和NRF模块进行连接的时候数据输出和输入线不能交叉连接(MCU 的MISO 和 NRF的 MISO 相连, MOSI同理)

以下是代码 , 适用于stm32f030

1. spi配置

使用STM32F030F4P6的SPI协议和NRF24L01模块进行通讯 实现无线数据的收发
#ifndef __bsp_spi_h
#define __bsp_spi_h

#include "stm32f0xx_gpio.h"

#define SPIx SPI1                            //SPI_1
#define SPI1_PORT GPIOA                //PA 端口
#define PORTA_LCK RCC_AHBPeriph_GPIOA    //GPIO 时钟
#define SPI_LCK RCC_APB2Periph_SPI1//spi 时钟
#define SPI1_CSN GPIO_Pin_1        //PA1    NSS
#define SPI1_SCK GPIO_Pin_5        //PA5    SCK
#define SPI1_MISO GPIO_Pin_6    //PA6    MISO
#define SPI1_MOSI GPIO_Pin_7    //PA7    MOSI

void SPI_Config(void);
u8 SPI_SendByte(u8 byte);
void Pin_CSN(u8 u);

#endif
bsp_spi.h 使用STM32F030F4P6的SPI协议和NRF24L01模块进行通讯 实现无线数据的收发
#include "bsp_spi.h"
#include "stm32f0xx_gpio.h"

//初始化
void SPI_Config()
{
    GPIO_InitTypeDef GPIO_InitStruct;
    SPI_InitTypeDef SPI_InitStruct;
    
    //端口初始化
    RCC_AHBPeriphClockCmd(PORTA_LCK , ENABLE);//开启GPIO时钟
    RCC_APB2PeriphClockCmd(SPI_LCK, ENABLE);//开启SPI_1时钟
    
    //复用模式
    GPIO_PinAFConfig(SPI1_PORT,GPIO_PinSource5,GPIO_AF_0);//SCK
    GPIO_PinAFConfig(SPI1_PORT,GPIO_PinSource6,GPIO_AF_0);//MISO
    GPIO_PinAFConfig(SPI1_PORT,GPIO_PinSource7,GPIO_AF_0);//MOSI
    
    GPIO_InitStruct.GPIO_Pin =  SPI1_SCK | SPI1_MISO | SPI1_MOSI;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_Init(SPI1_PORT, &GPIO_InitStruct);
    
    GPIO_InitStruct.GPIO_Pin = SPI1_CSN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_Init(SPI1_PORT , &GPIO_InitStruct);
    
    //spi初始化
    //SPI_I2S_DeInit(SPIx);    //将寄存器重设为缺省值
    //SPI_Cmd(SPIx, DISABLE);
    //SPI_Direction_2Lines_FullDuplex SPI_Direction_1Line_Rx SPI_Direction_1Line_Tx
    SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    //SPI_Mode_Master 主机 SPI_Mode_Slave 从机
    SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
    SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;//SPI_CPOL_Low SPI_CPOL_High
    SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;//SPI_CPHA_1Edge SPI_CPHA_2Edge
    SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
    //SPI_FirstBit_MSB SPI_FirstBit_LSB
    SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStruct.SPI_CRCPolynomial = 7;
    SPI_Init(SPIx, &SPI_InitStruct);
    //SPI_I2S_IT_TXE SPI_I2S_IT_RXNE SPI_I2S_IT_ERR
    SPI_I2S_ITConfig(SPIx, SPI_I2S_IT_TXE | SPI_I2S_IT_RXNE, ENABLE);//中断
    SPI_RxFIFOThresholdConfig(SPI1, SPI_RxFIFOThreshold_QF);    //重要,把应答数据位设置为 8 位
    SPI_Cmd(SPIx, ENABLE);//使能
}

//SPI 收发一个字节
u8 SPI_SendByte(u8 byte)
{
    //设置时间溢出
    u32 SPITimeout = 0xffff;
    /* 等待发送缓冲区为空,TXE 事件 */
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET)
    {
        if ((SPITimeout--) == 0) return 0;
    }
    /* 写入数据寄存器,把要写入的数据写入发送缓冲区 */
    SPI_SendData8(SPIx, byte);//SPI_I2S_SendData16
    //设置时间溢出
    SPITimeout = 0xfffff;
    /* 等待接收缓冲区非空,RXNE 事件 */
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET)
    {
        if ((SPITimeout--) == 0) return 0;
    }
    /* 读取数据寄存器,获取接收缓冲区数据 */
    return SPI_ReceiveData8(SPIx);
}
//设置片选高低电平
void Pin_CSN(u8 u)
{
    if(u==0)
    {
        SPI1_PORT->BRR = SPI1_CSN;
    }
    else
    {
        SPI1_PORT->BSRR = SPI1_CSN;
    }
}
bsp_spi.c

2.nrf配置

使用STM32F030F4P6的SPI协议和NRF24L01模块进行通讯 实现无线数据的收发
#ifndef __bsp_nrf0241_h
#define __bsp_nrf0241_h

#include "stm32f0xx_gpio.h"

#define NRF_PORT GPIOA                //PA 端口
#define KEY0 GPIO_Pin_0        //KEY0
#define LED0 GPIO_Pin_4        //LED0
#define NRF_CE GPIO_Pin_2        //PA2    CE
#define NRF_IRQ GPIO_Pin_3        //PA3    IRQ
#define NOP 0xFF // 空操作。可以用来读 状态寄存器

//设置ce置高和拉低
void Pin_CE(u8 u);
//获取IRQ中断的电平,(没有用到)
u8 Get_IRQ(void);
//写入数据
u8 SPI_WriteBuf(u8 reg, u8 *pBuf, u8 len);
//读取数据
u8 SPI_ReadBuf(u8 reg, u8 *pBuf, u8 len);
//读写一条指令
u8 SPI_RWReg(u8 reg, u8 value);
//配置
void NRF_Config(void);
//获取按键的电平(用于判断按键是否按下)
u8 Get_KEY0(void);
//配置测试按键和LED灯
void KEY0_LED0_Config(void);
//设置LED灯(低电平点亮)
void Pin_LED0(u8 u);
//发送数据buff为数据,len为个数
void send_data(u8 *buff,u8 len);
//检测NRF模块是否存在 存在返回0
u8 nrf24l0_check(void);
//读取状态寄存器, 用于判断发送成功, 接收成功, 发送达到最大值
u8 Get_Status(void);
//接收数据
void receive_data(void);
//获取接收到的数据 buf 存放接收的数据, len数据个数
void Get_Data(u8 *buf,u8 len);
//清除所有(发送, 接收, 最大发送次数)的中断
void ClearStatus(void);

#endif
bsp_nrf0241.h 使用STM32F030F4P6的SPI协议和NRF24L01模块进行通讯 实现无线数据的收发
#include "bsp_nrf0241.h"
#include "stm32f0xx_gpio.h"
#include "bsp_spi.h"
#include "delay.h"

void KEY0_LED0_Config()
{
    GPIO_InitTypeDef GPIO_InitStruct;
    NVIC_InitTypeDef NVIC_InitStructure;
    EXTI_InitTypeDef EXTI_InitStructure;
    
    RCC_AHBPeriphClockCmd(PORTA_LCK , ENABLE);
    //用户测试的按键和LED灯
    GPIO_InitStruct.GPIO_Pin =  KEY0;//按键
    GPIO_InitStruct.GPIO_PuPd  = GPIO_PuPd_UP;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_Init(NRF_PORT, &GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Pin = LED0;//LED灯
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_Init(NRF_PORT , &GPIO_InitStruct);
    Pin_LED0(1);//低电平 熄灭LED灯
    //添加按键中断
    EXTI_InitStructure.EXTI_Line = KEY0;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    //EXTI_Trigger_Rising , EXTI_Trigger_Falling , EXTI_Trigger_Rising_Falling
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿触发
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);
    //中断
    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority = 1;        //子优先级1
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;        //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器
}
u8 Get_KEY0(void)
{
    return GPIO_ReadInputDataBit(NRF_PORT, KEY0);
}
void Pin_LED0(u8 u)
{
    if(u==0)
    {
        NRF_PORT->BRR = LED0;
    }
    else
    {
        NRF_PORT->BSRR = LED0;
    }
}
//地址
u8 TX_ADDRESS1[5]= {0x34,0x43,0x10,0x10,0x01}; //本地地址
u8 RX_ADDRESS1[5]= {0x34,0x43,0x10,0x10,0x01}; //接收地址
//配置
void NRF_Config()
{
    GPIO_InitTypeDef GPIO_InitStruct;
    NVIC_InitTypeDef NVIC_InitStructure;
    EXTI_InitTypeDef EXTI_InitStructure;
    
    //端口初始化
    RCC_AHBPeriphClockCmd(PORTA_LCK , ENABLE);
    
    GPIO_InitStruct.GPIO_Pin =  NRF_CE;//CE 输出
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_Init(NRF_PORT, &GPIO_InitStruct);
    
    GPIO_InitStruct.GPIO_Pin =  NRF_IRQ;//IRQ 中断输入
    GPIO_InitStruct.GPIO_PuPd  = GPIO_PuPd_NOPULL;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_Init(NRF_PORT, &GPIO_InitStruct);
    
    //中断
    EXTI_InitStructure.EXTI_Line = NRF_IRQ;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    //EXTI_Trigger_Rising , EXTI_Trigger_Falling , EXTI_Trigger_Rising_Falling
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);
    //中断
    NVIC_InitStructure.NVIC_IRQChannel = EXTI2_3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority = 1;        //子优先级1
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;        //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器
    
    //配置RNF
    Pin_CSN(1);
    Pin_CE(0);
    //0x02 发射, 0x03 接收- crc不使能 crc模式:8位效验
    //0x0e 发射, 0x0f 接收- crc使能 crc模式:16位效验
    SPI_RWReg(0x20+0x00,0x02);//0x02 发射, 0x03 接收
    SPI_RWReg(0x20+0x01,0x00);//自动应答 若通道0应答:0x01 禁止自动应答:0x00
    SPI_RWReg(0x20+0x02,0x01);//接收地址允许 通道0允许
    SPI_RWReg(0x20+0x03,0x03);//设置地址宽度 5个地址宽度
    SPI_RWReg(0x20+0x04,0x00);//建立自动重发 禁止自动重发
    SPI_RWReg(0x20+0x05,40);//射频通道
    SPI_RWReg(0x20+0x06,0x07);//射频寄存器
    SPI_RWReg(0x20+0x07,0x70);//状态寄存器
    SPI_WriteBuf(0x20+0x0A,RX_ADDRESS1,5);//通道0接收地址
    SPI_WriteBuf(0x20+0x10,TX_ADDRESS1,5);//发送地址
    SPI_RWReg(0x20+0x11,32);//接收数据通道0有效数据宽度 1-32 字节
}
//发送
void TX_MODE()
{
    //配置RNF
    Pin_CSN(1);
    Pin_CE(0);
    //0x02 发射, 0x03 接收- crc不使能 crc模式:8位效验
    //0x0e 发射, 0x0f 接收- crc使能 crc模式:16位效验
    SPI_RWReg(0x20+0x00,0x02);
    SPI_RWReg(0x20+0x01,0x00);//自动应答 若通道0应答:0x01 禁止自动应答:0x00
    SPI_RWReg(0x20+0x02,0x01);//接收地址允许 通道0允许
    SPI_RWReg(0x20+0x03,0x03);//设置地址宽度 5个地址宽度
    SPI_RWReg(0x20+0x04,0x00);//建立自动重发 禁止自动重发
    SPI_RWReg(0x20+0x05,40);//射频通道
    SPI_RWReg(0x20+0x06,0x07);//射频寄存器
    SPI_RWReg(0x20+0x07,0x70);//状态寄存器
    SPI_WriteBuf(0x20+0x0A,RX_ADDRESS1,5);//通道0接收地址
    SPI_WriteBuf(0x20+0x10,TX_ADDRESS1,5);//发送地址
    SPI_RWReg(0x20+0x11,32);//接收数据通道0有效数据宽度 1-32 字节
}
//接收
void RX_MODE()
{
    //配置RNF
    Pin_CSN(1);
    Pin_CE(0);
    //0x02 发射, 0x03 接收- crc不使能 crc模式:8位效验
    //0x0e 发射, 0x0f 接收- crc使能 crc模式:16位效验
    SPI_RWReg(0x20+0x00,0x03);//0x02 发射, 0x03 接收
    SPI_RWReg(0x20+0x01,0x00);//自动应答, 若通道0应答:0x01 禁止自动应答:0x00
    SPI_RWReg(0x20+0x02,0x01);//接收地址允许 通道0允许
    SPI_RWReg(0x20+0x03,0x03);//设置地址宽度 5个地址宽度
    SPI_RWReg(0x20+0x04,0x00);//建立自动重发 禁止自动重发
    SPI_RWReg(0x20+0x05,40);//射频通道
    SPI_RWReg(0x20+0x06,0x07);//射频寄存器
    SPI_RWReg(0x20+0x07,0x70);//状态寄存器
    SPI_WriteBuf(0x20+0x0A,RX_ADDRESS1,5);//通道0接收地址
    SPI_WriteBuf(0x20+0x10,TX_ADDRESS1,5);//发送地址
    SPI_RWReg(0x20+0x11,32);//接收数据通道0有效数据宽度 1-32 字节
    Pin_CE(1);
    delay_us(120);
}

//发送数据
void send_data(u8 *buff,u8 len)
{
    TX_MODE();
    SPI_RWReg(0xE1,0xFF);//清除发送寄存器
    SPI_WriteBuf(0xA0,buff,len);//写入发送寄存器
    Pin_CE(1);
    delay_us(20);
    Pin_CE(0);
}
//接收数据
void receive_data()
{
    RX_MODE();
    SPI_RWReg(0xE2,0xFF);//清除接收寄存器
    Pin_CE(1);
    delay_us(120);
}
//获取数据
void Get_Data(u8 *buf,u8 len)
{
    SPI_ReadBuf(0x61,buf,len);
}
//清除中断
void ClearStatus()
{
    Pin_CE(0);
    SPI_RWReg(0x20+0x07,0x70);
    Pin_CE(1);
    delay_us(20);
}
void Pin_CE(u8 u)
{
    if(u==0)
    {
        NRF_PORT->BRR = NRF_CE;
    }
    else
    {
        NRF_PORT->BSRR = NRF_CE;
    }
}
u8 Get_IRQ(void)
{
    return GPIO_ReadInputDataBit(NRF_PORT, NRF_IRQ);
}

//用于写数据:为寄存器地址,pBuf:为待写入数据地址,uchars:写入数据的个数
u8 SPI_WriteBuf(u8 reg, u8 *pBuf, u8 len) 
{
    u8 s,ctr;
    Pin_CSN(0);
    delay_us(100);
    s=SPI_SendByte(reg);
    
    for(ctr=0; ctr<len; ctr++)
        SPI_SendByte(*pBuf++);
    Pin_CSN(1);
    delay_us(100);
    return s;
}
//功能: 用于读数据,reg:为寄存器地址,pBuf:为待读出数据地址,uchars:读出数据的个数
u8 SPI_ReadBuf(u8 reg, u8 *pBuf, u8 len) 
{
    u8 s,ctr;
    Pin_CSN(0);
    delay_us(100);
    s=SPI_SendByte(reg);
    
    for(ctr=0; ctr<len; ctr++)
        pBuf[ctr]=SPI_SendByte(NOP);
    Pin_CSN(1);
    delay_us(100);
    return s;
}
//功能:NRF24L01 读写寄存器函数
u8 SPI_RWReg(u8 reg, u8 value) 
{
    u8 status = 0x00;
    Pin_CSN(0);
    delay_us(100);
    status = SPI_SendByte(reg); //发送寄存器地址,
    SPI_SendByte(value);//发送寄存器值
    delay_us(100);
    Pin_CSN(1);
    return (status);
}
//功能:NRF24L01 读写寄存器函数
u8 Get_Status() 
{
    return SPI_RWReg(0x07,0xFF);
}
//检测是否存在
u8 nrf24l0_check(void)
{
    u8 buf[5]={0XA5,0XA5,0XA5,0XA5,0XA5};
    u8 i;
    SPI_WriteBuf(0x20+0x10,buf,5);
    SPI_ReadBuf(0x10,buf,5);
    for(i=0; i<5; i++)if(buf[i]!=0xA5)break;
    if(i!=5)return 1;
    return 0;
}
bsp_nrf0241.c

3.stm32f0xx_it.c 中断内的函数

使用STM32F030F4P6的SPI协议和NRF24L01模块进行通讯 实现无线数据的收发
#include "delay.h"
#include "stm32f0xx.h"
#include "bsp_nrf0241.h"
//按键中断
void EXTI0_1_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line0)!= RESET)
    {
        delay_ms(20);
        if(Get_KEY0()!= RESET)//消除按键抖动
        {
            u8 tx_buf[32]={0x11};//用户测试的数据
            send_data(tx_buf,32);//发送
        }
        EXTI_ClearITPendingBit(EXTI_Line0);//清除中断标志
    }
}
//nrf2401收发中断
void EXTI2_3_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line3)!= RESET)
    {
        u8 gstatus = Get_Status();//获取状态
        //发送
        if((gstatus & 0x20) != 0)
        {
            //发送成功 LED灯闪烁一次
            Pin_LED0(0);
            delay_ms(1000);
            Pin_LED0(1);
        }
        //发送达到最大次数
        if((gstatus & 0x10) != 0)
        {
            //发送最大次数
            Pin_LED0(0);
            delay_ms(1000);
            Pin_LED0(1);
        }
        //接收
        if((gstatus & 0x40) != 0)
        {
            //接收到数据
            u8 tx_bufr[32];
            Get_Data(tx_bufr,32);
            if(tx_bufr[0] == 0x11)//和发送数据进行对比
            {
                Pin_LED0(0);
                delay_ms(1000);
                Pin_LED0(1);
            }
        }
        //清除中断标志
        EXTI_ClearITPendingBit(EXTI_Line3);
    }
    ClearStatus();//清除中断
    receive_data();//继续接收
}
stm32f0xx_it.c

4.delay.h 延时函数(摘自网络)

使用STM32F030F4P6的SPI协议和NRF24L01模块进行通讯 实现无线数据的收发
#include "stm32f0xx.h"
#include "delay.h"

static u8  fac_us=0;//us延时倍乘数
static u16 fac_ms=0;//ms延时倍乘数
//初始化延迟函数
//SYSTICK的时钟固定为HCLK时钟的1/8
//SYSCLK:系统时钟
void delay_init(u8 SYSCLK)
{
    SysTick->CTRL&=0xfffffffb;//bit2清空,选择外部时钟  HCLK/8
    fac_us=SYSCLK/8;            
    fac_ms=(u16)fac_us*1000;
}                                    
//延时nms
//注意nms的范围
//SysTick->LOAD为24位寄存器,所以,最大延时为:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK单位为Hz,nms单位为ms
//对72M条件下,nms<=1864 
void delay_ms(u16 nms)
{                     
    u32 temp;           
    SysTick->LOAD=(u32)nms*fac_ms;//时间加载(SysTick->LOAD为24bit)
    SysTick->VAL =0x00;           //清空计数器
    SysTick->CTRL=0x01 ;          //开始倒数  
    do
    {
        temp=SysTick->CTRL;
    }
    while(temp&0x01&&!(temp&(1<<16)));//等待时间到达   
    SysTick->CTRL=0x00;       //关闭计数器
    SysTick->VAL =0X00;       //清空计数器              
}   
//延时nus
//nus为要延时的us数.                                               
void delay_us(u32 nus)
{        
    u32 temp;             
    SysTick->LOAD=nus*fac_us;     
    SysTick->VAL=0x00;
    SysTick->CTRL=0x01 ;
    do
    {
        temp=SysTick->CTRL;
    }
    while(temp&0x01&&!(temp&(1<<16)));
    SysTick->CTRL=0x00;
    SysTick->VAL =0X00; 
}
delay.h

5.main.c 入口测试函数

使用STM32F030F4P6的SPI协议和NRF24L01模块进行通讯 实现无线数据的收发
#include "stm32f0xx.h"
#include "delay.h"
#include "bsp_spi.h"
#include "bsp_nrf0241.h"

void daly(uint32_t a)
{
    for(;a>0;a--);
}

int main(void)
{
    //初始化延时函数 stm32f030为48
    delay_init(48);
    /*
    *KEY0_LED0_Config();配置一个按键和一个LED灯
    * PA0 按键
    * PA4 LED灯(系统自带的用户LED灯 低电平点亮)
    *
    *SPI_Config();配置SPI
    * PA1 NSS 片选
    * PA5 SCK 时钟
    * PA6 MISO 主机输入从机输出
    * PA7 MOSI 主机输出从机输入
    *
    *NRF_Config();配置NRF24L01
    * PA2 CE 控制收发
    * PA3 IRQ 收发中断
    */
    KEY0_LED0_Config();
    SPI_Config();
    NRF_Config();
    delay_us(20);
    if(nrf24l0_check()==0)
    {
        //存在nrf2401模块
        Pin_LED0(0);
        delay_ms(1000);
        Pin_LED0(1);
        
        receive_data();//接收
    }
    while(1){ }
}
main.c

 

准备两块用于收发的stm32f030单片机和NRF无线模块 用杜邦线连接起来(注意 MISO 和 MOSI 要对应连接, 不要交叉连接), 有必要还要引出用于测试的key0按钮, LED是板子默认的PA4, 连接好后分别给两块板子插上烧录器烧录编译好的代码, 就可以按KEY0进行测试了, 如果另外一个单片机的LED灯亮说明成功了.

如果有不足的地方和经验欢迎在评论区交流.

上一篇:杭电OJ第11页2070~2074算法题(C语言)


下一篇:【STM32H7的DSP教程】第38章 STM32H7的FIR高通滤波器实现(支持逐个数据的实时滤波)