目录
一、原理
1.nRF24L01模块简介
nRF24L01是由NORDIC生产的工作在2.4GHz~2.5GHz的ISM 频段的单片无线收发器芯片。无线收发器包括:频率发生器、增强型“SchockBurst”模式控制器、功率放大器、晶体振荡器、调制器和解调器。
输出功率频道选择和协议的设置可以通过SPI 接口进行设置。几乎可以连接到各种单片机芯片,并完成无线数据传送工作。
极低的电流消耗:当工作在发射模式下发射功率为0dBm 时电流消耗为11.3mA ,接收模式时为12.3mA,掉电模式和待机模式下电流消耗更低。
nRF24L01原理图
nRF24L01引脚定义
2.通信说明
每个nRF24L01模块都可以设置发送地址和接收地址,地址长度均为40位,两个模块间的通信是依靠地址来识别的,通信地址与接收地址相匹配,才能进行数据收发。
例如:
A模块的发送地址是A5A5A5A5,其意思就是向A5A5A5A5这个地址发送数据,所以B模块的接收地址必须是A5A5A5A5,这样才能接收到A模块发送的数据。因为存在应答机制,B模块会向给它发送数据的地址回复应答数据(也就是A5A5A5A5),所以A模块的接收地址也要是A5A5A5A5。
如果两个模块要互相发送数据,都将发送地址和接收地址设置为同一个即可
nRF24L01 在接收模式下可以接收6路不同通道的数据,见上图。每个数据通道使用不同的地址,但是共用相同的频道。也就是说6个不同的 nRF24L01 设置为发送模式后可以与用一个设置为接收模式的 nRF24L01 进行通讯,而设置为接收模式的 nRF24L01 可以对这个6个发送端进行识别。数据通道0是唯一的一个可以配置为 40 位自身地址的数据通道。1~5数据通道都为8位自身地址和32位公用地址。所有的数据通道都可以设置为增强型 ShockBurst 模式。
nRF24L01 在确认收到数据后记录地址,并以此地址为目标地址发送应答信号。在发送端,数据通道0被用作接收应答信号,因此,数据通道0的接收地址要与发送端地址相等以确保接收到正确的应到信号。见下图选地址举例。
模块在同一时间内只能是发送模式或者接收模式,为了确保模块能及时接收到数据,一般都是让模块处于接收状态,要发送数据时再切换到发送状态,数据发送完后立即切换到接收状态。
当模块接收到数据后,IRQ引脚会输出低电平,所以我们在程序中检测到IRQ变为低电平后,读取模块的接收区即可。
2.SPI协议简介
SPI物理层
![](https://img-blog.csdnimg.cn/direct/04f880428d9b4290a1b1b068cb5de5ab.png)
协议层
![](https://img-blog.csdnimg.cn/direct/893c7f031a234e1a9227575c172ae92b.png)
![](https://img-blog.csdnimg.cn/direct/c2f952bb7e7f4523ab72a710b671b00a.png)
![](https://img-blog.csdnimg.cn/direct/4e5ef19776774d96898dac64dc6687ec.png)
![](https://img-blog.csdnimg.cn/direct/af1fddcc220b43b397f0cabb5746c7df.png)
3.模块使用方法
使用方法:
-
将 nfr.c 和 nfr.h 文件添加到工程
-
调用SPI_NRF_Init()对SPI接口进行初始化
-
调用函数NRF_Check()对模块进行通信检测,如果返回值为SUCCESS则表明开发板和模块通信正常
-
调用NRF_RX_Mode()函数,将模块设置为接收模式
-
在while循环中调用NRF_Rx_Dat()函数,如果函数返回值为RX_DR,则表明接收到数据
发送数据:
-
调用NRF_TX_Mode()函数,将模块切换为发送模式
-
调用NRF_Tx_Dat()函数来发送数据,如果返回值为TX_DS,则数据发送成功
-
调用NRF_RX_Mode()函数,将模块设置为接收模式
-
将这两个地址设置成一致(两台开发板以上地址要也要一模一样)
-
模块与开发板的连接:
驱动代码中使用SPI5与模块连接,连接如下
nRF24l01 开发板
GND<--->GND
3.3V<--->3.3V
CE<--->PG9
CSN<--->PG3
SCK<--->PF7
MOSI<--->PF9
MISO<--->PF8
IRQ<--->PC3
-
int couter = 0; uint8_t key1; uint8_t key2; int8_t touch=0 ; int8_t touch2=0 ; uint32_t delay_time = 50000; uint32_t system_time = 0; //编写中断服务函数 void EXTI0_IRQHandler()//中断服务函数名称 { if(EXTI_GetITStatus(EXTI_Line0)!=RESET )//证明触发中断 { //100ms = 100 000us delay_time += 10000; EXTI_ClearITPendingBit(EXTI_Line0); } } void EXTI15_10_IRQHandler() { if(EXTI_GetITStatus(EXTI_Line13)!=RESET )//证明触发中断 { delay_time-=10000; EXTI_ClearITPendingBit(EXTI_Line13); } } uint8_t chect_state ; uint8_t rec_state ; uint8_t rec_buf[32] = {0}; int main(void) { //初始化串口 USART1 //因为要用PA9 和PA10所以先初始化 GPIO_InitTypeDef gpio_info; LED_init(); key1_init(); key2_init(); Delay_init(); ADC_init(); ADC_GetValue(); UART_Init(115200); SPI_NRF_Init(); chect_state = NRF_Check(); //通讯检测 if(chect_state == SUCCESS ) { printf ("init SUCCESS\r\n"); } else { printf ("init FAIL\r\n"); } //初始化PI11蜂鸣器 //5.使能串口 USART_Cmd(USART1,ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOI,ENABLE); gpio_info.GPIO_Mode = GPIO_Mode_OUT; gpio_info.GPIO_OType = GPIO_OType_PP; gpio_info.GPIO_Pin = GPIO_Pin_11; gpio_info.GPIO_PuPd = GPIO_PuPd_UP; gpio_info.GPIO_Speed = GPIO_Low_Speed; GPIO_Init(GPIOI,&gpio_info); //将模块切换到接收模式 NRF_RX_Mode(); LED_Green_Ctrl(LED_OFF); LED_Blue_Ctrl(LED_OFF); LED_Red_Ctrl(LED_OFF); while(1) { //轮询检测,是否收到数据,如果返回值为RX_DR,表明收到数据 rec_state = NRF_Rx_Dat(rec_buf); if(rec_state == RX_DR) { //表明收到了数据,数据保存在rec_buf数组中 printf ("rec_state\r\n"); if(rec_buf[0]==0x33) { LED_Red_Ctrl( LED_ON); LED_Green_Ctrl(LED_OFF ); LED_Blue_Ctrl(LED_OFF); } } if(rec_buf[0]==0x44) { LED_Red_Ctrl( LED_OFF); LED_Green_Ctrl(LED_OFF ); LED_Blue_Ctrl(LED_OFF); } if(rec_buf[1]==0x66) { LED_Red_Ctrl( LED_OFF); LED_Green_Ctrl(LED_OFF ); LED_Blue_Ctrl(LED_ON); } if(rec_buf[1]==0x55) { LED_Red_Ctrl( LED_OFF); LED_Green_Ctrl(LED_OFF ); LED_Blue_Ctrl(LED_OFF); } if(GPIO_ReadInputDataBit(GPIOA ,GPIO_Pin_0)==1) { Delay_ms(100); if(GPIO_ReadInputDataBit(GPIOA ,GPIO_Pin_0)==1) { uint8_t send_buf[32] = {0}; uint8_t send_state; touch++; NRF_TX_Mode(); if(touch==1) { send_buf [0] = 0x33; send_buf [1] = 0x44; } if(touch==2) { send_buf [0] = 0x44; send_buf [1] = 0x33; touch=0; } send_state = NRF_Tx_Dat(send_buf); if(send_state == TX_DS) { printf ("send SUCCESS\r\n"); } else { printf ("send FAIL\r\n"); } //NRF_RX_Mode(); } } //KEY2 if(GPIO_ReadInputDataBit(GPIOC ,GPIO_Pin_13)==1) { Delay_ms(100); if(GPIO_ReadInputDataBit(GPIOC ,GPIO_Pin_13)==1) { uint8_t send_buf[32] = {0}; uint8_t send_state; touch2++; NRF_TX_Mode(); if(touch2==1) { send_buf [0] = 0x55; send_buf [1] = 0x66; } if(touch2==2) { send_buf [0] = 0x66; send_buf [1] = 0x55; touch2=0; } send_state = NRF_Tx_Dat(send_buf); if(send_state == TX_DS) { printf ("send SUCCESS\r\n"); } else { printf ("send FAIL\r\n"); } NRF_RX_Mode(); } } } }
以上代码可以实现在串口助手中显示两台开发板是否通讯成功,A按下KEY1,A发送成功B接收成功,A按下KEY2,B开发板的红色LED亮,再次按下熄灭,B同样可以控制A。
(以上内容均来自野火STM32开发板资料及老师教学内容)