Главная » Микроконтроллеры
Призовой фонд
на ноябрь 2017 г.
1. Термометр Relsib WT51
Рэлсиб
2. 1000 руб
PCBWay
3. Тестер компонентов LCR-T4
Паяльник
4. 200 руб.
От пользователей

Похожие статьи:


Индикация места ключа (Часть1)

Хочу поделится своим первым опытом с разработкой устройства на микроконтроллере. У данной статьи будет 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) можно собрать на макетке

Выберем третий вариант, т.к. он самый быстрый.

111.jpg

Подключим VCC микроконтроллера и +5V программатора к плюсу источника, в качестве источника четыре батарейки АА, в сумме 6 Вольт, на трех батарейках выдает ошибку - не видит микроконтроллер

GND микроконтроллера и GND программатора к минусу источника. Выводы микроконтроллера SCK, MISO, MOSI соответственно к тем же на программаторе.

Далее самое интересное, процесс прошивки кристалла:

мы создадим довольно красивую печатную плату к данному устройству.

Список радиоэлементов

Обозначение Тип Номинал Количество ПримечаниеМагазинМой блокнот
U1 МК AVR 8-бит
ATmega8
1 Поиск в LCSCВ блокнот
Резистор
10 кОм
8 Поиск в LCSCВ блокнот
Резистор
330 Ом
8 Поиск в LCSCВ блокнот
Резистор
130 Ом
3 Поиск в LCSCВ блокнот
D1-D3 СветодиодЗеленый3 Поиск в LCSCВ блокнот
Seg1-Seg3 Индикатор3 Поиск в LCSCВ блокнот
SW0-SW4 Кнопка5 Поиск в LCSCВ блокнот
J1 Панелька2 Штырька1 Поиск в LCSCВ блокнот
J2, J3 Панелька4 Штырька2 Поиск в LCSCВ блокнот
Добавить все

Скачать список элементов (PDF)

Прикрепленные файлы:

Теги:

Опубликована: 0 0
Я собрал 0 Участие в конкурсе 2
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 3.7 Проголосовало: 2 чел.

Комментарии (25) | Я собрал (0) | Подписаться

+1
Иван #
А нельзя ли было сделать так, чтобы первая кнопка отвечала за "сотни", вторая - за "десятки", третья - за "единицы". Ведь так проще.
В зависимости от кол-ва аудиторий (я как понимаю соответствуют этажам, 6 этажей - 6.. аудиторий) числа циклически переключались бы от 0 до 9. Либо кнопки попарно одна под одной: верхняя - увеличивает до 9, нижняя - уменьшает до 0.
В общем все равно респект, мало кто до "железа" доводит свой диплом
Ответить
0

[Автор]
nikdemars #
Задумка хорошая, можно было бы сделать и так
Ответить
0
Денис #
Еще можно убрать светодиоды для обозначения разрядов и сделать активный разряд мигающим. Если в течение 0 сек они не меняются, то мигание прекращается. После нажатия любой кнопки опять начинает мигать для редактирования. Так можно избавиться от лишних деталей
Ответить
0
Саша #
А лучше 6 кнопок по две на каждый разряд
1 инкремент (+1)
2 декремент (-1)
Ответить
+2
Drum #
А где же здесь С++?
Ответить
0

[Автор]
nikdemars #
В AVR Studio 6 при создании проекта доступен С++
Ответить
+1
hd44780 #
Это С, а не С++.
С++ - объектно-ориентированный язык, там основа всего - ключевое слово class и работа с динамической памятью операторами new/delete. На AVR-ах это не применяют из-за очень малого объёма RAM. Запомните это раз и навсегда. Иначе Вас и высмеять могут за такие "познания".
Ответить
-1

[Автор]
nikdemars #
В корне несогласен, откройте Atmel Studio 6, там при создании предлагает создать:
AVR Assembler Project
GCC C Executable Project C/C++
GCC C++ Executable Project C/C++
Ответить
+1
Drum #
Выбор проекта GCC C++ Executable Project C/C++ не делает Вашу программу C++. C++ обратно совместим с C, и потому компилятор не ругается на этот С код. Но в программе нет ни одного элемента C++. Ни классов, ни операторов, ни каких либо других элементов. Это не делает Вашу программу хуже. В принципе здесь С++ и приткнуть-то некуда. Но формально это чистый С, и Ваш преподователь мог бы придраться к этому, если бы захотел.
Ответить
-1

[Автор]
nikdemars #
Да это уже не важно, важно то, что оценка есть, немного опыта набрался и hd44780 не прав, т.к. на С++ можно программировать AVR, единственное что я этого не использовал
Ответить
0
Artos5 #
С++ тут и близко нету. Тут чистейший Си.
Немного странно код написан. Зачем так "не оптимально" писать? Можно сделать проще и при этом гораздо меньше ресурсов МК будет использовано. Также можно применить тоже 3 шт. кнопки одна для выбора "разряда", вторая - "+" , третья - "-". А выбранный разряд сделать мигающим. Было бы гораздо лучше. Я так делал для ввода пароля в системе контроля доступа.
Ответить
0

