کنترل پورت از طریق رجیسترهای atmega. برنامه نویسی میکروکنترلرهای AVR در C. Port A ثبت داده - PORTA

بیت

بخوان / بنویس

مقدار اولیه

بیت 7 - همه وقفه ها را فعال کنید. برای فعال کردن وقفه ها، این بیت باید روی 1 تنظیم شود. فعال کردن یک وقفه خاص توسط رجیسترهای ماسک وقفه EIMSK و TIMSK کنترل می شود. اگر این بیت (=0) پاک شود، هیچ یک از وقفه ها مدیریت نمی شود. بیت پس از وقوع وقفه توسط سخت افزار پاک می شود و تنظیم می شود تا بعداً با دستور RETI وقفه را فعال کند.
· بیت 6 - بیت کپی را ذخیره کنید. دستورالعمل های کپی بیت BLD و BST از این بیت به عنوان منبع و مقصد برای عملیات بیت استفاده می کنند. دستور BST بیتی از ثبات عمومی را در بیت T کپی می کند، دستور BLD بیت T را در بیت ثبات عمومی کپی می کند.
· بیت 5 - پرچم حمل نیمه. این نشان دهنده انتقال بین تترادها هنگام انجام تعدادی از عملیات حسابی است.
· بیت 4 - بیت علامت. بیت S دارای مقدار نتیجه عملیات XOR (N(+)V) روی پرچم های ارزش منفی (N) و مکمل این دو پرچم سرریز (V) است.

· بیت 3 - مکمل دو پرچم سرریز. از محاسبات مکمل دو پشتیبانی می کند.
· بیت 2 - پرچم منفی. این پرچم نشان دهنده نتیجه منفی تعدادی از عملیات های حسابی و منطقی است.
· بیت 1 - پرچم صفر. این پرچم نتیجه صفر تعدادی عملیات حسابی و منطقی را نشان می دهد.
· بیت 0 - حامل پرچم. این پرچم نشان دهنده حمل در حین عملیات حسابی و منطقی است.

میکروکنترلر AT90S8535 دارای 4 پورت I/O موازی A، B، C و D می باشد.
پورت A یک پورت دو طرفه 8 بیتی است. تعامل با پورت A از طریق سه ثبات در فضای ورودی / خروجی حافظه داده انجام می شود: ثبت داده - PORTA، $1B (3B$)، ثبت جهت داده - DDRA، $1A ($3A)، ثبت داده ورودی - PINA، 19 دلار (39 دلار). ثبات PINA فقط خواندنی است، در حالی که رجیسترهای PORTA و DDRA خواندنی و نوشتنی هستند. ثبت PINA یک رجیستر به معنای کامل کلمه نیست. دسترسی به آن خواندن وضعیت فیزیکی هر پین پورت را فراهم می کند. پورت A همچنین برای ورودی سیگنال های آنالوگ A/D استفاده می شود.

ثبت داده پورت A -پورتا

بیت

بخوان / بنویس

مقدار اولیه

ثبت مسیر داده پورت A -DDRA

بیت

بخوان / بنویس

مقدار اولیه

ثبت اطلاعات ورودی پورت A -PINA

بیت

بخوان / بنویس

مقدار اولیه

پورت B یک پورت ورودی/خروجی دو طرفه 8 بیتی است. مانند پورت A، ارتباط با پورت B از طریق سه رجیستر در فضای ورودی/خروجی حافظه داده انجام می شود: ثبت داده - PORTB، 18 دلار (38 دلار)، ثبت جهت داده - DDRB، 17 دلار (37 دلار) و ثبت داده ورودی - PINB، 16 دلار. (36 دلار). ثبت PINB فقط خواندنی است. رجیستر PINB یک رجیستر به معنای کامل کلمه نیست. دسترسی به آن خواندن وضعیت فیزیکی هر پین پورت را فراهم می کند. پین های پورت B می توانند عملکردهای جایگزین نشان داده شده در جدول 1 را انجام دهند. 2.1.

جدول 2.1. توابع جایگزین پین پورت B

پین پورت

عملکرد جایگزین

T0 - ورودی ساعت شمارنده/تایمر 0

T1 - ورودی ساعت تایمر / شمارنده 1

AIN0 - پایانه مثبت مقایسه کننده

AIN1 - ترمینال منفی مقایسه کننده

– ورودی انتخاب برده SPI

MOSI - SPI اصلی خروجی/تنظیم ورودی Slave

MISO - تنظیمات اصلی ورودی/خروجی SPI

SCK - سیگنال ساعت SPI

هنگام استفاده از پین ها برای توابع جایگزین، رجیسترهای PORTB، DDRB باید بر اساس آن تنظیم شوند.

ثبت داده پورتبPORTB

بیت

بخوان / بنویس

مقدار اولیه

ثبت جهت داده پورت B -DDRB

بیت

بخوان / بنویس

مقدار اولیه

ثبت اطلاعات ورودی پورت B -PINB

بیت

بخوان / بنویس

مقدار اولیه

پورت C یک پورت ورودی/خروجی دو طرفه 8 بیتی است. درست مانند پورت های A و B، تعامل با پورت C از طریق سه رجیستر در فضای ورودی / خروجی حافظه داده انجام می شود: ثبات داده PORTC، 15 دلار (35 دلار)، ثبات جهت داده DDRC، 14 دلار (34 دلار) است. ) و ثبت داده ورودی PINC، 13 دلار (33 دلار) است. ثبات PINC فقط خواندنی است، در حالی که رجیسترهای PORTC و DDRC خواندن و نوشتن هستند. رجیستر PINC یک ثبات به معنای کامل کلمه نیست. دسترسی به آن خواندن وضعیت فیزیکی هر پین پورت را فراهم می کند.
پورت C فقط دو پایه دارد که می توانند عملکردهای جایگزین را انجام دهند: پین های PC6 و PC7 عملکردهای TOSC1 و TOSC2 تایمر/ شمارنده 2 را انجام می دهند.

ثبت داده پورتسیPORTC

بیت

بخوان / بنویس

مقدار اولیه

ثبت جهت داده پورت C -DDRC

بیت

بخوان / بنویس

مقدار اولیه

ثبت اطلاعات ورودی پورت C -PINC

بیت

بخوان / بنویس

مقدار اولیه

پورت D یک پورت ورودی/خروجی دو طرفه 8 بیتی است. مانند پورت های A، B و C، ارتباط با پورت D از طریق سه رجیستر در فضای ورودی/خروجی حافظه داده انجام می شود: رجیستر داده PORTD، $12 ($32)، ثبات جهت داده DDRD، $11 ($31) است. و ثبت داده های ورودی - PIND، 10 دلار (30 دلار). ثبات PIND قابلیت خواندن را فراهم می کند، در حالی که رجیسترهای PORTD و DDRD قابلیت خواندن و نوشتن را ارائه می دهند. ثبات PIND یک ثبات به معنای کامل کلمه نیست. دسترسی به آن خواندن وضعیت فیزیکی هر پین پورت را فراهم می کند.
پین های پورت D می توانند عملکردهای جایگزین نشان داده شده در جدول 1 را انجام دهند. 2.2.

جدول 2.2. توابع پین پورت D جایگزین

پین پورت

عملکرد جایگزین

RxD - ورودی گیرنده UART

TxD - خروجی فرستنده UART

INT0 - ورودی وقفه خارجی 0

