أردوينو وحفنة من الأسلاك ج2

2013-12-07

سنتابع ما يمكننا القيام به بواسطة لوح أردوينو وحفنة من الأسلاك فقط لاغير. في هذه المقالة سنعمل ما يلي:

  • التعرف على المسجلات الخاصة وتقليب الضوء بواسطتها
  • قراءة حساس الحرارة الداخلي (موجود داخل المتحكم الدقيق)
  • التعرف على المؤقتات واستخدامها لتقليب الضوء دوريا دون دالة التأخير delay
  • تقليب الضوء دون استعمال دالة loop التي ستكون خالية.
  • تقليب الضوء بواسطة كلمة سر عبر serial
  • استخراج البرنامج من المتحكم الدقيق وتفكيكه عبر avrdude (لاستخراج كلمة السر من المتحكم)
  • إضافة مكتبات واستعملها
  • تقليب الضوء بواسطة كلمة سر لا يمكن فكها

مقدمة عن المسجلات

معالج avr يحتوي على عدد من المسجلات عامة الأغراض ذات 8-بت مثل r0 إلى r31 والمسجلات مرتبطة بعناوين خاصة في الذاكرة RAM تبدأ من 0x0 إلى 0x1f. وهناك مسجلات أخرى متعلقة بعمليات الإدخال والإخراج (المداخل والمخارج الرقمية والتناظرية والمؤقتات وغيرها من ملحقات) ولها أسماء خاصة سنأتي على بعضها يمكنك مراجعة الوثائق الرسمية لسردها كاملة Datasheet

المسجلات ذات ال 16-بت تقسم إلى مسجلين كل واحد منهما 8-بت الأقل قيمة تضاف له اللاحقة L والأعلى قيمة تضاف له الاحقة H (أي low و high) ففي النهاية معالج avr هو معالج ذي 8-بت لا يستطيع التعامل مع أكثر من ذلك دفعة واحدة.

المسجلات ذات البت الواحد لا تعيش وحدها وإنما تعيش داخل مسجل ذي 8-بت مثلا المنفذ رقم 13 المرتبط بالضوء LED في لوح أردوينو أونو هو PB5 (أي البت رقم 5 أي البت السادس في مسجل PORTB) أما في ليوناردو هو PC7 (أي البت رقم 7 أي البت الثامن في مسجل PORTC)

يمكنك أن تعرف طريقة توصيل المنافذ في أي لوح أردوينو من خلال مراجعة ملف pins_arduino.h في لينكس تجد هذه الملفات هنا

/usr/share/arduino/hardware/arduino/variants/standard/pins_arduino.h /usr/share/arduino/hardware/arduino/variants/leonardo/pins_arduino.h

للتحكم في حالة بت في مسجل ما نستعمل العمليات الثنائية مثلا لتفعيل البت (تسمى تعيين set) نستعمل عملية or بين المسجل وبين القناع Mask (والذي هو 1 مزاحة إلى مكان البت مثلا البت رقم 5 قناعه هو 32 والبت رقم 7 قناعه 128) ولتقليب حالة البت (تسمى toggle) نستعمل xor بين المسجل والقناع أما لإطفاء/إبطال حالة البت (تسمى إخلاء clear) نحتاج عمليتين إما أن تعمل تعيين ثم تقليب كما ذكرنا سابقا أو تستعمل عملية and مع متممة القناع.

لقراءة حالة بت نستعمل عملية and مع القناع. أردوينو تعرف الدوال المساعدة التالية.

- bitSet(value, bit) - bitClear(value, bit) - bitRead(value, bit) - bitWrite(value, bit, bitvalue)

لتتعلم المزيد عما يوفر لك أردوينو انظر Arduino.h في لينكس تجدها في المسار التالي:

/usr/share/arduino/hardware/arduino/cores/arduino/Arduino.h

