با سلام خدمت تمامی دوستان عزیز و تشکر از آقای حردانی بابت مطلب خوبی که درباره راهاندازی کتابخانه ff.h در سایت سیسوگ قرار دادند. لازم دونستم مطالبی که مدتی پیش درباره راهاندازی Micro SD با AVR در نرمافزار کدویژن یاد گرفتم و درباره آنها چیز زیادی در اینترنت پیدا نکردم را در اختیار بقیه هم قرار بدم.
مدتی پیش سعی کردم یک کارت حافظه Micro SD 2GB را راهاندازی کنم. بعد از مطالعه درباره ساختار داخلی مموری کارتها (که اون هم چند روزی وقتم را گرفت!) رسیدم به راهاندازی SD Card با کتابخانه ff.h که مطلب نوشته شده توسط آقای حردانی را توی این سایت (سایت سیسوگ) دیدم و بر اساس اون شروع کردم به راهاندازی مموری کارتم. مطالب کاملاً واضح و مفید بودند؛ ولی در حین کار با مشکلاتی روبرو شدم که چیزی درباره اونها گفته نشده بود. لازم دیدم مطالب قبلی را تکمیل کنم تا اگر کسی با چنین مشکلاتی روبرو شد، بهراحتی از اونها عبور کند.
با ادامه مطالب همراه من باشید…
خوب! برای شروع، سعی میکنم مواردی که آقای حردانی در سایت سیسوگ قبلاً توضیح دادن را خیلی سریع به ترتیب بگم و بعد بریم سراغ ادامه کار. اولین مرحله انتخاب حداقل قطعات موردنیاز برای اجرای پروژه است! پس یک میکروی مناسب میخوایم، یک نمایشگر مثل السیدی 2*16 و یک مموری کارت و خشاب اون. میتونید در مرحله اول از شبیهسازی مثل پروتئوس استفاده کنید. توی کدویژن یه پروژه جدید ایجاد میکنیم و بر اساس نیاز هامون یک سری از قسمتهای داخل میکرو را فعال میکنیم. مثل قسمت ارتباط SPI، یک تایمر (که حدوداً هر 10 میلیثانیه یکبار یک وقفه بده و داخل اون وقفه، مانع خوابیدن مموری کارت بشه!) برای راه اندازی مموری کارت و…
تا اینجا، پروژهای ایجاد کردیم که فقط تابع ارتباط SPI، یک تایمر و یک نمایشگر و چند تا کتابخانه دیگر داخلش وجود دارد. تا اینجای برنامه خبری از مموری کارت نیست و حجم RAM اشغال شده توی شکل زیر معلومه! که 8 بایت بیشتر نیست!
برای اینکه بتونیم مموری کارت را راهاندازی کنیم باید نکاتی رو انجام بدیم تا میکرو بتونه مموری کارت را بشناسد. ابتدا باید کتابخانه ff.h را در برنامه شامل کنیم. ولی این کار بهتنهایی کافی نیست و باید از طریق منوی تنظیمات کدویژن این کتابخانه را فعال کرد. اگر این کار را نکنید و فقط کتابخانه را در برنامه شامل کنید، اونوقت موقع کامپایل کردن خطای زیر را خواهید داشت!
از منوی Project قسمت Configure را انتخاب میکنیم. سپس از پنجره تنظیماتی که باز میشه وارد سربرگ C compiler می شیم و از اونجا سربرگ مربوط به کتابخانه Micro SD را میاریم و تنظیمات را مطابق شکل زیر انجام میدیم. تمامی این مراحل را قبلاً آقای حردانی توضیح دادند و بنده فقط برای یادآوری گفتم.
از طرفی، در پروژه ایجاد شده در پروتئوس هم قطعات موردنیاز را به پروژه اضافه میکنیم.
مطالبی که تا اینجا گفته شد، فقط یک یادآوری بود. از اینجا به بعد مطالب جدید هستند. پس بریم و ادامه مطالب را ببینیم!
برمیگردیم سراغ کدویژن و برنامه را یکبار دیگر کامپایل میکنیم. با اضافهکردن کتابخانه ff.h به برنامه کدویژن (بهصورت کامل)، حجم RAM استفاده شده در برنامه از 8 بایت به 21 بایت رسید. کتابخانه ff.h توابع زیادی دارد که بسته به نیازمان از اونها استفاده میکنیم. اگر در قسمت Help درباره کتابخانه ff.h جستجو کنید، نکتههای خوبی حتماً پیدا خواهید کرد. در داخل این کتابخانه مانند بقیه کتابخانهها از متغیرها، توابع و چیزای دیگه ای استفاده شده است. چند مورد از چیزای مهمی که شما میتونید در داخل این کتابخانه ببینید، انواع داده های کمککننده هستند. این دادههای کمککننده در قالب enum و structure یک سری اطلاعات خوب و کاربردی از مموری کارت در مراحل مختلف کار در اختیار کاربر قرار میدند. از جمله این اطلاعات مفید، میتوان به مواردی مثل انواع خطاهای به وجود آمده در حین برقراری اتصال، خواندن و نوشتن و یا اطلاعاتی که درباره فایل موجود در مموری، حجم فایل و… اشاره کرد.
حالا چطوری از این داده های کمکی استفاده کنیم؟ برای اینکه بتونیم از اطلاعات داده های کمککننده این کتابخانه استفاده کنیم باید مانند شکل زیر چند متغیر از همان جنس متغیرهای دادههای کمکی، داخل برنامه بسازیم.
در ادامه سعی میکنم توضیح مختصری راجع به توابع کتابخانه ff.h بدم تا دید بهتری نسبت به اونها داشته باشید.
تابع f_mount:
برای بارگذاری درایو مموری کارت استفاده میشه. اگه یادتون باشه ما دو تا متغیر در قسمت قبل در برنامه ساختیم و گفتیم که بهوسیله اونها میتونیم اطلاعات مفیدی درباره مموری کارت داشته باشیم. ولی این نکته را نباید فراموش کنیم، تا زمانی که از تابع f_mount استفاده نکنید و مموری کارت را بارگذاری نکرده باشید، اطلاعات مربوط به FATFS در اختیار شما قرار نخواهد گرفت! البته با این دستور، بخشی از اطلاعات مموری کارت را به دست خواهیم آورد.
بعد از نوشتن تابع f_mount یکبار دیگه برنامه را کامپایل کنید. نکته جالب اینجاست که میزان RAM اشغال شده توسط برنامه فقط بعد استفادهکردن از همین یک تابع مموری کارت، از 21 بایت به 583 بایت رسید!
تابع f_open:
این تابع برای باز کردن فایل موردنظر در مموری کارت و بهدستآوردن اطلاعات مفید درباره آن استفاده میشود. این دستور را در برنامه مینویسیم و برنامه را کامپایل میکنیم. خواهید دید که حجم RAM اشغال شده از 583 بایت به 1139 بایت رسید. درصورتی که میکروکنترلر ATmega16 فقط 1024 بایت RAM دارد. این باعث می شود کدویژن خطا بگیرد و نتواند برنامه را کامپایل کند.
دیدیم که کتابخانه ff.h نیاز به رم بالایی دارد تا بتوانیم از آن استفاده کنیم. پس در انتخاب میکرو باید دقت بیشتری کنیم. همین روند اجرا شده را با میکروکنترلر ATmega32 انجام میدهیم. مقدار حجم RAM میکروکنترلر ATmega32 برابر با 2048 بایت است. پس اکنون مشکل 1139 بایت رم اشغال شده را نخواهیم داشت. پس برنامه را از اینجا به بعد برای میکروکنترلر ATmega32 خواهیم نوشت.
همانطور که در شکل زیر میبینید با اجرای این دو تابع، توانستیم با استفاده از داده های کمککننده اطلاعات مفیدی از مموری کارت در اختیار داشته باشیم.
حالا میخواهیم داخل مموری کارت و در یک فایل متنی text مطلبی را بنویسیم.
تابع f_write:
برای نوشتن در یک فایل متنی از نوع .txt درون مموری کارت استفاده میشه. بعد از استفاده از این دستور حجم رم اشغال شده به 1155 بایت میرسد.
خوب، تا اینجا تونستیم یک فایل متنی در مموری کارت ایجاد کنیم و داخل اون متنی را بنویسیم و تا اینجا حدود 1155 بایت از رم میکرو را اشغال کردیم. حالا میخوایم متنی که قبلاً نوشتیم را بخونیم.
تابع f_read:
برای خواندن فایل متنی در مموری کارت استفاده میشه. آخرین بار بعد از نوشتن یک فایل متنی در مموری کارت، آن را بستیم و از مموری کارت خارج شدیم. پس باید دوباره مموری کارت را بارگذاری کنیم و فایل متنی را باز کنیم و سپس متن داخل آن را بخوانیم.
بعد از استفاده از این دستور، حجم رم اشغال شده به 1192 بایت می رسد. حالا که تونستیم با مموری کارت ارتباط برقرار کنیم، بیایم و کمی برنامه را ویرایش کنیم تا کاربر بهتر متوجه بشه که توی کدوم مرحله قرار داره! دو مرحله نوشتن و خواندن را به صورت جداگانه در زیر تابع های مربوط به خود مینویسیم. تابع نوشتن به صورت زیر خواهد بود:
و تابع خواندن هم بهصورت زیر اجرا خواهد شد.
این دو تابع نوشتن و خواندن دقیقاً مانند دستورات نوشتن و خواندن قبلی عمل میکنند؛ ولی با این تفاوت که این بار کمی بهش جلوه های ویژه اضافه کردیم! با این کار حجم حافظه اشغال شده 1455 بایت شد!
خوب! چه اتفاقی افتاد! من دارم خطر را احساس میکنم! رم میکروی من، بعد از اجرای چند تا دستور ساده از کتابخانه ff.h داره پر میشه! فقط کافیه، چند تا تابع دیگه از کتابخانه ff.h در چند جای دیگه برنامه استفاده کنم تا کدویژن خطای استفاده بیش از اندازه RAM بده و به مشکل کمبود فضای رم برخورد کنم! نظر شما چیه و باید چه کاری انجام بدیم؟ هنوز خطای مربوط به رم نداریم!
پس بیایید و از یکی دیگه از توابع کتابخانه ff.h استفاده کنیم. برای مثال چک کنیم ببینیم روی آخرین کاراکتر فایل متنی داخل مموری کارت هستیم یا نه؟!
بعد از نوشتن این تابع و اجرای اون متوجه مشکل بالا (کمبود حافظه رم) خواهید شد!
میزان رم مورد استفاده شده در میکرو به 1555 بایت رسید! حالا دیگه خود کدویژن خطا میگیره و اجازه ادامه کار را به شما نمیده.
دو راهحل برای رفع این مشکل وجود داره که اولین راهحل اصلاً صحیح نیست و فقط خودتون را بیشتر به دردسر می اندازید.
راهحل اول:
یک میکروکنترلر قویتر و با حجم رم بیشتر انتخاب کنید!
راهحل دوم:
برنامهای که تا اینجا نوشتیم را اصلاح کنیم!
خوب! راهحل اول آسونه ولی راهحل دوم اصولیتر. پس میریم سراغ راهحل دوم.
تصور کنید شما برای اجرای یک برنامه، یک کتابخانه نوشتهاید که داخل آن چندین زیر تابع وجود دارد. در برنامه خود نیز چندین و چند بار از توابع موجود در کتابخانهای که درست کردید، استفاده میکنید و هیچوقت رم میکروی شما به این سرعت پر نمیشود. ولی چرا در توابعی که برای استفاده از مموری کارت نوشته شده، باعث شد رم میکرو اینقدر سریع پر شود؟
اگر در متن توابع دقت کنید، خواهید دید که برای اجرای هر کدام از توابع write و read مجبور به استفاده مجدد از دستورات یا همان توابع کتابخانه ff.h شدهایم. پس به نظر میاد مشکل را پیدا کرده باشیم! استفاده پیدرپی (بیش از یکبار) از توابع کتابخانه مموری کارت باعث پر شدن سریع رم میکرو شده!
یعنی چی؟ چه اتفاقی افتاده؟!
برای مثال، هر بار که شما تابع f_open را مینویسید، بخشی از رم به متغیرهای داخل تابع اختصاص داده میشه. اگر بیش از یکبار یکی از این توابع را بنویسید (استفاده بشه) میکرو مجدداً بخش اضافهتری از رم خو را در اختیار اون تابع قرار میده و این باعث میشه که خیلی سریع رم میکرو پر بشه و شما نتوانید کاری انجام بدید! پس باید از توابع کتابخانه ff.h فقط یکبار استفاده بشه یا بهتره کاملتر بگم، فقط یکبار در برنامه نوشته بشه!
به نظر میاد مشکل ما حل نشد، بلکه بیشتر هم شد! وقتی یک تابع باید چندین بار در برنامه فراخوانی و استفاده بشه، چطور باید فقط یکبار نوشت بشه؟
راه حل اینه که شما باید خودتون به تعداد توابعی که قرار از کتابخانه ff.h استفاده کنید، تابع بنویسید که داخل اونها (و در کل برنامه شما) فقط یکبار از هر کدام از توابع کتابخانه ff.h نوشته (استفاده) شده باشه! حالا میتونید توابع خودتون را چندین بار در برنامه فراخوانی کنید بدون اینکه رم میکرو بیش از انتظار پر بشه!
پس برای هر کدام از توابع کتابخانه ff.h که خواستید استفاده کنید باید خودتون یک تابع براش بنویسید و اون تابع (از کتابخانه ff.h) را داخلش قرار بدید. حالا دیگه میتونید بجای فراخوانی توابع کتابخانه ff.h که اگر بیشتر از چندبار بشن، باعث پر شدن رم میکرو میشه، از توابع خودتون، هر تعداد دفعهای که خواستید استفاده کنید!
مثلاً دستور f_open فقط یکبار باید در برنامه شما نوشته شده باشد در غیر این صورت رم میکرو سریع پر خواهد شد. پس باید یک تابع بنویسیم و فقط یکبار دستور f_open را در آن تابع (و حتی کل برنامه) نوشته شود. حالا میتونید از تابعی که خودتون برای f_open نوشتید به دفعات زیاد در برنامه استفاده کنید.
امیدوارم مشکل شما هم حل شده باشه…
دستتون درد نکنه
ی راه بهتر اینکه خودتون لیبری رو بنویسید و هم میزان رم و هم سرعت اجرا رو بالا ببرید . مثلا از کد نویسی اسمبلی بهره بگیرید قطعا حجم اطلاعات خیلی کم میشه و یا از اشاره گرها و ساختارها و ترکیبشون با اسمبلی بهترین کارایی رو برای حجم کد و رم و سرعت اجرا بگیرید . برای این منظور میتونید به اپلیکیشن نوت های میکرو و کارت حافظه مراجعه کنید.
سلام
ممنون از راهنمایی شما
این یکی از کتابخانه های معروف و پایه و رفرنس برای کارت های مموری هستش که نویسنده اصلی اون یک آقای ژاپنی هست و داخل سایت ش به طور کامل همه چیز را توضیح داده.
شما کتابخانه به زبان اسمبلی برای مموری کارت نوشتید؟ خوشحال میشیم اگر در اختیار بقیه هم قرار بدید تا بتونیم مشکل رم اشغال شده را حل کنیم.