INT1 - ورودی وقفه خارجی 1

OC1B - پین مقایسه خروجی تایمر/ شمارنده 1

OC1A - خروجی مقایسه A تایمر/ شمارنده 1

ICP - ورودی ماشه ضبط تایمر/ شمارنده 1

OC2 - پین مقایسه خروجی تایمر/کنتر 2

هنگام استفاده از پین ها برای توابع جایگزین، رجیسترهای PORTD، DDRD باید بر اساس آن تنظیم شوند.

ثبت داده پورتDپورت

بیت

بخوان / بنویس

مقدار اولیه

ثبت جهت داده پورتDDDRD

بیت

بخوان / بنویس

مقدار اولیه

ثبت ورودی پورتDPIND

بیت

بخوان / بنویس

مقدار اولیه

از آنجایی که کار مورد نظر اولین کار است، برای اینکه دانش آموزان مهارت های کار با مجموعه آزمایشگاهی را کسب کنند، ابتدا همه دانشجویان یک کار را انجام می دهند. آنها از محل کار خود همان وظیفه کم کردن عدد 3 از عدد 5 را که در بند 1.5.3.1 ارائه شده است وارد رایانه شخصی می کنند. پس از کامپایل برنامه روی میکروکنترلر محل کار نوشته می شود و کار آن به معلم نشان داده می شود.
پس از چنین آشنایی با مجموعه، دانش آموز اقدام به انجام یک کار فردی می کند. اگر زمان وجود داشته باشد، معلم می تواند کار فردی را پیچیده کند.

عملیات بیتی مبتنی بر عملیات منطقی است که قبلاً به آنها پرداختیم. آنها نقش کلیدی در برنامه نویسی میکروکنترلرهای AVR و انواع دیگر دارند. تقریباً هیچ برنامه ای نمی تواند بدون استفاده از عملیات بیتی انجام دهد. تا کنون عمدا از آنها اجتناب کرده ایم تا یادگیری برنامه نویسی MK را آسانتر کنیم.

در تمام مقالات قبلی، ما فقط پورت های I/O را برنامه ریزی کردیم و از گره های داخلی اضافی مانند تایمر، مبدل های آنالوگ به دیجیتال، وقفه ها و سایر دستگاه های داخلی که بدون آنها MK تمام قدرت خود را از دست می دهد استفاده نکردیم.

قبل از شروع به تسلط بر دستگاه‌های MK داخلی، باید نحوه کنترل یا بررسی بیت‌های جداگانه رجیسترهای AVR MK را بیاموزید. قبلاً یک بررسی انجام می دادیم یا بیت های کل ثبات را به یکباره تنظیم می کردیم. بیایید ببینیم تفاوت چیست و سپس ادامه دهیم.

عملیات بیتی

اغلب، هنگام برنامه نویسی میکروکنترلرهای AVR، ما از آن استفاده می کنیم، زیرا در مقایسه با برنامه نویسان تازه کار MK وضوح بیشتری دارد و به خوبی درک می شود. به عنوان مثال، ما باید فقط بیت سوم پورت D را تنظیم کنیم. برای این کار، همانطور که قبلاً می دانیم، می توانیم از کد باینری زیر استفاده کنیم:

PORTD = 0b00001000;

اما با این دستور بیت سوم را روی یک قرار می دهیم و بقیه (0، 1، 2، 4، 5، 6 و 7) را صفر می کنیم. و حالا بیایید حالتی را تصور کنیم که رقم های 6 و 7 به عنوان ورودی ADC استفاده می شود و در این زمان سیگنالی از یک دستگاه به خروجی های مربوطه MK می رسد و با دستور بالا این سیگنال ها را ریست می کنیم. در نتیجه میکروکنترلر آنها را نمی بیند و معتقد است که سیگنال ها نیامده اند. بنابراین، به جای چنین دستوری، باید از دستور دیگری استفاده کنیم که فقط بیت سوم را روی یک قرار می دهد، در حالی که روی بقیه بیت ها تأثیر نمی گذارد. برای این کار معمولاً از عملیات بیتی زیر استفاده می شود:

PORT |= (1<<3);

در زیر به تجزیه و تحلیل نحو آن خواهیم پرداخت. و حالا یک مثال دیگر. فرض کنید باید وضعیت بیت سوم رجیستر PIND را بررسی کنیم و بدین ترتیب وضعیت دکمه را بررسی کنیم. اگر این بیت صفر شود، می دانیم که دکمه فشرده شده و سپس کد دستوری اجرا می شود که مطابق با وضعیت دکمه فشرده شده است. قبلاً از نماد زیر استفاده می کردیم:

اگر (پیند == 0b00000000)

(هر کد)

با این حال، با کمک آن، ما نه یک مورد، - سوم، بلکه همه بیت های PIND را به طور همزمان بررسی می کنیم. بنابراین، حتی اگر دکمه فشار داده شود و بیت مورد نظر ریست شود، اما در آن زمان سیگنالی روی هر پایه پورت D دیگری دریافت شود، بیت مربوطه روی یک تنظیم می شود و شرط داخل پرانتز نادرست خواهد بود. در نتیجه، کد موجود در بریس های فرفری حتی با فشار دادن دکمه اجرا نمی شود. بنابراین، برای بررسی وضعیت یک بیت سوم منفرد از ثبات PIND، باید از یک عملیات بیتی استفاده کرد:

اگر (~PIND & (1<<3))

(هر کد)

برای کار با تک تک بیت های میکروکنترلر، زبان برنامه نویسی C در زرادخانه خود قرار دارد که با آن می توانید وضعیت یک یا چند بیت جداگانه را به طور همزمان تغییر دهید یا بررسی کنید.

تنظیم یک بیت

برای تنظیم یک بیت، مانند پورت D، از عملیات OR بیتی استفاده می شود. این همان چیزی است که در ابتدای مقاله استفاده کردیم.

PORTD = 0b00011100; // مقدار اولیه

PORTD = PORTD | (یک<<0); применяем побитовую ИЛИ

PORT |= (1<<0); // сокращенная форма записи

PORTD == 0b00011101; // نتیجه

این دستور بیت را صفر می کند و بقیه را بدون تغییر می گذارد.

به عنوان مثال، بیایید بیت 6 پورت D را تنظیم کنیم.

PORTD = 0b00011100; // وضعیت پورت اولیه

PORT |= (1<<6); //

PORTD == 0b01011100; // نتیجه

برای نوشتن یک تا چند بیت جداگانه به طور همزمان، به عنوان مثال، پورت صفر، ششم و هفتم بنماد زیر اعمال می شود.

PORTB = 0b00011100; // مقدار اولیه

PORTB |= (1<<0) | (1<<6) | (1<<7); //

PORTB == 0b1011101; // نتیجه

بازنشانی (صفر کردن) بیت های فردی

برای بازنشانی یک بیت واحد، از سه دستور قبلاً بحث شده به طور همزمان استفاده می شود: .

بیایید بیت سوم رجیستر PORTC را ریست کنیم و بقیه را بدون تغییر بگذاریم.

PORTC = 0b00011100;

PORTC &= ~(1<<3);

PORTC == 0b00010100;

بیایید اقدامات مشابهی را برای رقم 2 و 4 انجام دهیم:

PORTC = 0b00111110;

PORTC &= ~((1<<2) | (1<<4));