لكل منفذ إدخال وإخراج عام الأغراض GPIO يتم التحكم في صفاته عبر بت واحد في 3 مسجلات مثلا PC7 (وهو منفذ 13 المرتبط بضوء LED في ليوناردو) يتم التحكم فيه عبر البت الثامن في كل من المسجلات الثلاثة: PORTC و PINC و DDRC

  • DDRC - أي Port C Data Direction - تحدد هل المنفذ للإدخال 0 أم للإخراج 1
  • PORTC - أي Port C Data Register - تحديد القيمة المطلوب إخراجها من المنفذ لكن في حالة الإدخل تحدد توصيل المقاومة الرافعة
  • PINC - أي Port C Input Register - تحديد القيمة التي يتم قرأتها من المنفذ

فيما يتعلق بالمنفذ PB5 (المنفذ 13 المتربط بضوء LED في أونو) ضع اللاحقة B مكان اللاحقة C في كل مما سبق.

إليك برنامج التقليب في أونو لاحظ طريقة توليد القناع عبر إزاحة الرقم 1 لليسار.

// for Uno void setup() { DDRB|= (1<<PB5) ; // 1<<PB5 means 32 } void loop() { PORTB^= (1<<PB5); delay(500); }

إليك برنامج التقليب في ليوناردو

// for Leonardo void setup() { DDRC|= (1<<PC7) ; // 1<<PC7 means 128 } void loop() { PORTC^= (1<<PC7); delay(500); }

نعم بالتأكيد دوال أردوينو pinMode و digitalWrite و digitalRead أسهل بكثير لكن لا يمكننا الدخول في أعماق المعالج الدقيق دون فهم ما سبق (كما سنفعل لاحقا). كما أن اللعب المسجلات مباشة أسرع من دوال أردوينو بكثير لأن دوال أردوينو تفعل العديد من الأشاء فهي تسترجع ما يربط بين رقم المنفذ والمسجل من ذاكرة الفلاش عبر دالة pgm_read_byte إلى الذاكرة رام (لأن المنظومة تعيش في قسم البرنامج لتوفير الذاكرة رام) ثم تعمل على المسجل.

حساس الحرارة الداخلي

فلتبدأ المتعة الآن. لو كان عندنا حساس حرارة عادي لوصلنا طرف الفحص إلى أحد المداخل التناظرية ثم استخدمنا دالة analogRead كما في هذا المثال.

لكننا سنستعمل حساس حرارة موجود داخل المتحكم الدقيق (يستعمل لضبط سرعة الساعة الداخلية عندما لا نستخدم مذبذب خارجي) يجدر بنا أن نقول أنه لا يقيس حرارة الجو بل يقيس حرارة الدارة لأنه بداخلها (لقياس حرارة الجو تحتاج أن تضع حساس خارجي بعيدا عن الدارة) والذي يمكن استخدامه كمدخل لزيادة العشوائية entropy.

عملية التحويل التناظري إلى رقمي تتم عبر تعيين بت ADEN في مسجل ADCSRA ثم بدء التحويل بتعيين ADSC في نفس المسجل ثم انتظار إشارة انتهاء التحويل وهي انطفاء هذا البت (ADSC).

دارة التحويل التناظري يتم التحكم في مصدر الفولتية المطلوب قياسها عبر مضمم muxer وهو دارة لها مخرج واحد تختاره من بين مداخلها المتعددة وتختلف طريقة تحديد مسجلات المضمم لربط حساس الحرارة إلى دارة التحويل التناظري بحسب طراز الدارة من خلال مسجل ADMUX. مسجل ADMUX

لو نظرنا إلى كتيب المتحكم الدقيق AtMega328 (المستخدم في أونو) في الفصل 23.8 لوجدا أنه يتحدث أنه علينا أن نضع 1000 في المسجلات الأربعة من MUX0 إلى MUX3 بالترتيب مع توصيل فولتية 1.1 المرجعية عبر 11 في مسجلي RESF0 و RESF1 في مسجل ADMUX

طريقة تفعيل حساس الحرارة في AtMega328

