সিরিয়াল কম্যুনিকেশন - সংক্ষিপ্ত সংস্করণ

গত দুই পর্বে আমরা অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং সম্পর্কে হালকা পাতলা ধারণা লাভ করেছিলাম। আজকের বিষয়বস্তু হল সিরিয়াল কম্যুনিকেশন।

যা যা লাগবে:

  • Arduino Board (Uno / Mega 2560)
  • Arduino IDE (-_-)
  • Usb Cable
  • Computer (duh!)

সিরিয়াল কম্যুনিকেশন (Serial Communication):

alt text

সিরিয়াল কম্যুনিকেশন হল এমন একটি ব্যবস্থা যার মাধ্যমে আপনি আপনার প্রিয় বোর্ডের সাথে কথা বলতে পারেন। লিটারেলি কথা? না ঠিক তা নয়, আপনি কিছু ডেটা পাঠাবেন সে সেটাকে প্রসেস করবে তারপর সেও কিছু তথ্য পাঠাবেন সেটা আবার আপনি দেখতে পারবেন কিংবা প্রসেস করতে পারবেন। অনেকটা কথা বলার মতই শুধু ভাষাটা হল 0 আর 1। আর এই কথা বলার জন্য আপনার অবশ্যই আরেকটা ডিভাইস দরকার যার সাথে আর্ডুইনো কানেক্টেড থাকতে পারবে এবং তার পাঠানো ডেটা সে বুঝবে।

সিরিয়াল কম্যুনিকেশন একটা মাধ্যম মাত্র। আরও অনেক ধরণের কম্যুনিকেশন সিস্টেম আছে, আর্ডুইনোতেই; কিন্তু সেগুলো আলোচনা করার সময় এখনো আসে নি। এই কোর্সে যতটুকু দরকার সেটুকুই শুধু “সংক্ষিপ্ত সংস্করণ” – এ থাকবে, যাতে জিনিসটা একঘেয়ে না হয় ও যতটা আলোচনা করা হয় ততটুকুই ভালভাবে শিখতে পারেন।

আমরা যখন আর্ডুইনো বোর্ড কনফিগার করছিলাম তখন দেখেছি সেটা একটা COM Port এ সংযুক্ত থাকে, যেমন COM3, COM14 ইত্যাদি। এই পোর্টকে আমরা দরজাও বলতে পারি। যে দরজা দিয়ে ডেটা যাওয়া আসা করে। আমরা যে কোড আপ্লোড করি, চিন্তা করুন তো, কীভাবে আপ্লোড হয়? হ্যাঁ, সিরিয়াল কম্যুনিকেশনের মাধ্যমে, কম্পাইল্ড .hex ফাইলটা বিভিন্ন প্রসেসের মধ্য দিয়ে চিপে প্রবেশ করে। আর্ডুইনোর ক্ষেত্রে সিরিয়াল কম্যুনিকেশন এ সাহায্য করার জন্য ATmega16u2 কিংবা ATmega8u2 চিপটি কাজ করে। এখানে আরও অনেক জটিল ব্যাপার স্যাপার আছে।

তাহলে বুঝলাম ডেটা পাঠানোর একটা টার্ম হল Serial! কিন্তু ডেটা ট্রান্সফার কীভাবে হচ্ছে?

এই প্রশ্নের উত্তর দিতে গেলে আমাদের আরেকটু জ্ঞানলাভ করতে হবে। Hardware এর ক্ষেত্রে এই ডেটা ট্রান্সফার করার জন্য বেশকয়েকটি প্রোটকল আছে, এই প্রোটকল গুলোর মধ্যে সাধারণত সর্বাধিক ব্যবহৃত প্রোটকলটি হল UART (Universal Asynchronous Receiver Transmitter)। এই পদ্ধতিটা অনেক পুরাতন এবং পুরাতন বা নতুন সব চিপেই ব্যবহারযোগ্য।

UART তে 8-bit ডেটা ট্রান্সফার করা হয়, একটা থাকে লো লেভেল স্টার্ট বিট এবং ৮ টা ডেটা বিটস ও আরেকটি হাই লেভেল স্টপ বিট। সিরিয়াল কম্যুনিকেশন চালু করার জন্য লো লেভেল স্টার্ট বিট ও হাই লেভেল স্টপ বিট ব্যবহার করা হয়।

UART এর আরেকটি সুবিধা, কোন নির্দিষ্ট ভোল্টেজ লেভেলে ডেটা ট্রান্সফার করতে হবে এমন কোন বাধ্যবাধকতা নেই।3.3V কিংবা 5V যে লজিকেই আপনার MCU চলুক না কেন তাতেই হবে। এখানে গুরুত্বপূর্ণ একটি কথা বলার দরকার, আপনি যে ডিভাইসের সাথে যোগাযোগ করতে চাচ্ছেন এই প্রোটকলের মাধ্যমে, দুই ক্ষেত্রে Transmission speed* সমান হতে হবে।

UART এর মাধ্যমে ডেটা পাঠানো হয় যেভাবে:

alt text

ধরা যাক, UART Protocol এর মাধ্যমে আমি “hello” ওয়ার্ড টি Boka নামক MCU তে পাঠাতে চাচ্ছি। তাহলে আমি যখন পাঠাব তখন এর সাথে একটি Start Bit বা ট্যাগ লাগানো হবে যাতে অন্য ডিভাইসটি বুঝতে পারে ডেটা ট্রান্সফার শুরু হতে যাচ্ছে এবং ডেটা রিসিভ করার জন্য তার তৈরি হতে হবে। কথা হল ডেটা পাঠাবো আমি পিসি থেকে, তার কান খোলা রাখলেই তো হয়, তার জন্য তাকে আবার তৈরি হতে হবে কেন?

বাস্তবে আমরা অনেক সময় অনেকের কথা ঠিকমত বুঝি না, মোটমাট এর কারণ হতে পারে পাঁচটি

  • হয় সে তাড়াতাড়ি কথা বলছে
  • অথবা এত ধীরে কথা বলছে যে শোনার আগ্রহ হারিয়ে ফেলি তাই বুঝি না
  • আমি বুঝিনা এমন ভাষায় কথা বলছে
  • তার কথার কোন মানে নেই
  • আরেকজন যখন কথা বলছে তখন আমি শুনছি না কিংবা আমি যখন কথা বলছি সে শুনছে না

UART/USART এর ক্ষেত্রে কম্যুনিকেশনে যে ঝামেলাটা হয় সেটা হল প্রথম দুইটা এবং শেষেরটা। Serial Communication Establishment এর জন্য একজনের বলার গতি ও আরেকজনের শোনার গতি সমান হতে হবে। যদি তা না হয়, তাহলেই PC একটা কথা বললে Boka বুঝবে উল্টাটা। কিংবা PC যখন কথা বলছে তখন Boka যদি কান খাড়া না করে বা vice versa না হলে ডেটা পাঠানো সম্ভব হবে না। এইকারণে PC যখন ডেটা পাঠাচ্ছে তখন Boka কে রিক্যুয়েস্ট করছে তার ঘড়ি (Clock) টা যেন PC এর সাথে মিলিয়ে Synchronized করে নেয়। ধরা যাক Boka MCU তার Clock ঠিকঠাক করে নিল এবং সে “hello” ডেটাটি নেওয়ার জন্য প্রস্তুত। আমরা যেহেতু প্রোগ্রামিংয়ে এক্সপার্ট B| তাই আমরা অনেক আগে থেকেই জানি যে String হল char টাইপের Null Terminated Array মাত্র। তাই String পাস করতে হলে একটা একটা করে ক্যারেক্টার পাঠাতে হবে আগে, তাই না?

এইবার ডেটা ট্রান্সফারের সময় যদি ঘড়ির ব্যাটারি চলে যায় এবং দুইটা ঘড়ি Synchronized না হয় তবে আবারও ডেটা ট্রান্সফারে সমস্যা হবে। পরীক্ষা করে(!) দেখা গেছে PCBoka MCU এর মধ্যে সুষ্ঠু ডেটা ট্রান্সফার করার জন্য তাদের ঘড়িদ্বয় শতকরা ৮০ ভাগ Accurate হতে হবে।

আবারও মূল কথা থেকে সরে আসার জন্য দুঃখিত। >:( যাকগে যেটা বলছিলাম আরকি, Start bit দিল এবং বলল আমি ডেটা পাঠাচ্ছি, এইবার Boka MCU Clock ঠিক করা মাত্র PC পাঠানো শুরু করল। এই ডেটাগুলোই হল সেই কাঙ্ক্ষিত ডেটা যেটা আমরা পাঠাতে চাচ্ছি। এগুলোকে আমরা আঁতলামি করলে বলব LSB (Least Significant Bit)। মাথায় রাখতে হবে প্রতিটা বিট পাঠানোর সময় পুরা এক, মানে যদি একটা বিট পাঠাতে ২ মাইক্রোসেকেন্ড লাগে তাহলে তার পরের বিট পাঠাতেও একই সময় লাগবে। রিসিভার বা Boka MCU একটা নির্দিষ্ট টাইম পরপর চেক করে দেখবে কি বিট আসছে এবং এই সময়টা হবে PC এর বিট পাঠানোর পর্যায়কালের অর্ধেক সময় বা এই উদাহরণে ১ মাইক্রোসেকেন্ড।

এখানে আবার একটা কথা আছে, PC তো আর জানে না Boka MCU কখন চেক করে, PC শুধু জানে কখন তার ট্রান্সমিশন শুরু করতে হবে এবং কতক্ষণ পরপর বিট পাঠাতে হবে।

বিট পাঠাতে পাঠাতে যখন পুরো “hello” টাই PC পাঠিয়ে দিল সে এবার “hello” এর লেজের সাথে একটা Parity Bit পাঠিয়ে দিতে পারে [may but not will]। এই Parity Bit টা কিন্তু Stop Bit না, এটা হল Error checking Bit। এই বিট Receiver [Boka MCU] Error চেকিংয়ের কাজে ব্যবহার করতে পারে। Parity Bit পাঠানোর পরপরই সে একটা Stop Bit পাঠিয়ে দেবে।

এই Parity Bit টা জেনারেট করার দায়িত্ব Transmitter এর কিন্তু Parity Bit টা কি হবে, ব্যবহার করা হবে কি হবে না সেটা নির্ভর করে PCBoka MCU এর সমঝোতার উপর। এখন ধরি সম্পূর্ণ word পাঠানোর পর যথাসময়ে Boka MCU Stop Bit টি পায় নি। তাহলে Boka MCU বোকার মত (নাকি চালাকের মত?) যতটুকু ডেটা পেয়েছে সম্পূর্ণটাই গার্বেজ ভ্যালু হিসেবে ধরবে এবং Framing Error* দেখাবে।

তাই UART Protocol এর জন্য সবকিছু কনফিগার করে নেওয়াই ভাল। কারণ UART অটোমেটিক্যালি সবকিছু সেট করে নিতে পারে না, আর যদি SenderReceiver কে Identically configure না করা হয় তাহলে Start, Stop কিংবা Parity Bit এগুলো হোস্টে পাস হয় না।

আবারও ধরি “hello” ভালভাবেই গেল, কিন্তু আমি এখন “world” পাঠাব, তাহলে কী করব? কিছু করা লাগবে না, কনফিগারেশন ঠিক থাকলে খালি পাঠালেই হবে, PC আবারও একটা Start Bit পাঠিয়ে বলবে আরেকটি ডেটা আসছে রেডি হও এবং Stop Bit পাঠিয়ে বলবে ডেটা পাঠানো শেষ।

তাই যখন ডেটা পাঠানো হয় না তখন Transmission line কে অলস লাইন বলতে আপত্তি নেই। USART প্রায় একই ভাবে কাজ করে কিন্তু এর কাজের ধরণ একটু আলাদা এবং উন্নত। USART নিয়ে আরেকটি পরিচ্ছদে কথা বলা যাবে।

যাই হোক সিরিয়াল কম্যুনেকশন নিয়ে আমরা অগাধ জ্ঞানলাভ করলাম, চলুন দেখি এটাকে এবার অ্যাপ্লাই করতে পারি কিনা।

আর্ডুইনোতে সিরিয়াল কম্যুনিকেশন:

আর্ডুইনোতে সিরিয়াল কম্যুনিকেশন তৈরি করা অনেক সহজ, এর কারণ অনেকগুলো, তার মধ্যে দুইটা কারণ হল সিরিয়াল কম্যুনিকেশনের জন্য ডেডিকেটেড ATmega8u2 বা ATmega16u2 চিপ এবং Arduino.h ফাইলটা। B|

আমরা শুধু দেখব সিরিয়াল কম্যুনিকেশনের মাধ্যমে কীভাবে পিসির সাথে আর্ডুইনো কথা বলতে পারে। তাহলে ঝটপট নিচের কোডটি কপি পেস্ট করে Arduino IDE তে বসিয়ে দিন। আমিও জানি আপনিও জানেন যে কোডটা নিজে লেখার মত সময় আপনার নাই, সময় না থাকলে কি করা; কপি পেস্ট করেন, আপনার ক্ষতি হইলে আমার কি :P

কোডটা আপ্লোড করুন এবং আর্ডুইনো বোর্ড কানেক্টেড রাখুন!

const int led = 13;
char command;

void setup() {
  Serial.begin(9600);
  Serial.println("Ready for command\nEnter A/a to turn on\nEnter other keys to turn off");
  pinMode(led, OUTPUT);
}

void ledOn()
{
  Serial.println("Led On!");
  digitalWrite(led, HIGH);
}

void ledOff()
{
  Serial.println("Led Off!");
  digitalWrite(led, LOW);
}


void loop() {
  if (Serial.available()){
    command = Serial.read();
    if (command == 'a' || command == 'A') ledOn();
    else ledOff();
  }
}

আউটপুট:

alt text

আউটপুট আরকি, নিজেই দেখে নিন।

প্রোগ্রাম Walkthru:

যেগুলোর ব্যাখ্যা দেওয়া নাই মনে হচ্ছে, পূর্বের পোস্টগুলোতে দেওয়া হয়েছে।

Line 5:

Serial.begin(9600);

OOP এর সূত্রমতে পাই, Serial হল একটি অবজেক্ট যার Definition “Arduino.h” হেডার ফাইলটিতে দেওয়া আছে। begin হল Serial এর একটি মেথড। OOP এর সময় বলেছিলাম, কোন অবজেক্টের মেথড ডাকার জন্য objectName.methodName(parameter) এই রুল ফলো করতে হয়। এখানেই ঠিক তাই করা হয়েছে, begin এর কাজ হল Serial communication establish করা।

begin মেথডে আমরা একটি ইন্টিজার ভ্যালু দেখতে পাচ্ছি 9600! এটি হল Baud Rate। মানে কত স্পিডে আর্ডুইনো পিসির সাথে কথা বলবে? UART এর ক্ষেত্রে আমরা জানি স্পিড সমান না হলে ঝামেলা তাই আমরা আর্ডুইনো বোর্ডের স্পিড ঠিক করে দিলাম। আর পিসির স্পিড ঠিক করলাম Serial Monitor এর মাধ্যমে ;)

Line 6:

  Serial.println("Ready for command\nEnter A/a to turn on\nEnter other keys to turn off");

println -> এই ফাংশনের কাজ হল সিরিয়াল মনিটরে কিছু প্রিন্ট করা। অর্থাৎ কিনা printf(“Hello world”) এর আর্ডুইনো Serial comm ভার্সন B|। print কমান্ড ও একই কাজ করবে তবে println ফাংশনটি কিছু প্রিন্ট করার পাশাপাশি একটা Enter বসিয়ে দেবে বা নিউলাইন প্রিন্ট করবে। যাতে আমাদের পড়তে সুবিধা হয়।

অর্থাৎ println("blablabla") হল print("blablabla\n") এর সমতুল্য।

Line 11:

void ledOn()
{
  Serial.println("Led On!");
  digitalWrite(led, HIGH);
}

এই ফাংশনটির কাজ হল সিরিয়ালে সে প্রিন্ট করবে “বাত্তি জ্বালাইসি” ও বাত্তি জ্বালিয়ে দেবে। পরের ফাংশনটি কি করবে সেটা অনুমান করুন (বাড়ির কাজ) :P

Line 24:

  if (Serial.available()){

এই available মেথডের কাজ হল চেক করে দেখা, আর্ডুইনো কি ডেটা গ্রহণে তৈরি কিনা? যদি হয় তাহলে তাকে পাঠাব নইলে নয়। আরও একটি মানে আমরা বের করতে পারি, available() মেথডের রিটার্ন টাইপ boolean বা bool

Line 25:

    command = Serial.read();

অর্থাৎ, সিরিয়ালে যদি আমি কিছু ইনপুট দেই তা আর্ডুইনো পড়ে command নামক ভ্যারিয়েবলে রাখবে। তারমানে read() মেথডের রিটার্ন টাইপ char (আপাতত এটাই জেনে রাখুন)

Line 26 ও Line 27:

    if (command == 'a' || command == 'A') ledOn();
    else ledOff();

যদি সিরিয়ালে যেটা পাইসি সেটা a বা A এর সমান হয় তাহলে বাত্তি জ্বালাও। নইলে বাত্তি নিভাও :D

একনজরে পুরো প্রোগ্রাম:

  • একটা ধ্রুব সংখ্যা ১৩ নিলাম যার নাম led
  • একটা ক্যারেক্টার টাইপ ভ্যারিয়েবল নিলাম যার নাম command
  • Serial communication চালু করলাম 9600 bits per sec স্পিডে
  • led কে আউটপুট বানালাম
  • একটা ফাংশন তৈরি করলাম ledOn নামে যার কাজ বাত্তি জ্বালানো ও আমাকে জানানো বাত্তি জ্বলেছে কিনা
  • আরেকটা ফাংশন তৈরি করলাম ledOff নামে যার কাজ বাত্তি নিভানো ও আমাকে জানানো বাত্তি নিভেছে কিনা
  • ইনফিনিটি লুপে প্রবেশ:
  • যদি সিরিয়াল পাই, তাহলে সিরিয়ালে যা ইনপুট দেয় তা command এ রাখলাম
  • command যদি a বা A এর সমান হয় তাহলে ledOn() ফাংশনরে ডাক দে
  • যদি তা না হয় তাহলে ledOff() ফাংশনরে ডাক দে

সিরিয়াল নিয়ে ব্যাপক জ্ঞান দিলাম, পরবর্তীতে ADC এর সময় কাজে দেবে। তখন আমরা আরও নতুন কিছু দেখব।

নোট:

Baud Rate:

এর মানে কত বিট হারে ডেটা পাস হচ্ছে। Arduino বা সাধারণত ডিভাইসগুলোর Baud Rate হয় 9600 bits per second। আর্ডুইনোর সর্বোচ্চ Baud Rate 115200 bits per second

Framing Error:

যদি PCMCU তে সিঙ্ক্রোনাইজেশন জাতীয় সমস্যা দেখা যায় কিংবা ডেটা সিগনাল Interrupted হয় তখন এই সমস্যাটা দেখায়।

সচরাচর জিজ্ঞাস্য প্রশ্ন [F. A. Q]

Serial Monitor কী জিনিস? কী কাজে লাগে?

ইয়ে Serial দেখার কাজে লাগে B|। সিরিয়াল মনিটর অনেক কাজে লাগে, সিরিয়ালে ডেটা পাঠানো, সিরিয়ালে নামক ওয়ালে ডিভাইসটা কি স্ট্যাটাস দিল তা দেখা যায়। কমান্ড পাঠানো যায়। ইত্যাদি কাজ করার জন্য Serial Monitor লাগে, আর্ডুইনোর বিল্ট-ইন সিরিয়াল মনিটর ছাড়াও অনেক ফ্রি ও ওপেনসোর্স সিরিয়াল মনিটর আছে বহুত ফাংশনসহ। আপাতত আমাদের তেমন ফিচার লাগে নাই বলে আমরা আর্ডুইনোর বিল্ট-ইন সিরিয়াল মনিটর ব্যবহার করছি।

Serial Communication এর উপকারিতা কী?

উপকারিতার কথা বলতে পারব না কিন্তু অপকারিতা নাই সেটা জানি :P। Sensor checking, wireless/wired data transmission, interfacing কিসে লাগে না সেটা বলেন! আস্তে আস্তে উপকারিতা বুঝতে পারবেন আশা রাখি।

টাইটেলটা বুঝলাম না “সিরিয়াল কম্যুনিকেশন (সংক্ষিপ্ত সংস্করণ)” – মানে??

মানে হল এখানে যা আলোচনা করা হয়েছে তা Serial communication এর ধারেকাছেও নাই, এর যে ৪-৫ টা প্রোটকল আছে তার প্রত্যেকটা নিয়ে বিশাল বিশাল বই লেখা সম্ভব। বাকি প্রোটকলগুলো আপাতত লাগছে না বলেই সেগুলো এখান থেকে বাদ দেওয়া হয়েছে। আরেকটা সংস্করণ করে সেখানে বাকি প্রোটকল নিয়ে হালকা আলোচনা করার ইচ্ছা আছে।

আপাতত এই পর্যন্তই, পরের পরিচ্ছদে আমরা ADC শিখব!