Хочу поделится своим первым опытом с разработкой устройства на микроконтроллере. У данной статьи будет 4 части:
часть 1 - теоретическая часть, проектирование устройства
часть 2 - прошивка микроконтроллера
часть 3 - изготовление ПП (фоторезист + FSR-8000)
часть 4 - делаем корпус
Данная статья ориентированна в основном для начинающих, кем я сам и являюсь, для меня это как бы Hello World AVR, поэтому строго не судите.
Для начала расскажу что за "Индикация места ключа" и причина его изготовления. Мне нужно было сдать экзамен по программированию на С++, попутно у меня хобби - электроника, и тут мне захотелось совместить приятное с полезным, преподаватель по С++ как-то говорил об одном устройстве, предлагал сделать его, но так никто и не откликнулся. Суть устройства - на кафедре очень часто бывает что никого нет, а ключ в каком нибудь кабинете с преподавателем, чтобы знали где ключ на дверь вешают бумажку, на которой написан номер кабинета где ключ, устройство должно как-то заменить эту бумажку. И тут я вспомнив это предлагаю преподавателю альтернативу, я устройство в котором буду использовать программирование на С++ вместо экзамена.
Для начала давайте определим основные критерии устройства:
- портативное (на батарейках)
- прочное (чтобы "бешеные" студенты не оторвали)
- должно иметь 2 части (панель управления и внешний индикатор)
- ну и по возможности симпатичное
Следующим шагом придумаем интерфейс устройства:
То, что слева - панель управления (то что внутри кафедры), те кружочки под числами - светодиоды, маленькие черные кружочки - тактовые кнопки, черная круглая - кнопка нажимная с фиксацией, числа в прямоугольнике - семисегментные индикаторы. Кнопка "Выбор разряда" выбирает разряд числа, светодиод под каждым разрядом подсвечивает тот разряд, который выбран, который мы сейчас редактируем. Кнопки "Добавить" и "Уменьшить" изменяют выбранную цифру, сброс обнуляет все числа. Кнопка "Вкл\Выкл" - тут понятно. То что справа - внешний индикатор, должен быть снаружи кафедры.
Микроконтроллер я выбрал Atmega8-16PU, т.к. только он был в наличии дома.
Для создания прошивки микроконтроллера я использовал Atmel Studio 6.0.
Для симуляции схемы и создания ПП использовал Proteus 7 Professional.
Схема устройства:
На схеме J1 - для подключения питания, J2, J3 - для внутрисхемного программирования.
Теперь перейдем к написанию программы, идея проста - есть три переменных, каждая из которых соответствует каждому индикатору, так же есть переменная, которая отвечает за состояние выбранного разряда, программа циклически повторяется и выводит эти переменные на семисегментники и светодиоды, нажатие тактовых кнопок изменяет эти значения, ну проще и быть не может. Перейдем к написанию кода
для начала подключим необходимые модули:
#define F_CPU 1000000UL //тактовая частота микроконтроллера #include // объявление для всех AVR #include // для Atmega8 #include // для пауз
Далее напишем основную функцию, весь остальной код будем писать между фигурными скобками
int main(void) { }
Настроим порты:
DDRD = 0xFF; // порт D как выход DDRC = 0xFF; // порт C как выход DDRB = 0x00; // порт B как вход
Объявим и создадим массив, который будет хранить переменные для порта D, для вывода на семисегментник символов 0,1,2,3,4,5,6,7,9, -:
// 0 1 2 3 4 5 6 7 8 9 - char SEGMENT[ ] = {0x3F, 0x06, 0x5B, 0x4F, 0x66,0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0b01000000};
Объявим и зададим значения переменным, о которых говорил выше. Поясню n_1 - значение первого индикатора, n_2 - 2-го индикатора, n_3 - 3-го, indickator - это номер выбранного разряда.
int n_1 = 0; int n_2 = 0; int n_3 = 0; char indickator = '1';
Далее пишем бесконечный цикл, в котором будем выводит переменные (n_1, n_2, n_3, indickator) и при нажатии кнопок изменять их значения
while(1) { }
Напишем оператор выбора, который будет подсвечивать индикаторы, и светодиоды, логика следующая -
если активен 1-й разряд, то
порту С ставим такое состояние, чтобы горел 1-й светодиод и был подключен только первый семисегментник
на порт D выводим символ, который соответствует переменной n_1
делаем паузу, чтобы 1-й семисегментник немного погорел
порту С ставим такое состояние, чтобы горел 1-й светодиод и был подключен только второй семисегментник
на порт D выводим символ, который соответствует переменной n_2
делаем паузу, чтобы 2-й семисегментник немного погорел
порту С ставим такое состояние, чтобы горел 1-й светодиод и был подключен только третий семисегментник
на порт D выводим символ, который соответствует переменной n_3
делаем паузу, чтобы 3-й семисегментник немного погорел
если активен 2-й разряд, то делаем тоже самое, разница лишь в том что горит 2-й светодиод, аналогично при активном третьем разряде.
switch(indickator) { case '1': { PORTC = 0b00001110; // вывод на 1-й индикатор PORTC = 0b00001011; PORTD = SEGMENT[n_1]; _delay_ms(5); PORTC = 0b00001101;// вывод на 2-й индикатор PORTD = SEGMENT[n_2]; _delay_ms(5); PORTC = 0b00001011;// вывод на 3-й индикатор PORTD = SEGMENT[n_3]; } break; case '2': { PORTC = 0b00010110; // вывод на 1-й индикатор PORTC = 0b00001011; PORTD = SEGMENT[n_1]; _delay_ms(5); PORTC = 0b00010101;// вывод на 2-й индикатор PORTD = SEGMENT[n_2]; _delay_ms(5); PORTC = 0b00010011;// вывод на 3-й индикатор PORTD = SEGMENT[n_3]; } break; case '3': { PORTC = 0b00100110; // вывод на 1-й индикатор PORTC = 0b00001011; PORTD = SEGMENT[n_1]; _delay_ms(5); PORTC = 0b00100101;// вывод на 2-й индикатор PORTD = SEGMENT[n_2]; _delay_ms(5); PORTC = 0b00100011;// вывод на 3-й индикатор PORTD = SEGMENT[n_3]; } break; }
Это переключение между семисегментниками невооруженным глазом не уловить (хотя на видео это можно заметить. покажу во второй части статьи) и нам кажется что горят все три индикатора одновременно, этим мы сэкономили 16 выводов микроконтроллера, которых у меня тут просто не найти.
Теперь добавим обработчик нажатия кнопки "Выбор разряда", суть - через резисторы 10кОм течет ток и на порте B каждый вывод равен 1 (плюс). При нажатии тактовой кнопки ток утекает в землю и на соответствующем выводе микроконтроллера возникает 0, т.е. минус. Используем это для описываемой кнопки, логика следующая -
если на соответствующем выводе порта В появился минус, то
если переменная indicator = 1, то делаем ее равную 2
если она равна 2, то делаем ее равную 3
если она равна 3, то делаем ее равную 1
После всего этого делаем паузу в 0,2 секунды, если паузу не сделать, то пока вы будете нажимать кнопку светодиод успеет смениться следующим по циклу несколько десятков или сотен раз, может и пару тысяч, а 0,2 секунды вполне хватает чтобы при однократном нажатии произошел всего один переход.
if (PINB == 0b11111110) // нажатие кнопки установка { switch(indickator) { case '1': indickator = '2' ; break; case '2': indickator = '3' ; break; case '3': indickator = '1' ; break; } _delay_ms(200); }
Следующий у нас на очереди обработчик кнопки "Увеличить", тут тоже все просто, если возник минус на выводе порта В, куда подключена соответствующая кнопка, то если выбран первый разряд, то увеличиваем там число, если 2-й, то увеличиваем второй на единицу и если третий, то третий увеличиваем, после чего также и по той же причине что выше делаем паузу в 0,2 секунды:
if (PINB == 0b11111101) // нажатие кнопки + { if (indickator == '1') { switch(n_1) { case 0: n_1 = 1; break; case 1: n_1 = 2; break; case 2: n_1 = 3; break; case 3: n_1 = 4; break; case 4: n_1 = 5; break; case 5: n_1 = 6; break; case 6: n_1 = 7; break; case 7: n_1 = 8; break; case 8: n_1 = 9; break; case 9: n_1 = 10; break; case 10: n_1 = 0; break; } } if (indickator == '2') { switch(n_2) { case 0: n_2 = 1; break; case 1: n_2 = 2; break; case 2: n_2 = 3; break; case 3: n_2 = 4; break; case 4: n_2 = 5; break; case 5: n_2 = 6; break; case 6: n_2 = 7; break; case 7: n_2 = 8; break; case 8: n_2 = 9; break; case 9: n_2 = 10; break; case 10: n_2 = 0; break; } } if (indickator == '3') { switch(n_3) { case 0: n_3 = 1; break; case 1: n_3 = 2; break; case 2: n_3 = 3; break; case 3: n_3 = 4; break; case 4: n_3 = 5; break; case 5: n_3 = 6; break; case 6: n_3 = 7; break; case 7: n_3 = 8; break; case 8: n_3 = 9; break; case 9: n_3 = 10; break; case 10: n_3 = 0; break; } } _delay_ms(200); }
Аналогично кнопке "Добавить" реализуем кнопочку "Уменьшить":
if (PINB == 0b11111011) // нажатие кнопки - { if (indickator == '1') { switch(n_1) { case 0: n_1 = 10; break; case 1: n_1 = 0; break; case 2: n_1 = 1; break; case 3: n_1 = 2; break; case 4: n_1 = 3; break; case 5: n_1 = 4; break; case 6: n_1 = 5; break; case 7: n_1 = 6; break; case 8: n_1 = 7; break; case 9: n_1 = 8; break; case 10: n_1 = 9; break; } } if (indickator == '2') { switch(n_2) { case 0: n_2 = 10; break; case 1: n_2 = 0; break; case 2: n_2 = 1; break; case 3: n_2 = 2; break; case 4: n_2 = 3; break; case 5: n_2 = 4; break; case 6: n_2 = 5; break; case 7: n_2 = 6; break; case 8: n_2 = 7; break; case 9: n_2 = 8; break; case 10: n_2 = 9; break; } } if (indickator == '3') { switch(n_3) { case 0: n_3 = 10; break; case 1: n_3 = 0; break; case 2: n_3 = 1; break; case 3: n_3 = 2; break; case 4: n_3 = 3; break; case 5: n_3 = 4; break; case 6: n_3 = 5; break; case 7: n_3 = 6; break; case 8: n_3 = 7; break; case 9: n_3 = 8; break; case 10: n_3 = 9; break; } } _delay_ms(200); }
Осталось добавить обработчик кнопки "Сброс", для этого отследим ее нажатие и просто "обнулим" значения всех переменных и добавим паузу, хотя и она тут особо роли не играет:
if (PINB == 0b11110111) // нажатие кнопки сброс { n_1 = 10; n_2 = 10; n_3 = 10; indickator = '1'; _delay_ms(100); }
Далее компилируем проект и загружаем прошивку в Proteus и симулируем:
Следующее что нам нужно сделать - это прошить микроконтроллер
Прошивать будем программой AlgorithmBuilder через программатор SPA0008, стоит он недорого, я покупал за 731 руб. в магазине ekits, намного дешевле конечно воспользоваться "пятью проводками", но у меня нет LTP порта и USB программатор более мобилен.
Для начала присоединим микроконтроллер к программатору, тут несколько вариантов:
1) можно купить плату-адаптер для данного типа микроконтроллера
2) можно сделать самому плату-адаптер для данного микроконтроллера
3) можно собрать на макетке
Выберем третий вариант, т.к. он самый быстрый.
Подключим VCC микроконтроллера и +5V программатора к плюсу источника, в качестве источника четыре батарейки АА, в сумме 6 Вольт, на трех батарейках выдает ошибку - не видит микроконтроллер
GND микроконтроллера и GND программатора к минусу источника. Выводы микроконтроллера SCK, MISO, MOSI соответственно к тем же на программаторе.
Далее самое интересное, процесс прошивки кристалла:
В следующей статье мы создадим довольно красивую печатную плату к данному устройству.
Список радиоэлементов
Обозначение | Тип | Номинал | Количество | Примечание | Магазин | Мой блокнот |
---|---|---|---|---|---|---|
U1 | МК AVR 8-бит | ATmega8 | 1 | Поиск в магазине Отрон | ||
Резистор | 10 кОм | 8 | Поиск в магазине Отрон | |||
Резистор | 330 Ом | 8 | Поиск в магазине Отрон | |||
Резистор | 130 Ом | 3 | Поиск в магазине Отрон | |||
D1-D3 | Светодиод | Зеленый | 3 | Поиск в магазине Отрон | ||
Seg1-Seg3 | Индикатор | 3 | Поиск в магазине Отрон | |||
SW0-SW4 | Кнопка | 5 | Поиск в магазине Отрон | |||
J1 | Панелька | 2 Штырька | 1 | Поиск в магазине Отрон | ||
J2, J3 | Панелька | 4 Штырька | 2 | Поиск в магазине Отрон | ||
Скачать список элементов (PDF)
Прикрепленные файлы:
- AVR_Studio_6_Project.rar (29 Кб)
- ISIS_Project.rar (86 Кб)
- AVR_key_AlgorithmBuilder.rar (6 Кб)
Комментарии (25) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация
В зависимости от кол-ва аудиторий (я как понимаю соответствуют этажам, 6 этажей - 6.. аудиторий) числа циклически переключались бы от 0 до 9. Либо кнопки попарно одна под одной: верхняя - увеличивает до 9, нижняя - уменьшает до 0.
В общем все равно респект, мало кто до "железа" доводит свой диплом
[Автор]
1 инкремент (+1)
2 декремент (-1)
[Автор]
С++ - объектно-ориентированный язык, там основа всего - ключевое слово class и работа с динамической памятью операторами new/delete. На AVR-ах это не применяют из-за очень малого объёма RAM. Запомните это раз и навсегда. Иначе Вас и высмеять могут за такие "познания".
[Автор]
AVR Assembler Project
GCC C Executable Project C/C++
GCC C++ Executable Project C/C++
[Автор]
Немного странно код написан. Зачем так "не оптимально" писать? Можно сделать проще и при этом гораздо меньше ресурсов МК будет использовано. Также можно применить тоже 3 шт. кнопки одна для выбора "разряда", вторая - "+" , третья - "-". А выбранный разряд сделать мигающим. Было бы гораздо лучше. Я так делал для ввода пароля в системе контроля доступа.
[Автор]
У людей с такими дипломами, не должен быть на столько корявый код :)
Не важно на чем программирует человек! Зачем переключателями делать инкремент / декремент? Если можно делать операции с переменной , а потом ее разложить и загнать на индикатор. Тут не надо быть профи в программировании для МК. Достаточно быть просто программистом.
[Автор]
В С++ опыта вообще нету и в программировании микроконтроллера тоже (писал же в начале статьи)
Пример кода без этих переключателей:
{
data0--;
flags=1;
}
if(plus==0 && flags==0)
{
data0++;
flags=1;
}
if(plus && minus)flags=0; // кнопки отжаты
delay_ms(50); // антидребезг
seg_shou = data_buff[data0];// выводим данные
И все, не надо прописывать кучу ненужного. И вы сравните какой размер кода при этом получится!
[Автор]
[Автор]
Идея реализована, уже хорошо.
Если усовершенствовать, то можно тогда использовать клавиатуру (0....9) и набирать номер аудитории на ней. Тогда вообще будет просто и легко.
Так как хочу использовать светодиоды, из которых нарисовать сегменты по подобию тех, которые используются тут. Какие изменения необходимы?
[Автор]