تبلیغات

به نام خدا

شروع بحث‌های تخصصی نرم‌افزاری در میکروکنترلر، ASCII Code ، اصل ضرب و ...


از این جلسه ما وارد مبحث آموزش مقدماتی زبان C می شویم تا دوستان کمی با مقدمات برنامه نویسی آشنا بشوند. در استفاده از میکروکنترلرها برای ساخت ربات های مقدماتی مثل مسیر یاب و آتش نشان و ... ما نیازی به آموختن برنامه نویسی در حد حرفه ای نداریم و کمی آشنایی با مقدمات برای ما کافیست!!!


بدون مقدمه بیشتر وارد بحث می شویم.

همانطور که می دانید، کوچک ترین واحد ذخیره سازی اطلاعات در حافظه، Bit است. (جلسه ی شانزدهم در مورد یک Bit توضیح داده شده).
هر 8 بیت را یک Byte می گویند. در حقیقت یک بایت اطلاعات، 8 تا 0 یا 1 است که در مجمع 256 حالت مختلف را پدید می اورند.

توضیح بیشتر:
یک بیت، فقط 2 حالت دارد، 0 یا 1. وقتی 2 بیت در کنار هم قرار می گیرند، هر کدام 2 حالت را پدید می اورند و در مجموع طبق اصل ضرب، 4 حالت به وجود می آید. یعنی:
1 و 1
1 و 0
0 و 1
0 و 0
اصل ضرب:



به مثال زیر توجه کنید.






در شکل بالا، برای رفتن از A به B، 3 مسیر وجود دارد؛ 5 مسیر هم برای رفتن از B به C وجود دارد. طبق اصل ضرب، برای رفتن از A به C مجموعاً 15=5*3 حالت وجود دارد.

در اینجا، در حقیقت تعداد کل حالت ها، برابر است با حاصل ضرب حالت های هر بیت (که 2 حالت می باشد) می باشد. به عنوان مثال برای محاسبه ی تعداد حالت های 3 بیت اطلاعات، داریم: 8=3^2=2*2*2.

طبق همین رابطه، یک بایت، 256=8^2 حالت مختلف می تواند باشد.




هر 1024 بایت را 1 کیلوبایت می گویند و هر 1024 کیلو بایت، یک مگابایت است. هر 1024 مگا بایت هم یک گیگابایت و هر 1024 گیگا بایت هم یک ترابایت نام دارد.( 1024=10^2)

حافظه های کامپیوترهای خانگی امروزی، می تواند تا چند صد گیگابایت هم باشد.


کد ASCII چیست:


موسسه ی استاندارد آمریکا، استانداردی برای ذخیره سازی اطلاعات معرفی کرد. این استاندارد 256 کاراکتر (یک کاراکتر عبارتست از یک عدد، رقم یا یک علامت مثل + و -) را کد گذاری کرد و به هر کدام یک عدد 8 رقمی در مبنای 2(یعنی یک بایت) نسبت داد. این کارکترها شامل همه ی حروف الفبای لاتین، اعداد 0 تا 9، علامت های مختلف مثل نماد جمع(+) و تفریق(-) و ... هستند.


در حقیقت طبق این استاندارد، برای ذخیره سازی هر کاراکتر، یک بایت از حافظه به آن اختصاص میابد. مثلاً برای ذخیره سازی کلمه ی"ALI" به 3 بایت حافظه نیاز داریم. جدول کدهای ASCII را می تونید در کتاب های برنامه نویسی یا با جستجو در اینترنت به راحتی ببینید.



انواع زبان های برنامه نویسی:



زبان ماشین:
سطح پایین ترین زبان برنامه نویسی زبان ماشین است. در این زبان شما باید به جای گذاشتن علامت + برای جمع کردن مقدار 2 عدد، باید از کد 00 استفاده کنید. این زبان، زبان قابل فهم برای کامپیوتر است، به همین خاطر به آن زبان ماشین می گویند. برنامه های ما در هر زبان برنامه نویسی دیگری، حتی اسمبلی، باید توسط کاپایلر مخصوص آن زبان، به زبان قابل فهم برای کامپیوتر یعنی زبان ماشین ترجمه شود.


زبان اسمبلی:
این زبان کمی پیشرفته تر از زبان ماشین است و کارکردن با آن خیلی راحت تر از زبان ماشین است. به عنوان مثال برای جمع کردن 2 مقدار با یکدیگر می توان از دستورADD استفاده کرد. در این زبان سیستم کد گذاری ASCII هم تعریف شده است و کاربر به عنوان مثال فقط کافیست کلمه ی ALI را تایپ کند، کامپایلر در اینجا کدهای مربوط به این کلمه را از جدول استخراج کرده و جایگزین می کند.


