找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4102|回复: 4
打印 上一主题 下一主题
收起左侧

STM32F030C8配置使用NRF24L01

[复制链接]
跳转到指定楼层
楼主
ID:276663 发表于 2018-3-19 16:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
STM32F030C8配置NRF24L01

前言:        
        工作使用到STM32F030,项目暂告一段落,空闲时间,调试一下基本的无线模块。其实还是碰到了一些阻碍。虽然STM32F103会用了NRF24L10,可是到了STM32F030还是有些配置上的区别,为了加快各位研发人员的开发进度,避免浪费大量的时间在硬件平台上,写出个人代码调试的经验。个人水平有限,如有错误,还请指正。

提示:
   使用内部RC时钟,最大速度48MHz。


第一步:初始化端口
/*******************************************************************************
  *@brief  初始化端口   因为CSN用的PB12  CE 用的PA11所以两个时钟都要开
  *@param  None
  *@retval None
****************************************************************Author:Liming**/
void NRF24L01_GPIO_Init(void)
{
   GPIO_InitTypeDef GPIO_InitStructure;
   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA|RCC_AHBPeriph_GPIOB,ENABLE);//使能端口A/B时钟

         GPIO_InitStructure.GPIO_Pin= SPI2_CE_PIN;
         GPIO_InitStructure.GPIO_Mode= GPIO_Mode_OUT;
   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_2;
         GPIO_Init(SPI2_CE_PORT,&GPIO_InitStructure);                                                     //CE控制脚

         GPIO_InitStructure.GPIO_Pin= SPI2_CSN_PIN;
         GPIO_Init(SPI2_CSN_PORT,&GPIO_InitStructure);                                                            //CSN控制脚        
   GPIO_ResetBits(SPI2_CE_PORT,SPI2_CE_PIN);
   GPIO_SetBits(SPI2_CSN_PORT,SPI2_CSN_PIN);

   GPIO_InitStructure.GPIO_Pin = SPI2_SCK_PIN;
         GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF;
   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
         GPIO_InitStructure.GPIO_Speed= GPIO_Speed_Level_2;      
         GPIO_Init(SPI2_SCK_GPIO_PORT,&GPIO_InitStructure);                                                 //SPI 引脚

    GPIO_InitStructure.GPIO_Pin = SPI2_MISO_PIN;
   GPIO_Init(SPI2_MISO_GPIO_PORT,&GPIO_InitStructure);

   GPIO_InitStructure.GPIO_Pin = SPI2_MOSI_PIN;
   GPIO_Init(SPI2_MOSI_GPIO_PORT,&GPIO_InitStructure);

    GPIO_PinAFConfig(SPI2_SCK_GPIO_PORT, SPI2_SCK_SOURCE,SPI2_SCK_AF);
    GPIO_PinAFConfig(SPI2_MISO_GPIO_PORT,SPI2_MISO_SOURCE, SPI2_MISO_AF);
    GPIO_PinAFConfig(SPI2_MOSI_GPIO_PORT,SPI2_MOSI_SOURCE, SPI2_MOSI_AF);
}

第二步:初始化SPI
/*******************************************************************************
  *@brief  初始化SPI  因为NRF24L01SPI最大支持10M,所以分频到6MHz
  *@param  None
  *@retval None
****************************************************************Author:Liming**/
void SPIx_Init(void)
{        
         SPI_InitTypeDefSPI_InitStruture;
         RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);//使能SPI2时钟

         SPI_InitStruture.SPI_Direction= SPI_Direction_2Lines_FullDuplex;//SPI 设置为双线双向全双工
         SPI_InitStruture.SPI_Mode= SPI_Mode_Master;//设置为主SPI
         SPI_InitStruture.SPI_DataSize  = SPI_DataSize_8b;//SPI 发送接收8 位帧结构
         SPI_InitStruture.SPI_CPOL       =SPI_CPOL_Low;//时钟悬空低
         SPI_InitStruture.SPI_CPHA      =SPI_CPHA_1Edge;//数据捕获于第一个时钟沿
         SPI_InitStruture.SPI_BaudRatePrescaler= SPI_BaudRatePrescaler_8;//波特率预分频值为8 48/8=6MHz        
         SPI_InitStruture.SPI_NSS= SPI_NSS_Soft;//内部 NSS 信号有SSI 位控制
         SPI_InitStruture.SPI_FirstBit= SPI_FirstBit_MSB;  //数据传输从 MSB 位开始
         SPI_InitStruture.SPI_CRCPolynomial= 7;                                    //CRC校验计算式
         SPI_Init(SPI2,&SPI_InitStruture);                                //应用到SPI1
    SPI_RxFIFOThresholdConfig(SPI2, SPI_RxFIFOThreshold_QF);// 很重要的一句代码
         SPI_Cmd(SPI2,ENABLE);  
}  


