Програмиране на микроконтролери на C от нулата. CodeVisionAVR. Обща информация за начинаещи в програмирането на езика C. Кой микроконтролер да изберете за работа

Някак си веднага се почувствах длъжен да дам съвет относно избора на среда за програмиране на AVR контролери. Само не ми хвърляйте чехли. малко съм :)

Има много езици за програмиране на микроконтролери. Средите за програмиране също са доста и е некоректно да се сравняват една с друга. Най-добрите езиципрограмирането не съществува. Това означава, че ще трябва да изберете най-подходящия език и среда за програмиране за вас.

Ако в момента сте изправени пред избор върху какво да започнете работа, тогава ето няколко препоръки за вас.

Предишен опит в програмирането.Не пренебрегвайте предишния си опит в програмирането. Дори и да беше BASIC. Дори да е било отдавна в училище. Програмирането е като карането на велосипед – след като започнете, бързо си спомняте всичко, което сте забравили. Започнете с BASIC - овладейте го - по-късно ще бъде по-лесно да изберете нещо по-подходящо за вашите цели.

Помощ от околната среда.Вашите приятели пишат ли на Паскал? Проблемът е решен за вас - пишете на Pascal! Винаги ще ви помогнат със съвет, ще ви дадат библиотеки и ще ви дадат готови проекти за изучаване. Като цяло те ще се радват да ви приветстват в тяхната общност. Ако направите обратното, ще получите обратния резултат. Приятелите на CIS индустрията ще ви кълват, ако решите да изучавате Assembler. Не очаквайте помощ.

Добра книга за AVR програмиране ще помогне много. За съжаление има много малко от тях. Ако попаднете на книга и смятате, че всичко е обяснено много достъпно, опитайте я. Не препоръчвам да учите от електронни книги, в краен случай ги разпечатайте. Много е неудобно да превключвате между средата и текста на файла на книгата. Много по-приятно е да прочетете книга и да я опитате веднага, без да се разсейвате от превключване; освен това можете да правите бележки в полетата и да записвате идеите, които възникват.

Средата за програмиране е по-проста.Ако има няколко програмни среди за вашия език, от които да избирате, не се колебайте, изберете тази, която е по-проста. Нека бъде по-малко функционален. Оставете я да компилира ужасно раздут код. Основното нещо е просто да започнете да работите. След като се почувствате удобно в проста среда, можете лесно да преминете към по-напреднала и „правилна“ среда. И не слушайте тези, които казват, че ще загубите повече време - грешат. От учениците в началните класове не се иска да четат „Война и мир“, дават им се по-прости книги – с картинки.

библиотеки.Наличието на библиотеки е противоречиво за изучаването на езици. Разбира се, по-късно те ще направят живота много по-лесен, но в началото библиотеките „Черна кутия“ са неразбираеми и не допринасят наистина за разбирането на езика. От друга страна, те правят програмите по-лесни за четене и позволяват на начинаещия да създава сложни програми без много усилия. Така че не се притеснявайте твърде много за тяхното присъствие. Поне на първо време.

Ефективен код.Изборът на среда за програмиране, за да се научите да програмирате въз основа единствено на това колко ефективен е кодът, който компилира, е лоша идея. Важното е да се чувстваш комфортно, когато започнеш да учиш – какво ще излезе от това е десетото нещо. Разбира се, можете да работите върху това по-късно.

Магьосници.Всяко устройство на борда на чипа трябва да бъде конфигурирано с помощта на портове. Процедурата е доста досадна и са необходими листове с данни. Освен това има нюанси, които не са лесни за разбиране от начинаещ. Ето защо е много желателно да има магьосници в околната среда. Vyzards са автоматични тунери за SPI, I2C, USART и др. Колкото повече устройства се поддържат, толкова по-добре. Задавате необходимите периферни параметри, а съветникът сам генерира код, който ще предостави посочените параметри. Прави живота много по-лесен.


Общи препоръкитакова - програмирането в началния етап трябва да бъде възможно най-просто (дори примитивно). Средата за програмиране трябва да бъде лесна за научаване (тъй като първо трябва да овладеете програмирането и да не губите време в ръчкане с настройките). За предпочитане е русифициран. Руско ръководство и примерни програми също биха били полезни. Възможността за мигане на кристала от околната среда е желателна. След това, когато усвоите основите на програмирането, можете да преминете към по-сложни черупки.


