风筝
发表于: 2021-4-30 11:41:47 | 显示全部楼层

在物联网时代,无线通信在日常生活中变得越来越流行。如今,设备可以通过云或本地网络相互通信。当谈及本地无线通信时,需要一个执行这些任务的RF系统模块,我们可以找到具有各种配置的RF系统模块,例如低功耗蓝牙、Zigbee、ESP Wi-Fi模块、433MHz RF模块、Lora、nRF等。今天,在本文中,我们将讨论nRF24L01,它是Nordic Semiconductor公司的RF收发器。该模块在2.4GHz频段下运行,其波特率为250Kbps至2Mbps。 250Kbps至2Mbps的波特率在许多国家都是合法的,这就是为什么将其用于工业和医疗应用的原因。有许多基于nRF24L01芯片的模块可用,其中一种模块带有板载天线通讯范围可达100m,另一种模块使用外部天线通讯范围可达1000m。在本文中,我们将在Arduino开发板与PIC18F622K微控制器之间建立无线通信,通过这种方式,我们可以对通信过程的工作方式有一个更清晰的了解,让我们开始吧。


什么是nRF24L01 2.4GHz射频收发器模块?

nRF24L01是单芯片低功耗RF收发器模块。这就是为什么我们可以将其配置用于发送和接收的模块。但是nRF24L01只能执行半双工通信,因此我们可以一次发送或接收数据。 nRF24L01工作在2.4GHz频段,可合法用于工业、科学和医学用途。该模块的引脚如下所示。

nRF24L01-Pinout.jpg


该模块的功耗非常低,这就是为什么它适合物联网项目的原因。由于该模块通过SPI通信,因此很容易通过SPI总线与任何微控制器连接。而且,此模块对于100m至1000m的远程通信具有250Kbps至2Mbps的极高传输速度。


这是一个非常便宜的模块,可在2.4GHz ISM频段下运行。它的最大吞吐量为2Mbps,并且该模块的信号采用GFSK调制技术进行编码。该模块工作在1.9V至3.6V,仅消耗13.5mA电流,在深度睡眠模式下,消耗26uA电流。该模块另外一个优势是,模块的SPI引脚可承受5V的电压,因此我们可以将该模块直接与Arduino通信,而无需逻辑电平转换器。


所需的组件

