[hermit auto=”1″ loop=”1″ unexpand=”1″ fullheight=”1″]netease_album#:34515142[/hermit]这两天在搞NRF24L01,其实一个开始是打算搞蓝牙串口模块的,但是感觉那玩意没啥技术含量,而且基本上就是一对一连接,而且到时候上位机搞起来也麻烦,毕竟以我风格,如果用都用蓝牙了,那上位机肯定是电脑上插个USB蓝牙,然后用易语言写个上位机程序直接控制,但是以以前的经历来说,易语言搞个串口通讯太不稳定,经常挂掉,有线串口还好,主要就是蓝牙,一用蓝牙就程序就死,以前做过蓝牙灯的项目,就是用蓝牙去控制灯泡开关,当时调试的时候也打算用易语言写上位机,结果根本没法通讯,一个数据包发过去基本就挂了.后来没办法逼我写安卓的,好多了.

谈回NRF24L01,一开始用这玩意也是因为有个比赛项目的后续改造用到了这个模块,当时是在STM32上调的,花了蛮多时间,调通了,也理解了不少东西,后来也零零散散在51上调过,也成了.所以也算是有点知根知底的意思了吧.

arduino这东西,搞外围肯定先找库,搞NRF24L01的时候也是第一时间去找库,当时找到两种,一种是arduino中文社区上的一篇帖子里的,RF24这个库,但是人家楼主都用红字标明了这库不稳定,这就基本判死刑了.还有一个Mirf库,网上教程也比较多,然后看了下还算可以,也没啥差评,功能也够用.就打算用这玩意.先是下库,百度搜”Mirf”.一搜一大堆,人家教程里也会直接贴下载链接.安装也是老样子,解压后文件夹拖到libraries里.

后来到了模块连线.这里稍微有个小注意.其实也还好,arduino或者单片机之类玩多了以后应该就知道了.NRF24L01是用SPI总线通讯的,而arduino也有硬件SPI,所以接线是有要求的,要根据硬件SPI的接口去接,不是说随便接下然后程序里一个#define定义一下就行了的.而且我这次是arduino UNO和arduino MEGA2560通讯,这俩板子的硬件SPI接口引脚号不一样,所以这个要去查一查.网上有很多这种引脚图,建议在桌面上放几个这种jpg.以便随时参考.

还有就是如果后面调程序的时候,发现始终不能通讯,可以考虑在两个NRF24L01模块的VCC和GND之间加个10uf电容(虽然我现在实际加的是100uf).另外有时候就算加了也没法通讯,必须要用手去接近arduino板或者arduino板与模块的连线才能用.不知道为啥,虽然以前也出现过这种情况,当时是自己打板子.做STM32,SW下载的时候必须要用手去摸PCB才能下载,莫名其妙,后来问了一些大神,说是要把信号线加粗,因为项目做完了,而且SW下载也不是常用的东西,也就没改.不知道加粗有没有效果.针对arduino的问题.估计也是差不多.加粗点信号线.把线搞短一点,尽量别用杜邦线.用单股的线,接地搞好点估计就没问题了,不过也没试.以后有机会再说吧.然后调程序的时候我先用了人家写的两个模块ping的程序,试过还不错,延时5-15毫秒左右.应该算是能接受,反正也就传些数据和命令.不是实时性太强的东西.

这里先贴下人家的ping程序

首先是发送端代码:

[codesyntax lang=”cpp”]

#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
void setup(){
  Serial.begin(9600);
  Mirf.cePin = 7; 
  Mirf.csnPin = 8;                                    //在这里自定义CE和CSN引脚
  Mirf.spi = &MirfHardwareSpi;               //Set the SPI Driver
  Mirf.init();                                             //Setup pins / SPI
  Mirf.setRADDR((byte *)"clie1");             
/*这句是设置本机的地址(其他模块向本机传送数据时用的地址),
地址长度是五个字节,这里把“clie1”转换为字节型当作本机地址*/
  Mirf.payload = sizeof(unsigned long);   
/*这里用于约定对话长度(字节数),也就是每次发送的数据长度,
最大32字节,默认16字节。这里的sizeof()函数返回了unsigned long型变量的长度*/
  Mirf.config(); 
  Serial.println("Beginning ... "); 
}
void loop(){
  unsigned long time = millis();
  Mirf.setTADDR((byte *)"serv1");
/*设置接收端地址*/
  Mirf.send((byte *)&time);
/*发送现在已经运行的时间(转换为字节型)*/
  while(Mirf.isSending()){
/*isSending是返回布尔值的函数,判断数据是否正在发送*/
  }
  Serial.println("Finished sending");
  delay(10);
  while(!Mirf.dataReady()){
/*dataready是一个返回布尔值的函数,判断数据接收是否完成*/
    Serial.println("Waiting");
    if ( ( millis() - time ) > 1000 ) {
      Serial.println("Timeout on response from server!");
      return;
    }
  }
  Mirf.getData((byte *) &time);
/*从缓冲区读取数据,接收用的变量应该与约定的对话长度等长*/
  Serial.print("Ping: ");
  Serial.println((millis() - time));
/*串口输出时间差*/
   
  delay(1000);
}

[/codesyntax]

 

然后是接收端代码:

[codesyntax lang=”cpp”]