PORTC == 0b00101010;

تغییر ضربان

علاوه بر تنظیم و تنظیم مجدد، یک دستور مفید نیز استفاده می شود که یک بیت را به حالت مخالف سوئیچ می کند: یک به صفر و بالعکس. این عملیات منطقی به طور گسترده ای در ساخت افکت های مختلف نورپردازی، به عنوان مثال، گلدسته سال نو استفاده می شود. مثال PORTA را در نظر بگیرید

PORTA = 0b00011111;

پورتا ^= (1<<2);

PORTA == 0b00011011;

تغییر وضعیت بیت های صفر، دوم و ششم:

PORTA = 0b00011111;

پورتا ^= (1<<0) | (1<<2) | (1<<6);

پورتا == 0b01011010;

بررسی وضعیت یک بیت فردی. اجازه دهید یادآوری کنم که بررسی (برخلاف نوشتن) یک پورت I / O با خواندن داده ها از ثبت PIN انجام می شود.

رایج ترین تست توسط یکی از دو عبارت حلقه انجام می شود: if و while. قبلاً با این اپراتورها آشنا شده بودیم.

بررسی تخلیه برای وجود یک صفر منطقی (تنظیم مجدد) با اگر

اگر (0==(PIND & (1<<3)))

اگر بیت سوم پورت D پاک شود، Code1 اجرا می شود. در غیر این صورت کد2 اجرا می شود.

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

اگر (~PIND & (1<<3))

بررسی تخلیه برای وجود یک واحد منطقی (تنظیم) با اگر

اگر (0 != (PIND & (1<<3)))

اگر (PIND & (1<<3))

دو حلقه بالا به طور مشابه عمل می کنند، اما به دلیل انعطاف پذیری زبان برنامه نویسی C، می توان آنها را متفاوت نوشت. عمل != به معنای برابر نیست. اگر بیت سوم پورت ورودی/خروجی PD (یکی) تنظیم شود، Code1 اجرا می شود، در غیر این صورت، Code2 اجرا می شود.

منتظر کمی تنظیم مجدد با در حالی که

در حالی که (PIND & (1<<5))

تا زمانی که بیت پنجم رجیستر PIND تنظیم شده باشد، کد1 اجرا می شود. با تنظیم مجدد، اجرای Code2 شروع می شود.

منتظر تنظیم بیت هستیم در حالی که

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

برای مدت طولانی بدون توجه رفتیم میکروکنترلرهای AVR، و اکنون زمان اصلاح این سوء تفاهم است! در مورد سایر کنترلرها، ما به تدریج لوازم جانبی AVR مختلف، ابتدا تئوری، انواع رجیسترها و در نهایت، نمونه های کوچک را در نظر خواهیم گرفت.

من به عنوان یک IDE استفاده می کنم AVR Studio 5، نسخه ششم AVR Studioمن حتی آن را امتحان نکردم، اخیراً اغلب با وظایف AVR مواجه نشده ام) به طور کلی، بد نیست AVR Studio 4 را نیز نصب کرده باشید، زیرا گاهی اوقات پیش می آید که باید کنترلر را از طریق برنامه ریزی کنید. AVR Studio 5ممکن به نظر نمی رسد اخیراً می خواستم ATMega2560 را با استفاده از برنامه نویس STK500 فلش کنم و بعد از استودیو 5 غیرممکن شد) این به خوبی از روزهای قدیم AVR Studio 4 باقی مانده بود و در عرض چند دقیقه مشکل حل شد.

دیگه چی میتونم بگم؟ .. بله، در اصل، همین، شما می توانید دست به کار شوید؛)

طبیعتاً ما شروع خواهیم کرد GPIO - پورت های ورودی-خروجی، زیرا بدون آنها هیچ جا وجود ندارد) و قبل از توصیف رجیسترهایی که عملکرد پورت ها را کنترل می کنند، چند لحظه "الکتریکی" را یادداشت می کنم.

در ورودی هر پایه میکروکنترلر، توسعه دهندگان دلسوز چند دیود قرار می دهند که در صورت تجاوز از ولتاژ مجاز، میکروکنترلر را نجات دهد. ولی! در واقعیت، همه چیز چندان هم گلگون نیست و اگر به عنوان مثال، 7.5 ولت به ورودی میکروکنترلر اعمال شود، هیچ کس و هیچ چیز به کنترلر کمک نمی کند، از تجربه خود ما تأیید شده است. بنابراین، تمام آزمایشات باید با دقت انجام شود)

حالا برای ثبت نام تمام کار با پورت های I/O در AVR در سه رجیستر متمرکز شده است - DDRx، PORTx، PINx. کاراکتر "x" با نام پورت مربوطه (A,B…) جایگزین می شود. یعنی اگر بخواهیم با پورت A میکروکنترلر کار کنیم، به رجیسترهای DDRA، PORTA، PINA نیاز داریم. اگر بخواهیم با پایه پنجم پورت A (PA5) کار کنیم، به بیت پنجم از ثبات های ذکر شده در بالا علاقه مند هستیم. همانطور که می بینید، همه چیز بسیار ساده است) فقط باید بفهمیم چه چیزی و کجا باید بنویسیم، هر یک از این ثبت ها مسئول چه چیزی هستند. پس شروع کردیم...

ثبت DDRx

DDRx مسئول جهت عملکرد پین های مربوطه میکروکنترلر است. هر پین می تواند ورودی یا خروجی باشد، سومی وجود ندارد. برای پیکربندی خروجی برای کار در حالت ورود رجیستر DDR، باید برای این پورت عدد 0 و برای خروجی عدد 1 بنویسید، فرض کنید باید PA6 را به عنوان ورودی و PA3 را به عنوان خروجی پیکربندی کنیم. چه کار می کنیم؟ درسته، بیت سوم رجیستر DDRA رو 1 قرار میدیم و روی بیت ششم همون رجیستر DDRA 0 مینویسیم.تموم شد!

ثبت PINx

ما نمی توانیم چیزی در این ثبت بنویسیم، این ثبت منحصراً برای خواندن داده ها در نظر گرفته شده است. این ثبات حاوی اطلاعاتی در مورد سطح سیگنال در پورت مربوطه است. همانطور که به یاد داریم، میکروکنترلر یک دستگاه دیجیتال است و سیگنال های روی پایه های آن می تواند زیاد باشد (منطقی 1) یا کم (منطقی 0). اگر بخواهیم بدانیم چه چیزی در ورودی PB4 داریم، پس به بیت چهارم ثبت PINB علاقه مندیم.

PORTx را ثبت کنید.

این رجیستر کمی پیچیده تر از موارد قبلی است. عملکرد آن بستگی به جهتی دارد که پین ​​های میکروکنترلر در آن کار می کنند. اگر از پین به عنوان ورودی استفاده شود، رجیستر PORTx نوع ورودی را مشخص می کند. در اینجا دو گزینه ممکن وجود دارد:

PORTx = 1 - با این پیکربندی، یک ورودی با یک کشش (PullUp) دریافت می کنیم.

PORTX = 0 - ورودی امپدانس بالا (Hi-Z) - این بدان معنی است که مقاومت پورت آنقدر زیاد است که می توان آن را بی نهایت در نظر گرفت.

پس بیایید با ثبات PORTx ادامه دهیم. اگر خروجی به عنوان یک خروجی کار کند و رجیستر PORTx یکی باشد، خروجی یک سطح سیگنال بالا خواهد بود، به طور مشابه، PORTx \u003d 0 - سطح پایین.

