رجیستر چیست؟رجیستری‌های PORTx, PINx , DDRx، قسمتی از برنامه‌ی یک ربات مسیریاب بسیار ساده و ...

Mute

عضو جدید
کاربر ممتاز
AT Mega16 داراي پايه هاي متعددي براي تبادل اطلاعات با مدار است. هر 8پايه ي مجاور که اين وظيفه را دارند يک پورت ناميده مي شوند (به شکل نگاه کنيد) . AT Mega16 داراي 4 پورت با نام هاي A ، B ، C و D مي باشد. پايه هاي هر پورت به اين شکل نمايش داده مي شود:
شماره ي پايه+"."+نام پورت
مثلاً اولين پايه ي پورت D به اين صورت نشان داده مي شود: D.0
و پايه ي سوم پورت C به صورت : C.2
حال به ترتيب پايه هاي ATMEGA16L دقت کنيد


123.GIF


دقت کنيد که شماره گذاري پايه ها در پورت ها از 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;

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

http://robofa.ir/index.php?newsid=27







 

سعید گروسی

عضو جدید
کاربر ممتاز
همین طورکه میدانیدزبان c یک زبان سطح میانه هستش
به این معنی که هم ازدستورات سطح بالاتوی آن استفاده میشه وهم سطح پائین
اصطلاح سطح بالایعنی به زبان انسان نزدیک تروسطح پائین یعنی به زیبان ماشین نزدیکتر
زبان سطح میانه معمولاریجیستری هستش.
من چندتاریجیستررومعرفی میکنم که مربوط به avr وزبان برنامه نویسی c هستش امیدوارم مفیدواقع بشه.

ریجیسترتایمر:


 

Mute

عضو جدید
کاربر ممتاز
کاربرد رجیستر ها در avr

کاربرد رجیستر ها در avr