●    PIC单片机(PIC18F46K22

●    Arduino Uno / Nano开发板

●    nRF24L01模块

●    20MHz晶振

●    33pf电容

●    4.7k电阻

●    10uF和0.1uF电容

●    LED指示灯

●    按键开关

●    面包板

●    跳线


连接nRF24L01和PIC18F46K22单片机的原理图

下面显示了制作基于PIC18F6K22的SPI通信电路的完整原理图。

PIC18F6K22-based-SPI-Communication-Test-Circuit.png


注意:nRF24L01模块对电源噪声非常敏感。因此,最好在电源中增加一个去耦电容,可以是10uF和0.1uF。 Arduino开发板上的3.3V引脚可能无法为nRF24L01模块提供足够的电源。因此,使用外部电源是一种好方法。

nRF24L01-Module.jpg


PIC18F6K22-based-SPI-Communication-Board.jpg

跳转到指定楼层
风筝
发表于: 2021-4-30 11:56:21 | 显示全部楼层

在PIC单片机和Arduino微控制器之间建立通信的代码

在本文中,我们使用nRF24L01库在PIC18单片机和Arduino之间通过RF发送和接收数据。我们使用Microchip代码配置器(MCC)为(PIC18F46K22)配置程序。


注意:为方便起见,我们已从Arduino移植了NRF库,您可以通过单击下面的链接来下载:

Arduino库


PIC18F46K22单片机的代码

首先在代码中包含上面提到的库文件。

  1. #include "mcc_generated_files/mcc.h"
  2. #include "nrf24_lib.h"
  3. #include <string.h>
复制代码

接下来,我们定义2个宏,用于为nRF24L01 Tx操作和Rx操作配置应用程序。对于Tx操作,我们需要将NRF24L01_TX_EX的值更改为1;对于Rx操作,我们需要将其值更改为0。

  1. #define NRF24L01_TX_EX  0
  2. #define NRF24L01_RX_EX  !NRF24L01_TX_EX
复制代码

接下来,我们使用Timer0定义一个回调函数,用于每1秒间隔闪烁LED。

  1. void blink_led() {
  2. LED_Toggle();
  3. }
复制代码

main()函数中,我们调用SYSTEM_Initialize()函数来初始化系统外设,例如(INTERRUPT、Pin、Timer0、UART、SPI1),并启用全局和外设中断。

  1. void main(void)
  2. {
  3. // Initialize the device
  4. SYSTEM_Initialize();
  5. // If using interrupts in PIC18 High/Low Priority Mode you need to enable the Global High and Low Interrupts
  6. // If using interrupts in PIC Mid-Range Compatibility Mode you need to enable the Global and Peripheral Interrupts
  7. // Use the following macros to:
  8. // Enable the Global Interrupts
  9. INTERRUPT_GlobalInterruptEnable();
  10. // Disable the Global Interrupts
  11. //INTERRUPT_GlobalInterruptDisable();
  12. // Enable the Peripheral Interrupts
  13. INTERRUPT_PeripheralInterruptEnable();
  14. // Disable the Peripheral Interrupts
  15. //INTERRUPT_PeripheralInterruptDisable();
复制代码

系统初始化后,我们调用TMR0_SetInterruptHandler()函数设置回调函数,然后启动Timer0。

  1. TMR0_SetInterruptHandler(blink_led);
  2. TMR0_StartTimer();
复制代码

完成所有初始化后,我们可以使用nRF24L01开始该过程。首先,我们需要初始化nRF24,为此,我们调用nrf24_rf_init()函数以及nRF24L01操作模式(Tx或Rx)和RF通道频率(0-127)。成功初始化nRF24后,打印当前配置的nRF24的寄存器映射设置。

  1. #if NRF24L01_TX_EX
  2. ret = nrf24_rf_init(TX_MODE, 115); // Tx mode with 2400+115 Ghz RF frq
  3. #elif NRF24L01_RX_EX
  4. ret = nrf24_rf_init(RX_MODE, 115); // Rx mode with 2400+115 Ghz RF frq
  5. #endif
  6. if (ret == NRF24_INIT_OK) {
  7.     printf("###############################################################\r\n");
  8.     printf("NRF24L01 Initialize successful\r\n");
  9.     nrf24_printf_rf_config();
  10.     printf("###############################################################\r\n");
复制代码

初始化nRF24之后,我们在while循环中执行Tx和Rx操作过程。

●  在Tx模式下:我们创建一个带有整数变量值的缓冲区,并将该缓冲区传递给nrf24_send_rf_​​data()并递增整数变量值。

  1. #if NRF24L01_TX_EX
  2.     static char val = 0;
  3.     sprintf(bufferTX, "Sending: %d", val);
  4.     nrf24_send_rf_data(bufferTX);
  5.     val++;
  6.     __delay_ms(100);
复制代码

●  在Rx模式下:我们监视nrf24_is_rf_data_available()以获取nRF24是否接收某些数据的状态。接收到一些数据后,我们调用nrf24_read_rf_​​data()将接收到的数据放入缓冲区并打印缓冲区。

  1. #elif NRF24L01_RX_EX
  2.     while (nrf24_is_rf_data_available()) {
  3.     }
  4.     nrf24_read_rf_data(bufferRX);
  5.     printf("RX data %s\r\n", bufferRX);
  6.     __delay_ms(10);
  7. #endif
复制代码

Arduino的代码

首先在代码中包含所有必需的库。该库包括用于访问nRF24L01命令的RF24、SPI库和printf库。而且,我们还包括一些将用于将模块设置为发送器和接收器。

  1. //Include Libraries
  2. #include <SPI.h>
  3. #include <nRF24L01.h>
  4. #include <RF24.h>
  5. #include "printf.h"
  6. #define NRF24L01_TX_EX  1
  7. #define NRF24L01_RX_EX  !NRF24L01_TX_EX
复制代码

接下来,我们为RF24创建一个实例,并传递CE和CSN PIN,我们还保存了要与模块进行通信的地址。

  1. //create an RF24 object
  2. RF24 radio(9, 8);  // CE, CSN
  3. //address through which two modules communicate.
  4. const byte address[6] = {0xe1, 0xe1, 0xe1, 0xe1, 0xe1};
复制代码

接下来,我们定义setup函数。我们初始化了串口监视器以进行调试,并且还设置了NRF24 Radio。

  1.   Serial.begin(115200);
  2.   printf_begin();
  3.   Serial.println(F("\n\rRF24/examples/scanner/"));
  4.   // Setup and configure rf radio
  5.   radio.begin();
  6.   radio.setAutoAck(false);
复制代码

现在,记住我们定义的两个宏。借助这些宏,您可以非常轻松地将模块设置为发送器或接收器。

  1. #if NRF24L01_TX_EX
  2.   //set the address
  3.   radio.openWritingPipe(address);
  4.   radio.setPALevel(RF24_PA_MIN); //set as: RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX
  5.   radio.setDataRate(RF24_2MBPS); //set as: F24_250KBPS, F24_1MBPS, F24_2MBPS ==>250KBPS = longest range
  6.   radio.setChannel(115); //sets channel from 2.4 to 2.524 GHz in 1 MHz increments 2.483.5 GHz is normal legal limit
  7.   radio.setCRCLength(RF24_CRC_8);
  8.   radio.printDetails();
  9.   //Set module as transmitter
  10.   radio.stopListening();
  11. #elif NRF24L01_RX_EX
  12.   radio.openReadingPipe(0, address);
  13.   radio.setPALevel(RF24_PA_MIN); //set as: RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX
  14.   radio.setDataRate(RF24_2MBPS); //set as: F24_250KBPS, F24_1MBPS, F24_2MBPS ==>250KBPS = longest range
  15.   radio.setChannel(115); //sets channel from 2.4 to 2.524 GHz in 1 MHz increments 2.483.5 GHz is normal legal limit
  16.   radio.setCRCLength(RF24_CRC_8);
  17.   // Get into standby mode
  18.   radio.startListening();
  19.   radio.stopListening();
  20.   radio.printDetails();
  21.   // Get into standby mode
  22.   radio.startListening();
  23. #endif
复制代码

接下来,在loop()函数中,我们定义了32个数组,将消息存储到该数组中并将其发送到另一个模块。现在,借助sprint()函数,我们一次发送一个字符,并在串口监视器窗口上打印该值以进行调试。

  1. void loop()
  2. {
  3. #if NRF24L01_TX_EX
  4.   //Send message to receiver
  5.   char text[32] = {0};
  6.   sprintf(text, "Hello PIC18 %d", val++);
  7.   radio.write(&text, sizeof(text));
  8.   Serial.println(text);
  9. #elif NRF24L01_RX_EX
  10.   //Read the data if available in buffer
  11.   if (radio.available())
  12.   {
  13.     char text[32] = {0};
  14.     radio.read(&text, sizeof(text));
  15.     Serial.println(text);
  16.   }  
  17. #endif
  18. delay(250);
  19. }’
复制代码

回复

使用道具 举报

风筝
发表于: 2021-4-30 14:21:13 | 显示全部楼层

测试和调试通信过程

我们完成电路搭建,并上传代码后,将通过使用放入代码中的调试日志对电路进行测试。 如您所见,我们已经使用Arduino IDE串口监视器和UART转换器来输出Arduino UNO的调试数据,而对于PIC微控制器,我们使用了PuTTY串口监视器。

nRF24L01-With-PIC18F46K22-Microcontroller.jpg


调试日志(Uno作为Tx,PIC作为Rx):

首先我们在Arduino IDE串口监视器上看到“ Hello PIC18 10”消息。 然后,我们在PIC微控制器侧查看PuTTY串口监视器,以验证接收到的数据消息是否相同。 下图显示了这一点。

Debugging-Log-for-Uno-as-Tx-and-PIC-as-Rx.jpg


调试日志(Uno为Rx,PIC为Tx):

首先我们在PuTTY串口监视器中看到“ Hello Arduino 10”消息,然后就在Arduino IDE串口监视器中检查以确认接收到的数据消息是否相同。

Debugging-Log-for-Uno-as-Rx-and-PIC-as-Tx.jpg

回复

使用道具 举报

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

本版积分规则

主题 10 | 回复: 13



手机版|

GMT+8, 2024-7-20 12:28 , Processed in 0.056822 second(s), 12 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

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