مقدمه
بعضیاوقات نیاز است که برای برخیاز پروژهها یک ردیاب درست کنید، حالا این ردیاب ممکناست که برای خودروهای شخصی یا ردیابی اشخاص و یا برای کارهای دیگری که مدنظر است بهکار رود. حال مسئلهای که وجود دارد این است که چطور باید این کار را انجامداد؟ دقتکنید نکتهای که در ساخت ردیابها بسیار حائز اهمیت است، اندازه برد و توان مصرفی است، که این پارامترها کاملا بستگی به نوع پروژه دارد. فرضکنید برای یک خودرو شخصی ردیاب درست میکنید، مسلما در این نوع پروژهها شما با محدودیت فضا مواجه هستید که باید حتما آنرا درنظربگیرید. در این مقاله میخواهیم اطلاعات GPS ماژول SIM808 را توسط آردوینو دریافت و سپس در قالب یک پیام بههمراه نقشه گوگل(GoogleMap) به مخاطب ارسالکنیم. برای انجام این پروژه بهموارد زیر نیاز است: ماژول سیم SIM808 آنتن GPS و GSM
آردوینو UNO
خب همانطورکه میدانید یک پروژه الکترونیکی از دو بخش کدنویسی و طراحی سختافزار تشکیلشدهاست، البته هرکدام از این دو بخش برای خود یک دنیای کاملا مجزایی است که حرفهایشدن در هریک از اینها مستلزم تلاش بیوقفه است. در این آموزش تمرکز ما صرفا روی بخش اول، یعنی کدنویسی است.
کدنویسی ماژول SIM808
توصیهای که میکنیم قبلاز خواندن این بخش، مقاله راهاندازی GSM Modem با آردوینو(MC60) را مطالعهکنید.
در این بخش به موارد زیر میپردازیم.
- راهاندازی GPS
- ارسال پیام
- دریافت پیام
- تنظیمات فعالسازی
- اعلام موجودی
- شناسایی اپراتور
- تغییر زبان سیمکارت به انگلیسی
- دریافت شماره تلفن
- معرفی تابع فیلتر پیام
- حذف پیامهای دریافتی جهت مدیریت حافظه
- ارسال پیام بههمراه مختصات GoogleMap
- معرفی تابع فیلتر برای بدستآوردن مقادیر GPS
- معرفی تابع ارسال پیام بههمراهداشتن TimeOut و Debug
نکته: تمامی قابلیتها با کمی خلاقیت قابل تعمیم برای تمام میکروکنترلرهای دیگر هم میباشد
راه اندازی GPS با SIM808
برای راهاندازی این قسمت نیاز است که یک دیدکلی نسبت به دیتاشیت این ماژول داشتهباشیم تا بتوانیم کار موردنظر خود را انجامدهیم.
دقتکنید که دستورات GPS این ماژول کمی دچار تغییر شدهاند و این اشتباه را نکنید که دستورات را طبق دیتاشیتهای قدیمی این ماژول وارد کنید چون به احتمال زیاد دچارخطا خواهید شد. البته این روند برای ورژنهای جدید ماژولهای این شرکت صادق میباشد.
بهطورمثال اگر دستور روشنکردن GPS را بهصورت AT+CGPSPWR=1 وارد کنید ماژول EEROR را نمایشخواهد داد حال برای رفع این موضوع فقط کافیست که دستور را بهصورت AT+CGNSPWR=1 وارد کنید و بهطورکلی میتوان گفت که بهجای GPS واژه GNS قرار دهید. دلیل اینکار هم این است که در سریهای قبلی این ماژولها از سیستم GPS پشتیبانی میشد اما چندسالی است که ورژنهای جدید این ماژولها از سیستم GNSS پشتیبانی میکنند و همین امر سبب تغییر برخیاز دستورات ماژول شده است.
خب برای راهاندازی GPS ماژول SIM808 به دستورات زیر نیاز داریم.
- AT+CGNSPWR=1 روشنکردن GPS
- AT+CGNSPWR=0 خاموشکردن GPS
- AT+CGNSINF ارسال اطلاعات
sendData("AT+CGNSPWR=1",1000,DEBUG); for(int i;i<2;i++){ sendTabData("AT+CGNSINF",1000,DEBUG); delay(300); if (state !=0) { Serial.println("State :"+state); Serial.println("Time :"+timegps); Serial.println("Latitude :"+latitude); Serial.println("Longitude :"+longitude); } }
این تابع جهت دیباگ GPS بهکار میرود بهصورتیکه اطلاعاتی از قبیل طول و عرض جغرافیایی را روی سریال مانیتور نمایش میدهد و از این طریق بهراحتی میتوانید تشخیصدهید که پارامترهای GPS را دریافت کردهاید.
ارسال پیام در SIM808
int Send_Message(String phone , String text){ mySerial.print("AT+CMGF=1"); delay(1000); mySerial.print("AT+CMGS="); mySerial.print("\"") ; mySerial.print(phone); mySerial.print("\"") ; mySerial.print("\r\n"); delay(100); mySerial.print(text); delay(100); mySerial.print(char(26)); delay(100); return 1; }
این تابع همانطورکه از اسمش هم مشخصاست صرفا برای ارسال پیام نوشتهشدهاست که عملکرد آن بهصورتزیر است.
Send_Message("0938866****" , "This is GPS Location")
فعال سازی SIM808
void GSM_Initilaize() { boolean gsm_Init = 1; while (gsm_Init > 0) { mySerial.println("AT"); while (mySerial.available()) { if (mySerial.find("OK") > 0) gsm_Init = 0; } delay(100); } boolean Ready = 1; while (Ready > 0) { mySerial.println("AT+CPIN?"); while (mySerial.available()) { if (mySerial.find("+CPIN: READY") > 0) Ready = 0; } delay(1000); } mySerial.write("AT+CMGF=1\r\n"); delay(1000); }
این تابع جهت آمادهسازی GSM نوشتهشدهاست و طبق دستوراتی که ارسال میشود، اگر ماژول پیامی تحتعنوان CPIN READY دریافتکرد، به اینمعنی است که ماژول آمادهبهکار است.
دریافت پیام در SIM808
String receive message(){ if(mySerial.find("CNMI")>=0){ mySerial.println("AT+CMGR=1") ; delay(10); mySerial.setTimeout(2000) ; String input = mySerial.readString(); delay(500); String number ="0"; String firstword = "\",\""; String lastword = "\",\"\",\""; int n1 = input.indexOf(firstword) + firstword.length() ; int n2 = input.lastIndexOf(lastword); if(n1>-1 and n2>-1){ number = input.substring(n1 , n2); } if(number=="0"){ return "0"; }else{ mySerial.println("AT+CMGD=1,4") ; return input; } } }
این تابع صرفا برای تشخیص پیامهای ورودی است که به سیمکارت ارسال میشود و درصورتیکه پیام دریافتی در کد تعریفشدهباشد وارد شرط مربوطه شده و کار مربوطبه خود را انجام میدهد، در غیر اینصورت پیام خوانده نخواهد شد و درنهایت حذف میشود.
تشخیص اپراتور در SIM808
String Operator(){ delay(50); mySerial.println("AT+COPS?"); mySerial.setTimeout(100) ; String input = mySerial.readString(); mySerial.setTimeout(10) ; input = word_filter(input,"\"","\""); input.trim(); delay(10); if(input=="43235"){ return "Irancell"; }else{ return "Not Recognized"; } }
این تابع صرفا اپراتور ایرانسل را شناسایی میکند و درصورتیکه از سیمکارت ایرانسل استفادهشود بهراحتی توسط این تابع شناسایی میشود و درنهایت بهصورت خودکار توسط توابع دیگر موجودی را به کاربر اعلام میکند البته این تابع بهسادگی قابل تعمیم برای سیمکارتهای دیگر هم میباشد. که با کمی خلاقیت قادربه این کار خواهید بود.
دریافت اعلام موجودی در SIM808
String Balance(String Operator){ if(Operator=="Irancell"){ mySerial.println("AT+CUSD=1,\"*141*1#\""); mySerial.setTimeout(6000); String Balance_Read = mySerial.readString(); delay(100); mySerial.println(input ); String firsword = "Credit"; String lastword = "WOW"; int Word1 = Balance_Read.indexOf(firsword) + firsword.length() ; int Word2 = Balance_Read.lastIndexOf(lastword); if(Word1 ==-1 or Word2==-1){ return "0" ; }else{ Balance_Read = Balance_Read.substring(Word1 , Word2); } delay(100); Balance_Read.replace("Rial", ""); Balance_Read.replace(".", ""); Balance_Read.replace("IRR", ""); Balance_Read.trim(); return Balance_Read; } }
این تابع موجودی سیمکارت را برمیگرداند، که عملکرد آن همانطوری که مشخصشدهاست یک کد USSD برای اپرتور ارسال میکند درصورتیکه زبان اپراتور به زبان انگلیسی تعییر کرده باشد بهراحتی موجودی سیمکارت را برای مخاطب موردنظر ارسال میکند.
تغییر زبان اپراتور به زبانانگلیسی در SIM808
void Operator_Setting(String Operator) { String oprator = service(); if(oprator == "Irancell"){ mySerial.println("AT+CUSD=1,\"*555*4*3*2#\""); } delay(3000); mySerial.println("AT+CUSD=2"); }
این تابع زبان اپراتور را به زبانانگلیسی جهت دریافت موجودی سیم کارت تغییر میدهد، تا در قسمت تابع دریافت موجودی مشکلی پیش نیاید.
دریافت شمارهتلفن در SIM808
String Get_PhoneNumber(String Number){ String word1 = "+98"; String word2 = "\",\"\",\""; int Word1 = Number.indexOf(word1) + word1.length() ; int Word2 = Number.lastIndexOf(word2); if(Word1 ==-1 or Word2==-1){ return "0" ; }else{ Number = "0" + Number.substring(Word1 , Word2 ); } return Number; }
این تابع کار دریافت شماره تلفنهای ورودی را برعهده دارد به طوریکه هر شمارهای که بخواهد پیام دهد، ابتدا توسط این تابع شماره ورودی دریافت میشود.
ارسال پیام توسط نقشه GoogleMap
برای این کار نیاز داریم که لینک گوگل را پیدا کنیم که دقیقا با چه فرمتی نوشتهشدهاست و دقیقا همان فرمت را پیادهسازی کنیم.
https://www.google.com/maps/@52.2129919,5.2793703,7z
اگر به خط بالا دقت کنید میبینید که دارای مقادیر مختلفی است حالا این اعداد چه چیزی را بیان میکنند؟ این اعداد دقیقا همان طول و عرض جغرافیایی هستند، کاری هم که ما باید انجامدهیم دقیقا بدستآوردن همین مقادیر است و درنهایت جایگزینکردن مقادیر بدست آمده در مختصات GoogleMap.
نکته: حتی اگر یک نقطه اضافی در مختصات قرار بگیرید گوگل آن مختصات را شناسایی نخواهد کرد پس باید فیلترکردن مقادیر بهدرستی صورتبگیرد اگر به هردلیلی پساز اجرای پروژه موقعیت مکانی که ارسال شد گوگل مپ آن را شناسایی نکرد، به احتمالزیاد مشکل از فرمت اطلاعات ارسالشده است.
فرمت صحیح بهصورت خط زیر میباشد:
http://maps.google.com/maps?q=loc:xxxx,xxxxx
تابع GPS
void sendTabData(String command , const int timeout , boolean debug){ mySerial.println(command); long int time = millis(); int i = 0; while((time+timeout) > millis()){ while(mySerial.available()){ char c = mySerial.read(); if (c != ',') { data[i] +=c; delay(100); } else { i++; } } } if (debug) { state = data[1]; timegps = data[2]; latitude = data[3]; longitude =data[4]; } }
کاری که این تابع انجام میدهد فیلترکردن مقادیر دریافتی از GPS است و همانطوریکه توضیحدادیم، در این پروژه نیاز به دریافت طول و عرض جغرافیایی داریم البته مقادیر دیگری را هم اگر نیاز داشتید بهراحتی میتوانید آنرا دریافت کنید و در پروژههای خود استفادهکنید.
تابع ارسال پیام بههمراه داشتن TimeOut و Debug
String sendData (String command , const int timeout ,boolean debug){ String response = ""; mySerial.println(command); long int time = millis(); int i = 0; while ( (time+timeout ) > millis()){ while (mySerial.available()){ char c = mySerial.read(); response +=c; } } if (debug) { Serial.print(response); } return response; }
یکیاز مهمترین توابعی که میتوان گفت از اهمیت بسیاربالایی برخوردار است، همین تابع است. از این جهت مهم است که طبق یک زمانبندی خاص، دیتا را ارسال میکند و تا زمان تعیینشده منتظر جواب میماند درصورتیکه جواب دریافت نشد منتظر نخواهد ماند و ادامه کد را انجامخواهد داد. البته دقتکنید مدل حرفهای تر آن توسط تایمر پیادهسازی میشود و بهراحتی قابلتعمیم برای تمام میکروکنترلرهای دیگر است.
نحوه اتصال برد آردوینو به SIM808
خب حالا وقت تلفیق کدها با یکدیگر رسیده است که تمامی آپشنها را در قالب یک کد پیادهسازی کنیم. نکتهای که حائز اهمیت است، این مقاله صرفا آموزشی است و به روشهای بسیارساده کدنویسی شدهاست تا خوانایی کد برای تمامی خوانندگان واضح باشد.
#include <SoftwareSerial.h> #define DEBUG true SoftwareSerial mySerial(10,11 );// RX, TX String data[5]; String state,timegps,latitude,longitude; String Phone= costumer; String Operator,Balance; String Phone = "xxxxxxxx"; // like a 0938*****75 void setup() { Serial.begin(9600); mySerial.begin(9600); mySerial.println("AT&F"); delay(100); mySerial.println("AT+CMGF=1"); mySerial.setTimeout(100); sendData("AT+CGNSPWR=1",1000,DEBUG); delay(50); while(1){ Operator= Ooperator(); if(Operator=="nothing"){ Serial.println(Operator); }// end if operator else{ Serial.println(Operator); Operator_Setting(Operator); GSM_Initilaize(); Balance=balance(Ooperator()); // Send_Message(Phone, Balance); Send_Message(Phone, "Welcome to SIM808"); Serial.println(Balance); return; } }// end while } // end of Main void loop() { String Read_Message = receive_message(); if(Read_Message != "0"){ String phones = Get_PhoneNumber(Read_Message); delay(100); sendTabData("AT+CGNSINF",1000,DEBUG); delay(300); if (state !=0) { Serial.println("State :"+state); Serial.println("Time :"+timegps); Serial.println("Latitude :"+latitude); Serial.println("Longitude :"+longitude); } delay(1000); //send_sms(Phone , "http://maps.google.com/maps?q=loc:"+latitude+","+longitude); Serial.println("http://maps.google.com/maps?q=loc:"+latitude+","+longitude); } }
طبق کد بالا هر ۱ ثانیه یک بار مختصات به روز میشوند. و درنهایت اگر همهچیز بهدرستی صورتگرفتهباشد باید به جواب شکلزیر برسید.
State :1 Time :20190714064955.000 Latitude :32.659565 Longitude :51.65073 http://maps.google.com/maps?q=loc:32.659565,51.65073 State :1 Time :20190714064955.000 Latitude :32.659565 Longitude :51.65073 http://maps.google.com/maps?q=loc:32.659565,51.65073 State :1 Time :20190714064955.000 Latitude :32.659565 Longitude :51.65073 http://maps.google.com/maps?q=loc:32.659565,51.65073 State :1 Time :20190714064955.000 Latitude :32.659565 Longitude :51.65073 http://maps.google.com/maps?q=loc:32.659565,51.65073 State :1 Time :20190714064955.000 Latitude :32.659565 Longitude :51.65073 http://maps.google.com/maps?q=loc:32.659565,51.65073 State :1 Time :20190714064955.000 Latitude :32.659565 Longitude :51.65073 http://maps.google.com/maps?q=loc:32.659565,51.65073
امیدواریم که این آموزش هم برای شما مفید واقع شده باشد. با ما همراه باشید.
منبع: سیسوگ