Последна препоръка: работете с истински кристал. Не се страхувайте да го изгорите. Натрупайте практически опит. Работата с емулатори (например Proteus), макар и да ви освобождава от човъркането с поялника, никога няма да може да ви достави удовлетворението, което ще получите от работещата програма и първото мигане на светодиода! Разбирането, че сте направили реално работеща диаграма със собствените си ръце, ви дава увереност и стимул да продължите напред!

(Посетен 7377 пъти, 1 посещения днес)

Здравей, скъпи Хабражител!

В тази статия искам да говоря за това как веднъж реших да започна да програмирам микроконтролери, какво беше необходимо за това и какво се случи в крайна сметка.

Темата за микроконтролерите ме заинтересува отдавна, още през 2001 г. Но тогава се оказа проблематично да получа програмист на мястото си на пребиваване и нямаше въпрос за закупуването му чрез интернет. Трябваше да отложа този въпрос за по-добри времена. И тогава, един прекрасен ден, открих, че са дошли по-добри времена, без да напускам дома, мога да купя всичко, от което се нуждая. Реших да го пробвам. И така, от какво имаме нужда:

1. Програмист
Има много опции на пазара - от най-евтините ISP (In-System Programming) програмисти за няколко долара до мощни програмисти за отстраняване на грешки за няколкостотин. Нямайки много опит по този въпрос, първо реших да опитам един от най-простите и най-евтините - USBasp. Едно време го купих от eBay за 12$, сега можете да го намерите дори за 3-4$. Това всъщност е китайска версия на програмиста от Томас Фишл. Какво мога да кажа за него? Само едно нещо - работи. В допълнение, той поддържа доста AVR контролери от серията ATmega и ATtiny. Под Linux не изисква драйвер.

За да флашнете фърмуера, трябва да свържете изходите на програматора VCC, GND, RESET, SCK, MOSI, MISO със съответните изходи на микроконтролера. За простота сглобих спомагателната верига директно върху макетната платка:

Отляво на дъската е същият микроконтролер, който ще мигаме.

2. Микроконтролер
Не се занимавах много с избора на микроконтролер и взех ATmega8 от Atmel - 23 I/O пина, два 8-битови таймера, един 16-битов, честота до 16 MHz, ниска консумация (1-3,6 mA) , евтино ($2). Като цяло, за начало - повече от достатъчно.

Под Linux комбинацията 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.

За Windows ще трябва да инсталирате драйвер. Иначе проблеми няма. В името на научния интерес изпробвах комбинацията AVR Studio + eXtreme Burner на Windows. Отново всичко работи чудесно.

Да започнем с програмирането

AVR контролерите могат да бъдат програмирани както на асемблер (AVR асемблер), така и на C. Тук според мен всеки трябва да направи своя избор в зависимост от конкретната задача и предпочитанията си. Лично аз първо започнах да се занимавам с асемблер. Когато програмирате на асемблер, архитектурата на устройството става по-ясна и имате усещането, че навлизате директно във вътрешността на контролера. Освен това вярвам, че в програми, които са особено критични по размер и производителност, познаването на асемблер може да бъде много полезно. След като се запознах с AVR асемблера, пропълзях до C.

След като се запознах с архитектурата и основните принципи, реших да събера нещо полезно и интересно. Тук дъщеря ми ми помогна, тя играе шах и една хубава вечер каза, че иска да има часовник-таймер за игри с време. БАМ! Ето я - идеята на първия проект! Можете, разбира се, да ги поръчате от eBay, но аз исках да си направя собствен часовник, с черни... ъъъ... индикатори и бутони. Казано, сторено!

Беше решено да се използват два 7-сегментни диодни индикатора като дисплей. За управление бяха достатъчни 5 бутона - „Играч 1“, „Играч 2“, „Нулиране“, „Настройки“ и „Пауза“. Е, не забравяйте за звуковата индикация за края на играта. Изглежда, че това е всичко. Фигурата по-долу показва обща схема за свързване на микроконтролера към индикатори и бутони. Ще ни трябва, когато анализираме изходния код на програмата:

Дебрифинг

Нека започнем, както се очаква, от входната точка на програмата - основната функция. Всъщност няма нищо забележително в това - настройка на портове, инициализация на данни и безкраен цикъл от натискания на бутони за обработка. Е, извикване на sei() - разрешаване на обработка на прекъсване, повече за тях малко по-късно.