في حين لو نظرنا إلى كتيب AtMega32U4 (المستخدم في ليوناردو) في الفصل 24.6 لوجدنا أنه يتحدث عن وضع 100111 في المسجلات الستة من MUX0 إلى MUX5 مع توصيل الفولتية المرجعية 2.56 فولت عبر وضع 11 في مسجلي RESF0 و RESF1 في مسجل ADC. وهنا يجب الانتباه أن MUX5 لا يعيش داخل مسجل ADMUX مثل بقية إخوته وإنما يعيش داخل ADCSRB.

طريقة تفعيل حساس الحرارة في AtMega32U4

يمكننا عمل برنامج واحد لكلا الطرازين من خلال preprocesser كما يلي

#if defined(__AVR_ATmega328__) #elif defined(__AVR_ATmega32U4__) #endif

ليصبح البرنامج النهائي كما يلي:

void setup() { Serial.begin(9600); } void loop() { Serial.print("Temp: "); Serial.println(GetTemp()); delay(1000); } #if defined(__AVR_ATmega328__) float GetTemp() { // for details see: http://playground.arduino.cc/Main/InternalTemperatureSensor int adc_result; ADMUX = 0b11001000; // set the adc to compare the internal temp sensor against ADCSRA |= (1 << ADEN); // enable the ADC delay(20); // wait a moment for the adc to settle ADCSRA |= (1<<ADSC); // Start the ADC // Detect end-of-conversion loop_until_bit_is_clear(ADCSRA,ADSC); // see http://www.nongnu.org/avr-libc/user-manual/group__avr__sfr.html // Reading register ADCW adc_result=ADCW; // convert it to celecious return (adc_result - 324.31 ) / 1.22; } #elif defined(__AVR_ATmega32U4__) float GetTemp() { // for details see: http://forum.sparkfun.com/viewtopic.php?f=32&t=32433 int adc_result; ADMUX = 0b11000111; ADCSRB |= (1 << MUX5); ADCSRA |= (1 << ADEN); delay(20); ADCSRA |= (1<<ADSC); loop_until_bit_is_clear(ADCSRA,ADSC); adc_result=ADCW; return adc_result - 273.0; } #endif

انظر:

ويمكن قراءة الحرارة عبر المرقاب التسلسلي أو في بايثون باستعمال pyserial

$ python >> from serial import Serial >> from glob import glob >> s=Serial(port=glob('/dev/ttyACM*')[0], baudrate=9600) >> print s.readline() Temp: 30.00

تقليب الضوء بالمؤقتات وطلب المقاطعة دون دالة التأخير delay

سنعمل الآن على تقليب ضوء الثنائية LED بشكل دوري باستخدام المؤقتات دون أي تدخل من دالة loop ودون استعمال دالة delay. تعلم هذه المهارة مفيد عندما تريد عمل شيء بشكل دوري مع دقة في توقيت بغض النظر عن السياق مثلا لنفرض أنك تريد قراءة الحرارة الداخلية وإرسالها إلى الحاسوب أو التخاطب مع وحدة bluetooth داخل دالة loop أو استخدام مكتبة من طرف ثالث تحتوي على delay لمدة 5 ثوان كيف ستضمن أن يظل الضوء يتقلب كل نصف ثانية؟ لا يمكنك تخيل ماذا يمكنك أن تفعله بهذه الميزة! يمكنك مثلا أن تستخدم المؤقتات لإصدار نغمات صوتية بتردد معين أو حتى توليد الموجة المناسبة لعمل صورة على شاشة تلفاز كما في Arduino TvOut

علبة طعام ولوح أردوينو

لعبة غزو الفضاء من خلال لوح أردوينو

تحتوي رقاقات AVR على عدد من المؤقتات وتستخدم بعض هذه المؤقتات في دوال أردوينو (بمعنى آخر استخدام هذه المؤقتات يحرمك من تلك الدوال)

  • المؤقت رقم صفر ذو البتات الثمانية ويستخدم في دوال delay و millis و micros
  • المؤقت رقم 1 ذو البتات ال 16 ويستخدم في في مكتبة Servo library
  • المؤقت رقم 2 ذو 8-بت ويستخدم في أونو في دالة tone