بعد از این ها نوبت به زبان های برنامه نویسی سطح بالا می رسد. این زبان ها سعی کرده اند تا حد امکان به زبان گفتار انسان نزدیک شوند. زبان C یکی از زبان های سطح بالا می باشد.



یک برنامه، شامل چندین دستور مختلف هستش که ما آنها را پشت سرهم با ترتیب مشخصی می نویسیم. در زبان C دستورات باید حتماً داخل توابع باشند. یک تابع عبارتست از چند دستور که در داخل یک آکولاد ({}) نوشته می شوند و نام مشخصی هم برای ان ها گذاشته می شود. همچنین توابع می توانند اطلاعاتی را به عنوان ورودی و خروجی از برنامه دریافت و به آن بازگردانند.

در زبان C وجود تابعی با نام main الزامیست. یعنی ما باید حتماً تابعی با نام main در برنامه ی خود داشته باشیم و اجرای برنامه هم از تابع main شروع می شود.



در Codevision، بعد از انجام تنظیمات اولیه، خود برنامه برای شما قالبی را آماده می کند که در آن تنظیمات اولیه ی پورت ها و .... همچنین بعضی تعاریف اولیه مثل تابع main انجام شده است. فقط کافیست شما دستورات خود را در داخل آن فضای مشخص شده (در داخل تابع main) تایپ کنید.


در ادامه ی آموزش این جلسه برنامه ی یک مسیریاب ساده  دو سنسوره رو می نویسیم...


اما ابتدا باید چندتا نکته ی دیگه هم یاد بگیریم.

همونطور که گفته شد AT Mega16 دارای پایه های متعددی برای تبادل اطلاعات با مدار است. هر 8پایه ی مجاور که این وظیفه را دارند یک پورت نامیده می شوند (به شکل نگاه کنید) . AT Mega16 دارای 4 پورت با نام های A ، B ، C و D می باشد. پایه های هر پورت به این شکل نمایش داده می شود:

شماره ی پایه+"."+نام پورت

مثلاً اولین پایه ی پورت D به این صورت نشان داده می شود: D.0
و پایه ی سوم پورت C به صورت : C.2
حال به ترتیب پایه های ATMEGA16L دقت کنید


دقت کنید که شماره گذاری پایه ها در پورت ها از 0 شروع می شود.
همچنین گفته شد، پایه های میکروکنترلر می توانند به صورت ورودی یا خروجی تنظیم شوند، مثلاً در یک ربات مسیریاب میتوان چند پایه را تنظیم کرد که ورودی باشند و اطلاعات سنسورها را دریافت کنند، یا انها را تنظیم کرد تا خروجی باشند و موتورها را هدایت کنند. این تنظیم به صورت نرم افزاری و با تنظیم رجیستر DDRx انجام می گیرد. اما ابتدا باید رجیستر را تعریف کنیم.

رجیستر چیست؟
رجیسترها توعی حافظه هستند که به طور مستقیم با بخشش پردازشگر میکروکنترلر در ارتباط هستند. هر رجیستر یک بایت یا 8 بیت است. یکی از ویژگی های رجیسترها این است که به خاطر ارتباط نزدیک با پردازنده، سرعت بسیار بالاتری نسبت به سایر خانه های حافظه دارند.


رجیستر DDRx:
رجیستر DDRx (Data Direction) برای تنظیم ورودی یا خروجی بودن پایه های میکروکنترلر است. برای تنظیم پایه ها در برنامه، باید به جای x باید آدرس پایه ی مورد نظر(مثل B.3) را بنویسیم. اگر بخواهیم آن پایه خروجی باشد باید بیت رجیستر مربوط به آن را 1 کنیم، و اگر بخواهیم آن پایه ورودی باشد، باید بیت رجیستر مربوط به آن را 0 کنیم. به عنوان مثال اگر بخواهیم پایه17 یعنی D.3 خروجی باشد باید این جمله را بنویسیم: DDRD.3=1;
و اگر بخواهیم این پایه ورودی باشد: DDRD.3=0;


رجیستر PORTx:
در صورتی که پایه ها به صورت خروجی تنظیم شده باشند، هر چه در این رجیستر نوشته شود سطح منطقی پایه ی متناظر را تعیین می کند، مثلاً اگر بنویسیم PORTB.3=1 پایه B.3 یعنی پایه ی 4، 1 منطقی خواهد شد(یعنی ولتاژ 5 ولت بر روی این پایه قرار می گیرد). و اگر بنویسیم PORTC.1=0، پایه ی C.1 یعنی پایه ی 23، 0 منطقی خواهد شد (یعنی ولتاژ این پایه 0 می شود.).