همانطور كه ميدانيد وظيفه رجيستر در ميكرو نگهداري اطلاعات است، رجيسترهاي حافظه RAM در AVR از نوع هشت بيتي هستند و شما ميتوانيد اطلاعتتان را در قالب 8 بيت دران اين رجيسترها به عنوان حافظه موقت قرار بدهيد و از آنها استفاده كنيد. اما اين 32 رجيستر تفاوتي با بقيه رجيسترهاي RAM شما و رجيسترهاي با كاربرد خاص دارند و تفاوت اين هست كه اين 32 رجيستر مستقيما با ALU ميكرو در ارتباط هستند و شما براي انجام محاسبات نياز به اين داريد كه اطلاعات را در آنها قرار بدهيد تا بتوانيد به واحد ALU ارسال كنيد و از طريق همين رجيسترها هم بايد اطلاعات را از ALU دريافت كنيد، به عنوان مثال اگر شما ميخواهيد عدد 10 را با 20 جمع كنيد بايد حتما اين اعداد را از طريق اين رجيسترها به ALU ارسال كنيد، در بعضي از ميكروها فقط يك رجيستر هست كه مستقيما با ALU در ارتباط هست كه معمولا به Accumulator يا Working Register معروف هست و اين بستگي به نوع معماري تراشه دارد. در AVR اين 32 رجيستر نقش Accumulator را دارند.
· در بعضي از دستورات شما ميتوانيد مستقيما از همه 32 رجيستر استفاده كنيد و آنها را كنترل كنيد . اما در بعضي از دستورات شما فقط به نيمه بالايي يعني از R16 تا R31 دسترسي داريد. مثلا در دستوراتي مانند SBR , CBR كه براي صفر و يك كردن بيتي رجيستر ها به كار ميروند محدوديت وجود دارد و شما نميتوانيد اين دستورات را براي رجيسترهاي R0 تا R15 هم مانند 16 رجيستر R16 تا R31 مستقيما به كار ببريد.
· بعضي از اين رجيسترها علاوه بر كاربرد اصلي كاربردهاي ديگري هم دارند، مثلا رجيسترهاي R31 , R30 را ميشود با هم به عنوان يك رجيستر 16 بيتي با نام Z در نظر گرفت و در آدرس دهي از آن استفاده كرد ( البته كاربردهاي ديگه هم دارد )، رجيستر هاي R29 , R28 هم ميتوانند با هم تركيب بشوند و همچنين رجيسترهاي R27 , R26 هم به همين صورت، رجيسترهاي ديگري هم در بعضي موارد كابردهاي خاص ديگري انجام ميدهند.
· مي توان گفت كه اگر ما فرض كنيم ALU به عنوان شاه در نظر گرفته شود ، اين شاه فقط به 32 نفر اعتماد دارد و اطلاعات را از اين 32 نفر مستقيما دريافت ميكند، كه در AVR اين 32 نفر همان 32 رجيستر R0 تا R31 هستند و ALU نميتواند مستقيما اطلاعات را از يك خانه از حافظه RAM بردارد و پردازش كند ، شما اگر بخواهيد يك عدد را هم وارد ALU كنيد بايد حتما آن عدد را در اين رجيسترها قرار بدهيد و از اين طريق عدد را براي پردازش به واحد محاسبه و منطق كه همان ALU هست ارسال كنيد. در زبان هاي سطح بالا مثل بيسيك يا زباني مثل C بيشتر اين كارها را كامپايلر براي شما انجام ميدهد و شما لازم نيست زياد وارد جزئيات كار اين رجيسترها بشويد، زماني كه شما يك متغيير را در زباني مثل C تعريف ميكنيد يك خانه از حافظه موقت به آن اختصاص داده ميشود ( كامپايلر براي آن در نظر ميگيرد ) و اگر شما دستوري مانند PORTB = 25 را بنويسيد كامپايلر خودش كدي را توليد ميكند كه ابتدا عدد 25 در يكي از اين رجيسترها كه اشاره شد ريخته شده و بعد از آنجا روي پورت B قرار گيرد ، در حالي كه در زبان اسمبلي كه يك زبان سطح پايين هست شما بايد حتما ابتدا اين عدد را در ثباتي مثل R16 بريزيد و سپس آن را روي پورت بريزيد، مثلا به اين صورت:
· LDI R16,25
· OUT PORTB,R16
· همانطور كه ميبينيد در خط اول مقدار 25 در رجيستر R16 كه نقش واسط را دارد ريخته شده و بعد از آن از رجيستر R16 خوانده شده و در رجيستر PORTB قرار ميگيرد. زماني كه شما يك خط دستور براي اينكار در C بنويسيد كامپايلر حداقل كاري كه براي آن انجام ميدهد اين است كه زمان اسمبل كردن برنامه اين دو خط را براي آن ايجاد ميكند . حالا اگر دستوراتي مثل دستور جمع يا ضرب و تقسيم هم مد نظر باشد روال كار همين است و شما از هر زباني كه استفاده كنيد به خاطر معماري تراشه اين اطلاعات بايد حتما توسط رجيسترهاي R0 تا R31 به ALU وارد بشوند و شما چه متوجه بشيود، چه نشويد و چه بخواهيد چه نخواهيد AVR براي اينكه بتواند عمليات محاسباتي شما را روي داده ها انجام دهد بايد از اين 32 رجيستر كمك بگيرد تا بتواند اطلاعاتتان را براي پردازش وارد بخش محاسبه و منطق كند ( ALU )
· تمام موارد فوق به معماري تراشه برمي گردد و معمولا براي برنامه نويسان اسمبلي مهم هست، كمتر پيش مي آيد كه برنامه نويسان زبان سطح بالا خودشان را با اين موارد درگير كنند و براي صرفه جويي در وقت اين كار به كامپايلر سپرده ميشود.
· در ميكروهايي مانند PIC ها شما همين كار را از طريق رجيستري با نام W انجام ميدهيد ( به خاطر نوع معماري و ساختمان داخلي متفاوت )، و هر عملياتي كه بخواهيد انجام بدهيد بايد اطلاعات از طريق اين رجيستر وارد ALU گردد و مثلا اگر بخواهيد مثال بالا را انجام بدهيد به اين صورت انجام مي شود:
· MOVLW .25
· MOVWF PORTB
· در خط اول مقدار 25 دسيمال در ثبات w قرار ميگيرد و در خط بعدي اين مقدار از w به PORTB منتقل ميشود.
· از اين لحاظ معماري AVR در اين قسمت نسبت به PIC اين برتري را دارد كه شما به جاي يك رجيستر در بيشتر موارد 32 رجيستر در اختيار داريد كه ميتوانند مستقيما با ALU در ارتباط باشند، البته معماري PIC هم اصولي تر از اين حرفهاست كه از اين بابت كمبودي احساس بشه !
· خلاصه: اين 32 رجيستر، رجيسترهاي مهمي هستند كه ALU فقط از آنها اطلاعاتش را ميگيرد و پردازش ميكند و مي توان گفت در هر برنامه اي كه نوشته بشه عدم استفاده از آنها به نوعي محال هست، البته در زبانهاي سطح بالا تقريبا اين موارد اصلا مطرح نيست و شما فقط متغير را تعريف ميكنيد و كامپايلر خودش زحمت اين كارها را ميكشد اما اگر بخواهيد كمي حرفه اي تر به قضيه نگاه كنيد در همان زبان ها نيز براش شما مهم ميشود كه متغيري كه تعريف ميكنيد در كجا قرار ميگيرد و چگونه كدي كه مينويسيد كامپايل ميشود، يكي از فاكتورها ضعف و قدرت كامپايلر ها اين هست كه به متغيرها مكان مناسبي اختصاص بدهند تا بتوانند دستور العمل ها را به بهترين شكل انجام دهند و كد اضافي توليد نكنند. به نظر من شما اگر با زبان هاي سطح بالا كار ميكنيد حتما به اين نكات هم دقت كنید چون اگر حالا چندان هم داراي اهميت نباشند بعدها اهميت زيادي پيدا ميكنند.
 
بالا