المتحكم الدقيق AtMega328 المستخدم في لوح أونو يحتوي على مؤقتي 8-بت (هما timer0 و timer2) ومؤقت واحد 16-بت هو timer1. في حين يحتوي AtMega32U4 المستخدم في ليوناردو يحتوي على مؤقت 8-بت (هو timer0) ومؤقتين إثنين 16-بت (هما timer1 و timer3) ومؤقت ذي 10-بت عالي السرعة (أسرع من ساعة المعالج وتصل سرعته إلى 64 MHz واسمه timer4)

سنستخدم في مثالنا المؤقت timer1 لأنه متوفر في كل من أونو و ليوناردو ولا تعتمد عليه دوال أردوينو (حيث أنني لن أستخدم مكتبة السيرفو)

الكود التالي يقلب الضوء الواصل مع منفذ رقم 13 مرتين في الثانية باستخدام المقاطعة ISR (يعني يضيء لمدة نصف ثانية ثم يطفيء لمدة نصف ثانية).

#define ledPin 13 void setup() { pinMode(ledPin, OUTPUT); // initialize timer1 noInterrupts(); // disable all interrupts TCNT1 = 0; TCCR1A = 0; TCCR1B = 0; TCCR1B |= (1 << WGM12); // CTC mode TCCR1B |= (1 << CS12); // 256 prescaler OCR1A = 31250; // compare match register 16MHz/256/2Hz TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt interrupts(); // enable all interrupts } ISR(TIMER1_COMPA_vect) // timer compare interrupt service routine { digitalWrite(ledPin, !digitalRead(ledPin)); // toggle LED pin } void loop() { }

ملاحظات:

  • دالة loop خالية يمكنك أن تفعل داخلها ما تشاء دون أن تؤثر على تقليب الضوء وزمن ذلك.
  • استخدام ISR لتسجيل دالة تستدعى مرتين كل ثانية (التردد هو 2Hz والزمن الدوري هو نصف ثانية)
  • في كل نصف ثانية تقلب تلك الدالة حالة الضوء
  • يمكن استخدام digitalRead لقراءة القيمة المطلوبة من منفذ مسجل كمخرج.
  • دوال المقاطعة يجب أن تكون مختصرة وسريعة إن احتجت للقيام بعمل يستغرق وقت طويل ضع علامة ما في متغير ما في دالة المقاطعة وفي دالة loop إن كانت العلامة موجودة نفذ الشيء الذي يستغرق الوقت الطويل.

شرح البرنامج السابق: قمنا بتعطيل طلبات المقاطعة ريثما ننتهي من إعداد المسجلات بين دالتي noInterrupts و interrupts (وما هما إلا اسم آخر لدالتي cli و sei على الترتيب). ثم قمنا بتصفير قيمة عداد المؤقت timer1 وهو المسجل TCNT1 ثم قمنا بإخلاء المسجلات التي تتحكم في المؤقت timer1 وهي TCCR1A و TCCR1B (وإن شئت TCCR1C) حتى نقوم لاحقا بتعين البتات التي نريد منها بعملية "أو" في مثالنا لم يلزمنا تعين شيء من مزايا TCCR1A لكننا استعملنا TCCR1B لاختيار خافض السرعة prescaler حيث طلبنا من المؤقت قسمة التردد على 256 (أي تردد الساعة وهو 16 مليون مقسومة على 256). كذلك استعملناه لتعين طور العمل المطلوب WGM واخترنا طور CTC والذي يعني Clear timer on Compare أي يظل يعد حتى يصل العداد للقيمة المحددة في مسجل OCR1A فيصفر العداد ويبدأ من جديد.