بیایید یک مثال کوچک برای روشن شدن مطلب بزنیم 😉

بیایید پین PC4 را طوری پیکربندی کنیم که در حالت ورودی pull-up کار کند. برای انجام این کار، 0 (حالت ورودی) را در بیت چهارم رجیستر DDRC بنویسید و بیت چهارم را در رجیستر PORTC روی 1 قرار دهید (بالا کشیدن). همین.

در اصل، این تنها چیزی است که به نظریه مربوط می شود، ما بیشتر از این به کاوش نخواهیم پرداخت. باقی مانده است که سنت ها را رعایت کنید و با دیود بازی کنید. اجازه دهید دیود به پین ​​PV5 متصل شود. بیایید او را پلک بزنیم! و اول از همه، بیایید یک پروژه ایجاد کنیم. من همانطور که قبلاً گفتم از AVR Studio 5 استفاده می کنم و به عنوان یک کنترلر ATMega88 مورد علاقه خود را انتخاب می کنم)

// فایل مورد نیاز را وصل کنید#عبارتند از /*******************************************************************/ // یک تابع ساده برای ایجاد تاخیرتاخیر خالی (زمان int بدون علامت) (int بدون علامت i = 0 ؛ برای (i = 0 ؛ i< time ; i++ ) ; } /*******************************************************************/ // خروجی ما را مقداردهی کنید، روی خروجی کار می کند void initAll() (DDRB = 0b00100000 ;) /*******************************************************************/ // بدنه واقعی تابع main(). int main(void) (initAll() ; while (1) (// دیود را روشن کنید PORTB = 0b00100000 ؛ // تأخیر استراحت (50000) ؛ // دیود را خاموش کنید PORTB = 0b00000000 ؛ تاخیر (5000) /*******************************************************************/

اولین ارتباط ما با این است میکروکنترلرهای AVR. به زودی، در صورت امکان، کل حاشیه آنها را در نظر خواهیم گرفت، و سپس می توانیم چیز جالب تری را راه بیندازیم.

اکنون شما این را می خوانید و فکر می کنید - حافظه، رجیسترها، پشته و غیره خوب هستند. اما شما نمی توانید آن را احساس کنید، نمی توانید آن را ببینید. مگر اینکه در شبیه ساز، اما من می توانم در دلفی با همان شرایط کدنویسی کنم. گوشت کجاست!!!

در دوره های دیگر آنجا، تقریباً از اولین خطوط، آنها کار مهمی انجام می دهند - آنها با یک دیود پلک می زنند و می گویند که این Hello World ما است. و اینجا؟ ژید؟؟؟

بله، بله، بله، شما را درک می کنم. علاوه بر این، احتمالاً قبلاً به سمت رقبای خود دویدید و به آنها یک دیود چشمک زدید؛)))) هیچ چیز، قابل بخشش نیست.

من فقط نمی خواستم در همان پلک زدن دیدودیک ها متوقف شوم، و پیشرفت مستلزم درک روشنی از مبانی و اصول است - یک پایگاه نظری قدرتمند. اما اکنون زمان تمرین است.

ما قبلاً در مورد پورت ها صحبت کرده ایم، شما قبلاً یک الگوی برنامه دارید، بنابراین بیایید بلافاصله شروع کنیم.

ابزار
کار با پورت ها معمولا به معنای کار با بیت هاست. این برای قرار دادن یک بیت، تنظیم مجدد، کمی معکوس است. بله، البته، دستورات راحت در اسمبلر وجود دارد

cbi/sbi، اما آنها فقط در یک محدوده آدرس کوچک (از 0 تا 1F) کار می کنند، بنابراین اجازه دهید ابتدا ماکروهای جهانی بنویسیم تا بتوانیم در آینده از آنها استفاده کنیم و نگران فضای آدرس نباشیم.

ماکروها نامیده خواهند شد:

  • SETB بایت، بیت، دما
  • CLRB بایت، بیت، دما
  • INVB بایت، بیت، دما، temp2

علاوه بر این، هنگام کار با بیت های RVV پایین (آدرس 0-1F)، ممکن است مقدار پارامتر TEMP مشخص نشود - به هر حال جایگزین نخواهد شد. به استثنای دستورات وارونگی، ثبات های میانی در آنجا مورد نیاز خواهند بود.

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

  • SETBM بایت، بیت
  • CLRBM بایت، بیت
  • INVBM بایت، بیت

در اینجا کد منبع آنها است. همانطور که می بینید، شرایط زبان ماکرو به طور فعال استفاده می شود، که امکان ایجاد ماکروهای جهانی را فراهم می کند. کامپایلر متوجه می شود که کدام نسخه را در کجا قرار دهد :)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 < 0x20 SBI @0,@1 .else .if @0<0x40 PUSH R17 IN R17,@0 ORI R17,1<<@1 OUT @0,R17 POP R17 .else PUSH R17 LDS R17,@0 ORI R17,1<<@1 STS @0,R17 POP R17 .endif .endif .ENDM ;SET BIT with REG .MACRO SETB .if @0 < 0x20 ; Low IO SBI @0,@1 .else .if @0<0x40 ; High IO IN @2,@0 ORI @2,1<<@1 OUT @0,@2 .else ; Memory LDS @2,@0 ORI @2,1<<@1 STS @0,@2 .endif .endif .ENDM ;............................................................. ;Clear BIT with REG .MACRO CLRB .if @0 < 0x20 ; Low IO CBI @0,@1 .else .if @0<0x40 ; High IO IN @2,@0 ANDI @2,~(1<<@1) OUT @0,@2 .else ; Memory LDS @2,@0 ANDI @2,~(1<<@1) STS @0,@2 .endif .endif .ENDM ;Clear BIT with STACK .MACRO CLRBM .if @0 < 0x20 CBI @0,@1 .else .if @0<0x40 PUSH R17 IN R17,@0 ANDI R17,~(1<<@1) OUT @0,R17 POP R17 .else PUSH R17 LDS R17,@0 ANDI R17,~(1<<@1) STS @0,R17 POP R17 .endif .endif .ENDM ;............................................................. .MACRO INVB .if @0 < 0x40 IN @2,@0 LDI @3,1<<@1 EOR @3,@2 OUT @0,@3 .else LDS @2,@0 LDI @3,1<<@1 EOR @2,@3 STS @0,@2 .endif .ENDM .MACRO INVBM .if @0 < 0x40 PUSH R16 PUSH R17 IN R16,@0 LDI R17,1<<@1 EOR R17,R16 OUT @0,R17 POP R17 POP R16 .else PUSH R16 PUSH R17 LDS R16,@0 LDI R17,1<<@1 EOR R17,R16 STS @0,R17 POP R17 POP R16 .endif .ENDM ;= End macro.inc ========================================