第三步:基础支持程序代码
/*******************************************************************************
  *@brief  SPIx 读写一个字节 这一步我使用F103的都不行
  *@param  TxData:要写入的字节
  *@retval tmp:读取到的字节
****************************************************************Author:Liming**/
uint8_t SPIx_ReadWriteByte(uint8_t TxData)
{
uint8_t tmp = 0x00;

  /*Wait until the transmit buffer is empty */
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) != SET)
  {
}  
  /*Send the byte */
SPI_SendData8(SPI2, TxData);

  /*Wait to receive a byte */
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) != SET)
  {
  }
  /*Return the byte read from the SPI bus */   
  tmp= SPI_ReceiveData8(SPI2);

  /*Wait until the BSY flag is set */   
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) != RESET)
  {
}  

  /*Return read Data */
return tmp;
}



/*******************************************************************************
  *@brief  写寄存器
  *@param  None
  *@retval     None
****************************************************************Author:Liming**/
u8 NRF24L01_Write_Reg(u8 reg,u8 value)
{
         u8status;         
     SPI_CSN_LOW;                 //使能SPI传输
       status =SPIx_ReadWriteByte(reg);//发送寄存器号
       SPIx_ReadWriteByte(value);      //写入寄存器的值
       SPI_CSN_HIGH;                 //禁止SPI传输      
       return(status);                            //返回状态值
}

/*******************************************************************************
  *@brief  读寄存器
  *@param  None
  *@retval     None
****************************************************************Author:Liming**/
u8 NRF24L01_Read_Reg(u8 reg)
{
         u8reg_val;           
        SPI_CSN_LOW;           //使能SPI传输         
       SPIx_ReadWriteByte(reg);   //发送寄存器号
       reg_val=SPIx_ReadWriteByte(0XFF);//读取寄存器内容
       SPI_CSN_HIGH;           //禁止SPI传输                     
       return(reg_val);           //返回状态值
}        

/*******************************************************************************
  *@brief  读多字节数据
  *@param  None
  *@retval     None
****************************************************************Author:Liming**/
unsigned char NRF24L01_Read_Buf(unsigned charreg,unsigned char *pBuf,unsigned char len)
{
         unsignedchar status,u8_ctr;         
       SPI_CSN_LOW;           //使能SPI传输
       status=SPIx_ReadWriteByte(reg);//发送寄存器值(位置),并读取状态值            
        for(u8_ctr=0;u8_ctr<len;u8_ctr++)pBuf[u8_ctr]=SPIx_ReadWriteByte(0XFF);//读出数据
       SPI_CSN_HIGH;       //关闭SPI传输
       return status;        //返回读到的状态值
}
/*******************************************************************************
  *@brief  写多字节数据
  *@param  None
  *@retval     None
****************************************************************Author:Liming**/
unsigned char NRF24L01_Write_Buf(unsignedchar reg, unsigned char *pBuf, unsigned char len)
{
         unsignedchar status,u8_ctr;      
        SPI_CSN_LOW;          //使能SPI传输
       status = SPIx_ReadWriteByte(reg);//发送寄存器值(位置),并读取状态值
       for(u8_ctr=0; u8_ctr<len;u8_ctr++)SPIx_ReadWriteByte(*pBuf++); //写入数据  
       SPI_CSN_HIGH;        //关闭SPI传输
       return status;          //返回读到的状态值
}        






/*******************************************************************************
  *@brief  发送一包数据
  *@param  None
  *@retval     None
****************************************************************Author:Liming**/
void NRF24L01_TxPacket(unsigned char*txbuf)
{
         unsignedchar sta;   
         SPI_CE_LOW;
   NRF24L01_Write_Reg(FLUSH_TX,0X00); // 清理发送寄存器   
       NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//写数据到TXBUF  32个字节
   NRF24L01_Write_Reg(SPI_WRITE_REG + CONFIG, 0x0E);  // 清理发送寄存器
   NRF_STATUS = NRF_STATUS_TX;
        SPI_CE_HIGH;    //启动发送         
}