يتم اختيار مصدر المؤقت Clock Source عبر بتات CS10 و CS11 و CS12 في مسجل TCCR1B وقيمها

  • إطفاء المؤقت وقيمته 0b000
  • تردد ساعة المعالج وقيمته 0b001
  • خافض التردد بمقدار 8 و 64 و 256 و 1024 وقيمها 0b010 إلى 0b101 على الترتيب (ونحن اخترنا في مثالنا القسمة على 256 أي 0b100)
  • تردد خارجي كلما هبطت فولتية المنفذ T1
  • تردد خارجي كلما صعدت فولتية المنفذ T1

التردد الخارجي المنفصل عن ساعة المعالج مفيد لتوصيل مذبب يصلح لتطبيقات الساعة الحقيقية حيث نصله بكريستالة الكوارتز ذات التردد 32678 هيرتز انظر هذا المثال الرسمي من Atmel

يتم اختيار طور المؤقت من خلال البيتات الخاصة ب WGM (وهي WGM10 و WGM11 و WGM12 في حالة المؤقت timer1) داخل مسجل TCCR1B ومنها:

  • الطور العادي: يظل العداد يزيد حتى يصل إلى القيمة القصوى MAX (وهي 255 في حالة 8-بت و 65535 في حالة عداد 16-بت) ونختاره بوضع WGM لتكون 0b000
  • طور CTC: يقلب هذا العداد عندما يصل إلى القيمة TOP المعينة في OCR1A ونختاره بوضع 0b010 في WGM
  • أطوار PWM المختلفة

نحن نريد الحصول على مقاطعة كل نصف ثانية أي مرتين في الثانية وحيث أن المعالج يعمل بتردد 16 مليون وأن المؤقت في مثالنا يعمل على سرعة المعالج مقسومة على 256 فإن العداد سيعد حتى 62500 في الثانية الواحدة وإن كنا في الطور العادي وانتظرنا العداد ليصل لقيمته القصوى وهي 65535 فإن مقاطعة قلب العداد overflow ستحدث كل 65535.0 مقسوم على 62500 أي 1.04856 أي أكثر من ثانية بقليل.

وحيث أننا نريد مقاطعة مرتين في الثانية سيصل العداد إلى 62500 مقسومة على 2 أي 31250 بعد مرور نصف ثانية وإلى هذا الرقم نريد أن ننتهي ونعود من جديد لذا نضع القيمة 31250 في مسجل OCR1A ونستخدم طور CTC أي أن يقلب العداد عند الوصول لقيمة معينة (يجب أن تكون صحيحة وضمن سعة المؤقت)

أما المسجل TIMSK1 فهو يحتوي على المقاطعات المعينة للمؤقت timer1 ومنها

  • عندما يفيض العداد ويقلب من جديد TOIE1
  • عندما يصل إلى القيمة المطلوبة A (وهو المطلوب في مثالنا)
  • عندما يصل إلى القيمة المطلوبة B
  • عندما يصل إلى القيمة المطلوبة C (في بعض المعالجات)
  • عندما نستلم نبضة دخل

للمزيد من المعلومات انظر مرجع الرقاقة المستخدمة. ويجدر بنا أن نشير أنه يجوز العبث بقيمة العداد أثناء عمل المؤقت.

تقليب الضوء دون مقاطعات

الكود التالي يقلب الضوء الواصل مع منفذ رقم 13 دون أي تدخل من دالة loop ودون أي دالة مقاطعة حتى لكن يلزمنا مد سلك إضافي. يمكن برمجة مسجل التحكم في المؤقت ليقوم بتعين set حالة المنفذ المقابل له أو إخلاؤه clear أو تقليب toggle وهذا الأخير هو الذين نريده. يمكن تقليب حالة المنفذ OC1A (في أونو و ليوناردو هو منفذ رقم 9 انظر pins_arduino.h) عند الوصول للقيمة المعينة في مسجل OCR1A (كذلك منفذ OC1B من خلال OCR1B وهكذا) ولو كان معنا ضوء خارجي نصل طرفه الموجب مع منفذ 9 والسالب مع الأرض GND لكن بما أننا لن نستخدم في هذه المقالة أي مكون خارجي إلا الأسلاك. ببساطة سنجعل منفذ 13 مدخلا ونصله بسلك مع منفذ 9 ليقوده. ارفع البرنامج التالي ولاحظ معنا