;= شروع macro.inc ====================================== ;تنظیم بیت با پشته .MACRO SETBM .if @0< 0x20 SBI @0,@1 .else .if @0<0x40 PUSH R17 IN R17,@0 ORI R17,1<<@1 OUT @0,R17 POP R17 .else PUSH R17 LDS R17,@0 ORI R17,1<<@1 STS @0,R17 POP R17 .endif .endif .ENDM ;SET BIT with REG .MACRO SETB .if @0 < 0x20 ; Low IO SBI @0,@1 .else .if @0<0x40 ; High IO IN @2,@0 ORI @2,1<<@1 OUT @0,@2 .else ; Memory LDS @2,@0 ORI @2,1<<@1 STS @0,@2 .endif .endif .ENDM ;............................................................. ;Clear BIT with REG .MACRO CLRB .if @0 < 0x20 ; Low IO CBI @0,@1 .else .if @0<0x40 ; High IO IN @2,@0 ANDI @2,~(1<<@1) OUT @0,@2 .else ; Memory LDS @2,@0 ANDI @2,~(1<<@1) STS @0,@2 .endif .endif .ENDM ;Clear BIT with STACK .MACRO CLRBM .if @0 < 0x20 CBI @0,@1 .else .if @0<0x40 PUSH R17 IN R17,@0 ANDI R17,~(1<<@1) OUT @0,R17 POP R17 .else PUSH R17 LDS R17,@0 ANDI R17,~(1<<@1) STS @0,R17 POP R17 .endif .endif .ENDM ;............................................................. .MACRO INVB .if @0 < 0x40 IN @2,@0 LDI @3,1<<@1 EOR @3,@2 OUT @0,@3 .else LDS @2,@0 LDI @3,1<<@1 EOR @2,@3 STS @0,@2 .endif .ENDM .MACRO INVBM .if @0 < 0x40 PUSH R16 PUSH R17 IN R16,@0 LDI R17,1<<@1 EOR R17,R16 OUT @0,R17 POP R17 POP R16 .else PUSH R16 PUSH R17 LDS R16,@0 LDI R17,1<<@1 EOR R17,R16 STS @0,R17 POP R17 POP R16 .endif .ENDM ;= End macro.inc ========================================

با گذشت زمان، وقتی در اسمبلر می نویسید، تعداد زیادی از این ماکروها وجود دارد. آنها در یک فایل جداگانه خارج می شوند و به سادگی به هر یک از پروژه های شما متصل می شوند و نوشتن کد آسان و لذت بخش می شود.

اما برگردیم به کد،
بیایید یک LED چشمک بزنیم، پس بالاخره؟

البته مشکلی نیست ال ای دی ها از قبل روی برد دمو نصب شده اند، چرا از آنها استفاده نکنید؟ آنها روی پین های پورت PD4، PD5، PD7 آویزان می شوند. شما فقط باید جامپر بپوشید.

; ورودی سخت افزار داخلی ==================================== SETB DDRD,4,R16 ; DDRD.4 = 1 SETB DDRD,5,R16 ; DDRD.5 = 1 SETB DDRD,7,R16 ; DDRD.7 = 1 ; پایان سخت افزار داخلی ===================================

باقی مانده است که دیودهایمان را روشن کنیم. آنها با نوشتن بیت ها در رجیستر PORT روشن می شوند. این قبلاً در بخش اصلی برنامه انجام شده است.

; اصلی ================================================= ======= اصلی: SETB PORTD,4,R16; چراغ LED1 SETB PORTD,7,R16; چراغ LED3 JMP اصلی ; پایان اصلی ================================================ ====

ما کامپایل می کنیم، می توانید آن را در ردیاب اجرا کنید، بلافاصله خواهید دید که چگونه بیت ها تغییر می کنند. ما در حال فلش زدن هستیم و پس از کلیک بر روی RESET و تخلیه بوت لودر (البته که ندارید) این عکس را مشاهده خواهید کرد:


و برای نسخه دوم


که در! یک جورهایی خسته کننده است. به آنها چشمک بزنیم.

بیایید ماکروهایمان را جایگزین کنیم.

; اصلی ================================================= ======= اصلی: SETB PORTD,4,R16; چراغ LED1 INVB PORTD,7,R16,R17; معکوس LED3 JMP اصلی ; پایان اصلی ================================================ ====

روشن، چشمک زد...

اما انجیر - هر دو روشن است، اما یکی کمی تاریک است. در واقع سوسو می زند، اما بسیار بسیار سریع. اگر یک اسیلوسکوپ را در خروجی PD7 فرو کنید، خواهید دید که سطح با فرکانس دیوانه‌وار تغییر می‌کند:


چه باید کرد؟ واضح است که سرعت را کاهش دهید. چگونه؟ ساده ترین راه، که در اکثریت قریب به اتفاق آموزش ها و شروع سریع تمرین می شود، تاخیر احمقانه است. آن ها دریافت کدی مانند:

; اصلی ================================================= ======= اصلی: SETB PORTD,4,R16; چراغ LED1 INVB PORTD,7,R16,R17; معکوس LED3 RCALL تاخیر JMP اصلی ; پایان اصلی ================================================ ==== ; = رویه=============================================== == .equ LowByte = 255 .equ MedByte = 255 .equ HighByte = 255 تاخیر: LDI R16,LowByte ; بارگذاری سه بایت LDI R17,MedByte. گزیده ما LDI R18، حلقه HighByte: SUBI R16,1 ; تفریق 1 SBCI R17.0 ; فقط C SBCI R18.0 را کم کنید. فقط حلقه C BRCC را کم کنید. در صورت عدم وجود انتقال - انتقال RET ; مراحل پایانی ==============================================

ما آن را فلش کردیم، راه اندازی کردیم ... اوه بله، اکنون چشمک زدن قابل توجه خواهد بود.

با پارامترهای 255.255.255 سرعت شاتر در 8 مگاهرتز حدود 2.1 ثانیه خواهد بود. می توانید مدت زمان تاخیر را چند بایت دیگر افزایش دهید. سپس می توانید حداقل یک ساعت شارژ کنید.

اما این روش ناقص است، حالا دلیل آن را به شما نشان خواهم داد.

بیایید یک دکمه اضافه کنیم. اجازه دهید LED3 در وارونگی چشمک بزند. و آن را طوری می کنیم که با فشار دادن دکمه، LED1 روشن و زمانی که آزاد شد، LED2 روشن باشد.

بیایید ساعت A را به عنوان یک دکمه در نظر بگیریم، آن را به پورت PD6 وصل کنیم.


برای ورژن II هم همینطوره. فقط دکمه را از گروه دکمه ها بردارید و خروجی PD6 کنترلر را به پین ​​COL1 روی صفحه کلید وصل کنید.

فقط به جامپرهایی که روی جامپرهای فیلد دکمه هستند توجه کنید. آبی ها هستند. و همچنین یک جامپر مشکی نامحسوس که با فلش سمت راست نشان داده می شود. ستون سمت چپ دکمه ها را به زمین متصل می کند. روی پین‌های GND و ROW1 می‌چرخد. همه چیز روی تابلو امضا شده است.

بررسی دکمه توسط دستور SBIC انجام می شود، اما ابتدا باید مقداردهی اولیه شود. DDR=0، PORT=1 - ورودی pull-up.

این خطوط را به بخش مقداردهی اولیه (Internal Hardware Init) اضافه کنید:

; اصلی ================================================= ======= اصلی: SBIS PIND,6 ; اگر دکمه فشار داده شود - انتقال RJMP BT_Push SETB PORTD,5 ; روشن کردن LED2 CLRB PORTD,4 ; خاموش کردن LED1 بعدی: INVB PORTD,7,R16,R17. معکوس LED3 RCALL تاخیر JMP اصلی BT_Push: SETB PORTD,4 ; روشن کردن LED1 CLRB PORTD,5 ; خاموش کردن LED2 RJMP بعدی پایان اصلی ================================================ ====