#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
void setup(){
  Serial.begin(9600);
  Mirf.spi = &MirfHardwareSpi;
  Mirf.init();
  Mirf.setRADDR((byte *)"serv1");
  Mirf.payload = sizeof(unsigned long);
  Mirf.config();
  Serial.println("Listening..."); 
}
void loop(){
  byte data[Mirf.payload];
  if(!Mirf.isSending() && Mirf.dataReady()){
    Serial.println("Got packet");
    Mirf.getData(data);
    Mirf.setTADDR((byte *)"clie1");
    Mirf.send(data);
    Serial.println("Reply sent.");
  }
}

[/codesyntax]

 

然后是我的程序,因为我不打算拿NRF24L01做类似串口透传的东西,所以就写了个数据包.发送接收都是以数据包为单位的.

首先是h定义文件:

[codesyntax lang=”cpp”]

#include <arduino.h>
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>

struct DataPackte //数据包结构体
{  
        int command;  //命令
        char data[16];  //数据
        char property[8];  //属性
};  

#define NRF24L01_CE_PIN 49 //设置NRF24L01模块的CE引脚
#define NRF24L01_CSN_PIN 53 //设置NRF24L01模块的CSN引脚
#define NRF24L01_IRQ_INTERRUPT_NUMBER  4 //设置NRF24L01模块的IRQ引脚对应的中断号
#define NRF24L01_RADDR "car_1" //本设备的地址,长度为5
#define NRF24L01_TADDR "HOST_" //要发送到的设备的地址,长度为5
#define NRF24L01_CHANNEL 5 //通讯信道
void NRF24L01_Init(void);//初始化NRF24LO1
void NRF24L01_tmp(void);
bool NRF24L01_GetDataPacket(DataPackte* datapackte);//获取数据包,参数为数据包指针
bool NRF24L01_SendDataPacket(byte *SendAddr, char channel, DataPackte datapackte);//发送数据包,参数1是对方的地址,使用字节数组指针

[/codesyntax]

然后是Cpp文件

[codesyntax lang=”cpp”]

#include "NRF24L01.h"

void NRF24L01_IRQ(void)//NRF24L01模块的中断服务函数
{

}

void NRF24L01_Init(void)
{
  Mirf.cePin = NRF24L01_CE_PIN;
  Mirf.csnPin = NRF24L01_CSN_PIN;                                //在这里自定义CE和CSN引脚
  Mirf.spi = &MirfHardwareSpi; //这一句不用管,应该是设置一个函数指针指向Mirf模块内部的函数
  Mirf.init();//初始化Mirf库
  Mirf.setRADDR((byte *)NRF24L01_RADDR); //设置接收地址(本机地址)
  Mirf.setTADDR((byte *)NRF24L01_TADDR); //设置发送地址(对方地址)
  Mirf.channel = NRF24L01_CHANNEL; //设置通讯信道
  Mirf.payload = sizeof(DataPackte); //设置数据包长度
  Mirf.config(); //配置Mirf,使以上更改生效
  attachInterrupt(NRF24L01_IRQ_INTERRUPT_NUMBER, NRF24L01_IRQ, RISING); //设置NRF24LO1模块的中断引脚,使用上升沿中断,中断服务函数为NRF24L01_IRQ()
}

bool NRF24L01_GetDataPacket(DataPackte* datapackte)//获取数据包,参数为数据包指针
{
  union tmp_Data_Packe//声明共用体
  {
    DataPackte tmp_datapackte;//结构体变量
    unsigned char char_datapackte[sizeof(DataPackte)];//字节数组
  } tmp; //声明的时候同时创建一个tmp的tmp_Data_Packe共用体
  
  if (Mirf.dataReady()) //如果数据接收完毕
  {
    Mirf.getData(tmp.char_datapackte);//获取数据,将数据装填到共用体
    *datapackte=tmp.tmp_datapackte;//返回数据包
    return true;
  }
  else
  {
    return false;
  }
}

bool NRF24L01_SendDataPacket(byte *SendAddr, char channel, DataPackte datapackte) //发送数据包,参数1是对方的地址,使用字节数组指针
{
  union tmp_Data_Packe//声明共用体
  {
    DataPackte tmp_datapackte;//结构体变量
    unsigned char char_datapackte[sizeof(DataPackte)];//字节数组
  } tmp; //声明的时候同时创建一个tmp的tmp_Data_Packe共用体
  if (!Mirf.isSending())//是否正在发送中
  {
    Mirf.setTADDR((byte *)SendAddr); //设置发送地址(对方地址)
    Mirf.channel = channel; //设置通讯信道
    Mirf.payload = sizeof(DataPackte); //设置数据包长度
    Mirf.config(); //配置Mirf,使以上更改生效
    tmp.tmp_datapackte = datapackte; //将共用体中的结构体变量赋值
    Mirf.send(tmp.char_datapackte);//发送数据,使用共用体的字节数组对结构体进行拆分
    return true;
  }
  else
  {
    return false;
  }
}

[/codesyntax]

 

目前程序里只写了发送和接收数据包,还没好好利用NRF24L01的IRQ中断引脚,另外接下来可能会考虑加点群发的功能.嘛~看有没有时间呗~程序的话,上面那段基本主从机都一样.一些引脚定义在H文件里改下就行了.