#define ledPin 13 void setup() { pinMode(ledPin, INPUT); pinMode(9, OUTPUT); // we want to Toggle OC1A => PB5 => digital 9 digitalWrite(ledPin, 0); digitalWrite(9, 0); // initialize timer1 noInterrupts(); // disable all interrupts TCCR1A = 0; TCCR1A |= (1 << COM1A0); // you can just say TCCR1A = 0b01000000; TCCR1B = 0; TCCR1B |= (1 << WGM12); // CTC mode TCCR1B |= (1 << CS12); // 256 prescaler // TCCR1B = 0b1100; // you can just say intead of the 3 previous lines TCCR1C = 0; TCNT1 = 0; OCR1A = 31250; // compare match register 16MHz/256/2Hz interrupts(); // enable all interrupts } void loop() { }
  • دالة loop خالية
  • لم نستعمل أي دالة مقاطعة ISR
  • طلبنا تقليب المنفذ OC1A من خلال تعين COM1A0 في مسجل TCCR1A

تقليب الضوء بواسطة كلمة سر عبر serial

الآن سنعمل شيء أسهل من كل الأمثلة الماضية. وهي كود يقلب الضوء عند استلام كلمة السر والتي هي في مثالنا aRdu!no@P!n#13 ونقرؤها arduino at pin number 13 مع الانتباه للحروف الكبيرة.

#include<stdlib.h> #define led 13 #define PASS_MAX_LEN 20 // the password is aRdu!no@P!n#13 pronounced "arduino at pin number 13" char *valid_pass="aRdu!no@P!n#13"; char ch, *pass; // large enough to hold 20 chars+ \0 int toggle, len, value, offset, led_status; // the setup routine runs once when you press reset: void setup() { Serial.begin(9600); pass=(char*)malloc(PASS_MAX_LEN+1); toggle=len=value=offset=0; led_status=LOW; pinMode(led, OUTPUT); digitalWrite(led, led_status); Serial.println("Enter Password to toggle led status"); } void loop() { if (toggle) { toggle=0; led_status=!led_status; Serial.println("toggled"); digitalWrite(led, led_status); } if (Serial.available()) fromSerial(); } void fromSerial() { while(Serial.available() && offset<PASS_MAX_LEN) { ch=(char)Serial.read(); // if (ch=='\n' || ch=='\r') break; if you are sending lines pass[offset++]=ch; } len=offset; pass[offset]='\0'; offset=0; Serial.print("You have entered :"); Serial.println(pass); if (strncmp(pass, valid_pass, len)==0) { toggle=1; Serial.println("correct"); } else { Serial.println("wrong"); } }
  • في دالة setup قمنا بحجز مكان يتسع لاستقبال 20 محرف + علامة النهابة \0
  • في دالة loop ننظر هل علينا تقليب الضوء بالنظر هل تم تعين قيمة المتغير toggle وننظر هل استلمنا شيء عبر المنفذ التسلسلي
  • نستدعي الدالة fromSerial لنستهلك ما وصلنا عبر المنفذ التسلسلي
  • دالة fromSerial تستقبل المحارف وتصفها داخل المتغير pass واحدا فواحد ماتوفرت وما كانت تحت ال 20
  • إن طابقت كلمة السر الكلمة المطلوبة نعين المتغير toggle ونكتب correct وإلا نكتب كلمة wrong
  • لاحظ استعمال دوال سي القياسية malloc و strncmp

استخراج البرنامج من المتحكم الدقيق وتفكيكه

