Программирование avr контроллеров для начинающих. Основы программирования микроконтроллеров AVR. Программирование микроконтроллеров AVR фирмы Atmel

Людей, работающих с программной частью микроконтроллеров, редко причисляют к классическим разработчикам ПО. Всё дело в том, что помимо софтверных знаний, им требуются ещё кое-какие сведения об используемом железе. Многих программистов такие знания не касаются вовсе.

Плюс, разработчик приложений или сайтов всегда подсознательно стремится к триумфу. Создание уникального и популярного продукта является той отметкой, разделяющей карьеру на нормальную и успешную. А создавая программу для микроконтроллера, вы вряд ли будете думать об общественной оценке вашего вклада. Впрочем, давайте по порядку.

Возраст

Начнём с главного: когда уже (ещё) можно начать прокладывать свой путь в профессию? Ответ предсказуем: чем раньше, тем лучше. И изобилие специальных наборов для детей к этому располагает. Даже дело не в том, что с возрастом вам будет сложнее перестраиваться и обучаться этой дисциплине. Просто опыт, как и во многих других IT-профессиях, здесь играет решающее значение.

Но не всё так плохо. Всё же в России этот рынок не очень развит. Начав путь разработчика ПО для МК после 30, вы сможете сделать неплохую карьеру в какой-то одной сфере или конкретном месте деятельности. Если, конечно, не пытаться стать «многостаночником». Всегда бывают исключения, но многое зависит от вашей прошлой деятельности. Наверное, стоит принять во внимание, что даже 10 лет в этой профессии не впечатляют работодателя.

Знания

От пустых слов перейдём к реальным требованиям. «MustKnow» в программировании микроконтроллеров - язык C/C++. Да, мировые тенденции сейчас указывают на переход на более совершенные или хотя бы простые языки ( Arduino или D). Но это будущее довольно отдалённое, закладывать путь в него можно разве что сегодняшним школьникам младших классов.

Кроме того, будет очень полезным знание ассемблера. Это необходимо для пошагового отслеживания исполнения кода, чтобы избежать плавающих ошибок и неоправданных потерь в быстродействии.

В остальном довольно общая компьютерная наука: протоколы передачи, простейшее знание электроники и схемотехники (хотя бы принципы работы АЦП/ЦАП, работать с ключами, питанием и пр.), умение читать (и понимать) техническую документацию на английском языке. Но главное - не работать по принципу “научного тыка”, в противном случае ваши микроконтроллеры рискуют превратиться в “камни”.

Еще один совет: постигать все эти знания необходимо на практике. Начать можно с дешёвых, но эффективных готовых плат со всей необходимой обвязкой, вроде Arduino или Raspberry Pi, которые в будущем наверняка станут для вас хорошими помощниками. А уже потом, если возникнет желание, поиграть с периферией.

Литература

На прошлой неделе, подачи одного из пользователей GeekBrains, я всерьёз задумался над вопросом “Где можно пройти курсы по программированию микроконтроллеров?”, да и вообще о профильной литературе в целом (и это несмотря на профильное высшее образование и около 10 лет опыта работы). Дело не в том, что их не существует (есть и курсы , и книги), просто главный инструмент разработчика ПО для МК - техническая документация, поставляемая вместе с платформой.

Все универсальные книги могут описать отличия, преимущества и недостатки тех или иных микроконтроллеров, на что обратить внимание при написании кода, обучить “красоте” и основным принципам. Но огромный плюс и он же главный недостаток данной профессии - подробная индивидуальная инструкция по работе с каждым более-менее серьёзным контроллером.

Это означает, что абсолютно любой человек может взять, прочитать её и через несколько мгновений организовать стандартное мигание “светодиодами”. Но даже с 50 годами стажа вы не сможете сесть за незнакомый микроконтроллер и, не читая документацию, сделать с ним что-то полезное (придётся, как минимум взглянуть на расположение контактов и их назначение по умолчанию).

IDE

Как и у популярных направлений программирования, здесь также имеются собственные IDE. Каждая крупная компания выпускает собственную среду разработки для своих продуктов. Есть и универсальные решения. Стоит обратить внимание на Keil uVision - это такой универсальный и, пожалуй, наиболее популярный инструмент (хоть и не лучший) на все случаи жизни. Полный перечень можете найти .

Работа

Если вам действительно нравится идея программировать микроконтроллеры, создавая уникальные современные гаджеты, то найти вакансии себе по душе не составит труда. Люди данной профессии востребованы, причём как в стартапах, так и в крупных прогосударственных структурах, в том числе военных.

