nrf24L01 check不通过问题分析
下面这段代码是有问题的,使nrf24L01 check不通过。
#include "stm32f10x.h" // Device header #include "spi.h" #include "OLED.h" /****** SPI2引脚连接 ******/ #define PA4_SPI1_NSS GPIO_Pin_4 #define PA5_SPI1_SCK GPIO_Pin_5 #define PA6_SPI1_MISO GPIO_Pin_6 #define PA7_SPI1_MOSI GPIO_Pin_7 // SPI1初始化 //--------------------------------------------------------------------------------------------------------------- void SPI1_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // GPIOA时钟使能 RCC_APB1PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); // SPI1时钟使能 GPIO_InitStructure.GPIO_Pin = PA6_SPI1_MISO; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化GPIOB GPIO_InitStructure.GPIO_Pin = PA5_SPI1_SCK | PA7_SPI1_MOSI; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // PA7/6/5复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化GPIOA GPIO_SetBits(GPIOA, PA5_SPI1_SCK | PA6_SPI1_MISO | PA7_SPI1_MOSI); // PA5/6/7上拉 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // SPI设置为双线双向全双工 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; // SPI主机 SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 发送接收8位帧结构 SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; // 时钟悬空低 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; // 数据捕获于第1个时钟沿 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; // NSS信号由软件控制 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; // 定义波特率预分频的值:波特率预分频值为16 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // 数据传输从MSB位开始 SPI_InitStructure.SPI_CRCPolynomial = 7; // CRC值计算的多项式 SPI_Init(SPI1, &SPI_InitStructure); SPI_Cmd(SPI1, ENABLE); // 使能SPI外设 SPI1_ReadWriteByte(0xFF); // 启动传输 } //--------------------------------------------------------------------------------------------------------------- // 设置SPI速度 //--------------------------------------------------- // SPI_DivideFrequency_2 2分频: 18MHz // SPI_DivideFrequency_4 4分频: 9MHz // SPI_DivideFrequency_8 8分频: 4.5MHz // SPI_DivideFrequency_16 16分频:2.25MHz void SPI1_SetSpeed(uint8_t SPI_DivideFrequency) { SPI1->CR1 &= 0XFFC7; SPI1->CR1 |= SPI_DivideFrequency; // 设置SPI1速度 // SPI_Cmd(SPI1,ENABLE); } //--------------------------------------------------- // SPI读写一个字节 // TxData:要写入的字节 // 返回值:读取到的字节 //----------------------------------------------------------------------- uint8_t SPI1_ReadWriteByte(uint8_t TxData) { uint8_t TxWait = 0; uint8_t RxWait = 0; count++; OLED_ShowString(4, 1, "TxWt:"); // 等待发送缓存为空 while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) { TxWait++; OLED_ShowNum(4, 6, TxWait, 3); if (TxWait > 250) // 等待时间过长则放弃本次读写 return 0; } OLED_ShowString(4, 9, "RxWt:"); SPI_I2S_SendData(SPI1, TxData); // SPI1写一个字节 // 等待接收缓存为空 while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET) { RxWait++; OLED_ShowNum(4, 14, RxWait, 3); if (RxWait > 250) // 等待时间过长则放弃本次读写 return 0; } return SPI_I2S_ReceiveData(SPI1); // 将读到的字节返回 }
原因就出在这行代码上:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // GPIOA时钟使能
nrf24l01用到了中断有IRQ引脚处理必须用到AFIO,换成这样就好了。在STM32中,AFIO主要完成两个任务:复用功能引脚重映射、中断引脚选择。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
下面是网络文章摘录
端口重映射初始化过程的步骤
接下来看一下端口重映射初始化过程的步骤,拿串口1为例,除了之前使能复用功能的2个时钟之外,还需要使能AFIO功能时钟,然后调用重映射函数:
- GPIO端口时钟使能。要使用到端口复用,首先是要使能端口的时钟了;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
- 复用的外设时钟使能。比如要将PB6、PB7引脚复用成串口,必须也要使能串口时钟;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
- 使能AFIO时钟。重映射必须使能AFIO时钟;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
STM32F103:什么时候需要复用IO(AFIO)?
https://news.eeworld.com.cn/mcu/article_2018061539739.html
刚接触STM32F103,在尝试编写“按键中断”和“PWM呼吸灯”程序的时候,发现例程都用到了管脚复用AFIO:
//打开管脚复用AFIORCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
写到“232USART串口通信”程序时,当我非常自信的写下上面这句代码后,发现例程里面却没有这句话,很让人摸不着头脑……查了很多资料,加上自己的理解,发现AFIO的使用还是有点内容值得总结一下的。
AFIO介绍:
MCU有对外管脚,包括CPU的管脚和内置外设(PWM,TIM,ADC……)的管脚;
他们都需要对外接口IO,但是管脚总数是有限的,有的管脚既作为普通IO,也作为外设IO,有时候甚至好几个内置外设共用一个IO,这就是管脚复用现象。
比如随便一个管脚的原理图上:
PA2/USART2_TX/ADC123_IN2/TIM5_CH3/TIM2_CH3
表明这个管脚除了作为普通PA2之外,还作为复用IO,有USART2,ADC,TIM5,TIM2等……
总结:
- 普通管脚就是GPIO,复用管脚(非普通管脚)就是AFIO;
- 只要用到内置外设的管脚,都需要打开复用IO(AFIO),比如对外输出PWM波形,使用AD转换等。
STM32之AFIO
https://blog.sina.com.cn/s/blog_5d9349d10100u9ni.html
1、不是说使用了IO的复用功能就一定要启动RCC_APB2Periph_AFIO的Clock的,参考下图
http://hi.csdn.net/attachment/201107/5/0_1309846137454X.gif
2、只有使用了AFIO的事件控制寄存器、AFIO的重映射功能以及外部中断(EXTI)控制寄存器才需要开启AFIO的时钟,STM32参考手册从来没说过使用IO的复用功能就一定要开启AFIO时钟,这是个误区。
作者:yangsail
出处:https://www.cnblogs.com/yangsail/p/18229810
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通