نعم هذا البرنامج قد يبدو رائع ويمكنه أن يتحكم في فتح الأبواب أو ما شابه ويمكن استلام كلمة السر تسلسليا عبر وحدة بلوتوث أو غيرها لكن لحظة! فليكن بمعلومك يمكن استخراج البرنامج من المتحكم الدقيق وهناك قصة معروفة وهي أن دارة ELM327 التي توصل بالسيارة وتتواصل من خلال معيار CAN Bus وتحوله إلى إشارة تسلسلية توصل بالحاسب حيث يكمن برنامج تشخيص السيارة. سعر هذه المنتجات التي تستخدم هذه الدارة حوالي 100 دولار. دارة ELM ما هي إلا متحكم دقيق من عائلة PIC قام الصينيون باستخلاص البرنامج من دارة ELM يبدو أنها لم تكن محمية (في أول إصداراتها) وأصبح هناك منتجات لتشخيص السيارة بحوالي 10 دولار.

تحتوي المتحكمات الدقيقة ميزة أنه يمكن قراءة البرنامج الموجود فيها وتحتوي ميزة الحماية (تفعّل بتعين قيمة في ذاكرة خاصة تسمى fuse) وتعني الحماية أن تعليمات القراءة تعيد دائما أصفار وإزالة الحماية تزيل البرنامج معها. تزعم المتحكمات الدقيقة من Macrochip (عائلة PIC) ومن Atmel (عائلة AVR) أنه لا يمكن استخلاص البرامج المحمية منها (على الأقل بالطرق العادية في ظروف التشغيل العادية)

سنتعلم كيف نستخلص البرنامج من لوح أردوينو غير محمي دون أي أدوات خاصة. يتم رفع البرنامج إلى لوح أردوينو عبر برنامج اسمه avrdude ويمكن أيضا استخلاصه منه بنفس الطريقة. برنامج avrdude يدعم عدة مبرمجات يمكن استعراضها من خلال الأمر

avrdude -c ?

يحتوي ملف boards.txt أسماء المبرمجات الخاصة بكل لوح أردوينو مثلا لوح أونو يحاكي المبرمج stk500v1 أما ليوناردو فيحاكي avr109. لقد قمت باستخراج البرنامج من لوح ليوناردو بالأمرين

avrdude -v -p m32u4 -P /dev/ttyACM* -c avr109 -U flash:r:test.hex:i avrdude -v -p m32u4 -P /dev/ttyACM* -c avr109 -U flash:r:test.bin:r

الأول يستخرجه بهيئة hex ورمزها i والثاني يستخرجه بصورته الخامة (رمزها r أي raw)

المعاملات هي - v وتعني verbose أي تعطينا المعلومات أثناء العمل - p تليها طراز الدارة في حالتي هي AtMega32U4 ورمزها m32u4 - P يليها منفذ التواصل وهو في حالتنا ttyACM متبوع برقم لذا وضعت* في ويندوز قد يكون COM ثم رقم - U تليها نوع الذاكرة وهي flash ثم العملية r أو w ثم اسم الملف ثم هيأته

قبل أن تجرب الأمرين السابقيين اعلم أن لو أردوينو لا يحاكي المبرمج إلا في الثواني الأولى من تشغيله ثم يبدأ بتنفيذ البرنامج. الطريقة الصحيحة هي أن تكتب أمر الاستخراج ولا تضغط ENTER ثم تضغظ زر إعادة التشغيل reset ثم تنتظر حوالي ثانية ثم تضغط ENTER لينفذ أمر الاستخراج. التوقيت مهم حيث يجب أن لا تستعجل وتبدأ الاستخراج قبل أن يتعرف نظام التشغيل على لوح أردوينو ويجب أن لا تتأخر عندما يمل لوح أردوينو الانتظار وينتقل إلى تنفذ برنامج المستخدم.

إذا كان عندك لو أونو فلربما المبرمج stk500v1 المدمج به مختزل ولا يحتوي دالة القراءة قد تحتاج لوح أونو آخر وتصله انظر Arduino As ISP

اكتب الأمر التالي وستجد كلمة السر بين حفنة من أسطر المخرجات

