روش خلاقانه برای افزایش پورت میکروکنترلر تنها با یک بیت
ممکن است برای شما هم پیشآمده باشد که به دلیل محدودیت پایههای میکروکنترلر مجبور شده باشید که میکروکنترلر را عوض کنید و از میکروکنترلری با تعداد پایههای بیشتر استفاده کنید. برای افزایش تعداد پورتهای میکروکنترلر، راههای زیادی وجود دارد؛ یکی از این راهها استفاده از لچ(latch) است. اما لچها هم خارج از اشکال نیستند. مشکل اساسی آنها پیچیدگی سیمکشیشان است.
همانطور که در تصویر فوق مشاهده میکنید، برای گسترش پورتهای میکرو به 64 بیت، شما نیازمند 12 پایه بر روی میکروکنترلر خواهید بود. در کنار این نقص، این روش، پرسرعتترین روش ممکن برای گسترش پورتهای میکروکنترلر است. با توجه به پیچیدگی زیاد در سیمکشی، و همچنین تعداد پایههای زیاد برای راهاندازی، بیشتر طراحها ترجیح میدهند از روش جایگزین دیگری استفاده کنند و آن، استفاده از شیفت رجیستر است. در واقع شیفت رجیستر مجموعهای از فلیپفلاپها است که در آن خروجی هر فلیپفلاپ به ورودی فلیپفلاپ بعدی در یک زنجیره متصل است. نتیجه اینکه در یک مدار که موقعیت جابهجا میشود، آرایهای از بیتها در آن ذخیره شده، در هر پالس ساعت، یک بیت که در ورودی حاضر است به داخل رفته و آخرین بیت از آن خارج میشود. به صورت خلاصه میتوان گفت که یک شیفت رجیستر دادههای ارسالشده بهصورت سریال را به شکل موازی در خروجی ظاهر میکند.
آیسی 74Hc595
آیسی محبوب 74Hc595 یکی از آیسی های پراستفاده برای افزایش پورتهای میکروکنترلر است. این آیسی درواقع یک شیفت رجیستر به همراه یک لچ است. با استفاده از آیسی 74Hc595 بهراحتی و با کمترین سیمکشی ممکن، شما خواهید توانست پورتهای میکروکنترلر خود را افزایش دهید.
همانطور که در عکس فوق مشاهده میکنید برای گسترش پورت از طریق 74Hc595 شما فقط نیاز به 3 پایه از میکروکنترلر دارید، یک پایه جهت کلاک، یک پایه جهت دیتا و پایه آخر هم برای لود کردن داده ارسالشده در خروجی. مطابق نمودار زیر:
با استفاده از این روش می توان هر تعداد پورت جدید که لازم باشد به سیستم اضافه کرد و تنها 3 پایه از میکرو، مورد نیاز است.
افزایش پورت تنها با یک پایه!
حال فرض کنید بعد از طراحی، تنها یک پایه از میکروکنترلر آزاد مانده و قصد دارید یک LCD یا Seven Segment به مدار خود اضافه کنید. ظاهراً تنها راه موجود تعویض میکروکنترلر است! اما آیا واقعاً راهی است که با استفاده از یک پایه، یک LCD را راهاندازی کنیم؟
در جواب باید بگویم: بله، همیشه راهی هست! این بار راهحل پیچیده نیست و خیلی ساده خواهد بود، برای این کار ما از همان آیسی 74HC595 کمک خواهیم گرفت؛ ولی به شیوهای که بتوانیم با استفاده از یک خط داده، سه سیگنال کنترلی را ایجاد نماییم.
اصول کار خیلی ساده است: ما با قرار دادن یک RC در مسیر داده، سعی میکنیم که سیگنال DAT نسبت به CLK دارای یک شیفت زمانی باشد. همانگونه که در تصویر فوق مشاده میکنید برای اعمال صفر بر روی سیگنال DAT باید با توجه به مقادیر RC استفادهشده، سیگنال ورودی مدتزمان مناسبی صفر باقی بماند. در غیر این صورت مقدار یک ثبت خواهد شد. ولی هنوز یک مشکل دیگر وجود دارد: تولید سیگنال Latch. برای ظاهر شدن دادههای شیفت دادهشده در خروجی، باید پایه Latch نیز تحریک شود، برای این منظور نیز از همین تکنیک استفاده میکنیم؛ با این تفاوت که RC استفادهشده باید زمان متفاوتی نسبت به DAT داشته باشد.
برای جلوگیری از رخ دادن خطا، سعی میکنیم که زمانهای RC تا جای ممکن از هم فاصله داشته باشند. به همین منظور، مقاومت Latch را بیست برابر مقاومت DAT انتخاب میکنیم و مقدار خازنها را برابر در نظر میگیریم.
محاسبه مقادیر RC
آیسی 74HC595 قادر است تا فرکانس 20 مگاهرتز کلاک را تحمل کند. اما محدودیت ما به لحاظ وجود فیلتر پایین گذر (RC) موجود در مدار است. بنابراین سعی میکنیم که مقادیر انتخابشده به نحوی باشند که مدار برای طیف وسیعی از میکروکنترلرها قابلاستفاده باشد. مقدار خازن را ثابت و مساوی 2.2 نانوفارد، ورودی DAT مقاومت را مساوی 1.5 کیلو و ورودی Latch را بافاصله 20 برابر و مقدار 33 کیلواهم در نظر میگیریم.
سورس کد
#define Shift_DDR DDRD #define Shift_PORT PORTD #define Shift_Pin (1<<2) void Shift_Init(void) { Shift_DDR |= Shift_Pin; Shift_PORT |= Shift_Pin; } void Shift_WriteZero(void) { Shift_PORT &= ~Shift_Pin; _delay_us(15); Shift_PORT |= Shift_Pin; _delay_us(30); } void Shift_WriteOne(void) { Shift_PORT &= ~Shift_Pin; _delay_us(1); Shift_PORT |= Shift_Pin; _delay_us(15); } void Shift_Load(void) { Shift_PORT &= ~Shift_Pin; _delay_us(200); Shift_PORT |= Shift_Pin; _delay_us(300); } void Shift_WriteByte(char Byte) { for(int i=0;i<8;i++) { if(Byte&0x80) Shift_WriteOne(); else Shift_WriteZero(); Byte<<=1; } Shift_Load(); }
تابع Shift_WriteByte یک بایت از طریق یک خط داده منتقل خواهد کرد. دقت داشته باشید قبل از فراخوانی آن حتما یک بار تابع Shift_Init را جهت پیکربندی پورت فراخوانی کرده باشید. مطابق کد زیر:
int main(void) { Shift_Init(); uint8_t Data = 1; while(1) { Shift_WriteByte(Data); Data<<=1; if(Data == 0x00) Data = 1; _delay_ms(100); } }
منبع: سیسوگ