Финансово трудно придётся новичкам (до 1 года опыта): зарплата в районе 20 тыс. рублей в месяц для программиста МК. Это вполне реальная цифра в регионах. Зато если вы живёте в столице, у вас есть опыт работы с популярным видом МК (от 3 лет активной деятельности) и голова на плечах, то вполне можно рассчитывать и на 150 тыс. рублей в месяц. В целом, не сказать, что конкуренция за места у данных разработчиков высокая, но с течением времени она неизбежно растёт.

Опять же, для людей с опытом есть вариант поискать счастье за границей. Особенно если у вас уже есть опыт полноценной работы. Дело в том, что в России идея IoT пока не слишком развивается. Да и вообще автоматизация пока не затрагивает небольшие системы. А в США, Японии и других развитых странах хороший разработчик ПО для МК - на вес золота. Правда, придётся учитывать иной уровень конкуренции и серьёзные требования по производительности труда.

И кстати

В любом случае, прежде чем осознанно встать на эти рельсы, займитесь программированием МК в качестве хобби. Сделайте “умной” свою комнату или дом, повторите несколько экспериментов из , опубликуйте собственные достижения, посвятите этому делу мозги и душу. И если не возникнет ощущения “колхоза”, то... добро пожаловать в клуб!

Здравствуйте, уважаемые Хабражители!

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

Тема микроконтроллеров меня заинтересовала очень давно, году этак в 2001. Но тогда достать программатор по месту жительства оказалось проблематично, а о покупке через Интернет и речи не было. Пришлось отложить это дело до лучших времен. И вот, в один прекрасный день я обнаружил, что лучшие времена пришли не выходя из дома можно купить все, что мне было нужно. Решил попробовать. Итак, что нам понадобится:

1. Программатор
На рынке предлагается много вариантов - от самых дешевых ISP (In-System Programming) программаторов за несколько долларов, до мощных программаторов-отладчиков за пару сотен. Не имея большого опыта в этом деле, для начала я решил попробовать один из самых простых и дешевых - USBasp. Купил в свое время на eBay за $12, сейчас можно найти даже за $3-4. На самом деле это китайская версия программатора от Thomas Fischl . Что могу сказать про него? Только одно - он работает. К тому же поддерживает достаточно много AVR контроллеров серий ATmega и ATtiny. Под Linux не требует драйвера.

Для прошивки надо соединить выходы программатора VCC, GND, RESET, SCK, MOSI, MISO с соответствующими выходами микроконтроллера. Для простоты я собрал вспомогательную схему прямо на макетной плате:

Слева на плате - тот самый микроконтроллер, который мы собираемся прошивать.

2. Микроконтроллер
С выбором микроконтроллера я особо не заморачивался и взял ATmega8 от Atmel - 23 пина ввода/вывода, два 8-битных таймера, один 16-битный, частота - до 16 Мгц, маленькое потребление (1-3.6 мА), дешевый ($2). В общем, для начала - более чем достаточно.

Под Linux для компиляции и загрузки прошивки на контроллер отлично работает связка avr-gcc + avrdude. Установка тривиальная. Следуя инструкции , можно за несколько минут установить все необходимое ПО. Единственный ньюанс, на который следует обратить внимание - avrdude (ПО для записи на контроллер) может потребовать права супер-пользователя для доступа к программатору. Выход - запустить через sudo (не очень хорошая идея), либо прописать специальные udev права. Синтаксис может отличаться в разных версиях ОС, но в моем случае (Linux Mint 15) сработало добавление следующего правила в файл /etc/udev/rules.d/41-atmega.rules:

# USBasp programmer SUBSYSTEM=="usb", ATTR{idVendor}=="16c0", ATTR{idProduct}=="05dc", GROUP="plugdev", MODE="0666"

После этого, естественно, необходим перезапуск сервиса
service udev restart
Компилировать и прошивать без проблем можно прямо из командной строки (кто бы сомневался), но если проектов много, то удобнее поставить плагин и делать все прямо из среды Eclipse.

Под Windows придется поставить драйвер. В остальном проблем нет. Ради научного интереса попробовал связку AVR Studio + eXtreme Burner в Windows. Опять-таки, все работает на ура.

Начинаем программировать

