NRF24L01⽆线通信模块使⽤⽰例和调试⼼得总结 nRF24L01是由NORDIC⽣产的⼯作在2.4GHz~2.5GHz的ISM 频段的单⽚⽆线收发器芯⽚。凭借其低功耗、传输速率⾼、误传率低等的优点,现已⼴泛应⽤在各种嵌⼊式系统中。本⽂就该模块总结⼀些学习过程中的经验和⼼得。
1. NRF24L01模块
该模块⼯作电压为3.3V,当该模块与单⽚机相连时,两者基于SPI通信协议进⾏数据交换。如果有两个以上的NRF⽆线模块且当代码中未设置SPI⽚选信号时,此时可⼀对多通信(即⼀个发多个收到该信息)。其外观如下: NRF24L01模块外观
内置式永磁同步电机
下⾯是该模块的PCB图,其中CE、CSN、IRQ为控制引脚;MOSI、MISO、SCK为SPI通信引脚。上⾯的这些引脚均可直接接普通的IO⼝,⽽不必特意选择SPI外设对应的引脚。下⾯解释各个引脚的具体含义: NRF24L01PCB封装
引脚引脚含义
VCC、GND电源引脚,注意务必接到3.3V的电源上
CE 使能引脚CSN
SPI⽚选引脚SCK
SPI数据引脚IRQ 可屏蔽中断引脚
引脚
引脚含义
uwb人员定位 本⽂的⽰例程序应⽤在两个NRF24L01模块之间相互通信的场合,其通信拓扑关系如下图:
本次实验中的通信关系图
上图中,之所以为了添加上位机与单⽚机的通信,主要是为了控制和验证通信内容。
2. SPI通信协议
上⾯提到了SPI通信协议,了解该协议的主要特点将⾮常有助于我们的调试⼯作。下⾯就讲⼀讲SPI通信协议:
SPI是串⾏外设接⼝(Serial Peripheral Interface)的缩写,是⼀种⾼速的,全双⼯,同步的通信总线,并且在芯⽚的管脚上只占⽤四根线,节约了芯⽚的管脚,同时为PCB的布局上节省空间,提供⽅便,正是出于这种简单易⽤的特性,越来越多的芯⽚集成了这种通信协议。
SPI的通信原理很简单,它以主从⽅式⼯作,这种模式通常有⼀个主设备和⼀个或多个从设备,需要⾄少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是MISO(主设备数据输⼊)、MOSI(主设备数据输出)、SCLK(时钟)、
CS(⽚选)。
(1)MISO– Master Input Slave Output,主设备数据输⼊,从设备数据输出;
(2)MOSI– Master Output Slave Input,主设备数据输出,从设备数据输⼊;
(3)SCLK – Serial Clock,时钟信号,由主设备产⽣;
(4)CS – Chip Select,从设备使能信号,由主设备控制。
SPI通信的内部简明图如下:
从图中可以看出, 主机和从机都有⼀个串⾏移位寄存器,主机通过向它的 SPI 串⾏寄存器写⼊⼀个字节来发起⼀次传输。寄存器通过MOSI 信号线将字节传送给从机,从机也将⾃⼰的移位寄存器中的内容通过 MISO 信号线返回给主机。这样,两个移位寄存器中的内容就被交换。外设的写操作和读操作是同步完成的。如果只进⾏写操作,主机只需忽略接收到的字节;反之,若主机要读取从机的⼀个字节,就必须发送⼀个空字节来引发从机的传输。
SPI 主要特点有: 可以同时发出和接收串⾏数据; 可以当作主机或从机⼯作; 提供频率可编程时钟; 发送结束中断标志; 写冲突保护; 总线竞争保护等。
SPI 总线四种⼯作⽅式 SPI 模块为了和外设进⾏数据交换,根据外设⼯作要求,其输出串⾏同步时钟极性和相位可以进⾏配置,时钟极性(CPOL)对传输协议没有重⼤的影响。如果CPOL=0,串⾏同步时钟的空闲状态为低电平;如果 CPOL=1,串⾏同步时钟的空闲状态为⾼电平。时钟相位( CPHA)能够配置⽤于选择两种不同的传输协议之⼀进⾏数据传输。如果CPHA=0,在串⾏同步时钟的第⼀个跳变沿(上升或下降)数据被采样;如果 CPHA=1,在串⾏同步时钟的第⼆个跳变沿(上升或下降)数据被采样。 SPI 主模块和与之通信的外设备时钟相位和极性应该⼀致。
SPI时序图如下:
SPI通信时序图
3. 软件设计
本次实验在stm32f10xxx单⽚机上学习NRF⽆线模块的通信特点。代码中主要包含:NRF24L01模块的驱动程序(如初始化、发送/接收数据等函数的编写)、串⼝通信等。软件流程如下:
(1)初始化NRF⽆线模块和其他必要的外设;
(2)进⼊默认发送数据状态;
(3)监控串⼝中断,确认是否要修改通信状态——切换发送/接收信息状态;
由于代码量较⼤,这⾥只展⽰主函数和串⼝中断服务函数如下:
#include"stm32f10x.h"
#include"delay.h"
载人行李箱#include"24l01.h"
#include"timer.h"
#include"spi.h"
#include<stdio.h>
#include"usart.h"
u8 mode;
int main()
{
u8 i;
u8 hell[]="Hello! NRF24L01",buff;
mode=1;
delay_init();
uart_init(115200);//设置串⼝波特率
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置NVIC中断分组2:2位抢占优先级,2位响应优先级
NRF24L01_Init();//初始化NRF24L01模块
delay_ms(50);
while(NRF24L01_Check())//如果通信模块有问题会通过串⼝向上位机发送警告信息
{
printf("ERROR!\n");//向上位机报错
delay_ms(500);
触摸调光ic}
while(1)
{
if(mode)
{
NRF24L01_TX_Mode();
for(i=0;hell[i]!='\0';i++)
{
while(NRF24L01_TxPacket(&hell[i])!= TX_OK);//发送⼀个字节
取石网篮}
printf("%s",hell);//发送完后,再向上位机汇报所发送的内容
}
柿子去皮机else
{
NRF24L01_RX_Mode();
i =0;
while(NRF24L01_RxPacket(&buff));//向上位机发送接收到的数据
printf("%c",buff);
}
}
}
void USART1_IRQHandler(void)//串⼝1中断服务程序,通过串⼝修改NRF24L01模块的⼯作状态
{
if(USART_GetITStatus(USART1, USART_IT_RXNE)!= RESET)//接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
mode =USART_ReceiveData(USART1)-'0';//读取接收到的数据
}
}
4. 总结
嵌⼊式通信的调试⼯作⼀直是最复杂的任务之⼀,因此,本着开源的精神,笔者将此次调试好的、完整的C语⾔项⽬共享在公众
号“24K纯学渣”上⾯,回复“NRF⽆线通信”即可获取!另外,限于作者⽔平,难免出现⼀些纰漏,以上所述如有不妥,欢迎⼤家评论交流!