خوب، کار می کند. دکمه فشرده شده است - دیودها تغییر می کنند. سومی با خوشحالی چشمک می زند. اما یک نکته وجود دارد:

برنامه کند می شود! من دکمه را فشار دادم، اما تصویر تغییر نکرد، باید صبر کنید، آن را نگه دارید ... چرا؟ و این به دلیل bydlokoding ما است.

یادتان هست که به شما گفتم تاخیرهای احمقانه ای که در آن MK هیچ کاری انجام نمی دهد، شر جهنمی است؟ اینجا! حالا خودت دیدی خوب، باید با شر مبارزه کرد. چگونه؟ خوب، من قبلاً هم این را گفتم - انجام یک چرخه پیوسته با پرچم ها. حداقل یک کار مفید به تاخیر ما اضافه کنید.

اندام بشکه ای
اکنون به شما نشان خواهم داد که چگونه می توانید یک ارگ بشکه ای دیجیتال بسازید. یادت هست چطوری درست شد؟

درام با میخ های بیرون زده و فنرها در رنگ های مختلف وجود دارد. میخ‌ها می‌چرخند، چشمه‌ها تکان می‌خورند - قلقلک می‌زنند. به نظر می رسد raskolbasny Mouzon. و چه می شود اگر گردی ما به شکل یک روبان بزرگ شود. آیا این درست نیست که ناخن ها شبیه به یک واحد هستند؟ ;))))

نوار یک شمارنده خواهد بود که از صفر، مثلاً به FF.FF.FF.FF و سپس دوباره به صفر یا مقداری دیگر، تا آنجایی که ما نیاز داریم و انجام خواهیم داد، شمارش می کند. و زیربرنامه های ما نقش فنرها را بازی می کنند که به مکان های مناسب چسبیده اند - ثابت آنها را با مقدار فعلی شمارنده مقایسه می کنند.

تصادفی؟ بیایید یک شیطنت بکنیم!

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

فرض کنید اندام بشکه ای از 0 تا 1000 می شمارد و باید دیود را 10 بار پلک بزنیم. نیازی به چسباندن 10 هندلر با مقادیر مختلف نیست. یکی کافی است، اما برای اینکه مقدار **10 را بگیرد. بقیه چیزها برای ما مهم نیست. و روی 0010، 0110، 0210، 0310، 0410، 0510، 0610، 0710، 0810، 0910 کار خواهد کرد. فواصل مکررتر نیز طبق نیاز ما تقسیم می شوند، کافی است وارد دسته دیگری شویم. در اینجا فقط لازم است فراموش نکنید که ارقام ارشد nafig را قطع نکنید تا تداخل نداشته باشید.

بیا شروع کنیم. ابتدا، بیایید شمارنده خود را در بخش داده ایجاد کنیم:

LDS R16,CCNT LDS R17,CCNT+1 LDS R18,CCNT+2 LDS R19,CCNT+3

همه چیز، اکنون در R16 جوانترین بایت شمارنده ما، و در R19 قدیمی ترین.

رجیسترها را می توان از قبل به پشته فشار داد، اما من توصیه بهتری به شما خواهم کرد - هنگام نوشتن یک برنامه، به الگوریتم فکر کنید به گونه ای که از ثبات ها به عنوان یک TEMP پیوسته استفاده کنید که داده های آن فقط در اینجا و اکنون مرتبط هستند. و آنچه در روش بعدی برای آنها اتفاق می افتد دیگر مهم نیست - همه چیزهایی که باید در RAM ذخیره شوند.

شما می توانید این کار را به این صورت انجام دهید:

LDI R20.1 ; ما به یک CLR R15 نیاز داریم. و همچنین یک صفر. اضافه کردن R16, R20; اگر رجیستر 255 باشد، 1 را اضافه می کنیم، C ADC R17، R15 خواهد بود. 0+C ADC R18,R15 را اضافه کنید. 0+С ADC R19,R15 را اضافه کنید. 0+C اضافه کنید

ما مجبور شدیم دو ثبات دیگر را برای ذخیره ثابت های جمع خود صرف کنیم. همه از این واقعیت است که AVR قادر به اضافه کردن ثبات با شماره مستقیم نیست. اما او می تواند بخواند.

من قبلاً نشان داده ام که R-(-1)=R+1، اما هیچ کس ما را منع نمی کند که همان ترفند را در اینجا ترتیب دهیم - جمع را از طریق تفریق انجام دهیم.

1 2 3 4 SUBI R16، (-1) SBCI R17، (-1) SBCI R18، (-1) SBCI R19، (-1)

SUBI R16، (-1) SBCI R17، (-1) SBCI R18، (-1) SBCI R19، (-1)

افزایشی از یک عدد چهار بایتی به ما می دهد R19:R18:R17:R16

و حالا من مقداری جادوی عدد صحیح را به شما نشان خواهم داد.
چرا کار خواهد کرد؟ خودت نگاه کن:

SUBI R16، (-1) در واقع R16 - 255 است و تقریباً در همه موارد به ما وامی از دسته بعدی - C می دهد. و تعداد بیشتری در ثبت باقی می ماند.

آن ها ببینید این ریاضی چگونه کار می کند، شماره را در کدهای اضافی به خاطر بسپارید. من در یک مثال اعشاری چهار رقمی نشان خواهم داد. ما فقط چهار تفاوت داریم، نه بیشتر، نه کمتر. یک عدد منفی 0-1 است درست است؟ خوب.

1 C 0000-1=9999+C

آن ها ما، همانطور که بودیم، 1 را از 1 C 0000 پنج رقمی برداشتیم، اما فقط چهار رقم داریم! دریافت کد اضافی 9999 و پرچم وام C (نشان دهنده وجود وام)

آن ها در ریاضی عدد صحیح ما 9999=-1 :) بررسی -1+1 = 0 آسان است درست است؟

9999+1 = 1 C 0000 درست است! :))) و 1 رقم مهم به سادگی در ظرفیت قرار نمی گیرد و وارد پرچم حمل C می شود که همچنین نشان دهنده سرریز است.

خوب، حالا بیایید R-(-1) را بگیریم و انجام دهیم. اجازه دهید R=4 باشد

1 C 0004-9999 = 0005+C

پس آن را گرفتند و از طریق تفریق جمع کردند. فقط جادو، درسته؟ ;)

شوخی اسمبلر این است که اینها فقط دستور هستند، نه یک دکترین و نه یک قانون. و دستوراتی که شامل محاسبات علامت می شوند را می توان در هر جایی استفاده کرد، به شرطی که نتیجه مورد نیاز ما را بدهد!

اینجا و اینجا - شمارنده ما نیز بدون علامت است، اما ما از ویژگی های حساب دیفرانسیل و انتگرال استفاده می کنیم زیرا برای ما راحت تر است.

پرچم C فقط زمانی ظاهر نمی‌شود که عدد 255 (در مثال اعشاری 9999) را علامت بزنیم، سپس 255-255 = 0 خواهد بود و فقط Z ظاهر می‌شود، اما ما به آن نیازی نداریم.

STS CCNT,R16 STS CCNT+1,R17 STS CCNT+2,R18 STS CCNT+3,R19

کد افزایشی یک ثابت چهار بایتی در حافظه را می توان در یک ماکرو جمع کرد تا کد را به هم نریزد.

; اصلی ================================================= ======= اصلی: SETB PORTD,4 ; چراغ LED1 INVB PORTD,7,R16,R17; LED3 معکوس بعدی: INCM CCNT JMP اصلی

حالت اشکال زدایی را شروع کنید و یک نقطه شکست (F9) روی برچسب Main قرار دهید و مکان نما را به اولین نقطه شکست هدایت کنید.

0xB6 (CCNT) 0x9F (CCNT+1) 0x04 (CCNT+2) 0x00 (CCNT+3)

اکنون فقط مقایسه تعداد با این بازیگران باقی مانده است.

چگونه مقایسه کنیم؟ بله، خیلی ساده است. همه چیز بستگی به چیزی دارد که می خواهیم به دست آوریم. اگر یک رویداد برای کل دوره شمارنده جهانی هوردی‌گوردی ما وجود داشته باشد، پس احمقانه، بایت به بایت. در این حالت دیود شما یک ثانیه پس از شروع چشمک می زند و سپس نیم ساعت صبر می کنید تا کل شمارنده چهار بایتی سرریز شود.

برای اینکه هر ثانیه چشمک بزند، باید هنگام مقایسه، بیت های بالای شمارنده جهانی را بپوشانید، گویی که عرض بیت آن نه 32 بیت، بلکه کمتر است (و بیشتر اوقات سرریز می شود).

بایت‌های پایین‌تر همانطور که هست مقایسه می‌شوند، و قدیمی‌ترین بایت فقط تا حداکثر رقم خود است، بقیه باید قطع شوند.

آن ها مهم ترین بیت برای این مورد CCNT+2=0x04 است اگر در نمایش باینری پس 0x04 = 00000 100 بنابراین، ما یک شمارنده چهار رقمی داریم که به معنای رویدادی با ماسک است

00 04 9F B6 ( 00000000 00000 100 10011111 10110110)

قبل از سرریز چند بار دوفیگا وجود خواهد داشت. ببینید، من صفرها را به صورت پررنگ برجسته کردم. ما به هیچ وجه قدیمی‌تر را با هم مقایسه نمی‌کنیم، اما قبل از قدیمی‌تر، باید از طریق AND روی ماسک 00000111 فشار دهید تا بیت‌های بالا را قطع کنید.

آنها هنوز باید قبل از سرریز و صفر کردن شمارنده پر شوند. اما اگر آنها را پنهان کنیم، سرنوشت بعدی آنها ما را آزار نمی دهد. بذار تیک تا اومدن دوم برامون مهم نیست.

LDS R16,CCNT ; ما اعداد را در رجیسترهای LDS R17,CCNT+1 LDS R18,CCNT+2 ANDI R18,0x07 بارگذاری می کنیم. ما یک ماسک CPI R16,0xB6 را تحمیل می کنیم. مقایسه بایت به بایت BRNE NoMatch CPI R17.0x9F BRNE NoMatch CPI R18.0x04 BRNE NoMatch ; اگر مطابقت داشت، اکشن Match را انجام می دهیم: INVB PORTD,7,R16,R17 ; LED3 معکوس؛ مطابقت نداشت - این کار را نکنید :) NoMatch: بعدی: INCM CCNT ; چرخاندن اندام بشکه JMP اصلی

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

این فقط به طور قابل توجهی کندتر از آنچه ما می خواستیم چشمک می زند. نه 1 ثانیه، بلکه 8. خوب، چه می خواستید - با اضافه کردن روش مقایسه، چرخه را با چند دستور دیگر طولانی کردیم. و اکنون نه برای 25 چرخه، بلکه برای 36 انجام می شود. دوباره همه اعداد را محاسبه کنید :)))))))

اما این بیشترین ttimes نیست! شوخی این است که شما بخشی از کد را در حال اجرا دارید، و برخی دیگر نه - دستورات مقایسه و انتقال. بنابراین، محاسبه دقیق تأخیر بر اساس چرخه ها آسان تر است - باید برای هر تکرار محاسبه کنید که چه زمانی و چه تعداد انتقال خواهید داشت، چند چرخه طول می کشد ...

و اگر کد حتی بزرگتر باشد، در نهایت لوله و خطا با هر تکرار جمع می شود!

اما اگر کد پردازش دکمه را اضافه کنید:

; اصلی ================================================= ======= اصلی: SBIS PIND,6 ; اگر دکمه فشار داده شود - انتقال RJMP BT_Push SETB PORTD,5 ; روشن کردن LED2 CLRB PORTD,4 ; خاموش کردن LED1 بعدی: LDS R16,CCNT ; بارگذاری اعداد در رجیسترها LDS R17,CCNT+1 LDS R18,CCNT+2 ANDI R18.0x07 CPI R16.0xB6 ; مقایسه بایت به بایت BRNE NoMatch CPI R17.0x9F BRNE NoMatch CPI R18.0x04 BRNE NoMatch ; اگر مطابقت داشت، اکشن Match را انجام می دهیم: INVB PORTD,7,R16,R17 ; LED3 معکوس؛ مطابقت نداشت - این کار را نکنید :) NoMatch: NOP INCM CCNT JMP اصلی BT_Push: SETB PORTD,4 ; روشن کردن LED1 CLRB PORTD,5 ; خاموش کردن LED2 RJMP بعدی پایان اصلی ================================================ ====

سپس خواهیم دید که اثری از ترمزها باقی نمانده است. دکمه ها فوراً به فشار دادن پاسخ می دهند و LED خود به خود چشمک می زند. چند وظیفه ای! :)

به طور کلی، گردی در جایی که محاسبات دقیق مورد نیاز است مناسب نیست. اما اگر کار از سری "شما باید به طور دوره ای تکان بخورید و مهم نیست دقیقا چقدر" باشد، این کار است. زیرا منابع سخت افزاری را مانند تایمر اشغال نمی کند.

به عنوان مثال، به طور دوره ای صفحه کلید را اسکن کنید، مثلاً هر 2048 چرخش حلقه اصلی. خودتان تخمین بزنید که چه عددی را برای مقایسه باید بارگذاری کنید و چه ماسکی را اعمال کنید :)

می توانید دانلود کنید و نگاهی بیندازید، آن را ردیابی کنید تا ببینید که چگونه همه چیز می چرخد.

و برای محاسبات دقیق زمان، تایمرهایی وجود دارد. اما بحث جداگانه ای در مورد آنها وجود دارد.

  • آموزش

بهره برداری از پورت های ورودی/خروجی

با مطالعه این مطالب، که در آن همه چیز با جزئیات زیاد و با تعداد زیادی مثال توضیح داده شده است، می توانید به راحتی بر پورت های ورودی / خروجی میکروکنترلرهای AVR مسلط و برنامه ریزی کنید.

یک مثال در یک میکروکنترلر در نظر گرفته خواهد شد ATMega8 .

ما برنامه را در آن می نویسیم Atmel Studio 6.0 .

ما مدار را در آن شبیه سازی خواهیم کرد Proteus 7 Professional .

میکروکنترلر از طریق پورت های ورودی/خروجی با دنیای خارج ارتباط برقرار می کند. طرح پورت I/O در دیتاشیت نشان داده شده است:

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

هر پورت میکروکنترلر AVR (معمولاً A، B و گاهی اوقات C یا حتی D نامیده می شود) دارای 8 بیت است که هر کدام به یک پایه خاص از شاسی متصل می شوند. هر پورت دارای سه رجیستر ویژه است DDRx, PORTxو پینکس(که در آن x حرف پورت A، B، C یا D است). هدف از ثبت:

DDRx– بیت های پورت x را برای ورودی یا خروجی تنظیم کنید.

PORTx– کنترل وضعیت خروجی پورت x (اگر بیت مربوطه به عنوان یک خروجی پیکربندی شده باشد)، یا با اتصال یک مقاومت کششی داخلی (اگر بیت مربوطه به عنوان ورودی پیکربندی شده باشد).

پینکس- سطوح بیت منطقی پورت x را بخوانید.

پینثبت خوانده شده است. فقط از آن می توان خواند. در ثبت نام PINxnحاوی اطلاعاتی در مورد سطح منطقی فعلی در پین های پورت است. صرف نظر از تنظیمات پورت. بنابراین اگر بخواهیم بدانیم چه چیزی در ورودی داریم، بیت مربوطه رجیستر را می خوانیم PINxn. علاوه بر این، دو مرز وجود دارد: مرز صفر تضمین شده و مرز یک تضمین شده - آستانه هایی که فراتر از آنها می توانیم به وضوح سطح منطقی فعلی را به وضوح تعیین کنیم. برای منبع تغذیه پنج ولت، اینها به ترتیب 1.4 و 1.8 ولت هستند. یعنی وقتی ولتاژ از حداکثر به حداقل می رسد، بیت های موجود در رجیستر پینکستنها زمانی که ولتاژ به کمتر از 1.4 ولت کاهش یابد، از 1 به 0 تغییر می کند، اما زمانی که ولتاژ از حداقل به حداکثر افزایش یابد، بیت تنها زمانی از 0 به 1 تغییر می کند که ولتاژ به 1.8 ولت برسد. یعنی یک هیسترزیس سوئیچینگ از 0 به 1 وجود دارد که سوئیچینگ آشفته تحت تأثیر تداخل و تداخل را حذف می کند و همچنین خواندن اشتباه سطح منطقی بین آستانه های سوئیچینگ را حذف می کند.

با کاهش ولتاژ تغذیه، البته این آستانه ها نیز کاهش می یابد.

DDRxnثبت جهت پورت است. پورت در یک زمان خاص می تواند ورودی یا خروجی باشد (اما برای وضعیت بیت های PINxn، این مهم نیست. خواندن از PINxnارزش واقعی همیشه ممکن است).

DDRxy= 0 - خروجی به عنوان یک ورودی کار می کند.

DDRxy= 1 - خروجی به عنوان یک OUTPUT کار می کند.

PORTxn- حالت کنترل وضعیت خروجی وقتی خروجی را روی ورودی تنظیم می کنیم، سپس از PORTxنوع ورودی بستگی دارد (Hi-Z یا PullUp، بیشتر در مورد آن در زیر).

هنگامی که پین ​​روی خروجی تنظیم می شود، مقدار بیت مربوطه در رجیستر PORTxوضعیت خروجی را تعریف می کند. اگر PORTxn=1 سپس خروجی log.1 است، اگر PORTxn=0 سپس خروجی log.0 است.

هنگامی که پایه برای ورودی پیکربندی شده است، سپس اگر PORTxn=0، سپس خروجی در حالت Hi-Z است. اگر PORTxn\u003d 1 سپس خروجی در حالت PullUp با مقاومت pull-up 100k به قدرت است.

جدول. پیکربندی پین پورت

DDRxn PORTxn I/O نظر
0 0 I (ورودی) ورودی ورودی امپدانس بالا. (من استفاده از آن را توصیه نمی کنم، زیرا ممکن است تداخل منبع تغذیه ایجاد شود)
0 1 I (ورودی) ورودی مقاومت داخلی کشیده شد.
1 0 O (خروجی) خروجی خروجی کم است.
1 1 O (خروجی) خروجی خروجی زیاد است.

تصویر کلی عملیات بندر در شکل ها نشان داده شده است:

برنج. DDRxn=0 PORTxn=0 - حالت: HI-Z– ورودی امپدانس بالا

برنج. DDRxn=0 PORTxn=1 - حالت: بالا بکش– ورودی با pull-up to log.1.

برنج. DDRxn=1 PORTxn=0 - حالت: خروجی– خروجی log.0 (تقریبا GND)

برنج. DDRxn=1 PORTxn=1 - حالت: خروجی- در خروجی log.1. (تقریبا VCC)

ورود سلام-Z- حالت ورودی با امپدانس بالا
این حالت به صورت پیش فرض فعال است. همه سوئیچ ها باز هستند و مقاومت پورت بسیار بالاست. اصولاً در مقایسه با سایر حالت ها می توان آن را بی نهایت دانست. یعنی از نظر الکتریکی ، خروجی ، همانطور که بود ، اصلاً به هیچ جایی وصل نمی شود و روی چیزی تأثیر نمی گذارد. ولی! در عین حال، دائماً وضعیت خود را در رجیستر می خواند پینو ما همیشه می توانیم بفهمیم که در ورودی چه چیزی داریم - یک یا صفر. این حالت برای گوش دادن به هر گذرگاه داده خوب است، زیرا. روی اتوبوس تاثیری نداره اگر ورودی در هوا باشد چه اتفاقی می افتد؟ و در این مورد، بسته به پیکاپ های خارجی، تداخل الکترومغناطیسی و به طور کلی، بر روی فاز ماه و آب و هوا در مریخ، ولتاژ روی آن می پرد (روشی ایده آل برای برش اعداد تصادفی!). اغلب، در این مورد، یک سینوس ناپایدار 50 هرتز روی پورت، یک پیکاپ از شبکه 220 ولت است و در رجیستر پین 0 و 1 با فرکانس حدود 50 هرتز تغییر می کند

ورود بالا بکش- ورودی کششی
در DDRxn=0 و PORTxn=1، سوئیچ pull-up بسته می شود و یک مقاومت 100 کیلو اهم به خط وصل می شود که بلافاصله خطی را که به هیچ جا وصل نشده است به حالت log.1 می رساند. هدف از سفت شدن واضح است - جلوگیری از تغییر هرج و مرج در وضعیت در ورودی تحت تأثیر پیکاپ ها. اما اگر یک صفر منطقی در ورودی ظاهر شود (خط توسط یک دکمه یا میکروکنترلر / میکرو مدار دیگر به زمین بسته شود)، یک مقاومت ضعیف 100 کیلو اهم نمی تواند ولتاژ روی خط را در سطح log نگه دارد. ورودی log.0 خواهد بود.

حالت خروج
در اینجا، من فکر می کنم، همه چیز واضح است - اگر لازم باشد log.1 را به پورت صادر کنیم، پورت خروجی را روشن می کنیم ( DDRxn=1) و خروجی log.1 ( PORTxn\u003d 1) - در همان زمان، سوئیچ بالایی بسته می شود و ولتاژ نزدیک به برق در خروجی ظاهر می شود. و اگر به log.0 نیاز دارید، پورت خروجی را روشن کنید ( DDRxn=1) و خروجی log.0 ( PORTxn\u003d 1) - در همان زمان، دریچه پایین باز می شود که حدود صفر ولت در خروجی می دهد.