Программировать AVR контроллеры можно как на ассемблере (AVR assembler), так и на Си. Тут, думаю, каждый должен сделать свой выбор сам в зависимости от конкретной задачи и своих предпочтений. Лично я в первую очередь начал ковырять ассемблер. При программировании на ассемблере архитектура устройства становится понятнее и появляется ощущение, что копаешься непосредственно во внутренностях контроллера. К тому же полагаю, что в особенно критических по размеру и производительности программах знание ассемблера может очень пригодиться. После ознакомления с AVR ассемблером я переполз на Си.

После знакомства с архитектурой и основными принципами, решил собрать что-то полезное и интересное. Тут мне помогла дочурка, она занимается шахматами и в один прекрасный вечер заявила, что хочет иметь часы-таймер для партий на время. БАЦ! Вот она - идея первого проекта! Можно было конечно заказать их на том же eBay, но захотелось сделать свои собственные часы, с блэк… эээ… с индикаторами и кнопочками. Сказано - сделано!

В качестве дисплея решено было использовать два 7-сегментных диодных индикатора. Для управления достаточно было 5 кнопок - “Игрок 1” , “Игрок 2” , “Сброс” , “Настройка” и “Пауза” . Ну и не забываем про звуковую индикацию окончания игры. Вроде все. На рисунке ниже представлена общая схема подключения микроконтроллера к индикаторам и кнопкам. Она понадобится нам при разборе исходного кода программы:

Разбор полета

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

Int main(void) { init_io(); init_data(); sound_off(); sei(); while(1) { handle_buttons(); } return 0; }
Рассмотрим каждую функцию в отдельности.