Int main(void) ( init_io(); init_data(); sound_off(); sei(); while(1) ( handle_buttons(); ) return 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 във входни пинове, а останалите в изходни пинове. 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) ( Таймер1--; ако (Таймер1 == 0) process_timeoff(); ) ако (ActiveTimer == 2 && Таймер2 > 0) ( Таймер2--; ако (Таймер2 == 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((Timer1%60)/10 , 0b00000010); _delay_ms(0.25); display_number((Timer1%60)%10, 0b00000001); _delay_ms(0.25); display_number((Timer2/60)/10, 0b10000000); _delay_ms(0.25); display_number((Timer2/ 60)%10, 0b01000000); _delay_ms(0.25); display_number((Timer2%60)/10, 0b00100000); _delay_ms(0.25); display_number((Timer2%60)%10, 0b00010000); _delay_ms(0.25); PORTD = 0; ) void display_number(int число, int маска) ( PORTB = number_mask(номер); PORTD = маска; )

Функцията за показване използва метод на динамично показване. Факт е, че всеки отделен индикатор има 9 контакта (7 за управление на сегмента, 1 за точка и 1 за захранване). За да контролирате 4 цифри, ще са необходими 36 контакта. Твърде разточително. Следователно извеждането на цифри към индикатор с няколко цифри е организирано по следния принцип:

Напрежението се подава алтернативно към всеки от общите контакти, което ви позволява да маркирате желания номер на съответния индикатор, като използвате същите 8 контролни контакта. При достатъчно висока изходна честота изглежда като статична картина за окото. Ето защо всичките 8 захранващи контакта на двата индикатора в схемата са свързани към 8 изхода на порт D, а 16 сегментно-контролиращи контакта са свързани по двойки и свързани към 8 изхода на порт B. Така функцията на дисплея със закъснение от 0,25 ms последователно показва желаното число на всеки от индикаторите. Накрая се изключват всички изходи, които подават напрежение към индикаторите (команда 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(int key) ( int bit; switch (key) ( case KEY_SETUP: bit = SETUP_BIT; break; case KEY_RESET: bit = RESET_BIT; break; case KEY_PAUSE: bit = PAUSE_BIT; break; case KEY_PLAYER1: bit = PLAYER1_BIT; break; case KEY_PLAYER2: bit = PLAYER2_BIT; break; default: return; ) if (bit_is_clear( BUTTON_PIN, бит)) ( if (_pressed == 0) ( _delay_ms(DEBOUNCE_TIME); if (bit_is_clear(BUTTON_PIN, bit)) ( _pressed |= ключ; // ключ за превключване на действие (клавиш) ( случай 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); ) ) ) else ( _pressed &= ~ключ; ))

Тази функция проверява последователно всичките 5 бутона и обработва кликването, ако има такова. Щракването се регистрира чрез отметка bit_is_clear(BUTTON_PIN, bit) , т.е. бутонът е натиснат, ако съответният вход е свързан към маса, което ще стане според схемата при натискане на бутона. Необходими са забавяне с продължителност DEBOUNCE_TIME и многократна проверка, за да се избегнат множество ненужни операции поради отскачане на контакт. Запазването на натиснатия статус в съответните битове на променливата _pressed се използва за предотвратяване на повторно задействане, когато бутонът е натиснат за дълго време.
Функциите за обработка на кликове са доста тривиални и смятам, че нямат нужда от допълнителни коментари.

Пълен текст на програмата

#define F_CPU 4000000UL #include #включи #включи #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 KEY_SETUP 0b00000001 #define KEY_RESET 0b000000 10 # define KEY_PAUSE 0b00000100 #define KEY_PLAYER1 0b00001000 #define KEY_PLAYER2 0b00010000 volatile int ActiveTimer = 0; volatile int Timer1 = 0; volatile int Timer2 = 0; volatile int _buzzer = 0; volatile int _pressed = 0; // декларации на функции void init_io(); void init_data(); int number_mask(int num); невалидни handle_buttons(); void handle_button(int ключ); невалиден процес_настройка(); анулиран process_reset(); невалиден процес_пауза(); анулиран process_timeoff(); анулиран process_player1(); анулиран process_player2(); празен дисплей (); void display_number(int маска, int число); void sound_on(int интервал); невалиден 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(); ) return 0; ) void init_io() ( // задаване на изход DDRB = 0xFF; DDRD = 0xFF ; // задайте вход DDRC = 0b11100000; // изтеглящи резистори 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 = RESET_BIT ; break; case KEY_PAUSE: bit = PAUSE_BIT; break; case KEY_PLAYER1: bit = PLAYER1_BIT; break; case KEY_PLAYER2: bit = PLAYER2_BIT; break; default: return; ) if (bit_is_clear(BUTTON_PIN, bit)) ( if (_pressed == 0). case KEY_PAUSE: process_pause(); break; case KEY_PLAYER1: process_player1(); break; case KEY_PLAYER2: process_player2(); break; ) sound_on(15); ) ) ) else ( _pressed &= ~key; ) ) 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() ( display_number((Timer1/60)/10, 0b00001000) ; _delay_ms(0.25); display_number((Timer1/60)%10, 0b00000100); _delay_ms(0.25); display_number((Timer1%60)/10, 0b00000010); _delay_ms(0.25); display_number((Timer1%60)% 10, 0b00000001); _delay_ms(0.25); display_number((Timer2/60)/10, 0b10000000); _delay_ms(0.25); display_number((Timer2/60)%10, 0b01000000); _delay_ms(0.25); display_number((Timer2) %60)/10, 0b00100000); _delay_ms(0.25); display_number((Timer2%60)%10, 0b00010000); _delay_ms(0.25); PORTD = 0; ) void display_number(int число, int маска) ( PORTB = number_mask (номер); PORTD = маска; ) void sound_on(int интервал) ( _buzzer = интервал; // поставяне на зумер пин висок PORTC |= 0b00100000; ) void sound_off() ( // поставяне на зумер пин нисък PORTC &= ~0b00100000; )

Прототипът е сглобен на макет.

Урок 0.

И така, днес откриваме серия от уроци по програмиране на микроконтролери от семейството AVR.

Днес ще бъдат обсъдени следните въпроси:

  1. Какво е микроконтролер?
  2. Къде се използват микроконтролери?

Въведение.

Микроконтролерите са навсякъде. В телефони, перални машини, „умни домове“, машинни инструменти във фабрики, а също и в безброй други технически устройства. Широкото им използване прави възможно замяната на сложни аналогови схеми с по-компресирани цифрови.

И така, какво е микроконтролер?

Микроконтролер (Микроконтролер, MCU) - микросхема, предназначена за управление на електронни устройства. Можете да си го представите като прост компютър, способен да взаимодейства с външни устройства. Например отваряне и затваряне на транзистори, получаване на данни от температурни сензори, показване на данни на LCD екрани и т.н. В допълнение, микроконтролерът може да извършва различни обработки на входни данни, точно като вашия персонален компютър.

Тоест микроконтролерите ни предлагат почти неограничени възможности за управление на всякакви устройства, благодарение на наличието на I/0 портове (входно/изходни портове), както и възможността за тяхното програмиране.

Къде се използват микроконтролери?

  1. Домакински уреди (Перални, микровълнови печки и др.).
  2. Мобилни технологии (Роботи, роботизирани системи, комуникационно оборудване и др.).
  3. Индустриално оборудване (системи за управление на машини).
  4. Компютърни технологии (Дънни платки, системи за управление на периферни устройства).
  5. Развлекателно оборудване (Детски играчки, декорации).
  6. Транспорт (системи за управление на автомобилни двигатели, системи за сигурност)

Това не е пълен списък с приложения за микроконтролери. Често е много изгодно да се замени набор от контролни чипове с един микроконтролер, поради опростеното производство и намалената консумация на енергия.

Първи стъпки с AVR

AVR- семейство микроконтролери от Atmel.Те имат достатъчна производителност за повечето любителски устройства. Те също така се използват широко в индустрията.

Има различни езици за програмиране на AVR микроконтролери, но може би най-подходящите са асемблер и C, тъй като тези езици най-добре изпълняват всички необходими възможности за управление на хардуера на микроконтролера.

Асемблерният език е език за програмиране от ниско ниво, който използва директния набор от инструкции на микроконтролера. Създаването на програма на този език изисква добро познаване на командната система на програмируемия чип и достатъчно време за разработване на програмата. Асемблерният език е по-нисък от C в скоростта и удобството на разработване на програми, но има забележими предимства в размера на крайния изпълним код и, съответно, скоростта на неговото изпълнение.

C ви позволява да създавате програми с много по-голям комфорт, предоставяйки на разработчика всички предимства на езика от високо ниво.
Още веднъж трябва да се отбележи, че архитектурата и командната система на AVR са създадени с прякото участие на разработчиците на компилатора на езика C и отчитат характеристиките на този език. Компилирането на C изходен код е бързо и създава компактен, ефективен код.

Основните предимства на C пред асемблера: висока скорост на разработка на програми; универсалност, която не изисква задълбочено проучване на архитектурата на микроконтролера; по-добра документируемост и четимост на алгоритъма; наличие на библиотеки с функции; поддръжка за изчисления с плаваща запетая.

Езикът C хармонично съчетава възможностите за програмиране на ниско ниво със свойствата на езика на високо ниво. Способността за програмиране на ниско ниво ви позволява лесно да работите директно с хардуера, а свойствата на езика на високо ниво ви позволяват да създавате лесно четим и модифицируем програмен код. В допълнение, почти всички C компилатори имат способността да използват вмъквания на асемблер за писане на програмни секции, които са критични по отношение на времето за изпълнение и потреблението на ресурси.

С една дума, C е най-удобният език както за начинаещи, запознаващи се с AVR микроконтролери, така и за сериозни разработчици.

Компилаторите се използват за преобразуване на изходния код на програма във файл на фърмуера на микроконтролера.

Atmel предоставя мощен асемблиращ компилатор, който е включен в средата за разработка Atmel Studio, работеща под Windows. Заедно с компилатора, средата за разработка съдържа дебъгер и емулатор.
Atmel Studio е напълно безплатно и достъпно на уебсайта на Atmel.

В момента има доста C компилатори за AVR. За най-мощен от тях се смята компилаторът на IAR Systems от Стокхолм. Неговите служители участваха в разработването на командната система AVR в средата на 90-те години. IAR C Compiler има обширни възможности за оптимизиране на кода и идва като част от интегрираната среда за разработка на IAR Embedded Workbench (EWB), която включва също асемблерен компилатор, линкер, мениджър на проекти и библиотеки и дебъгер. Цената на пълната версия на пакета е 2820 EUR. От уебсайта на компанията можете да изтеглите безплатна пробна версия за 30 дни или неограничена версия с ограничение за размера на кода от 4 KB.

Американската компания Image Craft от Пало Алто, Калифорния произвежда компилатор на език C, който придоби доста широка популярност. JumpStart C за AVR има приемлива оптимизация на кода и не много висока цена (от $50 до $499 в зависимост от версията). Демо версията на JumpStart C за AVR е напълно функционална за 45 дни.

Румънският компилатор Code Vision AVR C придоби не по-малка популярност, цената на пълната версия на този компилатор е сравнително ниска и възлиза на 150 евро. Компилаторът идва с интегрирана среда за разработка, която в допълнение към стандартните функции включва доста интересна функция - CodeWizardAVR Automatic Program Generator. Наличието на сериен терминал в средата за разработка ви позволява да отстранявате грешки в програми, като използвате серийния порт на микроконтролера. Можете да изтеглите безплатна пробна версия от разработчиците с ограничение за размера на кода от 4 KB и деактивирано запазване на генерирания изходен код в C.

Компанията MikroElektronika, разположена в сръбския град Белград, произвежда цяло семейство компилатори за AVR микроконтролери. Компилатор за езика C, наречен mikroC PRO за AVR, струва $249. Има и mikroBasic и mikroPascal на същата цена. На уебсайта на разработчиците има демо версии с ограничение за размер на кода от 4096 байта. Предимството на това семейство компилатори е единна платформа и единна идеология, която може да осигури лесен преход не само между езици, но и между микроконтролери (има версии на компилатор за PIC, STM32, 8051...).

Интегрираната среда за разработка стана наистина емблематична. Той включва мощни компилатори за C и асемблер, програмиста AVRDUDE, програма за отстраняване на грешки, симулатор и много други поддържащи програми и помощни програми. WinAVR се интегрира безпроблемно със средата за разработка AVR Studio на Atmel. Асемблерът е идентичен по входен код с асемблера на AVR Studio. Компилаторите C и асемблер имат способността да създават файлове за отстраняване на грешки във формат COFF, което ви позволява да използвате не само вградени инструменти, но и да използвате мощния симулатор на AVR Studio. Друго важно предимство е, че WinAVR се разпространява безплатно без ограничения (производителите поддържат GNU General Public License).

Като обобщение си струва да се каже, че WinAVR е идеален избор за тези, които започват да овладяват AVR микроконтролери. Именно тази среда за разработка се счита за основна в този курс.

Киселев Роман, май 2007 г Статията е актуализирана на 26 май 2014 г

И така, какво е микроконтролер (наричан по-долу MK)? Това е, относително казано, малък компютър, разположен в една интегрална схема. Има процесор (аритметична логическа единица или ALU), флаш памет, EEPROM памет, много регистри, I/O портове, както и допълнителни функции като таймери, броячи, компаратори, USART и т.н. След подаване на захранване , микроконтролерът се стартира и започва да изпълнява програмата, съхранена в неговата флаш памет. В същото време той може да контролира голямо разнообразие от външни устройства чрез I/O портове.

Какво означава това? Това означава, че в MK можете да внедрите всяка логическа схема, която ще изпълнява определени функции. Това означава, че MK е микросхема, вътрешното съдържание на която всъщност създаваме сами. Това позволява, закупувайки няколко напълно идентични MK, да сглобите напълно различни схеми и устройства върху тях. Ако искате да направите някакви промени в работата на електронно устройство, няма да е необходимо да използвате поялник, ще трябва само да препрограмирате MK. В този случай дори не е необходимо да го премахвате от вашето устройство, ако използвате AVR, тъй като тези MK поддържат програмиране в рамките на веригата. По този начин микроконтролерите преодоляват празнината между програмирането и електрониката.

AVR са 8-битови микроконтролери, т.е. тяхното ALU може да изпълнява прости операции само с 8-битови числа в един тактов цикъл. Сега е време да поговорим за това кой MK ще използваме. Работя с ATMega16 MK. Той е много разпространен и може да бъде закупен в почти всеки магазин за радиочасти за около 100 рубли. Ако не го намерите, тогава можете да закупите всеки друг MK от серията MEGA, но в този случай ще трябва да потърсите документация за него, тъй като едни и същи „крака“ на различни MK могат да изпълняват различни функции и от свързване, изглежда, ако всички заключения са правилни, може да получите работещо устройство или може би просто облак от вонящ дим. Когато купувате ATMega16, уверете се, че идва в голям 40-пинов DIP пакет и също така купете гнездо за него, в което може да се постави. За да работите с него, ще ви трябват и допълнителни устройства: светодиоди, бутони, конектори и др.

ATMega16 има много голям брой разнообразни функции. Ето някои от неговите характеристики:

  • Максимална тактова честота – 16 MHz (8 MHz за ATMega16L)
  • Повечето команди се изпълняват в един такт
  • 32 8-битови работни регистъра
  • 4 пълни 8-битови I/O порта
  • два 8-битови таймера/брояча и един 16-битов
  • 10-битов аналогово-цифров преобразувател (ADC)
  • вътрешен тактов генератор на 1 MHz
  • аналогов компаратор
  • интерфейси SPI, I2C, TWI, RS-232, JTAG
  • вътрешносхемно програмиране и самопрограмиране
  • модул за широчинно-импулсна модулация (PWM).

Пълните характеристики на това устройство, както и инструкциите за тяхното използване, можете да намерите в справочника (Лист с данни) за този MK. Вярно, на английски е. Ако знаете английски, не забравяйте да изтеглите този лист с данни, той съдържа много полезна информация.

Нека най-накрая да се заемем с работата. Препоръчвам да направите специална платка за разработка и отстраняване на грешки за микроконтролера, на която можете да сглобите всяка електрическа верига с микроконтролер без поялник (или почти без него). Използването на такава платка значително ще улесни работата с MK и ще ускори процеса на изучаване на неговото програмиране. Изглежда така:

Какво ще ви трябва за това?

Първо, ще ви трябва самата дъска. Купих готов в магазин за радиочасти за 115 рубли. След това запоих всички необходими части към него. Резултатът е невероятно удобно нещо, на което можете да сглобите всяка електрическа верига за няколко минути, като свържете кабели и инсталирате микросхеми и индикатори.

За да свържете елементи на веригата, е много удобно да използвате кабели с конектори в краищата. Тези конектори се поставят върху „краката“, стърчащи до всеки порт на MK. Микроконтролерът трябва да бъде инсталиран в гнездото, а не запоен към платката, в противен случай ще бъде много трудно да го премахнете, ако случайно го изгорите. По-долу е pinout на ATMEGA16 MK:

Нека обясним кои крака ни интересуват сега.

  • VCC - тук се подава захранване (4,5 - 5,5 V) от стабилизиран източник
  • GND – земя
  • RESET – нулиране (при ниско ниво на напрежение)
  • XTAL1, XTAL2 – тук е свързан кварцов резонатор
  • PA, PB, PC, PD – входно/изходни портове (съответно A, B, C и D).

Всичко, което произвежда 7-11 V DC, може да се използва като източник на захранване. За стабилна работа на МК е необходимо стабилизирано захранване. Като стабилизатор можете да използвате микросхеми от серия 7805. Това са линейни интегрирани стабилизатори, чийто вход се захранва с 7-11 V постоянен нестабилизиран ток, а изходът е 5 V стабилизиран ток. Преди и след 7805 трябва да инсталирате филтърни кондензатори (електролитни за филтриране на нискочестотни смущения и керамични за високочестотни). Ако не можете да намерите стабилизатор, тогава можете да използвате като източник на захранване батерия от 4,5 V. MK трябва да се захранва директно от него.

По-долу е дадена диаграма на MK връзката:

Нека сега да разберем какво е какво тук.

BQ1 е кварцов резонатор, който задава работната честота на MK. Можете да зададете до 16 MHz, но тъй като планираме да работим в бъдеще с COM порт, препоръчвам да използвате резонатори за следните честоти: 14.7456 MHz, 11.0592 MHz, 7.3725 MHz, 3.6864 MHz или 1,8432 MHz (по-късно ще стане ясно защо). Използвах 11.0592 MHz. Ясно е, че колкото по-висока е честотата, толкова по-висока е скоростта на устройството.

R1 е издърпващ резистор, който поддържа напрежение от 5 V на входа RESET. Ниско ниво на напрежение на този вход показва нулиране. След нулирането MK се зарежда (10 - 15 ms) и отново започва да изпълнява програмата. Тъй като това е вход с висок импеданс, не можете да го оставите „да виси във въздуха“ - малък пикап върху него ще доведе до неочаквано нулиране на MK. Точно за това е R1. За надеждност препоръчвам също да инсталирате кондензатор C6 (не повече от 20 µF).

SB1 – бутон за нулиране.

Кварцовият резонатор и филтърният кондензатор C3 трябва да бъдат разположени възможно най-близо до MK (не повече от 5-7 cm), тъй като в противен случай може да възникнат смущения в проводниците, което води до неизправности на MK.

Синият правоъгълник на диаграмата очертава самия програмист. Удобно е да го направите под формата на проводник, единият край на който е включен в LPT порта, а другият в определен конектор до MK. Жицата не трябва да е много дълга. Ако възникнат проблеми с този кабел (обикновено не, но всичко може да се случи), ще трябва да запоите адаптера Altera ByteBlaster. Как да направите това е написано в описанието на програмиста AVReal.

Сега, след като се справихме с хардуера, е време да преминем към софтуера.

Има няколко среди за разработка за програмиране на AVR. Първо, това е AVR Studio - официалната система за програмиране на Atmel. Позволява ви да пишете на асемблер и да дебъгвате програми, написани на асемблер, C и C++. IAR е търговска система за програмиране на C, C++ и асемблер. WinAVR е компилатор с отворен код. AtmanAVR е система за програмиране за AVR с интерфейс, почти напълно същият като Visual C++ 6. AtmanAVR също ви позволява да отстранявате грешки в програми и съдържа много помощни функции, които улесняват писането на код. Тази система за програмиране е комерсиална, но според лиценза можете да я използвате безплатно за един месец.

Предлагам да започнете да работите с IAR като най-прозрачната среда за разработка. В IAR проектът се създава изцяло на ръка; следователно, след като сте завършили няколко проекта, вече ясно ще знаете какво означава всеки ред от код и какво ще се случи, ако го промените. Когато работите с AtmanAVR, ще трябва или да използвате предварително създаден шаблон, който е много тромав и труден за разбиране от човек без опит, или да имате много проблеми със заглавните файлове, когато сглобявате проекта от нулата. След като се занимавахме с IAR, впоследствие ще разгледаме други компилатори.

Така че, първо вземете IAR. Среща се много често и намирането му не би трябвало да е проблем. След като изтеглите IAR 3.20 от някъде, инсталирайте компилатора/работната среда и го стартирайте. След това можете да започнете работа.

След като стартирате IAR, изберете файл/ново/работно пространство, изберете пътя до нашия проект и създайте папка за него и му дайте име, например „Prog1“. Сега нека създадем проект: Проект/Създаване на нов проект…Нека го наречем също “Prog1”. Щракнете с десния бутон върху заглавието на проекта в дървото на проекта и изберете „Опции“

Тук ще конфигурираме компилатора за конкретен MK. Първо, трябва да изберете типа процесор ATMega16 в раздела Target, да поставите отметка в квадратчето Enable bit definitions in I/O-include files в раздела Library Configuration (така че да можете да използвате имената на битове на различни MK регистри в програмния код ), и изберете типа C библиотека там /EU++. В категорията ICCAVR трябва да поставите отметка в квадратчето Разрешаване на многобайтова поддръжка в раздела Език и да изключите оптимизацията в раздела Оптимизация (в противен случай ще съсипе първата ни програма).

След това изберете категорията XLINK. Тук трябва да определите формата на компилирания файл. Тъй като сега задаваме опции за режима за отстраняване на грешки, както е описано в заглавието, трябва да получим файл за отстраняване на грешки като изход. По-късно ще го отворим в AVR Studio. За да направите това, трябва да изберете разширението.cof, а типът на файла е ubrof 7.

Сега щракнете върху OK, след което променете Debug на Release.

Отидете отново на Опции, където всички параметри с изключение на XLINK са зададени на едни и същи. В XLINK променете разширението на .hex и файловия формат на intel-standart.

Това е всичко. Сега можете да започнете да пишете първата си програма. Създайте нов източник/текст и въведете следния код в него:

#включи"iom16.h" short unsigned int i; невалиденосновен( невалиден) (DDRB = 255; PORTB = 0; докато(1) { ако(PORTB == 255) PORTB = 0; друго PORTB++; за(i=0; i

Файлът "iom16.h" се намира в папката (C:\Program Files)\IAR Systems\Embedded Workbench 3.2\avr\inc. Ако използвате друг MK, например ATMega64, изберете файла „iom64.h“. Тези заглавни файлове съхраняват информация за MK: имената на регистрите, битовете в регистрите и имената на прекъсванията. Всеки отделен щифт на порт A, B, C или D може да действа като вход или изход. Това се определя от Data Direction Register (DDR). 1 прави крака изход, 0 вход. По този начин, като зададем например DDRA = 13, правим "краката" PB0, PB2, PB3 изходи, останалите - входове, т.к. 13 в двоична система е 00001101.

PORTB е регистър, който определя състоянието на щифтовете на порта. След като написахме 0 там, задаваме напрежението на всички изходи на 0 V. След това има безкраен цикъл. Когато програмират МК, те винаги правят безкраен цикъл, в който МК извършва някакво действие, докато не бъде нулиран или докато не настъпи прекъсване. В този цикъл те пишат, така да се каже, „фонов код“, който MK изпълнява като последно нещо. Това може да бъде например показване на информация на дисплей. В нашия случай съдържанието на регистъра PORTB се увеличава, докато се напълни. След това всичко започва отначало. И накрая, десет хиляди цикъл for. Това е необходимо за формиране на видимо забавяне при превключване на състоянието на порт B.



Сега запазваме този файл в папката на проекта като Prog1.c, копираме файла iom16.h в папката на проекта, избираме Project/Add Files и добавяме „iom16.h“ и „Prog1.c“. Изберете Release, натиснете F7, програмата се компилира и трябва да се появи съобщението:


Общ брой грешки: 0
Общ брой предупреждения: 0

Ето снимка на моя програмист:

Изтеглете програмиста AVRel. Копирайте го (AVReal32.exe) в папката Release/exe, където трябва да се намира файла Prog1.hex. Захранваме МК, свързваме кабела за програмиране. Отворете Far Manager (най-удобно е да флашнете MK), отидете в тази папка, натиснете Ctrl+O. Тъй като имаме напълно нов MK, ние неща

avreal32.exe +MEGA16 -o11.0592MHZ -p1 -fblev=0,jtagen=1,cksel=F,sut=1 –w

Не забравяйте да въведете правилната честота, ако не използвате 11059200 Hz! В същото време т.нар предпазители – регистри, които контролират работата му (използване на вътрешен генератор, Jtag и др.). След това е готов да приеме първата програма. Програмистът получава използвания LPT порт, честота, име на файл и други като параметри (всички те са изброени в описанието на AVReal). Набираме:

Avreal32.exe +Mega16 -o11.0592MHz -p1 -e -w -az -% Prog1.hex

Ако връзката е правилна, програмистът ще отчете успешно програмиране. Няма гаранция, че това ще работи от първия път (при първото извикване на програмата). Аз самият понякога се програмирам втори път. Може би LPT портът е повреден или има смущения в кабела. Ако възникнат проблеми, проверете внимателно кабела си. От моя собствен опит знам, че 60% от неизправностите са свързани с липса на контакт на правилното място, 20% с наличието на ненужен и още 15% с погрешно запояване на грешното нещо към грешното нещо. Ако всичко друго се провали, прочетете описанието на програмиста и опитайте да изградите Byte Blaster.

Да приемем, че всичко работи за вас. Ако сега свържете осем светодиода към порт B на MK (направете това с изключен MK и е препоръчително да включите 300-400 Ohm резистори последователно със светодиодите) и подадете захранване, ще се случи малко чудо - „ вълна” ще тече през тях!

© Киселев Роман
май 2007 г


Връх