رجیستر PINx:
در صورتی که پایه ها به صورت ورودی تنظیم شده باشند، محتویات این رجیستر حاوی اطلاعات دریافتی از پایه های میکروکنترلر است. مثلاً اگر PINB.1=0 باشد، یعنی بر روی پایه شماره ی 2 یا همان B.1 ؛ 0 منطقی اعمال شده است(مثلاً اگر به سنسوری وصل شده است، خروجی سنسور 0 منطقی بوده است). در حقیقت این رجیستر برای خواندن وضعیت پایه های ورودی مورد استفاده قرار می گیرد.


نکته ی بسیار مهم: دقت کنید که در زبان C، باید در انتهای هر خط از برنامه یک علامت ";" گذاشته شود. به این علامت در زبان انگلیسی سِمی کالِن می گویند.

نکته ی مهم:
در حقیقت برای هر پورت 3 رجیستر(حافظه 1 بایتی) در داخل میکروکنترلر وجود دارد که به مجموع این 12 رجیستر، رجیسترهای I/O (Input/Output) می گویند.



بسیار خوب، حالا نوبت نوشتن برنامه ی 1 ربات مسیریاب ساده است که فقط 2 تا سنسور داره!!!

نرم افزاری کمکی به نام Code Wizard در داخل همان Codevision وجود دارد که کار ما را برای انجام تنظیمات اولیه مانند تنظیم ورودی یا خروجی بودن پایه ها آسان می کند. یعنی دیگه نیازی نیست برای هر پایه تک تک با رجیستری DDR سرو کله بزنیم، و به راحتی با چند تا تیک ساده همه ی پایه ها رو تنظیم می کنیم. البته Code wizard همونطور که از اسمش هم معلومه بسیاری امکانات جادویی دیگری هم داره که در جلسات آینده به تدریج با آن ها آشنا خواهیم شد. Code Wizard در حقیقت برای ساده تر کردن و سریع تر کردن برنامه نویسی در فضای Codevision طراحی شده است و کارش این است که قسمت های زیادی از برنامه را به صورت خود کار و طبق خواسته های ما برای ما می نویسد.

پس با این حساب نیازی نیست تنظیمات رجیستری DDRx رو ما در برنامه خودمون انجام بدیم و این کار رو به Code wizard واگذار می کنیم. با Code wizard در جلسه ی آینده آشنا خواهیم شد.

پس در این جلسه فرض می کنیم تنظیمات اولیه مثل رجیستری DDRx و ... انجام شده است. پایه های B.0 و B.1 را به صورت ورودی(برای دریافت اطلاعات سنسورها)، و پایه های B.2 ،B.3 ، B.4 و B.5را به صورت خروجی (برای کنترل حرکت موتورها) تنظیم کرده می کنیم.

B2 و B.3 برای کنترل موتور سمت راست و B.0 برای سنسور سمت راست!

B.4 و B.5 برای کنترل موتور سمت چپ و B.1 برای سنسور سمت چپ!

حال مانند ربات قبلی، یک پایه از هر موتور را 0 می کنیم؛ و روشن و خاموش کردن هر موتور را، با اعمال 0 یا 1 منطقی بر روی پایه ی دیگر کنترل می کنیم.

پایه ی دیگر را هم به صورت هماهنگ با سنسور متناظر آن سمت 0 و 1 می کنیم، یعنی اگر خروجی سنسور 0 بود، پایه ی موتور را 0 می کنیم و اگر 1 بود ، پایه را 1 کرده و موتور را فعال می کنیم.(به شرطی که از مدار گیرنده ی شماره 2 استفاده شود(جلسه ی 15))

در زبان C علامت "=" یک عملگر است که عملوند سمت راست خود را خوانده و در عملوند سمت چپ خود می ریزد. مثلاً وقتی می نویسیم:

PORTB.3=PINB.0;

ابتدا مقداری B.0 خوانده می شود و سپس بر روی B.3 ریخته می شود. یعتی مثلاً اگر روی B.0 ، 1 منطقی اعمال شده باشد، پایه ی B.3 نیز 1 منطقی می شود.

حال با توضیحات داده شده به برنامه ی ربات مسیر یاب ساده دقت کنید:

PORTB.2=0;

PORTB.4=0;

PORTB.3=PINB.0;

PORTB.5=PINB.1;

همانطور که می بینید این برنامه بسیار ساده و کوتاه است.

در جلسات آینده سعی می کنیم شما رو با Code wizard بیشتر آشنا کنیم. منتظر سوالات و نظرات دوستای خوبم هستم.

موفق و سربلند باشید.

یا حق...