• دستگاه و برنامه نویسی میکروکنترلرهای AVR. میکروکنترلر و نحوه شکست آن مبانی برنامه نویسی میکروکنترلر AVR

    سلام حبراژیتل عزیز!

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

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

    1. برنامه نویس
    گزینه های زیادی در بازار وجود دارد - از ارزان ترین برنامه نویسان ISP (برنامه نویسی درون سیستم) با چند دلار تا برنامه نویسان دیباگر قدرتمند با چند صد دلار. بدون داشتن تجربه زیادی در این تجارت، برای شروع تصمیم گرفتم یکی از ساده ترین و ارزان ترین - USBasp را امتحان کنم. به موقع در eBay با قیمت 12 دلار خریداری شده است، اکنون می توان آن را حتی با 3-4 دلار پیدا کرد. در واقع این نسخه چینی برنامه نویس توماس فیشل است. در مورد او چه بگویم؟ فقط یک چیز - کار می کند. علاوه بر این، تعداد زیادی از کنترلرهای AVR سری ATmega و ATtiny را پشتیبانی می کند. تحت لینوکس به درایور نیاز ندارد.

    برای سیستم عامل باید خروجی های برنامه نویس VCC، GND، RESET، SCK، MOSI، MISO را با خروجی های مربوطه میکروکنترلر متصل کنید. برای سادگی، من یک مدار کمکی درست روی تخته نان ساخته ام:

    در سمت چپ روی برد همان میکروکنترلری است که قرار است فلش کنیم.

    2. میکروکنترلر
    من با انتخاب میکروکنترلر زیاد اذیت نشدم و ATmega8 را از Atmel گرفتم - 23 پین ورودی / خروجی، دو تایمر 8 بیتی، یکی 16 بیتی، فرکانس - تا 16 مگاهرتز، کم مصرف (1-3.6 میلی آمپر) ، ارزان (2 دلار). به طور کلی، برای شروع - بیش از اندازه کافی.

    تحت لینوکس، باندل avr-gcc + avrdude برای کامپایل و آپلود میان‌افزار در کنترل‌کننده به خوبی کار می‌کند. نصب بی اهمیت است. با پیروی از دستورالعمل ها، می توانید تمام نرم افزارهای لازم را در چند دقیقه نصب کنید. تنها چیزی که باید به آن توجه داشت این است که avrdude (نرم افزار نوشتن کنترلر) ممکن است برای دسترسی به برنامه نویس به حقوق فوق العاده کاربر نیاز داشته باشد. راه حل این است که آن را از طریق sudo اجرا کنید (ایده خوبی نیست)، یا حقوق ویژه udev تنظیم کنید. نحو ممکن است در نسخه های مختلف سیستم عامل متفاوت باشد، اما در مورد من (Linux Mint 15) افزودن قانون زیر به فایل /etc/udev/rules.d/41-atmega.rules کار می کند:

    # برنامه نویس USBasp SUBSYSTEM=="usb", ATTR(idVendor)=="16c0", ATTR(idProduct)=="05dc", GROUP="plugdev", MODE="0666"

    پس از آن، البته، شما باید سرویس را مجددا راه اندازی کنید
    راه اندازی مجدد سرویس udev
    شما می توانید بدون مشکل مستقیماً از خط فرمان کامپایل و فلش کنید (چه کسی در آن شک دارد) ، اما اگر پروژه های زیادی وجود دارد ، نصب افزونه راحت تر است و همه چیز را مستقیماً از محیط Eclipse انجام دهید.

    در ویندوز، باید یک درایور نصب کنید. در غیر این صورت هیچ مشکلی وجود ندارد. به خاطر علاقه علمی، تعدادی AVR Studio + eXtreme Burner را در ویندوز امتحان کردم. باز هم، همه چیز عالی کار می کند.

    شروع برنامه نویسی

    کنترلرهای AVR را می توان هم در اسمبلر ( اسمبلر AVR ) و هم در C برنامه ریزی کرد. در اینجا، به نظر من، هر کس باید بسته به کار خاص و ترجیحات خود، انتخاب کند. من شخصاً اول از همه شروع به انتخاب اسمبلر کردم. هنگام برنامه نویسی در اسمبلر، معماری دستگاه واضح تر می شود و این احساس به وجود می آید که مستقیماً در داخل کنترلر فرو می روید. علاوه بر این، من معتقدم در برنامه هایی که از نظر اندازه و عملکرد بسیار مهم هستند، دانش اسمبلر می تواند بسیار مفید باشد. پس از آشنایی با اسمبلر AVR، به C خزیدم.

    بعد از آشنایی با معماری و اصول اولیه تصمیم گرفتم مطلب مفید و جالبی را جمع آوری کنم. در اینجا دخترم به من کمک کرد، او شطرنج بازی می‌کند و یک عصر خوب گفت که می‌خواهم برای بازی‌ها یک تایمر داشته باشد. بام! اینجاست - ایده اولین پروژه! البته می‌توانید آنها را در همان eBay سفارش دهید، اما من می‌خواستم ساعت خودم را بسازم، با مشکی ... اوه ... با نشانگرها و دکمه‌ها. زودتر گفته شد!

    تصمیم گرفته شد از دو نشانگر LED 7 قسمتی به عنوان نمایشگر استفاده شود. 5 دکمه برای کنترل کافی بود - "Player 1"، "Player 2"، "Reset"، "Settings" و "Pause". خوب، در مورد نشانه های صوتی پایان بازی را فراموش نکنید. بنظر همینه شکل زیر طرح کلی برای اتصال میکروکنترلر به نشانگرها و دکمه ها را نشان می دهد. هنگام تجزیه کد منبع برنامه به آن نیاز خواهیم داشت:

    شرح پرواز

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

    Int main(void) (init_io(); init_data(); sound_off(); sei(); while(1) ( handle_buttons(); ) 0؛ )
    بیایید هر تابع را جداگانه در نظر بگیریم.

    Void init_io() (// تنظیم خروجی DDRB = 0xFF؛ DDRD = 0xFF؛ // تنظیم ورودی DDRC = 0b11100000؛ // مقاومت‌های بالاکش PORTC |= 0b00011111؛ // تایمر TIMSK = (1) را قطع می‌کند<

    راه‌اندازی پورت‌های I/O بسیار ساده است - یک عدد در رجیستر DDRx نوشته می‌شود (که در آن x حرفی است که پورت را مشخص می‌کند)، که هر بیت آن به این معنی است که آیا پین مربوطه یک دستگاه ورودی (مطابق با 0) خواهد بود یا یک عدد دستگاه خروجی (مربوط به 1). بدین ترتیب با ارسال عدد 0xFF به DDRB و DDRD پورت های خروجی B و D را ساختیم. بر این اساس، دستور DDRC = 0b11100000; 5 پایه اول پورت C را به پایه های ورودی و بقیه را به پایه های خروجی تبدیل می کند. Command PORTC |= 0b00011111; شامل مقاومت های کششی داخلی در 5 ورودی کنترلر است. طبق نمودار دکمه هایی به این ورودی ها متصل می شوند که با فشردن آن ها به زمین بسته می شوند. بنابراین کنترلر متوجه می شود که دکمه فشرده شده است.

    به دنبال آن دو تایمر، Timer0 و Timer1 تنظیم می شود. ما از اولی برای به روز رسانی نشانگرها استفاده می کنیم و از دومی برای شمارش معکوس زمان استفاده می کنیم، پس از تنظیم آن برای روشن شدن هر ثانیه. شرح مفصلی از تمام ثابت ها و روش تنظیم تایمر در یک بازه مشخص را می توان در مستندات ATmega8 یافت.

    وقفه در رسیدگی

    ISR (TIMER0_OVF_vect) ( display(؛ if (_buzzer > 0) ( _buzzer--; if (_buzzer == 0) sound_off(); ) ) ISR(TIMER1_COMPA_vect) ( if (ActiveTimer == 1 && Timer1 > 0) ( Timer1--; if (Timer1 == 0) process_timeoff(); ) if (ActiveTimer == 2 && Timer2 > 0) ( Timer2--; if (Timer2 == 0) process_timeoff(); ) )

    هنگامی که تایمر منقضی می شود، کنترل به کنترل کننده وقفه مناسب منتقل می شود. در مورد ما، این کنترل کننده TIMER0_OVF_vect است که رویه نمایش زمان را روی نشانگرها فراخوانی می کند و TIMER1_COMPA_vect است که شمارش معکوس را پردازش می کند.

    خروجی به اندیکاتورها

    Void display() ( display_number((Timer1/60)/10, 0b00001000); _delay_ms(0.25); display_number((Timer1/60)%10, 0b00000100); _delay_ms(0.25); display_number((Timer) , 0b00000010؛ _delay_ms(0.25); display_number((Timer1%60)%10, 0b00000001); _delay_ms(0.25); display_number((Timer2/60)/10, 0b1000000000); 60)%10، 0b01000000؛ _delay_ms(0.25)؛ display_number((Timer2%60)/10, 0b00100000); _delay_ms(0.25); display_number((Timer2%60)%10, 0b00000); = 0؛ ) void display_number (تعداد int، ماسک int) (PORTB = number_mask(شماره)؛ PORTD = mask;)

    تابع نمایش از روش نمایش پویا استفاده می کند. واقعیت این است که هر نشانگر فردی 9 مخاطب دارد (7 برای کنترل بخش، 1 برای یک نقطه و 1 برای قدرت). برای کنترل 4 رقم 36 پین لازم است. بیش از حد اسراف. بنابراین، خروجی ارقام روی یک نشانگر با چندین رقم بر اساس اصل زیر سازماندهی می شود:

    ولتاژ به طور متناوب به هر یک از کنتاکت های مشترک اعمال می شود، که به شما امکان می دهد با استفاده از همان 8 کنتاکت کنترل، عدد مورد نظر را در نشانگر مربوطه برجسته کنید. با فرکانس خروجی به اندازه کافی بالا، این تصویر برای چشم مانند یک تصویر ثابت به نظر می رسد. به همین دلیل است که هر 8 کنتاکت برق هر دو نشانگر در نمودار به 8 خروجی پورت D و 16 کنتاکت کنترل کننده سگمنت ها به صورت جفت وصل شده و به 8 خروجی پورت B متصل می شوند. عدد به هر یک از نشانگرها با تاخیر 0.25 میلی ثانیه. در پایان، تمام خروجی هایی که ولتاژ را به نشانگرها می دهند خاموش می شوند (فرمان PORTD = 0;). اگر این کار انجام نشود، آخرین رقم نمایش داده شده تا تماس بعدی با عملکرد نمایشگر روشن می‌ماند، که باعث درخشش آن نسبت به بقیه می‌شود.

    رسیدگی به کلیک ها

    void handle_buttons() ( handle_button(KEY_SETUP)؛ handle_button(KEY_RESET); handle_button(KEY_PAUSE); handle_button(KEY_PLAYER1); handle_button(KEY_PLAYER2)؛ ) void handle_button (KEY_RESET) = SETUP_BIT؛ شکست؛ مورد KEY_RESET: بیت = RESET_BIT؛ شکست؛ مورد KEY_PAUSE: بیت = PAUSE_BIT؛ شکست؛ مورد KEY_PLAYER1: بیت = PLAYER1_BIT؛ شکست؛ مورد KEY_PLAYER2: بیت = PLAYER2_BIT؛ شکستن؛ اگر پیش‌فرض است. BUTTON_PIN، بیت)) (اگر (_فشرده شده == 0) ( _delay_ms(DEBOUNCE_TIME)؛ if (bit_is_clear(BUTTON_PIN، بیت)) ( _فشرده شده |= کلید؛ // کلید عمل کلید (کلید) (مورد KEY_SETUP: process_setup(); break؛ case KEY_RESET: process_reset(); break; case KEY_PAUSE: process_pause(); break; case KEY_PLAYER1: process_player1(); break; case KEY_PLAYER2: process_player2(); break; ) sound_on(15); ) ) ) other ( _pressed &= ~کلید؛ ))

    این عملکرد همه 5 دکمه را به نوبه خود بررسی می کند و در صورت وجود فشار را کنترل می کند. کلیک با علامت زدن bit_is_clear (BUTTON_PIN، bit) ثبت می شود، یعنی. اگر ورودی مربوطه به زمین وصل شود، دکمه فشار داده می شود، که طبق نمودار، با فشار دادن دکمه، این اتفاق می افتد. یک تأخیر DEBOUNCE_TIME و یک بررسی مجدد برای جلوگیری از چندین محرک غیرضروری به دلیل جهش تماس لازم است. ذخیره وضعیت فشار دادن در بیت های مربوط به متغیر _pressed برای جلوگیری از عملیات مکرر زمانی که دکمه برای مدت طولانی فشار داده می شود استفاده می شود.
    عملکردهای مدیریت کلیک ها کاملاً بی اهمیت هستند و من معتقدم که نیازی به نظرات اضافی ندارند.

    متن کامل برنامه

    #تعریف F_CPU 4000000UL #شامل #عبارتند از #عبارتند از #define DEBOUNCE_TIME 20 #define BUTTON_PIN PINC #define SETUP_BIT PC0 #define RESET_BIT PC1 #define PAUSE_BIT PC2 #define PLAYER1_BIT PC3 #define PLAYER2_BIT PC4 #define PLAYER2_BIT PC4 #define_BIT PC0 0b00000010 #define KEY_PAUSE 0b00000100 #define KEY_PLAYER1 0b00001000 #define KEY_PLAYER2 0b00010000 volatile int ActiveTimer = 0; volatile int Timer1 = 0; volatile int Timer2 = 0; فرار int_buzzer = 0; فرار int_pressed = 0; // اعلان تابع void init_io(); void init_data(); int number_mask(int number); void handle_buttons(); void handle_button(int key); void process_setup(); void process_reset(); void process_pause(); void process_timeoff(); void process_player1(); void process_player2(); void display(); void display_number (int mask، int number); void sound_on (int interval); void sound_off(); // ISR را قطع می کند (TIMER0_OVF_vect) ( display(؛ if (_buzzer > 0) ( _buzzer--; if (_buzzer == 0) sound_off(); ) ) ISR(TIMER1_COMPA_vect) ( if (ActiveTimer == 1 && Timer1 > 0) ( Timer1--; if (Timer1 == 0) process_timeoff(); ) if (ActiveTimer == 2 && Timer2 > 0) ( Timer2--; if (Timer2 == 0) process_timeoff(); ) ) int main (void) (init_io(); init_data(); sound_off(); sei(); while(1) ( handle_buttons(); ) 0; ) void init_io() (// تنظیم خروجی DDRB = 0xFF؛ DDRD = 0xFF ؛ // ورودی DDRC را تنظیم کنید = 0b11100000؛ // مقاومت های pull-up PORTC |= 0b00011111؛ // تایمر TIMSK را قطع می کند = (1<5940 || Timer2 > 5940) ( Timer1 = 0; Timer2 = 0; ) ) void process_reset() (init_data(); ) void process_timeoff() (init_data(); sound_on(30); ) void process_pause() ( ActiveTimer = 0; ) void process_player1() ( ActiveTimer = 2; ) void process_player2() ( ActiveTimer = 1; ) void handle_button(int key) (int bit; switch (key) ( case KEY_SETUP: bit = SETUP_BIT; break; case KEY_RESET_BIT: bit = RESET ؛ شکست؛ حروف کوچک KEY_PAUSE: بیت = PAUSE_BIT؛ شکست؛ مورد KEY_PLAYER1: بیت = PLAYER1_BIT؛ شکست؛ مورد KEY_PLAYER2: بیت = PLAYER2_BIT؛ شکست؛ پیش‌فرض: بازگشت؛ ) اگر (bit_is_clear(BUTTON_PIN = if (bit) 0) ( _delay_ms(DEBOUNCE_TIME)؛ if (bit_is_clear(BUTTON_PIN، bit)) ( _فشرده شده |= کلید؛ // کلید عمل کلید (کلید) (مورد KEY_SETUP: process_setup(); break؛ مورد KEY_RESET: process_reset(); break; case KEY_PAUSE: process_pause(); break; case KEY_PLAYER1: process_player1(); break; case KEY_PLAYER2: process_player2(); break; ) sound_on(15); ) ) ) other ( _فشرده شده &= ~ کلید ) ) void handle_buttons() ( handle_button(KEY_SETUP)؛ handle_button(KEY_RESET); handle_button(KEY_PAUSE); handle_button(KEY_PLAYER1); handle_button(KEY_PLAYER2); ) void display()(0)number 1(,0b0) 00) ؛ _delay_ms(0.25)؛ display_number((Timer1/60)%10, 0b00000100); _delay_ms(0.25); display_number((Timer1%60)/10, 0b00000010); _delay_ms(0.26)% displayer 10, 0b00000001)؛ _delay_ms(0.25)؛ display_number((Timer2/60)/10, 0b10000000); _delay_ms(0.25); display_number((Timer2/60)%10, 0b0100000)%10, 0b0100000; %60)/10، 0b00100000؛ _delay_ms(0.25)؛ display_number((Timer2%60)%10, 0b00010000); _delay_ms(0.25); PORTD = 0; ) void display_number (int number, int mask) (شماره)؛ PORTD = mask; ) void sound_on (int interval) ( _buzzer = interval; // put buzzer pin high PORTC |= 0b00100000; ) void sound_off() (// put buzzer pin low PORTC &= ~0b00100000; )

    نمونه اولیه روی تخته نان مونتاژ شد.

    من بیش از یکی دو بار گفته ام که مطالعه MK باید با اسمبلر شروع شود. یک دوره کامل در سایت به این اختصاص داده شده است (اگرچه خیلی سازگار نیست، اما به تدریج آن را به یک ظاهر مناسب می پردازم). بله، دشوار است، نتیجه در روز اول نخواهد بود، اما شما یاد خواهید گرفت که بفهمید در کنترلر خود چه اتفاقی می افتد. شما خواهید دانست که چگونه کار می کند، و منابع دیگران را مانند یک میمون کپی نکنید و سعی کنید بفهمید که چرا ناگهان کار نمی کند. علاوه بر این، برای C بسیار ساده‌تر است که با کد redneck که در نامناسب‌ترین لحظه با یک چنگال بیرون می‌آید، اشتباه کند.

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

    از سوی دیگر، نقطه قوت C، قابلیت حمل کد است. البته اگر همه چیز را درست بنویسیم. تفکیک الگوریتم های کاری و پیاده سازی آهنین آنها در بخش های مختلف پروژه. سپس، برای انتقال الگوریتم به MK دیگر، کافی است فقط لایه رابط را بازنویسی کنید، جایی که تمام دسترسی به سخت افزار در آن نوشته شده است، و تمام کدهای کار را به همان صورت باقی بگذارید. و البته خوانایی. کد منبع Sish در یک نگاه راحت‌تر قابل درک است (اگرچه برای مثال، برایم مهم نیست که چه چیزی را تکان دهم - حداقل si، حداقل asm :))، اما، دوباره، اگر همه چیز درست نوشته شده باشد. من هم به این نکات توجه خواهم کرد.

    به عنوان یک قطعه آهن آزمایشی که سهم شیر همه نمونه ها روی آن قرار می گیرد، تابلوی اشکال زدایی من خواهد بود.

    اولین برنامه C برای AVR

    انتخاب یک کامپایلر و نصب یک محیط
    کامپایلرهای C زیادی برای AVR وجود دارد:
    اول از همه این IAR AVR C- تقریباً بدون تردید به عنوان بهترین کامپایلر برای AVR، tk شناخته شده است. خود کنترلر با همکاری نزدیک بین Atmel و متخصصان IAR ایجاد شد. اما شما باید برای همه چیز هزینه کنید. و این کامپایلر نه تنها نرم افزار تجاری گران قیمت است، بلکه دارای تنظیمات بسیار زیادی است که برای کامپایل آن در آن فقط باید سخت کار کنید. من واقعاً با او دوستی نداشتم، پروژه به دلیل خطاهای عجیب در مرحله پیوند پوسیده شد (بعداً متوجه شدم که یک شکاف کج بود).

    دوم می رود WinAVR GCCیک کامپایلر بهینه سازی قدرتمند است. متن باز کامل، کراس پلتفرم، به طور کلی، تمام لذت های زندگی. همچنین کاملاً با AVR Studio ادغام می شود و به شما امکان می دهد همان جا اشکال زدایی کنید که بسیار راحت است. در کل من آن را انتخاب کردم.

    همچنین داشته باشند CodeVision AVR Cیک کامپایلر بسیار محبوب است. به دلیل سادگی آن محبوب شد. شما می توانید در عرض چند دقیقه یک برنامه کار را در آن دریافت کنید - جادوگر کد شروع تا حد زیادی به این امر کمک می کند و استانداردهایی را برای مقداردهی اولیه هر ارتز تعیین می کند. صادقانه بگویم، من به نوعی با او مشکوک رفتار می کنم - زمانی که مجبور شدم برنامه ای را که توسط این کامپایلر نوشته شده بود جدا کنم، نوعی فرنی و نه کد معلوم شد. مقدار وحشتناکی از حرکات و عملیات غیر ضروری، که منجر به مقدار نسبتاً زیادی کد و عملکرد کند شد. با این حال، ممکن است در DNA سیستم عامل اصلی خطایی وجود داشته باشد. به علاوه او پول می خواهد. نه به اندازه IAR، اما قابل توجه است. و در حالت دمو به شما امکان می دهد بیش از 2 کیلوبایت کد بنویسید.
    البته یک کرک وجود دارد، اما اگر دزدی کنید، یک میلیون، به معنای IAR :)

    نیز وجود دارد Image Craft AVR Cو میکرو سیاز میکروالکترونیک نیازی به استفاده از هیچکدام نبود، اما ... SWGبسیار تمجید می کند میکروپاسکالآنها می گویند، یک محیط برنامه نویسی و کتابخانه های فوق العاده راحت. من فکر می کنم MicroC بدتر نخواهد بود، بلکه پولی نیز خواهد داشت.

    همانطور که گفتم من انتخاب کردم WinAVRبه سه دلیل: رایگان، در AVR Studio ادغام می شود و فقط یک دسته کد آماده برای آن برای همه موارد نوشته شده است.

    پس WinAVR را با و AVR Studio دانلود کنید. در مرحله بعد، ابتدا استودیو نصب می شود، سپس از بالا، WinAVR رول می شود و به صورت یک پلاگین به استودیو می چسبد. من قویاً توصیه می کنم WinAVR را در یک مسیر کوتاه قرار دهید، چیزی مانند C:\WinAVR، بنابراین از مشکلات زیادی در مسیرها جلوگیری می کنید.

    ایجاد پروژه
    بنابراین، استودیو راه‌اندازی شد، C خراب شد، وقت آن است که سعی کنید چیزی را برنامه‌ریزی کنید. بیایید با ساده ترین، ساده ترین شروع کنیم. استودیو را اجرا کنید، پروژه جدیدی را در آنجا به عنوان کامپایلر AVR GCC انتخاب کنید و نام پروژه را وارد کنید.

    فضای کاری با یک فایل *.c خالی باز می شود.

    اکنون پیکربندی نمایش مسیرها در نشانک های استودیو ضرری ندارد. برای این کار به آدرس زیر بروید:
    Menu Tools - Options - General - FileTabs و گزینه "Filename Only" را از لیست کشویی انتخاب کنید. در غیر این صورت، کار غیرممکن خواهد بود - تب حاوی مسیر کامل فایل خواهد بود و بیش از دو یا سه برگه روی صفحه وجود نخواهد داشت.

    راه اندازی پروژه
    به طور کلی، ایجاد یک فایل ساخت که در آن تمام وابستگی ها شرح داده شوند، کلاسیک در نظر گرفته می شود. و این احتمالا درست است. اما برای من که با IDE های کاملاً یکپارچه مانند بزرگ شدم uVisionیا AVR Studioاین رویکرد عمیقاً بیگانه است. بنابراین، من این کار را به روش خودم، با تمام ابزار استودیو انجام خواهم داد.

    روی دکمه چرخ دنده کلیک کنید.


    اینها تنظیمات پروژه شما یا بهتر است بگوییم تنظیمات تولید خودکار فایل make هستند. در صفحه اول، فقط باید فرکانس کار MK خود را وارد کنید. بستگی به فیوز بیت ها دارد، بنابراین فرکانس را 8000000 هرتز فرض می کنیم.
    به خط بهینه سازی نیز توجه کنید. اکنون بهینه سازی اندازه -Os وجود دارد. فعلاً آن را همانطور که هست بگذارید، سپس می توانید سعی کنید با این پارامتر بازی کنید. -O0 اصلا بهینه سازی نیست.

    مرحله بعدی تنظیم مسیرها است. اول از همه، دایرکتوری پروژه خود را در آنجا اضافه کنید - کتابخانه های شخص ثالث را در آنجا قرار می دهید. مسیر ".\" در لیست ظاهر می شود

    فایل make تولید می شود، می توانید آن را در پوشه پیش فرض پروژه خود نگاه کنید، فقط نگاه کنید، ببینید چه چیزی وجود دارد.


    فعلاً همین است. همه جا OK را کلیک کنید و به منبع بروید.

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

    به این صورت کار خواهد کرد:
    هنگامی که یک واحد به پورت COM می رسد (کد 0x31) دیود را روشن می کنیم و زمانی که صفر رسید (کد 0x30) آن را خاموش می کنیم. علاوه بر این، همه چیز در وقفه ها انجام می شود و وظیفه پس زمینه چشمک زدن یک دیود دیگر خواهد بود. ساده و معنی دار.

    جمع آوری طرح
    ما باید ماژول مبدل USB-USART را به پین ​​های USART میکروکنترلر متصل کنیم. برای این کار یک جامپر از دو سیم برداشته و به صورت ضربدری روی پین ها قرار می دهیم. یعنی Rx کنترلر را با Tx مبدل و Tx مبدل را با Rx کنترلر وصل می کنیم.

    به نظر می رسد، در پایان، این طرح است:


    من اتصال خروجی های باقی مانده، منبع تغذیه، تنظیم مجدد را در نظر نمی گیرم، استاندارد است

    ما کد را می نویسیم

    من فوراً رزرو می کنم که به طور خاص به توصیف خود زبان C نمی پردازم. برای انجام این کار، به سادگی حجم عظیمی از مطالب وجود دارد، از زبان برنامه نویسی کلاسیک C از K&R گرفته تا کتابچه های راهنمای مختلف.

    یکی از این روش‌ها در انبار من پیدا شد، یک بار با استفاده از آن این زبان را مطالعه کردم. همه چیز کوتاه، واضح و دقیق است. کم کم دارم تایپ می کنم و به سایتم می کشم.

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

    بعید است که من آن را بهتر توصیف کنم، بنابراین، از دوره آموزشی، به جای توضیح دقیق در مورد پیچیدگی های Cish، من به سادگی پیوندهای مستقیم به صفحات جداگانه این کتابچه راهنمای کاربر می دهم.

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

    1 #عبارتند از

    #عبارتند از

    این فایل در پوشه قرار دارد WinAVRو شامل توضیحاتی در مورد تمامی رجیسترها و پورت های کنترلر می باشد. و همه چیز در آنجا مشکل است، با اشاره به یک کنترل کننده خاص، که توسط کامپایلر از طریق آن منتقل می شود ساختنفایل در پارامتر MCUو بر اساس این متغیر یک فایل هدر با شرح آدرس تمامی پورت ها و رجیسترهای این کنترلر خاص به پروژه شما متصل می شود. چگونه! بدون آن، شما هم می توانید، اما پس از آن نمی توانید از نام های ثبت نمادین مانند SREG یا UDR استفاده کنید، و باید آدرس هر یک مانند "0xC1" را به خاطر بسپارید، و این باعث شکستن سر شما می شود.

    دقیقا همین تیم #عبارتند از<имя файла> به شما امکان می دهد محتویات هر فایل متنی را به پروژه خود اضافه کنید، به عنوان مثال، یک فایل با شرح توابع یا یک قطعه کد دیگر. و برای اینکه دستورالعمل بتواند این فایل را پیدا کند، مسیرهای پروژه خود را نشان دادیم (دایرکتوری WinAVR قبلاً به طور پیش فرض در آنجا ثبت شده است).

    عملکرد اصلی
    یک برنامه C در مورد توابع است. آنها را می توان به هر ترتیب و به روش های مختلف تودرتو کرد و از یکدیگر فراخوانی کرد. هر تابع دارای سه پارامتر مورد نیاز است:

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

    همه مقادیر ارسال شده و برگردانده شده باید بسته به داده از نوعی باشند.

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

    1 2 3 4 5 int main(void) (بازگرداندن 0 ;)

    int main(void) (return 0; )

    همین، اولین ساده ترین برنامه نوشته شده است، مهم نیست که هیچ کاری نمی کند، ما تازه شروع کرده ایم.

    ببینیم چیکار کردیم
    بین المللینوع داده ای است که تابع اصلی برمی گرداند.

    البته در میکروکنترلر اصلیدر اصل، هیچ چیز قابل بازگشت نیست، و در تئوری باید باشد خالی اصلی (باطل)، اما GCC در ابتدا روی رایانه شخصی تیز می شود و در آنجا برنامه می تواند پس از تکمیل مقدار را به سیستم عامل برگرداند. بنابراین GCC روشن است خالی اصلی (باطل)قسم به هشدار.

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

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

    اینجا اینها هستند { } براکت های فرفری یک بلوک برنامه است، در این مورد بدنه تابع است اصلی، کد در آنجا قرار خواهد گرفت.

    برگشت- این مقدار بازگشتی است که تابع main پس از تکمیل می دهد، زیرا ما یک int داریم، یعنی یک عدد، پس باید یک عدد برگردانیم. اگرچه هنوز منطقی نیست، زیرا. در میکروکنترلر از اصلی، ما فقط نمی توانیم به جایی برویم. من پوچ برمی گردم برای نفیگ. و کامپایلر معمولا هوشمند است و برای این مورد کد تولید نمی کند.
    اگر چه، اگر منحرف، سپس از اصلیمی توانید به MK بروید - به عنوان مثال، در بخش بوت لودر بیفتید و آن را اجرا کنید، اما در اینجا برای تصحیح آدرس های انتقال از قبل به انتخاب سطح پایین سیستم عامل نیاز دارید. در زیر نحوه انجام آن را خواهید دید و درک خواهید کرد. برای چی؟ حالا این یک سوال دیگر است، در 99.999٪ موارد این ضروری نیست :)

    تمام شد، ادامه دهید. بیایید یک متغیر اضافه کنیم، ما واقعاً به آن نیاز نداریم و نباید متغیرهایی را بدون آن معرفی کنیم، اما در حال یادگیری هستیم. اگر متغیرها در داخل بدنه تابع اضافه شوند، آنگاه محلی هستند و فقط در این تابع وجود دارند. وقتی از تابع خارج می شوید، این متغیرها حذف می شوند و حافظه رم به نیازهای مهم تری داده می شود. .

    1 2 3 4 5 6 int main(void) (char i بدون علامت؛ بازگشت 0؛ )

    int main(void) ( char i بدون علامت؛ بازگشت 0؛ )

    بدون امضایعنی بدون امضا واقعیت این است که در نمایش باینری، مهم ترین بیت به علامت اختصاص داده می شود، به این معنی که عدد +127/-128 در یک بایت (char) قرار می گیرد، اما اگر علامت کنار گذاشته شود، از 0 تا 255. معمولاً علامت لازم نیست. بنابراین بدون امضا.
    منفقط یک نام متغیر است. بیشتر نه.

    حال باید پورت ها را مقداردهی اولیه کنیم و UART. البته، می توانید کتابخانه را بگیرید و متصل کنید و نوعی UartInit (9600) را فراخوانی کنید. اما پس از آن شما نمی دانید واقعا چه اتفاقی افتاده است.

    ما این کار را انجام می دهیم:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int main(void) ( char i بدون علامت؛ #define XTAL 8000000L #define baudrate 9600L #define bauddivider (XTAL/(16*baudrate)-1)#define HI(x) ((x)>>8) #define LO(x) ((x)& 0xFF) UBRRL = LO(bauddivider) ; UBRRH = HI(bauddivider) ; UCSRA = 0 ; UCSRB=1<< RXEN| 1 << TXEN| 1 << RXCIE| 0 << TXCIE; UCSRC = 1 << URSEL| 1 << UCSZ0| 1 << UCSZ1; }

    int main(void) ( char i بدون علامت؛ #define XTAL 8000000L #define baudrate 9600L #define bauddivider (XTAL/(16*baudrate)-1) #define HI(x) ((x)>>>8) #define LO( x) ((x)& 0xFF) UBRRL = LO(bauddivider)؛ UBRRH = HI(bauddivider)؛ UCSRA = 0؛ UCSRB = 1<

    ترسناک؟ در واقع، تنها پنج خط آخر کد واقعی وجود دارد. همه چیز، آن #تعريف كردناین یک زبان ماکرو پیش پردازنده است. تقریباً همان تاپ های اسمبلر، اما نحو تا حدودی متفاوت است.

    آنها عملیات معمول شما را برای محاسبه ضرایب مورد نیاز تسهیل می کنند. در خط اول می گوییم که به جای XTALمی توانید با خیال راحت 8000000 را جایگزین کنید، و L- نشانگر نوع، آنها می گویند طولانی فرکانس ساعت پردازنده است. همینطور بادریت- فرکانس انتقال داده از طریق UART.

    بوددیوادردر حال حاضر پیچیده تر است، به جای آن عبارت محاسبه شده توسط فرمول دو قبلی جایگزین می شود.
    خوب و LOو سلاماز این نتیجه، بایت های کم و زیاد گرفته می شود، زیرا بدیهی است که نمی تواند در یک بایت جا شود. که در سلام x (پارامتر ورودی ماکرو) هشت بار به سمت راست منتقل می شود، در نتیجه فقط بایت بالا از آن باقی می ماند. و در LOبه صورت بیتی و با عدد 00FF عمل می کنیم و در نتیجه فقط بایت کم باقی می ماند.

    بنابراین هر کاری که انجام می شود مانند است #تعريف كردنمی توانید با خیال راحت آن را دور بیندازید و اعداد لازم را روی ماشین حساب محاسبه کنید و بلافاصله آنها را در خطوط UBBRL = ... وارد کنید. و UBBRH=…..

    می توان. ولی! این کار را انجام دهید اکیدا غیر ممکن است!

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

    سپس همه چیز ساده است:
    همه این "UBRLL and Co" رجیسترهای پیکربندی فرستنده UART هستند که با آن با جهان ارتباط برقرار خواهیم کرد. و اکنون مقادیر لازم را به آنها اختصاص داده ایم و آنها را روی سرعت دلخواه و حالت دلخواه قرار می دهیم.

    مشاهده ورودی 1<به این معنی است: 1 را بردارید و در جای خود قرار دهید RXENدر یک بایت RXENاین بیت چهارم ثبت است UCSRB، بنابراین 1<عدد باینری 00010000 را تشکیل می دهد، TXENبیت 3 است و 1< 00001000 خواهد داد. تک "|" به صورت بیتی است یا، بنابراین 00010000 | 00001000 = 00011000. به همین ترتیب، بیت های پیکربندی لازم باقیمانده تنظیم شده و به پشته مشترک اضافه می شوند. در نتیجه، شماره جمع آوری شده در UCSRB نوشته می شود. در دیتاشیت MK در بخش USART با جزئیات بیشتر توضیح داده شده است. بنابراین حواس خود را با جزئیات فنی پرت نکنید.

    تمام شد، وقت آن است که ببینیم چه اتفاقی می افتد. روی compilation کلیک کنید و شبیه سازی را شروع کنید (Ctrl+F7).

    اشکال زدایی
    همه انواع نوارهای پیشرفت از آن عبور کردند، استودیو تغییر کرد و یک فلش زرد در نزدیکی ورودی عملکرد اصلی ظاهر شد. این جایی است که پردازنده در حال حاضر است و شبیه سازی متوقف شده است.

    واقعیت این است که در ابتدا، در واقع، در خط UBRRL = LO (bauddivider) قرار داشت. از این گذشته، آنچه ما در تعریف داریم کد نیست، بلکه محاسبات اولیه است، بنابراین شبیه ساز کمی کسل کننده است. اما اکنون او متوجه شد که اولین دستور انجام شده است و اگر به درختی بروید نمای ورودی/خروجی، به بخش USART بروید و به بایت UBBRL در آنجا نگاه کنید، خواهید دید که قبلاً یک مقدار در آنجا وجود دارد! 0x33.

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

    افتتاح
    حالا شبیه سازی را به صفر برگردانید. آنجا کلیک کنید بازنشانی (Shift+F5). لیست جدا شده را باز کنید، اکنون خواهید دید که واقعاً در کنترلر چه اتفاقی می افتد. مشاهده -> Disassembler. و نه YYAAAA!!! مونتاژ کننده!!! ناگوار!!! و ضروری است. به طوری که بعداً، هنگامی که مشکلی پیش می‌آید، کد را احمقانه نکنید و در انجمن‌ها سؤالات کوتاه‌تری نپرسید، بلکه بلافاصله وارد قلوه‌ها شوید و ببینید که کجا دوشاخه دارید. هیچ چیز وحشتناکی در آنجا وجود ندارد.

    ابتدا تاپ های این سری وجود خواهد داشت:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 +00000000: 940C002A JMP 0x0000002A پرش +00000002: 940C0034 JMP 0x00000034 پرش +00000004: 940C0034 JMP 03000000C MP 0 x00000034 Jump +00000008: 940C0034 JMP 0x00000034 Jump +0000000A: 940C0034 JMP 0x000000034 Jump +00000000C +00000000C 00000000C 940C0034 JMP 0x00000034 + 0000000E: 940C0034 JMP 0x00000034 Jump +00000010: 940C0034 JMP 0x00000034 Jump +000000012: 940C0034 JMP 000000000000000000000012: 940C0034 JMP 00000001 JMP 0 x00000034 Jump +00000016: 940C0034 JMP 0x00000034 Jump +00000018: 940C0034 JMP 0x00000034 Jump +00000001A 00000001A +00000001A 00000001A 00000001A +00000001A 00000001A 00000001A +00000001A 00000001A 00000001A +00000001A 00000001A 00000001A: +0000001C : 940C0034 JMP 0x00000034 Jump +0000001E: 940C0034 JMP 0x00000034 Jump +00000020: 940C0034 JMP 0300000C JMP 0x0000003 4 پرش +00000024: 940C0034 JMP 0x00000034 پرش +00000026: 940C0034 JMP 0x00000034 پرش +000000034 JMP +0000000028: JMP0000004

    00000000: 940C002A JMP 0x0000002A پرش +00000002: 940C0034 JMP 0x00000034 پرش +00000004: 940C0034 JMP 0x0000000C MP 0 x00000034 Jump +00000008: 940C0034 JMP 0x00000034 Jump +0000000A: 940C0034 JMP 0x000000034 Jump +00000000C +00000000C 00000000C +00000000C: 940C0034 JMP 0x00000034 0000000E : 940C0034 JMP 0x00000034 Jump +00000010: 940C0034 JMP 0x00000034 Jump +000000012: 940C0034 JMP 0000000000000000000012: 940C0034 JMP 000000010 JMP 0x0000003 4 پرش +00000016: 940C0034 JMP 0x00000034 پرش +00000018: 940C0034 JMP 0x00000034 پرش +000000034 JMP +00000001A +00000001A +00000001A +00000001A: 0000001C: 940C0034 JMP 0x00000034 Jump +0000001E: 940C0034 JMP 0x00000034 Jump +00000020: 940C0034 JMP 0x0000000C MP 0x00000034 Jump +00000024: 940C0034 JMP 0x00000034 Jump +00000026: 940C0034 JMP 0x00000034 Jump +000000028 +000000028: JMP00300000

    این جدول برداری وقفه است. بعداً به آن باز خواهیم گشت، فعلاً فقط نگاه کنید و به یاد داشته باشید که آنجاست. ستون اول آدرس سلول فلش است که دستور در آن قرار دارد، دومی کد دستوری، سومین دستور mnemonic، همان دستور اسمبلر، عملوندهای سوم دستور است. اوه، و نظر خودکار.
    بنابراین، اگر نگاه کنید، انتقال های مداوم وجود دارد. و کد دستور JMP چهار بایت است، حاوی آدرس پرش به عقب نوشته شده است - بایت کم در آدرس پایین و کد دستور پرش 940C

    0000002B: BE1F OUT 0x3F، R1 خروجی به محل ورودی/خروجی

    این صفر را در آدرس 0x3F بنویسید.اگر به ستون نمای I/O نگاه کنید، می بینید که آدرس 0x3F آدرس رجیستر SREG - ثبت پرچم کنترل کننده است. آن ها ما SREG را برای اجرای برنامه در شرایط صفر بازنشانی می کنیم.

    1 2 3 4 +0000002C: E5CF LDI R28,0x5F بارگیری فوری +0000002D: E0D4 LDI R29,0x04 بارگیری فوری +0000002E: خروجی BFDE OUT 0x3E,R29 خروجی به مکان ورودی/خروجی +00000002F موقعیت مکانی ورودی/خروجی +00000002F

    0000002C: E5CF LDI R28,0x5F بارگیری فوری +0000002D: E0D4 LDI R29,0x04 بارگیری فوری +0000002E: خروجی BFDE OUT 0x3E,R29 خروجی به محل ورودی/خروجی +00000002F موقعیت مکانی ورودی/خروجی +000000002

    این در حال بارگیری نشانگر پشته است. شما نمی توانید مستقیماً رجیسترها را در I/O بارگذاری کنید، فقط از طریق یک ثبات میانی. بنابراین، ابتدا LDI به متوسط، و سپس از آنجا OUT به I / O. من همچنین در مورد پشته بیشتر به شما خواهم گفت. در ضمن، بدانید که این یک حافظه پویا است، در انتهای RAM آویزان می شود و آدرس ها و متغیرهای میانی را در خود ذخیره می کند. حالا ما نشان دادیم که پشته از کجا شروع می شود.

    00000032: 940C0041 JMP 0x00000041 پرش

    یک پرش به انتهای saaaaamy برنامه، و در آنجا وقفه‌ها غیرفعال شده و به شدت روی خود حلقه می‌شوند:

    1 2 +00000041: 94F8 CLI وقفه جهانی غیرفعال کردن +00000042: CFFF RJMP PC-0x0000 پرش نسبی

    00000041: 94F8 CLI وقفه جهانی غیرفعال کردن +00000042: CFFF RJMP PC-0x0000 پرش نسبی

    این در صورت شرایط پیش بینی نشده، مانند خروج از عملکرد اصلی است. کنترلر را می توان با بازنشانی سخت افزاری یا به احتمال زیاد با بازنشانی از یک سگ نگهبان از چنین حلقه ای خارج کرد. خوب، یا همانطور که در بالا گفتم، این مکان ها را در ویرایشگر هگز درست کنید و هر کجا که می خواهیم سوار شوید. همچنین توجه داشته باشید که دو نوع پرش JMP و RJMP وجود دارد که اولی پرش مستقیم به یک آدرس است. چهار بایت را اشغال می کند و می تواند یک پرش مستقیم روی کل منطقه حافظه انجام دهد. نوع دوم انتقال - RJMP - نسبی است. دستور او دو بایت طول می کشد، اما او از موقعیت فعلی (آدرس) 1024 قدم به جلو یا عقب می پرد. و پارامترهای آن نشان دهنده افست از نقطه فعلی است. بیشتر استفاده می شود، tk. نیمی از فضای فلاش را اشغال می کند و به ندرت نیاز به انتقال طولانی است.

    1 +00000034: 940C0000 JMP 0x00000000 پرش

    00000034: 940C0000 JMP 0x00000000 پرش

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

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

    1 2 3 4 5 6 7 8 9 10 11 12 <

    00000036: E383 LDI R24,0x33 بارگیری فوری +00000037: B989 OUT 0x09,R24 خروجی به محل ورودی/خروجی 15: UBRRH = HI(bauddivider); +00000038: BC10 OUT 0x20,R1 خروجی به محل ورودی/خروجی 16: UCSRA = 0; +00000039: B81B OUT 0x0B,R1 خروجی به محل ورودی/خروجی 17: UCSRB = 1<

    و این جامب است:

    1 2 3 +0000003E: E080 LDI R24,0x00 بارگیری فوری +0000003F: E090 LDI R25,0x00 بارگیری فوری +00000040: 9508 بازگشت زیربرنامه RET

    0000003E: E080 LDI R24,0x00 بارگیری فوری +0000003F: E090 LDI R25,0x00 بارگیری فوری +00000040: 9508 بازگشت زیربرنامه RET

    سوال اینجاست که چرا کامپایلر چنین تاپ هایی را اضافه می کند؟ و این چیزی بیش از Return 0 نیست، سپس ما تابع را به عنوان int main (void) تعریف کردیم، بنابراین ما چهار بایت دیگر را به هم زدیم، نمی فهمم چیست :) و اگر شما void را اصلی (void) کنید، فقط RET باقی می ماند. اما یک هشدار ظاهر می شود که می گویند عملکرد اصلی ما چیزی را بر نمی گرداند. در کل هر کاری میخوای انجام بده :)

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

    تا یکی دو روز دیگر ادامه دارد...

    آف تاپ:
    الکسی 78من یک پلاگین برای فایرفاکس ساختم که به راحتی می توانید در سایت و انجمن من حرکت کنید.
    بحث و دانلود،

    روز بخیر رادیو آماتورهای عزیز!
    من به شما خوش آمد می گویم به سایت ""

    میکروکنترلر چیست و چرا به آن نیاز است؟ بیایید به تعریف آن نگاه کنیم:

    - یک ریزمدار طراحی شده برای کنترل وسایل الکترونیکی، یا به روشی دیگر - یک کامپیوتر ساده (میکرو کامپیوتر) که قادر به انجام کارهای ساده است.

    یعنی در واقع یک میکروکنترلر وسیله ای است که به ما امکان می دهد ایده های خود را (حتی احمقانه) محقق کنیم، اما البته در حد توانایی های آن. و مهمتر از همه، تحقق یک ایده نه با ایجاد ساختارهای الکترونیکی پیچیده، بلکه فقط، اساسا، با قدرت فکر ما به دست می آید (آیا می خواهید یک جادوگر شوید؟).
    محبوب ترین در بین آماتورهای رادیویی دو نوع میکروکنترلر است:
    PIC- فناوری ریزتراشه
    AVR- توسط Atmel

    من می خواهم یک انحراف کوتاه انجام دهم و یکی از مواضع خود را روشن کنم. من قصد ندارم در مورد شایستگی های این یا آن نوع میکروکنترلرها، این یا آن نرم افزار و به طور کلی همه چیزهایی که به میکروکنترلرها مربوط می شود، برای توصیه چیزی و حتی بیشتر از آن تحمیل به خوانندگان بحث کنم. همه اینها به سلیقه، ترجیحات شخصی و اهداف نهایی شما در یادگیری میکروکنترلرها بستگی دارد. خوب، از آنجایی که "عظمت را نمی توان پذیرفت"، من تمام روایت های بعدی خود را در رابطه با میکروکنترلرهای AVR و برنامه "Algorithm Builder" نه چندان رایج، اما مورد علاقه من، انجام خواهم داد. انواع مختلف میکروکنترلرها، برنامه ها، البته، تفاوت هایی دارند، اما مشترکات زیادی نیز دارند. و دنیای میکروکنترلرها را به گونه ای یاد خواهیم گرفت که بعداً دانش به دست آمده بدون هیچ مشکلی روی PIC ها و هر نرم افزاری اعمال شود. و اجازه دهید یک بار دیگر به شما یادآوری کنم که این سری مقالات تلاش من برای کمک به کسانی است که اولین بار در مورد وجود میکروکنترلرها شنیده اند و می خواهند نحوه کار با آنها را درک کنند.

    برای یادگیری نحوه کار با میکروکنترلرها به چه چیزهایی نیاز دارید؟ من به نظر من چند شرط اصلی را مشخص می کنم:
    1. میل و پشتکار .
    همه چیز در اینجا بسیار ساده است: یک میل وجود دارد - همه چیز درست می شود. و آرزوی همراه با پشتکار، به طور کلی، یک چیز فوق العاده است.
    2. دانش دستگاه میکروکنترلر.
    دانش عمیق در اینجا مهم نیست (و شاید اصلاً مورد نیاز نباشد)، اما لازم است بدانید که چه چیزی "روی" میکروکنترلر است. فقط با دانستن اینکه میکروکنترلر از چه چیزی تشکیل شده است، چه دستگاه هایی دارد، قابلیت های آنها، چگونه کار می کنند - تنها در این صورت است که می توانیم از قابلیت های میکروکنترلر به طور کامل استفاده کنیم.
    3. آشنایی با زبان برنامه نویسی و دستورات کنترل میکروکنترلر.
    نحوه کار میکروکنترلر، وظایفی که به آن محول می کنید و چگونه آنها را انجام می دهد، توسط برنامه تعبیه شده در آن تعیین می شود - برنامه ای که خودتان برای میکروکنترلر ایجاد می کنید. و به منظور بررسی مسائلی که ممکن است در آینده پیش بیاید، در این مورد با جزئیات بیشتری صحبت خواهیم کرد.

    برنامه(در ترجمه، این کلمه به معنای "نسخه" است) - توصیف اولیه رویدادها یا اقدامات آینده.

    به عنوان مثال، ما می خواهیم میکروکنترلر یک LED چشمک بزند. یک کار ساده، اما با این وجود، برای اینکه میکروکنترلر بتواند این کار را انجام دهد، ابتدا باید گام به گام تمام اقدامات میکروکنترلر را شرح دهیم، برنامه ای بنویسیم که باید آن را اجرا کند تا نتیجه مورد نیاز ما به دست آید - یک LED چشمک زن . چیزی شبیه به این:
    ♦ LED را روشن کنید:
    - پیکربندی خروجی که LED به آن متصل است تا روی خروجی اطلاعات کار کند
    - یک سطح منطقی را به این پین اعمال کنید که به شما امکان می دهد LED را روشن کنید
    ♦ کمی صبر کنید:
    - به زیر برنامه ای بروید که مکث ایجاد می کند (که همچنین باید "جویده" شود)
    - پس از اتمام زیربرنامه مکث، به برنامه اصلی بازگردید
    ♦ LED را خاموش کنید:
    - یک سطح منطقی را به خروجی اعمال کنید و LED را خاموش کنید
    و غیره
    با اصطلاح برنامهاصطلاح دیگری به طور ناگسستنی به هم مرتبط است - الگوریتم(مانند گرگ و خرگوش، تام و جری).

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

    در صورتی که در برنامه به جزئی ترین راه هستیم اقدامات را تجویز کندمیکروکنترلر، سپس در الگوریتم ما مسیر اقدام را مشخص کندمیکروکنترلری که بر اساس آن یک برنامه ایجاد می کنیم. مشابه مثال بالا:
    ♦ LED را روشن کنید
    ♦ کمی صبر کنید
    ♦ LED را خاموش کنید
    و غیره
    بدین ترتیب، الگوریتم پیشرو برنامه است. و هر چه یک الگوریتم با دقت و تفکر بیشتری ایجاد شود، ایجاد یک برنامه آسان تر خواهد بود.

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

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

    زبان برنامه نویسی - این روشی برای انتقال دستورات، دستورالعمل ها، راهنمای عملی برای میکروکنترلر است.

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

    01000110
    10010011
    01010010

    بعید است که کسی بتواند چنین مجموعه ای از ترکیبات دو عدد را دریابد و کار برنامه نویسان اول بسیار پر زحمت بود. برنامه نویسان برای آسان کردن زندگی خود شروع به ایجاد اولین زبان های برنامه نویسی کردند. بنابراین، هر چه زبان برنامه نویسی به چنین مجموعه ای از صفر و یک نزدیکتر باشد، "سطح پایین" آن بیشتر است و هر چه از آنها دورتر باشد، "سطح بالا" بیشتر است.
    رایج ترین زبان های برنامه نویسی برای میکروکنترلرها:
    - زبان سطح پایین - مونتاژ کننده
    – زبان سطح بالا – C (Ci)
    بیایید به مثالی از تفاوت آنها نگاه کنیم (این نمونه ها انتزاعی هستند).
    فرض کنید باید دو عدد را اضافه کنیم: 25 و 35.
    در کد بومی، این دستور ممکن است به شکل زیر باشد:
    00000101 1101001
    به زبان سطح پایین:
    ADD Rd, Rr
    به زبان سطح بالا:
    25+35
    تفاوت بین زبان های سطح پایین و سطح بالا با چشم غیر مسلح قابل مشاهده است ، نظرات ، همانطور که می گویند ، اضافی است.
    اما بیایید بیشتر به این مثال ها بپردازیم. ما مثال کد ماشین را تجزیه و تحلیل نمی کنیم، زیرا با مثال در اسمبلر یکسان است. در هسته خود، دستورالعمل‌های اسمبلی همان کدهای ماشین (فرمان‌ها) هستند که به سادگی حروف اختصاری به آنها اختصاص داده می‌شود تا در صفر و یک گم نشوند. با دستور اسمبلر ADD Rd, Rr، میکروکنترلر را تنظیم می کنیم تا دو عدد پیدا شده را اضافه کند (و برای این کار ابتدا باید آنها را در آنجا بنویسیم) - اولی در Rd، دومی در Rr، و نتیجه جمع را قرار می دهیم. در خیابان همانطور که می بینید، ما یک وظیفه بسیار خاص برای میکروکنترلر تعیین می کنیم: از کجا آن را دریافت کنیم، با آن چه کار کنیم، و نتیجه را کجا قرار دهیم. در این حالت مستقیماً با میکروکنترلر کار می کنیم.
    دستور به زبان سطح بالا: 25+35، یک نماد ریاضی آشنا برای ما، برای چشمان ما دلپذیر. اما در این حالت ما مستقیماً با میکروکنترلر کار نمی کنیم، فقط وظیفه جمع دو عدد را برای آن تعیین می کنیم. نتیجه و ترتیب اعمال در این حالت مانند هنگام اجرای دستور اسمبلر خواهد بود: ابتدا این دو عدد در جایی نوشته می شوند، سپس جمع می شوند و نتیجه در جایی قرار می گیرد.
    و تفاوت اصلی بین زبان های سطح بالا و سطح پایین در اینجا نهفته است. اگر در اسمبلر کل فرآیند را کنترل کنیم (چه بخواهیم چه نخواهیم): می دانیم این دو عدد کجا نوشته شده اند و می دانیم که نتیجه کجا خواهد بود، پس در یک زبان سطح بالا ما روند را کنترل نمی کنیم. خود برنامه تصمیم می گیرد که اعداد را کجا از قبل بنویسد و نتیجه را در کجا قرار دهد. در بیشتر موارد، ما نیازی به دانستن این موضوع نداریم، زیرا برای ما نتیجه اصلی عدد 60 در خروجی است. در نتیجه، برنامه‌های زبان‌های سطح بالا خواناتر، دلپذیرتر و از نظر اندازه کوچک‌تر هستند - از این گذشته، ما مجبور نیستیم "به همه سوراخ‌ها برویم" و هر مرحله از میکروکنترلر، برنامه را رنگ کنیم. این کار را بعداً وقتی آن را کامپایل می کند برای ما انجام می دهد - آن را به کدهای ماشین ترجمه می کند. اما یک نقطه ضعف نیز وجود دارد. دو الگوریتم یکسان که در اسمبلر و سی نوشته شده اند، پس از تبدیل آنها به کدهای ماشین، اندازه متفاوتی خواهند داشت: برنامه ای که در اسمبلر نوشته شده است 20 تا 40 درصد کوتاه تر از برنامه ای است که در C نوشته شده است - شیطان می داند که C به کدام سمت می رود. به نتیجه ای که نیاز داریم برسیم و مواردی وجود دارد که به یک زبان سطح بالا اعتماد وجود ندارد و در برنامه C کد نوشته شده در اسمبلر را وارد می کنند.
    برنامه نویسان حرفه ای، به عنوان یک قاعده، چندین زبان برنامه نویسی را می دانند (یا در تیمی کار می کنند که شامل متخصصان زبان های مختلف است)، خلاقانه ویژگی ها و مزایای خود را در یک برنامه ترکیب می کنند. خوب، ما، آماتورها، باید حداقل یک زبان (برای شروع) بدانیم، و باید از یک زبان سطح پایین - اسمبلی - شروع کنیم (و من کاملاً در این امر متقاعد هستم و هیچ کس مرا متقاعد نخواهد کرد).

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

    دستورات و دستورالعمل های کنترل میکروکنترلر.
    میکروکنترلرهای AVR دارای بیش از 130 فرمان مختلف هستند که به آن اجازه می دهد تمام امکانات ذاتی خود را تحقق بخشد. اما من فوراً می گویم که تعداد کمی از آماتورها همه آنها را می شناسند، چه رسد به استفاده از همه آنها. معمولاً در تمرین آماتورها دانش کافی و نیمی از تیم ها یا حتی کمتر وجود دارد. اما شما باید دستورات را یاد بگیرید. هرچه دستورات بیشتری بدانید، برنامه های پیچیده تر (به معنای خوب کلمه) و ظریف تر خواهند بود.

    واحد منطق محاسباتی و سازماندهی حافظه - حافظه برنامه، حافظه داده، حافظه غیر فرار


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

    اطلاعات کلی

    میکروکنترلرها را می توان در همه جا پیدا کرد. آنها در یخچال، ماشین لباسشویی، تلفن، ماشین های تولیدی، خانه های هوشمند و بسیاری از وسایل فنی دیگر یافت می شوند. استفاده گسترده از آنها به دلیل امکان جایگزینی مدارهای آنالوگ پیچیده تر و در مقیاس بزرگ تر دستگاه ها است. برنامه نویسی MK AVR به شما امکان می دهد کنترل مستقلی بر روی دستگاه های الکترونیکی ارائه دهید. این میکروکنترلرها را می توان به عنوان یک کامپیوتر ساده در نظر گرفت که می تواند با تجهیزات خارجی تعامل داشته باشد. بنابراین، آنها می توانند ترانزیستورها را باز یا بسته کنند، داده ها را از سنسورها دریافت کنند و آنها را روی صفحه نمایش نشان دهند. همچنین میکروکنترلرها می توانند پردازش های مختلفی از اطلاعات ورودی را مانند رایانه شخصی انجام دهند. اگر برنامه نویسی AVR را از ابتدا یاد بگیرید و به سطح یک حرفه ای برسید، امکانات تقریبا بی حد و حصری برای کنترل دستگاه های مختلف با استفاده از پورت های I / O و همچنین تغییر کد آنها باز می شود.

    کمی در مورد AVR

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

    1. داخلی. ماشین لباسشویی، یخچال، اجاق مایکروویو و غیره.
    2. سیار. ربات ها، ارتباطات و غیره.
    3. محاسبه. سیستم های کنترل دستگاه های جانبی، مادربردها.
    4. سرگرم کننده. جواهرات و اسباب بازی های کودکانه.
    5. حمل و نقل. امنیت خودرو و سیستم های مدیریت موتور.
    6. تجهیزات صنعتی. سیستم های کنترل ماشین.

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

    چگونه اولین میکروکنترلر خود را تهیه کنیم؟

    برنامه نویسی AVR به موارد زیر نیاز دارد:

    1. در دسترس بودن محیط توسعه لازم.
    2. در واقع خود میکروکنترلرها.

    اجازه دهید نکته دوم را با جزئیات بیشتری در نظر بگیریم. سه امکان برای تهیه دستگاه مورد نیاز وجود دارد:

    1. مستقیم خود میکروکنترلر را بخرید.
    2. یک دستگاه را به عنوان بخشی از طراح (به عنوان مثال، آردوینو) دریافت کنید.
    3. میکروکنترلر را خودتان جمع کنید.

    در پاراگراف اول هیچ چیز پیچیده ای وجود ندارد، بنابراین بیایید بلافاصله به سراغ دوم و سوم برویم.

    یک دستگاه را به عنوان بخشی از طراح دریافت کنید

    آردوینو معروف به عنوان نمونه انتخاب خواهد شد. همچنین یک پلت فرم مناسب برای توسعه سریع و با کیفیت بالا دستگاه های الکترونیکی مختلف است. برد آردوینو شامل مجموعه خاصی از قطعات برای کار است (پیکربندی های مختلفی وجود دارد). باید شامل یک کنترلر AVR باشد. این رویکرد به شما امکان می دهد تا به سرعت شروع به توسعه دستگاه کنید، به مهارت های خاصی نیاز ندارد، از نظر اتصال تخته های اضافی دارای فرصت های قابل توجهی است، و همچنین می توانید اطلاعات زیادی را در اینترنت در مورد سؤالات مورد علاقه پیدا کنید. اما بدون معایب هم نبود. با خرید یک آردوینو، فرد خود را از این فرصت محروم می‌کند که عمیق‌تر در برنامه‌نویسی AVR غوطه‌ور شود، تا میکروکنترلر و ویژگی‌های کار آن را بهتر بشناسد. خط نسبتاً باریکی از مدل‌ها نیز به موارد منفی می‌افزاید، به همین دلیل است که اغلب مجبور می‌شوید برای کارهای خاص مادربرد بخرید. یک ویژگی همچنین این واقعیت است که برنامه نویسی در "SI" در اینجا کاملاً با فرم استاندارد متفاوت است. با وجود تمام کاستی ها، آردوینو برای یادگیری افراد مبتدی مناسب است. اما نباید از آن سوء استفاده کرد.

    خود مونتاژ

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

    چگونگی کار؟

    بنابراین، بیایید بگوییم که مشکل میکروکنترلر حل شده است. علاوه بر این، در نظر گرفته خواهد شد که به طور مستقل خریداری یا خریداری شده است. برای تسلط بر برنامه نویسی AVR به چه چیز دیگری نیاز دارید؟ برای این منظور به یک محیط توسعه نیاز دارید (یک دفترچه یادداشت معمولی نیز به عنوان پایه مناسب است، اما توصیه می کنم در Notepad ++ توقف کنید). اگرچه برنامه های دیگری برای برنامه نویسی AVR وجود دارد، اما نرم افزار ارائه شده قادر خواهد بود تمامی نیازها را برطرف کند. شما همچنین به یک برنامه نویس نیاز دارید. می توان آن را در نزدیکترین فروشگاه خریداری کرد، به صورت آنلاین سفارش داد یا توسط خودتان مونتاژ کرد. برد مدار چاپی هم صدمه نمی بیند. اجباری نیست، اما استفاده از آن به شما امکان می دهد در اعصاب و زمان خود صرفه جویی کنید. همچنین به طور مستقل خریداری / ایجاد شده است. و آخرین مورد منبع تغذیه است. برای AVR، تامین ولتاژ 5 ولت ضروری است.

    کجا و چگونه درس بخوانیم؟

    شما نمی توانید از ابتدا شاهکار بسازید. این نیاز به دانش، تجربه و تمرین دارد. اما از کجا می توانید آنها را تهیه کنید؟ راه های مختلفی وجود دارد. در ابتدا، می توانید به طور مستقل اطلاعات لازم را در شبکه جهانی جستجو کنید. برای کسب مهارت های اولیه شغلی می توانید در دوره های برنامه نویسی (از راه دور یا حضوری) ثبت نام کنید. هر رویکرد مزایای خاص خود را دارد. بنابراین، دوره های برنامه نویسی از راه دور ارزان تر و شاید رایگان خواهد بود. اما اگر چیزی درست نشد، با جلسات حضوری، یک توسعه دهنده با تجربه می تواند به سرعت علت مشکل را پیدا کند. همچنین، آشنایی با ادبیاتی که به صورت رایگان در دسترس است، اضافی نخواهد بود. مطمئناً نمی‌توانید برخی از کتاب‌ها را ترک کنید، اما می‌توانید اطلاعات اولیه در مورد دستگاه، برنامه‌نویسی در "SI"، "Assembler" و سایر لحظات کاری را کسب کنید.

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

    این یک موضوع فوق العاده مهم است. بدون درک نحوه عملکرد پورت های ورودی/خروجی، برنامه ریزی AVR در مدار اصلا امکان پذیر نیست. از این گذشته ، تعامل میکروکنترلر با دستگاه های خارجی دقیقاً با واسطه آنها انجام می شود. در نگاه اول، یک مبتدی ممکن است فکر کند که پورت یک مکانیسم نسبتا گیج کننده است. برای جلوگیری از چنین تصوری، ما طرح کار آن را با جزئیات در نظر نخواهیم گرفت، بلکه فقط یک ایده کلی از این به دست می آوریم. پیاده سازی نرم افزار را در نظر بگیرید. به عنوان نمونه ای از یک دستگاه، میکروکنترلر AtMega8 انتخاب شد - یکی از محبوب ترین های کل خانواده AVR. یک پورت I/O از سه رجیستر تشکیل شده است که وظیفه عملیات آن را بر عهده دارند. در سطح فیزیکی، آنها به عنوان پاها درک می شوند. هر یک از آنها مربوط به یک بیت خاص در ثبات کنترل است. هر پا می تواند هم برای ورودی اطلاعات و هم برای خروجی آن کار کند. به عنوان مثال، می توانید یک عملکرد جرقه زنی LED یا یک پردازش فشار دکمه را روی آن آویزان کنید. به هر حال، سه ثبات ذکر شده عبارتند از: PORTx، PINx و DDRx. هر یک از آنها هشت بیتی هستند (به یاد داشته باشید که ما AtMega8 را در نظر می گیریم). یعنی یک بیت توسط فلان پا اشغال شده است.

    عملیات ثبت نام

    مهم ترین از نظر جهت گیری، کنترل DDRx است. 8 بیتی هم هست. مقادیر برای آن را می توان 0 یا 1 نوشت. عملکرد کنترلر هنگام استفاده از صفر و یک چگونه تغییر می کند؟ اگر بیت خاصی روی 0 تنظیم شود، پین مربوطه به حالت ورودی تغییر می کند. و خواندن داده های دستگاه های خارجی از آن امکان پذیر خواهد بود. اگر روی 1 تنظیم شود، میکروکنترلر می تواند چیزی را کنترل کند (مثلاً به ترانزیستور دستور دهید ولتاژ را عبور دهد و LED را روشن کند). دومین مورد مهم PORTx است. او مسئولیت مدیریت وضعیت پاها را بر عهده دارد. بیایید به یک مثال نگاه کنیم. فرض کنید یک پورت خروجی داریم. اگر یک منطقی را در PORTx تنظیم کنیم، سیگنالی از میکروکنترلر به دستگاه کنترل ارسال می شود تا شروع به کار کند. به عنوان مثال، LED را روشن کنید. وقتی روی صفر تنظیم شود، خاموش می شود. یعنی نیازی به کار مداوم با رجیستر کنترل DDRx نیست. و در نهایت، بیایید در مورد PINx صحبت کنیم. این رجیستر وظیفه نمایش وضعیت پین کنترلر را در زمانی که روی حالت ورودی تنظیم می شود، دارد. لازم به ذکر است که PINx فقط در حالت خواندن کار می کند. چیزی نمی توان بر آن نوشت. اما برای خواندن وضعیت فعلی پا مشکلی نیست.

    کار با آنالوگ ها

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

    ایمنی

    هنگام برنامه نویسی میکروکنترلرهای AVR در "SI" یا "Assembler"، باید بسیار با دقت کار کنید. واقعیت این است که با تنظیم ترکیب خاصی از ثبات ها و تغییر تنظیمات داخلی، می توانید با خیال راحت میکروکنترلر را مسدود کنید. این امر به ویژه در مورد فیوزها صادق است. اگر اعتمادی به صحت اقدامات آنها وجود ندارد، بهتر است از استفاده از آنها خودداری کنید. همین امر در مورد برنامه نویسان نیز صدق می کند. اگر تجهیزات کارخانه ای خریداری کنید، بدون مشکل میکروکنترلرها را فلش می کند. هنگام مونتاژ با دستان خود، ممکن است وضعیت غم انگیزی ایجاد شود که در آن برنامه نویس دستگاه را مسدود می کند. این می تواند هم به دلیل خطا در کد برنامه و هم از طریق مشکلات در خود آن اتفاق بیفتد. ضمناً در مورد یک نکته دیگر (این بار مثبت) که قبلاً گذراً ذکر شد اما هرگز به طور کامل افشا نشد. اکنون تقریباً همه میکروکنترلرهای مدرن عملکرد برنامه نویسی در مدار را دارند. چه مفهومی داره؟ فرض کنید دستگاه روی برد لحیم شده بود. و برای تغییر سیستم عامل آن، اکنون نیازی به لحیم کردن آن ندارید، زیرا چنین تداخلی می تواند به خود میکروکنترلر آسیب برساند. کافی است به پین ​​های مناسب متصل شده و از طریق آن ها آن را مجددا برنامه ریزی کنید.

    کدام مدل را انتخاب کنیم؟

    به عنوان بخشی از مقاله، AtMega8 در نظر گرفته شد. این یک میکروکنترلر نسبتاً متوسط ​​​​برای ویژگی های آن است، که با این وجود، برای اکثر صنایع دستی کافی است. اگر تمایل به ایجاد چیزی در مقیاس بزرگ وجود دارد، می توانید هیولاهای عجیب و غریب مانند Atmega128 را بگیرید. اما آنها برای توسعه دهندگان با تجربه تر طراحی شده اند. بنابراین، اگر تجربه کافی وجود ندارد، بهتر است با دستگاه های کوچک و ساده شروع کنید. علاوه بر این، آنها بسیار ارزان تر هستند. موافقم، مسدود کردن تصادفی یک میکروکنترلر برای صد روبل یک چیز است و کاملاً چیز دیگری - برای پانصد روبل. بهتر است دست خود را پر کنید و جنبه های مختلف عملکرد را درک کنید تا در آینده مقادیر قابل توجهی را از دست ندهید. در ابتدا می توانید با AtMega8 شروع کنید و سپس بر اساس نیاز خود پیمایش کنید.

    نتیجه

    بنابراین مبحث برنامه نویسی AVR در کلی ترین اصطلاح مورد توجه قرار گرفت. البته چیزهای بیشتری برای گفتن وجود دارد. بنابراین، به عنوان مثال، علامت گذاری میکروکنترلرها در نظر گرفته نشد. و می تواند خیلی چیزها را بگوید. بنابراین، اساسا میکروکنترلرها با ولتاژ 5 ولت کار می کنند. در حالی که وجود مثلاً حرف L می تواند نشان دهنده این باشد که تنها 2.7 ولت برای کارکرد دستگاه کافی است.همانطور که می بینید گاهی اوقات دانش در مورد علامت گذاری می تواند نقش بسیار مهمی در عملکرد صحیح و بادوام دستگاه ها داشته باشد. . زمان کارکرد میکروکنترلرها نیز موضوع جالبی است. هر دستگاه برای یک دوره خاص طراحی شده است. بنابراین، برخی می توانند هزار ساعت کار کنند. بقیه دارای سهام تضمینی 10000 هستند!

    برنامه نویسی میکروکنترلر

    معرفی

    بخش 2. محیط های برنامه نویسی. نمودارهای اتصال میکروکنترلر

    بخش 3. اجرای عملی برنامه بر روی میکروکنترلر

    فهرست منابع استفاده شده

    معرفی

    مرتبط بودن موضوعمیکروکنترلرها در تمام حوزه های زندگی انسان، دستگاه هایی که اطراف آن را احاطه کرده اند، استفاده می شود. سهولت اتصال و عملکرد عالی. با کمک برنامه نویسی میکروکنترلر می توان بسیاری از مشکلات عملی فناوری سخت افزار را حل کرد.

    هدف کار. بر اساس یک مثال کاربردی، ویژگی های سودمند استفاده از میکروکنترلرها، نیاز به پیاده سازی آنها در دستگاه های مختلف را نشان دهید.

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

    میکروکنترلر، علاوه بر واحد پردازش مرکزی (CPU)، دارای حافظه و دستگاه های ورودی/خروجی متعددی است: مبدل های آنالوگ به دیجیتال، کانال های انتقال اطلاعات سریال و موازی، تایمرهای بلادرنگ، مدولاتورهای عرض پالس (PWM). مولدهای پالس قابل برنامه ریزی و غیره هدف اصلی آن استفاده در سیستم‌های کنترل خودکار ساخته شده در طیف گسترده‌ای از دستگاه‌ها است: کارت‌های اعتباری، دوربین‌ها، تلفن‌های همراه، استریو، تلویزیون، ضبط‌کننده‌های ویدئویی و فیلم‌برداری، ماشین‌های لباسشویی، اجاق‌های مایکروویو، سیستم‌های اعلام سرقت، سیستم‌های احتراق موتور بنزینی، موتورهای الکتریکی لوکوموتیو، راکتورهای هسته ای و خیلی چیزهای دیگر. سیستم های کنترل جاسازی شده به چنان پدیده ای انبوه تبدیل شده اند که در واقع شاخه جدیدی از اقتصاد به نام EmbeddedSystems (سیستم های تعبیه شده) شکل گرفته است.

    ATMEL MC ها که عملکرد بسیار خوبی دارند، بسیار گسترده هستند.

    استفاده از MC را می توان به دو مرحله تقسیم کرد: مرحله اول برنامه نویسی، زمانی که کاربر برنامه ای را توسعه می دهد و آن را مستقیماً در تراشه فلش می کند و مرحله دوم هماهنگی محرک های طراحی شده با MC قابل برنامه ریزی است. به طور قابل توجهی اشکال زدایی برنامه را در مرحله اول تسهیل کنید - شبیه سازی که به صورت بصری عملکرد ریزپردازنده را شبیه سازی می کند. در مرحله دوم، یک شبیه ساز درون مدار برای اشکال زدایی استفاده می شود که دستگاهی پیچیده و گران قیمت است که اغلب برای کاربر عادی غیرقابل دسترس است.

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

    توسعه یک طرح برنامه نویس، که با سادگی، وضوح و هزینه کم مشخص می شود، هم برای برنامه نویسی کریستال ها و هم برای آموزش بصری طیف گسترده ای از کاربران در اصول برنامه نویسی MC ضروری می شود.

    بخش 1. هدف و دامنه، معماری آنها

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

    رایج ترین دستگاه های تعبیه شده شامل دستگاه های حافظه و پورت های ورودی/خروجی (I/O)، رابط های ارتباطی، تایمرها، ساعت های سیستم هستند. دستگاه های حافظه شامل حافظه دسترسی تصادفی (RAM)، حافظه فقط خواندنی (ROM)، رام قابل برنامه ریزی مجدد (EPROM)، رام قابل برنامه ریزی مجدد الکتریکی (EEPROM) می باشد. تایمرها هم شامل ساعت واقعی و هم تایمرهای وقفه هستند. امکانات I/O عبارتند از پورت های ارتباط سریال، پورت های موازی (خطوط I/O)، مبدل های آنالوگ به دیجیتال (A/D)، مبدل های دیجیتال به آنالوگ (D/A)، درایورهای نمایشگر کریستال مایع (LCD)، یا درایورهای نمایشگر فلورسنت خلاء (VFD). دستگاه های تعبیه شده قابل اعتمادتر هستند زیرا به مدارهای الکتریکی خارجی نیاز ندارند.

    برخلاف میکروکنترلر، کنترلر معمولاً بردی نامیده می شود که بر اساس یک میکروکنترلر ساخته شده است، اما اغلب در هنگام استفاده از عبارت میکروکنترلر، از نام اختصاری این دستگاه استفاده می شود و برای سادگی، پیشوند میکرو را کنار می گذارند. همچنین، هنگام اشاره به میکروکنترلرها، می توانید کلمات "chip" یا "microchip"، "crystal" (بیشتر میکروکنترلرها بر روی یک کریستال سیلیکونی ساخته می شوند)، اختصارات MK یا از میکروکنترلر انگلیسی - MC را پیدا کنید.

    برنامه میکروکنترلر میکرو مدار الکترونیکی

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

    ویژگی اصلی طبقه بندی میکروکنترلرها، عمق بیت داده های پردازش شده توسط واحد منطق حسابی (ALU) است. بر این اساس آنها به 4-، 8-، 16-، 32- و 64 بیتی تقسیم می شوند. امروزه بیشترین سهم از بازار جهانی میکروکنترلرها متعلق به دستگاه های هشت بیتی است (حدود 50 درصد از نظر ارزش). پس از آنها میکروکنترلرهای 16 بیتی و DSP (DSP - پردازشگر سیگنال دیجیتال - پردازشگر سیگنال دیجیتال)، متمرکز بر استفاده در سیستم های پردازش سیگنال هستند (هر یک از گروه ها تقریبا 20٪ از بازار را اشغال می کنند). در هر گروه، میکروکنترلرها به دستگاه های CISC و RISC تقسیم می شوند. پرتعدادترین گروه میکروکنترلرهای CISC هستند، اما در سال های اخیر روند واضحی به سمت افزایش سهم معماری RISC در میان تراشه های جدید مشاهده شده است.

    فرکانس ساعت یا به طور دقیق تر سرعت اتوبوس تعیین می کند که در واحد زمان چند محاسبه می تواند انجام شود. به طور کلی عملکرد یک میکروکنترلر و مصرف انرژی آن با افزایش فرکانس کلاک افزایش می یابد. عملکرد میکروکنترلر در MIPS (میلیون دستورالعمل در ثانیه - یک میلیون دستورالعمل در ثانیه) اندازه گیری می شود.

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

    بسته به هزینه و ابعاد دستگاهی که نیاز به کنترل دارد، الزامات مربوط به کنترلر نیز تعیین می شود. اگر شیء کنترلی ده‌ها متر در منطقه اشغال کند، مانند مبادلات تلفنی خودکار، ایستگاه‌های پایه سیستم‌های ارتباط سلولی یا خطوط ارتباطی رله رادیویی، رایانه‌های جهانی می‌توانند به عنوان کنترل‌کننده استفاده شوند. در این مورد، کنترل را می توان از طریق پورت های داخلی کامپیوتر (LPT، COM، USB یا اترنت) انجام داد. در چنین کامپیوترهایی با روشن شدن برق یک برنامه کنترلی وارد می شود که کامپیوتر جهانی را به یک کنترل کننده تبدیل می کند.

    استفاده از یک کامپیوتر جهانی به عنوان یک کنترلر، توسعه سریع سیستم های ارتباطی جدید، ارتقاء آسان آنها (با تغییر برنامه) و همچنین استفاده از واحدهای انبوه (و در نتیجه ارزان) آماده را ممکن می سازد.

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