strings test.bin

لتفكيك الكود إلى تعاليم لغة التجميع اكتب أي من الأمرين

avr-objdump -m avr --target=binary -C -D test.bin > test1.asm avr-objdump -m avr --target=ihex -C -D test.hex > test2.asm

تثبيت المكتبات

سنتعلم كيف نعمل برنامج يقلب الضوء عند استقبال كلمة السر دون أن يمكن استخراج كلمة السر حتى لو استخرج البرنامج وذلك باستخدام دالة تشفير باتجاه واحد one way hash وهي دالة md5sum وهي ليست ضمن دوال سي القياسية لذا سنتعلم أولا كيف نثبت دوال خارجية.

من خلال البحث في غوغل عن دالة md5sum بسيطة مناسبة لأردوينو وجدت ArduinoMD5

قم بتنزيلها ثم انقل مجلد الدالة إلى مجلد libraries الموجود داخل sketchbook الذي يحتوي مشاريع أردوينو لمزيد من المعلومات انظر وثائق أردوينو

تقليب الضوء بواسطة كلمة سر لا يمكن فكها

الآن لنعود لمشروعنا فلنحسب أولا القيمة الصحيحة لكلمة السر المطلوبة. استخدم لغتك المفضلة لعمل ذلك. أنا أستخدم بايثون. افتح مفسر بايثون التفاعلي واكتب فيه

from hashlib import md5 print repr(md5("aRdu!no@P!n#13").digest())

دالة md5 تحول أي نص إلى 128-بت أي 16-بايت وغالبا ما يتم تبادلها على شكل ما يسمى hexdigest لكني بالأمر السابق طبعت ال 16-بت بصورتها الخامة وهي

\xa9\x8f!\x87\x05\x99%\xf8\xec`\xa5\x9d`\x99z\xa0

الآن اكتب البرنامج التالي ولاحظ أنه لا يحتوي على كلمة السر.

#include <MD5.h> #include<stdlib.h> #define led 13 #define PASS_MAX_LEN 20 #define MD5_LEN 16 unsigned char *valid_md5=(unsigned char*)"\xa9\x8f!\x87\x05\x99%\xf8\xec`\xa5\x9d`\x99z\xa0"; unsigned char *passed_md5; char ch, *pass; int toggle, len, value, offset, led_status; void setup() { Serial.begin(9600); passed_md5=(unsigned char*)malloc(MD5_LEN); pass=(char*)malloc(PASS_MAX_LEN+1); toggle=len=value=offset=0; led_status=LOW; pinMode(led, OUTPUT); digitalWrite(led, led_status); Serial.println("Enter Password to toggle led status"); } void loop() { if (toggle) { toggle=0; led_status=!led_status; Serial.println("toggled"); digitalWrite(led, led_status); } if (Serial.available()) fromSerial(); } void hash_into(unsigned char* digest, char *arg, int len) { MD5_CTX context; MD5::MD5Init(&context); MD5::MD5Update(&context, arg, len); MD5::MD5Final(digest, &context); } void fromSerial() { while(Serial.available() && offset<PASS_MAX_LEN) { ch=(char)Serial.read(); // if (ch=='\n' || ch=='\r') break; if you are sending lines pass[offset++]=ch; } len=offset; pass[offset]='\0'; offset=0; Serial.print("You have entered :"); Serial.println(pass); hash_into(passed_md5, pass, len); if (memcmp(passed_md5, valid_md5, MD5_LEN)==0) { toggle=1; Serial.println("correct"); } else { Serial.println("wrong"); } }
5


بلال العفوري
بلال العفوريمنذ 3 سنوات

ابحث عن تعلم مثل هذه المعلومات منذ مدة , شكرا مؤيد , وحبذا لو كانت على شكل ورشة او دورة تدريبية

2

feedel
feedelمنذ 3 سنوات

عندي اوردوينو ميكا ماذا اكتب لكي اسحب اي برنامج منها وشكرا

0

Test User