Application example of Arduino(NANO) NRF24L01
Software preparation:
microBox Library( https://github.com/wastel7/microBox ): build a mini command line system
Mirf Library ( https://github.com/E-elektronic/Mirf ): provide RF related core functions
Please download the above library by yourself
Hardware preparation:
Arduino NANO plate x 2; NRF24L01 x 2; Other;
Development environment:
VS2017 + Arduino IDE(1.8.4)
Hardware connection:
The connection mode of Server, Client and NRF24L01 module is the same. Wiring sequence: VCC:3.3V; GND:GND; CSN: 7; CE:8; MOSI:11; SCK:13; IRQ: not connected; MISO:12;
Be careful:
1. The Microbox library needs to be modified to test this example. The modifications are as follows:
microBox.h:
#Define max? CMD? Num 128 / / set the appropriate value to accept the input correctly
#Define max? CMD? Buf? Size 128 / / set as needed
2. After a simple performance test, the routine can send and receive at most 50ms (send 32Byte and receive 32Byte)
3. In some cases, it may fail to send. After testing, it is found that it is the problem of the Client side. Solution: reset the Client side, and now provide the "reset" instruction to support soft reset
Client code (client.ino):
#include "microBox.h" #pragma region UserDefined //#define DEBUG #undef DEBUG #ifndef ADD_RF #define ADD_RF #endif // !ADD_RF #ifdef ADD_RF /* * Hardware SPI: * MISO -> 12 * MOSI -> 11 * SCK -> 13 * * Configurable: * CE -> 8 * CSN -> 7 */ #include <SPI.h> #include "Mirf.h" #include "nRF24L01.h" #include "MirfHardwareSpiDriver.h" #define ulong unsigned long #define dword ulong uint8_t code[32] = { 0 }; void(*ResetInternal) (void) = 0; //CRC-8, Widh:8, Poly:0x07, Init: 0x00 //RefIn:False, RefOut:False, XorOut:0x00 byte CalcCRC8(byte * pdata, unsigned int len) { byte crc = 0x00; for (int i = 0; i < len; i++) { crc ^= ((*pdata++) & 0xFF); for (byte j = 0; j < 8; j++) { if (crc & 0x80) { crc <<= 1; crc ^= 0x07; } else { crc <<= 1; } } } return crc; } bool RfSend_Internal(uint8_t * data) { int i = 0; unsigned long time = millis(); byte crc = CalcCRC8(data, 32); Serial.print("cmd: "); for (i=0;i<32;i++) { (data[i] < 0x10) ? Serial.print(0) : i; Serial.print(data[i], HEX); (i==31)? Serial.println(""):Serial.print(" "); } Mirf.send(data); while (Mirf.isSending()) { if ((millis() - time) > 2000) { Serial.println("timeout on send cmd!"); return false; } } while (!Mirf.dataReady()) { if ((millis() - time) > 2000) { Serial.println("timeout on response from server!"); return false; } } Mirf.getData(data); Serial.print("ack: "); for (i = 0; i < 32; i++) { (data[i] < 0x10) ? Serial.print(0) : i; Serial.print(data[i], HEX); (i==31)? Serial.println(""):Serial.print(" "); } Serial.print("result: "); if (crc == data[0]) Serial.println("succ"); else Serial.println("fail"); } void RfSend(char **param, uint8_t parCnt) { if (parCnt == 8) { ulong uli[8]; for (int i=0; i < 8; i++) { uli[i] = strtoul(param[i], 0, 16); code[3 + i * 4] = (uint8_t)(uli[i] & 0xff); code[2 + i * 4] = (uint8_t)((uli[i] & 0xff00) >> 8); code[1 + i * 4] = (uint8_t)((uli[i] & 0xff0000) >> 16); code[0 + i * 4] = (uint8_t)((uli[i] & 0xff000000) >> 24); } RfSend_Internal(code); } else Serial.println(F("Usage: rf-send hex-code(8 dwords), eg: rf-send 01020304 05060708 090A0B0C 0D0E0F10 11121314 15161718 191A1B1C 1D1E1F20")); } void Reset(char **param, uint8_t parCnt) { ResetInternal(); } void UsrInit() { Mirf.spi = &MirfHardwareSpi; Mirf.init(); Mirf.setRADDR((byte *)"sndr0"); Mirf.setTADDR((byte *)"serv0"); Mirf.payload = 32; //Mirf.channel = 10; Mirf.config(); } #endif // ADD_RF #pragma endregion #pragma region InternalFunc char historyBuf[100]; char hostname[] = "tdxk"; PARAM_ENTRY Params[] = { {"hostname", hostname, PARTYPE_STRING | PARTYPE_RW, sizeof(hostname), NULL, NULL, 0}, {NULL, NULL} }; void getMillis(char **param, uint8_t parCnt) { Serial.println(millis()); } void freeRam(char **param, uint8_t parCnt) { extern int __heap_start, *__brkval; int v; Serial.println((int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval)); } void writePin(char **param, uint8_t parCnt) { uint8_t pin, pinval; if (parCnt == 2) { pin = atoi(param[0]); pinval = atoi(param[1]); digitalWrite(pin, pinval); } else Serial.println(F("Usage: writepin pinNum pinvalue")); } void readPin(char **param, uint8_t parCnt) { uint8_t pin; if (parCnt == 1) { pin = atoi(param[0]); Serial.println(digitalRead(pin)); } else Serial.println(F("Usage: readpin pinNum")); } void setPinDirection(char **param, uint8_t parCnt) { uint8_t pin, pindir; if (parCnt == 2) { pin = atoi(param[0]); if (strcmp(param[1], "out") == 0) pindir = OUTPUT; else pindir = INPUT; pinMode(pin, pindir); } else Serial.println(F("Usage: setpindir pinNum in|out")); } void readAnalogPin(char **param, uint8_t parCnt) { uint8_t pin; if (parCnt == 1) { pin = atoi(param[0]); Serial.println(analogRead(pin)); } else Serial.println(F("Usage: readanalog pinNum")); } void writeAnalogPin(char **param, uint8_t parCnt) { uint8_t pin, pinval; if (parCnt == 2) { pin = atoi(param[0]); pinval = atoi(param[1]); analogWrite(pin, pinval); } else Serial.println(F("Usage: writeanalog pinNum pinvalue")); } #pragma endregion void setup() { Serial.begin(115200); microbox.begin(&Params[0], hostname, true, historyBuf, 100); microbox.AddCommand("free", freeRam); microbox.AddCommand("millis", getMillis); microbox.AddCommand("readanalog", readAnalogPin); microbox.AddCommand("readpin", readPin); microbox.AddCommand("setpindir", setPinDirection); microbox.AddCommand("writeanalog", writeAnalogPin); microbox.AddCommand("writepin", writePin); #ifdef ADD_RF UsrInit(); microbox.AddCommand("rf-send", RfSend); microbox.AddCommand("reset", Reset); #endif // ADD_RF } void loop() { microbox.cmdParser(); }
Server code (Server.ino):
/** * An Mirf example which copies back the data it recives. * * Pins: * Hardware SPI: * MISO -> 12 * MOSI -> 11 * SCK -> 13 * * Configurable: * CE -> 8 * CSN -> 7 * */ #include <SPI.h> #include "Mirf.h" #include "nRF24L01.h" #include "MirfHardwareSpiDriver.h" #define DEBUG //#undef DEBUG #define ulong unsigned long #define dword ulong #define SEND_DATA(dw1,dw2,dw3,dw4,dw5, dw6, dw7, dw8) {SendData((dword)(dw1),(dword)(dw2),(dword)(dw3),(dword)(dw4),(dword)(dw5),(dword)(dw6),(dword)(dw7),(dword)(dw8));Mirf.send(data); } //FLAG #define ACK_OK 0xE0 #define ACK_NG 0xE1 #define ACK_ERROR 0xE2 byte data[32]; byte checksum; ulong ulCode[8] = {0}; //CRC-8, Widh:8, Poly:0x07, Init: 0x00 //RefIn:False, RefOut:False, XorOut:0x00 byte CalcCRC8(byte * pdata, unsigned int len) { byte crc = 0x00; for (int i = 0; i < len; i++) { crc ^= ((*pdata++) & 0xFF); for (byte j = 0; j < 8; j++) { if (crc & 0x80) { crc <<= 1; crc ^= 0x07; } else { crc <<= 1; } } } return crc; } void SendData(dword dw1, dword dw2, dword dw3, dword dw4, dword dw5, dword dw6, dword dw7, dword dw8) { int i = 0; dword dwData[8] = { dw1, dw2, dw3, dw4, dw5, dw6, dw7, dw8}; for (i = 0; i < 8; i++) { data[3 + i * 4] = (uint8_t)(dwData[i] & 0xff); data[2 + i * 4] = (uint8_t)((dwData[i] & 0xff00) >> 8); data[1 + i * 4] = (uint8_t)((dwData[i] & 0xff0000) >> 16); data[0 + i * 4] = (uint8_t)((dwData[i] & 0xff000000) >> 24); } Serial.print("ack: "); for (i = 0; i < 32; i++) { (data[i] < 0x10) ? Serial.print(0) : i; Serial.print(data[i], HEX); (i == 31) ? Serial.println("") : Serial.print(" "); } } void setup() { Serial.begin(115200); Mirf.spi = &MirfHardwareSpi; Mirf.init(); Mirf.setRADDR((byte *)"serv0"); //serv0 Mirf.payload = 32; Mirf.config(); Serial.println("Listening..."); } void loop() { int i = 0; if (!Mirf.isSending() && Mirf.dataReady()) { Mirf.getData(data); Serial.print("cmd: "); for (i=0;i<32;i++) { (data[i] < 0x10) ? Serial.print(0) : i; Serial.print(data[i], HEX); (i==31)? Serial.println(""):Serial.print(" "); } Mirf.setTADDR((byte *)"sndr0"); //sndr0 for (i=0;i<8;i++) { ulCode[i] = (unsigned long)((unsigned long)data[0 + i * 4] << 24 | (unsigned long)data[1 + i * 4] << 16 | (unsigned long)data[2 + i * 4] << 8 | data[3 + i * 4]); } checksum = CalcCRC8(data, 32); switch (ulCode[0]) { case 0x00000000: SEND_DATA(((dword)checksum << 24) + ACK_OK, 0, 0, 0, 0, 0, 0, 0); break; case 0x00000001: SEND_DATA(((dword)checksum << 24) + ACK_OK, 0x01020304, 0x05060708, 0x090A0B0C, 0x0D0E0F10, 0x11121314, 0x15161718, 0x191A1B1C); break; case 0x00000002: SEND_DATA(((dword)checksum << 24) + ACK_OK, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678); break; default: SEND_DATA(((dword)checksum << 24) + ACK_ERROR, 0, 0, 0, 0, 0, 0, 0); break; } } }
Test diagram: