১৫. 8051 এর টাইমার পেরিফেরাল দিয়ে delay() ফাংশন
টাইমার যে আসলে কত গুরুত্বপূর্ণ একটি পেরিফেরাল তা বলে বুঝানো যাবেনা। এর আগের পোস্টগুলোতে আমরা টাইমার সম্পর্কে যথেষ্ট জেনেছি কিন্তু তারপরও কিছু খুঁটিনাটি বিষয় এখনও বাকি থেকে গেছে। আজকের পোস্টে আমরা মোটামোটি ভাবে টাইমার সম্পর্কে বাকি বিষয়গুলো জেনে নিব। টাইমার দিয়ে delay() ফাংশন রিলেটেড কিছু করতে গেলে অবশ্যই 8051 মাইক্রোকন্ট্রোলারের সাথে ১২ মেগাহার্টজের ক্রিস্টাল অসসিলেটর সংযোগ করতে হবে। কারন আমরা আগেই জেনেছি। ১২ মেগাহার্টজ ক্রিস্টাল অসসিলেটরের জন্যে 8051 মাইক্রোকন্ট্রোলারের মেশিন সাইকেলের পালস্ হয় ১ মাইক্রোসেকেন্ড। হিসাবের সিমপ্লিসিটি বজায় রাখার জন্যেই এরুপ ক্রিস্টাল সিলেক্ট করা। তাহলে এটুকু বোঝা যাচ্ছে যে মাইক্রোকন্ট্রোলারের এরুপ কনফিগারেশনের জন্যে আমরা টাইমার দিয়ে সর্বনিম্ন ১ মাইক্রোসেকেন্ড এবং সর্বোচ্চ ৬৫.৫৩৫ মিলিসেকেন্ড পর্যন্ত সময় গণনা করতে পারি। সর্বোচ্চ ৬৫.৫৩৫ মিলি সেকেন্ড কেন সেটা আমাদের সবারই মোটামোটি বুঝতে পারার কথা। না বুঝে থাকলে টাইমার রিলেটেড আগের পোস্টগুলো একটু দেখে নিবো। এখন ঘটনা হল এই ৬৫.৫৩৫ মিলিসেকেন্ড গণনার পর কি হবে?? আমাদের যদি এর চেয়ে বেশি সময় গণনার দরকার হয় তখন কি করব? তখন আসলে আমাদের ইন্টারাপ্টের সাহায্য নিতে হবে। এবং ইন্টারাপ্টের সাথে সাথে আরেকটু হিসাব করতে হবে। কথা না বাড়িয়ে সরাসরি হিসাব দেখে নেয়া যাক একটি উদাহরনের মাধ্যমে।
ধরা যাক আমরা একটি লেড বাল্ব ১ সেকেন্ড পর পর অন অফ করতে চাই। তাহলে হিসাবটি হবে-
আমাদের প্রয়োজন = ১ সেকেন্ড = ১,০০০ মিলিসেকেন্ড
যেহেতু 8051 মাইক্রোকন্ট্রোলার সর্বোচ্চ ৬৫.৫৩৫ মিলিসেকেন্ড সময় গণনা করতে পারে সেহেতু,
১,০০০ / ৬৫.৫৩৫ = ১৫.২৫৯০ সংখ্যক বার আমাদের টাইমারের কাউন্ট রিপিট করতে হবে। কিন্তু যেহেতু এটি একটি ভগ্নাংশ সংখ্যা সেহেতু এই সংখ্যকবার তো লুপ ঘুরানো যাবেনা। এর জন্যে আমরা দশমিক পয়েন্টের আগ সংখ্যা পর্যন্ত লুপ ঘুরাবো। অর্থাৎ ১৫ সংখ্যকবার টাইমারকে ওভার-ফ্লো হতে দিব। ১৬ বিটের টাইমার একবার ওভার-ফ্লো হতে সময় লাগে ৬৫.৫৩৫ মিলিসেকেন্ড, তাহলে ১৫ সংখ্যকবার লুপ ঘুরাতে সময় লাগবে মোট = ১৫ * ৬৫.৫৩৫ মিলিসেকেন্ড = ৯৮৩.০২৫ মিলিসেকেন্ড। কিন্তু আমাদের টার্গেট হল ১,০০০ মিলিসেকেন্ড। যেহেতু আমরা দশমিকের পরের সংখ্যা নেগ্লেক্ট করেছি সেহেতু টার্গেট সময়ের চাইতে আমাদের কিছু সময় কম এসেছে।
সময়ের ঘাটতি = ১,০০০ - ৯৮৩.০২৫ = ১৬.৯৭৫ মিলিসেকেন্ড।
এখন এইসময় তো আমরা টাইমার দিয়ে খুব সহজেই গণনা করতে পারি। টাইমার রেজিস্টারের মান হিসাবের জন্যে আমাদের সুত্র হল-
Register_value = Timer Max Value - (Delay / tick)
= ৬৫,৫৩৬ - ((১৬.৯৭৫ * ১০০০) / ১)
= ৬৫,৫৩৬ - ১৬৯৭৫
= ৪৮,৫৬০ হেক্সাডেসিমেলে BDB1
তাহলে ১৫ নম্বর বার ওভার-ফ্লো হওয়ার পরে ১৬ নম্বরের বার আমাদের টাইমার রেজিস্টারের ভ্যালু হবে,
TH0 = 0xBD এবং TL0 = 0xB1
এই সবকিছুই আমাদেরকে ইন্টারাপ্ট-সার্ভিস-রুটিনের মাঝে সেট করে দিতে হবে। মূলত কতবার ওভার-ফ্লো হচ্ছে তা আমরা ইন্টারাপ্ট-সার্ভিস-রুটিনের মধ্যে কোন একটি ভ্যারিয়েবেলের মাধ্যমে কাউন্ট করতে পারি এবং যখনই আমাদের উক্ত নম্বর অর্থাৎ ১৫ পেয়ে যাব তখনই একটি কন্ডিশনের মাধ্যমে টাইমার রেজিস্টারের নতুন ভ্যালু দুটি সেট করে দিব। এভাবেই আমরা টাইমার দিয়ে ১ সেকেন্ডের ডিলে তৈরি করতে পারি। শুধু ১ সেকেন্ডের ডিলেই নয় যেকোন সময়ের ডিলে আমরা এভাবে হিসাব করে তৈরি করে নিতে পারি। বিষয়টি এখনও ক্লিয়ার না হয়ে থাকলে কোড অংশটুকু দেখে নিই। তাহলেই ক্লিয়ার হয়ে যাবে কনসেপ্টটি।
উপরের কোডের সবকিছুই আমাদের বোঝার কথা। আমরা এখানে ১ সেকেন্ডের একটি ডিলে তৈরি করেছি। কিন্তু প্রকৃতপক্ষে এখানেও ১ সেকেন্ডের কিছু কম বেশি আছে। কারন আমরা লজিক গুলো যে সি কোড দিয়ে করেছি সেখানে হয়ত দুই এক মেশিন সাইকেল এদিক অদিক হয়েছে। তারপর ও আমরা অন্ধের মত লুপ না ঘুরিয়ে টাইমার পেরিফেরালস্ দিয়ে এখন থেকে যেকোন delay() টাইপের ফাংশন তৈরি করে নিতে পারব বলে আশা করি। যতটা সম্ভব টাইম রিলেটেড কাজ আমরা মাইক্রোকন্ট্রোলারের টাইমার পেরিফেরালস্কে কাজে লাগিয়েই করার চেষ্টা করব। আর হ্যা আমাদের সার্কিটটি দেখতে নিচের মত হবে।
আপাতত সব কাজই আমরা একই সার্কিট দিয়ে করব। কেননা এসবই শুধু আমরা সিমুলেশন করে চালিয়ে দেখব। প্র্যাক্টিকালি কাজ করতে গেলে আমাদের যা যা করনীয় তখন সেসব শিখে নেয়া যাবে।
code_and_circuit
ধরা যাক আমরা একটি লেড বাল্ব ১ সেকেন্ড পর পর অন অফ করতে চাই। তাহলে হিসাবটি হবে-
আমাদের প্রয়োজন = ১ সেকেন্ড = ১,০০০ মিলিসেকেন্ড
যেহেতু 8051 মাইক্রোকন্ট্রোলার সর্বোচ্চ ৬৫.৫৩৫ মিলিসেকেন্ড সময় গণনা করতে পারে সেহেতু,
১,০০০ / ৬৫.৫৩৫ = ১৫.২৫৯০ সংখ্যক বার আমাদের টাইমারের কাউন্ট রিপিট করতে হবে। কিন্তু যেহেতু এটি একটি ভগ্নাংশ সংখ্যা সেহেতু এই সংখ্যকবার তো লুপ ঘুরানো যাবেনা। এর জন্যে আমরা দশমিক পয়েন্টের আগ সংখ্যা পর্যন্ত লুপ ঘুরাবো। অর্থাৎ ১৫ সংখ্যকবার টাইমারকে ওভার-ফ্লো হতে দিব। ১৬ বিটের টাইমার একবার ওভার-ফ্লো হতে সময় লাগে ৬৫.৫৩৫ মিলিসেকেন্ড, তাহলে ১৫ সংখ্যকবার লুপ ঘুরাতে সময় লাগবে মোট = ১৫ * ৬৫.৫৩৫ মিলিসেকেন্ড = ৯৮৩.০২৫ মিলিসেকেন্ড। কিন্তু আমাদের টার্গেট হল ১,০০০ মিলিসেকেন্ড। যেহেতু আমরা দশমিকের পরের সংখ্যা নেগ্লেক্ট করেছি সেহেতু টার্গেট সময়ের চাইতে আমাদের কিছু সময় কম এসেছে।
সময়ের ঘাটতি = ১,০০০ - ৯৮৩.০২৫ = ১৬.৯৭৫ মিলিসেকেন্ড।
এখন এইসময় তো আমরা টাইমার দিয়ে খুব সহজেই গণনা করতে পারি। টাইমার রেজিস্টারের মান হিসাবের জন্যে আমাদের সুত্র হল-
Register_value = Timer Max Value - (Delay / tick)
= ৬৫,৫৩৬ - ((১৬.৯৭৫ * ১০০০) / ১)
= ৬৫,৫৩৬ - ১৬৯৭৫
= ৪৮,৫৬০ হেক্সাডেসিমেলে BDB1
তাহলে ১৫ নম্বর বার ওভার-ফ্লো হওয়ার পরে ১৬ নম্বরের বার আমাদের টাইমার রেজিস্টারের ভ্যালু হবে,
TH0 = 0xBD এবং TL0 = 0xB1
এই সবকিছুই আমাদেরকে ইন্টারাপ্ট-সার্ভিস-রুটিনের মাঝে সেট করে দিতে হবে। মূলত কতবার ওভার-ফ্লো হচ্ছে তা আমরা ইন্টারাপ্ট-সার্ভিস-রুটিনের মধ্যে কোন একটি ভ্যারিয়েবেলের মাধ্যমে কাউন্ট করতে পারি এবং যখনই আমাদের উক্ত নম্বর অর্থাৎ ১৫ পেয়ে যাব তখনই একটি কন্ডিশনের মাধ্যমে টাইমার রেজিস্টারের নতুন ভ্যালু দুটি সেট করে দিব। এভাবেই আমরা টাইমার দিয়ে ১ সেকেন্ডের ডিলে তৈরি করতে পারি। শুধু ১ সেকেন্ডের ডিলেই নয় যেকোন সময়ের ডিলে আমরা এভাবে হিসাব করে তৈরি করে নিতে পারি। বিষয়টি এখনও ক্লিয়ার না হয়ে থাকলে কোড অংশটুকু দেখে নিই। তাহলেই ক্লিয়ার হয়ে যাবে কনসেপ্টটি।
#include<reg52.h>
sbit led = P2^0; //declare P2.0 pin as output pin
unsigned char i = 0; //global interrupt to count the over-flow number
void init_timer(void); //init_timer() function prototype
void main()
{
P2 = 0xFE; //declare P2.0 bit as ouput b11111110
init_timer(); //just initialize the timer0 at the very beginning
while(1) //infinite loop to run the program continuous
{
//do other work here. because interrupt takes care of toggling led
}
}
/*
FCPU = 12 MHz
Timer0 Frequency = 12 / 12 = 1 MHz
1 tick = 1 / Timer0 Frequency
= 1 / 1 MHz
= 1 uS
our target = 1 second = 1000 ms
1000ms / 65.535ms = 15.2590
15 times overflow needs-
15 * 65.535 = 983.025 ms
lack time = 1000 - 983.025 = 16.975 ms
delay = tick * 1 uS
count = delay / tick
Register Value = Timer Max - count
= Timer Max - (delay / tick)
for 16.975 ms delay
---------------
Register Value = Timer Max - (delay / tick)
= 65,536 - ((16.975 * 1000) / 1)
= 65,536 - 16,975
= 48,560 in hex => 0xBD B1
-- --
TH0 TL0
*/
void init_timer()
{
TMOD = 0x01; //set timer0 in mode1
TH0 = 0x00; //load 0x00 in TH0 and
TL0 = 0x00; //load 0x00 in TL0 to get 65.535ms
ET0 = 1; //enbale Timer0 interrupt in IE register
EA = 1; //enable global interrupt in IE register
TR0 = 1; //run timer0
}
void timer_0() interrupt 1
{
if(i >= 15) //check whether the 15 times overflow has been occured
{
TR0 = 0; //stop the timer first
TH0 = 0xBD; //load 0xBD to THO
TL0 = 0xB1; //and load 0xB1 to TLO to count 16.975 ms
TR0 = 1; //start the timer0 again
while(TF0 == 0); //wait until over-flow
led =! led; //change led state
TF0 = 0; //clear the flag bit
i = 0; //make overflow counter zero again
}
i++; //count the overflow number
}
উপরের কোডের সবকিছুই আমাদের বোঝার কথা। আমরা এখানে ১ সেকেন্ডের একটি ডিলে তৈরি করেছি। কিন্তু প্রকৃতপক্ষে এখানেও ১ সেকেন্ডের কিছু কম বেশি আছে। কারন আমরা লজিক গুলো যে সি কোড দিয়ে করেছি সেখানে হয়ত দুই এক মেশিন সাইকেল এদিক অদিক হয়েছে। তারপর ও আমরা অন্ধের মত লুপ না ঘুরিয়ে টাইমার পেরিফেরালস্ দিয়ে এখন থেকে যেকোন delay() টাইপের ফাংশন তৈরি করে নিতে পারব বলে আশা করি। যতটা সম্ভব টাইম রিলেটেড কাজ আমরা মাইক্রোকন্ট্রোলারের টাইমার পেরিফেরালস্কে কাজে লাগিয়েই করার চেষ্টা করব। আর হ্যা আমাদের সার্কিটটি দেখতে নিচের মত হবে।
code_and_circuit
মন্তব্যসমূহ
একটি মন্তব্য পোস্ট করুন