[Автор]
nikdemars #
Это уже все поняли и так, я написал С++, потому что выбирал при создании "GCC C++ Executable Project C/C++", и знаю что это не делает программу С++. Дальше, почему так не оптимизировано - во первых, я только начал изучать данный язык, во вторых это моя первая программа для микроконтроллера (писал в начале статьи, что это мой Hello World), в третьих почти любую программу можно оптимизировать.
Ответить
+1
Artos5 #
есть международные и всероссийские дипломы за программирование.

У людей с такими дипломами, не должен быть на столько корявый код :)
Не важно на чем программирует человек! Зачем переключателями делать инкремент / декремент? Если можно делать операции с переменной , а потом ее разложить и загнать на индикатор. Тут не надо быть профи в программировании для МК. Достаточно быть просто программистом.
Ответить
0

[Автор]
nikdemars #
Дипломы за язык Delphi и есть разные стили программирования, есть спортивное (где надо оптимально и быстро написать), а есть по творческим проектам, где смотрится полезность программы, ее интерфейс и т.д.
В С++ опыта вообще нету и в программировании микроконтроллера тоже (писал же в начале статьи)
Ответить
0
Artos5 #
Также, очень желательно в переключателях (Switch) прописывать default: я надеюсь такого уровня программист как вы, знает зачем?

Пример кода без этих переключателей:

if (minus==0 && flags==0)
{
data0--;
flags=1;
}

if(plus==0 && flags==0)
{
data0++;
flags=1;
}

if(plus && minus)flags=0; // кнопки отжаты

delay_ms(50); // антидребезг

seg_shou = data_buff[data0];// выводим данные

И все, не надо прописывать кучу ненужного. И вы сравните какой размер кода при этом получится!
Отредактирован 19.02.2013 13:51
Ответить
0

[Автор]
nikdemars #
default тут не нужен, он никогда не сработает
Ответить
0
Artos5 #
default: как раз сработает, в случае если значение переменной не попадет ни в один из значений case x:
Ответить
0

[Автор]
nikdemars #
Значение переменной всегда попадет в данном случае
Ответить
+1
mouse #
Не нужно так катергорично судить. Конечно, можно все оптимизировать, когда уже написано и выложено.
Идея реализована, уже хорошо.
Если усовершенствовать, то можно тогда использовать клавиатуру (0....9) и набирать номер аудитории на ней. Тогда вообще будет просто и легко.
Ответить
0
mouse2004 #
Тут читал, читал и вспомнил за свое. У меня есть идея сделать табло для спортивных мероприятий. Два разряда + две точки разделители + два разряда. Табло висит на стене. Управление через проводной пульт. На пульте кнопки +\- для каждого разряда (всего 4 пары). Скажите, подойдет ли данная схема, если ее немного изменить?
Так как хочу использовать светодиоды, из которых нарисовать сегменты по подобию тех, которые используются тут. Какие изменения необходимы?
Ответить
0
Дмитрий #
Не подскажите: если делать счётчик на основе Вашего проекта (т.е. просто кнопка + и -, сброс) и чтобы он считал от 1 до 999) что необходимо прописать в программе?
Ответить
0
nikdemars #
Тут рассматривается частный случай на 10 шагов, в вашем случае нужно почти весь код менять, т.к. подход совершенно другой
Ответить
0
Дмитрий #
Ну я в принципе написал код (под основу вашего проекта), только почему то те сегменты которые не должны зажигаться, горят заметно (очень сложно различить цифру). Это ошибка в коде или микроконтроллера?
Ответить
0

[Автор]
nikdemars #
Скорее всего в коде. Там надо, чтобы при выводе был подключен только 1 индикатор, потом второй, потом третий, при этом, чтобы остальные были отключенны, это у меня делается через порт С
Ответить
0
Ильнур #
Попробуйте вывести число из одинаковых цифр типа 111 или 777, если подсветки сегментов при этом не наблюдается, то скорее проблема в коде. По идее сперва выводится в порт первое число, потом подается напряжение на общий анод (или катод) первого индикатора на какое то время, потом напряжение с общего анода (или катода) первого индикатора снимается, в порт отправляется второе число, подается напряжение на общий анод (или катод) второго индикатора, так же на какой то период,затем снимается, и так далее по кругу. То есть отправка значения на сегменты должна происходить в середине между включением и выключением питания на общем аноде (или катоде) выбранного индикатора. Подготовили, отправили значение в порт, засветили индикатор, потушили, подготовили,отправили, засветили второй индикатор, потушили.
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется напряжение?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

Pickit 2 - USB-программатор PIC-микроконтроллеров
Pickit 2 - USB-программатор PIC-микроконтроллеров
USB осциллограф DSO-2090 МиниПК MK809V - 4 ядра, Android 4.4.2
вверх