/*******************************************************************************
  *@brief  接收一包数据
  *@param  None
  *@retval     None
****************************************************************Author:Liming**/
unsigned char NRF24L01_RxPacket(u8 *rxbuf)
{
         unsignedchar sta;                                                                                    

         sta=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值         
         NRF24L01_Write_Reg(SPI_WRITE_REG+STATUS,sta);//清除TX_DSMAX_RT中断标志
         if(sta&RX_OK)//接收到数据
         {
                   NRF24L01_Read_Buf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据
                   NRF24L01_Write_Reg(FLUSH_RX,0xff);//清除RX FIFO寄存器
                   return1;
         }         
         return0;//没收到任何数据
}


/*******************************************************************************
  *@brief  检测NRF24L01是否存在  进入调试模式查看是否值正确
  *@param  None
  *@retval     1失败      0成功
****************************************************************Author:Liming**/
uint8_t NRF24L01_Check(void)
{
         uint8_tbuf[5]={0XA5,0XA5,0XA5,0XA5,0XA5};
         uint8_tbuf1[5]={0,0,0,0,0};
         uint8_ti,Temp;
         NRF24L01_Write_Buf(SPI_WRITE_REG+TX_ADDR,buf,5);//写入5个字节的地址.
   NRF24L01_Read_Buf(TX_ADDR,buf1,5); //读出写入的地址  
         for(i=0;i<5;i++)                //调试断点打到这一行,查看buf1是否都是0XA5
    {
       if( buf1 != 0XA5 )break;                                                  
    }
         if(i! = 5 )return 1;//检测24L01错误
         return0;            //检测到24L01
}


/*******************************************************************************
  *@brief  切换NRF24L01到接收模式 需要设置发送地址,
*        有些人自己调程序,老是说会断,或者模式切换出问题,或许参考一下红色部分的思路。
  *@param  None
  *@retval     None
****************************************************************Author:Liming**/