Void init_io() { // set output DDRB = 0xFF; DDRD = 0xFF; // set input DDRC = 0b11100000; // pull-up resistors PORTC |= 0b00011111; // timer interrupts TIMSK = (1<

Настройка портов ввода/вывода происходит очень просто - в регистр DDRx (где x - буква, обозначающая порт) записивается число, каждый бит которого означает, будет ли соответствующий пин устройством ввода (соответствует 0) либо вывода (соответствует 1). Таким образом, заслав в DDRB и DDRD число 0xFF, мы сделали 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) { 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((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 number, int mask) { PORTB = number_mask(number); PORTD = mask; }

Функция display использует метод динамической индикации. Дело в том, что каждый отдельно взятый индикатор имеет 9 контактов (7 для управления сегментами, 1 для точки и 1 для питания). Для управления 4 цифрами понадобилось бы 36 контактов. Слишком расточительно. Поэтому вывод разрядов на индикатор с несколькими цифрами организован по следующему принципу:

Напряжение поочередно подается на каждый из общих контактов, что позволяет высветить на соответствующем индикаторе нужную цифру при помощи одних и тех же 8 управляющих контактов. При достаточно высокой частоте вывода это выглядит для глаза как статическая картинка. Именно поэтому все 8 питающих контактов обоих индикаторов на схеме подключены к 8 выходам порта D, а 16 управляющих сегментами контактов соединены попарно и подключены к 8 выходам порта B. Таким образом, функция display с задержкой в 0.25 мс попеременно выводит нужную цифру на каждый из индикаторов. Под конец отключаются все выходы, подающие напряжение на индикаторы (команда PORTD = 0;). Если этого не сделать, то последняя выводимая цифра будет продолжать гореть до следующего вызова функции display, что приведет к ее более яркому свечению по сравнению с остальными.

Обработка нажатий

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, bit)) { if (_pressed == 0) { _delay_ms(DEBOUNCE_TIME); if (bit_is_clear(BUTTON_PIN, bit)) { _pressed |= key; // key action switch (key) { case 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 &= ~key; } }

Эта функция по очереди опрашивает все 5 кнопок и обрабатывает нажатие, если таковое случилось. Нажатие регистрируется проверкой bit_is_clear(BUTTON_PIN, bit) , т.е. кнопка нажата в том случае, если соответствующий ей вход соединен с землей, что и произойдет, согласно схеме, при нажатии кнопки. Задержка длительностью DEBOUNCE_TIME и повторная проверка нужна во избежание множественных лишних срабатываний из-за дребезга контактов. Сохранение статуса нажатия в соответствующих битах переменной _pressed используется для исключения повторного срабатывания при длительном нажатии на кнопку.
Функции обработки нажатий достаточно тривиальны и полагаю, что в дополнительных комментариях не нуждаются.

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

#define F_CPU 4000000UL #include #include #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 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; volatile int _buzzer = 0; volatile int _pressed = 0; // function declarations void init_io(); void init_data(); int number_mask(int num); 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(); // interrupts 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() { // set output DDRB = 0xFF; DDRD = 0xFF; // set input DDRC = 0b11100000; // pull-up resistors PORTC |= 0b00011111; // timer interrupts 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) { _delay_ms(DEBOUNCE_TIME); if (bit_is_clear(BUTTON_PIN, bit)) { _pressed |= key; // key action switch (key) { case 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 &= ~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 number, int mask) { PORTB = number_mask(number); PORTD = mask; } void sound_on(int interval) { _buzzer = interval; // put buzzer pin high PORTC |= 0b00100000; } void sound_off() { // put buzzer pin low PORTC &= ~0b00100000; }

Прототип был собран на макетной плате.

Урок 0.

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

Сегодня будут рассмотрены следующие вопросы:

  1. Что такое микроконтроллер?
  2. Где применяются микроконтроллеры?

Вступление.

Микроконтроллеры везде. В телефонах, стиральных машинах, «умных домах»,станках на заводе а так же ещё в бесчисленном множестве технических устройств. Их повсеместное применение позволяет заменить сложные аналоговые схемы, более сжатыми цифровыми.

Так что же такое, микроконтроллер?

Микроконтроллер (Micro Controller Unit, MCU ) - микросхема, предназначенная для управления электронными устройствами.Можно представить его в виде простейшего компьютера, способного взаимодействовать с внешними устройствами.Например, открывать и закрывать транзисторы, получать данные с датчиков температуры, выводить данные на lcd экраны и т. д. . К тому же, микроконтроллер может производить различную обработку входных данных, как и Ваш персональный компьютер.

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

Где используются микроконтроллеры?

  1. Бытовая техника(Стиральные машины, микроволновые печи и.т.д.).
  2. Мобильная техника(Роботы, робототехнические системы, средства связи и др.).
  3. Промышленное оборудование(Системы управления станками).
  4. Вычислительная техника(Материнские платы,системы управления периферийными устройствами).
  5. Развлекательная техника(Детские игрушки, украшения).
  6. Транспорт(Системы управления двигателем автомобиля, системы безопасности)

Это далеко не полный список сфер применения микроконтроллеров. Часто, очень выгодно заменить набор управляющих микросхем одним микроконтроллером, ввиду упрощения производства, снижения энергопотребления.

Начало знакомства с AVR

AVR — семейство микроконтроллеров фирмы Atmel.Обладают достаточной производительностью для большинства любительских устройств. Так же находят широкое применение в промышленности.

Здравствуйте девочки и мальчики. Надеюсь вы не забыли свои волшебные палочки, потому что они вам понадобятся. Сегодня я расскажу вам как написать простую утилиту для программирования микроконтроллера и посмотреть как она работает без возни с программаторами, травлением и паянием плат. Программа увеличивает/уменьшает на единицу значение на индикаторе нажатии на кнопку.

Для начала нам потребуется среда разработки. Для программирования микроконтроллеров использую MPLAB IDE версии 7.20 (по моему эта прожка бесплатна). Далее нам потребуется компилятор - HI-TECH C PRO для микроконтроллеров PIC16. Этот зверёк имеет полную ознакомительную версию на некоторое время, а потом сваливается в демо режим. Отличие демо режима от обычного-только в размере получаемых программ(нам на это по барабану, для начала вполне сойдёт и демо версия). И, наконец, необходима среда для моделирования работы нашего устройства. Пусть это будет Proteus 7.4, потому что это единственная известная мне программа, позволяющая моделировать работу микроконтроллера и электрической схемы. У меня лицензионная версия этой программы.

Итак приступим. Для начала создадим проект в MP LAB. Project->New. В диалоговом окне указываем Имя проекта и путь к нему. Путь не должен содержать русских букв и папок с длинными именами (кстати забыл вас предупредить, что при установке MP LAB путь к нему также не должен содержать русских букв, пробелов и не быть слишком длинным).

#include //========= переменные ======== volatile unsigned char counter @ 0x30; // переменная для подсчитывания количества нажатий на кнопку bit Knop_bit_first; // Бит для обработки нажатий на кнопку 1 bit Knop_bit_second; // Бит для обработки нажатий на кнопку 2 //============================= unsigned char NST(unsigned char F) // функция перевода десятичного числа в код для семисегментного индикатора { // на входе десятичное число, на выходе бинарный код для вывода на индикатор switch (F) { case 0: return 0x3f; case 1: return 0x06; case 2: return 0x5b; case 3: return 0x4f; case 4: return 0x66; case 5: return 0x6d; case 6: return 0x7d; case 7: return 0x07; case 8: return 0x7f; case 9: return 0x6f; } } void main(void) // основная часть программы { //==== инициализация микроконтроллера и переменных ======= GIE=0; // запрет всех прерываний, установкой бита GIE в 0 TRISA=0xff; TRISB=0x00; PORTB=0x00; OPTION=0x00; INTCON=0x27; counter=0; Knop_bit_first=0; Knop_bit_second=0; //======================================================= while(1) // организация вечного цикла { if(RA0==0 && counter<9) { if(Knop_bit_first==0) { counter++; Knop_bit_first=1; } } else { Knop_bit_first=0; } if(RA1==0 && counter>0) { if(Knop_bit_second==0) { counter--; Knop_bit_second=1; } } else { Knop_bit_second=0; } PORTB=NST(counter); } }

В идеале это должно работать так - при нажатии на кнопку, число на индикаторе увеличивается на единицу.
В том пике, котрый выбрал я два порта-порт A (8 линий или 8 ножек в микросхеме) и порт B (8 линий). Через любую линию можно как вводить информацию в микроконтроллер так и выводить её. За настройку портов отвечают 2 системных регистра TRISA и TRISB. Запись TRISA=0000010 b означает, что все линии порта A настроены на вывод данных из микроконтроллера кроме первой.
В нашем случае нужно написать TRISA=00000011 b или если не заморачиваться с бинарными кодами TRISA=0xff(все линии порта А на ввод).
Считать информацию с порта или подать на выход можно используя биты RA0..RA3 и RB0..RB7. Это и используется в программе при опросе кнопок, подключённых к RA0 и RA1(кстати при нажатии кнопки, на ножке будет сигнал логического нуля, а при отпускании лог. ед.).
Чтобы скомпилировать нажмите F10. Проверьте в папке проекта должен появится файлик с расширением *.hex. Далее проверим работает ли наша программа. для этого необходимо собрать в протеусе схему нашего устройства.

Щелкните по кнопке P (на рисунке помечена цифрой 1). Это что-то наподобие библиотеки. Элемент можно найти вбиванием в поле keywords его названия. Нам понадобятся: pic16f628a, индикатор 7seg-com-cathode(красного цвета, мы же настоящие ситхи), резисторы chipres10K, кнопки button, батарейки cell и заземление, которое можно найти щёлкнув по кнопке terminals mode(на рисунке помечена цифрой 2) и выбрав из списка ground. Элементы по мере выуживания из библиотеки постепенно накапливаются в списке component mode.
Далее перетаскиваем всё что нам нужно на основное поле и собираем схему. Меняем номиналы сопротивлений и батареек на нужные-правый щелчок мышью по компоненту->Edit properties. Далее загрузим программу в микроконтроллер-правый щелчок мышью по микроконтроллеру->Edit properties->Program file и указываем путь до файлика нашей программы с расширением *.hex(помните он появлялся в паке проекта после компиляции). Запустить/остановить моделирование можно кнопками старт/стоп(спасибо КЭП), они на рисунке обозначены как 3 и 4.

Эту статью (а точнее цикл статей…) я решил полностью посвятить микроконтроллерам фирмы Atmel. Конечно, тема эта избитая… НО! На собственном опыте знаю, что познать истину среди этого, извините, БАРДАКА, очень и очень сложно! Поэтому решил попытаться внести хотя бы какую-нибудь ясность в головы жаждущих познать этого страшного зверя, зовущегося «Микроконтроллер».

Итак, цель этой статьи в том, чтобы описать и по возможности показать весь процесс создания устройства на основе микроконтроллера с «нуля». То есть, от задумки (например, решили мы собрать новогоднюю мигалку, подобную описанной уважаемым alx32 в статье …) до воплощения в железе. Разумеется, минуя все промежуточные стадии: постановка задачи, выбор МК, подбор обвязки, формулировка алгоритма, написание программы, отладка, создание платы и, самое долгожданное – запуск!!!

Обновлено: добавлены файлы. Итак, задача : нам нужно создать устройство, способное зажигать в определенном порядке (пусть будет по очереди) , N-ное количество светодиодов (пускай будет 8 штук).
(это для начала……..)


Теперь можно браться за программирование. Писать можно на чем угодно, но начинающим советую отдать предпочтение языку C , т.к. программировать проще и нагляднее. Лично я пользуюсь компилятором CodeVision AVR (он есть в файловом архиве), дальнейшие листинги программ будут приводиться именно для этого компилятора.

Определимся с алгоритмом . Нам нужно по очереди через определенный промежуток времени активировать один из выходов МК.

Включать/выключать можно разными способами :
- присваивать значения каждому выводу отдельно;
- записывать значения сразу всех выводов.

Значения (последовательность) можно получить :
- набрав все команды вручную;
- из массива;
- математическим методом.

Временной интервал можно задать :
- функциями delay (задержка);
- через таймер.

Поэкспериментируем со всеми этими способами. Но сначала нужна заготовка…

Чтобы создать заготовку программы воспользуемся генератором кода, встроенным в CVAVR . Для этого запускаем программу, нажимаем File -> New , в открывшемся окне выбираем “Project” и жмем OK . На вопрос «Воспользоваться генератором кода?» отвечаем “Yes”.
Появилось окно генератора кода. В нем выбираем тип МК и его тактовую частоту, остальное оставляем как есть:


Далее переходим на вкладку “Ports” и там в “PortB” и выставляем следующее:


Так мы определили все выводы порта B как выходы, а нолики означают, что при включении питания на них будет устанавливаться логический "0 ".
Остальные функции нам пока не нужны.

Жмем “File -> Generate, Save and Exit” , выбираем куда сохранить файлы проекта и видим окно с созданным генератором кодом.

Теперь давайте введем в программу наш код .
Простейший вариант реализации (хотя и самы не красивый с точки зрения программирования) – записываем значения каждого вывода, а задержки делаем через функцию delay .

delay_ms(x ); - задержка на x миллисекунд

delay_us(x ); - задержка на x микросекунд

PORTB - порт, с которым мы работаем.

PORTB.x - обращение к выводу x порта B

Находим в конце текста такие строки


Это бесконечный цикл (т.е.выполняется всё время, пока включено питание) нашей программы. Всё, что перед ним – команды предварительной настройки микроконтроллера. Строки, начинающиеся с “//” – комментарии, их тоже полезно иногда читать.

Исключён фрагмент. Наш журнал существует на пожертвования читателей. Полный вариант этой статьи доступен только


Жмем кнопочку Make the project

(в панели инструментов).

Матерится?
И правильно! Компилятор не знает функции delay_ms() , поэтому надо указать ему файл, в котором эта функция описана.
Для этого в самом начале текста программы нужно вставить строку #include (тут точка_с_запятой не нужна! )
Примерно вот так:

Снова жмем волшебную кнопочку.
Проект создан .
Теперь в папке, в которую мы сохранили сам проект, появился файл название_проекта .hex – это и есть прошивка микроконтроллера!

Но подождите, не торопитесь хвататься за паяльник… Мы ведь учимся программировать, а не паять!

Именно поэтому предлагаю проверить нашу программу в виртуальном режиме, а именно – в таком замечательном и любимом мною продукте от Labcenter Electronics - Proteus VSM Там можно моделировать абсолютно любые схемы (даже примитивы Лапласа есть!). Взять ее можно в прикрепленном архиве, вместе с файлами проекта. Правда версия не совсем крякнутая, поэтому не работает сохранение. Что с этим делать расскажу в отдельной статье.

Итак, запускаем ISIS (среда разработки принципиальных схем). В этом окне нажимам кнопочку “P”.

В строке “Keywords” вводим “attiny2313” и справа получаем:


Выбирать особо не из чего, поэтому щелкаем дважды по этой одинокой строке и видим слева в основном окне:


Это значит, что элемент добавлен.

Теперь введите в поле “Keywords” слова “LED-RED” и “RES” . Добавьте резистор и светодиод в проект и закройте окно выбора элементов.

Пробуем собрать схему (вывод RESET обязательно подключите к +5V, иначе ничего не заработает! и в жизни это тоже желательно!)

Вот небольшая подсказка :

А для редактирования свойств элементов достаточно щелкнуть по ним дважды.

Собрали? Надеюсь, не покалечили при этом себя, близких и окружающие предметы.

Простите за издевательство, просто если разберешься сам – уже не забудешь, так что, постигайте, программа очень мощная и она стоит того, чтобы ее освоить! :laughing:

Когда схема собрана, можно прошить наш виртуальный МК. Для этого щелкаем по нему дважды и видим окно.