את המעגל יצרתי באמצעות תוכנה מאוד שימושית ופופולרית בשם – fritzing שלא ארחיב עליה כאן רק אצרף את הקובץ לצורך הדפסת המעגל.
יש 2 ספריות נפוצות לארדואינו לצורך עבודה עם המודול הזה – rf24 ו mirf.
אני מצאתי את הספרייה rf24 מתאימה יותר לצורך של רשת מודולים אל אף שהיא יותר מורכבת מאשר ספריית ה mirf כמו כן ישנה ספרייה מעולה (אם כי קצת מורכבת) לצורך רשת מודולים שמבוססת על ספריית ה rf24 בשם – rf24network .
אני אדלג על הסבר לספריית rf24 ואקפוץ ישר לעניינים – rf24network.
להלן סכימת החיבור בין הארדואינו לבין רכיב ה nrf24l01 :
סכמת חיבור ארדואינו ל NRF24L01
סיגנל
ארדואינו
NRF24L01
GND
GND
1
VCC
3.3V
2
CE
9
3
CSN
10
4
SCK
13
5
MOSI
11
6
MISO
12
7
סכמת חיבור ארדואינו ל NRF24L01
כלומר אם יש בארדואינו פרו 13 יציאות דיגיטליות ו7 יציאות אנלוגיות אחרי חיבור למודול האלחוטי נשארנו עם 8 יציאות דיגיטליות ו7 אנלוגיות.(שזה דיי מספיק למודול אחד – יכולת שליטה על עד 8 אלמנטים וחיבור של עד 7 חיישנים ).
כלומר אני צריך לתכנן מעגל לחיבור מודול האלחוט לארדואינו וחשיפה של 8 פינים דיגיטליים ו 7 אנלוגיים כמו כן עלי להמיר את 5V שמגיע מהארדואינו למודול האלחוט (VCC) מ5V ל 3.3V.
כמו כן עלי לחשוף גם את הפין ה RST לצורך העברת הקוד לארדואינו ואת פין ה RAW לצורך חיבור למקור מתח חיצוני לדוגמה סוללה.
את המעגל יצרתי באמצעות שיטת ה – tuner transfer שלא כאן המקום להרחיב.
השתמשתי בארדואינו פרו 5V ולא ב-3.3V בגלל שההבדל בעלות זה כמעט דולר אך הדבר הצריך ממני להוסיף למעגל ממיר מתח ל3.3 בגלל שזה מה שמקבל מודול ה- nrf24l01 (כמעט 10 ממירי מתח וקבלים עלו לי קצת מעל 2 דולר כך שעדיין יוצא יותר זול).
המעגלים (לוח הארדואינו המודפס שבתמונות לא קשור לפרויקט):
אפרט קצת על מבנה רשת העלים.
היישום הרשת היה קצת שונה מהיישום של מחבר הספרייה rf24network אך עדיין מבוסס על טופולוגית עץ.
ישנו בסיס ראשי בכתובת 00 (כתובות העלים הם בפורמט uint16_t unsigned 16-bit integer) והיות ויש אפשרות ל6 צינורות (PIPES) תקשורת לכל מודול nrf24l01 לפי ה – DATASHEET, אז כל עלה בסיס יכול לתקשר עם 5 בנים (sibling) ועם האבא שלו, הבסיס הראשי היות והוא אב לכולם ואין לו אב משלו יש לו אפשרות להתחבר ל 6 בנים אך כדי לשמור על הקוד פשוט ושכל עלה ראשי יהיה עם אותם המאפיינים אז גם העלה הראשי ביותר יכול לתקשר רק עם 5 בנים.
כל עלה יכול לתקשר עם בסיס האב שלו או עם אחד הבנים שלו אך לא עם אחד מהאחים שלו או עם הסבא או הנכד וכו'…
הקוד שלי הוא עד הרמה השלישית, כלומר 5 בחזקת 3 כלומר 1+25+125+5 עלים = עד 151 נקודות מודולים ברשת ! יכולתי להוסיף עוד 'דור' לרשת ואז היה אפשרות ליותר מפי חמש אך 151 מודולים זה דיי והותר לרשת ביתית.
להלן סכמה של המודולים והכתובות שלהם – נשים לב שהספרות הכי ימניות במספר uint16_t הם בעצם כתובת האב:
בסיס האב הראשי – 00 יהיה בעל קישוריות לאינטרנט (wired / wifi) והוא יהיה אחראי על חשיפת כל רשת החיישנים ומודולי השליטה לרשת האינטרנט.
לבסיס האב הראשי 5 ילדים – 01,02,03,04,05 הוא יכול לתקשר רק איתם והם איתו. האחים לא מדברים בינהם – 01 לא יכול לתקשר עם 02, אלא רק עם האב שלו (00) ועם חמשת ילדיו – 011,021,031,041,051 ,כלומר אם בסיס 00 מעוניין להעביר פקודה לעלה 011 או לקרוא מידע מעלה 011 התעבורה צריכה להיות דרך עלה 01 שהוא האב של 011 והבן של 00 וכן על זה הדרך…
ואם נתרגם למספרים רגילים אז מודול 0 מדבר עם מודולים 1-5 ומודול 1 מדבר עם אביו(0) ועם מודולים 9,17,25,33,41(כפולות של 8).
מודול 2 מדבר עם אביו(0) ועם ילדיו שהם 10,18,26,34,42 (גם כן כפולות של 8) וכן הלאה.
חשבתי בהתחלה לשמור את כתובת העלים ב EEPROM אך לשם הפשטות הכנסתי לכל עלה את הכתובת שלו בתוך קוד המקור (hard coded).
אני מצרף כאן קוד מקור למודול הבסיס וקוד מקור לכל מודולי העלים כרגע הכל זה רישומים ל serial consule אין עדיין חיישנים או relays:
קוד הבסיס:
/*
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* https://iot.org.il
* Internet Of Things Implement by Arduino Pro and nrf24l01
* using RF24Network
*
* Base NODE - main node with eventually internet gateway always with address 00
* By Vardi Michael.
* Adapt from Maniacbug - http://maniacbug.wordpress.com
*/
#include <RF24Network.h>
#include <RF24.h>
#include <SPI>
// nRF24L01(+) radio attached using Getting Started board
RF24 radio(9,10);
// Network uses that radio
RF24Network network(radio);
// Address of our node
const uint16_t this_node = 00;
// Address of the other node
uint16_t other_node;
// Structure of message
char bits[8];
struct a_message//structure of message(need to be less than 32 bytes)
{
uint16_t addressTo; //where the message destination
char digital1To8; // char with take 2 bytes - 8 bits so we can put inside one char 8 digital pins status...
int A1;//sensor number 1
int A2;//sensor number 2
int A3;//sensor number 3
int A4;//sensor number 4
int A5;//sensor number 5
char typeOfMsg;//is it sensor reading or digital command
uint16_t addressFrom;//original origin of the message.
};
String getValue(String data, char separator, int index)
{
int found = 0;
int strIndex[] = {0, -1};
int maxIndex = data.length()-1;
for(int i=0; i<=maxIndex && found<=index; i++) { if(data.charAt(i)==separator || i==maxIndex) { found++; strIndex[0] = strIndex[1]+1; strIndex[1] = (i == maxIndex) ? i+1 : i; } } return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}
void getBits(char c){
for (int i = 7; i >= 0; --i)
{
bits[i]=(c & (1 << i)) ? '1' : '0'; } } void setup(void) { Serial.begin(57600); Serial.println("Base Node Started"); SPI.begin(); radio.begin(); network.begin(/*channel*/ 90, /*node address*/ this_node); } void loop(void) { // Pump the network regularly network.update(); String content = ""; char character; // Is there anything ready for us? while ( network.available() ) { // If so, grab it and print it out RF24NetworkHeader header; a_message message; network.read(header,&message,sizeof(message)); Serial.print(message.addressFrom); Serial.print(";"+message.A1); Serial.print(";"+message.A2); Serial.print(";"+message.A3); Serial.print(";"+message.A4); Serial.print(";"+message.A5); Serial.println(";"+message.typeOfMsg);//+";"+message.A2+";");//+message.A3+";"+message.A4+";"+message.A5+";");//+";"+message.A2+";"+message.A3+";"+message.A4+";"+message.A5+";"+message.typeOfMsg); } while(Serial.available()) { character = Serial.read(); content.concat(character); delay (1); } if (content != "") { if(content !="ack") { a_message message = { getValue(content,';',0).toInt(), getValue(content,';',1).charAt(0),getValue(content,';',2).toInt(),getValue(content,';',3).toInt(),getValue(content,';',4).toInt(),getValue(content,';',5).toInt(),getValue(content,';',6).toInt(), getValue(content,';',7).charAt(0),getValue(content,';',8).toInt()}; if(message.addressTo>5)
{
if(message.addressTo>45)
other_node = message.addressTo % 64;
else
other_node = message.addressTo % 8;
}
else
other_node = message.addressTo;
RF24NetworkHeader header(/*to node*/ other_node);
Serial.print("Sending to node ");
Serial.println(other_node);
bool ok = network.write(header,&message,sizeof(message));
if (ok)
Serial.println("ok");
else
Serial.println("failed");
}
else{
a_message message = { getValue(content,';',0).toInt(),'a',0,0,0,0,0,getValue(content,';',7).charAt(0),getValue(content,';',7).toInt()};
if(message.addressTo>5)
{
if(message.addressTo>45)
other_node = message.addressTo % 64;
else
other_node = message.addressTo % 8;
}
else
other_node = message.addressTo;
RF24NetworkHeader header(/*to node*/ other_node);
Serial.print("Sending to node ");
Serial.println(other_node);
bool ok = network.write(header,&message,sizeof(message));
if (ok)
Serial.println("ok");
else
Serial.println("failed");
}
}
}
להלן קוד המקור של העלים(כאן זה דוגמה לעלה מספר 01 כלומר 1):
/*
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* https://iot.org.il
* Internet Of Things Implement by Arduino Pro and nrf24l01
* using RF24Network
*
* Leaf NODE - Leaf node with hardcoded address.
* By Vardi Michael.
* Adapt from Maniacbug - http://maniacbug.wordpress.com
*/
#include <RF24Network.h>
#include <RF24.h>
#include <SPI>
// nRF24L01(+) radio attached using Getting Started board RF24 radio(9,10); // Network uses that radio RF24Network network(radio); // Address of our node const uint16_t this_node = 021; // Address of the other node const uint16_t base_node =00; uint16_t other_node; boolean is_queue=false; // Structure of message char bits[8]; struct a_message { uint16_t addressTo; char digital1To8; int A1; int A2; int A3; int A4; int A5; char typeOfMsg; uint16_t addressFrom; }; void getBits(char c){ for (int i = 7; i >= 0; --i) { bits[i]=(c & (1 << i)) ? '1' : '0'; } } void setup() { Serial.begin(57600); Serial.print(this_node); Serial.println(" Node Started"); SPI.begin(); radio.begin(); network.begin(/*channel*/ 90, /*node address*/ this_node); } void loop(void) { // Pump the network regularly network.update(); a_message message; // Is there anything ready for us? while ( network.available() ) { // If so, grab it and print it out delay(200); RF24NetworkHeader header; network.peek(header); network.read(header,&message,sizeof(message)); is_queue=true; } network.update(); if(is_queue) { if(message.addressTo==this_node&&message.addressFrom==base_node) { Serial.print("Received packet from "); Serial.print(message.addressFrom); Serial.print(";"); Serial.print(message.digital1To8); Serial.print(";"); Serial.print(message.A1); Serial.print(";"); Serial.print(message.A2); Serial.print(";"); Serial.print(message.A3); Serial.print(";"); Serial.print(message.A4); Serial.print(";"); Serial.print(message.A5); Serial.print(";"); Serial.print(message.typeOfMsg+";"); Serial.println(message.addressTo); } else { if(message.addressTo>45) { int tmpAddress; tmpAddress = message.addressTo / 64; other_node=tmpAddress*64+this_node%64; } else{ int tmpAddress; tmpAddress = message.addressTo / 8; other_node=tmpAddress*8+this_node%8; } RF24NetworkHeader header2(/*to node*/ other_node); a_message nextMsg = message; Serial.print("Sending to node "); Serial.println(other_node); bool ok = network.write(header2,&nextMsg,sizeof(nextMsg)); if (ok) Serial.println("ok"); else Serial.println("failed"); } is_queue=false; } }
לצורך ניסוי ניקח 3 מודולים.
מודול ראשון יהיה מודול הבסיס ונעביר אליו את הסקיצה של קוד הבסיס.
מודול שני יהיה עלה שהוא בן ל 00 עם הכתובת 01.(יש לשנות את הכתובת של המודול בקוד מקור המצורף ל 01 במקום 021).
מודול שלישי הוא בן ל מודול שני 01 הוא יהיה 021 שזה המספר 17.
נפתח 3 מופעים של ה ARDUINO IDE לכל מודול נזהה באיזה פורט הוא מאזין (כמובן שיש לחבר לPRO MINI כבל תקשורת ע"מ שיוכל לתקשר טורית דרך ה USB עם המחשב וזה לא יכוסה פה) ונפתח בכל מופע את הSERIAL MONITOR ונאזין על הפורט הרלוונטי.
נקבל במודול הבסיס את ההודעה הבאה:
Base Node Started
ובמודולי העלה נקבל :
17 Node Started
או
1 Node Started
בהתאמה.
במוניטור הסיריאלי של נקודת הבסיס נזין את השדר הבא:
17;a;2;2;2;2;2;s;00
השדר:
17 – כתובת היעד
a – תו שמורכב משני בייטים כלומר 8 סיביות שיכולות לייצג מצב של 8 יציאות דיגיטליות וכך לבזבז פחות מקום בשדר.
2 – איזשהו קריאה של חיישן לדגמה
s – הודעה שהשדר הוא מסוג קריאת חיישן ולא פקודה כשלהיא ליציאה דיגיטלית
00 – כתובת מקור השדר.
ונראה שבעלה 01 התקבל השדר אך היות וזה לא מיועד אליו אלא הוא משמש כאן רק כ"תיבת ממסר" הוא מעביר את המסר לעלה המתאים שזה 021(17).
היות וטווח השידור והקליטה של nrf24l01 מוגבלים היכולת לשרשר מודולים מאפשרת להרחיב את טווח השידור והקליטה של הרשת ולהתגבר על המגבלה הזאת.