void RX_Mode(void)
{
   unsigned char status;
         SPI_CE_LOW;     //CE拉低,进入配置模式
    status = NRF24L01_Read_Reg(STATUS);
   NRF24L01_Write_Reg(SPI_WRITE_REG+STATUS,status);//清除中断
   NRF24L01_Write_Reg(SPI_WRITE_REG+SETUP_AW,0x01);//3字节地址   
    NRF24L01_Write_Reg(FLUSH_RX,0x00);//清除RX FIFO寄存器

/* 设置通道0接收地址*/
       NRF24L01_Write_Buf(SPI_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDR_PIPE0,RX_ADR_WIDTH);
/* 设置通道1接收地址*/
   NRF24L01_Write_Buf(SPI_WRITE_REG+RX_ADDR_P1,(u8*)RX_ADDR_PIPE1,RX_ADR_WIDTH);
   NRF24L01_Write_Reg(SPI_WRITE_REG+RX_ADDR_P2, RX_ADDR_PIPE2);// 设置通道2接收地址
   NRF24L01_Write_Reg(SPI_WRITE_REG+RX_ADDR_P3, RX_ADDR_PIPE3);// 设置通道3接收地址
   NRF24L01_Write_Reg(SPI_WRITE_REG+RX_ADDR_P4, RX_ADDR_PIPE4);// 设置通道4接收地址
   NRF24L01_Write_Reg(SPI_WRITE_REG+RX_ADDR_P5, RX_ADDR_PIPE5);// 设置通道5接收地址

       NRF24L01_Write_Reg(SPI_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0的有效数据宽度
   NRF24L01_Write_Reg(SPI_WRITE_REG+RX_PW_P1,RX_PLOAD_WIDTH);//选择通道1的有效数据宽度
   NRF24L01_Write_Reg(SPI_WRITE_REG+RX_PW_P2,RX_PLOAD_WIDTH);//选择通道2的有效数据宽度
   NRF24L01_Write_Reg(SPI_WRITE_REG+RX_PW_P3,RX_PLOAD_WIDTH);//选择通道3的有效数据宽度
   NRF24L01_Write_Reg(SPI_WRITE_REG+RX_PW_P4,RX_PLOAD_WIDTH);//选择通道4的有效数据宽度
   NRF24L01_Write_Reg(SPI_WRITE_REG+RX_PW_P5,RX_PLOAD_WIDTH);//选择通道5的有效数据宽度

   NRF24L01_Write_Reg(SPI_WRITE_REG+EN_AA,0x3F);    //使能所有通道的自动应答      
       NRF24L01_Write_Reg(SPI_WRITE_REG+EN_RXADDR,0x3F);//使能所有通道的接收地址
NRF24L01_Write_Reg(SPI_WRITE_REG+RF_CH,0X00);           //设置RF通信频率
/*设置TX发射参数,0db增益,2Mbps,低噪声增益开启   */
       NRF24L01_Write_Reg(SPI_WRITE_REG+RF_SETUP,0x0F);
/*配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式*/
       NRF24L01_Write_Reg(SPI_WRITE_REG+CONFIG,0x3F);
   NRF_STATUS = NRF_STATUS_RX;
       SPI_CE_HIGH;    //CE拉高,进入接收模式
}



/*******************************************************************************
  *@brief  切换NRF24L01到发送模式 需要设置发送地址,
*         如果使能了自动应答还需要写通道0的接收地址和发送地址相同。
*                     有些人自己调程序,老是说会断,或者模式切换出问题,或许参考一下红色部分的思路。
  *@param  None
  *@retval     None
****************************************************************Author:Liming**/
void TX_Mode(void)
{        
   unsigned char status;   
         SPI_CE_LOW;
    status = NRF24L01_Read_Reg(STATUS);
   NRF24L01_Write_Reg(SPI_WRITE_REG+STATUS,status);//清除RX FIFO寄存器
   NRF24L01_Write_Reg(SPI_WRITE_REG+SETUP_AW,0x01);//3字节地址   
    NRF24L01_Write_Reg(FLUSH_TX,0x00);//清除TX FIFO寄存器

         /*TX节点地址*/
       NRF24L01_Write_Buf(SPI_WRITE_REG+TX_ADDR,(u8*)TX_ADDR_PIPE0,TX_ADR_WIDTH);
       /*设置TX节点地址,主要为了使能ACK*/
NRF24L01_Write_Buf(SPI_WRITE_REG+RX_ADDR_P0,(u8*)TX_ADDR_PIPE0,TX_ADR_WIDTH);
       NRF24L01_Write_Reg(SPI_WRITE_REG+EN_AA,0x01);     //使能通道0的自动应答   
       NRF24L01_Write_Reg(SPI_WRITE_REG+EN_RXADDR,0x01);//使能通道0的接收地址  
/*设置自动重发间隔时间:500us+ 86us;最大自动重发次数:5次*/
       NRF24L01_Write_Reg(SPI_WRITE_REG+SETUP_RETR,0x15);
       NRF24L01_Write_Reg(SPI_WRITE_REG+RF_CH,0X00);     //设置RF通道为40
/*设置TX发射参数,0db增益,2Mbps,低噪声增益开启  */
       NRF24L01_Write_Reg(SPI_WRITE_REG+RF_SETUP,0x0F);  
/*配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断*/
       NRF24L01_Write_Reg(SPI_WRITE_REG+CONFIG,0x0E);   
   NRF_STATUS = NRF_STATUS_TX;
         SPI_CE_HIGH;//CE为高,10us后启动发送
}        


到这里基本已经可以读写寄存器了,也就是NRF24L01已经调通了基本的发送和接受。遇到的问题或许还有中断引脚的配置,毕竟STM32F0还是和STM32F1不一样。另外一篇详细讲外部中断的配置。

全部资料51hei下载地址:
STM32F030C8配置NRF24L01.pdf (508.95 KB, 下载次数: 51)


评分

参与人数 1黑币 +100 收起 理由
admin + 100 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏4 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:798565 发表于 2020-7-7 17:34 | 只看该作者
请问有头文件的定义吗?
回复

使用道具 举报

板凳
ID:798565 发表于 2020-7-7 17:39 | 只看该作者
请问有头文件的定义函数吗
回复

使用道具 举报

地板
ID:798565 发表于 2020-7-8 09:37 | 只看该作者
您好,请问您有STM32F030C8配置NRLF24L01的头文件相关定义嘛
回复

使用道具 举报

5#
ID:276663 发表于 2020-7-8 13:15 | 只看该作者
728996695 发表于 2020-7-8 09:37
您好,请问您有STM32F030C8配置NRLF24L01的头文件相关定义嘛

抱歉,时间久远不能找到当时的头文件,你可能要稍微花点时间自己把头文件补上。
nRF的那些定义都是一样的,至于单片机的管脚,SPI2你可以看看是哪几个管脚。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表